vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

rpm-fake-resolver.c (7066B)


      1 // $Id$    --*- c -*--
      2 
      3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 //  
      5 // This program is free software; you can redistribute it and/or modify
      6 // it under the terms of the GNU General Public License as published by
      7 // the Free Software Foundation; version 2 of the License.
      8 //  
      9 // This program is distributed in the hope that it will be useful,
     10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 // GNU General Public License for more details.
     13 //  
     14 // You should have received a copy of the GNU General Public License
     15 // along with this program; if not, write to the Free Software
     16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     17 
     18 
     19 // Protocol:
     20 // 1. startup
     21 // 2. initialize (setuid, ctx-migrate, chroot, ...)
     22 // 3. send "." token to fd 3
     23 // 4. wait one character on fd 1
     24 // 5. process this character and consume further characters from fd 1 as far
     25 //    as needed
     26 // 6. go to 3) (or exit)
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #  include <config.h>
     30 #endif
     31 
     32 #include "internal.h"
     33 #include "vserver.h"
     34 #include "util.h"
     35 
     36 #include <getopt.h>
     37 #include <stdlib.h>
     38 #include <stdbool.h>
     39 #include <grp.h>
     40 #include <pwd.h>
     41 #include <fcntl.h>
     42 #include <errno.h>
     43 
     44 #define ENSC_WRAPPERS_PREFIX	"rpm-fake-resolver: "
     45 #define ENSC_WRAPPERS_VSERVER	1
     46 #define ENSC_WRAPPERS_UNISTD	1
     47 #define ENSC_WRAPPERS_IO	1
     48 #define ENSC_WRAPPERS_FCNTL	1
     49 #include <wrappers.h>
     50 
     51 #define MAX_RQSIZE	0x1000
     52 
     53 int wrapper_exit_code = 1;
     54 
     55 struct ArgInfo {
     56     xid_t		ctx;
     57     uid_t		uid;
     58     gid_t		gid;
     59     bool		do_fork;
     60     bool		in_ctx;
     61     char const *	pid_file;
     62     char const *	chroot;
     63     uint32_t		caps;
     64     int			flags;
     65 };
     66 
     67 static struct option const
     68 CMDLINE_OPTIONS[] = {
     69   { "help",     no_argument,  0, 'h' },
     70   { "version",  no_argument,  0, 'v' },
     71   { 0,0,0,0 }
     72 };
     73 
     74 static void
     75 showHelp(int fd, char const *cmd, int res)
     76 {
     77   WRITE_MSG(fd, "Usage:  ");
     78   WRITE_STR(fd, cmd);
     79   WRITE_MSG(fd,
     80 	    " [-c <ctx>] [-u <uid>] [-g <gid>] [-r <chroot>] [-s] [-n]\n"
     81 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
     82   exit(res);
     83 }
     84 
     85 static void
     86 showVersion()
     87 {
     88   WRITE_MSG(1,
     89 	    "rpm-fake-resolver " VERSION " -- NSS resovler for rpm-fake\n"
     90 	    "This program is part of " PACKAGE_STRING "\n\n"
     91 	    "Copyright (C) 2003 Enrico Scholz\n"
     92 	    VERSION_COPYRIGHT_DISCLAIMER);
     93   exit(0);
     94 }
     95 
     96 
     97 inline static void
     98 parseArgs(struct ArgInfo *args, int argc, char *argv[])
     99 {
    100   while (1) {
    101     int		c = getopt_long(argc, argv, "F:C:c:u:g:r:ns", CMDLINE_OPTIONS, 0);
    102     if (c==-1) break;
    103 
    104     switch (c) {
    105       case 'h'		:  showHelp(1, argv[0], 0);
    106       case 'v'		:  showVersion();
    107 
    108       case 'c'		:  args->ctx     = atoi(optarg); break;
    109       case 'u'		:  args->uid     = atoi(optarg); break;
    110       case 'g'		:  args->gid     = atoi(optarg); break;
    111       case 'F'		:  args->flags   = atoi(optarg); break;
    112       case 'C'		:  args->caps    = atoi(optarg); break;
    113       case 'r'		:  args->chroot  = optarg;   break;
    114       case 'n'		:  args->do_fork = false;    break;
    115       case 's'		:  args->in_ctx  = true;     break;
    116       default		:
    117 	WRITE_MSG(2, "Try '");
    118 	WRITE_STR(2, argv[0]);
    119 	WRITE_MSG(2, " --help' for more information.\n");
    120 	exit(1);
    121 	break;
    122     }
    123   }
    124 
    125   if (optind!=argc) {
    126     WRITE_MSG(2, "No further options allowed; aborting ...\n");
    127     exit(1);
    128   }
    129   
    130   if (args->chroot==0) {
    131     WRITE_MSG(2, "No chroot specified; aborting...\n");
    132     exit(1);
    133   }
    134 }
    135 
    136 static void
    137 sendResult(bool state, uint32_t res)
    138 {
    139   if (state) {
    140     static uint8_t	ONE = 1;
    141     Ewrite(1, &ONE, sizeof ONE);
    142   }
    143   else {
    144     static uint8_t	ZERO = 0;
    145     Ewrite(1, &ZERO, sizeof ZERO);
    146   }
    147 
    148   Ewrite(1, &res, sizeof res);
    149 }
    150 
    151 static void
    152 do_getpwnam()
    153 {
    154   uint32_t	len;
    155 
    156   if (EreadAll(0, &len, sizeof len) &&
    157       len<MAX_RQSIZE) {
    158     char		buf[len+1];
    159     struct passwd *	res = 0;
    160     
    161     if (EreadAll(0, buf, len)) {
    162       buf[len] = '\0';
    163       res = getpwnam(buf);
    164     }
    165     
    166     if (res!=0) sendResult(true,  res->pw_uid);
    167     else        sendResult(false, -1);
    168   }
    169   // TODO: logging
    170 }
    171 
    172 static void
    173 do_getgrnam()
    174 {
    175   uint32_t	len;
    176 
    177   if (EreadAll(0, &len, sizeof len) &&
    178       len<MAX_RQSIZE) {
    179     char		buf[len+1];
    180     struct group *	res = 0;
    181     
    182     if (EreadAll(0, buf, len)) {
    183       buf[len] = '\0';
    184       res = getgrnam(buf);
    185     }
    186     
    187     if (res!=0) sendResult(true,  res->gr_gid);
    188     else        sendResult(false, -1);
    189   }
    190   // TODO: logging
    191 }
    192 
    193 static void
    194 do_closenss()
    195 {
    196   uint8_t	what;
    197 
    198   if (EreadAll(0, &what, sizeof what)) {
    199     switch (what) {
    200       case 'p'	:  endpwent(); break;
    201       case 'g'	:  endgrent(); break;
    202       default	:  break;
    203     }
    204   }
    205 }
    206 
    207 static void
    208 run()
    209 {
    210   uint8_t	c;
    211 
    212   while (EwriteAll(3, ".", 1),
    213 	 EreadAll (0, &c, sizeof c)) {
    214     switch (c) {
    215       case 'P'	:  do_getpwnam(); break;
    216       case 'G'	:  do_getgrnam(); break;
    217       case 'Q'	:  exit(0);
    218       case 'C'	:  do_closenss(); break;
    219       case '.'	:  Ewrite(1, ".", 1); break;
    220       default	:  Ewrite(1, "?", 1); break;
    221     }
    222   }
    223 }
    224 
    225 static void
    226 daemonize(struct ArgInfo const UNUSED * args, int pid_fd)
    227 {
    228   int		p[2];
    229   pid_t		pid;
    230   char		c;
    231   
    232   Epipe(p);
    233   pid = Efork();
    234   
    235   if (pid!=0) {
    236     if (pid_fd!=-1) {
    237       char	buf[sizeof(id_t)*3 + 2];
    238       size_t	l;
    239 
    240       l = utilvserver_fmt_uint(buf, pid);
    241       Ewrite(pid_fd, buf, l);
    242       Ewrite(pid_fd, "\n", 1);
    243     }
    244     _exit(0);
    245   }
    246   Eclose(p[1]);
    247   TEMP_FAILURE_RETRY(read(p[0], &c, 1));
    248   Eclose(p[0]);
    249 }
    250 
    251 static void
    252 activateContext(xid_t xid, bool in_ctx,
    253 		uint32_t UNUSED xid_caps, int UNUSED xid_flags)
    254 {
    255   if (in_ctx) {
    256     struct vc_ctx_flags		flags = {
    257       .flagword = 0,
    258       .mask     = VC_VXF_STATE_SETUP,
    259     };
    260 
    261     Evc_set_cflags(xid, &flags);
    262   }
    263   else if (vc_isSupported(vcFEATURE_MIGRATE))
    264       Evc_ctx_migrate(xid, 0);
    265   else {
    266 #ifdef VC_ENABLE_API_COMPAT
    267     Evc_new_s_context(xid, xid_caps, xid_flags);
    268 #else
    269     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not change context: migrate kernel feature missing and 'compat' API disabled\n");
    270     exit(wrapper_exit_code);
    271 #endif
    272   }
    273 }
    274 
    275 int main(int argc, char * argv[])
    276 {
    277   struct ArgInfo	args = {
    278     .ctx      = VC_DYNAMIC_XID,
    279     .uid      = 99,
    280     .gid      = 99,
    281     .do_fork  = true,
    282     .pid_file = 0,
    283     .chroot   = 0,
    284     .in_ctx   = false,
    285     .flags    = S_CTX_INFO_LOCK,
    286   };
    287   int			pid_fd = -1;
    288 
    289 #ifdef __GLIBC__
    290 #  warning  *** rpm-fake-resolver is built against glibc; please do not report errors before trying a dietlibc version ***
    291   WRITE_MSG(2,
    292 	    "***  rpm-fake-resolver was built with glibc;  please do  ***\n"
    293 	    "***  not report errors before trying a dietlibc version. ***\n");
    294 #endif
    295 
    296   parseArgs(&args, argc, argv);
    297   if (args.pid_file && args.do_fork)
    298     pid_fd = EopenD(args.pid_file, O_CREAT|O_WRONLY, 0644);
    299   
    300   if (args.chroot) Echroot(args.chroot);
    301   Echdir("/");
    302 
    303   activateContext(args.ctx, args.in_ctx, args.caps, args.flags);
    304   Esetgroups(0, &args.gid);
    305   Esetgid(args.gid);
    306   Esetuid(args.uid);
    307 
    308   if (args.do_fork) daemonize(&args, pid_fd);
    309   if (pid_fd!=-1)   close(pid_fd);
    310   run();
    311 }