1 // $Id: chcontext.c,v 1.1.4.3 2004/01/07 16:24:01 ensc Exp $
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on chcontext.cc by Jacques Gelinas
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)
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.
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.
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
36 #include "linuxcaps.h"
40 # define CAP_QUOTACTL 29
45 fprintf (stderr,"chcontext version %s\n",VERSION);
47 ,"chcontext [ options ] command arguments ...\n"
49 "chcontext allocate a new security context and executes\n"
50 "a command in that context.\n"
51 "By default, a new/unused context is allocated\n"
55 "\tAdd a capability from the command. This option may be\n"
56 "\trepeated several time.\n"
57 "\tSee /usr/include/linux/capability.h\n"
58 "\tIn general, this option is used with the --secure option\n"
59 "\t--secure removes most critical capabilities and --cap\n"
60 "\tadds specific ones.\n"
64 "\tRemove a capability from the command. This option may be\n"
65 "\trepeated several time.\n"
66 "\tSee /usr/include/linux/capability.h\n"
69 "\tSelect the context. On root in context 0 is allowed to\n"
70 "\tselect a specific context.\n"
71 "\tContext number 1 is special. It can see all processes\n"
72 "\tin any contexts, but can't kill them though.\n"
73 "\tOption --ctx may be repeated several times to specify up to 16 contexts.\n"
76 "\tStart the command in background and make the process\n"
77 "\ta child of process 1.\n"
79 "--domainname new_domainname\n"
80 "\tSet the domainname (NIS) in the new security context.\n"
81 "\tUse \"none\" to unset the domain name.\n"
84 "\tSet one flag in the new or current security context. The following\n"
85 "\tflags are supported. The option may be used several time.\n"
87 "\tfakeinit: The new process will believe it is process number 1.\n"
88 " Useful to run a real /sbin/init in a vserver.\n"
89 "\tlock: The new process is trapped and can't use chcontext anymore.\n"
90 "\tsched: The new process and its children will share a common \n"
91 " execution priority.\n"
92 "\tnproc: Limit the number of process in the vserver according to\n"
93 " ulimit setting. Normally, ulimit is a per user thing.\n"
94 " With this flag, it becomes a per vserver thing.\n"
95 "\tprivate: No one can join this security context once created.\n"
96 "\tulimit: Apply the current ulimit to the whole context\n"
98 "--hostname new_hostname\n"
99 "\tSet the hostname in the new security context\n"
100 "\tThis is need because if you create a less privileged\n"
101 "\tsecurity context, it may be unable to change its hostname\n"
104 "\tRemove all the capabilities to make a virtual server trustable\n"
107 "\tDo not print the allocated context number.\n"
109 "Information about context is found in /proc/self/status\n");
113 int main (int argc, char *argv[])
122 unsigned remove_cap = 0;
123 unsigned add_cap = 0;
124 unsigned long secure = (1<<CAP_LINUX_IMMUTABLE)
125 |(1<<CAP_NET_BIND_SERVICE)
126 |(1<<CAP_NET_BROADCAST)
137 |(1<<CAP_SYS_RESOURCE)
141 const char *hostname=NULL, *domainname=NULL;
143 for (i=1; i<argc; i++){
144 const char *arg = argv[i];
145 const char *opt = argv[i+1];
146 if (strcmp(arg,"--ctx")==0){
148 fprintf (stderr,"Too many context, max 16, ignored.\n");
150 ctxs[nbctx++] = atoi(opt);
153 }else if (strcmp(arg,"--disconnect")==0){
155 }else if (strcmp(arg,"--silent")==0){
157 }else if (strcmp(arg,"--flag")==0){
158 if (strcmp(opt,"lock")==0){
160 }else if (strcmp(opt,"sched")==0){
162 }else if (strcmp(opt,"nproc")==0){
164 }else if (strcmp(opt,"private")==0){
166 }else if (strcmp(opt,"fakeinit")==0){
168 }else if (strcmp(opt,"hideinfo")==0){
170 }else if (strcmp(opt,"ulimit")==0){
173 fprintf (stderr,"Unknown flag %s\n",opt);
176 }else if (strcmp(arg,"--cap")==0){
181 // The following capabilities are normally available
182 // to vservers administrator, but are place for
184 {"CAP_CHOWN",CAP_CHOWN},
185 {"CAP_DAC_OVERRIDE",CAP_DAC_OVERRIDE},
186 {"CAP_DAC_READ_SEARCH",CAP_DAC_READ_SEARCH},
187 {"CAP_FOWNER",CAP_FOWNER},
188 {"CAP_FSETID",CAP_FSETID},
189 {"CAP_KILL",CAP_KILL},
190 {"CAP_SETGID",CAP_SETGID},
191 {"CAP_SETUID",CAP_SETUID},
192 {"CAP_SETPCAP",CAP_SETPCAP},
193 {"CAP_SYS_TTY_CONFIG",CAP_SYS_TTY_CONFIG},
194 {"CAP_LEASE",CAP_LEASE},
195 {"CAP_SYS_CHROOT",CAP_SYS_CHROOT},
197 // Those capabilities are not normally available
198 // to vservers because they are not needed and
199 // may represent a security risk
200 {"CAP_LINUX_IMMUTABLE",CAP_LINUX_IMMUTABLE},
201 {"CAP_NET_BIND_SERVICE",CAP_NET_BIND_SERVICE},
202 {"CAP_NET_BROADCAST",CAP_NET_BROADCAST},
203 {"CAP_NET_ADMIN", CAP_NET_ADMIN},
204 {"CAP_NET_RAW", CAP_NET_RAW},
205 {"CAP_IPC_LOCK", CAP_IPC_LOCK},
206 {"CAP_IPC_OWNER", CAP_IPC_OWNER},
207 {"CAP_SYS_MODULE",CAP_SYS_MODULE},
208 {"CAP_SYS_RAWIO", CAP_SYS_RAWIO},
209 {"CAP_SYS_PACCT", CAP_SYS_PACCT},
210 {"CAP_SYS_ADMIN", CAP_SYS_ADMIN},
211 {"CAP_SYS_BOOT", CAP_SYS_BOOT},
212 {"CAP_SYS_NICE", CAP_SYS_NICE},
213 {"CAP_SYS_RESOURCE",CAP_SYS_RESOURCE},
214 {"CAP_SYS_TIME", CAP_SYS_TIME},
215 {"CAP_MKNOD", CAP_MKNOD},
216 {"CAP_QUOTACTL", CAP_QUOTACTL},
220 unsigned *cap = &add_cap;
225 for (j=0; tbcap[j].option != NULL; j++){
226 if (strcasecmp(tbcap[j].option,opt)==0){
227 *cap |= (1<<tbcap[j].bit);
231 if (tbcap[j].option == NULL){
232 fprintf (stderr,"Unknown capability %s\n",opt);
235 }else if (strcmp(arg,"--secure")==0){
236 remove_cap |= secure;
237 }else if (strcmp(arg,"--hostname")==0){
240 }else if (strcmp(arg,"--domainname")==0){
241 if (opt != NULL && strcmp(opt,"none")==0) opt = "";
250 }else if (argv[i][0] == '-'){
254 We must fork early because fakeinit set the current
255 process as the special init process
257 if (disconnect == 0 || fork()==0){
259 int xflags = flags & 16;
261 if (nbctx == 0) ctxs[nbctx++] = -1;
262 newctx = vc_new_s_context(ctxs[0],0,flags&~16);
264 if (hostname != NULL){
265 if (sethostname (hostname,strlen(hostname))==-1){
266 fprintf (stderr,"Can't set the host name (%s)\n"
269 printf ("Host name is now %s\n",hostname);
272 if (domainname != NULL){
273 setdomainname (domainname,strlen(domainname));
275 printf ("Domain name is now %s\n",domainname);
278 remove_cap &= (~add_cap);
279 if (remove_cap!=0 || xflags!=0)
280 vc_new_s_context (-2,remove_cap,xflags);
282 printf ("New security context is %d\n"
283 ,ctxs[0] == -1 ? newctx : ctxs[0]);
285 execvp (argv[i],argv+i);
286 fprintf (stderr,"Can't exec %s (%s)\n",argv[i]
289 perror ("Can't set the new security context\n");
291 if (disconnect != 0) _exit(0);