--- embedaddon/sudo/src/sudo.c 2012/02/21 16:23:02 1.1 +++ embedaddon/sudo/src/sudo.c 2012/05/29 12:26:49 1.1.1.2 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2011 Todd C. Miller + * Copyright (c) 2009-2012 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,9 +25,6 @@ #include #include #include -#ifdef HAVE_SYS_SELECT_H -# include -#endif /* HAVE_SYS_SELECT_H */ #include #include #include @@ -66,6 +63,9 @@ #endif #ifdef HAVE_LOGIN_CAP_H # include +# ifndef LOGIN_SETENV +# define LOGIN_SETENV 0 +# endif #endif #ifdef HAVE_PROJECT_H # include @@ -86,8 +86,11 @@ # endif /* __hpux */ # include #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ -#ifdef HAVE_PRIV_SET -# include +#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) +# include +#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) +# include +# include #endif #include "sudo.h" @@ -102,25 +105,17 @@ struct plugin_container policy_plugin; struct plugin_container_list io_plugins; struct user_details user_details; const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */ -int debug_level; +static int sudo_mode; /* * Local functions */ static void fix_fds(void); static void disable_coredumps(void); +static void sudo_check_suid(const char *path); static char **get_user_info(struct user_details *); static void command_info_to_details(char * const info[], struct command_details *details); -static int policy_open(struct plugin_container *plugin, char * const settings[], - char * const user_info[], char * const user_env[]); -static void policy_close(struct plugin_container *plugin, int exit_status, - int error); -static int iolog_open(struct plugin_container *plugin, char * const settings[], - char * const user_info[], char * const command_details[], - int argc, char * const argv[], char * const user_env[]); -static void iolog_close(struct plugin_container *plugin, int exit_status, - int error); /* Policy plugin convenience functions. */ static int policy_open(struct plugin_container *plugin, char * const settings[], @@ -135,8 +130,6 @@ static int policy_list(struct plugin_container *plugin char * const argv[], int verbose, const char *list_user); static int policy_validate(struct plugin_container *plugin); static void policy_invalidate(struct plugin_container *plugin, int remove); -static int policy_init_session(struct plugin_container *plugin, - struct passwd *pwd); /* I/O log plugin convenience functions. */ static int iolog_open(struct plugin_container *plugin, char * const settings[], @@ -145,10 +138,11 @@ static int iolog_open(struct plugin_container *plugin, static void iolog_close(struct plugin_container *plugin, int exit_status, int error); static int iolog_show_version(struct plugin_container *plugin, int verbose); +static void iolog_unlink(struct plugin_container *plugin); -#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) +#ifdef RLIMIT_CORE static struct rlimit corelimit; -#endif /* RLIMIT_CORE && !SUDO_DEVEL */ +#endif /* RLIMIT_CORE */ #if defined(__linux__) static struct rlimit nproclimit; #endif @@ -156,16 +150,19 @@ static struct rlimit nproclimit; int main(int argc, char *argv[], char *envp[]) { - int nargc, sudo_mode, exitcode = 0; + int nargc, ok, exitcode = 0; char **nargv, **settings, **env_add; char **user_info, **command_info, **argv_out, **user_env_out; struct plugin_container *plugin, *next; struct command_details command_details; sigset_t mask; - int ok; + debug_decl(main, SUDO_DEBUG_MAIN) + #if defined(SUDO_DEVEL) && defined(__OpenBSD__) - extern char *malloc_options; - malloc_options = "AFGJPR"; + { + extern char *malloc_options; + malloc_options = "AFGJPR"; + } #endif #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) @@ -187,22 +184,27 @@ main(int argc, char *argv[], char *envp[]) # endif #endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ - if (geteuid() != 0) - errorx(1, _("must be setuid root")); + /* Make sure we are setuid root. */ + sudo_check_suid(argv[0]); - /* Reset signal mask, disable core dumps and make sure fds 0-2 are open. */ + /* Reset signal mask and make sure fds 0-2 are open. */ (void) sigemptyset(&mask); (void) sigprocmask(SIG_SETMASK, &mask, NULL); - disable_coredumps(); fix_fds(); /* Fill in user_info with user name, uid, cwd, etc. */ memset(&user_details, 0, sizeof(user_details)); user_info = get_user_info(&user_details); + /* Read sudo.conf. */ + sudo_conf_read(); + + /* Disable core dumps if not enabled in sudo.conf. */ + disable_coredumps(); + /* Parse command line arguments. */ sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add); - sudo_debug(9, "sudo_mode %d", sudo_mode); + sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode); /* Print sudo version early, in case of plugin init failure. */ if (ISSET(sudo_mode, MODE_VERSION)) { @@ -211,13 +213,13 @@ main(int argc, char *argv[], char *envp[]) (void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS); } - /* Read sudo.conf and load plugins. */ - if (!sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins)) + /* Load plugins. */ + if (!sudo_load_plugins(&policy_plugin, &io_plugins)) errorx(1, _("fatal error, unable to load plugins")); /* Open policy plugin. */ ok = policy_open(&policy_plugin, settings, user_info, envp); - if (ok != TRUE) { + if (ok != 1) { if (ok == -2) usage(1); else @@ -230,14 +232,14 @@ main(int argc, char *argv[], char *envp[]) tq_foreach_fwd(&io_plugins, plugin) { ok = iolog_open(plugin, settings, user_info, NULL, nargc, nargv, envp); - if (ok == TRUE) + if (ok == 1) iolog_show_version(plugin, !user_details.uid); } break; case MODE_VALIDATE: case MODE_VALIDATE|MODE_INVALIDATE: ok = policy_validate(&policy_plugin); - exit(ok != TRUE); + exit(ok != 1); case MODE_KILL: case MODE_INVALIDATE: policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL); @@ -249,13 +251,13 @@ main(int argc, char *argv[], char *envp[]) case MODE_LIST|MODE_INVALIDATE: ok = policy_list(&policy_plugin, nargc, nargv, ISSET(sudo_mode, MODE_LONG_LIST), list_user); - exit(ok != TRUE); + exit(ok != 1); case MODE_EDIT: case MODE_RUN: ok = policy_check(&policy_plugin, nargc, nargv, env_add, &command_info, &argv_out, &user_env_out); - sudo_debug(8, "policy plugin returns %d", ok); - if (ok != TRUE) { + sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok); + if (ok != 1) { if (ok == -2) usage(1); exit(1); /* plugin printed error message */ @@ -266,11 +268,11 @@ main(int argc, char *argv[], char *envp[]) ok = iolog_open(plugin, settings, user_info, command_info, nargc, nargv, envp); switch (ok) { - case TRUE: + case 1: break; - case FALSE: - /* I/O plugin asked to be disabled, remove from list. */ - tq_remove(&io_plugins, plugin); + case 0: + /* I/O plugin asked to be disabled, remove and free. */ + iolog_unlink(plugin); break; case -2: usage(1); @@ -280,15 +282,19 @@ main(int argc, char *argv[], char *envp[]) plugin->name); } } + /* Setup command details and run command/edit. */ command_info_to_details(command_info, &command_details); command_details.argv = argv_out; command_details.envp = user_env_out; if (ISSET(sudo_mode, MODE_BACKGROUND)) SET(command_details.flags, CD_BACKGROUND); + /* Become full root (not just setuid) so user cannot kill us. */ + (void) setuid(ROOT_UID); /* Restore coredumpsize resource limit before running. */ -#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) - (void) setrlimit(RLIMIT_CORE, &corelimit); -#endif /* RLIMIT_CORE && !SUDO_DEVEL */ +#ifdef RLIMIT_CORE + if (sudo_conf_disable_coredump()) + (void) setrlimit(RLIMIT_CORE, &corelimit); +#endif /* RLIMIT_CORE */ if (ISSET(command_details.flags, CD_SUDOEDIT)) { exitcode = sudo_edit(&command_details); } else { @@ -299,6 +305,7 @@ main(int argc, char *argv[], char *envp[]) default: errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode); } + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); exit(exitcode); } @@ -310,6 +317,7 @@ static void fix_fds(void) { int miss[3], devnull = -1; + debug_decl(fix_fds, SUDO_DEBUG_UTIL) /* * stdin, stdout and stderr must be open; set them to /dev/null @@ -330,6 +338,7 @@ fix_fds(void) if (devnull > STDERR_FILENO) close(devnull); } + debug_return; } /* @@ -340,6 +349,7 @@ static int fill_group_list(struct user_details *ud) { int maxgroups, tries, rval = -1; + debug_decl(fill_group_list, SUDO_DEBUG_UTIL) #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) maxgroups = (int)sysconf(_SC_NGROUPS_MAX); @@ -360,7 +370,7 @@ fill_group_list(struct user_details *ud) ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); } - return rval; + debug_return_int(rval); } static char * @@ -369,6 +379,7 @@ get_user_groups(struct user_details *ud) char *cp, *gid_list = NULL; size_t glsize; int i, len; + debug_decl(get_user_groups, SUDO_DEBUG_UTIL) /* * Systems with mbr_check_membership() support more than NGROUPS_MAX @@ -402,7 +413,7 @@ get_user_groups(struct user_details *ud) i ? "," : "", (unsigned int)ud->groups[i]); cp += len; } - return gid_list; + debug_return_str(gid_list); } /* @@ -412,15 +423,25 @@ get_user_groups(struct user_details *ud) static char ** get_user_info(struct user_details *ud) { - char cwd[PATH_MAX]; - char host[MAXHOSTNAMELEN]; - char **user_info, *cp; + char *cp, **user_info, cwd[PATH_MAX], host[MAXHOSTNAMELEN]; struct passwd *pw; - int i = 0; + int fd, i = 0; + debug_decl(get_user_info, SUDO_DEBUG_UTIL) /* XXX - bound check number of entries */ user_info = emalloc2(32, sizeof(char *)); + ud->pid = getpid(); + ud->ppid = getppid(); + ud->pgid = getpgid(0); + ud->tcpgid = (pid_t)-1; + fd = open(_PATH_TTY, O_RDWR|O_NOCTTY|O_NONBLOCK, 0); + if (fd != -1) { + ud->tcpgid = tcgetpgrp(fd); + close(fd); + } + ud->sid = getsid(0); + ud->uid = getuid(); ud->euid = geteuid(); ud->gid = getgid(); @@ -441,6 +462,12 @@ get_user_info(struct user_details *ud) } ud->shell = estrdup(ud->shell); + easprintf(&user_info[++i], "pid=%d", (int)ud->pid); + easprintf(&user_info[++i], "ppid=%d", (int)ud->ppid); + easprintf(&user_info[++i], "pgid=%d", (int)ud->pgid); + easprintf(&user_info[++i], "tcpgid=%d", (int)ud->tcpgid); + easprintf(&user_info[++i], "sid=%d", (int)ud->sid); + easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid); easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid); easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid); @@ -456,12 +483,12 @@ get_user_info(struct user_details *ud) ud->cwd = user_info[i] + sizeof("cwd=") - 1; } - if ((cp = ttyname(STDIN_FILENO)) || (cp = ttyname(STDOUT_FILENO)) || - (cp = ttyname(STDERR_FILENO))) { + if ((cp = get_process_ttyname()) != NULL) { user_info[++i] = fmt_string("tty", cp); if (user_info[i] == NULL) errorx(1, _("unable to allocate memory")); ud->tty = user_info[i] + sizeof("tty=") - 1; + efree(cp); } if (gethostname(host, sizeof(host)) == 0) @@ -479,7 +506,7 @@ get_user_info(struct user_details *ud) user_info[++i] = NULL; - return user_info; + debug_return_ptr(user_info); } /* @@ -492,6 +519,7 @@ command_info_to_details(char * const info[], struct co long lval; unsigned long ulval; char *cp, *ep; + debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM) memset(details, 0, sizeof(*details)); details->closefrom = -1; @@ -502,8 +530,9 @@ command_info_to_details(char * const info[], struct co break; \ } + sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:"); for (i = 0; info[i] != NULL; i++) { - sudo_debug(9, "command info: %s", info[i]); + sudo_debug_printf(SUDO_DEBUG_INFO, " %d: %s", i, info[i]); switch (info[i][0]) { case 'c': SET_STRING("chroot=", chroot) @@ -545,21 +574,14 @@ command_info_to_details(char * const info[], struct co break; } if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) { - if (atobool(info[i] + sizeof("noexec=") - 1) == TRUE) + if (atobool(info[i] + sizeof("noexec=") - 1) == true) SET(details->flags, CD_NOEXEC); break; } -#ifdef _PATH_SUDO_NOEXEC - /* XXX - deprecated */ - if (strncmp("noexec_file=", info[i], sizeof("noexec_file=") - 1) == 0) { - noexec_path = info[i] + sizeof("noexec_file=") - 1; - break; - } -#endif /* _PATH_SUDO_NOEXEC */ break; case 'p': if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) { - if (atobool(info[i] + sizeof("preserve_groups=") - 1) == TRUE) + if (atobool(info[i] + sizeof("preserve_groups=") - 1) == true) SET(details->flags, CD_PRESERVE_GROUPS); break; } @@ -653,12 +675,12 @@ command_info_to_details(char * const info[], struct co SET_STRING("selinux_role=", selinux_role) SET_STRING("selinux_type=", selinux_type) if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) { - if (atobool(info[i] + sizeof("set_utmp=") - 1) == TRUE) + if (atobool(info[i] + sizeof("set_utmp=") - 1) == true) SET(details->flags, CD_SET_UTMP); break; } if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) { - if (atobool(info[i] + sizeof("sudoedit=") - 1) == TRUE) + if (atobool(info[i] + sizeof("sudoedit=") - 1) == true) SET(details->flags, CD_SUDOEDIT); break; } @@ -695,7 +717,7 @@ command_info_to_details(char * const info[], struct co break; } if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) { - if (atobool(info[i] + sizeof("use_pty=") - 1) == TRUE) + if (atobool(info[i] + sizeof("use_pty=") - 1) == true) SET(details->flags, CD_USE_PTY); break; } @@ -707,12 +729,50 @@ command_info_to_details(char * const info[], struct co if (!ISSET(details->flags, CD_SET_EUID)) details->euid = details->uid; +#ifdef HAVE_SETAUTHDB + aix_setauthdb(IDtouser(details->euid)); +#endif + details->pw = getpwuid(details->euid); + if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL) + errorx(1, _("unable to allocate memory")); +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif + #ifdef HAVE_SELINUX if (details->selinux_role != NULL && is_selinux_enabled() > 0) SET(details->flags, CD_RBAC_ENABLED); #endif + debug_return; } +static void +sudo_check_suid(const char *path) +{ + struct stat sb; + debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM) + + if (geteuid() != 0) { + if (strchr(path, '/') != NULL && stat(path, &sb) == 0) { + /* Try to determine why sudo was not running as root. */ + if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) { + errorx(1, + _("%s must be owned by uid %d and have the setuid bit set"), + path, ROOT_UID); + } else { + errorx(1, _("effective uid is not %d, is %s on a file system " + "with the 'nosuid' option set or an NFS file system without" + " root privileges?"), ROOT_UID, path); + } + } else { + errorx(1, + _("effective uid is not %d, is sudo installed setuid root?"), + ROOT_UID); + } + } + debug_return; +} + /* * Disable core dumps to avoid dropping a core with user password in it. * We will reset this limit before executing the command. @@ -721,9 +781,10 @@ command_info_to_details(char * const info[], struct co static void disable_coredumps(void) { -#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)) +#if defined(__linux__) || defined(RLIMIT_CORE) struct rlimit rl; #endif + debug_decl(disable_coredumps, SUDO_DEBUG_UTIL) #if defined(__linux__) /* @@ -739,15 +800,18 @@ disable_coredumps(void) (void)setrlimit(RLIMIT_NPROC, &rl); } #endif /* __linux__ */ -#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) +#ifdef RLIMIT_CORE /* - * Turn off core dumps. + * Turn off core dumps? */ - (void) getrlimit(RLIMIT_CORE, &corelimit); - memcpy(&rl, &corelimit, sizeof(struct rlimit)); - rl.rlim_cur = 0; - (void) setrlimit(RLIMIT_CORE, &rl); -#endif /* RLIMIT_CORE && !SUDO_DEVEL */ + if (sudo_conf_disable_coredump()) { + (void) getrlimit(RLIMIT_CORE, &corelimit); + memcpy(&rl, &corelimit, sizeof(struct rlimit)); + rl.rlim_cur = 0; + (void) setrlimit(RLIMIT_CORE, &rl); + } +#endif /* RLIMIT_CORE */ + debug_return; } #ifdef HAVE_PROJECT_H @@ -757,6 +821,7 @@ set_project(struct passwd *pw) struct project proj; char buf[PROJECT_BUFSZ]; int errval; + debug_decl(set_project, SUDO_DEBUG_UTIL) /* * Collect the default project for the user and settaskid @@ -809,107 +874,20 @@ set_project(struct passwd *pw) warning("getdefaultproj"); } endprojent(); + debug_return; } #endif /* HAVE_PROJECT_H */ /* - * Disable execution of child processes in the command we are about - * to run. On systems with privilege sets, we can remove the exec - * privilege. On other systems we use LD_PRELOAD and the like. - */ -static void -disable_execute(struct command_details *details) -{ -#ifdef _PATH_SUDO_NOEXEC - char *cp, **ev, **nenvp; - int env_len = 0, env_size = 128; -#endif /* _PATH_SUDO_NOEXEC */ - -#ifdef HAVE_PRIV_SET - /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */ - if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0) - return; - warning(_("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT")); -#endif /* HAVE_PRIV_SET */ - -#ifdef _PATH_SUDO_NOEXEC - nenvp = emalloc2(env_size, sizeof(char *)); - for (ev = details->envp; *ev != NULL; ev++) { - if (env_len + 2 > env_size) { - env_size += 128; - nenvp = erealloc3(nenvp, env_size, sizeof(char *)); - } - /* - * Prune out existing preloaded libraries. - * XXX - should save and append instead of replacing. - */ -# if defined(__darwin__) || defined(__APPLE__) - if (strncmp(*ev, "DYLD_INSERT_LIBRARIES=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0) - continue; - if (strncmp(*ev, "DYLD_FORCE_FLAT_NAMESPACE=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0) - continue; -# elif defined(__osf__) || defined(__sgi) - if (strncmp(*ev, "_RLD_LIST=", sizeof("_RLD_LIST=") - 1) == 0) - continue; -# elif defined(_AIX) - if (strncmp(*ev, "LDR_PRELOAD=", sizeof("LDR_PRELOAD=") - 1) == 0) - continue; -# else - if (strncmp(*ev, "LD_PRELOAD=", sizeof("LD_PRELOAD=") - 1) == 0) - continue; -# endif - nenvp[env_len++] = *ev; - } - - /* - * Preload a noexec file? For a list of LD_PRELOAD-alikes, see - * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html - * XXX - need to support 32-bit and 64-bit variants - */ -# if defined(__darwin__) || defined(__APPLE__) - nenvp[env_len++] = "DYLD_FORCE_FLAT_NAMESPACE="; - cp = fmt_string("DYLD_INSERT_LIBRARIES", noexec_path); -# elif defined(__osf__) || defined(__sgi) - easprintf(&cp, "_RLD_LIST=%s:DEFAULT", noexec_path); -# elif defined(_AIX) - cp = fmt_string("LDR_PRELOAD", noexec_path); -# else - cp = fmt_string("LD_PRELOAD", noexec_path); -# endif - if (cp == NULL) - error(1, NULL); - nenvp[env_len++] = cp; - nenvp[env_len] = NULL; - - details->envp = nenvp; -#endif /* _PATH_SUDO_NOEXEC */ -} - -/* * Setup the execution environment immediately prior to the call to execve() - * Returns TRUE on success and FALSE on failure. + * Returns true on success and false on failure. */ -int +bool exec_setup(struct command_details *details, const char *ptyname, int ptyfd) { - int rval = FALSE; - struct passwd *pw; + bool rval = false; + debug_decl(exec_setup, SUDO_DEBUG_EXEC) -#ifdef HAVE_SETAUTHDB - aix_setauthdb(IDtouser(details->euid)); -#endif - pw = getpwuid(details->euid); -#ifdef HAVE_SETAUTHDB - aix_restoreauthdb(); -#endif - - /* - * Call policy plugin's session init before other setup occurs. - * The session init code is expected to print an error as needed. - */ - if (policy_init_session(&policy_plugin, pw) != TRUE) - goto done; - #ifdef HAVE_SELINUX if (ISSET(details->flags, CD_RBAC_ENABLED)) { if (selinux_setup(details->selinux_role, details->selinux_type, @@ -918,12 +896,12 @@ exec_setup(struct command_details *details, const char } #endif - if (pw != NULL) { + if (details->pw != NULL) { #ifdef HAVE_PROJECT_H - set_project(pw); + set_project(details->pw); #endif #ifdef HAVE_GETUSERATTR - aix_prep_user(pw->pw_name, ptyname ? ptyname : user_details.tty); + aix_prep_user(details->pw->pw_name, ptyname ? ptyname : user_details.tty); #endif #ifdef HAVE_LOGIN_CAP_H if (details->login_class) { @@ -931,7 +909,8 @@ exec_setup(struct command_details *details, const char login_cap_t *lc; /* - * We only use setusercontext() to set the nice value and rlimits. + * We only use setusercontext() to set the nice value and rlimits + * unless this is a login shell (sudo -i). */ lc = login_getclass((char *)details->login_class); if (!lc) { @@ -939,9 +918,16 @@ exec_setup(struct command_details *details, const char errno = ENOENT; goto done; } - flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; - if (setusercontext(lc, pw, pw->pw_uid, flags)) { - if (pw->pw_uid != ROOT_UID) { + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + /* Set everything except user, group and login name. */ + flags = LOGIN_SETALL; + CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER|LOGIN_SETENV|LOGIN_SETPATH); + CLR(details->flags, CD_SET_UMASK); /* LOGIN_UMASK instead */ + } else { + flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; + } + if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) { + if (details->pw->pw_uid != ROOT_UID) { warning(_("unable to set user context")); goto done; } else @@ -954,6 +940,14 @@ exec_setup(struct command_details *details, const char /* * Set groups, including supplementary group vector. */ + if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) { + if (details->ngroups >= 0) { + if (sudo_setgroups(details->ngroups, details->groups) < 0) { + warning(_("unable to set supplementary group IDs")); + goto done; + } + } + } #ifdef HAVE_SETEUID if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) { warning(_("unable to set effective gid to runas gid %u"), @@ -967,15 +961,6 @@ exec_setup(struct command_details *details, const char goto done; } - if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) { - if (details->ngroups >= 0) { - if (sudo_setgroups(details->ngroups, details->groups) < 0) { - warning(_("unable to set supplementary group IDs")); - goto done; - } - } - } - if (ISSET(details->flags, CD_SET_PRIORITY)) { if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) { warning(_("unable to set process priority")); @@ -991,9 +976,6 @@ exec_setup(struct command_details *details, const char } } - if (ISSET(details->flags, CD_NOEXEC)) - disable_execute(details); - #ifdef HAVE_SETRESUID if (setresuid(details->uid, details->euid, details->euid) != 0) { warning(_("unable to change to runas uid (%u, %u)"), details->uid, @@ -1043,10 +1025,10 @@ exec_setup(struct command_details *details, const char } #endif - rval = TRUE; + rval = true; done: - return rval; + debug_return_bool(rval); } /* @@ -1058,29 +1040,34 @@ run_command(struct command_details *details) struct plugin_container *plugin; struct command_status cstat; int exitcode = 1; + debug_decl(run_command, SUDO_DEBUG_EXEC) cstat.type = CMD_INVALID; cstat.val = 0; - sudo_execve(details, &cstat); + sudo_execute(details, &cstat); switch (cstat.type) { case CMD_ERRNO: /* exec_setup() or execve() returned an error. */ - sudo_debug(9, "calling policy close with errno"); + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling policy close with errno %d", cstat.val); policy_close(&policy_plugin, 0, cstat.val); tq_foreach_fwd(&io_plugins, plugin) { - sudo_debug(9, "calling I/O close with errno"); + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling I/O close with errno %d", cstat.val); iolog_close(plugin, 0, cstat.val); } exitcode = 1; break; case CMD_WSTATUS: /* Command ran, exited or was killed. */ - sudo_debug(9, "calling policy close with wait status"); + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling policy close with wait status %d", cstat.val); policy_close(&policy_plugin, cstat.val, 0); tq_foreach_fwd(&io_plugins, plugin) { - sudo_debug(9, "calling I/O close with wait status"); + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling I/O close with wait status %d", cstat.val); iolog_close(plugin, cstat.val, 0); } if (WIFEXITED(cstat.val)) @@ -1092,27 +1079,46 @@ run_command(struct command_details *details) warningx(_("unexpected child termination condition: %d"), cstat.type); break; } - return exitcode; + debug_return_int(exitcode); } static int policy_open(struct plugin_container *plugin, char * const settings[], char * const user_info[], char * const user_env[]) { - return plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation, - _sudo_printf, settings, user_info, user_env); + int rval; + debug_decl(policy_open, SUDO_DEBUG_PCOMM) + + /* + * Backwards compatibility for older API versions + */ + switch (plugin->u.generic->version) { + case SUDO_API_MKVERSION(1, 0): + case SUDO_API_MKVERSION(1, 1): + rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version, + sudo_conversation, _sudo_printf, settings, user_info, user_env); + break; + default: + rval = plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation, + _sudo_printf, settings, user_info, user_env, plugin->options); + } + + debug_return_bool(rval); } static void policy_close(struct plugin_container *plugin, int exit_status, int error) { + debug_decl(policy_close, SUDO_DEBUG_PCOMM) plugin->u.policy->close(exit_status, error); + debug_return; } static int policy_show_version(struct plugin_container *plugin, int verbose) { - return plugin->u.policy->show_version(verbose); + debug_decl(policy_show_version, SUDO_DEBUG_PCOMM) + debug_return_bool(plugin->u.policy->show_version(verbose)); } static int @@ -1120,49 +1126,69 @@ policy_check(struct plugin_container *plugin, int argc char *env_add[], char **command_info[], char **argv_out[], char **user_env_out[]) { - return plugin->u.policy->check_policy(argc, argv, env_add, command_info, - argv_out, user_env_out); + debug_decl(policy_check, SUDO_DEBUG_PCOMM) + debug_return_bool(plugin->u.policy->check_policy(argc, argv, env_add, + command_info, argv_out, user_env_out)); } static int policy_list(struct plugin_container *plugin, int argc, char * const argv[], int verbose, const char *list_user) { + debug_decl(policy_list, SUDO_DEBUG_PCOMM) if (plugin->u.policy->list == NULL) { warningx(_("policy plugin %s does not support listing privileges"), plugin->name); - return FALSE; + debug_return_bool(false); } - return plugin->u.policy->list(argc, argv, verbose, list_user); + debug_return_bool(plugin->u.policy->list(argc, argv, verbose, list_user)); } static int policy_validate(struct plugin_container *plugin) { + debug_decl(policy_validate, SUDO_DEBUG_PCOMM) if (plugin->u.policy->validate == NULL) { warningx(_("policy plugin %s does not support the -v option"), plugin->name); - return FALSE; + debug_return_bool(false); } - return plugin->u.policy->validate(); + debug_return_bool(plugin->u.policy->validate()); } static void policy_invalidate(struct plugin_container *plugin, int remove) { + debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM) if (plugin->u.policy->invalidate == NULL) { errorx(1, _("policy plugin %s does not support the -k/-K options"), plugin->name); } plugin->u.policy->invalidate(remove); + debug_return; } -static int -policy_init_session(struct plugin_container *plugin, struct passwd *pwd) +int +policy_init_session(struct command_details *details) { - if (plugin->u.policy->init_session) - return plugin->u.policy->init_session(pwd); - return TRUE; + int rval = true; + debug_decl(policy_init_session, SUDO_DEBUG_PCOMM) + + if (policy_plugin.u.policy->init_session) { + /* + * Backwards compatibility for older API versions + */ + switch (policy_plugin.u.generic->version) { + case SUDO_API_MKVERSION(1, 0): + case SUDO_API_MKVERSION(1, 1): + rval = policy_plugin.u.policy_1_0->init_session(details->pw); + break; + default: + rval = policy_plugin.u.policy->init_session(details->pw, + &details->envp); + } + } + debug_return_bool(rval); } static int @@ -1171,9 +1197,10 @@ iolog_open(struct plugin_container *plugin, char * con int argc, char * const argv[], char * const user_env[]) { int rval; + debug_decl(iolog_open, SUDO_DEBUG_PCOMM) /* - * Backwards compatibility for API major 1, minor 0 + * Backwards compatibility for older API versions */ switch (plugin->u.generic->version) { case SUDO_API_MKVERSION(1, 0): @@ -1181,42 +1208,52 @@ iolog_open(struct plugin_container *plugin, char * con sudo_conversation, _sudo_printf, settings, user_info, argc, argv, user_env); break; + case SUDO_API_MKVERSION(1, 1): + rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version, + sudo_conversation, _sudo_printf, settings, user_info, + command_info, argc, argv, user_env); + break; default: rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, - _sudo_printf, settings, user_info, command_info, argc, argv, - user_env); + _sudo_printf, settings, user_info, command_info, + argc, argv, user_env, plugin->options); } - return rval; + debug_return_bool(rval); } static void iolog_close(struct plugin_container *plugin, int exit_status, int error) { + debug_decl(iolog_close, SUDO_DEBUG_PCOMM) plugin->u.io->close(exit_status, error); + debug_return; } static int iolog_show_version(struct plugin_container *plugin, int verbose) { - return plugin->u.io->show_version(verbose); + debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM) + debug_return_bool(plugin->u.io->show_version(verbose)); } /* - * Simple debugging/logging. + * Remove the specified I/O logging plugin from the io_plugins list. + * Deregisters any hooks before unlinking, then frees the container. */ -void -sudo_debug(int level, const char *fmt, ...) +static void +iolog_unlink(struct plugin_container *plugin) { - va_list ap; - char *buf; + debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM) - if (level > debug_level) - return; + /* Deregister hooks, if any. */ + if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) { + if (plugin->u.io->deregister_hooks != NULL) + plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION, + deregister_hook); + } + /* Remove from io_plugins list and free. */ + tq_remove(&io_plugins, plugin); + efree(plugin); - /* Bracket fmt with program name and a newline to make it a single write */ - va_start(ap, fmt); - evasprintf(&buf, fmt, ap); - va_end(ap); - fprintf(stderr, "%s: %s\n", getprogname(), buf); - efree(buf); + debug_return; }