X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fvsh.c;h=cadafc5a6b7ccc745b1e6fb3c26944a9afa97dc0;hb=5594cc4c22c895396adc5c59d39b294f7b171de1;hp=0ec80a8a243dff5c59028579c6ccb1061ec2d1a1;hpb=521cecd5317bca492230bcba4a839267341d12c2;p=util-vserver.git diff --git a/src/vsh.c b/src/vsh.c index 0ec80a8..cadafc5 100644 --- a/src/vsh.c +++ b/src/vsh.c @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -37,15 +37,16 @@ #include #include #include +#include #include #include +#include //-------------------------------------------------------------------- -#include "linuxcaps.h" #include "vserver.h" +#include "planetlab.h" -/* Null byte made explicit */ -#define NULLBYTE_SIZE 1 +#undef CONFIG_VSERVER_LEGACY /* Base for all vserver roots for chroot */ #define VSERVER_ROOT_BASE "/vservers" @@ -54,32 +55,26 @@ static int setuidgid_root() { if (setgid(0) < 0) { - fprintf(stderr, "setgid error\n"); + PERROR("setgid(0)"); return -1; } if (setuid(0) < 0) { - fprintf(stderr, "setuid error\n"); + PERROR("setuid(0)"); return -1; } return 0; } -static void compute_new_root(char *base, char **root, uid_t uid) +static void compute_new_root(char *base, char **root, const struct passwd *pwd) { int root_len; - struct passwd *pwd; - - if ((pwd = getpwuid(uid)) == NULL) { - perror("vserver: getpwuid error "); - exit(1); - } root_len = strlen(base) + strlen("/") + strlen(pwd->pw_name) + NULLBYTE_SIZE; (*root) = (char *)malloc(root_len); if ((*root) == NULL) { - perror("vserver: malloc error "); + PERROR("malloc(%d)", root_len); exit(1); } @@ -87,334 +82,94 @@ static void compute_new_root(char *base, char **root, uid_t uid) (*root)[root_len - 1] = '\0'; } -/* Example: sandbox_root = /vservers/bnc, relpath = /proc/1 */ -static int sandbox_file_exists(char *sandbox_root, char *relpath) -{ - struct stat stat_buf; - char *file; - int len, exists = 0; - - len = strlen(sandbox_root) + strlen(relpath) + NULLBYTE_SIZE; - if ((file = (char *)malloc(len)) == NULL) { - perror("vserver: malloc error "); - exit(1); - } - sprintf(file, "%s%s", sandbox_root, relpath); - file[len - 1] = '\0'; - if (stat(file, &stat_buf) == 0) { - exists = 1; - } - - - free(file); - return exists; -} - -static int proc_mounted(char *sandbox_root) -{ - return sandbox_file_exists(sandbox_root, "/proc/1"); -} - -static int devpts_mounted(char *sandbox_root) -{ - return sandbox_file_exists(sandbox_root, "/dev/pts/0"); -} - -static void mount_proc(char *sandbox_root,uid_t uid) -{ - char *source = "/proc"; - char *target; - int len; - - len = strlen(sandbox_root) + strlen("/") + strlen("proc") + NULLBYTE_SIZE; - if ((target = (char *)malloc(len)) == NULL) { - perror("vserver: malloc error "); - exit(1); - } - - sprintf(target, "%s/proc", sandbox_root); - target[len - 1] = '\0'; - if (!proc_mounted(sandbox_root)) - mount(source, target, "proc", MS_BIND | MS_RDONLY, NULL); - - free(target); -} - -static void mount_devpts(char *sandbox_root) -{ - char *source = "/dev/pts"; - char *target; - int len; - - len = strlen(sandbox_root) + strlen("/") + strlen("dev/pts") + NULLBYTE_SIZE; - if ((target = (char *)malloc(len)) == NULL) { - perror("vserver: malloc error "); - exit(1); - } - - sprintf(target, "%s/dev/pts", sandbox_root); - target[len - 1] = '\0'; - if (!devpts_mounted(sandbox_root)) - mount(source, target, "devpts", 0, NULL); - - free(target); -} - -static int sandbox_chroot(uid_t uid) +static int sandbox_chroot(const struct passwd *pwd) { char *sandbox_root = NULL; - compute_new_root(VSERVER_ROOT_BASE,&sandbox_root, uid); - mount_proc(sandbox_root,uid); - mount_devpts(sandbox_root); + compute_new_root(VSERVER_ROOT_BASE,&sandbox_root, pwd); if (chroot(sandbox_root) < 0) { - fprintf(stderr,"vserver: chroot error (%s): ",sandbox_root); - perror(""); + PERROR("chroot(%s)", sandbox_root); exit(1); } if (chdir("/") < 0) { - perror("vserver: chdir error "); + PERROR("chdir(/)"); exit(1); } return 0; } -#ifndef CAP_CONTEXT -# define CAP_CONTEXT 29 -#endif - -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_CONTEXT", CAP_CONTEXT}, - {NULL,0} -}; - -#define VSERVERCONF "/etc/vservers/" -static unsigned get_remove_cap(char *name) { - FILE *fb; - unsigned remove_cap; - - char *vserverconf; - int vserverconflen; - - remove_cap = /* NOTE: keep in sync with chcontext.c */ - (1<pw_name; char *home_env, *logname_env, *mail_env, *shell_env, *user_env; int home_len, logname_len, mail_len, shell_len, user_len; static char *envp[10]; - if ((pwd = getpwnam(username)) == NULL) { - perror("vserver: getpwnam error "); - exit(1); - } - if (setgid(pwd->pw_gid) < 0) { - perror("vserver: setgid error "); + PERROR("setgid(%d)", pwd->pw_gid); exit(1); } if (setuid(pwd->pw_uid) < 0) { - perror("vserver: setuid error "); + PERROR("setuid(%d)", pwd->pw_uid); exit(1); } if (chdir(pwd->pw_dir) < 0) { - perror("vserver: chdir error "); + PERROR("chdir(%s)", pwd->pw_dir); exit(1); } @@ -436,7 +191,7 @@ void runas_slice_user(char *username) (mail_env == NULL) || (shell_env == NULL) || (user_env == NULL)) { - perror("vserver: malloc error "); + PERROR("malloc"); exit(1); } @@ -464,46 +219,24 @@ void runas_slice_user(char *username) (putenv(mail_env) < 0) || (putenv(shell_env) < 0) || (putenv(user_env) < 0)) { - perror("vserver: putenv error "); + PERROR("vserver: putenv error "); exit(1); } } - - -void slice_enter(char *context) +void slice_enter(struct passwd *pwd) { - struct passwd *pwd; - unsigned remove_cap; - uid_t uid; - - if ((pwd = getpwnam(context)) == NULL) { - fprintf(stderr,"vserver: getpwname(%s) failed",context); - exit(2); - } - - context = (char*)malloc(strlen(pwd->pw_name)+NULLBYTE_SIZE); - if (!context) { - perror("vserver: malloc failed"); - exit(2); - } - strcpy(context,pwd->pw_name); - if (setuidgid_root() < 0) { /* For chroot, new_s_context */ - fprintf(stderr,"vserver: Could not setuid/setguid to root:root\n"); + fprintf(stderr, "vsh: Could not become root, check that SUID flag is set on binary\n"); exit(2); } - remove_cap = get_remove_cap(context); - - uid = pwd->pw_uid; - if (sandbox_chroot(uid) < 0) { - fprintf(stderr, "vserver: Could not chroot to vserver root\n"); - exit(2); - } +#ifdef CONFIG_VSERVER_LEGACY + (void) (sandbox_chroot(pwd)); +#endif - if (sandbox_processes(uid, remove_cap) < 0) { - fprintf(stderr, "vserver: Could not sandbox processes in vserver\n"); + if (sandbox_processes((xid_t) pwd->pw_uid, pwd->pw_name, pwd) < 0) { + fprintf(stderr, "vsh: Could not change context to %d\n", pwd->pw_uid); exit(2); } } @@ -520,15 +253,13 @@ enum EXIT_ENOENT = 127 }; -extern void slice_enter(char *); -extern void runas_slice_user(char *); - int main(int argc, char **argv) { - char *context, *username, *shell; - struct passwd *pwd; + struct passwd pwdd, *result, *prechroot, *postchroot = &pwdd; + char *context, *username, *shell, *pwdBuffer; + long pwdBuffer_len; uid_t uid; - int index, i; + int index, i; if (argv[0][0]=='-') index = 1; @@ -536,43 +267,57 @@ int main(int argc, char **argv) index = 0; uid = getuid(); - if ((pwd = getpwuid(uid)) == NULL) { - fprintf(stderr,"vsh: getpwnam error failed for %d\n",uid); + if ((prechroot = getpwuid(uid)) == NULL) { + PERROR("getpwuid(%d)", uid); exit(1); } - context = (char*)strdup(pwd->pw_name); + context = (char*)strdup(prechroot->pw_name); if (!context) { - perror("vsh: strdup failed"); + PERROR("strdup"); exit(2); } /* enter vserver "context" */ - slice_enter(context); + slice_enter(prechroot); - /* Now run as username in this context. Note that for PlanetLab's - vserver configuration the context name also happens to be the - "default" username within the vserver context. - */ + /* Get the /etc/passwd entry for this user, this time inside + * the chroot. + */ username = context; - runas_slice_user(username); - /* With the uid/gid appropriately set. Let's figure out what the - * shell in the vserver's /etc/passwd is for the given username. - */ - if ((pwd = getpwnam(username)) == NULL) { - fprintf(stderr,"vsh: getpwnam error failed for %s\n",username); + pwdBuffer_len = sysconf(_SC_GETPW_R_SIZE_MAX); + if (pwdBuffer_len == -1) { + PERROR("sysconf(_SC_GETPW_R_SIZE_MAX"); + exit(1); + } + pwdBuffer = (char*)malloc(pwdBuffer_len); + if (pwdBuffer == NULL) { + PERROR("malloc(%d)", pwdBuffer_len); + exit(1); + } + + errno = 0; + if ((getpwnam_r(username,postchroot,pwdBuffer,pwdBuffer_len, &result) != 0) || + (errno != 0) || result != postchroot) { + PERROR("getpwnam_r(%s)", username); exit(1); } + /* Now run as username in this context. Note that for PlanetLab's + vserver configuration the context name also happens to be the + "default" username within the vserver context. + */ + runas_slice_user(postchroot); + /* Make sure pw->pw_shell is non-NULL.*/ - if (pwd->pw_shell == NULL || pwd->pw_shell[0] == '\0') { - pwd->pw_shell = (char *) DEFAULT_SHELL; + if (postchroot->pw_shell == NULL || postchroot->pw_shell[0] == '\0') { + postchroot->pw_shell = (char *) DEFAULT_SHELL; } - shell = (char *)strdup(pwd->pw_shell); + shell = (char *)strdup(postchroot->pw_shell); if (!shell) { - perror("vsh: strdup failed"); + PERROR("strdup"); exit(2); } @@ -584,7 +329,8 @@ int main(int argc, char **argv) char **args; args = (char**)malloc(sizeof(char*)*(argc+2)); if (!args) { - perror("vsh: malloc failed"); + PERROR("malloc(%d)", sizeof(char*)*(argc+2)); + exit(1); } args[0] = argv[0]; args[1] = "-l";