modernized declarations (use WRAPPER_DECL)
[util-vserver.git] / util-vserver / src / vcontext.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2004 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 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "util.h"
24 #include "lib/internal.h"
25
26 #include <vserver.h>
27 #include <getopt.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 #define ENSC_WRAPPERS_PREFIX    "vcontext: "
32 #define ENSC_WRAPPERS_UNISTD    1
33 #define ENSC_WRAPPERS_VSERVER   1
34 #define ENSC_WRAPPERS_FCNTL     1
35 #include <wrappers.h>
36
37 #define CMD_HELP                0x1000
38 #define CMD_VERSION             0x1001
39 #define CMD_XID                 0x4000
40 #define CMD_CREATE              0x4001
41 #define CMD_MIGRATE             0x4003
42 #define CMD_FAKEINIT            0x4002
43 #define CMD_DISCONNECT          0x4004
44 #define CMD_UID                 0x4005
45 #define CMD_CHROOT              0x4006
46 #define CMD_SILENT              0x4007
47
48 struct option const
49 CMDLINE_OPTIONS[] = {
50   { "help",       no_argument,       0, CMD_HELP },
51   { "version",    no_argument,       0, CMD_VERSION },
52   { "ctx",        required_argument, 0, CMD_XID },
53   { "xid",        required_argument, 0, CMD_XID },
54   { "create",     no_argument,       0, CMD_CREATE },
55   { "migrate",    no_argument,       0, CMD_MIGRATE },
56   { "fakeinit",   no_argument,       0, CMD_FAKEINIT },
57   { "disconnect", no_argument,       0, CMD_DISCONNECT },
58   { "silent",     no_argument,       0, CMD_SILENT },
59   { "uid",        no_argument,       0, CMD_UID },
60   { "chroot",     no_argument,       0, CMD_CHROOT },
61   { 0,0,0,0 },
62 };
63
64 struct Arguments {
65     bool                do_create;
66     bool                do_migrate;
67     bool                do_disconnect;
68     bool                is_fakeinit;
69     int                 verbosity;
70     bool                do_chroot;
71     uid_t               uid;
72     xid_t               xid;
73 };
74
75 int             wrapper_exit_code = 255;
76
77 static void
78 showHelp(int fd, char const *cmd, int res)
79 {
80   WRITE_MSG(fd, "Usage:\n    ");
81   WRITE_STR(fd, cmd);
82   WRITE_MSG(fd,
83             " --create [--xid <xid>] <opts>* [--] <program> <args>*\n    ");
84   WRITE_STR(fd, cmd);
85   WRITE_MSG(fd,
86             " --migrate --xid <xid>  <opts>* [--] <program> <args>*\n"
87             "\n"
88             "<opts> can be:\n"
89             "    --chroot        ...  chroot into current directory\n"
90             "    --uid <uid>     ...  change uid\n"
91             "    --fakeinit      ...  set current process as general process reaper\n"
92             "                         for ctx (possible for --migrate only)\n"
93             "    --silent        ...  be silent\n"
94             "\n"
95             "Please report bugs to " PACKAGE_BUGREPORT "\n");
96
97   exit(res);
98 }
99
100 static void
101 showVersion()
102 {
103   WRITE_MSG(1,
104             "vcontext " VERSION " -- manages the creation of security contexts\n"
105             "This program is part of " PACKAGE_STRING "\n\n"
106             "Copyright (C) 2004 Enrico Scholz\n"
107             VERSION_COPYRIGHT_DISCLAIMER);
108   exit(0);
109 }
110
111 static inline ALWAYSINLINE int
112 initSync(int p[2], bool do_disconnect)
113 {
114   if (!do_disconnect) return 0;
115
116   Epipe(p);
117   fcntl(p[1], F_SETFD, FD_CLOEXEC);
118   return Efork();
119 }
120
121 static inline ALWAYSINLINE void
122 doSyncStage1(int p[2], bool do_disconnect)
123 {
124   int   fd;
125
126   if (!do_disconnect) return;
127   
128   fd = Eopen("/dev/null", O_RDONLY, 0);
129   Esetsid();
130   Edup2(fd, 0);
131   Eclose(p[0]);
132   if (fd!=0) Eclose(fd);
133   Ewrite(p[1], ".", 1);
134 }
135
136 static inline ALWAYSINLINE void
137 doSyncStage2(int p[2], bool do_disconnect)
138 {
139   if (!do_disconnect) return;
140
141   Ewrite(p[1], "X", 1);
142 }
143
144 static void
145 waitOnSync(pid_t pid, int p[2])
146 {
147   int           c;
148   size_t        l;
149
150   Eclose(p[1]);
151   l = Eread(p[0], &c, 1);
152   if (l!=1) exitLikeProcess(pid);
153   l = Eread(p[0], &c, 1);
154   if (l!=0) exitLikeProcess(pid);
155 }
156
157 static inline ALWAYSINLINE void
158 tellContext(xid_t ctx, bool do_it)
159 {
160   char          buf[sizeof(xid_t)*3+2];
161   size_t        l;
162
163   if (!do_it) return;
164
165   l = utilvserver_fmt_long(buf,ctx);
166
167   WRITE_MSG(2, "New security context is ");
168   write(2, buf, l);
169   WRITE_MSG(2, "\n");
170 }
171
172 static inline ALWAYSINLINE int
173 doit(struct Arguments const *args, char *argv[])
174 {
175   int                   p[2];
176   pid_t                 pid = initSync(p, args->do_disconnect);
177   
178   if (pid==0) {
179     xid_t       xid;
180     if (args->do_create) {
181       xid = Evc_create_context(args->xid);
182       tellContext(xid, args->verbosity>=1);
183     }
184     else
185       xid = args->xid;
186
187     if (args->do_chroot)
188       Echroot(".");
189
190     if (args->uid!=(uid_t)(-1) && getuid()!=args->uid) {
191       Esetuid(args->uid);
192       if (getuid()!=args->uid) {
193         WRITE_MSG(2, "vcontext: Something went wrong while changing the UID\n");
194         exit(255);
195       }
196     }
197
198     if (args->is_fakeinit) {
199       struct vc_ctx_flags       flags;
200       Evc_get_flags(xid, &flags);
201 #warning !!! IMPLEMENT ME !!!
202         //if (flags.mask
203       if (0) {
204         WRITE_MSG(2, "vcontext: context has already a fakeinit-process\n");
205         exit(255);
206       }
207     }
208
209     if (args->do_migrate)
210       Evc_migrate_context(xid);
211
212     doSyncStage1(p, args->do_disconnect);
213     execvp (argv[optind],argv+optind);
214     doSyncStage2(p, args->do_disconnect);
215
216     PERROR_Q("chcontext: execvp", argv[optind]);
217     exit(255);
218   }
219
220   waitOnSync(pid, p);
221   return EXIT_SUCCESS;
222 }
223
224 int main (int argc, char *argv[])
225 {
226   struct Arguments              args = {
227     .do_create     = false,
228     .do_migrate    = false,
229     .do_disconnect = false,
230     .is_fakeinit   = false,
231     .verbosity     = 1,
232     .uid           = -1,
233     .xid           = VC_DYNAMIC_XID,
234   };
235   
236   while (1) {
237     int         c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
238     if (c==-1) break;
239     
240     switch (c) {
241       case CMD_HELP             :  showHelp(1, argv[0], 0);
242       case CMD_VERSION          :  showVersion();
243       case CMD_CREATE           :  args.do_create     = true; break;
244       case CMD_MIGRATE          :  args.do_migrate    = true; break;
245       case CMD_DISCONNECT       :  args.do_disconnect = true; break;
246       case CMD_FAKEINIT         :  args.is_fakeinit   = true; break;
247       case CMD_CHROOT           :  args.do_chroot     = true; break;
248       case CMD_SILENT           :  --args.verbosity;          break;
249       case CMD_XID              :  args.xid           = atol(optarg); break;
250       case CMD_UID              :  args.uid           = atol(optarg); break;
251
252       default           :
253         WRITE_MSG(2, "Try '");
254         WRITE_STR(2, argv[0]);
255         WRITE_MSG(2, " --help\" for more information.\n");
256         return 255;
257         break;
258     }
259   }
260
261   if (!args.do_create && !args.do_migrate)
262     WRITE_MSG(2, "Neither '--create' nor '--migrate specified; try '--help' for more information\n");
263   else if (args.do_create  &&  args.do_migrate)
264     WRITE_MSG(2, "Can not specify '--create' and '--migrate' at the same time; try '--help' for more information\n");
265   else if (!args.do_migrate && args.is_fakeinit)
266     WRITE_MSG(2, "'--fakeinit' is possible in combination with '--migrate' only\n");
267   else if (!args.do_create && args.xid==VC_DYNAMIC_XID)
268     WRITE_MSG(2, "vcontext: Can not migrate to an unknown context\n");
269   else if (optind>=argc)
270     WRITE_MSG(2, "No command given; use '--help' for more information.\n");
271   else
272     return doit(&args, argv);
273
274   return 255;
275 }