version 1.1, 2012/02/21 16:23:02
|
version 1.1.1.3, 2012/10/09 09:29:52
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2009-2012 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 25
|
Line 25
|
#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 66
|
Line 63
|
#endif |
#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 86
|
# 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 | #if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) |
# include <priv.h> | # include <sys/sysctl.h> |
| #elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) |
| # include <sys/sysctl.h> |
| # include <sys/user.h> |
#endif |
#endif |
|
|
#include "sudo.h" |
#include "sudo.h" |
Line 102 struct plugin_container policy_plugin;
|
Line 105 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, *runas_user, *runas_group; /* extern for parse_args.c */ |
int debug_level; | 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 130 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 138 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 /* RLIMIT_CORE */ |
#if defined(__linux__) |
#if defined(__linux__) |
static struct rlimit nproclimit; |
static struct rlimit nproclimit; |
#endif |
#endif |
Line 156 static struct rlimit nproclimit;
|
Line 150 static struct rlimit nproclimit;
|
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; |
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__) |
#if defined(SUDO_DEVEL) && defined(__OpenBSD__) |
extern char *malloc_options; | { |
malloc_options = "AFGJPR"; | extern char *malloc_options; |
| malloc_options = "AFGJPR"; |
| } |
#endif |
#endif |
|
|
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
Line 187 main(int argc, char *argv[], char *envp[])
|
Line 184 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 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(); |
|
fix_fds(); |
fix_fds(); |
|
|
|
/* Read sudo.conf. */ |
|
sudo_conf_read(); |
|
|
/* 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 213 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")); |
errorx(1, _("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 |
Line 230 main(int argc, char *argv[], char *envp[])
|
Line 232 main(int argc, char *argv[], char *envp[])
|
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 251 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 268 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); |
Line 280 main(int argc, char *argv[], char *envp[])
|
Line 282 main(int argc, char *argv[], char *envp[])
|
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. */ |
|
(void) setuid(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 299 main(int argc, char *argv[], char *envp[])
|
Line 305 main(int argc, char *argv[], char *envp[])
|
default: |
default: |
errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode); |
errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode); |
} |
} |
|
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); |
exit(exitcode); |
exit(exitcode); |
} |
} |
|
|
Line 310 static void
|
Line 317 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 330 fix_fds(void)
|
Line 338 fix_fds(void)
|
if (devnull > STDERR_FILENO) |
if (devnull > STDERR_FILENO) |
close(devnull); |
close(devnull); |
} |
} |
|
debug_return; |
} |
} |
|
|
/* |
/* |
Line 340 static int
|
Line 349 static int
|
fill_group_list(struct user_details *ud) |
fill_group_list(struct user_details *ud) |
{ |
{ |
int maxgroups, tries, rval = -1; |
int maxgroups, tries, rval = -1; |
|
debug_decl(fill_group_list, SUDO_DEBUG_UTIL) |
|
|
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) |
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) |
maxgroups = (int)sysconf(_SC_NGROUPS_MAX); |
maxgroups = (int)sysconf(_SC_NGROUPS_MAX); |
Line 360 fill_group_list(struct user_details *ud)
|
Line 370 fill_group_list(struct user_details *ud)
|
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); |
rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); |
} |
} |
return rval; | debug_return_int(rval); |
} |
} |
|
|
static char * |
static char * |
Line 369 get_user_groups(struct user_details *ud)
|
Line 379 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; |
|
debug_decl(get_user_groups, SUDO_DEBUG_UTIL) |
|
|
/* |
/* |
* Systems with mbr_check_membership() support more than NGROUPS_MAX |
* Systems with mbr_check_membership() support more than NGROUPS_MAX |
Line 402 get_user_groups(struct user_details *ud)
|
Line 413 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 423 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[MAXHOSTNAMELEN]; |
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 441 get_user_info(struct user_details *ud)
|
Line 462 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 456 get_user_info(struct user_details *ud)
|
Line 483 get_user_info(struct user_details *ud)
|
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")); |
errorx(1, _("unable to allocate memory")); |
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 479 get_user_info(struct user_details *ud)
|
Line 506 get_user_info(struct user_details *ud)
|
|
|
user_info[++i] = NULL; |
user_info[++i] = NULL; |
|
|
return user_info; | debug_return_ptr(user_info); |
} |
} |
|
|
/* |
/* |
Line 492 command_info_to_details(char * const info[], struct co
|
Line 519 command_info_to_details(char * const info[], struct co
|
long lval; |
long lval; |
unsigned long ulval; |
unsigned long ulval; |
char *cp, *ep; |
char *cp, *ep; |
|
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 530 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) |
Line 545 command_info_to_details(char * const info[], struct co
|
Line 574 command_info_to_details(char * const info[], struct co
|
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 648 command_info_to_details(char * const info[], struct co
|
Line 670 command_info_to_details(char * const info[], struct co
|
} |
} |
break; |
break; |
} |
} |
|
#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') |
|
break; |
|
errno = 0; |
|
details->privs = priv_str_to_set(cp, ",", &endp); |
|
if (details->privs == NULL) |
|
warning("invalid runas_privs %s", endp); |
|
} |
|
if (strncmp("runas_limitprivs=", info[i], sizeof("runas_limitprivs=") - 1) == 0) { |
|
const char *endp; |
|
cp = info[i] + sizeof("runas_limitprivs=") - 1; |
|
if (*cp == '\0') |
|
break; |
|
errno = 0; |
|
details->limitprivs = priv_str_to_set(cp, ",", &endp); |
|
if (details->limitprivs == NULL) |
|
warning("invalid runas_limitprivs %s", endp); |
|
} |
|
#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; |
} |
} |
Line 695 command_info_to_details(char * const info[], struct co
|
Line 739 command_info_to_details(char * const info[], struct co
|
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 751 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) |
|
errorx(1, _("unable to allocate memory")); |
|
#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 *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. |
* 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 803 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(__linux__) || defined(RLIMIT_CORE) |
struct rlimit rl; |
struct rlimit rl; |
#endif |
#endif |
|
debug_decl(disable_coredumps, SUDO_DEBUG_UTIL) |
|
|
#if defined(__linux__) |
#if defined(__linux__) |
/* |
/* |
Line 739 disable_coredumps(void)
|
Line 822 disable_coredumps(void)
|
(void)setrlimit(RLIMIT_NPROC, &rl); |
(void)setrlimit(RLIMIT_NPROC, &rl); |
} |
} |
#endif /* __linux__ */ |
#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); | if (sudo_conf_disable_coredump()) { |
memcpy(&rl, &corelimit, sizeof(struct rlimit)); | (void) getrlimit(RLIMIT_CORE, &corelimit); |
rl.rlim_cur = 0; | memcpy(&rl, &corelimit, sizeof(struct rlimit)); |
(void) setrlimit(RLIMIT_CORE, &rl); | rl.rlim_cur = 0; |
#endif /* RLIMIT_CORE && !SUDO_DEVEL */ | (void) setrlimit(RLIMIT_CORE, &rl); |
| } |
| #endif /* RLIMIT_CORE */ |
| debug_return; |
} |
} |
|
|
#ifdef HAVE_PROJECT_H |
#ifdef HAVE_PROJECT_H |
Line 757 set_project(struct passwd *pw)
|
Line 843 set_project(struct passwd *pw)
|
struct project proj; |
struct project proj; |
char buf[PROJECT_BUFSZ]; |
char buf[PROJECT_BUFSZ]; |
int errval; |
int errval; |
|
debug_decl(set_project, SUDO_DEBUG_UTIL) |
|
|
/* |
/* |
* Collect the default project for the user and settaskid |
* Collect the default project for the user and settaskid |
Line 809 set_project(struct passwd *pw)
|
Line 896 set_project(struct passwd *pw)
|
warning("getdefaultproj"); |
warning("getdefaultproj"); |
} |
} |
endprojent(); |
endprojent(); |
|
debug_return; |
} |
} |
#endif /* HAVE_PROJECT_H */ |
#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() |
* 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 918 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 951 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 960 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; |
| 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")); |
warning(_("unable to set user context")); |
goto done; |
goto done; |
} else |
} else |
Line 954 exec_setup(struct command_details *details, const char
|
Line 982 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 1003 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 1018 exec_setup(struct command_details *details, const char
|
} |
} |
} |
} |
|
|
if (ISSET(details->flags, CD_NOEXEC)) |
|
disable_execute(details); |
|
|
|
#ifdef HAVE_SETRESUID |
#ifdef HAVE_SETRESUID |
if (setresuid(details->uid, details->euid, details->euid) != 0) { |
if (setresuid(details->uid, details->euid, details->euid) != 0) { |
warning(_("unable to change to runas uid (%u, %u)"), details->uid, |
warning(_("unable to change to runas uid (%u, %u)"), details->uid, |
Line 1029 exec_setup(struct command_details *details, const char
|
Line 1053 exec_setup(struct command_details *details, const char
|
} |
} |
|
|
/* |
/* |
* Restore nproc resource limit if pam_limits didn't do it for us. | * SuSE Enterprise Linux uses RLIMIT_NPROC and _SC_CHILD_MAX |
| * interchangably. This causes problems when setting RLIMIT_NPROC |
| * to RLIM_INFINITY due to a bug in bash where bash tries to honor |
| * the value of _SC_CHILD_MAX but treats a value of -1 as an error, |
| * and uses a default value of 32 instead. |
| * |
| * To work around this problem, we restore the nproc resource limit |
| * if sysconf(_SC_CHILD_MAX) is negative. In most cases, pam_limits |
| * will set RLIMIT_NPROC for us. |
| * |
* We must do this *after* the uid change to avoid potential EAGAIN |
* We must do this *after* the uid change to avoid potential EAGAIN |
* from setuid(). |
* from setuid(). |
*/ |
*/ |
#if defined(__linux__) | #if defined(__linux__) && defined(_SC_CHILD_MAX) |
{ |
{ |
struct rlimit rl; |
struct rlimit rl; |
if (getrlimit(RLIMIT_NPROC, &rl) == 0) { | long l; |
| errno = 0; |
| l = sysconf(_SC_CHILD_MAX); |
| if (l == -1 && errno == 0 && getrlimit(RLIMIT_NPROC, &rl) == 0) { |
if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY) |
if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY) |
(void) setrlimit(RLIMIT_NPROC, &nproclimit); |
(void) setrlimit(RLIMIT_NPROC, &nproclimit); |
} |
} |
} |
} |
#endif |
#endif |
|
|
rval = TRUE; | rval = true; |
|
|
done: |
done: |
return rval; | debug_return_bool(rval); |
} |
} |
|
|
/* |
/* |
Line 1058 run_command(struct command_details *details)
|
Line 1094 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 1133 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) |
{ |
{ |
|
debug_decl(policy_close, SUDO_DEBUG_PCOMM) |
plugin->u.policy->close(exit_status, error); |
plugin->u.policy->close(exit_status, error); |
|
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) |
| debug_return_bool(plugin->u.policy->show_version(verbose)); |
} |
} |
|
|
static int |
static int |
Line 1120 policy_check(struct plugin_container *plugin, int argc
|
Line 1180 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); | 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"), |
errorx(1, _("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 1251 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 1262 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) |
{ |
{ |
|
debug_decl(iolog_close, SUDO_DEBUG_PCOMM) |
plugin->u.io->close(exit_status, error); |
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) |
| 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); | |
} |
} |