#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
#endif
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
-# include <membership.h>
-#endif
#include <ctype.h>
#include <setjmp.h>
#include "sudoers.h"
-#include "lbuf.h"
#include "interfaces.h"
#include "sudoers_version.h"
#include "auth/sudo_auth.h"
* Prototypes
*/
static void init_vars(char * const *);
-static int set_cmnd(int);
+static int set_cmnd(void);
static void set_loginclass(struct passwd *);
-static void set_runasgr(char *);
-static void set_runaspw(char *);
+static void set_runaspw(const char *);
+static void set_runasgr(const char *);
+static int cb_runas_default(const char *);
static int sudoers_policy_version(int verbose);
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);
-/* XXX */
-extern int runas_ngroups;
-extern GETGROUPS_T *runas_groups;
-
/*
* Globals
*/
return -1;
}
+ bindtextdomain("sudoers", LOCALEDIR);
+
/*
* Signal setup:
* Ignore keyboard-generated signals so the user cannot interrupt
if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
sources++;
if (nss->setdefs(nss) != 0)
- log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
+ log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
}
}
if (sources == 0) {
- warningx("no valid sudoers sources found, quitting");
+ warningx(_("no valid sudoers sources found, quitting"));
return -1;
}
set_runaspw(runas_user ? runas_user : def_runas_default);
if (!update_defaults(SETDEF_RUNAS))
- log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
+ log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
if (def_fqdn)
set_fqdn(); /* deferred until after sudoers is parsed */
/* We do not currently log the exit status. */
if (error_code)
- warningx("unable to execute %s: %s", safe_cmnd, strerror(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))
pw_delref(runas_pw);
if (runas_gr != NULL)
gr_delref(runas_gr);
+ if (user_group_list != NULL)
+ grlist_delref(user_group_list);
}
/*
/* Is root even allowed to run sudo? */
if (user_uid == 0 && !def_root_sudo) {
- warningx("sudoers specifies that root is not allowed to sudo");
+ warningx(_("sudoers specifies that root is not allowed to sudo"));
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");
+ warningx(_("you are not permitted to use the -C option"));
goto bad;
}
def_closefrom = user_closefrom;
NewArgv[0] = user_cmnd;
NewArgv[1] = NULL;
} else {
+ /* Must leave an extra slot before NewArgv for bash's --login */
NewArgc = argc;
- NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
- memcpy(NewArgv, argv, argc * sizeof(char *));
+ NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
+ memcpy(++NewArgv, argv, argc * sizeof(char *));
NewArgv[NewArgc] = NULL;
if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
NewArgv[0] = estrdup(runas_pw->pw_shell);
}
+ /* If given the -P option, set the "preserve_groups" flag. */
+ if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
+ def_preserve_groups = TRUE;
+
/* Find command in path */
- cmnd_status = set_cmnd(sudo_mode);
+ 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\"",
+ warningx(_("unable to set locale to \"%s\", using \"C\""),
def_sudoers_locale);
setlocale(LC_ALL, "C");
}
else
pw = sudo_getpwnam(def_timestampowner);
if (!pw)
- log_error(0, "timestamp owner (%s): No such user",
+ log_error(0, _("timestamp owner (%s): No such user"),
def_timestampowner);
timestamp_uid = pw->pw_uid;
pw_delref(pw);
}
- /* If given the -P option, set the "preserve_groups" flag. */
- if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
- def_preserve_groups = TRUE;
-
/* If no command line args and "shell_noargs" is not set, error out. */
if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
rval = -2; /* usage error */
if (def_requiretty) {
int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
if (fd == -1) {
- audit_failure(NewArgv, "no tty");
- warningx("sorry, you must have a tty to run sudo");
+ audit_failure(NewArgv, _("no tty"));
+ warningx(_("sorry, you must have a tty to run sudo"));
goto bad;
} else
(void) close(fd);
if (sudo_user.pw != NULL)
pw_delref(sudo_user.pw);
sudo_user.pw = pw;
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
- mbr_uid_to_uuid(user_uid, user_uuid);
-#endif
}
}
}
/* If the user was not allowed to run the command we are done. */
if (!ISSET(validated, VALIDATE_OK)) {
if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
- audit_failure(NewArgv, "No user or host");
+ audit_failure(NewArgv, _("No user or host"));
log_denial(validated, 1);
} else {
if (def_path_info) {
log_denial(validated,
!(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
if (cmnd_status == NOT_FOUND)
- warningx("%s: command not found", user_cmnd);
+ 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);
+ 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");
+ audit_failure(NewArgv, _("validation failure"));
}
goto bad;
}
/* Finally tell the user if the command did not exist. */
if (cmnd_status == NOT_FOUND_DOT) {
- audit_failure(NewArgv, "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);
+ audit_failure(NewArgv, _("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);
goto bad;
} else if (cmnd_status == NOT_FOUND) {
- audit_failure(NewArgv, "%s: command not found", user_cmnd);
- warningx("%s: command not found", user_cmnd);
+ audit_failure(NewArgv, _("%s: command not found"), user_cmnd);
+ warningx(_("%s: command not found"), user_cmnd);
goto bad;
}
/* If user specified env vars make sure sudoers allows it. */
if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
- warningx("sorry, you are not allowed to preserve the environment");
+ warningx(_("sorry, you are not allowed to preserve the environment"));
goto bad;
} else
validate_env_vars(sudo_user.env_vars);
/* 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
+ * in conjunction with the -c option even if the shell name starts
+ * with a '-'. Unfortunately, bash 1.x uses -login, not --login
+ * so this will cause an error for that.
+ */
+ if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 &&
+ strcmp(NewArgv[1], "-c") == 0) {
+ /* Use the extra slot before NewArgv so we can store --login. */
+ NewArgv--;
+ NewArgc++;
+ NewArgv[0] = NewArgv[1];
+ NewArgv[1] = "--login";
+ }
+
#if defined(__linux__) || defined(_AIX)
/* Insert system-wide environment variables. */
read_env_file(_PATH_ENVIRONMENT, TRUE);
}
if (def_preserve_groups) {
command_info[info_len++] = "preserve_groups=true";
- } else if (runas_ngroups != -1) {
+ } 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 + (runas_ngroups * (MAX_UID_T_LEN + 1));
+ 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 < runas_ngroups; i++) {
+ for (i = 0; i < grlist->ngids; i++) {
/* XXX - check rval */
len = snprintf(cp, glsize - (cp - gid_list), "%s%u",
- i ? "," : "", (unsigned int) runas_groups[i]);
+ 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);
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 (list_user) {
list_pw = sudo_getpwnam(list_user);
if (list_pw == NULL) {
- warningx("unknown user: %s", list_user);
+ warningx(_("unknown user: %s"), list_user);
return -1;
}
}
* YP/NIS/NIS+/LDAP/etc daemon has died.
*/
if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
- errorx(1, "unknown user: %s", user_name);
- log_error(0, "unknown user: %s", user_name);
+ errorx(1, _("unknown user: %s"), user_name);
+ log_error(0, _("unknown user: %s"), user_name);
/* NOTREACHED */
}
-#ifdef HAVE_MBR_CHECK_MEMBERSHIP
- mbr_uid_to_uuid(user_uid, user_uuid);
-#endif
+
+ /*
+ * Get group list.
+ */
+ if (user_group_list == NULL)
+ user_group_list = get_group_list(sudo_user.pw);
+
+ /* Set runas callback. */
+ sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
/* It is now safe to use log_error() and set_perms() */
}
* and apply any command-specific defaults entries.
*/
static int
-set_cmnd(int sudo_mode)
+set_cmnd(void)
{
int rval;
char *path = user_path;
/* set user_args */
if (NewArgc > 1) {
- char *to, **from;
+ char *to, *from, **av;
size_t size, n;
/* Alloc and build up user_args. */
- for (size = 0, from = NewArgv + 1; *from; from++)
- size += strlen(*from) + 1;
+ for (size = 0, av = NewArgv + 1; *av; av++)
+ size += strlen(*av) + 1;
user_args = emalloc(size);
- for (to = user_args, from = NewArgv + 1; *from; from++) {
- n = strlcpy(to, *from, size - (to - user_args));
- if (n >= size - (to - user_args))
- errorx(1, "internal error, set_cmnd() overflow");
- to += n;
- *to++ = ' ';
+ if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
+ /*
+ * When running a command via a shell, the sudo front-end
+ * escapes potential meta chars. We unescape non-spaces
+ * for sudoers matching and logging purposes.
+ */
+ for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
+ while (*from) {
+ if (from[0] == '\\' && !isspace((unsigned char)from[1]))
+ from++;
+ *to++ = *from++;
+ }
+ *to++ = ' ';
+ }
+ *--to = '\0';
+ } else {
+ for (to = user_args, av = NewArgv + 1; *av; av++) {
+ n = strlcpy(to, *av, size - (to - user_args));
+ if (n >= size - (to - user_args))
+ errorx(1, _("internal error, set_cmnd() overflow"));
+ to += n;
+ *to++ = ' ';
+ }
+ *--to = '\0';
}
- *--to = '\0';
}
}
if (strlen(user_cmnd) >= PATH_MAX)
- errorx(1, "%s: file name too long", user_cmnd);
+ errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG));
if ((user_base = strrchr(user_cmnd, '/')) != NULL)
user_base++;
user_base = user_cmnd;
if (!update_defaults(SETDEF_CMND))
- log_error(NO_STDERR|NO_EXIT, "problem with defaults entries");
-
- if (!runas_user && !runas_group)
- set_runaspw(def_runas_default); /* may have been updated above */
+ log_error(NO_STDERR|NO_EXIT, _("problem with defaults entries"));
return rval;
}
(statbuf.st_mode & 0007777) == 0400) {
if (chmod(sudoers, sudoers_mode) == 0) {
- warningx("fixed mode on %s", sudoers);
+ warningx(_("fixed mode on %s"), sudoers);
SET(statbuf.st_mode, sudoers_mode);
if (statbuf.st_gid != sudoers_gid) {
if (chown(sudoers, (uid_t) -1, sudoers_gid) == 0) {
- warningx("set group on %s", sudoers);
+ warningx(_("set group on %s"), sudoers);
statbuf.st_gid = sudoers_gid;
} else
- warning("unable to set group on %s", sudoers);
+ warning(_("unable to set group on %s"), sudoers);
}
} else
- warning("unable to fix mode on %s", sudoers);
+ warning(_("unable to fix mode on %s"), sudoers);
}
/*
set_perms(PERM_SUDOERS);
if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0)
- log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers);
+ 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);
+ 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,
+ 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,
+ 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)
- log_error(NO_EXIT, "%s is owned by gid %u, should be %u", sudoers,
+ 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, "can't open %s", sudoers);
+ 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, "can't read %s", sudoers);
+ log_error(USE_ERRNO|NO_EXIT, _("unable to read %s"), sudoers);
fclose(fp);
fp = NULL;
}
if (login_class && strcmp(login_class, "-") != 0) {
if (user_uid != 0 &&
strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
- errorx(1, "only root can use -c %s", login_class);
+ errorx(1, _("only root can use `-c %s'"), login_class);
} else {
login_class = pw->pw_class;
if (!login_class || !*login_class)
lc = login_getclass(login_class);
if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
- log_error(errflags, "unknown login class: %s", login_class);
+ log_error(errflags, _("unknown login class: %s"), login_class);
if (!lc)
lc = login_getclass(NULL); /* needed for login_getstyle() later */
}
if (!(hp = gethostbyname(user_host))) {
#endif
log_error(MSG_ONLY|NO_EXIT,
- "unable to resolve host %s", user_host);
+ _("unable to resolve host %s"), user_host);
} else {
if (user_shost != user_host)
efree(user_shost);
* 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".
*/
-static void
-set_runaspw(char *user)
+void
+set_runaspw(const char *user)
{
if (runas_pw != NULL)
pw_delref(runas_pw);
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
} else {
- if ((runas_pw = sudo_getpwnam(user)) == NULL) {
- audit_failure(NewArgv, "unknown user: %s", user);
- log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
- }
+ if ((runas_pw = sudo_getpwnam(user)) == NULL)
+ log_error(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user);
}
}
* and store it in runas_gr.
*/
static void
-set_runasgr(char *group)
+set_runasgr(const char *group)
{
if (runas_gr != NULL)
gr_delref(runas_gr);
runas_gr = sudo_fakegrnam(group);
} else {
if ((runas_gr = sudo_getgrnam(group)) == NULL)
- log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group);
+ log_error(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group);
}
}
+/*
+ * Callback for runas_default sudoers setting.
+ */
+static int
+cb_runas_default(const char *user)
+{
+ /* Only reset runaspw if user didn't specify one. */
+ if (!runas_user && !runas_group)
+ set_runaspw(user);
+ return TRUE;
+}
+
/*
* Cleanup hook for error()/errorx()
*/
return -1;
}
- sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers policy plugin version %s\n",
+ 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",
+ 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);
+ 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);
+ 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);
+ 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();
deserialize_info(char * const settings[], char * const user_info[])
{
char * const *cur;
- const char *p;
+ const char *p, *groups = NULL;
int flags = 0;
#define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)
continue;
}
if (MATCHES(*cur, "gid=")) {
- user_gid = (gid_t) atoi(*cur + sizeof("gid=") - 1);
+ p = *cur + sizeof("gid=") - 1;
+ user_gid = (gid_t) atoi(p);
continue;
}
if (MATCHES(*cur, "groups=")) {
- /* Count number of groups */
- const char *val = *cur + sizeof("groups=") - 1;
- const char *cp;
- if (val[0] != '\0') {
- user_ngroups = 1;
- for (cp = val; *cp != '\0'; cp++) {
- if (*cp == ',')
- user_ngroups++;
- }
-
- user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
- user_ngroups = 0;
- cp = val;
- for (;;) {
- /* XXX - strtol would be better here */
- user_groups[user_ngroups++] = atoi(cp);
- cp = strchr(cp, ',');
- if (cp == NULL)
- break;
- cp++; /* skip over comma */
- }
- }
+ groups = *cur + sizeof("groups=") - 1;
continue;
}
if (MATCHES(*cur, "cwd=")) {
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;
}
efree(editor);
}
if (!editor_path) {
- audit_failure(NewArgv, "%s: command not found", editor);
- warningx("%s: command not found", editor);
+ audit_failure(NewArgv, _("%s: command not found"), editor);
+ warningx(_("%s: command not found"), editor);
}
return editor_path;
}