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