5420d5e4969dbfc98f85a4f6225691403d13f141
[util-vserver.git] / src / rpm-fake-resolver.c
1 // $Id: rpm-fake-resolver.c,v 1.15 2005/07/03 13:16:34 ensc Exp $    --*- 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 xid_caps, int 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);
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 #ifndef __dietlibc__
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 }