version 1.1, 2012/02/21 16:23:02
|
version 1.1.1.5, 2013/10/14 07:56:35
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 21
|
Line 21
|
#include <config.h> |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
|
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/wait.h> |
#include <sys/wait.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#ifdef HAVE_SYS_SELECT_H |
|
# include <sys/select.h> |
|
#endif /* HAVE_SYS_SELECT_H */ |
|
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/resource.h> |
#include <sys/resource.h> |
#include <stdio.h> |
#include <stdio.h> |
Line 61
|
Line 57
|
#if TIME_WITH_SYS_TIME |
#if TIME_WITH_SYS_TIME |
# include <time.h> |
# include <time.h> |
#endif |
#endif |
#ifdef HAVE_SETLOCALE |
|
# include <locale.h> |
|
#endif |
|
#ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
# include <login_cap.h> |
# include <login_cap.h> |
|
# ifndef LOGIN_SETENV |
|
# define LOGIN_SETENV 0 |
|
# endif |
#endif |
#endif |
#ifdef HAVE_PROJECT_H |
#ifdef HAVE_PROJECT_H |
# include <project.h> |
# include <project.h> |
Line 86
|
Line 82
|
# endif /* __hpux */ |
# endif /* __hpux */ |
# include <prot.h> |
# include <prot.h> |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
#ifdef HAVE_PRIV_SET |
|
# include <priv.h> |
|
#endif |
|
|
|
|
#include <sudo_usage.h> |
#include "sudo.h" |
#include "sudo.h" |
#include "sudo_plugin.h" |
#include "sudo_plugin.h" |
#include "sudo_plugin_int.h" |
#include "sudo_plugin_int.h" |
#include <sudo_usage.h> |
|
|
|
/* |
/* |
* Local variables |
* Local variables |
Line 101
|
Line 94
|
struct plugin_container policy_plugin; |
struct plugin_container policy_plugin; |
struct plugin_container_list io_plugins; |
struct plugin_container_list io_plugins; |
struct user_details user_details; |
struct user_details user_details; |
const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */ | const char *list_user; /* extern for parse_args.c */ |
int debug_level; | static struct command_details command_details; |
| static int sudo_mode; |
|
|
/* |
/* |
* Local functions |
* Local functions |
*/ |
*/ |
static void fix_fds(void); |
static void fix_fds(void); |
static void disable_coredumps(void); |
static void disable_coredumps(void); |
|
static void sudo_check_suid(const char *path); |
static char **get_user_info(struct user_details *); |
static char **get_user_info(struct user_details *); |
static void command_info_to_details(char * const info[], |
static void command_info_to_details(char * const info[], |
struct command_details *details); |
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. */ |
/* Policy plugin convenience functions. */ |
static int policy_open(struct plugin_container *plugin, char * const settings[], |
static int policy_open(struct plugin_container *plugin, char * const settings[], |
Line 135 static int policy_list(struct plugin_container *plugin
|
Line 121 static int policy_list(struct plugin_container *plugin
|
char * const argv[], int verbose, const char *list_user); |
char * const argv[], int verbose, const char *list_user); |
static int policy_validate(struct plugin_container *plugin); |
static int policy_validate(struct plugin_container *plugin); |
static void policy_invalidate(struct plugin_container *plugin, int remove); |
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. */ |
/* I/O log plugin convenience functions. */ |
static int iolog_open(struct plugin_container *plugin, char * const settings[], |
static int iolog_open(struct plugin_container *plugin, char * const settings[], |
Line 145 static int iolog_open(struct plugin_container *plugin,
|
Line 129 static int iolog_open(struct plugin_container *plugin,
|
static void iolog_close(struct plugin_container *plugin, int exit_status, |
static void iolog_close(struct plugin_container *plugin, int exit_status, |
int error); |
int error); |
static int iolog_show_version(struct plugin_container *plugin, int verbose); |
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; |
static struct rlimit corelimit; |
#endif /* RLIMIT_CORE && !SUDO_DEVEL */ | #endif |
#if defined(__linux__) | #ifdef __linux__ |
static struct rlimit nproclimit; |
static struct rlimit nproclimit; |
#endif |
#endif |
|
|
|
__dso_public int main(int argc, char *argv[], char *envp[]); |
|
|
int |
int |
main(int argc, char *argv[], char *envp[]) |
main(int argc, char *argv[], char *envp[]) |
{ |
{ |
int nargc, sudo_mode, exitcode = 0; | int nargc, ok, exitcode = 0; |
char **nargv, **settings, **env_add; |
char **nargv, **settings, **env_add; |
char **user_info, **command_info, **argv_out, **user_env_out; |
char **user_info, **command_info, **argv_out, **user_env_out; |
struct plugin_container *plugin, *next; |
struct plugin_container *plugin, *next; |
struct command_details command_details; |
|
sigset_t mask; |
sigset_t mask; |
int ok; | debug_decl(main, SUDO_DEBUG_MAIN) |
#if defined(SUDO_DEVEL) && defined(__OpenBSD__) | |
extern char *malloc_options; | |
malloc_options = "AFGJPR"; | |
#endif | |
|
|
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) | os_init(argc, argv, envp); |
if (argc > 0) | |
setprogname(argv[0]); | |
#endif | |
|
|
#ifdef HAVE_SETLOCALE |
|
setlocale(LC_ALL, ""); |
setlocale(LC_ALL, ""); |
#endif |
|
bindtextdomain(PACKAGE_NAME, LOCALEDIR); |
bindtextdomain(PACKAGE_NAME, LOCALEDIR); |
textdomain(PACKAGE_NAME); |
textdomain(PACKAGE_NAME); |
|
|
|
#ifdef HAVE_TZSET |
|
(void) tzset(); |
|
#endif /* HAVE_TZSET */ |
|
|
/* Must be done before we do any password lookups */ |
/* Must be done before we do any password lookups */ |
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) |
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) |
(void) set_auth_parameters(argc, argv); |
(void) set_auth_parameters(argc, argv); |
Line 187 main(int argc, char *argv[], char *envp[])
|
Line 168 main(int argc, char *argv[], char *envp[])
|
# endif |
# endif |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ |
|
|
if (geteuid() != 0) | /* Make sure we are setuid root. */ |
errorx(1, _("must be setuid root")); | sudo_check_suid(argv[0]); |
|
|
/* Reset signal mask, disable core dumps and make sure fds 0-2 are open. */ | /* Reset signal mask, save signal state and make sure fds 0-2 are open. */ |
(void) sigemptyset(&mask); |
(void) sigemptyset(&mask); |
(void) sigprocmask(SIG_SETMASK, &mask, NULL); |
(void) sigprocmask(SIG_SETMASK, &mask, NULL); |
disable_coredumps(); | save_signals(); |
fix_fds(); |
fix_fds(); |
|
|
|
/* Read sudo.conf. */ |
|
sudo_conf_read(NULL); |
|
|
/* Fill in user_info with user name, uid, cwd, etc. */ |
/* Fill in user_info with user name, uid, cwd, etc. */ |
memset(&user_details, 0, sizeof(user_details)); |
memset(&user_details, 0, sizeof(user_details)); |
user_info = get_user_info(&user_details); |
user_info = get_user_info(&user_details); |
|
|
|
/* Disable core dumps if not enabled in sudo.conf. */ |
|
disable_coredumps(); |
|
|
/* Parse command line arguments. */ |
/* Parse command line arguments. */ |
sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add); |
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. */ |
/* Print sudo version early, in case of plugin init failure. */ |
if (ISSET(sudo_mode, MODE_VERSION)) { |
if (ISSET(sudo_mode, MODE_VERSION)) { |
Line 211 main(int argc, char *argv[], char *envp[])
|
Line 198 main(int argc, char *argv[], char *envp[])
|
(void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS); |
(void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS); |
} |
} |
|
|
/* Read sudo.conf and load plugins. */ | /* Load plugins. */ |
if (!sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins)) | if (!sudo_load_plugins(&policy_plugin, &io_plugins)) |
errorx(1, _("fatal error, unable to load plugins")); | fatalx(_("fatal error, unable to load plugins")); |
|
|
/* Open policy plugin. */ |
/* Open policy plugin. */ |
ok = policy_open(&policy_plugin, settings, user_info, envp); |
ok = policy_open(&policy_plugin, settings, user_info, envp); |
if (ok != TRUE) { | if (ok != 1) { |
if (ok == -2) |
if (ok == -2) |
usage(1); |
usage(1); |
else |
else |
errorx(1, _("unable to initialize policy plugin")); | fatalx(_("unable to initialize policy plugin")); |
} |
} |
|
|
|
init_signals(); |
|
|
switch (sudo_mode & MODE_MASK) { |
switch (sudo_mode & MODE_MASK) { |
case MODE_VERSION: |
case MODE_VERSION: |
policy_show_version(&policy_plugin, !user_details.uid); |
policy_show_version(&policy_plugin, !user_details.uid); |
tq_foreach_fwd(&io_plugins, plugin) { |
tq_foreach_fwd(&io_plugins, plugin) { |
ok = iolog_open(plugin, settings, user_info, NULL, |
ok = iolog_open(plugin, settings, user_info, NULL, |
nargc, nargv, envp); |
nargc, nargv, envp); |
if (ok == TRUE) | if (ok != -1) |
iolog_show_version(plugin, !user_details.uid); |
iolog_show_version(plugin, !user_details.uid); |
} |
} |
break; |
break; |
case MODE_VALIDATE: |
case MODE_VALIDATE: |
case MODE_VALIDATE|MODE_INVALIDATE: |
case MODE_VALIDATE|MODE_INVALIDATE: |
ok = policy_validate(&policy_plugin); |
ok = policy_validate(&policy_plugin); |
exit(ok != TRUE); | exit(ok != 1); |
case MODE_KILL: |
case MODE_KILL: |
case MODE_INVALIDATE: |
case MODE_INVALIDATE: |
policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL); |
policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL); |
Line 249 main(int argc, char *argv[], char *envp[])
|
Line 238 main(int argc, char *argv[], char *envp[])
|
case MODE_LIST|MODE_INVALIDATE: |
case MODE_LIST|MODE_INVALIDATE: |
ok = policy_list(&policy_plugin, nargc, nargv, |
ok = policy_list(&policy_plugin, nargc, nargv, |
ISSET(sudo_mode, MODE_LONG_LIST), list_user); |
ISSET(sudo_mode, MODE_LONG_LIST), list_user); |
exit(ok != TRUE); | exit(ok != 1); |
case MODE_EDIT: |
case MODE_EDIT: |
case MODE_RUN: |
case MODE_RUN: |
ok = policy_check(&policy_plugin, nargc, nargv, env_add, |
ok = policy_check(&policy_plugin, nargc, nargv, env_add, |
&command_info, &argv_out, &user_env_out); |
&command_info, &argv_out, &user_env_out); |
sudo_debug(8, "policy plugin returns %d", ok); | sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok); |
if (ok != TRUE) { | if (ok != 1) { |
if (ok == -2) |
if (ok == -2) |
usage(1); |
usage(1); |
exit(1); /* plugin printed error message */ |
exit(1); /* plugin printed error message */ |
Line 266 main(int argc, char *argv[], char *envp[])
|
Line 255 main(int argc, char *argv[], char *envp[])
|
ok = iolog_open(plugin, settings, user_info, |
ok = iolog_open(plugin, settings, user_info, |
command_info, nargc, nargv, envp); |
command_info, nargc, nargv, envp); |
switch (ok) { |
switch (ok) { |
case TRUE: | case 1: |
break; |
break; |
case FALSE: | case 0: |
/* I/O plugin asked to be disabled, remove from list. */ | /* I/O plugin asked to be disabled, remove and free. */ |
tq_remove(&io_plugins, plugin); | iolog_unlink(plugin); |
break; |
break; |
case -2: |
case -2: |
usage(1); |
usage(1); |
break; |
break; |
default: |
default: |
errorx(1, _("error initializing I/O plugin %s"), | fatalx(_("error initializing I/O plugin %s"), |
plugin->name); |
plugin->name); |
} |
} |
} |
} |
|
/* Setup command details and run command/edit. */ |
command_info_to_details(command_info, &command_details); |
command_info_to_details(command_info, &command_details); |
command_details.argv = argv_out; |
command_details.argv = argv_out; |
command_details.envp = user_env_out; |
command_details.envp = user_env_out; |
if (ISSET(sudo_mode, MODE_BACKGROUND)) |
if (ISSET(sudo_mode, MODE_BACKGROUND)) |
SET(command_details.flags, CD_BACKGROUND); |
SET(command_details.flags, CD_BACKGROUND); |
|
/* Become full root (not just setuid) so user cannot kill us. */ |
|
if (setuid(ROOT_UID) == -1) |
|
warning("setuid(%d)", ROOT_UID); |
/* Restore coredumpsize resource limit before running. */ |
/* Restore coredumpsize resource limit before running. */ |
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) | #ifdef RLIMIT_CORE |
(void) setrlimit(RLIMIT_CORE, &corelimit); | if (sudo_conf_disable_coredump()) |
#endif /* RLIMIT_CORE && !SUDO_DEVEL */ | (void) setrlimit(RLIMIT_CORE, &corelimit); |
| #endif /* RLIMIT_CORE */ |
if (ISSET(command_details.flags, CD_SUDOEDIT)) { |
if (ISSET(command_details.flags, CD_SUDOEDIT)) { |
exitcode = sudo_edit(&command_details); |
exitcode = sudo_edit(&command_details); |
} else { |
} else { |
Line 297 main(int argc, char *argv[], char *envp[])
|
Line 291 main(int argc, char *argv[], char *envp[])
|
/* The close method was called by sudo_edit/run_command. */ |
/* The close method was called by sudo_edit/run_command. */ |
break; |
break; |
default: |
default: |
errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode); | fatalx(_("unexpected sudo mode 0x%x"), sudo_mode); |
} |
} |
|
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); |
exit(exitcode); |
exit(exitcode); |
} |
} |
|
|
|
int |
|
os_init_common(int argc, char *argv[], char *envp[]) |
|
{ |
|
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
|
if (argc > 0) |
|
setprogname(argv[0]); |
|
#endif |
|
return 0; |
|
} |
|
|
/* |
/* |
* Ensure that stdin, stdout and stderr are open; set to /dev/null if not. |
* Ensure that stdin, stdout and stderr are open; set to /dev/null if not. |
* Some operating systems do this automatically in the kernel or libc. |
* Some operating systems do this automatically in the kernel or libc. |
Line 310 static void
|
Line 315 static void
|
fix_fds(void) |
fix_fds(void) |
{ |
{ |
int miss[3], devnull = -1; |
int miss[3], devnull = -1; |
|
debug_decl(fix_fds, SUDO_DEBUG_UTIL) |
|
|
/* |
/* |
* stdin, stdout and stderr must be open; set them to /dev/null |
* stdin, stdout and stderr must be open; set them to /dev/null |
Line 320 fix_fds(void)
|
Line 326 fix_fds(void)
|
miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1; |
miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1; |
if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) { |
if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) { |
if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1) |
if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1) |
error(1, _("unable to open %s"), _PATH_DEVNULL); | fatal(_("unable to open %s"), _PATH_DEVNULL); |
if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1) |
if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1) |
error(1, "dup2"); | fatal("dup2"); |
if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1) |
if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1) |
error(1, "dup2"); | fatal("dup2"); |
if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1) |
if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1) |
error(1, "dup2"); | fatal("dup2"); |
if (devnull > STDERR_FILENO) |
if (devnull > STDERR_FILENO) |
close(devnull); |
close(devnull); |
} |
} |
|
debug_return; |
} |
} |
|
|
/* |
/* |
* Allocate space for groups and fill in using getgrouplist() |
* Allocate space for groups and fill in using getgrouplist() |
* for when we cannot use getgroups(). | * for when we cannot (or don't want to) use getgroups(). |
*/ |
*/ |
static int |
static int |
fill_group_list(struct user_details *ud) | fill_group_list(struct user_details *ud, int system_maxgroups) |
{ |
{ |
int maxgroups, tries, rval = -1; | int 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); |
|
if (maxgroups < 0) |
|
#endif |
|
maxgroups = NGROUPS_MAX; |
|
|
|
/* |
/* |
* It is possible to belong to more groups in the group database | * If user specified a max number of groups, use it, otherwise keep |
* than NGROUPS_MAX. We start off with NGROUPS_MAX * 2 entries | * trying getgrouplist() until we have enough room in the array. |
* and double this as needed. | |
*/ |
*/ |
ud->groups = NULL; | ud->ngroups = sudo_conf_max_groups(); |
ud->ngroups = maxgroups; | if (ud->ngroups > 0) { |
for (tries = 0; tries < 10 && rval == -1; tries++) { | |
ud->ngroups *= 2; | |
efree(ud->groups); | |
ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); |
ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); |
rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); | /* No error on insufficient space if user specified max_groups. */ |
| (void)getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); |
| rval = 0; |
| } else { |
| /* |
| * It is possible to belong to more groups in the group database |
| * than NGROUPS_MAX. We start off with NGROUPS_MAX * 4 entries |
| * and double this as needed. |
| */ |
| ud->groups = NULL; |
| ud->ngroups = system_maxgroups << 1; |
| for (tries = 0; tries < 10 && rval == -1; tries++) { |
| ud->ngroups <<= 1; |
| efree(ud->groups); |
| 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 * |
static char * |
Line 368 get_user_groups(struct user_details *ud)
|
Line 382 get_user_groups(struct user_details *ud)
|
{ |
{ |
char *cp, *gid_list = NULL; |
char *cp, *gid_list = NULL; |
size_t glsize; |
size_t glsize; |
int i, len; | int i, len, maxgroups, group_source; |
| debug_decl(get_user_groups, SUDO_DEBUG_UTIL) |
|
|
/* | #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) |
* Systems with mbr_check_membership() support more than NGROUPS_MAX | maxgroups = (int)sysconf(_SC_NGROUPS_MAX); |
* groups so we cannot use getgroups(). | if (maxgroups < 0) |
*/ | #endif |
| maxgroups = NGROUPS_MAX; |
| |
ud->groups = NULL; |
ud->groups = NULL; |
#ifndef HAVE_MBR_CHECK_MEMBERSHIP | group_source = sudo_conf_group_source(); |
if ((ud->ngroups = getgroups(0, NULL)) > 0) { | if (group_source != GROUP_SOURCE_DYNAMIC) { |
ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); | if ((ud->ngroups = getgroups(0, NULL)) > 0) { |
if (getgroups(ud->ngroups, ud->groups) < 0) { | /* Use groups from kernel if not too many or source is static. */ |
efree(ud->groups); | if (ud->ngroups < maxgroups || group_source == GROUP_SOURCE_STATIC) { |
ud->groups = NULL; | ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); |
| if (getgroups(ud->ngroups, ud->groups) < 0) { |
| efree(ud->groups); |
| ud->groups = NULL; |
| } |
| } |
} |
} |
} |
} |
#endif /* HAVE_MBR_CHECK_MEMBERSHIP */ |
|
if (ud->groups == NULL) { |
if (ud->groups == NULL) { |
if (fill_group_list(ud) == -1) | /* |
error(1, _("unable to get group vector")); | * Query group database if kernel list is too small or disabled. |
| * Typically, this is because NFS can only support up to 16 groups. |
| */ |
| if (fill_group_list(ud, maxgroups) == -1) |
| fatal(_("unable to get group vector")); |
} |
} |
|
|
/* |
/* |
Line 402 get_user_groups(struct user_details *ud)
|
Line 427 get_user_groups(struct user_details *ud)
|
i ? "," : "", (unsigned int)ud->groups[i]); |
i ? "," : "", (unsigned int)ud->groups[i]); |
cp += len; |
cp += len; |
} |
} |
return gid_list; | debug_return_str(gid_list); |
} |
} |
|
|
/* |
/* |
Line 412 get_user_groups(struct user_details *ud)
|
Line 437 get_user_groups(struct user_details *ud)
|
static char ** |
static char ** |
get_user_info(struct user_details *ud) |
get_user_info(struct user_details *ud) |
{ |
{ |
char cwd[PATH_MAX]; | char *cp, **user_info, cwd[PATH_MAX], host[HOST_NAME_MAX + 1]; |
char host[MAXHOSTNAMELEN]; | |
char **user_info, *cp; | |
struct passwd *pw; |
struct passwd *pw; |
int i = 0; | int fd, i = 0; |
| debug_decl(get_user_info, SUDO_DEBUG_UTIL) |
|
|
/* XXX - bound check number of entries */ |
/* XXX - bound check number of entries */ |
user_info = emalloc2(32, sizeof(char *)); |
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->uid = getuid(); |
ud->euid = geteuid(); |
ud->euid = geteuid(); |
ud->gid = getgid(); |
ud->gid = getgid(); |
Line 428 get_user_info(struct user_details *ud)
|
Line 463 get_user_info(struct user_details *ud)
|
|
|
pw = getpwuid(ud->uid); |
pw = getpwuid(ud->uid); |
if (pw == NULL) |
if (pw == NULL) |
errorx(1, _("unknown uid %u: who are you?"), (unsigned int)ud->uid); | fatalx(_("unknown uid %u: who are you?"), (unsigned int)ud->uid); |
|
|
user_info[i] = fmt_string("user", pw->pw_name); |
user_info[i] = fmt_string("user", pw->pw_name); |
if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
errorx(1, _("unable to allocate memory")); | fatal(NULL); |
ud->username = user_info[i] + sizeof("user=") - 1; |
ud->username = user_info[i] + sizeof("user=") - 1; |
|
|
/* Stash user's shell for use with the -s flag; don't pass to plugin. */ |
/* Stash user's shell for use with the -s flag; don't pass to plugin. */ |
Line 441 get_user_info(struct user_details *ud)
|
Line 476 get_user_info(struct user_details *ud)
|
} |
} |
ud->shell = estrdup(ud->shell); |
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], "uid=%u", (unsigned int)ud->uid); |
easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid); |
easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid); |
easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid); |
easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid); |
Line 452 get_user_info(struct user_details *ud)
|
Line 493 get_user_info(struct user_details *ud)
|
if (getcwd(cwd, sizeof(cwd)) != NULL) { |
if (getcwd(cwd, sizeof(cwd)) != NULL) { |
user_info[++i] = fmt_string("cwd", cwd); |
user_info[++i] = fmt_string("cwd", cwd); |
if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
errorx(1, _("unable to allocate memory")); | fatal(NULL); |
ud->cwd = user_info[i] + sizeof("cwd=") - 1; |
ud->cwd = user_info[i] + sizeof("cwd=") - 1; |
} |
} |
|
|
if ((cp = ttyname(STDIN_FILENO)) || (cp = ttyname(STDOUT_FILENO)) || | if ((cp = get_process_ttyname()) != NULL) { |
(cp = ttyname(STDERR_FILENO))) { | |
user_info[++i] = fmt_string("tty", cp); |
user_info[++i] = fmt_string("tty", cp); |
if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
errorx(1, _("unable to allocate memory")); | fatal(NULL); |
ud->tty = user_info[i] + sizeof("tty=") - 1; |
ud->tty = user_info[i] + sizeof("tty=") - 1; |
|
efree(cp); |
} |
} |
|
|
if (gethostname(host, sizeof(host)) == 0) |
if (gethostname(host, sizeof(host)) == 0) |
Line 470 get_user_info(struct user_details *ud)
|
Line 511 get_user_info(struct user_details *ud)
|
strlcpy(host, "localhost", sizeof(host)); |
strlcpy(host, "localhost", sizeof(host)); |
user_info[++i] = fmt_string("host", host); |
user_info[++i] = fmt_string("host", host); |
if (user_info[i] == NULL) |
if (user_info[i] == NULL) |
errorx(1, _("unable to allocate memory")); | fatal(NULL); |
ud->host = user_info[i] + sizeof("host=") - 1; |
ud->host = user_info[i] + sizeof("host=") - 1; |
|
|
get_ttysize(&ud->ts_lines, &ud->ts_cols); |
get_ttysize(&ud->ts_lines, &ud->ts_cols); |
Line 479 get_user_info(struct user_details *ud)
|
Line 520 get_user_info(struct user_details *ud)
|
|
|
user_info[++i] = NULL; |
user_info[++i] = NULL; |
|
|
return user_info; | debug_return_ptr(user_info); |
} |
} |
|
|
/* |
/* |
Line 489 static void
|
Line 530 static void
|
command_info_to_details(char * const info[], struct command_details *details) |
command_info_to_details(char * const info[], struct command_details *details) |
{ |
{ |
int i; |
int i; |
|
id_t id; |
long lval; |
long lval; |
unsigned long ulval; |
|
char *cp, *ep; |
char *cp, *ep; |
|
const char *errstr; |
|
debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM) |
|
|
memset(details, 0, sizeof(*details)); |
memset(details, 0, sizeof(*details)); |
details->closefrom = -1; |
details->closefrom = -1; |
Line 502 command_info_to_details(char * const info[], struct co
|
Line 545 command_info_to_details(char * const info[], struct co
|
break; \ |
break; \ |
} |
} |
|
|
|
sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:"); |
for (i = 0; info[i] != NULL; i++) { |
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]) { |
switch (info[i][0]) { |
case 'c': |
case 'c': |
SET_STRING("chroot=", chroot) |
SET_STRING("chroot=", chroot) |
SET_STRING("command=", command) |
SET_STRING("command=", command) |
SET_STRING("cwd=", cwd) |
SET_STRING("cwd=", cwd) |
if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { |
if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { |
cp = info[i] + sizeof("closefrom=") - 1; |
|
if (*cp == '\0') |
|
break; |
|
errno = 0; |
errno = 0; |
lval = strtol(cp, &ep, 0); | cp = info[i] + sizeof("closefrom=") - 1; |
if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 10); |
!(errno == ERANGE && | if (*cp == '\0' || *ep != '\0') |
(lval == LONG_MAX || lval == LONG_MIN)) && | fatalx(_("%s: %s"), info[i], _("invalid value")); |
lval < INT_MAX && lval > INT_MIN) { | if ((errno == ERANGE && |
details->closefrom = (int)lval; | (lval == LONG_MAX || lval == LONG_MIN)) || |
} | (lval > INT_MAX || lval < 0)) |
| fatalx(_("%s: %s"), info[i], _("value out of range")); |
| details->closefrom = (int)lval; |
break; |
break; |
} |
} |
break; |
break; |
|
case 'e': |
|
if (strncmp("exec_background=", info[i], sizeof("exec_background=") - 1) == 0) { |
|
if (atobool(info[i] + sizeof("exec_background=") - 1) == true) |
|
SET(details->flags, CD_EXEC_BG); |
|
break; |
|
} |
|
break; |
case 'l': |
case 'l': |
SET_STRING("login_class=", login_class) |
SET_STRING("login_class=", login_class) |
break; |
break; |
case 'n': |
case 'n': |
/* XXX - bounds check -NZERO to NZERO (inclusive). */ |
|
if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) { |
if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) { |
cp = info[i] + sizeof("nice=") - 1; |
|
if (*cp == '\0') |
|
break; |
|
errno = 0; |
errno = 0; |
lval = strtol(cp, &ep, 0); | cp = info[i] + sizeof("nice=") - 1; |
if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 10); |
!(errno == ERANGE && | if (*cp == '\0' || *ep != '\0') |
(lval == LONG_MAX || lval == LONG_MIN)) && | fatalx(_("%s: %s"), info[i], _("invalid value")); |
lval < INT_MAX && lval > INT_MIN) { | if ((errno == ERANGE && |
details->priority = (int)lval; | (lval == LONG_MAX || lval == LONG_MIN)) || |
SET(details->flags, CD_SET_PRIORITY); | (lval > INT_MAX || lval < INT_MIN)) |
} | fatalx(_("%s: %s"), info[i], _("value out of range")); |
| details->priority = (int)lval; |
| SET(details->flags, CD_SET_PRIORITY); |
break; |
break; |
} |
} |
if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) { |
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); |
SET(details->flags, CD_NOEXEC); |
break; |
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; |
break; |
case 'p': |
case 'p': |
if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) { |
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); |
SET(details->flags, CD_PRESERVE_GROUPS); |
break; |
break; |
} |
} |
Line 567 command_info_to_details(char * const info[], struct co
|
Line 608 command_info_to_details(char * const info[], struct co
|
case 'r': |
case 'r': |
if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) { |
if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) { |
cp = info[i] + sizeof("runas_egid=") - 1; |
cp = info[i] + sizeof("runas_egid=") - 1; |
if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
break; | if (errstr != NULL) |
errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
ulval = strtoul(cp, &ep, 0); | details->egid = (gid_t)id; |
if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_EGID); |
(errno != ERANGE || ulval != ULONG_MAX)) { | |
details->egid = (gid_t)ulval; | |
SET(details->flags, CD_SET_EGID); | |
} | |
break; |
break; |
} |
} |
if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) { |
if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) { |
cp = info[i] + sizeof("runas_euid=") - 1; |
cp = info[i] + sizeof("runas_euid=") - 1; |
if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
break; | if (errstr != NULL) |
errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
ulval = strtoul(cp, &ep, 0); | details->euid = (uid_t)id; |
if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_EUID); |
(errno != ERANGE || ulval != ULONG_MAX)) { | |
details->euid = (uid_t)ulval; | |
SET(details->flags, CD_SET_EUID); | |
} | |
break; |
break; |
} |
} |
if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) { |
if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) { |
cp = info[i] + sizeof("runas_gid=") - 1; |
cp = info[i] + sizeof("runas_gid=") - 1; |
if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
break; | if (errstr != NULL) |
errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
ulval = strtoul(cp, &ep, 0); | details->gid = (gid_t)id; |
if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_GID); |
(errno != ERANGE || ulval != ULONG_MAX)) { | |
details->gid = (gid_t)ulval; | |
SET(details->flags, CD_SET_GID); | |
} | |
break; |
break; |
} |
} |
if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) { |
if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) { |
int j; | /* parse_gid_list() will call fatalx() on error. */ |
| |
/* count groups, alloc and fill in */ | |
cp = info[i] + sizeof("runas_groups=") - 1; |
cp = info[i] + sizeof("runas_groups=") - 1; |
if (*cp == '\0') | details->ngroups = parse_gid_list(cp, NULL, &details->groups); |
break; | |
for (;;) { | |
details->ngroups++; | |
if ((cp = strchr(cp, ',')) == NULL) | |
break; | |
cp++; | |
} | |
if (details->ngroups != 0) { | |
details->groups = | |
emalloc2(details->ngroups, sizeof(GETGROUPS_T)); | |
cp = info[i] + sizeof("runas_groups=") - 1; | |
for (j = 0; j < details->ngroups;) { | |
errno = 0; | |
ulval = strtoul(cp, &ep, 0); | |
if (*cp == '\0' || (*ep != ',' && *ep != '\0') || | |
(ulval == ULONG_MAX && errno == ERANGE)) { | |
break; | |
} | |
details->groups[j++] = (gid_t)ulval; | |
cp = ep + 1; | |
} | |
details->ngroups = j; | |
} | |
break; |
break; |
} |
} |
if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) { |
if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) { |
cp = info[i] + sizeof("runas_uid=") - 1; |
cp = info[i] + sizeof("runas_uid=") - 1; |
if (*cp == '\0') | id = atoid(cp, NULL, NULL, &errstr); |
break; | if (errstr != NULL) |
errno = 0; | fatalx(_("%s: %s"), info[i], _(errstr)); |
ulval = strtoul(cp, &ep, 0); | details->uid = (uid_t)id; |
if (*cp != '\0' && *ep == '\0' && | SET(details->flags, CD_SET_UID); |
(errno != ERANGE || ulval != ULONG_MAX)) { | break; |
details->uid = (uid_t)ulval; | } |
SET(details->flags, CD_SET_UID); | #ifdef HAVE_PRIV_SET |
| if (strncmp("runas_privs=", info[i], sizeof("runas_privs=") - 1) == 0) { |
| const char *endp; |
| cp = info[i] + sizeof("runas_privs=") - 1; |
| if (*cp != '\0') { |
| details->privs = priv_str_to_set(cp, ",", &endp); |
| if (details->privs == NULL) |
| warning("invalid runas_privs %s", endp); |
} |
} |
break; |
break; |
} |
} |
|
if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) { |
|
const char *endp; |
|
cp = info[i] + sizeof("runas_limitprivs=") - 1; |
|
if (*cp != '\0') { |
|
details->limitprivs = priv_str_to_set(cp, ",", &endp); |
|
if (details->limitprivs == NULL) |
|
warning("invalid runas_limitprivs %s", endp); |
|
} |
|
break; |
|
} |
|
#endif /* HAVE_PRIV_SET */ |
break; |
break; |
case 's': |
case 's': |
SET_STRING("selinux_role=", selinux_role) |
SET_STRING("selinux_role=", selinux_role) |
SET_STRING("selinux_type=", selinux_type) |
SET_STRING("selinux_type=", selinux_type) |
if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) { |
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); |
SET(details->flags, CD_SET_UTMP); |
break; |
break; |
} |
} |
if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) { |
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); |
SET(details->flags, CD_SUDOEDIT); |
break; |
break; |
} |
} |
break; |
break; |
case 't': |
case 't': |
if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { |
if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { |
cp = info[i] + sizeof("timeout=") - 1; |
|
if (*cp == '\0') |
|
break; |
|
errno = 0; |
errno = 0; |
lval = strtol(cp, &ep, 0); | cp = info[i] + sizeof("timeout=") - 1; |
if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 10); |
!(errno == ERANGE && | if (*cp == '\0' || *ep != '\0') |
(lval == LONG_MAX || lval == LONG_MIN)) && | fatalx(_("%s: %s"), info[i], _("invalid value")); |
lval <= INT_MAX && lval >= 0) { | if ((errno == ERANGE && |
details->timeout = (int)lval; | (lval == LONG_MAX || lval == LONG_MIN)) || |
SET(details->flags, CD_SET_TIMEOUT); | (lval > INT_MAX || lval < 0)) |
} | fatalx(_("%s: %s"), info[i], _("value out of range")); |
| details->timeout = (int)lval; |
| SET(details->flags, CD_SET_TIMEOUT); |
break; |
break; |
} |
} |
break; |
break; |
case 'u': |
case 'u': |
if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) { |
if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) { |
cp = info[i] + sizeof("umask=") - 1; |
|
if (*cp == '\0') |
|
break; |
|
errno = 0; |
errno = 0; |
ulval = strtoul(cp, &ep, 8); | cp = info[i] + sizeof("umask=") - 1; |
if (*cp != '\0' && *ep == '\0' && | lval = strtol(cp, &ep, 8); |
(errno != ERANGE || ulval != ULONG_MAX)) { | if (*cp == '\0' || *ep != '\0') |
details->umask = (uid_t)ulval; | fatalx(_("%s: %s"), info[i], _("invalid value")); |
SET(details->flags, CD_SET_UMASK); | if ((errno == ERANGE && |
} | (lval == LONG_MAX || lval == LONG_MIN)) || |
| (lval > 0777 || lval < 0)) |
| fatalx(_("%s: %s"), info[i], _("value out of range")); |
| details->umask = (mode_t)lval; |
| SET(details->flags, CD_SET_UMASK); |
break; |
break; |
} |
} |
if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) { |
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); |
SET(details->flags, CD_USE_PTY); |
break; |
break; |
} |
} |
Line 707 command_info_to_details(char * const info[], struct co
|
Line 729 command_info_to_details(char * const info[], struct co
|
if (!ISSET(details->flags, CD_SET_EUID)) |
if (!ISSET(details->flags, CD_SET_EUID)) |
details->euid = details->uid; |
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) |
|
fatal(NULL); |
|
#ifdef HAVE_SETAUTHDB |
|
aix_restoreauthdb(); |
|
#endif |
|
|
#ifdef HAVE_SELINUX |
#ifdef HAVE_SELINUX |
if (details->selinux_role != NULL && is_selinux_enabled() > 0) |
if (details->selinux_role != NULL && is_selinux_enabled() > 0) |
SET(details->flags, CD_RBAC_ENABLED); |
SET(details->flags, CD_RBAC_ENABLED); |
#endif |
#endif |
|
debug_return; |
} |
} |
|
|
|
static void |
|
sudo_check_suid(const char *sudo) |
|
{ |
|
char pathbuf[PATH_MAX]; |
|
struct stat sb; |
|
bool qualified; |
|
debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM) |
|
|
|
if (geteuid() != 0) { |
|
/* Search for sudo binary in PATH if not fully qualified. */ |
|
qualified = strchr(sudo, '/') != NULL; |
|
if (!qualified) { |
|
char *path = getenv_unhooked("PATH"); |
|
if (path != NULL) { |
|
int len; |
|
char *cp, *colon; |
|
|
|
cp = path = estrdup(path); |
|
do { |
|
if ((colon = strchr(cp, ':'))) |
|
*colon = '\0'; |
|
len = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", cp, sudo); |
|
if (len <= 0 || len >= sizeof(pathbuf)) |
|
continue; |
|
if (access(pathbuf, X_OK) == 0) { |
|
sudo = pathbuf; |
|
qualified = true; |
|
break; |
|
} |
|
cp = colon + 1; |
|
} while (colon); |
|
efree(path); |
|
} |
|
} |
|
|
|
if (qualified && stat(sudo, &sb) == 0) { |
|
/* Try to determine why sudo was not running as root. */ |
|
if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) { |
|
fatalx( |
|
_("%s must be owned by uid %d and have the setuid bit set"), |
|
sudo, ROOT_UID); |
|
} else { |
|
fatalx(_("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, sudo); |
|
} |
|
} else { |
|
fatalx( |
|
_("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. |
* Disable core dumps to avoid dropping a core with user password in it. |
* We will reset this limit before executing the command. |
* We will reset this limit before executing the command. |
Line 721 command_info_to_details(char * const info[], struct co
|
Line 809 command_info_to_details(char * const info[], struct co
|
static void |
static void |
disable_coredumps(void) |
disable_coredumps(void) |
{ |
{ |
#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)) | #if defined(RLIMIT_CORE) |
struct rlimit rl; |
struct rlimit rl; |
#endif | debug_decl(disable_coredumps, SUDO_DEBUG_UTIL) |
|
|
#if defined(__linux__) |
|
/* |
/* |
* Unlimit the number of processes since Linux's setuid() will | * Turn off core dumps? |
* apply resource limits when changing uid and return EAGAIN if | |
* nproc would be violated by the uid switch. | |
*/ |
*/ |
|
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); |
|
} |
|
debug_return; |
|
#endif /* RLIMIT_CORE */ |
|
} |
|
|
|
/* |
|
* Unlimit the number of processes since Linux's setuid() will |
|
* apply resource limits when changing uid and return EAGAIN if |
|
* nproc would be exceeded by the uid switch. |
|
*/ |
|
static void |
|
unlimit_nproc(void) |
|
{ |
|
#ifdef __linux__ |
|
struct rlimit rl; |
|
debug_decl(unlimit_nproc, SUDO_DEBUG_UTIL) |
|
|
(void) getrlimit(RLIMIT_NPROC, &nproclimit); |
(void) getrlimit(RLIMIT_NPROC, &nproclimit); |
rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; |
rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; |
if (setrlimit(RLIMIT_NPROC, &rl)) { | if (setrlimit(RLIMIT_NPROC, &rl) != 0) { |
memcpy(&rl, &nproclimit, sizeof(struct rlimit)); |
memcpy(&rl, &nproclimit, sizeof(struct rlimit)); |
rl.rlim_cur = rl.rlim_max; |
rl.rlim_cur = rl.rlim_max; |
(void)setrlimit(RLIMIT_NPROC, &rl); |
(void)setrlimit(RLIMIT_NPROC, &rl); |
} |
} |
|
debug_return; |
#endif /* __linux__ */ |
#endif /* __linux__ */ |
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) |
|
/* |
|
* 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 */ |
|
} |
} |
|
|
#ifdef HAVE_PROJECT_H |
|
static void |
|
set_project(struct passwd *pw) |
|
{ |
|
struct project proj; |
|
char buf[PROJECT_BUFSZ]; |
|
int errval; |
|
|
|
/* |
|
* Collect the default project for the user and settaskid |
|
*/ |
|
setprojent(); |
|
if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) { |
|
errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL); |
|
switch(errval) { |
|
case 0: |
|
break; |
|
case SETPROJ_ERR_TASK: |
|
switch (errno) { |
|
case EAGAIN: |
|
warningx(_("resource control limit has been reached")); |
|
break; |
|
case ESRCH: |
|
warningx(_("user \"%s\" is not a member of project \"%s\""), |
|
pw->pw_name, proj.pj_name); |
|
break; |
|
case EACCES: |
|
warningx(_("the invoking task is final")); |
|
break; |
|
default: |
|
warningx(_("could not join project \"%s\""), proj.pj_name); |
|
} |
|
case SETPROJ_ERR_POOL: |
|
switch (errno) { |
|
case EACCES: |
|
warningx(_("no resource pool accepting default bindings " |
|
"exists for project \"%s\""), proj.pj_name); |
|
break; |
|
case ESRCH: |
|
warningx(_("specified resource pool does not exist for " |
|
"project \"%s\""), proj.pj_name); |
|
break; |
|
default: |
|
warningx(_("could not bind to default resource pool for " |
|
"project \"%s\""), proj.pj_name); |
|
} |
|
break; |
|
default: |
|
if (errval <= 0) { |
|
warningx(_("setproject failed for project \"%s\""), proj.pj_name); |
|
} else { |
|
warningx(_("warning, resource control assignment failed for " |
|
"project \"%s\""), proj.pj_name); |
|
} |
|
} |
|
} else { |
|
warning("getdefaultproj"); |
|
} |
|
endprojent(); |
|
} |
|
#endif /* HAVE_PROJECT_H */ |
|
|
|
/* |
/* |
* Disable execution of child processes in the command we are about | * Restore saved value of RLIMIT_NPROC. |
* 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 |
static void |
disable_execute(struct command_details *details) | restore_nproc(void) |
{ |
{ |
#ifdef _PATH_SUDO_NOEXEC | #ifdef __linux__ |
char *cp, **ev, **nenvp; | debug_decl(restore_nproc, SUDO_DEBUG_UTIL) |
int env_len = 0, env_size = 128; | |
#endif /* _PATH_SUDO_NOEXEC */ | |
|
|
#ifdef HAVE_PRIV_SET | (void) setrlimit(RLIMIT_NPROC, &nproclimit); |
/* 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 | debug_return; |
nenvp = emalloc2(env_size, sizeof(char *)); | #endif /* __linux__ */ |
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() |
* 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) |
exec_setup(struct command_details *details, const char *ptyname, int ptyfd) |
{ |
{ |
int rval = FALSE; | bool rval = false; |
struct passwd *pw; | 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 |
#ifdef HAVE_SELINUX |
if (ISSET(details->flags, CD_RBAC_ENABLED)) { |
if (ISSET(details->flags, CD_RBAC_ENABLED)) { |
if (selinux_setup(details->selinux_role, details->selinux_type, |
if (selinux_setup(details->selinux_role, details->selinux_type, |
Line 918 exec_setup(struct command_details *details, const char
|
Line 882 exec_setup(struct command_details *details, const char
|
} |
} |
#endif |
#endif |
|
|
if (pw != NULL) { | if (details->pw != NULL) { |
#ifdef HAVE_PROJECT_H |
#ifdef HAVE_PROJECT_H |
set_project(pw); | set_project(details->pw); |
#endif |
#endif |
|
#ifdef HAVE_PRIV_SET |
|
if (details->privs != NULL) { |
|
if (setppriv(PRIV_SET, PRIV_INHERITABLE, details->privs) != 0) { |
|
warning("unable to set privileges"); |
|
goto done; |
|
} |
|
} |
|
if (details->limitprivs != NULL) { |
|
if (setppriv(PRIV_SET, PRIV_LIMIT, details->limitprivs) != 0) { |
|
warning("unable to set limit privileges"); |
|
goto done; |
|
} |
|
} else if (details->privs != NULL) { |
|
if (setppriv(PRIV_SET, PRIV_LIMIT, details->privs) != 0) { |
|
warning("unable to set limit privileges"); |
|
goto done; |
|
} |
|
} |
|
#endif /* HAVE_PRIV_SET */ |
|
|
#ifdef HAVE_GETUSERATTR |
#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 |
#endif |
#ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
if (details->login_class) { |
if (details->login_class) { |
Line 931 exec_setup(struct command_details *details, const char
|
Line 915 exec_setup(struct command_details *details, const char
|
login_cap_t *lc; |
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); |
lc = login_getclass((char *)details->login_class); |
if (!lc) { |
if (!lc) { |
Line 939 exec_setup(struct command_details *details, const char
|
Line 924 exec_setup(struct command_details *details, const char
|
errno = ENOENT; |
errno = ENOENT; |
goto done; |
goto done; |
} |
} |
flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; | if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
if (setusercontext(lc, pw, pw->pw_uid, flags)) { | /* Set everything except user, group and login name. */ |
if (pw->pw_uid != ROOT_UID) { | flags = LOGIN_SETALL; |
warning(_("unable to set user context")); | 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)) { |
| warning(_("unable to set user context")); |
| if (details->pw->pw_uid != ROOT_UID) |
goto done; |
goto done; |
} else |
|
warning(_("unable to set user context")); |
|
} |
} |
} |
} |
#endif /* HAVE_LOGIN_CAP_H */ |
#endif /* HAVE_LOGIN_CAP_H */ |
Line 954 exec_setup(struct command_details *details, const char
|
Line 944 exec_setup(struct command_details *details, const char
|
/* |
/* |
* Set groups, including supplementary group vector. |
* 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 |
#ifdef HAVE_SETEUID |
if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) { |
if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) { |
warning(_("unable to set effective gid to runas gid %u"), |
warning(_("unable to set effective gid to runas gid %u"), |
Line 967 exec_setup(struct command_details *details, const char
|
Line 965 exec_setup(struct command_details *details, const char
|
goto done; |
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 (ISSET(details->flags, CD_SET_PRIORITY)) { |
if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) { |
if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) { |
warning(_("unable to set process priority")); |
warning(_("unable to set process priority")); |
Line 991 exec_setup(struct command_details *details, const char
|
Line 980 exec_setup(struct command_details *details, const char
|
} |
} |
} |
} |
|
|
if (ISSET(details->flags, CD_NOEXEC)) | /* |
disable_execute(details); | * Unlimit the number of processes since Linux's setuid() will |
| * return EAGAIN if RLIMIT_NPROC would be exceeded by the uid switch. |
| */ |
| unlimit_nproc(); |
|
|
#ifdef HAVE_SETRESUID |
#ifdef HAVE_SETRESUID |
if (setresuid(details->uid, details->euid, details->euid) != 0) { |
if (setresuid(details->uid, details->euid, details->euid) != 0) { |
Line 1014 exec_setup(struct command_details *details, const char
|
Line 1006 exec_setup(struct command_details *details, const char
|
} |
} |
#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */ |
#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */ |
|
|
|
/* Restore previous value of RLIMIT_NPROC. */ |
|
restore_nproc(); |
|
|
/* |
/* |
* Only change cwd if we have chroot()ed or the policy modules |
* Only change cwd if we have chroot()ed or the policy modules |
* specifies a different cwd. Must be done after uid change. |
* specifies a different cwd. Must be done after uid change. |
Line 1028 exec_setup(struct command_details *details, const char
|
Line 1023 exec_setup(struct command_details *details, const char
|
} |
} |
} |
} |
|
|
/* | rval = true; |
* Restore nproc resource limit if pam_limits didn't do it for us. | |
* We must do this *after* the uid change to avoid potential EAGAIN | |
* from setuid(). | |
*/ | |
#if defined(__linux__) | |
{ | |
struct rlimit rl; | |
if (getrlimit(RLIMIT_NPROC, &rl) == 0) { | |
if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY) | |
(void) setrlimit(RLIMIT_NPROC, &nproclimit); | |
} | |
} | |
#endif | |
|
|
rval = TRUE; |
|
|
|
done: |
done: |
return rval; | debug_return_bool(rval); |
} |
} |
|
|
/* |
/* |
Line 1058 run_command(struct command_details *details)
|
Line 1038 run_command(struct command_details *details)
|
struct plugin_container *plugin; |
struct plugin_container *plugin; |
struct command_status cstat; |
struct command_status cstat; |
int exitcode = 1; |
int exitcode = 1; |
|
debug_decl(run_command, SUDO_DEBUG_EXEC) |
|
|
cstat.type = CMD_INVALID; |
cstat.type = CMD_INVALID; |
cstat.val = 0; |
cstat.val = 0; |
|
|
sudo_execve(details, &cstat); | sudo_execute(details, &cstat); |
|
|
switch (cstat.type) { |
switch (cstat.type) { |
case CMD_ERRNO: |
case CMD_ERRNO: |
/* exec_setup() or execve() returned an error. */ |
/* 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); |
policy_close(&policy_plugin, 0, cstat.val); |
tq_foreach_fwd(&io_plugins, plugin) { |
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); |
iolog_close(plugin, 0, cstat.val); |
} |
} |
exitcode = 1; |
exitcode = 1; |
break; |
break; |
case CMD_WSTATUS: |
case CMD_WSTATUS: |
/* Command ran, exited or was killed. */ |
/* 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); |
policy_close(&policy_plugin, cstat.val, 0); |
tq_foreach_fwd(&io_plugins, plugin) { |
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); |
iolog_close(plugin, cstat.val, 0); |
} |
} |
if (WIFEXITED(cstat.val)) |
if (WIFEXITED(cstat.val)) |
Line 1092 run_command(struct command_details *details)
|
Line 1077 run_command(struct command_details *details)
|
warningx(_("unexpected child termination condition: %d"), cstat.type); |
warningx(_("unexpected child termination condition: %d"), cstat.type); |
break; |
break; |
} |
} |
return exitcode; | debug_return_int(exitcode); |
} |
} |
|
|
static int |
static int |
policy_open(struct plugin_container *plugin, char * const settings[], |
policy_open(struct plugin_container *plugin, char * const settings[], |
char * const user_info[], char * const user_env[]) |
char * const user_info[], char * const user_env[]) |
{ |
{ |
return plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation, | int rval; |
_sudo_printf, settings, user_info, user_env); | 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 |
static void |
policy_close(struct plugin_container *plugin, int exit_status, int error) |
policy_close(struct plugin_container *plugin, int exit_status, int error) |
{ |
{ |
plugin->u.policy->close(exit_status, error); | debug_decl(policy_close, SUDO_DEBUG_PCOMM) |
| if (plugin->u.policy->close != NULL) |
| plugin->u.policy->close(exit_status, error); |
| else |
| warning(_("unable to execute %s"), command_details.command); |
| debug_return; |
} |
} |
|
|
static int |
static int |
policy_show_version(struct plugin_container *plugin, int verbose) |
policy_show_version(struct plugin_container *plugin, int verbose) |
{ |
{ |
return plugin->u.policy->show_version(verbose); | debug_decl(policy_show_version, SUDO_DEBUG_PCOMM) |
| if (plugin->u.policy->show_version == NULL) |
| debug_return_bool(true); |
| debug_return_bool(plugin->u.policy->show_version(verbose)); |
} |
} |
|
|
static int |
static int |
Line 1120 policy_check(struct plugin_container *plugin, int argc
|
Line 1129 policy_check(struct plugin_container *plugin, int argc
|
char *env_add[], char **command_info[], char **argv_out[], |
char *env_add[], char **command_info[], char **argv_out[], |
char **user_env_out[]) |
char **user_env_out[]) |
{ |
{ |
return plugin->u.policy->check_policy(argc, argv, env_add, command_info, | debug_decl(policy_check, SUDO_DEBUG_PCOMM) |
argv_out, user_env_out); | if (plugin->u.policy->check_policy == NULL) { |
| fatalx(_("policy plugin %s is missing the `check_policy' method"), |
| plugin->name); |
| } |
| debug_return_bool(plugin->u.policy->check_policy(argc, argv, env_add, |
| command_info, argv_out, user_env_out)); |
} |
} |
|
|
static int |
static int |
policy_list(struct plugin_container *plugin, int argc, char * const argv[], |
policy_list(struct plugin_container *plugin, int argc, char * const argv[], |
int verbose, const char *list_user) |
int verbose, const char *list_user) |
{ |
{ |
|
debug_decl(policy_list, SUDO_DEBUG_PCOMM) |
if (plugin->u.policy->list == NULL) { |
if (plugin->u.policy->list == NULL) { |
warningx(_("policy plugin %s does not support listing privileges"), |
warningx(_("policy plugin %s does not support listing privileges"), |
plugin->name); |
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 |
static int |
policy_validate(struct plugin_container *plugin) |
policy_validate(struct plugin_container *plugin) |
{ |
{ |
|
debug_decl(policy_validate, SUDO_DEBUG_PCOMM) |
if (plugin->u.policy->validate == NULL) { |
if (plugin->u.policy->validate == NULL) { |
warningx(_("policy plugin %s does not support the -v option"), |
warningx(_("policy plugin %s does not support the -v option"), |
plugin->name); |
plugin->name); |
return FALSE; | debug_return_bool(false); |
} |
} |
return plugin->u.policy->validate(); | debug_return_bool(plugin->u.policy->validate()); |
} |
} |
|
|
static void |
static void |
policy_invalidate(struct plugin_container *plugin, int remove) |
policy_invalidate(struct plugin_container *plugin, int remove) |
{ |
{ |
|
debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM) |
if (plugin->u.policy->invalidate == NULL) { |
if (plugin->u.policy->invalidate == NULL) { |
errorx(1, _("policy plugin %s does not support the -k/-K options"), | fatalx(_("policy plugin %s does not support the -k/-K options"), |
plugin->name); |
plugin->name); |
} |
} |
plugin->u.policy->invalidate(remove); |
plugin->u.policy->invalidate(remove); |
|
debug_return; |
} |
} |
|
|
static int | int |
policy_init_session(struct plugin_container *plugin, struct passwd *pwd) | policy_init_session(struct command_details *details) |
{ |
{ |
if (plugin->u.policy->init_session) | int rval = true; |
return plugin->u.policy->init_session(pwd); | debug_decl(policy_init_session, SUDO_DEBUG_PCOMM) |
return TRUE; | |
| 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 |
static int |
Line 1171 iolog_open(struct plugin_container *plugin, char * con
|
Line 1204 iolog_open(struct plugin_container *plugin, char * con
|
int argc, char * const argv[], char * const user_env[]) |
int argc, char * const argv[], char * const user_env[]) |
{ |
{ |
int rval; |
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) { |
switch (plugin->u.generic->version) { |
case SUDO_API_MKVERSION(1, 0): |
case SUDO_API_MKVERSION(1, 0): |
Line 1181 iolog_open(struct plugin_container *plugin, char * con
|
Line 1215 iolog_open(struct plugin_container *plugin, char * con
|
sudo_conversation, _sudo_printf, settings, user_info, argc, argv, |
sudo_conversation, _sudo_printf, settings, user_info, argc, argv, |
user_env); |
user_env); |
break; |
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: |
default: |
rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, |
rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, |
_sudo_printf, settings, user_info, command_info, argc, argv, | _sudo_printf, settings, user_info, command_info, |
user_env); | argc, argv, user_env, plugin->options); |
} |
} |
return rval; | debug_return_bool(rval); |
} |
} |
|
|
static void |
static void |
iolog_close(struct plugin_container *plugin, int exit_status, int error) |
iolog_close(struct plugin_container *plugin, int exit_status, int error) |
{ |
{ |
plugin->u.io->close(exit_status, error); | debug_decl(iolog_close, SUDO_DEBUG_PCOMM) |
| if (plugin->u.io->close != NULL) |
| plugin->u.io->close(exit_status, error); |
| debug_return; |
} |
} |
|
|
static int |
static int |
iolog_show_version(struct plugin_container *plugin, int verbose) |
iolog_show_version(struct plugin_container *plugin, int verbose) |
{ |
{ |
return plugin->u.io->show_version(verbose); | debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM) |
| if (plugin->u.io->show_version == NULL) |
| debug_return_bool(true); |
| 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 | static void |
sudo_debug(int level, const char *fmt, ...) | iolog_unlink(struct plugin_container *plugin) |
{ |
{ |
va_list ap; | debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM) |
char *buf; | |
|
|
if (level > debug_level) | /* Deregister hooks, if any. */ |
return; | 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 */ | debug_return; |
va_start(ap, fmt); | |
evasprintf(&buf, fmt, ap); | |
va_end(ap); | |
fprintf(stderr, "%s: %s\n", getprogname(), buf); | |
efree(buf); | |
} |
} |