Egetrlimit(),Esetrlimit(): added
[util-vserver.git] / util-vserver / src / chcontext.c
1 // $Id$
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on chcontext.cc by Jacques Gelinas
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 //  
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //  
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 /*
21         chcontext is a wrapper to user the new_s_context system call. It
22         does little more than mapping command line option to the system call
23         arguments.
24 */
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28 #include "compat.h"
29
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
35
36 #include "vserver.h"
37
38 static void usage()
39 {
40         fprintf (stderr,"chcontext version %s\n",VERSION);
41         fprintf (stderr
42                 ,"chcontext [ options ] command arguments ...\n"
43                  "\n"
44                  "chcontext allocate a new security context and executes\n"
45                  "a command in that context.\n"
46                  "By default, a new/unused context is allocated\n"
47                  "\n"
48
49                  "--cap CAP_NAME\n"
50                  "\tAdd a capability from the command. This option may be\n"
51                  "\trepeated several time.\n"
52                  "\tSee /usr/include/linux/capability.h\n"
53                  "\tIn general, this option is used with the --secure option\n"
54                  "\t--secure removes most critical capabilities and --cap\n"
55                  "\tadds specific ones.\n"
56                  "\n"
57
58                  "--cap !CAP_NAME\n"
59                  "\tRemove a capability from the command. This option may be\n"
60                  "\trepeated several time.\n"
61                  "\tSee /usr/include/linux/capability.h\n"
62                  "\n"
63                  "--ctx num\n"
64                  "\tSelect the context. On root in context 0 is allowed to\n"
65                  "\tselect a specific context.\n"
66                  "\tContext number 1 is special. It can see all processes\n"
67                  "\tin any contexts, but can't kill them though.\n"
68                  "\tOption --ctx may be repeated several times to specify up to 16 contexts.\n"
69
70                  "--disconnect\n"
71                  "\tStart the command in background and make the process\n"
72                  "\ta child of process 1.\n"
73
74                  "--domainname new_domainname\n"
75                  "\tSet the domainname (NIS) in the new security context.\n"
76                  "\tUse \"none\" to unset the domain name.\n"
77
78                  "--flag\n"
79                  "\tSet one flag in the new or current security context. The following\n"
80                  "\tflags are supported. The option may be used several time.\n"
81                  "\n"
82                  "\tfakeinit: The new process will believe it is process number 1.\n"
83                  "            Useful to run a real /sbin/init in a vserver.\n"
84                  "\tlock: The new process is trapped and can't use chcontext anymore.\n"
85                  "\tsched: The new process and its children will share a common \n"
86                  "         execution priority.\n"
87                  "\tnproc: Limit the number of process in the vserver according to\n"
88                  "         ulimit setting. Normally, ulimit is a per user thing.\n"
89                  "         With this flag, it becomes a per vserver thing.\n"
90                  "\tprivate: No one can join this security context once created.\n"
91                  "\tulimit: Apply the current ulimit to the whole context\n"
92
93                  "--hostname new_hostname\n"
94                  "\tSet the hostname in the new security context\n"
95                  "\tThis is need because if you create a less privileged\n"
96                  "\tsecurity context, it may be unable to change its hostname\n"
97
98                  "--secure\n"
99                  "\tRemove all the capabilities to make a virtual server trustable\n"
100
101                  "--silent\n"
102                  "\tDo not print the allocated context number.\n"
103                  "\n"
104                  "Information about context is found in /proc/self/status\n");
105 }
106
107
108 int main (int argc, char *argv[])
109 {
110         int ret = -1;
111         int i;
112         int nbctx = 0;
113         int ctxs[16];
114         int disconnect = 0;
115         int fakeinit = 0;
116         int silent = 0;
117         int flags = 0;
118         unsigned remove_cap = 0;
119         unsigned add_cap = 0;
120         unsigned long secure = ( (1<<VC_CAP_LINUX_IMMUTABLE)
121                                 |(1<<VC_CAP_NET_BROADCAST)
122                                 |(1<<VC_CAP_NET_ADMIN)
123                                 |(1<<VC_CAP_NET_RAW)
124                                 |(1<<VC_CAP_IPC_LOCK)
125                                 |(1<<VC_CAP_IPC_OWNER)
126                                 |(1<<VC_CAP_SYS_MODULE)
127                                 |(1<<VC_CAP_SYS_RAWIO)
128                                 |(1<<VC_CAP_SYS_PACCT)
129                                 |(1<<VC_CAP_SYS_ADMIN)
130                                 |(1<<VC_CAP_SYS_BOOT)
131                                 |(1<<VC_CAP_SYS_NICE)
132                                 |(1<<VC_CAP_SYS_RESOURCE)
133                                 |(1<<VC_CAP_SYS_TIME)
134                                 |(1<<VC_CAP_MKNOD));
135         const char *hostname=NULL, *domainname=NULL;
136
137         for (i=1; i<argc; i++){
138                 const char *arg = argv[i];
139                 const char *opt = argv[i+1];
140                 if (strcmp(arg,"--ctx")==0){
141                         if (nbctx >= 16){
142                                 fprintf (stderr,"Too many context, max 16, ignored.\n");
143                         }else{
144                                 ctxs[nbctx++] = atoi(opt);
145                         }
146                         i++;
147                 }else if (strcmp(arg,"--disconnect")==0){
148                         disconnect = 1;
149                 }else if (strcmp(arg,"--silent")==0){
150                         silent = 1;
151                 }else if (strcmp(arg,"--flag")==0){
152                         if (strcmp(opt,"lock")==0){
153                                 flags |= 1;
154                         }else if (strcmp(opt,"sched")==0){
155                                 flags |= 2;
156                         }else if (strcmp(opt,"nproc")==0){
157                                 flags |= 4;
158                         }else if (strcmp(opt,"private")==0){
159                                 flags |= 8;
160                         }else if (strcmp(opt,"fakeinit")==0){
161                                 fakeinit = 1;
162                                 flags |= 16;
163                         }else if (strcmp(opt,"hideinfo")==0){
164                                 flags |= 32;
165                         }else if (strcmp(opt,"ulimit")==0){
166                                 flags |= 64;
167                         }else{
168                                 fprintf (stderr,"Unknown flag %s\n",opt);
169                         }
170                         i++;
171                 }else if (strcmp(arg,"--cap")==0){
172                         unsigned *cap = &add_cap;
173                         int      bit;
174
175                         if (opt[0] == '!'){
176                                 cap = &remove_cap;
177                                 opt++;
178                         }
179
180                         bit = vc_text2cap(opt);
181
182                         if (bit!=-1) *cap |= (1<<bit);
183                         else {
184                                 fprintf (stderr,"Unknown capability %s\n",opt);
185                         }
186                         i++;
187                 }else if (strcmp(arg,"--secure")==0){
188                         remove_cap |= secure;
189                 }else if (strcmp(arg,"--hostname")==0){
190                         hostname = opt;
191                         i++;
192                 }else if (strcmp(arg,"--domainname")==0){
193                         if (opt != NULL && strcmp(opt,"none")==0) opt = "";
194                         domainname = opt;
195                         i++;
196                 }else{
197                         break;
198                 }
199         }
200         if (i == argc){
201                 usage();
202         }else if (argv[i][0] == '-'){
203                 usage();
204         }else{
205                 /*
206                         We must fork early because fakeinit set the current
207                         process as the special init process
208                 */
209                 if (disconnect == 0 || fork()==0){
210                         int newctx;
211                         if (nbctx == 0) ctxs[nbctx++] = -1;
212                         newctx = vc_new_s_context(ctxs[0],0,flags);
213                         if (newctx != -1){
214                                 if (hostname != NULL){
215                                         if (sethostname (hostname,strlen(hostname))==-1){
216                                                 fprintf (stderr,"Can't set the host name (%s)\n"
217                                                         ,strerror(errno));
218                                         }else if (!silent){
219                                                 printf ("Host name is now %s\n",hostname);
220                                         }
221                                 }
222                                 if (domainname != NULL){
223                                         setdomainname (domainname,strlen(domainname));
224                                         if (!silent){
225                                                 printf ("Domain name is now %s\n",domainname);
226                                         }
227                                 }
228                                 remove_cap &= (~add_cap);
229                                 if (remove_cap != 0) vc_new_s_context (-2,remove_cap,0);
230                                 if (!silent){
231                                         printf ("New security context is %d\n"
232                                                 ,ctxs[0] == -1 ? newctx : ctxs[0]);
233                                 }
234                                 execvp (argv[i],argv+i);
235                                 fprintf (stderr,"Can't exec %s (%s)\n",argv[i]
236                                         ,strerror(errno));
237                         }else{
238                                 perror ("Can't set the new security context\n");
239                         }
240                         if (disconnect != 0) _exit(0);
241                 }
242         }
243         return ret;
244 }
245