--- embedaddon/sudo/plugins/sudoers/sudoers.c 2012/05/29 12:26:49 1.1.1.2 +++ embedaddon/sudo/plugins/sudoers/sudoers.c 2012/10/09 09:29:52 1.1.1.3 @@ -145,6 +145,7 @@ sudoers_policy_open(unsigned int version, sudo_conv_t volatile int sources = 0; sigaction_t sa; struct sudo_nss *nss; + struct sudo_nss *nss_next; debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN) sudo_version = version; @@ -201,12 +202,15 @@ sudoers_policy_open(unsigned int version, sudo_conv_t set_perms(PERM_ROOT); /* Open and parse sudoers, set global defaults */ - tq_foreach_fwd(snl, nss) { - if (nss->open(nss) == 0 && nss->parse(nss) == 0) { - sources++; - if (nss->setdefs(nss) != 0) - log_error(NO_STDERR, _("problem with defaults entries")); - } + for (nss = snl->first; nss != NULL; nss = nss_next) { + nss_next = nss->next; + if (nss->open(nss) == 0 && nss->parse(nss) == 0) { + sources++; + if (nss->setdefs(nss) != 0) + log_error(NO_STDERR, _("problem with defaults entries")); + } else { + tq_remove(snl, nss); + } } if (sources == 0) { warningx(_("no valid sudoers sources found, quitting")); @@ -268,12 +272,20 @@ sudoers_policy_close(int exit_status, int error_code) (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); + sudo_pw_delref(sudo_user.pw); + sudo_user.pw = NULL; + sudo_pw_delref(runas_pw); + runas_pw = NULL; + if (runas_gr != NULL) { + sudo_gr_delref(runas_gr); + runas_gr = NULL; + } + if (user_group_list != NULL) { + sudo_grlist_delref(user_group_list); + user_group_list = NULL; + } + efree(user_gids); + user_gids = NULL; debug_return; } @@ -281,6 +293,7 @@ sudoers_policy_close(int exit_status, int error_code) /* * The init_session function is called before executing the command * and before uid/gid changes occur. + * Returns 1 on success, 0 on failure and -1 on error. */ static int sudoers_policy_init_session(struct passwd *pwd, char **user_env[]) @@ -293,7 +306,7 @@ sudoers_policy_init_session(struct passwd *pwd, char * if (sigsetjmp(error_jmp, 1)) { /* called via error(), errorx() or log_fatal() */ - return -1; + debug_return_bool(-1); } debug_return_bool(sudo_auth_begin_session(pwd, user_env)); @@ -363,10 +376,6 @@ sudoers_policy_main(int argc, char * const argv[], int /* Find command in path */ cmnd_status = set_cmnd(); - if (cmnd_status == -1) { - rval = -1; - goto done; - } #ifdef HAVE_SETLOCALE if (!setlocale(LC_ALL, def_sudoers_locale)) { @@ -384,7 +393,7 @@ sudoers_policy_main(int argc, char * const argv[], int validated = nss->lookup(nss, validated, pwflag); if (ISSET(validated, VALIDATE_OK)) { - /* Handle "= auth" in netsvc.conf */ + /* Handle [SUCCESS=return] */ if (nss->ret_if_found) break; } else { @@ -417,7 +426,7 @@ sudoers_policy_main(int argc, char * const argv[], int pw = sudo_getpwnam(def_timestampowner); if (pw != NULL) { timestamp_uid = pw->pw_uid; - pw_delref(pw); + sudo_pw_delref(pw); } else { log_error(0, _("timestamp owner (%s): No such user"), def_timestampowner); @@ -455,8 +464,11 @@ sudoers_policy_main(int argc, char * const argv[], int /* Require a password if sudoers says so. */ rval = check_user(validated, sudo_mode); - if (rval != true) + if (rval != true) { + if (!ISSET(validated, VALIDATE_OK)) + log_failure(validated, cmnd_status); goto done; + } /* 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 */ @@ -466,7 +478,7 @@ sudoers_policy_main(int argc, char * const argv[], int if ((pw = sudo_getpwnam(prev_user)) != NULL) { if (sudo_user.pw != NULL) - pw_delref(sudo_user.pw); + sudo_pw_delref(sudo_user.pw); sudo_user.pw = pw; } } @@ -474,30 +486,7 @@ sudoers_policy_main(int argc, char * const argv[], int /* 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")); - 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")); - } + log_failure(validated, cmnd_status); goto bad; } @@ -664,7 +653,7 @@ sudoers_policy_main(int argc, char * const argv[], int gid_t egid; size_t glsize; char *cp, *gid_list; - struct group_list *grlist = get_group_list(runas_pw); + struct group_list *grlist = sudo_get_grlist(runas_pw); /* We reserve an extra spot in the list for the effective gid. */ glsize = sizeof("runas_groups=") - 1 + @@ -678,19 +667,19 @@ sudoers_policy_main(int argc, char * const argv[], int (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")); + errorx(1, _("internal error, %s overflow"), "runas_groups"); 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")); + errorx(1, _("internal error, %s overflow"), "runas_groups"); cp += len; } } command_info[info_len++] = gid_list; - grlist_delref(grlist); + sudo_grlist_delref(grlist); } if (def_closefrom >= 0) easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom); @@ -712,6 +701,12 @@ sudoers_policy_main(int argc, char * const argv[], int if (user_type != NULL) command_info[info_len++] = fmt_string("selinux_type", user_type); #endif /* HAVE_SELINUX */ +#ifdef HAVE_PRIV_SET + if (runas_privs != NULL) + command_info[info_len++] = fmt_string("runas_privs", runas_privs); + if (runas_limitprivs != NULL) + command_info[info_len++] = fmt_string("runas_limitprivs", runas_limitprivs); +#endif /* HAVE_SELINUX */ /* Must audit before uid change. */ audit_success(NewArgv); @@ -800,7 +795,7 @@ sudoers_policy_list(int argc, char * const argv[], int } rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL); if (list_user) { - pw_delref(list_pw); + sudo_pw_delref(list_pw); list_pw = NULL; } @@ -865,7 +860,7 @@ init_vars(char * const envp[]) * Get group list. */ 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. */ sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; @@ -938,7 +933,7 @@ set_cmnd(void) 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")); + errorx(1, _("internal error, %s overflow"), "set_cmnd()"); to += n; *to++ = ' '; } @@ -975,13 +970,23 @@ open_sudoers(const char *sudoers, bool doedit, bool *k switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) { case SUDO_PATH_SECURE: + /* + * If we are expecting sudoers to be group readable but + * it is not, we must open the file as root, not uid 1. + */ + if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) { + if ((sb.st_mode & S_IRGRP) == 0) { + 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) { log_error(USE_ERRNO, _("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 (sb.st_size != 0 && fgetc(fp) == EOF) { log_error(USE_ERRNO, _("unable to read %s"), sudoers); @@ -1067,8 +1072,13 @@ set_loginclass(struct passwd *pw) } #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. + * Use AI_FQDN if available since "canonical" is not always the same as fqdn. */ void set_fqdn(void) @@ -1079,7 +1089,7 @@ set_fqdn(void) zero_bytes(&hint, sizeof(hint)); hint.ai_family = PF_UNSPEC; - hint.ai_flags = AI_CANONNAME; + hint.ai_flags = AI_FQDN; if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { log_error(MSG_ONLY, _("unable to resolve host %s"), user_host); } else { @@ -1088,11 +1098,11 @@ set_fqdn(void) efree(user_host); user_host = estrdup(res0->ai_canonname); 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; } @@ -1106,7 +1116,7 @@ set_runaspw(const char *user) debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN) if (runas_pw != NULL) - pw_delref(runas_pw); + sudo_pw_delref(runas_pw); if (*user == '#') { if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); @@ -1127,7 +1137,7 @@ set_runasgr(const char *group) debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN) if (runas_gr != NULL) - gr_delref(runas_gr); + sudo_gr_delref(runas_gr); if (*group == '#') { if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) runas_gr = sudo_fakegrnam(group); @@ -1254,10 +1264,12 @@ deserialize_info(char * const args[], char * const set } if (MATCHES(*cur, "runas_user=")) { runas_user = *cur + sizeof("runas_user=") - 1; + sudo_user.flags |= RUNAS_USER_SPECIFIED; continue; } if (MATCHES(*cur, "runas_group=")) { runas_group = *cur + sizeof("runas_group=") - 1; + sudo_user.flags |= RUNAS_GROUP_SPECIFIED; continue; } if (MATCHES(*cur, "prompt=")) { @@ -1317,6 +1329,16 @@ deserialize_info(char * const args[], char * const set def_use_loginclass = true; continue; } +#ifdef HAVE_PRIV_SET + if (MATCHES(*cur, "runas_privs=")) { + def_privs = *cur + sizeof("runas_privs=") - 1; + continue; + } + if (MATCHES(*cur, "runas_limitprivs=")) { + def_limitprivs = *cur + sizeof("runas_limitprivs=") - 1; + continue; + } +#endif /* HAVE_PRIV_SET */ #ifdef HAVE_SELINUX if (MATCHES(*cur, "selinux_role=")) { user_role = *cur + sizeof("selinux_role=") - 1; @@ -1420,8 +1442,8 @@ deserialize_info(char * const args[], char * const set break; cp++; /* skip over comma */ } - set_group_list(user_name, gids, ngids); - efree(gids); + user_gids = gids; + user_ngids = ngids; } /* Setup debugging if indicated. */ @@ -1586,7 +1608,7 @@ sudoers_policy_register_hooks(int version, int (*regis register_hook(&hook); } -struct policy_plugin sudoers_policy = { +__dso_public struct policy_plugin sudoers_policy = { SUDO_POLICY_PLUGIN, SUDO_API_VERSION, sudoers_policy_open,