|
version 1.1, 2012/02/21 16:23:02
|
version 1.1.1.4, 2013/07/22 10:46:12
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * Copyright (c) 1993-1996, 1998-2011 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 1993-1996, 1998-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 16
|
Line 16
|
| * Sponsored in part by the Defense Advanced Research Projects |
* Sponsored in part by the Defense Advanced Research Projects |
| * Agency (DARPA) and Air Force Research Laboratory, Air Force |
* Agency (DARPA) and Air Force Research Laboratory, Air Force |
| * Materiel Command, USAF, under agreement number F39502-99-1-0512. |
* Materiel Command, USAF, under agreement number F39502-99-1-0512. |
| * |
|
| * For a brief history of sudo, please see the HISTORY file included |
|
| * with this distribution. |
|
| */ |
*/ |
| |
|
| #define _SUDO_MAIN |
#define _SUDO_MAIN |
|
Line 31
|
Line 28
|
| |
|
| #include <sys/types.h> |
#include <sys/types.h> |
| #include <sys/stat.h> |
#include <sys/stat.h> |
| #include <sys/param.h> |
|
| #include <sys/socket.h> |
#include <sys/socket.h> |
| #include <stdio.h> |
#include <stdio.h> |
| #ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
|
Line 60
|
Line 56
|
| #include <signal.h> |
#include <signal.h> |
| #include <grp.h> |
#include <grp.h> |
| #include <time.h> |
#include <time.h> |
| #ifdef HAVE_SETLOCALE |
|
| # include <locale.h> |
|
| #endif |
|
| #include <netinet/in.h> |
|
| #include <netdb.h> |
#include <netdb.h> |
| #ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
| # include <login_cap.h> |
# include <login_cap.h> |
| # ifndef LOGIN_DEFROOTCLASS |
# ifndef LOGIN_DEFROOTCLASS |
| # define LOGIN_DEFROOTCLASS "daemon" |
# define LOGIN_DEFROOTCLASS "daemon" |
| # endif |
# endif |
| |
# ifndef LOGIN_SETENV |
| |
# define LOGIN_SETENV 0 |
| |
# endif |
| #endif |
#endif |
| #ifdef HAVE_SELINUX |
#ifdef HAVE_SELINUX |
| # include <selinux/selinux.h> |
# include <selinux/selinux.h> |
| #endif |
#endif |
| #include <ctype.h> |
#include <ctype.h> |
| #include <setjmp.h> | #ifndef HAVE_GETADDRINFO |
| | # include "compat/getaddrinfo.h" |
| | #endif |
| |
|
| #include "sudoers.h" |
#include "sudoers.h" |
| #include "interfaces.h" |
|
| #include "sudoers_version.h" |
|
| #include "auth/sudo_auth.h" |
#include "auth/sudo_auth.h" |
| |
#include "secure_path.h" |
| |
|
| /* |
/* |
| * Prototypes |
* Prototypes |
| */ |
*/ |
| static void init_vars(char * const *); | static char *find_editor(int nfiles, char **files, char ***argv_out); |
| | static int cb_runas_default(const char *); |
| | static int cb_sudoers_locale(const char *); |
| static int set_cmnd(void); |
static int set_cmnd(void); |
| |
static void create_admin_success_flag(void); |
| |
static void init_vars(char * const *); |
| |
static void set_fqdn(void); |
| static void set_loginclass(struct passwd *); |
static void set_loginclass(struct passwd *); |
| static void set_runaspw(const char *); |
|
| static void set_runasgr(const char *); |
static void set_runasgr(const char *); |
| static int cb_runas_default(const char *); | static void set_runaspw(const char *); |
| static int sudoers_policy_version(int verbose); | static bool tty_present(void); |
| static int deserialize_info(char * const settings[], char * const user_info[]); | |
| static char *find_editor(int nfiles, char **files, char ***argv_out); | |
| static void create_admin_success_flag(void); | |
| |
|
| /* |
/* |
| * Globals |
* Globals |
| */ |
*/ |
| const char *sudoers_file = _PATH_SUDOERS; |
|
| mode_t sudoers_mode = SUDOERS_MODE; |
|
| uid_t sudoers_uid = SUDOERS_UID; |
|
| gid_t sudoers_gid = SUDOERS_GID; |
|
| struct sudo_user sudo_user; |
struct sudo_user sudo_user; |
| struct passwd *list_pw; |
struct passwd *list_pw; |
| struct interface *interfaces; |
|
| int long_list; |
int long_list; |
| int debug_level; |
|
| uid_t timestamp_uid; |
uid_t timestamp_uid; |
| extern int errorlineno; |
extern int errorlineno; |
| extern int parse_error; | extern bool parse_error; |
| extern char *errorfile; |
extern char *errorfile; |
| #ifdef HAVE_LOGIN_CAP_H |
|
| login_cap_t *lc; |
|
| #endif /* HAVE_LOGIN_CAP_H */ |
|
| #ifdef HAVE_BSD_AUTH_H |
#ifdef HAVE_BSD_AUTH_H |
| char *login_style; |
char *login_style; |
| #endif /* HAVE_BSD_AUTH_H */ |
#endif /* HAVE_BSD_AUTH_H */ |
| sudo_conv_t sudo_conv; |
|
| sudo_printf_t sudo_printf; |
|
| int sudo_mode; |
int sudo_mode; |
| |
|
| static char *prev_user; |
static char *prev_user; |
| static char *runas_user; |
static char *runas_user; |
| static char *runas_group; |
static char *runas_group; |
| static struct sudo_nss_list *snl; |
static struct sudo_nss_list *snl; |
| static const char *interfaces_string; |
|
| static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp; |
|
| |
|
| /* XXX - must be extern for audit bits of sudo_auth.c */ |
/* XXX - must be extern for audit bits of sudo_auth.c */ |
| int NewArgc; |
int NewArgc; |
| char **NewArgv; |
char **NewArgv; |
| |
|
| /* plugin_error.c */ | int |
| extern sigjmp_buf error_jmp; | sudoers_policy_init(void *info, char * const envp[]) |
| |
| static int | |
| sudoers_policy_open(unsigned int version, sudo_conv_t conversation, | |
| sudo_printf_t plugin_printf, char * const settings[], | |
| char * const user_info[], char * const envp[]) | |
| { |
{ |
| volatile int sources = 0; |
volatile int sources = 0; |
| sigaction_t sa; | struct sudo_nss *nss, *nss_next; |
| struct sudo_nss *nss; | debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN) |
| |
|
| if (!sudo_conv) |
|
| sudo_conv = conversation; |
|
| if (!sudo_printf) |
|
| sudo_printf = plugin_printf; |
|
| |
|
| if (sigsetjmp(error_jmp, 1)) { |
|
| /* called via error(), errorx() or log_error() */ |
|
| rewind_perms(); |
|
| return -1; |
|
| } |
|
| |
|
| bindtextdomain("sudoers", LOCALEDIR); |
bindtextdomain("sudoers", LOCALEDIR); |
| |
|
| /* |
|
| * Signal setup: |
|
| * Ignore keyboard-generated signals so the user cannot interrupt |
|
| * us at some point and avoid the logging. |
|
| * Install handler to wait for children when they exit. |
|
| */ |
|
| zero_bytes(&sa, sizeof(sa)); |
|
| sigemptyset(&sa.sa_mask); |
|
| sa.sa_flags = SA_RESTART; |
|
| sa.sa_handler = SIG_IGN; |
|
| (void) sigaction(SIGINT, &sa, &saved_sa_int); |
|
| (void) sigaction(SIGQUIT, &sa, &saved_sa_quit); |
|
| (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp); |
|
| |
|
| sudo_setpwent(); |
sudo_setpwent(); |
| sudo_setgrent(); |
sudo_setgrent(); |
| |
|
| |
/* Register fatal/fatalx callback. */ |
| |
fatal_callback_register(sudoers_cleanup); |
| |
|
| /* Initialize environment functions (including replacements). */ |
/* Initialize environment functions (including replacements). */ |
| env_init(envp); |
env_init(envp); |
| |
|
| /* Setup defaults data structures. */ |
/* Setup defaults data structures. */ |
| init_defaults(); |
init_defaults(); |
| |
|
| /* Parse settings and user_info */ | /* Parse info from front-end. */ |
| sudo_mode = deserialize_info(settings, user_info); | sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group); |
| |
|
| init_vars(envp); /* XXX - move this later? */ |
init_vars(envp); /* XXX - move this later? */ |
| |
|
|
Line 194 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 151 sudoers_policy_open(unsigned int version, sudo_conv_t
|
| set_perms(PERM_ROOT); |
set_perms(PERM_ROOT); |
| |
|
| /* Open and parse sudoers, set global defaults */ |
/* Open and parse sudoers, set global defaults */ |
| tq_foreach_fwd(snl, nss) { | for (nss = snl->first; nss != NULL; nss = nss_next) { |
| if (nss->open(nss) == 0 && nss->parse(nss) == 0) { | nss_next = nss->next; |
| sources++; | if (nss->open(nss) == 0 && nss->parse(nss) == 0) { |
| if (nss->setdefs(nss) != 0) | sources++; |
| log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries")); | if (nss->setdefs(nss) != 0) |
| } | log_warning(NO_STDERR, N_("problem with defaults entries")); |
| | } else { |
| | tq_remove(snl, nss); |
| | } |
| } |
} |
| if (sources == 0) { |
if (sources == 0) { |
| warningx(_("no valid sudoers sources found, quitting")); |
warningx(_("no valid sudoers sources found, quitting")); |
| return -1; | debug_return_bool(-1); |
| } |
} |
| |
|
| /* XXX - collect post-sudoers parse settings into a function */ |
/* XXX - collect post-sudoers parse settings into a function */ |
|
Line 212 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 172 sudoers_policy_open(unsigned int version, sudo_conv_t
|
| * Initialize external group plugin, if any. |
* Initialize external group plugin, if any. |
| */ |
*/ |
| if (def_group_plugin) { |
if (def_group_plugin) { |
| if (group_plugin_load(def_group_plugin) != TRUE) | if (group_plugin_load(def_group_plugin) != true) |
| def_group_plugin = NULL; |
def_group_plugin = NULL; |
| } |
} |
| |
|
|
Line 221 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 181 sudoers_policy_open(unsigned int version, sudo_conv_t
|
| * Note that if runas_group was specified without runas_user we |
* Note that if runas_group was specified without runas_user we |
| * defer setting runas_pw so the match routines know to ignore it. |
* defer setting runas_pw so the match routines know to ignore it. |
| */ |
*/ |
| |
/* XXX - qpm4u does more here as it may have already set runas_pw */ |
| if (runas_group != NULL) { |
if (runas_group != NULL) { |
| set_runasgr(runas_group); |
set_runasgr(runas_group); |
| if (runas_user != NULL) |
if (runas_user != NULL) |
|
Line 229 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 190 sudoers_policy_open(unsigned int version, sudo_conv_t
|
| set_runaspw(runas_user ? runas_user : def_runas_default); |
set_runaspw(runas_user ? runas_user : def_runas_default); |
| |
|
| if (!update_defaults(SETDEF_RUNAS)) |
if (!update_defaults(SETDEF_RUNAS)) |
| log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries")); | log_warning(NO_STDERR, N_("problem with defaults entries")); |
| |
|
| if (def_fqdn) |
if (def_fqdn) |
| set_fqdn(); /* deferred until after sudoers is parsed */ |
set_fqdn(); /* deferred until after sudoers is parsed */ |
| |
|
| /* Set login class if applicable. */ |
/* Set login class if applicable. */ |
| set_loginclass(sudo_user.pw); | set_loginclass(runas_pw ? runas_pw : sudo_user.pw); |
| |
|
| restore_perms(); |
restore_perms(); |
| |
|
| return TRUE; | debug_return_bool(true); |
| } |
} |
| |
|
| static void | int |
| sudoers_policy_close(int exit_status, int error_code) | |
| { | |
| if (sigsetjmp(error_jmp, 1)) { | |
| /* called via error(), errorx() or log_error() */ | |
| return; | |
| } | |
| |
| /* We do not currently log the exit status. */ | |
| if (error_code) | |
| warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code)); | |
| |
| /* Close the session we opened in sudoers_policy_init_session(). */ | |
| if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT)) | |
| (void)sudo_auth_end_session(runas_pw); | |
| |
| /* Free remaining references to password and group entries. */ | |
| pw_delref(sudo_user.pw); | |
| pw_delref(runas_pw); | |
| if (runas_gr != NULL) | |
| gr_delref(runas_gr); | |
| if (user_group_list != NULL) | |
| grlist_delref(user_group_list); | |
| } | |
| |
| /* | |
| * The init_session function is called before executing the command | |
| * and before uid/gid changes occur. | |
| */ | |
| static int | |
| sudoers_policy_init_session(struct passwd *pwd) | |
| { | |
| if (sigsetjmp(error_jmp, 1)) { | |
| /* called via error(), errorx() or log_error() */ | |
| return -1; | |
| } | |
| |
| return sudo_auth_begin_session(pwd); | |
| } | |
| |
| static int | |
| sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], |
sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], |
| char **command_infop[], char **argv_out[], char **user_env_out[]) | void *closure) |
| { |
{ |
| static char *command_info[32]; /* XXX */ |
|
| char **edit_argv = NULL; |
char **edit_argv = NULL; |
| |
char *iolog_path = NULL; |
| |
mode_t cmnd_umask = 0777; |
| struct sudo_nss *nss; |
struct sudo_nss *nss; |
| int cmnd_status = -1, validated; | int cmnd_status = -1, oldlocale, validated; |
| volatile int info_len = 0; | volatile int rval = true; |
| volatile int rval = TRUE; | debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN) |
| |
|
| if (sigsetjmp(error_jmp, 1)) { | /* XXX - would like to move this to policy.c but need the cleanup. */ |
| /* error recovery via error(), errorx() or log_error() */ | if (fatal_setjmp() != 0) { |
| | /* error recovery via fatal(), fatalx() or log_fatal() */ |
| rval = -1; |
rval = -1; |
| goto done; |
goto done; |
| } |
} |
|
Line 335 sudoers_policy_main(int argc, char * const argv[], int
|
Line 258 sudoers_policy_main(int argc, char * const argv[], int
|
| NewArgv = emalloc2(NewArgc + 2, sizeof(char *)); |
NewArgv = emalloc2(NewArgc + 2, sizeof(char *)); |
| memcpy(++NewArgv, argv, argc * sizeof(char *)); |
memcpy(++NewArgv, argv, argc * sizeof(char *)); |
| NewArgv[NewArgc] = NULL; |
NewArgv[NewArgc] = NULL; |
| if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) | if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL) |
| NewArgv[0] = estrdup(runas_pw->pw_shell); |
NewArgv[0] = estrdup(runas_pw->pw_shell); |
| } |
} |
| |
|
| /* If given the -P option, set the "preserve_groups" flag. */ |
/* If given the -P option, set the "preserve_groups" flag. */ |
| if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) |
if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) |
| def_preserve_groups = TRUE; | def_preserve_groups = true; |
| |
|
| /* Find command in path */ |
/* Find command in path */ |
| cmnd_status = set_cmnd(); |
cmnd_status = set_cmnd(); |
| if (cmnd_status == -1) { |
|
| rval = -1; |
|
| goto done; |
|
| } |
|
| |
|
| #ifdef HAVE_SETLOCALE |
|
| if (!setlocale(LC_ALL, def_sudoers_locale)) { |
|
| warningx(_("unable to set locale to \"%s\", using \"C\""), |
|
| def_sudoers_locale); |
|
| setlocale(LC_ALL, "C"); |
|
| } |
|
| #endif |
|
| |
|
| /* |
/* |
| * Check sudoers sources. | * Check sudoers sources, using the locale specified in sudoers. |
| */ |
*/ |
| |
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); |
| validated = FLAG_NO_USER | FLAG_NO_HOST; |
validated = FLAG_NO_USER | FLAG_NO_HOST; |
| tq_foreach_fwd(snl, nss) { |
tq_foreach_fwd(snl, nss) { |
| validated = nss->lookup(nss, validated, pwflag); |
validated = nss->lookup(nss, validated, pwflag); |
| |
|
| if (ISSET(validated, VALIDATE_OK)) { |
if (ISSET(validated, VALIDATE_OK)) { |
| /* Handle "= auth" in netsvc.conf */ | /* Handle [SUCCESS=return] */ |
| if (nss->ret_if_found) |
if (nss->ret_if_found) |
| break; |
break; |
| } else { |
} else { |
|
Line 376 sudoers_policy_main(int argc, char * const argv[], int
|
Line 288 sudoers_policy_main(int argc, char * const argv[], int
|
| } |
} |
| } |
} |
| |
|
| |
/* Restore user's locale. */ |
| |
sudoers_setlocale(oldlocale, NULL); |
| |
|
| if (safe_cmnd == NULL) |
if (safe_cmnd == NULL) |
| safe_cmnd = estrdup(user_cmnd); |
safe_cmnd = estrdup(user_cmnd); |
| |
|
| #ifdef HAVE_SETLOCALE |
|
| setlocale(LC_ALL, ""); |
|
| #endif |
|
| |
|
| /* If only a group was specified, set runas_pw based on invoking user. */ |
/* If only a group was specified, set runas_pw based on invoking user. */ |
| if (runas_pw == NULL) |
if (runas_pw == NULL) |
| set_runaspw(user_name); |
set_runaspw(user_name); |
|
Line 397 sudoers_policy_main(int argc, char * const argv[], int
|
Line 308 sudoers_policy_main(int argc, char * const argv[], int
|
| pw = sudo_getpwuid(atoi(def_timestampowner + 1)); |
pw = sudo_getpwuid(atoi(def_timestampowner + 1)); |
| else |
else |
| pw = sudo_getpwnam(def_timestampowner); |
pw = sudo_getpwnam(def_timestampowner); |
| if (!pw) | if (pw != NULL) { |
| log_error(0, _("timestamp owner (%s): No such user"), | timestamp_uid = pw->pw_uid; |
| | sudo_pw_delref(pw); |
| | } else { |
| | log_warning(0, N_("timestamp owner (%s): No such user"), |
| def_timestampowner); |
def_timestampowner); |
| timestamp_uid = pw->pw_uid; | timestamp_uid = ROOT_UID; |
| pw_delref(pw); | } |
| } |
} |
| |
|
| /* If no command line args and "shell_noargs" is not set, error out. */ |
/* If no command line args and "shell_noargs" is not set, error out. */ |
|
Line 411 sudoers_policy_main(int argc, char * const argv[], int
|
Line 325 sudoers_policy_main(int argc, char * const argv[], int
|
| } |
} |
| |
|
| /* Bail if a tty is required and we don't have one. */ |
/* Bail if a tty is required and we don't have one. */ |
| if (def_requiretty) { | if (def_requiretty && !tty_present()) { |
| int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); | audit_failure(NewArgv, N_("no tty")); |
| if (fd == -1) { | warningx(_("sorry, you must have a tty to run sudo")); |
| audit_failure(NewArgv, _("no tty")); | goto bad; |
| warningx(_("sorry, you must have a tty to run sudo")); | |
| goto bad; | |
| } else | |
| (void) close(fd); | |
| } |
} |
| |
|
| /* |
/* |
|
Line 427 sudoers_policy_main(int argc, char * const argv[], int
|
Line 337 sudoers_policy_main(int argc, char * const argv[], int
|
| */ |
*/ |
| if (ISSET(sudo_mode, MODE_EDIT) || |
if (ISSET(sudo_mode, MODE_EDIT) || |
| (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)) |
(ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)) |
| def_env_reset = FALSE; | def_env_reset = false; |
| |
|
| /* Build a new environment that avoids any nasty bits. */ |
/* Build a new environment that avoids any nasty bits. */ |
| rebuild_env(); |
rebuild_env(); |
| |
|
| /* Require a password if sudoers says so. */ |
/* Require a password if sudoers says so. */ |
| rval = check_user(validated, sudo_mode); |
rval = check_user(validated, sudo_mode); |
| if (rval != TRUE) | if (rval != true) { |
| | if (!ISSET(validated, VALIDATE_OK)) |
| | log_denial(validated, false); |
| goto done; |
goto done; |
| |
} |
| |
|
| /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ |
/* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ |
| /* XXX - causes confusion when root is not listed in sudoers */ |
/* XXX - causes confusion when root is not listed in sudoers */ |
|
Line 445 sudoers_policy_main(int argc, char * const argv[], int
|
Line 358 sudoers_policy_main(int argc, char * const argv[], int
|
| |
|
| if ((pw = sudo_getpwnam(prev_user)) != NULL) { |
if ((pw = sudo_getpwnam(prev_user)) != NULL) { |
| if (sudo_user.pw != NULL) |
if (sudo_user.pw != NULL) |
| pw_delref(sudo_user.pw); | sudo_pw_delref(sudo_user.pw); |
| sudo_user.pw = pw; |
sudo_user.pw = pw; |
| } |
} |
| } |
} |
|
Line 453 sudoers_policy_main(int argc, char * const argv[], int
|
Line 366 sudoers_policy_main(int argc, char * const argv[], int
|
| |
|
| /* If the user was not allowed to run the command we are done. */ |
/* If the user was not allowed to run the command we are done. */ |
| if (!ISSET(validated, VALIDATE_OK)) { |
if (!ISSET(validated, VALIDATE_OK)) { |
| if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) { | log_failure(validated, cmnd_status); |
| audit_failure(NewArgv, _("No user or host")); | |
| log_denial(validated, 1); | |
| } else { | |
| if (def_path_info) { | |
| /* | |
| * We'd like to not leak path info at all here, but that can | |
| * *really* confuse the users. To really close the leak we'd | |
| * have to say "not allowed to run foo" even when the problem | |
| * is just "no foo in path" since the user can trivially set | |
| * their path to just contain a single dir. | |
| */ | |
| log_denial(validated, | |
| !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); | |
| if (cmnd_status == NOT_FOUND) | |
| warningx(_("%s: command not found"), user_cmnd); | |
| else if (cmnd_status == NOT_FOUND_DOT) | |
| warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); | |
| } else { | |
| /* Just tell the user they are not allowed to run foo. */ | |
| log_denial(validated, 1); | |
| } | |
| audit_failure(NewArgv, _("validation failure")); | |
| } | |
| goto bad; |
goto bad; |
| } |
} |
| |
|
|
Line 485 sudoers_policy_main(int argc, char * const argv[], int
|
Line 375 sudoers_policy_main(int argc, char * const argv[], int
|
| |
|
| /* Finally tell the user if the command did not exist. */ |
/* Finally tell the user if the command did not exist. */ |
| if (cmnd_status == NOT_FOUND_DOT) { |
if (cmnd_status == NOT_FOUND_DOT) { |
| audit_failure(NewArgv, _("command in current directory")); | audit_failure(NewArgv, N_("command in current directory")); |
| warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); |
warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); |
| goto bad; |
goto bad; |
| } else if (cmnd_status == NOT_FOUND) { |
} else if (cmnd_status == NOT_FOUND) { |
| audit_failure(NewArgv, _("%s: command not found"), user_cmnd); | if (ISSET(sudo_mode, MODE_CHECK)) { |
| warningx(_("%s: command not found"), user_cmnd); | audit_failure(NewArgv, N_("%s: command not found"), NewArgv[0]); |
| | warningx(_("%s: command not found"), NewArgv[0]); |
| | } else { |
| | audit_failure(NewArgv, N_("%s: command not found"), user_cmnd); |
| | warningx(_("%s: command not found"), user_cmnd); |
| | } |
| goto bad; |
goto bad; |
| } |
} |
| |
|
|
Line 503 sudoers_policy_main(int argc, char * const argv[], int
|
Line 398 sudoers_policy_main(int argc, char * const argv[], int
|
| validate_env_vars(sudo_user.env_vars); |
validate_env_vars(sudo_user.env_vars); |
| } |
} |
| |
|
| if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) { | if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) { |
| if (def_iolog_file && def_iolog_dir) { | if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) { |
| command_info[info_len++] = expand_iolog_path("iolog_path=", | const char prefix[] = "iolog_path="; |
| def_iolog_dir, def_iolog_file, &sudo_user.iolog_file); | iolog_path = expand_iolog_path(prefix, def_iolog_dir, |
| | def_iolog_file, &sudo_user.iolog_file); |
| sudo_user.iolog_file++; |
sudo_user.iolog_file++; |
| } |
} |
| if (def_log_input) { |
|
| command_info[info_len++] = estrdup("iolog_stdin=true"); |
|
| command_info[info_len++] = estrdup("iolog_ttyin=true"); |
|
| } |
|
| if (def_log_output) { |
|
| command_info[info_len++] = estrdup("iolog_stdout=true"); |
|
| command_info[info_len++] = estrdup("iolog_stderr=true"); |
|
| command_info[info_len++] = estrdup("iolog_ttyout=true"); |
|
| } |
|
| if (def_compress_io) |
|
| command_info[info_len++] = estrdup("iolog_compress=true"); |
|
| } |
} |
| |
|
| log_allowed(validated); |
log_allowed(validated); |
|
Line 546 sudoers_policy_main(int argc, char * const argv[], int
|
Line 431 sudoers_policy_main(int argc, char * const argv[], int
|
| * unless umask_override is set. |
* unless umask_override is set. |
| */ |
*/ |
| if (def_umask != 0777) { |
if (def_umask != 0777) { |
| mode_t mask = def_umask; | cmnd_umask = def_umask; |
| if (!def_umask_override) { | if (!def_umask_override) |
| mode_t omask = umask(mask); | cmnd_umask |= user_umask; |
| mask |= omask; | |
| umask(omask); | |
| } | |
| easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask); | |
| } |
} |
| |
|
| if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
|
Line 564 sudoers_policy_main(int argc, char * const argv[], int
|
Line 445 sudoers_policy_main(int argc, char * const argv[], int
|
| *p = '-'; |
*p = '-'; |
| NewArgv[0] = p; |
NewArgv[0] = p; |
| |
|
| /* Set cwd to run user's homedir. */ |
|
| command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir); |
|
| |
|
| /* |
/* |
| * Newer versions of bash require the --login option to be used |
* Newer versions of bash require the --login option to be used |
| * in conjunction with the -c option even if the shell name starts |
* in conjunction with the -c option even if the shell name starts |
|
Line 582 sudoers_policy_main(int argc, char * const argv[], int
|
Line 460 sudoers_policy_main(int argc, char * const argv[], int
|
| NewArgv[1] = "--login"; |
NewArgv[1] = "--login"; |
| } |
} |
| |
|
| #if defined(__linux__) || defined(_AIX) | #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM)) |
| /* Insert system-wide environment variables. */ |
/* Insert system-wide environment variables. */ |
| read_env_file(_PATH_ENVIRONMENT, TRUE); | read_env_file(_PATH_ENVIRONMENT, true); |
| #endif |
#endif |
| |
#ifdef HAVE_LOGIN_CAP_H |
| |
/* Set environment based on login class. */ |
| |
if (login_class) { |
| |
login_cap_t *lc = login_getclass(login_class); |
| |
if (lc != NULL) { |
| |
setusercontext(lc, runas_pw, runas_pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV); |
| |
login_close(lc); |
| |
} |
| |
} |
| |
#endif /* HAVE_LOGIN_CAP_H */ |
| } |
} |
| |
|
| /* Insert system-wide environment variables. */ |
/* Insert system-wide environment variables. */ |
| if (def_env_file) |
if (def_env_file) |
| read_env_file(def_env_file, FALSE); | read_env_file(def_env_file, false); |
| |
|
| /* Insert user-specified environment variables. */ |
/* Insert user-specified environment variables. */ |
| insert_env_vars(sudo_user.env_vars); |
insert_env_vars(sudo_user.env_vars); |
| |
|
| /* Restore signal handlers before we exec. */ |
|
| (void) sigaction(SIGINT, &saved_sa_int, NULL); |
|
| (void) sigaction(SIGQUIT, &saved_sa_quit, NULL); |
|
| (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); |
|
| |
|
| if (ISSET(sudo_mode, MODE_EDIT)) { |
if (ISSET(sudo_mode, MODE_EDIT)) { |
| char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv); | efree(safe_cmnd); |
| if (editor == NULL) | safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv); |
| | if (safe_cmnd == NULL) |
| goto bad; |
goto bad; |
| command_info[info_len++] = fmt_string("command", editor); |
|
| command_info[info_len++] = estrdup("sudoedit=true"); |
|
| } else { |
|
| command_info[info_len++] = fmt_string("command", safe_cmnd); |
|
| } |
} |
| if (def_stay_setuid) { |
|
| easprintf(&command_info[info_len++], "runas_uid=%u", |
|
| (unsigned int)user_uid); |
|
| easprintf(&command_info[info_len++], "runas_gid=%u", |
|
| (unsigned int)user_gid); |
|
| easprintf(&command_info[info_len++], "runas_euid=%u", |
|
| (unsigned int)runas_pw->pw_uid); |
|
| easprintf(&command_info[info_len++], "runas_egid=%u", |
|
| runas_gr ? (unsigned int)runas_gr->gr_gid : |
|
| (unsigned int)runas_pw->pw_gid); |
|
| } else { |
|
| easprintf(&command_info[info_len++], "runas_uid=%u", |
|
| (unsigned int)runas_pw->pw_uid); |
|
| easprintf(&command_info[info_len++], "runas_gid=%u", |
|
| runas_gr ? (unsigned int)runas_gr->gr_gid : |
|
| (unsigned int)runas_pw->pw_gid); |
|
| } |
|
| if (def_preserve_groups) { |
|
| command_info[info_len++] = "preserve_groups=true"; |
|
| } else { |
|
| int i, len; |
|
| size_t glsize; |
|
| char *cp, *gid_list; |
|
| struct group_list *grlist = get_group_list(runas_pw); |
|
| |
|
| glsize = sizeof("runas_groups=") - 1 + (grlist->ngids * (MAX_UID_T_LEN + 1)); |
|
| gid_list = emalloc(glsize); |
|
| memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1); |
|
| cp = gid_list + sizeof("runas_groups=") - 1; |
|
| for (i = 0; i < grlist->ngids; i++) { |
|
| /* XXX - check rval */ |
|
| len = snprintf(cp, glsize - (cp - gid_list), "%s%u", |
|
| i ? "," : "", (unsigned int) grlist->gids[i]); |
|
| cp += len; |
|
| } |
|
| command_info[info_len++] = gid_list; |
|
| grlist_delref(grlist); |
|
| } |
|
| if (def_closefrom >= 0) |
|
| easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom); |
|
| if (def_noexec) |
|
| command_info[info_len++] = estrdup("noexec=true"); |
|
| if (def_noexec_file) |
|
| command_info[info_len++] = fmt_string("noexec_file", def_noexec_file); |
|
| if (def_set_utmp) |
|
| command_info[info_len++] = estrdup("set_utmp=true"); |
|
| if (def_use_pty) |
|
| command_info[info_len++] = estrdup("use_pty=true"); |
|
| if (def_utmp_runas) |
|
| command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name); |
|
| #ifdef HAVE_LOGIN_CAP_H |
|
| if (lc != NULL) |
|
| command_info[info_len++] = fmt_string("login_class", lc->lc_class); |
|
| #endif /* HAVE_LOGIN_CAP_H */ |
|
| #ifdef HAVE_SELINUX |
|
| if (user_role != NULL) |
|
| command_info[info_len++] = fmt_string("selinux_role", user_role); |
|
| if (user_type != NULL) |
|
| command_info[info_len++] = fmt_string("selinux_type", user_type); |
|
| #endif /* HAVE_SELINUX */ |
|
| |
|
| /* Must audit before uid change. */ |
/* Must audit before uid change. */ |
| audit_success(NewArgv); |
audit_success(NewArgv); |
| |
|
| *command_infop = command_info; | /* Setup execution environment to pass back to front-end. */ |
| | rval = sudoers_policy_exec_setup(edit_argv ? edit_argv : NewArgv, |
| | env_get(), cmnd_umask, iolog_path, closure); |
| |
|
| *argv_out = edit_argv ? edit_argv : NewArgv; | /* Zero out stashed copy of environment, it is owned by the front-end. */ |
| *user_env_out = env_get(); /* our private copy */ | env_init(NULL); |
| |
|
| goto done; |
goto done; |
| |
|
| bad: |
bad: |
| rval = FALSE; | rval = false; |
| |
|
| done: |
done: |
| |
fatal_disable_setjmp(); |
| rewind_perms(); |
rewind_perms(); |
| |
|
| /* Close the password and group files and free up memory. */ |
/* Close the password and group files and free up memory. */ |
| sudo_endpwent(); |
sudo_endpwent(); |
| sudo_endgrent(); |
sudo_endgrent(); |
| |
|
| return rval; | debug_return_bool(rval); |
| } |
} |
| |
|
| static int |
|
| sudoers_policy_check(int argc, char * const argv[], char *env_add[], |
|
| char **command_infop[], char **argv_out[], char **user_env_out[]) |
|
| { |
|
| if (!ISSET(sudo_mode, MODE_EDIT)) |
|
| SET(sudo_mode, MODE_RUN); |
|
| |
|
| return sudoers_policy_main(argc, argv, 0, env_add, command_infop, |
|
| argv_out, user_env_out); |
|
| } |
|
| |
|
| static int |
|
| sudoers_policy_validate(void) |
|
| { |
|
| user_cmnd = "validate"; |
|
| SET(sudo_mode, MODE_VALIDATE); |
|
| |
|
| return sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL); |
|
| } |
|
| |
|
| static void |
|
| sudoers_policy_invalidate(int remove) |
|
| { |
|
| user_cmnd = "kill"; |
|
| if (sigsetjmp(error_jmp, 1) == 0) { |
|
| remove_timestamp(remove); |
|
| plugin_cleanup(0); |
|
| } |
|
| } |
|
| |
|
| static int |
|
| sudoers_policy_list(int argc, char * const argv[], int verbose, |
|
| const char *list_user) |
|
| { |
|
| int rval; |
|
| |
|
| user_cmnd = "list"; |
|
| if (argc) |
|
| SET(sudo_mode, MODE_CHECK); |
|
| else |
|
| SET(sudo_mode, MODE_LIST); |
|
| if (verbose) |
|
| long_list = 1; |
|
| if (list_user) { |
|
| list_pw = sudo_getpwnam(list_user); |
|
| if (list_pw == NULL) { |
|
| warningx(_("unknown user: %s"), list_user); |
|
| return -1; |
|
| } |
|
| } |
|
| rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL); |
|
| if (list_user) { |
|
| pw_delref(list_pw); |
|
| list_pw = NULL; |
|
| } |
|
| |
|
| return rval; |
|
| } |
|
| |
|
| /* |
/* |
| * Initialize timezone, set umask, fill in ``sudo_user'' struct and | * Initialize timezone and fill in ``sudo_user'' struct. |
| * load the ``interfaces'' array. | |
| */ |
*/ |
| static void |
static void |
| init_vars(char * const envp[]) |
init_vars(char * const envp[]) |
| { |
{ |
| char * const * ep; |
char * const * ep; |
| |
debug_decl(init_vars, SUDO_DEBUG_PLUGIN) |
| |
|
| #ifdef HAVE_TZSET | sudoers_initlocale(setlocale(LC_ALL, NULL), def_sudoers_locale); |
| (void) tzset(); /* set the timezone if applicable */ | |
| #endif /* HAVE_TZSET */ | |
| |
|
| for (ep = envp; *ep; ep++) { |
for (ep = envp; *ep; ep++) { |
| /* XXX - don't fill in if empty string */ |
/* XXX - don't fill in if empty string */ |
|
Line 786 init_vars(char * const envp[])
|
Line 548 init_vars(char * const envp[])
|
| } |
} |
| |
|
| /* |
/* |
| * Get a local copy of the user's struct passwd with the shadow password | * Get a local copy of the user's struct passwd if we don't already |
| * if necessary. It is assumed that euid is 0 at this point so we | * have one. |
| * can read the shadow passwd file if necessary. | |
| */ |
*/ |
| if ((sudo_user.pw = sudo_getpwuid(user_uid)) == NULL) { | if (sudo_user.pw == NULL) { |
| /* | if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) { |
| * It is not unusual for users to place "sudo -k" in a .logout | /* |
| * file which can cause sudo to be run during reboot after the | * It is not unusual for users to place "sudo -k" in a .logout |
| * YP/NIS/NIS+/LDAP/etc daemon has died. | * file which can cause sudo to be run during reboot after the |
| */ | * YP/NIS/NIS+/LDAP/etc daemon has died. |
| if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) | */ |
| errorx(1, _("unknown uid: %u"), (unsigned int) user_uid); | if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) |
| | fatalx(_("unknown uid: %u"), (unsigned int) user_uid); |
| |
|
| /* Need to make a fake struct passwd for the call to log_error(). */ | /* Need to make a fake struct passwd for the call to log_fatal(). */ |
| sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid); | sudo_user.pw = sudo_mkpwent(user_name, user_uid, user_gid, NULL, NULL); |
| log_error(0, _("unknown uid: %u"), (unsigned int) user_uid); | log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid); |
| /* NOTREACHED */ | /* NOTREACHED */ |
| | } |
| } |
} |
| |
|
| /* |
/* |
| * Get group list. |
* Get group list. |
| */ |
*/ |
| if (user_group_list == NULL) |
if (user_group_list == NULL) |
| user_group_list = get_group_list(sudo_user.pw); | user_group_list = sudo_get_grlist(sudo_user.pw); |
| |
|
| /* Set runas callback. */ |
/* Set runas callback. */ |
| sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; |
sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; |
| |
|
| /* It is now safe to use log_error() and set_perms() */ | /* Set locale callback. */ |
| | sudo_defs_table[I_SUDOERS_LOCALE].callback = cb_sudoers_locale; |
| | |
| | /* Set maxseq callback. */ |
| | sudo_defs_table[I_MAXSEQ].callback = io_set_max_sessid; |
| | |
| | /* It is now safe to use log_fatal() and set_perms() */ |
| | debug_return; |
| } |
} |
| |
|
| /* |
/* |
|
Line 826 set_cmnd(void)
|
Line 596 set_cmnd(void)
|
| { |
{ |
| int rval; |
int rval; |
| char *path = user_path; |
char *path = user_path; |
| |
debug_decl(set_cmnd, SUDO_DEBUG_PLUGIN) |
| |
|
| /* Resolve the path and return. */ |
/* Resolve the path and return. */ |
| rval = FOUND; |
rval = FOUND; |
| user_stat = emalloc(sizeof(struct stat)); | user_stat = ecalloc(1, sizeof(struct stat)); |
| |
|
| /* Default value for cmnd, overridden below. */ |
/* Default value for cmnd, overridden below. */ |
| if (user_cmnd == NULL) |
if (user_cmnd == NULL) |
|
Line 880 set_cmnd(void)
|
Line 651 set_cmnd(void)
|
| for (to = user_args, av = NewArgv + 1; *av; av++) { |
for (to = user_args, av = NewArgv + 1; *av; av++) { |
| n = strlcpy(to, *av, size - (to - user_args)); |
n = strlcpy(to, *av, size - (to - user_args)); |
| if (n >= size - (to - user_args)) |
if (n >= size - (to - user_args)) |
| errorx(1, _("internal error, set_cmnd() overflow")); | fatalx(_("internal error, %s overflow"), "set_cmnd()"); |
| to += n; |
to += n; |
| *to++ = ' '; |
*to++ = ' '; |
| } |
} |
|
Line 888 set_cmnd(void)
|
Line 659 set_cmnd(void)
|
| } |
} |
| } |
} |
| } |
} |
| if (strlen(user_cmnd) >= PATH_MAX) | if (strlen(user_cmnd) >= PATH_MAX) { |
| errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG)); | errno = ENAMETOOLONG; |
| | fatal("%s", user_cmnd); |
| | } |
| |
|
| if ((user_base = strrchr(user_cmnd, '/')) != NULL) |
if ((user_base = strrchr(user_cmnd, '/')) != NULL) |
| user_base++; |
user_base++; |
|
Line 897 set_cmnd(void)
|
Line 670 set_cmnd(void)
|
| user_base = user_cmnd; |
user_base = user_cmnd; |
| |
|
| if (!update_defaults(SETDEF_CMND)) |
if (!update_defaults(SETDEF_CMND)) |
| log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries")); | log_warning(NO_STDERR, N_("problem with defaults entries")); |
| |
|
| return rval; | debug_return_int(rval); |
| } |
} |
| |
|
| /* |
/* |
|
Line 907 set_cmnd(void)
|
Line 680 set_cmnd(void)
|
| * Returns a handle to the sudoers file or NULL on error. |
* Returns a handle to the sudoers file or NULL on error. |
| */ |
*/ |
| FILE * |
FILE * |
| open_sudoers(const char *sudoers, int doedit, int *keepopen) | open_sudoers(const char *sudoers, bool doedit, bool *keepopen) |
| { |
{ |
| struct stat statbuf; | struct stat sb; |
| FILE *fp = NULL; |
FILE *fp = NULL; |
| int rootstat; | debug_decl(open_sudoers, SUDO_DEBUG_PLUGIN) |
| |
|
| /* | set_perms(PERM_SUDOERS); |
| * Fix the mode and group on sudoers file from old default. | |
| * Only works if file system is readable/writable by root. | |
| */ | |
| if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 && | |
| sudoers_uid == statbuf.st_uid && sudoers_mode != 0400 && | |
| (statbuf.st_mode & 0007777) == 0400) { | |
| |
|
| if (chmod(sudoers, sudoers_mode) == 0) { | switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) { |
| warningx(_("fixed mode on %s"), sudoers); | case SUDO_PATH_SECURE: |
| SET(statbuf.st_mode, sudoers_mode); | /* |
| if (statbuf.st_gid != sudoers_gid) { | * If we are expecting sudoers to be group readable but |
| if (chown(sudoers, (uid_t) -1, sudoers_gid) == 0) { | * it is not, we must open the file as root, not uid 1. |
| warningx(_("set group on %s"), sudoers); | */ |
| statbuf.st_gid = sudoers_gid; | if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) { |
| } else | if ((sb.st_mode & S_IRGRP) == 0) { |
| warning(_("unable to set group on %s"), sudoers); | restore_perms(); |
| | set_perms(PERM_ROOT); |
| | } |
| } |
} |
| } else | /* |
| warning(_("unable to fix mode on %s"), sudoers); | * Open sudoers and make sure we can read it so we can present |
| | * the user with a reasonable error message (unlike the lexer). |
| | */ |
| | if ((fp = fopen(sudoers, "r")) == NULL) { |
| | log_warning(USE_ERRNO, N_("unable to open %s"), sudoers); |
| | } else { |
| | if (sb.st_size != 0 && fgetc(fp) == EOF) { |
| | log_warning(USE_ERRNO, N_("unable to read %s"), |
| | sudoers); |
| | fclose(fp); |
| | fp = NULL; |
| | } else { |
| | /* Rewind fp and set close on exec flag. */ |
| | rewind(fp); |
| | (void) fcntl(fileno(fp), F_SETFD, 1); |
| | } |
| | } |
| | break; |
| | case SUDO_PATH_MISSING: |
| | log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers); |
| | break; |
| | case SUDO_PATH_BAD_TYPE: |
| | log_warning(0, N_("%s is not a regular file"), sudoers); |
| | break; |
| | case SUDO_PATH_WRONG_OWNER: |
| | log_warning(0, N_("%s is owned by uid %u, should be %u"), |
| | sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid); |
| | break; |
| | case SUDO_PATH_WORLD_WRITABLE: |
| | log_warning(0, N_("%s is world writable"), sudoers); |
| | break; |
| | case SUDO_PATH_GROUP_WRITABLE: |
| | log_warning(0, N_("%s is owned by gid %u, should be %u"), |
| | sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid); |
| | break; |
| | default: |
| | /* NOTREACHED */ |
| | break; |
| } |
} |
| |
|
| /* |
|
| * Sanity checks on sudoers file. Must be done as sudoers |
|
| * file owner. We already did a stat as root, so use that |
|
| * data if we can't stat as sudoers file owner. |
|
| */ |
|
| set_perms(PERM_SUDOERS); |
|
| |
|
| if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0) |
|
| log_error(USE_ERRNO|NO_EXIT, _("unable to stat %s"), sudoers); |
|
| else if (!S_ISREG(statbuf.st_mode)) |
|
| log_error(NO_EXIT, _("%s is not a regular file"), sudoers); |
|
| else if ((statbuf.st_mode & 07577) != sudoers_mode) |
|
| log_error(NO_EXIT, _("%s is mode 0%o, should be 0%o"), sudoers, |
|
| (unsigned int) (statbuf.st_mode & 07777), |
|
| (unsigned int) sudoers_mode); |
|
| else if (statbuf.st_uid != sudoers_uid) |
|
| log_error(NO_EXIT, _("%s is owned by uid %u, should be %u"), sudoers, |
|
| (unsigned int) statbuf.st_uid, (unsigned int) sudoers_uid); |
|
| else if (statbuf.st_gid != sudoers_gid && ISSET(statbuf.st_mode, S_IRGRP|S_IWGRP)) |
|
| log_error(NO_EXIT, _("%s is owned by gid %u, should be %u"), sudoers, |
|
| (unsigned int) statbuf.st_gid, (unsigned int) sudoers_gid); |
|
| else if ((fp = fopen(sudoers, "r")) == NULL) |
|
| log_error(USE_ERRNO|NO_EXIT, _("unable to open %s"), sudoers); |
|
| else { |
|
| /* |
|
| * Make sure we can actually read sudoers so we can present the |
|
| * user with a reasonable error message (unlike the lexer). |
|
| */ |
|
| if (statbuf.st_size != 0 && fgetc(fp) == EOF) { |
|
| log_error(USE_ERRNO|NO_EXIT, _("unable to read %s"), sudoers); |
|
| fclose(fp); |
|
| fp = NULL; |
|
| } |
|
| } |
|
| |
|
| if (fp != NULL) { |
|
| rewind(fp); |
|
| (void) fcntl(fileno(fp), F_SETFD, 1); |
|
| } |
|
| |
|
| restore_perms(); /* change back to root */ |
restore_perms(); /* change back to root */ |
| return fp; | |
| | debug_return_ptr(fp); |
| } |
} |
| |
|
| #ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
| static void |
static void |
| set_loginclass(struct passwd *pw) |
set_loginclass(struct passwd *pw) |
| { |
{ |
| int errflags; | const int errflags = NO_MAIL|MSG_ONLY; |
| | login_cap_t *lc; |
| | debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN) |
| |
|
| /* | if (!def_use_loginclass) |
| * Don't make it a fatal error if the user didn't specify the login | debug_return; |
| * class themselves. We do this because if login.conf gets | |
| * corrupted we want the admin to be able to use sudo to fix it. | |
| */ | |
| if (login_class) | |
| errflags = NO_MAIL|MSG_ONLY; | |
| else | |
| errflags = NO_MAIL|MSG_ONLY|NO_EXIT; | |
| |
|
| if (login_class && strcmp(login_class, "-") != 0) { |
if (login_class && strcmp(login_class, "-") != 0) { |
| if (user_uid != 0 && |
if (user_uid != 0 && |
| strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) |
strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) |
| errorx(1, _("only root can use `-c %s'"), login_class); | fatalx(_("only root can use `-c %s'"), login_class); |
| } else { |
} else { |
| login_class = pw->pw_class; |
login_class = pw->pw_class; |
| if (!login_class || !*login_class) |
if (!login_class || !*login_class) |
|
Line 1006 set_loginclass(struct passwd *pw)
|
Line 768 set_loginclass(struct passwd *pw)
|
| (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; |
(pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; |
| } |
} |
| |
|
| |
/* Make sure specified login class is valid. */ |
| lc = login_getclass(login_class); |
lc = login_getclass(login_class); |
| if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) { |
if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) { |
| log_error(errflags, _("unknown login class: %s"), login_class); | /* |
| if (!lc) | * Don't make it a fatal error if the user didn't specify the login |
| lc = login_getclass(NULL); /* needed for login_getstyle() later */ | * class themselves. We do this because if login.conf gets |
| | * corrupted we want the admin to be able to use sudo to fix it. |
| | */ |
| | if (login_class) |
| | log_fatal(errflags, N_("unknown login class: %s"), login_class); |
| | else |
| | log_warning(errflags, N_("unknown login class: %s"), login_class); |
| | def_use_loginclass = false; |
| } |
} |
| |
login_close(lc); |
| |
debug_return; |
| } |
} |
| #else |
#else |
| static void |
static void |
|
Line 1020 set_loginclass(struct passwd *pw)
|
Line 792 set_loginclass(struct passwd *pw)
|
| } |
} |
| #endif /* HAVE_LOGIN_CAP_H */ |
#endif /* HAVE_LOGIN_CAP_H */ |
| |
|
| |
#ifndef AI_FQDN |
| |
# define AI_FQDN AI_CANONNAME |
| |
#endif |
| |
|
| /* |
/* |
| * Look up the fully qualified domain name and set user_host and user_shost. |
* Look up the fully qualified domain name and set user_host and user_shost. |
| |
* Use AI_FQDN if available since "canonical" is not always the same as fqdn. |
| */ |
*/ |
| void | static void |
| set_fqdn(void) |
set_fqdn(void) |
| { |
{ |
| #ifdef HAVE_GETADDRINFO |
|
| struct addrinfo *res0, hint; |
struct addrinfo *res0, hint; |
| #else |
|
| struct hostent *hp; |
|
| #endif |
|
| char *p; |
char *p; |
| |
debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN) |
| |
|
| #ifdef HAVE_GETADDRINFO |
|
| zero_bytes(&hint, sizeof(hint)); |
zero_bytes(&hint, sizeof(hint)); |
| hint.ai_family = PF_UNSPEC; |
hint.ai_family = PF_UNSPEC; |
| hint.ai_flags = AI_CANONNAME; | hint.ai_flags = AI_FQDN; |
| if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { |
if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { |
| #else | log_warning(MSG_ONLY, N_("unable to resolve host %s"), user_host); |
| if (!(hp = gethostbyname(user_host))) { | |
| #endif | |
| log_error(MSG_ONLY|NO_EXIT, | |
| _("unable to resolve host %s"), user_host); | |
| } else { |
} else { |
| if (user_shost != user_host) |
if (user_shost != user_host) |
| efree(user_shost); |
efree(user_shost); |
| efree(user_host); |
efree(user_host); |
| #ifdef HAVE_GETADDRINFO |
|
| user_host = estrdup(res0->ai_canonname); |
user_host = estrdup(res0->ai_canonname); |
| freeaddrinfo(res0); |
freeaddrinfo(res0); |
| #else | if ((p = strchr(user_host, '.')) != NULL) |
| user_host = estrdup(hp->h_name); | user_shost = estrndup(user_host, (size_t)(p - user_host)); |
| #endif | else |
| | user_shost = user_host; |
| } |
} |
| if ((p = strchr(user_host, '.')) != NULL) | debug_return; |
| user_shost = estrndup(user_host, (size_t)(p - user_host)); | |
| else | |
| user_shost = user_host; | |
| } |
} |
| |
|
| /* |
/* |
| * Get passwd entry for the user we are going to run commands as |
* Get passwd entry for the user we are going to run commands as |
| * and store it in runas_pw. By default, commands run as "root". |
* and store it in runas_pw. By default, commands run as "root". |
| */ |
*/ |
| void | static void |
| set_runaspw(const char *user) |
set_runaspw(const char *user) |
| { |
{ |
| |
debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN) |
| |
|
| if (runas_pw != NULL) |
if (runas_pw != NULL) |
| pw_delref(runas_pw); | sudo_pw_delref(runas_pw); |
| if (*user == '#') { |
if (*user == '#') { |
| if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) |
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) |
| runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); |
runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); |
| } else { |
} else { |
| if ((runas_pw = sudo_getpwnam(user)) == NULL) |
if ((runas_pw = sudo_getpwnam(user)) == NULL) |
| log_error(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user); | log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user); |
| } |
} |
| |
debug_return; |
| } |
} |
| |
|
| /* |
/* |
|
Line 1085 set_runaspw(const char *user)
|
Line 854 set_runaspw(const char *user)
|
| static void |
static void |
| set_runasgr(const char *group) |
set_runasgr(const char *group) |
| { |
{ |
| |
debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN) |
| |
|
| if (runas_gr != NULL) |
if (runas_gr != NULL) |
| gr_delref(runas_gr); | sudo_gr_delref(runas_gr); |
| if (*group == '#') { |
if (*group == '#') { |
| if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) |
if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) |
| runas_gr = sudo_fakegrnam(group); |
runas_gr = sudo_fakegrnam(group); |
| } else { |
} else { |
| if ((runas_gr = sudo_getgrnam(group)) == NULL) |
if ((runas_gr = sudo_getgrnam(group)) == NULL) |
| log_error(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group); | log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group); |
| } |
} |
| |
debug_return; |
| } |
} |
| |
|
| /* |
/* |
|
Line 1105 cb_runas_default(const char *user)
|
Line 877 cb_runas_default(const char *user)
|
| /* Only reset runaspw if user didn't specify one. */ |
/* Only reset runaspw if user didn't specify one. */ |
| if (!runas_user && !runas_group) |
if (!runas_user && !runas_group) |
| set_runaspw(user); |
set_runaspw(user); |
| return TRUE; | return true; |
| } |
} |
| |
|
| /* |
/* |
| * Cleanup hook for error()/errorx() | * Callback for sudoers_locale sudoers setting. |
| */ |
*/ |
| void |
|
| plugin_cleanup(int gotsignal) |
|
| { |
|
| struct sudo_nss *nss; |
|
| |
|
| if (!gotsignal) { |
|
| if (snl != NULL) { |
|
| tq_foreach_fwd(snl, nss) |
|
| nss->close(nss); |
|
| } |
|
| if (def_group_plugin) |
|
| group_plugin_unload(); |
|
| sudo_endpwent(); |
|
| sudo_endgrent(); |
|
| } |
|
| } |
|
| |
|
| static int |
static int |
| sudoers_policy_version(int verbose) | cb_sudoers_locale(const char *locale) |
| { |
{ |
| if (sigsetjmp(error_jmp, 1)) { | sudoers_initlocale(NULL, locale); |
| /* error recovery via error(), errorx() or log_error() */ | return true; |
| return -1; | |
| } | |
| |
| sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"), | |
| PACKAGE_VERSION); | |
| sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"), | |
| SUDOERS_GRAMMAR_VERSION); | |
| |
| if (verbose) { | |
| sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file); | |
| #ifdef HAVE_LDAP | |
| # ifdef _PATH_NSSWITCH_CONF | |
| sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF); | |
| # endif | |
| sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), _PATH_LDAP_CONF); | |
| sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), _PATH_LDAP_SECRET); | |
| #endif | |
| dump_auth_methods(); | |
| dump_defaults(); | |
| sudo_printf(SUDO_CONV_INFO_MSG, "\n"); | |
| dump_interfaces(interfaces_string); | |
| sudo_printf(SUDO_CONV_INFO_MSG, "\n"); | |
| } | |
| return TRUE; | |
| } |
} |
| |
|
| static int | /* |
| deserialize_info(char * const settings[], char * const user_info[]) | * Cleanup hook for fatal()/fatalx() |
| | */ |
| | void |
| | sudoers_cleanup(void) |
| { |
{ |
| char * const *cur; | struct sudo_nss *nss; |
| const char *p, *groups = NULL; | debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN) |
| int flags = 0; | |
| |
|
| #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) | if (snl != NULL) { |
| tq_foreach_fwd(snl, nss) |
| /* Parse command line settings. */ | nss->close(nss); |
| user_closefrom = -1; | |
| for (cur = settings; *cur != NULL; cur++) { | |
| if (MATCHES(*cur, "closefrom=")) { | |
| user_closefrom = atoi(*cur + sizeof("closefrom=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "debug_level=")) { | |
| debug_level = atoi(*cur + sizeof("debug_level=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "runas_user=")) { | |
| runas_user = *cur + sizeof("runas_user=") - 1; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "runas_group=")) { | |
| runas_group = *cur + sizeof("runas_group=") - 1; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "prompt=")) { | |
| user_prompt = *cur + sizeof("prompt=") - 1; | |
| def_passprompt_override = TRUE; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "set_home=")) { | |
| if (atobool(*cur + sizeof("set_home=") - 1) == TRUE) | |
| SET(flags, MODE_RESET_HOME); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "preserve_environment=")) { | |
| if (atobool(*cur + sizeof("preserve_environment=") - 1) == TRUE) | |
| SET(flags, MODE_PRESERVE_ENV); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "run_shell=")) { | |
| if (atobool(*cur + sizeof("run_shell=") - 1) == TRUE) | |
| SET(flags, MODE_SHELL); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "login_shell=")) { | |
| if (atobool(*cur + sizeof("login_shell=") - 1) == TRUE) { | |
| SET(flags, MODE_LOGIN_SHELL); | |
| def_env_reset = TRUE; | |
| } | |
| continue; | |
| } | |
| if (MATCHES(*cur, "implied_shell=")) { | |
| if (atobool(*cur + sizeof("implied_shell=") - 1) == TRUE) | |
| SET(flags, MODE_IMPLIED_SHELL); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "preserve_groups=")) { | |
| if (atobool(*cur + sizeof("preserve_groups=") - 1) == TRUE) | |
| SET(flags, MODE_PRESERVE_GROUPS); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "ignore_ticket=")) { | |
| if (atobool(*cur + sizeof("ignore_ticket=") - 1) == TRUE) | |
| SET(flags, MODE_IGNORE_TICKET); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "noninteractive=")) { | |
| if (atobool(*cur + sizeof("noninteractive=") - 1) == TRUE) | |
| SET(flags, MODE_NONINTERACTIVE); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "sudoedit=")) { | |
| if (atobool(*cur + sizeof("sudoedit=") - 1) == TRUE) | |
| SET(flags, MODE_EDIT); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "login_class=")) { | |
| login_class = *cur + sizeof("login_class=") - 1; | |
| def_use_loginclass = TRUE; | |
| continue; | |
| } | |
| #ifdef HAVE_SELINUX | |
| if (MATCHES(*cur, "selinux_role=")) { | |
| user_role = *cur + sizeof("selinux_role=") - 1; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "selinux_type=")) { | |
| user_type = *cur + sizeof("selinux_type=") - 1; | |
| continue; | |
| } | |
| #endif /* HAVE_SELINUX */ | |
| #ifdef HAVE_BSD_AUTH_H | |
| if (MATCHES(*cur, "bsdauth_type=")) { | |
| login_style = *cur + sizeof("bsdauth_type=") - 1; | |
| continue; | |
| } | |
| #endif /* HAVE_BSD_AUTH_H */ | |
| #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) | |
| if (MATCHES(*cur, "progname=")) { | |
| setprogname(*cur + sizeof("progname=") - 1); | |
| continue; | |
| } | |
| #endif | |
| if (MATCHES(*cur, "network_addrs=")) { | |
| interfaces_string = *cur + sizeof("network_addrs=") - 1; | |
| set_interfaces(interfaces_string); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "sudoers_file=")) { | |
| sudoers_file = *cur + sizeof("sudoers_file=") - 1; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "sudoers_uid=")) { | |
| sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "sudoers_gid=")) { | |
| sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "sudoers_mode=")) { | |
| sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1, | |
| NULL, 8); | |
| continue; | |
| } | |
| } |
} |
| |
if (def_group_plugin) |
| |
group_plugin_unload(); |
| |
sudo_endpwent(); |
| |
sudo_endgrent(); |
| |
|
| for (cur = user_info; *cur != NULL; cur++) { | debug_return; |
| if (MATCHES(*cur, "user=")) { | |
| user_name = estrdup(*cur + sizeof("user=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "uid=")) { | |
| user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "gid=")) { | |
| p = *cur + sizeof("gid=") - 1; | |
| user_gid = (gid_t) atoi(p); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "groups=")) { | |
| groups = *cur + sizeof("groups=") - 1; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "cwd=")) { | |
| user_cwd = estrdup(*cur + sizeof("cwd=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "tty=")) { | |
| user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1); | |
| if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) | |
| user_tty += sizeof(_PATH_DEV) - 1; | |
| continue; | |
| } | |
| if (MATCHES(*cur, "host=")) { | |
| user_host = user_shost = estrdup(*cur + sizeof("host=") - 1); | |
| if ((p = strchr(user_host, '.'))) | |
| user_shost = estrndup(user_host, (size_t)(p - user_host)); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "lines=")) { | |
| sudo_user.lines = atoi(*cur + sizeof("lines=") - 1); | |
| continue; | |
| } | |
| if (MATCHES(*cur, "cols=")) { | |
| sudo_user.cols = atoi(*cur + sizeof("cols=") - 1); | |
| continue; | |
| } | |
| } | |
| if (user_cwd == NULL) | |
| user_cwd = "unknown"; | |
| if (user_tty == NULL) | |
| user_tty = "unknown"; /* user_ttypath remains NULL */ | |
| |
| if (groups != NULL && groups[0] != '\0') { | |
| const char *cp; | |
| GETGROUPS_T *gids; | |
| int ngids; | |
| |
| /* Count number of groups, including passwd gid. */ | |
| ngids = 2; | |
| for (cp = groups; *cp != '\0'; cp++) { | |
| if (*cp == ',') | |
| ngids++; | |
| } | |
| |
| /* The first gid in the list is the passwd group gid. */ | |
| gids = emalloc2(ngids, sizeof(GETGROUPS_T)); | |
| gids[0] = user_gid; | |
| ngids = 1; | |
| cp = groups; | |
| for (;;) { | |
| gids[ngids] = atoi(cp); | |
| if (gids[0] != gids[ngids]) | |
| ngids++; | |
| cp = strchr(cp, ','); | |
| if (cp == NULL) | |
| break; | |
| cp++; /* skip over comma */ | |
| } | |
| set_group_list(user_name, gids, ngids); | |
| efree(gids); | |
| } | |
| |
| #undef MATCHES | |
| return flags; | |
| } |
} |
| |
|
| static char * |
static char * |
| resolve_editor(char *editor, int nfiles, char **files, char ***argv_out) | resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out) |
| { |
{ |
| char *cp, **nargv, *editor_path = NULL; | char *cp, **nargv, *editor, *editor_path = NULL; |
| int ac, i, nargc, wasblank; | int ac, i, nargc; |
| | bool wasblank; |
| | debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN) |
| |
|
| editor = estrdup(editor); /* becomes part of argv_out */ | /* Note: editor becomes part of argv_out and is not freed. */ |
| | editor = emalloc(edlen + 1); |
| | memcpy(editor, ed, edlen); |
| | editor[edlen] = '\0'; |
| |
|
| /* |
/* |
| * Split editor into an argument vector; editor is reused (do not free). |
* Split editor into an argument vector; editor is reused (do not free). |
|
Line 1386 resolve_editor(char *editor, int nfiles, char **files,
|
Line 930 resolve_editor(char *editor, int nfiles, char **files,
|
| * line args so look for those and alloc space for them too. |
* line args so look for those and alloc space for them too. |
| */ |
*/ |
| nargc = 1; |
nargc = 1; |
| for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) { | for (wasblank = false, cp = editor; *cp != '\0'; cp++) { |
| if (isblank((unsigned char) *cp)) |
if (isblank((unsigned char) *cp)) |
| wasblank = TRUE; | wasblank = true; |
| else if (wasblank) { |
else if (wasblank) { |
| wasblank = FALSE; | wasblank = false; |
| nargc++; |
nargc++; |
| } |
} |
| } |
} |
|
Line 1399 resolve_editor(char *editor, int nfiles, char **files,
|
Line 943 resolve_editor(char *editor, int nfiles, char **files,
|
| if (cp == NULL || |
if (cp == NULL || |
| find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) { |
find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) { |
| efree(editor); |
efree(editor); |
| return NULL; | debug_return_str(NULL); |
| } |
} |
| nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *)); |
nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *)); |
| for (ac = 0; cp != NULL && ac < nargc; ac++) { |
for (ac = 0; cp != NULL && ac < nargc; ac++) { |
|
Line 1412 resolve_editor(char *editor, int nfiles, char **files,
|
Line 956 resolve_editor(char *editor, int nfiles, char **files,
|
| nargv[ac] = NULL; |
nargv[ac] = NULL; |
| |
|
| *argv_out = nargv; |
*argv_out = nargv; |
| return editor_path; | debug_return_str(editor_path); |
| } |
} |
| |
|
| /* |
/* |
|
Line 1423 resolve_editor(char *editor, int nfiles, char **files,
|
Line 967 resolve_editor(char *editor, int nfiles, char **files,
|
| static char * |
static char * |
| find_editor(int nfiles, char **files, char ***argv_out) |
find_editor(int nfiles, char **files, char ***argv_out) |
| { |
{ |
| char *cp, *editor, *editor_path = NULL, **ev, *ev0[4]; | const char *cp, *ep, *editor; |
| | char *editor_path = NULL, **ev, *ev0[4]; |
| | size_t len; |
| | debug_decl(find_editor, SUDO_DEBUG_PLUGIN) |
| |
|
| /* |
/* |
| * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one. |
* If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one. |
|
Line 1432 find_editor(int nfiles, char **files, char ***argv_out
|
Line 979 find_editor(int nfiles, char **files, char ***argv_out
|
| ev0[1] = "VISUAL"; |
ev0[1] = "VISUAL"; |
| ev0[2] = "EDITOR"; |
ev0[2] = "EDITOR"; |
| ev0[3] = NULL; |
ev0[3] = NULL; |
| for (ev = ev0; *ev != NULL; ev++) { | for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) { |
| if ((editor = getenv(*ev)) != NULL && *editor != '\0') { |
if ((editor = getenv(*ev)) != NULL && *editor != '\0') { |
| editor_path = resolve_editor(editor, nfiles, files, argv_out); | editor_path = resolve_editor(editor, strlen(editor), nfiles, |
| if (editor_path != NULL) | files, argv_out); |
| break; | |
| } |
} |
| } |
} |
| if (editor_path == NULL) { |
if (editor_path == NULL) { |
| /* def_editor could be a path, split it up */ | /* def_editor could be a path, split it up, avoiding strtok() */ |
| editor = estrdup(def_editor); | cp = editor = def_editor; |
| cp = strtok(editor, ":"); | do { |
| while (cp != NULL && editor_path == NULL) { | if ((ep = strchr(cp, ':')) != NULL) |
| editor_path = resolve_editor(cp, nfiles, files, argv_out); | len = ep - cp; |
| cp = strtok(NULL, ":"); | else |
| } | len = strlen(cp); |
| if (editor_path) | editor_path = resolve_editor(cp, len, nfiles, files, argv_out); |
| efree(editor); | cp = ep + 1; |
| | } while (ep != NULL && editor_path == NULL); |
| } |
} |
| if (!editor_path) { |
if (!editor_path) { |
| audit_failure(NewArgv, _("%s: command not found"), editor); | audit_failure(NewArgv, N_("%s: command not found"), editor); |
| warningx(_("%s: command not found"), editor); |
warningx(_("%s: command not found"), editor); |
| } |
} |
| return editor_path; | debug_return_str(editor_path); |
| } |
} |
| |
|
| #ifdef USE_ADMIN_FLAG |
#ifdef USE_ADMIN_FLAG |
|
Line 1464 create_admin_success_flag(void)
|
Line 1011 create_admin_success_flag(void)
|
| struct stat statbuf; |
struct stat statbuf; |
| char flagfile[PATH_MAX]; |
char flagfile[PATH_MAX]; |
| int fd, n; |
int fd, n; |
| |
debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN) |
| |
|
| /* Check whether the user is in the admin group. */ |
/* Check whether the user is in the admin group. */ |
| if (!user_in_group(sudo_user.pw, "admin")) |
if (!user_in_group(sudo_user.pw, "admin")) |
| return; | debug_return; |
| |
|
| /* Build path to flag file. */ |
/* Build path to flag file. */ |
| n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful", |
n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful", |
| user_dir); |
user_dir); |
| if (n <= 0 || n >= sizeof(flagfile)) |
if (n <= 0 || n >= sizeof(flagfile)) |
| return; | debug_return; |
| |
|
| /* Create admin flag file if it doesn't already exist. */ |
/* Create admin flag file if it doesn't already exist. */ |
| set_perms(PERM_USER); |
set_perms(PERM_USER); |
|
Line 1482 create_admin_success_flag(void)
|
Line 1030 create_admin_success_flag(void)
|
| close(fd); |
close(fd); |
| } |
} |
| restore_perms(); |
restore_perms(); |
| |
debug_return; |
| } |
} |
| #else /* !USE_ADMIN_FLAG */ |
#else /* !USE_ADMIN_FLAG */ |
| static void |
static void |
|
Line 1491 create_admin_success_flag(void)
|
Line 1040 create_admin_success_flag(void)
|
| } |
} |
| #endif /* USE_ADMIN_FLAG */ |
#endif /* USE_ADMIN_FLAG */ |
| |
|
| struct policy_plugin sudoers_policy = { | static bool |
| SUDO_POLICY_PLUGIN, | tty_present(void) |
| SUDO_API_VERSION, | { |
| sudoers_policy_open, | #if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__) |
| sudoers_policy_close, | return user_ttypath != NULL; |
| sudoers_policy_version, | #else |
| sudoers_policy_check, | int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); |
| sudoers_policy_list, | if (fd != -1) |
| sudoers_policy_validate, | close(fd); |
| sudoers_policy_invalidate, | return fd != -1; |
| sudoers_policy_init_session | #endif |
| }; | } |