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