implemented most parts of the new migrate method
[util-vserver.git] / util-vserver / src / rpm-fake-resolver.c
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_FCNTL     1
48 #include <wrappers.h>
49
50 #define MAX_RQSIZE      0x1000
51
52 int wrapper_exit_code = 1;
53
54 struct ArgInfo {
55     xid_t               ctx;
56     uid_t               uid;
57     gid_t               gid;
58     bool                do_fork;
59     char const *        pid_file;
60     char const *        chroot;
61 };
62
63 static struct option const
64 CMDLINE_OPTIONS[] = {
65   { "help",     no_argument,  0, 'h' },
66   { "version",  no_argument,  0, 'v' },
67   { 0,0,0,0 }
68 };
69
70 static void
71 showHelp(int fd, char const *cmd, int res)
72 {
73   WRITE_MSG(fd, "Usage:  ");
74   WRITE_STR(fd, cmd);
75   WRITE_MSG(fd,
76             " [-c <ctx>] [-u <uid>] [-g <gid>] [-r <chroot>] [-n]\n"
77             "Please report bugs to " PACKAGE_BUGREPORT "\n");
78   exit(res);
79 }
80
81 static void
82 showVersion()
83 {
84   WRITE_MSG(1,
85             "rpm-fake-resolver " VERSION " -- NSS resovler for rpm-fake\n"
86             "This program is part of " PACKAGE_STRING "\n\n"
87             "Copyright (C) 2003 Enrico Scholz\n"
88             VERSION_COPYRIGHT_DISCLAIMER);
89   exit(0);
90 }
91
92
93 inline static void
94 parseArgs(struct ArgInfo *args, int argc, char *argv[])
95 {
96   while (1) {
97     int         c = getopt_long(argc, argv, "c:u:g:r:n", CMDLINE_OPTIONS, 0);
98     if (c==-1) break;
99
100     switch (c) {
101       case 'h'          :  showHelp(1, argv[0], 0);
102       case 'v'          :  showVersion();
103
104       case 'c'          :  args->ctx = atoi(optarg); break;
105       case 'u'          :  args->uid = atoi(optarg); break;
106       case 'g'          :  args->gid = atoi(optarg); break;
107       case 'r'          :  args->chroot  = optarg;   break;
108       case 'n'          :  args->do_fork = false;    break;
109       default           :
110         WRITE_MSG(2, "Try '");
111         WRITE_STR(2, argv[0]);
112         WRITE_MSG(2, " --help\" for more information.\n");
113         exit(1);
114         break;
115     }
116   }
117
118   if (optind!=argc) {
119     WRITE_MSG(2, "No further options allowed; aborting ...\n");
120     exit(1);
121   }
122   
123   if (args->chroot==0) {
124     WRITE_MSG(2, "No chroot specified; aborting...\n");
125     exit(1);
126   }
127 }
128
129 static void
130 sendResult(bool state, uint32_t res)
131 {
132   if (state) {
133     static uint8_t      ONE = 1;
134     Ewrite(1, &ONE, sizeof ONE);
135   }
136   else {
137     static uint8_t      ZERO = 0;
138     Ewrite(1, &ZERO, sizeof ZERO);
139   }
140
141   Ewrite(1, &res, sizeof res);
142 }
143
144 static void
145 do_getpwnam()
146 {
147   uint32_t      len;
148   Eread(0, &len, sizeof len);
149
150   if (len<MAX_RQSIZE) {
151     char                buf[len+1];
152     struct passwd *     res;
153     
154     Eread(0, buf, len);
155     buf[len] = '\0';
156     res = getpwnam(buf);
157     if (res!=0) sendResult(true,  res->pw_uid);
158     else        sendResult(false, -1);
159   }
160   // TODO: logging
161 }
162
163 static void
164 do_getgrnam()
165 {
166   uint32_t      len;
167   Eread(0, &len, sizeof len);
168
169   if (len<MAX_RQSIZE) {
170     char                buf[len+1];
171     struct group *      res;
172     
173     Eread(0, buf, len);
174     buf[len] = '\0';
175     res = getgrnam(buf);
176     if (res!=0) sendResult(true,  res->gr_gid);
177     else        sendResult(false, -1);
178   }
179   // TODO: logging
180 }
181
182 static void
183 do_closenss()
184 {
185   uint8_t       what;
186   Eread(0, &what, sizeof what);
187   switch (what) {
188     case 'p'    :  endpwent(); break;
189     case 'g'    :  endgrent(); break;
190     default     :  break;
191   }
192 }
193
194 static void
195 run()
196 {
197   uint8_t       c;
198
199   while (true) {
200     Ewrite(3, ".", 1);
201     Eread (0, &c,  sizeof c);
202     switch (c) {
203       case 'P'  :  do_getpwnam(); break;
204       case 'G'  :  do_getgrnam(); break;
205       case 'Q'  :  exit(0);
206       case 'C'  :  do_closenss(); break;
207       case '.'  :  Ewrite(1, ".", 1); break;
208       default   :  Ewrite(1, "?", 1); break;
209     }
210   }
211 }
212
213 static void
214 daemonize(struct ArgInfo const UNUSED * args, int pid_fd)
215 {
216   int           p[2];
217   pid_t         pid;
218   char          c;
219   
220   Epipe(p);
221   pid = Efork();
222   
223   if (pid!=0) {
224     if (pid_fd!=-1) {
225       char      buf[sizeof(id_t)*3 + 2];
226       size_t    l;
227
228       l = utilvserver_fmt_uint(buf, pid);
229       Ewrite(pid_fd, buf, l);
230       Ewrite(pid_fd, "\n", 1);
231     }
232     _exit(0);
233   }
234   Eclose(p[1]);
235   read(p[0], &c, 1);
236   Eclose(p[0]);
237 }
238
239 static void
240 activateContext(xid_t xid)
241 {
242   if (vc_isSupported(vcFEATURE_MIGRATE)) {
243 #warning TODO: activate the context here or migrate to it
244     abort();
245   }
246   else 
247     Evc_new_s_context(xid, 0, S_CTX_INFO_LOCK);
248     //Evc_new_s_context(args.ctx, ~(VC_CAP_SETGID|VC_CAP_SETUID), S_CTX_INFO_LOCK);
249 }
250
251 int main(int argc, char * argv[])
252 {
253   struct ArgInfo        args = {
254     .ctx      = VC_DYNAMIC_XID,
255     .uid      = 99,
256     .gid      = 99,
257     .do_fork  = true,
258     .pid_file = 0,
259     .chroot   = 0
260   };
261   int                   pid_fd = -1;
262
263 #ifndef __dietlibc__
264 #  warning  *** rpm-fake-resolver is built against glibc; please do not report errors before trying a dietlibc version ***
265   WRITE_MSG(2,
266             "***  rpm-fake-resolver was built with glibc;  please do  ***\n"
267             "***  not report errors before trying a dietlibc version. ***\n");
268 #endif
269
270   parseArgs(&args, argc, argv);
271   if (args.pid_file && args.do_fork)
272     pid_fd = EopenD(args.pid_file, O_CREAT|O_WRONLY, 0644);
273   
274   if (args.chroot) Echroot(args.chroot);
275   Echdir("/");
276
277   activateContext(args.ctx);
278   Esetgroups(0, &args.gid);
279   Esetgid(args.gid);
280   Esetuid(args.uid);
281
282   if (args.do_fork) daemonize(&args, pid_fd);
283   if (pid_fd!=-1)   close(pid_fd);
284   run();
285 }