version 1.1.1.2, 2012/05/29 12:26:49
|
version 1.1.1.6, 2014/06/15 16:12:54
|
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> |
Line 78
|
Line 70
|
# include <selinux/selinux.h> |
# include <selinux/selinux.h> |
#endif |
#endif |
#include <ctype.h> |
#include <ctype.h> |
#include <setjmp.h> |
|
#ifndef HAVE_GETADDRINFO |
#ifndef HAVE_GETADDRINFO |
# include "compat/getaddrinfo.h" |
# include "compat/getaddrinfo.h" |
#endif |
#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" |
#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 args[], 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 |
*/ |
*/ |
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; |
uid_t timestamp_uid; |
uid_t timestamp_uid; |
extern int errorlineno; |
|
extern bool parse_error; |
|
extern char *errorfile; |
|
#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 int sudo_version; |
|
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; |
|
|
/* Declared here instead of plugin_error.c for static sudo builds. */ | int |
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[], char * const args[]) | |
{ |
{ |
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) |
debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN) | |
|
|
sudo_version = version; |
|
if (!sudo_conv) |
|
sudo_conv = conversation; |
|
if (!sudo_printf) |
|
sudo_printf = plugin_printf; |
|
|
|
/* Plugin args are only specified for API version 1.2 and higher. */ |
|
if (sudo_version < SUDO_API_MKVERSION(1, 2)) |
|
args = NULL; |
|
|
|
if (sigsetjmp(error_jmp, 1)) { |
|
/* called via error(), errorx() or log_fatal() */ |
|
rewind_perms(); |
|
debug_return_bool(-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 args, settings and user_info */ | /* Parse info from front-end. */ |
sudo_mode = deserialize_info(args, 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 197 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 144 sudoers_policy_open(unsigned int version, sudo_conv_t
|
snl = sudo_read_nss(); |
snl = sudo_read_nss(); |
|
|
/* LDAP or NSS may modify the euid so we need to be root for the open. */ |
/* LDAP or NSS may modify the euid so we need to be root for the open. */ |
set_perms(PERM_INITIAL); |
|
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) { | TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) { |
if (nss->open(nss) == 0 && nss->parse(nss) == 0) { | if (nss->open(nss) == 0 && nss->parse(nss) == 0) { |
sources++; | sources++; |
if (nss->setdefs(nss) != 0) | if (nss->setdefs(nss) != 0) |
log_error(NO_STDERR, _("problem with defaults entries")); | log_warning(NO_STDERR, N_("problem with defaults entries")); |
} | } else { |
| TAILQ_REMOVE(snl, nss, entries); |
| } |
} |
} |
if (sources == 0) { |
if (sources == 0) { |
warningx(_("no valid sudoers sources found, quitting")); | warningx(U_("no valid sudoers sources found, quitting")); |
debug_return_bool(-1); |
debug_return_bool(-1); |
} |
} |
|
|
Line 228 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 176 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 236 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 185 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, _("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 */ |
Line 249 sudoers_policy_open(unsigned int version, sudo_conv_t
|
Line 198 sudoers_policy_open(unsigned int version, sudo_conv_t
|
debug_return_bool(true); |
debug_return_bool(true); |
} |
} |
|
|
static void | int |
sudoers_policy_close(int exit_status, int error_code) | |
{ | |
debug_decl(sudoers_policy_close, SUDO_DEBUG_PLUGIN) | |
| |
if (sigsetjmp(error_jmp, 1)) { | |
/* called via error(), errorx() or log_fatal() */ | |
debug_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); | |
| |
debug_return; | |
} | |
| |
/* | |
* 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, char **user_env[]) | |
{ | |
debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN) | |
| |
/* user_env is only specified for API version 1.2 and higher. */ | |
if (sudo_version < SUDO_API_MKVERSION(1, 2)) | |
user_env = NULL; | |
| |
if (sigsetjmp(error_jmp, 1)) { | |
/* called via error(), errorx() or log_fatal() */ | |
return -1; | |
} | |
| |
debug_return_bool(sudo_auth_begin_session(pwd, user_env)); | |
} | |
| |
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) |
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_fatal() */ | if (fatal_setjmp() != 0) { |
| /* error recovery via fatal(), fatalx() or log_fatal() */ |
rval = -1; |
rval = -1; |
goto done; |
goto done; |
} |
} |
|
|
/* Is root even allowed to run sudo? */ |
/* Is root even allowed to run sudo? */ |
if (user_uid == 0 && !def_root_sudo) { |
if (user_uid == 0 && !def_root_sudo) { |
warningx(_("sudoers specifies that root is not allowed to sudo")); | warningx(U_("sudoers specifies that root is not allowed to sudo")); |
goto bad; |
goto bad; |
} |
} |
|
|
/* Check for -C overriding def_closefrom. */ |
|
if (user_closefrom >= 0 && user_closefrom != def_closefrom) { |
|
if (!def_closefrom_override) { |
|
warningx(_("you are not permitted to use the -C option")); |
|
goto bad; |
|
} |
|
def_closefrom = user_closefrom; |
|
} |
|
|
|
set_perms(PERM_INITIAL); |
set_perms(PERM_INITIAL); |
|
|
/* Environment variables specified on the command line. */ |
/* Environment variables specified on the command line. */ |
Line 361 sudoers_policy_main(int argc, char * const argv[], int
|
Line 252 sudoers_policy_main(int argc, char * const argv[], int
|
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 and apply per-command Defaults. */ |
cmnd_status = set_cmnd(); |
cmnd_status = set_cmnd(); |
if (cmnd_status == -1) { |
|
rval = -1; |
|
goto done; |
|
} |
|
|
|
#ifdef HAVE_SETLOCALE | /* Check for -C overriding def_closefrom. */ |
if (!setlocale(LC_ALL, def_sudoers_locale)) { | if (user_closefrom >= 0 && user_closefrom != def_closefrom) { |
warningx(_("unable to set locale to \"%s\", using \"C\""), | if (!def_closefrom_override) { |
def_sudoers_locale); | warningx(U_("you are not permitted to use the -C option")); |
setlocale(LC_ALL, "C"); | goto bad; |
| } |
| def_closefrom = user_closefrom; |
} |
} |
#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) { | TAILQ_FOREACH(nss, snl, entries) { |
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 394 sudoers_policy_main(int argc, char * const argv[], int
|
Line 283 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 409 sudoers_policy_main(int argc, char * const argv[], int
|
Line 297 sudoers_policy_main(int argc, char * const argv[], int
|
* Look up the timestamp dir owner if one is specified. |
* Look up the timestamp dir owner if one is specified. |
*/ |
*/ |
if (def_timestampowner) { |
if (def_timestampowner) { |
struct passwd *pw; | struct passwd *pw = NULL; |
|
|
if (*def_timestampowner == '#') | if (*def_timestampowner == '#') { |
pw = sudo_getpwuid(atoi(def_timestampowner + 1)); | const char *errstr; |
else | uid_t uid = atoid(def_timestampowner + 1, NULL, NULL, &errstr); |
| if (errstr == NULL) |
| pw = sudo_getpwuid(uid); |
| } |
| if (pw == NULL) |
pw = sudo_getpwnam(def_timestampowner); |
pw = sudo_getpwnam(def_timestampowner); |
if (pw != NULL) { |
if (pw != NULL) { |
timestamp_uid = pw->pw_uid; |
timestamp_uid = pw->pw_uid; |
pw_delref(pw); | sudo_pw_delref(pw); |
} else { |
} else { |
log_error(0, _("timestamp owner (%s): No such user"), | log_warning(0, N_("timestamp owner (%s): No such user"), |
def_timestampowner); |
def_timestampowner); |
timestamp_uid = ROOT_UID; |
timestamp_uid = ROOT_UID; |
} |
} |
Line 432 sudoers_policy_main(int argc, char * const argv[], int
|
Line 324 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(U_("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 455 sudoers_policy_main(int argc, char * const argv[], int
|
Line 343 sudoers_policy_main(int argc, char * const argv[], int
|
|
|
/* 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 466 sudoers_policy_main(int argc, char * const argv[], int
|
Line 357 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 474 sudoers_policy_main(int argc, char * const argv[], int
|
Line 365 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 506 sudoers_policy_main(int argc, char * const argv[], int
|
Line 374 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(U_("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(U_("%s: command not found"), NewArgv[0]); |
| } else { |
| audit_failure(NewArgv, N_("%s: command not found"), user_cmnd); |
| warningx(U_("%s: command not found"), user_cmnd); |
| } |
goto bad; |
goto bad; |
} |
} |
|
|
/* If user specified env vars make sure sudoers allows it. */ |
/* If user specified env vars make sure sudoers allows it. */ |
if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) { |
if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) { |
if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) { |
if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) { |
warningx(_("sorry, you are not allowed to preserve the environment")); | warningx(U_("sorry, you are not allowed to preserve the environment")); |
goto bad; |
goto bad; |
} else |
} else |
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 550 sudoers_policy_main(int argc, char * const argv[], int
|
Line 413 sudoers_policy_main(int argc, char * const argv[], int
|
display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */ |
display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */ |
|
|
/* Cleanup sudoers sources */ |
/* Cleanup sudoers sources */ |
tq_foreach_fwd(snl, nss) { | TAILQ_FOREACH(nss, snl, entries) { |
nss->close(nss); |
nss->close(nss); |
} |
} |
if (def_group_plugin) |
if (def_group_plugin) |
Line 567 sudoers_policy_main(int argc, char * const argv[], int
|
Line 430 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 585 sudoers_policy_main(int argc, char * const argv[], int
|
Line 444 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 626 sudoers_policy_main(int argc, char * const argv[], int
|
Line 482 sudoers_policy_main(int argc, char * const argv[], int
|
/* 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; |
|
gid_t egid; |
|
size_t glsize; |
|
char *cp, *gid_list; |
|
struct group_list *grlist = get_group_list(runas_pw); |
|
|
|
/* We reserve an extra spot in the list for the effective gid. */ |
|
glsize = sizeof("runas_groups=") - 1 + |
|
((grlist->ngids + 1) * (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; |
|
|
|
/* On BSD systems the effective gid is the first group in the list. */ |
|
egid = runas_gr ? (unsigned int)runas_gr->gr_gid : |
|
(unsigned int)runas_pw->pw_gid; |
|
len = snprintf(cp, glsize - (cp - gid_list), "%u", egid); |
|
if (len < 0 || len >= glsize - (cp - gid_list)) |
|
errorx(1, _("internal error, runas_groups overflow")); |
|
cp += len; |
|
for (i = 0; i < grlist->ngids; i++) { |
|
if (grlist->gids[i] != egid) { |
|
len = snprintf(cp, glsize - (cp - gid_list), ",%u", |
|
(unsigned int) grlist->gids[i]); |
|
if (len < 0 || len >= glsize - (cp - gid_list)) |
|
errorx(1, _("internal error, runas_groups overflow")); |
|
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_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 (def_use_loginclass) |
|
command_info[info_len++] = fmt_string("login_class", login_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. */ |
| |
/* Get private version of the environment and zero out stashed copy. */ | |
*user_env_out = env_get(); | |
env_init(NULL); |
env_init(NULL); |
|
|
goto done; |
goto done; |
Line 730 bad:
|
Line 505 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. */ |
Line 739 done:
|
Line 515 done:
|
debug_return_bool(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[]) |
|
{ |
|
debug_decl(sudoers_policy_check, SUDO_DEBUG_PLUGIN) |
|
|
|
if (!ISSET(sudo_mode, MODE_EDIT)) |
|
SET(sudo_mode, MODE_RUN); |
|
|
|
debug_return_bool(sudoers_policy_main(argc, argv, 0, env_add, command_infop, |
|
argv_out, user_env_out)); |
|
} |
|
|
|
static int |
|
sudoers_policy_validate(void) |
|
{ |
|
debug_decl(sudoers_policy_validate, SUDO_DEBUG_PLUGIN) |
|
|
|
user_cmnd = "validate"; |
|
SET(sudo_mode, MODE_VALIDATE); |
|
|
|
debug_return_bool(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL)); |
|
} |
|
|
|
static void |
|
sudoers_policy_invalidate(int remove) |
|
{ |
|
debug_decl(sudoers_policy_invalidate, SUDO_DEBUG_PLUGIN) |
|
|
|
user_cmnd = "kill"; |
|
if (sigsetjmp(error_jmp, 1) == 0) { |
|
remove_timestamp(remove); |
|
plugin_cleanup(0); |
|
} |
|
|
|
debug_return; |
|
} |
|
|
|
static int |
|
sudoers_policy_list(int argc, char * const argv[], int verbose, |
|
const char *list_user) |
|
{ |
|
int rval; |
|
debug_decl(sudoers_policy_list, SUDO_DEBUG_PLUGIN) |
|
|
|
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); |
|
debug_return_bool(-1); |
|
} |
|
} |
|
rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL); |
|
if (list_user) { |
|
pw_delref(list_pw); |
|
list_pw = NULL; |
|
} |
|
|
|
debug_return_bool(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; |
|
bool unknown_user = false; |
debug_decl(init_vars, SUDO_DEBUG_PLUGIN) |
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 842 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(U_("unknown uid: %u"), (unsigned int) user_uid); |
|
|
/* Need to make a fake struct passwd for the call to log_fatal(). */ | /* 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_fatal(0, _("unknown uid: %u"), (unsigned int) user_uid); | unknown_user = true; |
/* NOTREACHED */ | } |
} |
} |
|
|
/* |
/* |
* Get group list. | * Get group list and store initialize permissions. |
*/ |
*/ |
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_perms(PERM_INITIAL); |
|
|
/* 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; |
|
|
|
/* 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() */ |
/* It is now safe to use log_fatal() and set_perms() */ |
|
if (unknown_user) |
|
log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid); |
debug_return; |
debug_return; |
} |
} |
|
|
Line 938 set_cmnd(void)
|
Line 653 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(U_("internal error, %s overflow"), "set_cmnd()"); |
to += n; |
to += n; |
*to++ = ' '; |
*to++ = ' '; |
} |
} |
Line 946 set_cmnd(void)
|
Line 661 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 955 set_cmnd(void)
|
Line 672 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, _("problem with defaults entries")); | log_warning(NO_STDERR, N_("problem with defaults entries")); |
|
|
debug_return_int(rval); |
debug_return_int(rval); |
} |
} |
Line 975 open_sudoers(const char *sudoers, bool doedit, bool *k
|
Line 692 open_sudoers(const char *sudoers, bool doedit, bool *k
|
|
|
switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) { |
switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) { |
case SUDO_PATH_SECURE: |
case SUDO_PATH_SECURE: |
|
/* |
|
* If we are expecting sudoers to be group readable by |
|
* SUDOERS_GID but it is not, we must open the file as root, |
|
* not uid 1. |
|
*/ |
|
if (sudoers_uid == ROOT_UID && ISSET(sudoers_mode, S_IRGRP)) { |
|
if (!ISSET(sb.st_mode, S_IRGRP) || sb.st_gid != SUDOERS_GID) { |
|
restore_perms(); |
|
set_perms(PERM_ROOT); |
|
} |
|
} |
|
/* |
|
* 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) { |
if ((fp = fopen(sudoers, "r")) == NULL) { |
log_error(USE_ERRNO, _("unable to open %s"), sudoers); | log_warning(USE_ERRNO, N_("unable to open %s"), sudoers); |
} else { |
} else { |
/* |
|
* Make sure we can actually read sudoers so we can present the |
|
* user with a reasonable error message (unlike the lexer). |
|
*/ |
|
if (sb.st_size != 0 && fgetc(fp) == EOF) { |
if (sb.st_size != 0 && fgetc(fp) == EOF) { |
log_error(USE_ERRNO, _("unable to read %s"), | log_warning(USE_ERRNO, N_("unable to read %s"), |
sudoers); |
sudoers); |
fclose(fp); |
fclose(fp); |
fp = NULL; |
fp = NULL; |
Line 995 open_sudoers(const char *sudoers, bool doedit, bool *k
|
Line 723 open_sudoers(const char *sudoers, bool doedit, bool *k
|
} |
} |
break; |
break; |
case SUDO_PATH_MISSING: |
case SUDO_PATH_MISSING: |
log_error(USE_ERRNO, _("unable to stat %s"), sudoers); | log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers); |
break; |
break; |
case SUDO_PATH_BAD_TYPE: |
case SUDO_PATH_BAD_TYPE: |
log_error(0, _("%s is not a regular file"), sudoers); | log_warning(0, N_("%s is not a regular file"), sudoers); |
break; |
break; |
case SUDO_PATH_WRONG_OWNER: |
case SUDO_PATH_WRONG_OWNER: |
log_error(0, _("%s is owned by uid %u, should be %u"), | log_warning(0, N_("%s is owned by uid %u, should be %u"), |
sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid); |
sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid); |
break; |
break; |
case SUDO_PATH_WORLD_WRITABLE: |
case SUDO_PATH_WORLD_WRITABLE: |
log_error(0, _("%s is world writable"), sudoers); | log_warning(0, N_("%s is world writable"), sudoers); |
break; |
break; |
case SUDO_PATH_GROUP_WRITABLE: |
case SUDO_PATH_GROUP_WRITABLE: |
log_error(0, _("%s is owned by gid %u, should be %u"), | log_warning(0, N_("%s is owned by gid %u, should be %u"), |
sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid); |
sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid); |
break; |
break; |
default: |
default: |
Line 1033 set_loginclass(struct passwd *pw)
|
Line 761 set_loginclass(struct passwd *pw)
|
debug_return; |
debug_return; |
|
|
if (login_class && strcmp(login_class, "-") != 0) { |
if (login_class && strcmp(login_class, "-") != 0) { |
if (user_uid != 0 && | if (user_uid != 0 && pw->pw_uid != 0) |
strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) | fatalx(U_("only root can use `-c %s'"), login_class); |
errorx(1, _("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 1052 set_loginclass(struct passwd *pw)
|
Line 779 set_loginclass(struct passwd *pw)
|
* corrupted we want the admin to be able to use sudo to fix it. |
* corrupted we want the admin to be able to use sudo to fix it. |
*/ |
*/ |
if (login_class) |
if (login_class) |
log_fatal(errflags, _("unknown login class: %s"), login_class); | log_fatal(errflags, N_("unknown login class: %s"), login_class); |
else |
else |
log_error(errflags, _("unknown login class: %s"), login_class); | log_warning(errflags, N_("unknown login class: %s"), login_class); |
def_use_loginclass = false; |
def_use_loginclass = false; |
} |
} |
login_close(lc); |
login_close(lc); |
Line 1067 set_loginclass(struct passwd *pw)
|
Line 794 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) |
{ |
{ |
struct addrinfo *res0, hint; |
struct addrinfo *res0, hint; |
char *p; |
char *p; |
debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN) |
debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN) |
|
|
zero_bytes(&hint, sizeof(hint)); | memset(&hint, 0, 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) { |
log_error(MSG_ONLY, _("unable to resolve host %s"), user_host); | log_warning(MSG_ONLY, N_("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); |
user_host = estrdup(res0->ai_canonname); |
user_host = estrdup(res0->ai_canonname); |
freeaddrinfo(res0); |
freeaddrinfo(res0); |
|
if ((p = strchr(user_host, '.')) != NULL) |
|
user_shost = estrndup(user_host, (size_t)(p - user_host)); |
|
else |
|
user_shost = user_host; |
} |
} |
if ((p = strchr(user_host, '.')) != NULL) |
|
user_shost = estrndup(user_host, (size_t)(p - user_host)); |
|
else |
|
user_shost = user_host; |
|
debug_return; |
debug_return; |
} |
} |
|
|
Line 1103 set_fqdn(void)
|
Line 835 set_fqdn(void)
|
static void |
static void |
set_runaspw(const char *user) |
set_runaspw(const char *user) |
{ |
{ |
|
struct passwd *pw = NULL; |
debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN) |
debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN) |
|
|
if (runas_pw != NULL) |
|
pw_delref(runas_pw); |
|
if (*user == '#') { |
if (*user == '#') { |
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) | const char *errstr; |
runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); | uid_t uid = atoid(user + 1, NULL, NULL, &errstr); |
} else { | if (errstr == NULL) { |
if ((runas_pw = sudo_getpwnam(user)) == NULL) | if ((pw = sudo_getpwuid(uid)) == NULL) |
log_fatal(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user); | pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); |
| } |
} |
} |
|
if (pw == NULL) { |
|
if ((pw = sudo_getpwnam(user)) == NULL) |
|
log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user); |
|
} |
|
if (runas_pw != NULL) |
|
sudo_pw_delref(runas_pw); |
|
runas_pw = pw; |
debug_return; |
debug_return; |
} |
} |
|
|
Line 1124 set_runaspw(const char *user)
|
Line 863 set_runaspw(const char *user)
|
static void |
static void |
set_runasgr(const char *group) |
set_runasgr(const char *group) |
{ |
{ |
|
struct group *gr = NULL; |
debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN) |
debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN) |
|
|
if (runas_gr != NULL) |
|
gr_delref(runas_gr); |
|
if (*group == '#') { |
if (*group == '#') { |
if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) | const char *errstr; |
runas_gr = sudo_fakegrnam(group); | gid_t gid = atoid(group + 1, NULL, NULL, &errstr); |
} else { | if (errstr == NULL) { |
if ((runas_gr = sudo_getgrnam(group)) == NULL) | if ((gr = sudo_getgrgid(gid)) == NULL) |
log_fatal(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group); | gr = sudo_fakegrnam(group); |
| } |
} |
} |
|
if (gr == NULL) { |
|
if ((gr = sudo_getgrnam(group)) == NULL) |
|
log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group); |
|
} |
|
if (runas_gr != NULL) |
|
sudo_gr_delref(runas_gr); |
|
runas_gr = gr; |
debug_return; |
debug_return; |
} |
} |
|
|
Line 1151 cb_runas_default(const char *user)
|
Line 897 cb_runas_default(const char *user)
|
} |
} |
|
|
/* |
/* |
* Cleanup hook for error()/errorx() | * Callback for sudoers_locale sudoers setting. |
*/ |
*/ |
void |
|
plugin_cleanup(int gotsignal) |
|
{ |
|
struct sudo_nss *nss; |
|
|
|
if (!gotsignal) { |
|
debug_decl(plugin_cleanup, SUDO_DEBUG_PLUGIN) |
|
if (snl != NULL) { |
|
tq_foreach_fwd(snl, nss) |
|
nss->close(nss); |
|
} |
|
if (def_group_plugin) |
|
group_plugin_unload(); |
|
sudo_endpwent(); |
|
sudo_endgrent(); |
|
debug_return; |
|
} |
|
} |
|
|
|
static int |
static int |
sudoers_policy_version(int verbose) | cb_sudoers_locale(const char *locale) |
{ |
{ |
debug_decl(sudoers_policy_version, SUDO_DEBUG_PLUGIN) | sudoers_initlocale(NULL, locale); |
| return true; |
if (sigsetjmp(error_jmp, 1)) { | |
/* error recovery via error(), errorx() or log_fatal() */ | |
debug_return_bool(-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"); | |
if (interfaces_string != NULL) { | |
dump_interfaces(interfaces_string); | |
sudo_printf(SUDO_CONV_INFO_MSG, "\n"); | |
} | |
} | |
debug_return_bool(true); | |
} |
} |
|
|
static int | /* |
deserialize_info(char * const args[], 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) |
const char *debug_flags = NULL; | |
int flags = 0; | |
debug_decl(deserialize_info, SUDO_DEBUG_PLUGIN) | |
|
|
#define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) | if (snl != NULL) { |
| TAILQ_FOREACH(nss, snl, entries) { |
/* Parse sudo.conf plugin args. */ | nss->close(nss); |
if (args != NULL) { | |
for (cur = args; *cur != NULL; cur++) { | |
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(); |
|
|
/* Parse command line settings. */ | debug_return; |
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_flags=")) { | |
debug_flags = *cur + sizeof("debug_flags=") - 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; | |
} | |
} | |
| |
for (cur = user_info; *cur != NULL; cur++) { | |
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); | |
} | |
| |
/* Setup debugging if indicated. */ | |
if (debug_flags != NULL) { | |
sudo_debug_init(NULL, debug_flags); | |
for (cur = settings; *cur != NULL; cur++) | |
sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur); | |
for (cur = user_info; *cur != NULL; cur++) | |
sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur); | |
} | |
| |
#undef MATCHES | |
debug_return_int(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; |
int ac, i, nargc; |
bool wasblank; |
bool wasblank; |
debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN) |
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 1490 resolve_editor(char *editor, int nfiles, char **files,
|
Line 984 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) |
debug_decl(find_editor, SUDO_DEBUG_PLUGIN) |
|
|
/* |
/* |
Line 1500 find_editor(int nfiles, char **files, char ***argv_out
|
Line 996 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(U_("%s: command not found"), editor); |
} |
} |
debug_return_str(editor_path); |
debug_return_str(editor_path); |
} |
} |
Line 1541 create_admin_success_flag(void)
|
Line 1037 create_admin_success_flag(void)
|
/* 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 || (size_t)n >= sizeof(flagfile)) |
debug_return; |
debug_return; |
|
|
/* Create admin flag file if it doesn't already exist. */ |
/* Create admin flag file if it doesn't already exist. */ |
Line 1561 create_admin_success_flag(void)
|
Line 1057 create_admin_success_flag(void)
|
} |
} |
#endif /* USE_ADMIN_FLAG */ |
#endif /* USE_ADMIN_FLAG */ |
|
|
static void | static bool |
sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook)) | tty_present(void) |
{ |
{ |
struct sudo_hook hook; | #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__) |
| return user_ttypath != NULL; |
memset(&hook, 0, sizeof(hook)); | #else |
hook.hook_version = SUDO_HOOK_VERSION; | int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); |
| if (fd != -1) |
hook.hook_type = SUDO_HOOK_SETENV; | close(fd); |
hook.hook_fn = sudoers_hook_setenv; | return fd != -1; |
register_hook(&hook); | #endif |
| |
hook.hook_type = SUDO_HOOK_UNSETENV; | |
hook.hook_fn = sudoers_hook_unsetenv; | |
register_hook(&hook); | |
| |
hook.hook_type = SUDO_HOOK_GETENV; | |
hook.hook_fn = sudoers_hook_getenv; | |
register_hook(&hook); | |
| |
hook.hook_type = SUDO_HOOK_PUTENV; | |
hook.hook_fn = sudoers_hook_putenv; | |
register_hook(&hook); | |
} |
} |
|
|
struct policy_plugin sudoers_policy = { |
|
SUDO_POLICY_PLUGIN, |
|
SUDO_API_VERSION, |
|
sudoers_policy_open, |
|
sudoers_policy_close, |
|
sudoers_policy_version, |
|
sudoers_policy_check, |
|
sudoers_policy_list, |
|
sudoers_policy_validate, |
|
sudoers_policy_invalidate, |
|
sudoers_policy_init_session, |
|
sudoers_policy_register_hooks |
|
}; |
|