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