// $Id: chcontext.c,v 1.1.4.3 2004/01/07 16:24:01 ensc Exp $ // Copyright (C) 2003 Enrico Scholz // based on chcontext.cc by Jacques Gelinas // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /* chcontext is a wrapper to user the new_s_context system call. It does little more than mapping command line option to the system call arguments. */ #ifdef HAVE_CONFIG_H # include #endif #include "compat.h" #include #include #include #include #include #include "linuxcaps.h" #include "vserver.h" #ifndef CAP_QUOTACTL # define CAP_QUOTACTL 29 #endif static void usage() { fprintf (stderr,"chcontext version %s\n",VERSION); fprintf (stderr ,"chcontext [ options ] command arguments ...\n" "\n" "chcontext allocate a new security context and executes\n" "a command in that context.\n" "By default, a new/unused context is allocated\n" "\n" "--cap CAP_NAME\n" "\tAdd a capability from the command. This option may be\n" "\trepeated several time.\n" "\tSee /usr/include/linux/capability.h\n" "\tIn general, this option is used with the --secure option\n" "\t--secure removes most critical capabilities and --cap\n" "\tadds specific ones.\n" "\n" "--cap !CAP_NAME\n" "\tRemove a capability from the command. This option may be\n" "\trepeated several time.\n" "\tSee /usr/include/linux/capability.h\n" "\n" "--ctx num\n" "\tSelect the context. On root in context 0 is allowed to\n" "\tselect a specific context.\n" "\tContext number 1 is special. It can see all processes\n" "\tin any contexts, but can't kill them though.\n" "\tOption --ctx may be repeated several times to specify up to 16 contexts.\n" "--disconnect\n" "\tStart the command in background and make the process\n" "\ta child of process 1.\n" "--domainname new_domainname\n" "\tSet the domainname (NIS) in the new security context.\n" "\tUse \"none\" to unset the domain name.\n" "--flag\n" "\tSet one flag in the new or current security context. The following\n" "\tflags are supported. The option may be used several time.\n" "\n" "\tfakeinit: The new process will believe it is process number 1.\n" " Useful to run a real /sbin/init in a vserver.\n" "\tlock: The new process is trapped and can't use chcontext anymore.\n" "\tsched: The new process and its children will share a common \n" " execution priority.\n" "\tnproc: Limit the number of process in the vserver according to\n" " ulimit setting. Normally, ulimit is a per user thing.\n" " With this flag, it becomes a per vserver thing.\n" "\tprivate: No one can join this security context once created.\n" "\tulimit: Apply the current ulimit to the whole context\n" "--hostname new_hostname\n" "\tSet the hostname in the new security context\n" "\tThis is need because if you create a less privileged\n" "\tsecurity context, it may be unable to change its hostname\n" "--secure\n" "\tRemove all the capabilities to make a virtual server trustable\n" "--silent\n" "\tDo not print the allocated context number.\n" "\n" "Information about context is found in /proc/self/status\n"); } int main (int argc, char *argv[]) { int ret = -1; int i; int nbctx = 0; int ctxs[16]; int disconnect = 0; int silent = 0; int flags = 0; unsigned remove_cap = 0; unsigned add_cap = 0; unsigned long secure = (1<= 16){ fprintf (stderr,"Too many context, max 16, ignored.\n"); }else{ ctxs[nbctx++] = atoi(opt); } i++; }else if (strcmp(arg,"--disconnect")==0){ disconnect = 1; }else if (strcmp(arg,"--silent")==0){ silent = 1; }else if (strcmp(arg,"--flag")==0){ if (strcmp(opt,"lock")==0){ flags |= 1; }else if (strcmp(opt,"sched")==0){ flags |= 2; }else if (strcmp(opt,"nproc")==0){ flags |= 4; }else if (strcmp(opt,"private")==0){ flags |= 8; }else if (strcmp(opt,"fakeinit")==0){ flags |= 16; }else if (strcmp(opt,"hideinfo")==0){ flags |= 32; }else if (strcmp(opt,"ulimit")==0){ flags |= 64; }else{ fprintf (stderr,"Unknown flag %s\n",opt); } i++; }else if (strcmp(arg,"--cap")==0){ static struct { const char *option; int bit; }tbcap[]={ // The following capabilities are normally available // to vservers administrator, but are place for // completeness {"CAP_CHOWN",CAP_CHOWN}, {"CAP_DAC_OVERRIDE",CAP_DAC_OVERRIDE}, {"CAP_DAC_READ_SEARCH",CAP_DAC_READ_SEARCH}, {"CAP_FOWNER",CAP_FOWNER}, {"CAP_FSETID",CAP_FSETID}, {"CAP_KILL",CAP_KILL}, {"CAP_SETGID",CAP_SETGID}, {"CAP_SETUID",CAP_SETUID}, {"CAP_SETPCAP",CAP_SETPCAP}, {"CAP_SYS_TTY_CONFIG",CAP_SYS_TTY_CONFIG}, {"CAP_LEASE",CAP_LEASE}, {"CAP_SYS_CHROOT",CAP_SYS_CHROOT}, // Those capabilities are not normally available // to vservers because they are not needed and // may represent a security risk {"CAP_LINUX_IMMUTABLE",CAP_LINUX_IMMUTABLE}, {"CAP_NET_BIND_SERVICE",CAP_NET_BIND_SERVICE}, {"CAP_NET_BROADCAST",CAP_NET_BROADCAST}, {"CAP_NET_ADMIN", CAP_NET_ADMIN}, {"CAP_NET_RAW", CAP_NET_RAW}, {"CAP_IPC_LOCK", CAP_IPC_LOCK}, {"CAP_IPC_OWNER", CAP_IPC_OWNER}, {"CAP_SYS_MODULE",CAP_SYS_MODULE}, {"CAP_SYS_RAWIO", CAP_SYS_RAWIO}, {"CAP_SYS_PACCT", CAP_SYS_PACCT}, {"CAP_SYS_ADMIN", CAP_SYS_ADMIN}, {"CAP_SYS_BOOT", CAP_SYS_BOOT}, {"CAP_SYS_NICE", CAP_SYS_NICE}, {"CAP_SYS_RESOURCE",CAP_SYS_RESOURCE}, {"CAP_SYS_TIME", CAP_SYS_TIME}, {"CAP_MKNOD", CAP_MKNOD}, {"CAP_QUOTACTL", CAP_QUOTACTL}, {NULL,0} }; int j; unsigned *cap = &add_cap; if (opt[0] == '!'){ cap = &remove_cap; opt++; } for (j=0; tbcap[j].option != NULL; j++){ if (strcasecmp(tbcap[j].option,opt)==0){ *cap |= (1<