--- embedaddon/sudo/plugins/sudoers/match.c 2012/02/21 16:23:02 1.1.1.1 +++ embedaddon/sudo/plugins/sudoers/match.c 2013/07/22 10:46:12 1.1.1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2011 + * Copyright (c) 1996, 1998-2005, 2007-2013 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -24,7 +24,6 @@ #include #include -#include #include #include #ifdef STDC_HEADERS @@ -41,22 +40,31 @@ #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#endif #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_FNMATCH # include +#else +# include "compat/fnmatch.h" #endif /* HAVE_FNMATCH */ -#ifdef HAVE_EXTENDED_GLOB -# include -#endif /* HAVE_EXTENDED_GLOB */ +#ifndef SUDOERS_NAME_MATCH +# ifdef HAVE_GLOB +# include +# else +# include "compat/glob.h" +# endif /* HAVE_GLOB */ +#endif /* SUDOERS_NAME_MATCH */ #ifdef HAVE_NETGROUP_H # include +#else +# include #endif /* HAVE_NETGROUP_H */ -#include -#include -#include -#include #ifdef HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) @@ -73,27 +81,27 @@ # include # endif #endif +#include +#include +#include +#include #include "sudoers.h" #include "parse.h" +#include "sha2.h" #include -#ifndef HAVE_FNMATCH -# include "compat/fnmatch.h" -#endif /* HAVE_FNMATCH */ -#ifndef HAVE_EXTENDED_GLOB -# include "compat/glob.h" -#endif /* HAVE_EXTENDED_GLOB */ - static struct member_list empty; -static int command_matches_dir(char *, size_t); -static int command_matches_glob(char *, char *); -static int command_matches_fnmatch(char *, char *); -static int command_matches_normal(char *, char *); +static bool command_matches_dir(char *, size_t); +#ifndef SUDOERS_NAME_MATCH +static bool command_matches_glob(char *, char *); +#endif +static bool command_matches_fnmatch(char *, char *); +static bool command_matches_normal(char *, char *, struct sudo_digest *); /* - * Returns TRUE if string 's' contains meta characters. + * Returns true if string 's' contains meta characters. */ #define has_meta(s) (strpbrk(s, "\\?*[]") != NULL) @@ -101,12 +109,13 @@ static int command_matches_normal(char *, char *); * Check for user described by pw in a list of members. * Returns ALLOW, DENY or UNSPEC. */ -static int -_userlist_matches(struct passwd *pw, struct member_list *list) +int +userlist_matches(struct passwd *pw, struct member_list *list) { struct member *m; struct alias *a; int rval, matched = UNSPEC; + debug_decl(userlist_matches, SUDO_DEBUG_MATCH) tq_foreach_rev(list, m) { switch (m->type) { @@ -122,10 +131,11 @@ _userlist_matches(struct passwd *pw, struct member_lis matched = !m->negated; break; case ALIAS: - if ((a = alias_find(m->name, USERALIAS)) != NULL) { - rval = _userlist_matches(pw, &a->members); + if ((a = alias_get(m->name, USERALIAS)) != NULL) { + rval = userlist_matches(pw, &a->members); if (rval != UNSPEC) matched = m->negated ? !rval : rval; + alias_put(a); break; } /* FALLTHROUGH */ @@ -137,34 +147,30 @@ _userlist_matches(struct passwd *pw, struct member_lis if (matched != UNSPEC) break; } - return matched; + debug_return_bool(matched); } -int -userlist_matches(struct passwd *pw, struct member_list *list) -{ - alias_seqno++; - return _userlist_matches(pw, list); -} - /* * Check for user described by pw in a list of members. * If both lists are empty compare against def_runas_default. * Returns ALLOW, DENY or UNSPEC. */ -static int -_runaslist_matches(struct member_list *user_list, struct member_list *group_list) +int +runaslist_matches(struct member_list *user_list, + struct member_list *group_list, struct member **matching_user, + struct member **matching_group) { struct member *m; struct alias *a; int rval; int user_matched = UNSPEC; int group_matched = UNSPEC; + debug_decl(runaslist_matches, SUDO_DEBUG_MATCH) if (runas_pw != NULL) { /* If no runas user or runas group listed in sudoers, use default. */ if (tq_empty(user_list) && tq_empty(group_list)) - return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw); + debug_return_int(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw)); tq_foreach_rev(user_list, m) { switch (m->type) { @@ -180,10 +186,12 @@ _runaslist_matches(struct member_list *user_list, stru user_matched = !m->negated; break; case ALIAS: - if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { - rval = _runaslist_matches(&a->members, &empty); + if ((a = alias_get(m->name, RUNASALIAS)) != NULL) { + rval = runaslist_matches(&a->members, &empty, + matching_user, NULL); if (rval != UNSPEC) user_matched = m->negated ? !rval : rval; + alias_put(a); break; } /* FALLTHROUGH */ @@ -191,9 +199,17 @@ _runaslist_matches(struct member_list *user_list, stru if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) user_matched = !m->negated; break; + case MYSELF: + if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) || + strcmp(user_name, runas_pw->pw_name) == 0) + user_matched = !m->negated; + break; } - if (user_matched != UNSPEC) + if (user_matched != UNSPEC) { + if (matching_user != NULL && m->type != ALIAS) + *matching_user = m; break; + } } } @@ -208,10 +224,12 @@ _runaslist_matches(struct member_list *user_list, stru group_matched = !m->negated; break; case ALIAS: - if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { - rval = _runaslist_matches(&empty, &a->members); + if ((a = alias_get(m->name, RUNASALIAS)) != NULL) { + rval = runaslist_matches(&empty, &a->members, + NULL, matching_group); if (rval != UNSPEC) group_matched = m->negated ? !rval : rval; + alias_put(a); break; } /* FALLTHROUGH */ @@ -220,8 +238,11 @@ _runaslist_matches(struct member_list *user_list, stru group_matched = !m->negated; break; } - if (group_matched != UNSPEC) + if (group_matched != UNSPEC) { + if (matching_group != NULL && m->type != ALIAS) + *matching_group = m; break; + } } if (group_matched == UNSPEC) { if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid) @@ -230,30 +251,23 @@ _runaslist_matches(struct member_list *user_list, stru } if (user_matched == DENY || group_matched == DENY) - return DENY; + debug_return_int(DENY); if (user_matched == group_matched || runas_gr == NULL) - return user_matched; - return UNSPEC; + debug_return_int(user_matched); + debug_return_int(UNSPEC); } -int -runaslist_matches(struct member_list *user_list, struct member_list *group_list) -{ - alias_seqno++; - return _runaslist_matches(user_list ? user_list : &empty, - group_list ? group_list : &empty); -} - /* * Check for host and shost in a list of members. * Returns ALLOW, DENY or UNSPEC. */ -static int -_hostlist_matches(struct member_list *list) +int +hostlist_matches(struct member_list *list) { struct member *m; struct alias *a; int rval, matched = UNSPEC; + debug_decl(hostlist_matches, SUDO_DEBUG_MATCH) tq_foreach_rev(list, m) { switch (m->type) { @@ -269,10 +283,11 @@ _hostlist_matches(struct member_list *list) matched = !m->negated; break; case ALIAS: - if ((a = alias_find(m->name, HOSTALIAS)) != NULL) { - rval = _hostlist_matches(&a->members); + if ((a = alias_get(m->name, HOSTALIAS)) != NULL) { + rval = hostlist_matches(&a->members); if (rval != UNSPEC) matched = m->negated ? !rval : rval; + alias_put(a); break; } /* FALLTHROUGH */ @@ -284,41 +299,28 @@ _hostlist_matches(struct member_list *list) if (matched != UNSPEC) break; } - return matched; + debug_return_bool(matched); } -int -hostlist_matches(struct member_list *list) -{ - alias_seqno++; - return _hostlist_matches(list); -} - /* * Check for cmnd and args in a list of members. * Returns ALLOW, DENY or UNSPEC. */ -static int -_cmndlist_matches(struct member_list *list) +int +cmndlist_matches(struct member_list *list) { struct member *m; int matched = UNSPEC; + debug_decl(cmndlist_matches, SUDO_DEBUG_MATCH) tq_foreach_rev(list, m) { matched = cmnd_matches(m); if (matched != UNSPEC) break; } - return matched; + debug_return_bool(matched); } -int -cmndlist_matches(struct member_list *list) -{ - alias_seqno++; - return _cmndlist_matches(list); -} - /* * Check cmnd and args. * Returns ALLOW, DENY or UNSPEC. @@ -329,34 +331,34 @@ cmnd_matches(struct member *m) struct alias *a; struct sudo_command *c; int rval, matched = UNSPEC; + debug_decl(cmnd_matches, SUDO_DEBUG_MATCH) switch (m->type) { case ALL: matched = !m->negated; break; case ALIAS: - alias_seqno++; - if ((a = alias_find(m->name, CMNDALIAS)) != NULL) { - rval = _cmndlist_matches(&a->members); + if ((a = alias_get(m->name, CMNDALIAS)) != NULL) { + rval = cmndlist_matches(&a->members); if (rval != UNSPEC) matched = m->negated ? !rval : rval; + alias_put(a); } break; case COMMAND: c = (struct sudo_command *)m->name; - if (command_matches(c->cmnd, c->args)) + if (command_matches(c->cmnd, c->args, c->digest)) matched = !m->negated; break; } - return matched; + debug_return_bool(matched); } -static int -command_args_match(sudoers_cmnd, sudoers_args) - char *sudoers_cmnd; - char *sudoers_args; +static bool +command_args_match(char *sudoers_cmnd, char *sudoers_args) { int flags = 0; + debug_decl(command_args_match, SUDO_DEBUG_MATCH) /* * If no args specified in sudoers, any user args are allowed. @@ -364,7 +366,7 @@ command_args_match(sudoers_cmnd, sudoers_args) */ if (!sudoers_args || (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))) - return TRUE; + debug_return_bool(true); /* * If args are specified in sudoers, they must match the user args. * If running as sudoedit, all args are assumed to be paths. @@ -374,18 +376,20 @@ command_args_match(sudoers_cmnd, sudoers_args) if (strcmp(sudoers_cmnd, "sudoedit") == 0) flags = FNM_PATHNAME; if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0) - return TRUE; + debug_return_bool(true); } - return FALSE; + debug_return_bool(false); } /* - * If path doesn't end in /, return TRUE iff cmnd & path name the same inode; - * otherwise, return TRUE if user_cmnd names one of the inodes in path. + * If path doesn't end in /, return true iff cmnd & path name the same inode; + * otherwise, return true if user_cmnd names one of the inodes in path. */ -int -command_matches(char *sudoers_cmnd, char *sudoers_args) +bool +command_matches(char *sudoers_cmnd, char *sudoers_args, struct sudo_digest *digest) { + debug_decl(command_matches, SUDO_DEBUG_MATCH) + /* Check for pseudo-commands */ if (sudoers_cmnd[0] != '/') { /* @@ -396,13 +400,13 @@ command_matches(char *sudoers_cmnd, char *sudoers_args */ if (strcmp(sudoers_cmnd, "sudoedit") != 0 || strcmp(user_cmnd, "sudoedit") != 0) - return FALSE; + debug_return_bool(false); if (command_args_match(sudoers_cmnd, sudoers_args)) { efree(safe_cmnd); safe_cmnd = estrdup(sudoers_cmnd); - return TRUE; + debug_return_bool(true); } else - return FALSE; + debug_return_bool(false); } if (has_meta(sudoers_cmnd)) { @@ -410,16 +414,22 @@ command_matches(char *sudoers_cmnd, char *sudoers_args * If sudoers_cmnd has meta characters in it, we need to * use glob(3) and/or fnmatch(3) to do the matching. */ +#ifdef SUDOERS_NAME_MATCH + debug_return_bool(command_matches_fnmatch(sudoers_cmnd, sudoers_args)); +#else if (def_fast_glob) - return command_matches_fnmatch(sudoers_cmnd, sudoers_args); - return command_matches_glob(sudoers_cmnd, sudoers_args); + debug_return_bool(command_matches_fnmatch(sudoers_cmnd, sudoers_args)); + debug_return_bool(command_matches_glob(sudoers_cmnd, sudoers_args)); +#endif } - return command_matches_normal(sudoers_cmnd, sudoers_args); + debug_return_bool(command_matches_normal(sudoers_cmnd, sudoers_args, digest)); } -static int +static bool command_matches_fnmatch(char *sudoers_cmnd, char *sudoers_args) { + debug_decl(command_matches_fnmatch, SUDO_DEBUG_MATCH) + /* * Return true if fnmatch(3) succeeds AND * a) there are no args in sudoers OR @@ -428,23 +438,25 @@ command_matches_fnmatch(char *sudoers_cmnd, char *sudo * else return false. */ if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) - return FALSE; + debug_return_bool(false); if (command_args_match(sudoers_cmnd, sudoers_args)) { if (safe_cmnd) free(safe_cmnd); safe_cmnd = estrdup(user_cmnd); - return TRUE; - } else - return FALSE; + debug_return_bool(true); + } + debug_return_bool(false); } -static int +#ifndef SUDOERS_NAME_MATCH +static bool command_matches_glob(char *sudoers_cmnd, char *sudoers_args) { struct stat sudoers_stat; size_t dlen; char **ap, *base, *cp; glob_t gl; + debug_decl(command_matches_glob, SUDO_DEBUG_MATCH) /* * First check to see if we can avoid the call to glob(3). @@ -456,7 +468,7 @@ command_matches_glob(char *sudoers_cmnd, char *sudoers if ((base = strrchr(sudoers_cmnd, '/')) != NULL) { base++; if (!has_meta(base) && strcmp(user_base, base) != 0) - return FALSE; + debug_return_bool(false); } } /* @@ -466,10 +478,9 @@ command_matches_glob(char *sudoers_cmnd, char *sudoers * c) there are args in sudoers and on command line and they match * else return false. */ -#define GLOB_FLAGS (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE) - if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) { + if (glob(sudoers_cmnd, GLOB_NOSORT, NULL, &gl) != 0 || gl.gl_pathc == 0) { globfree(&gl); - return FALSE; + debug_return_bool(false); } /* For each glob match, compare basename, st_dev and st_ino. */ for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) { @@ -477,7 +488,7 @@ command_matches_glob(char *sudoers_cmnd, char *sudoers dlen = strlen(cp); if (cp[dlen - 1] == '/') { if (command_matches_dir(cp, dlen)) - return TRUE; + debug_return_bool(true); continue; } @@ -499,27 +510,153 @@ command_matches_glob(char *sudoers_cmnd, char *sudoers } globfree(&gl); if (cp == NULL) - return FALSE; + debug_return_bool(false); if (command_args_match(sudoers_cmnd, sudoers_args)) { efree(safe_cmnd); safe_cmnd = estrdup(user_cmnd); - return TRUE; + debug_return_bool(true); } - return FALSE; + debug_return_bool(false); } +#endif /* SUDOERS_NAME_MATCH */ -static int -command_matches_normal(char *sudoers_cmnd, char *sudoers_args) +#ifdef SUDOERS_NAME_MATCH +static bool +command_matches_normal(char *sudoers_cmnd, char *sudoers_args, struct sudo_digest *digest) { + size_t dlen; + debug_decl(command_matches_normal, SUDO_DEBUG_MATCH) + + dlen = strlen(sudoers_cmnd); + + /* If it ends in '/' it is a directory spec. */ + if (sudoers_cmnd[dlen - 1] == '/') + debug_return_bool(command_matches_dir(sudoers_cmnd, dlen)); + + if (strcmp(user_cmnd, sudoers_cmnd) == 0) { + if (command_args_match(sudoers_cmnd, sudoers_args)) { + efree(safe_cmnd); + safe_cmnd = estrdup(sudoers_cmnd); + debug_return_bool(true); + } + } + debug_return_bool(false); +} +#else /* !SUDOERS_NAME_MATCH */ + +static struct digest_function { + const char *digest_name; + const unsigned int digest_len; + void (*init)(SHA2_CTX *); + void (*update)(SHA2_CTX *, const unsigned char *, size_t); + void (*final)(unsigned char *, SHA2_CTX *); +} digest_functions[] = { + { + "SHA224", + SHA224_DIGEST_LENGTH, + SHA224Init, + SHA224Update, + SHA224Final + }, { + "SHA256", + SHA256_DIGEST_LENGTH, + SHA256Init, + SHA256Update, + SHA256Final + }, { + "SHA384", + SHA384_DIGEST_LENGTH, + SHA384Init, + SHA384Update, + SHA384Final + }, { + "SHA512", + SHA512_DIGEST_LENGTH, + SHA512Init, + SHA512Update, + SHA512Final + }, { + NULL + } +}; + +static bool +digest_matches(char *file, struct sudo_digest *sd) +{ + unsigned char file_digest[SHA512_DIGEST_LENGTH]; + unsigned char sudoers_digest[SHA512_DIGEST_LENGTH]; + unsigned char buf[32 * 1024]; + struct digest_function *func = NULL; + size_t nread; + SHA2_CTX ctx; + FILE *fp; + unsigned int i; + debug_decl(digest_matches, SUDO_DEBUG_MATCH) + + for (i = 0; digest_functions[i].digest_name != NULL; i++) { + if (sd->digest_type == i) { + func = &digest_functions[i]; + break; + } + } + if (func == NULL) { + warningx(_("unsupported digest type %d for %s"), sd->digest_type, file); + debug_return_bool(false); + } + if (strlen(sd->digest_str) == func->digest_len * 2) { + /* Convert the command digest from ascii hex to binary. */ + for (i = 0; i < func->digest_len; i++) { + if (!isxdigit((unsigned char)sd->digest_str[i + i]) || + !isxdigit((unsigned char)sd->digest_str[i + i + 1])) { + goto bad_format; + } + sudoers_digest[i] = hexchar(&sd->digest_str[i + i]); + } + } else { + size_t len = base64_decode(sd->digest_str, sudoers_digest, + sizeof(sudoers_digest)); + if (len != func->digest_len) + goto bad_format; + } + + if ((fp = fopen(file, "r")) == NULL) { + sudo_debug_printf(SUDO_DEBUG_INFO, "unable to open %s: %s", + file, strerror(errno)); + debug_return_bool(false); + } + + func->init(&ctx); + while ((nread = fread(buf, 1, sizeof(buf), fp)) != 0) { + func->update(&ctx, buf, nread); + } + if (ferror(fp)) { + warningx(_("%s: read error"), file); + fclose(fp); + debug_return_bool(false); + } + fclose(fp); + func->final(file_digest, &ctx); + + debug_return_bool(memcmp(file_digest, sudoers_digest, func->digest_len) == 0); +bad_format: + warningx(_("digest for %s (%s) is not in %s form"), file, + sd->digest_str, func->digest_name); + debug_return_bool(false); +} + +static bool +command_matches_normal(char *sudoers_cmnd, char *sudoers_args, struct sudo_digest *digest) +{ struct stat sudoers_stat; char *base; size_t dlen; + debug_decl(command_matches_normal, SUDO_DEBUG_MATCH) /* If it ends in '/' it is a directory spec. */ dlen = strlen(sudoers_cmnd); if (sudoers_cmnd[dlen - 1] == '/') - return command_matches_dir(sudoers_cmnd, dlen); + debug_return_bool(command_matches_dir(sudoers_cmnd, dlen)); /* Only proceed if user_base and basename(sudoers_cmnd) match */ if ((base = strrchr(sudoers_cmnd, '/')) == NULL) @@ -528,47 +665,65 @@ command_matches_normal(char *sudoers_cmnd, char *sudoe base++; if (strcmp(user_base, base) != 0 || stat(sudoers_cmnd, &sudoers_stat) == -1) - return FALSE; + debug_return_bool(false); /* * Return true if inode/device matches AND * a) there are no args in sudoers OR * b) there are no args on command line and none req by sudoers OR * c) there are args in sudoers and on command line and they match + * d) there is a digest and it matches */ if (user_stat != NULL && (user_stat->st_dev != sudoers_stat.st_dev || user_stat->st_ino != sudoers_stat.st_ino)) - return FALSE; - if (command_args_match(sudoers_cmnd, sudoers_args)) { - efree(safe_cmnd); - safe_cmnd = estrdup(sudoers_cmnd); - return TRUE; + debug_return_bool(false); + if (!command_args_match(sudoers_cmnd, sudoers_args)) + debug_return_bool(false); + if (digest != NULL && !digest_matches(sudoers_cmnd, digest)) { + /* XXX - log functions not available but we should log very loudly */ + debug_return_bool(false); } - return FALSE; + efree(safe_cmnd); + safe_cmnd = estrdup(sudoers_cmnd); + debug_return_bool(true); } +#endif /* SUDOERS_NAME_MATCH */ +#ifdef SUDOERS_NAME_MATCH /* - * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE. + * Return true if user_cmnd begins with sudoers_dir, else false. + * Note that sudoers_dir include the trailing '/' */ -static int +static bool command_matches_dir(char *sudoers_dir, size_t dlen) { + debug_decl(command_matches_dir, SUDO_DEBUG_MATCH) + debug_return_bool(strncmp(user_cmnd, sudoers_dir, dlen) == 0); +} +#else /* !SUDOERS_NAME_MATCH */ +/* + * Return true if user_cmnd names one of the inodes in dir, else false. + */ +static bool +command_matches_dir(char *sudoers_dir, size_t dlen) +{ struct stat sudoers_stat; struct dirent *dent; char buf[PATH_MAX]; DIR *dirp; + debug_decl(command_matches_dir, SUDO_DEBUG_MATCH) /* * Grot through directory entries, looking for user_base. */ dirp = opendir(sudoers_dir); if (dirp == NULL) - return FALSE; + debug_return_bool(false); if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) { closedir(dirp); - return FALSE; + debug_return_bool(false); } while ((dent = readdir(dirp)) != NULL) { /* ignore paths > PATH_MAX (XXX - log) */ @@ -590,67 +745,75 @@ command_matches_dir(char *sudoers_dir, size_t dlen) } closedir(dirp); - return dent != NULL; + debug_return_bool(dent != NULL); } +#endif /* SUDOERS_NAME_MATCH */ /* - * Returns TRUE if the hostname matches the pattern, else FALSE + * Returns true if the hostname matches the pattern, else false */ -int +bool hostname_matches(char *shost, char *lhost, char *pattern) { + debug_decl(hostname_matches, SUDO_DEBUG_MATCH) + if (has_meta(pattern)) { if (strchr(pattern, '.')) - return !fnmatch(pattern, lhost, FNM_CASEFOLD); + debug_return_bool(!fnmatch(pattern, lhost, FNM_CASEFOLD)); else - return !fnmatch(pattern, shost, FNM_CASEFOLD); + debug_return_bool(!fnmatch(pattern, shost, FNM_CASEFOLD)); } else { if (strchr(pattern, '.')) - return !strcasecmp(lhost, pattern); + debug_return_bool(!strcasecmp(lhost, pattern)); else - return !strcasecmp(shost, pattern); + debug_return_bool(!strcasecmp(shost, pattern)); } } /* - * Returns TRUE if the user/uid from sudoers matches the specified user/uid, - * else returns FALSE. + * Returns true if the user/uid from sudoers matches the specified user/uid, + * else returns false. */ -int +bool userpw_matches(char *sudoers_user, char *user, struct passwd *pw) { + debug_decl(userpw_matches, SUDO_DEBUG_MATCH) + if (pw != NULL && *sudoers_user == '#') { uid_t uid = (uid_t) atoi(sudoers_user + 1); if (uid == pw->pw_uid) - return TRUE; + debug_return_bool(true); } - return strcmp(sudoers_user, user) == 0; + debug_return_bool(strcmp(sudoers_user, user) == 0); } /* - * Returns TRUE if the group/gid from sudoers matches the specified group/gid, - * else returns FALSE. + * Returns true if the group/gid from sudoers matches the specified group/gid, + * else returns false. */ -int +bool group_matches(char *sudoers_group, struct group *gr) { + debug_decl(group_matches, SUDO_DEBUG_MATCH) + if (*sudoers_group == '#') { gid_t gid = (gid_t) atoi(sudoers_group + 1); if (gid == gr->gr_gid) - return TRUE; + debug_return_bool(true); } - return strcmp(gr->gr_name, sudoers_group) == 0; + debug_return_bool(strcmp(gr->gr_name, sudoers_group) == 0); } /* - * Returns TRUE if the given user belongs to the named group, - * else returns FALSE. + * Returns true if the given user belongs to the named group, + * else returns false. */ -int +bool usergr_matches(char *group, char *user, struct passwd *pw) { - int matched = FALSE; + int matched = false; struct passwd *pw0 = NULL; + debug_decl(usergr_matches, SUDO_DEBUG_MATCH) /* make sure we have a valid usergroup, sudo style */ if (*group++ != '%') @@ -669,60 +832,84 @@ usergr_matches(char *group, char *user, struct passwd } if (user_in_group(pw, group)) { - matched = TRUE; + matched = true; goto done; } /* not a Unix group, could be an external group */ if (def_group_plugin && group_plugin_query(user, group, pw)) { - matched = TRUE; + matched = true; goto done; } done: if (pw0 != NULL) - pw_delref(pw0); + sudo_pw_delref(pw0); - return matched; + debug_return_bool(matched); } +#ifdef HAVE_INNETGR /* - * Returns TRUE if "host" and "user" belong to the netgroup "netgr", - * else return FALSE. Either of "host", "shost" or "user" may be NULL + * Get NIS-style domain name and return a malloc()ed copy or NULL if none. + */ +static char * +sudo_getdomainname(void) +{ + char *domain = NULL; +#ifdef HAVE_GETDOMAINNAME + char *buf, *cp; + + buf = emalloc(HOST_NAME_MAX + 1); + if (getdomainname(buf, HOST_NAME_MAX + 1) == 0 && *buf != '\0') { + domain = buf; + for (cp = buf; *cp != '\0'; cp++) { + /* Check for illegal characters, Linux may use "(none)". */ + if (*cp == '(' || *cp == ')' || *cp == ',' || *cp == ' ') { + domain = NULL; + break; + } + } + } + if (domain == NULL) + efree(buf); +#endif /* HAVE_GETDOMAINNAME */ + return domain; +} +#endif /* HAVE_INNETGR */ + +/* + * Returns true if "host" and "user" belong to the netgroup "netgr", + * else return false. Either of "host", "shost" or "user" may be NULL * in which case that argument is not checked... * * XXX - swap order of host & shost */ -int +bool netgr_matches(char *netgr, char *lhost, char *shost, char *user) { +#ifdef HAVE_INNETGR static char *domain; -#ifdef HAVE_GETDOMAINNAME static int initialized; #endif + debug_decl(netgr_matches, SUDO_DEBUG_MATCH) +#ifdef HAVE_INNETGR /* make sure we have a valid netgroup, sudo style */ if (*netgr++ != '+') - return FALSE; + debug_return_bool(false); -#ifdef HAVE_GETDOMAINNAME /* get the domain name (if any) */ if (!initialized) { - domain = (char *) emalloc(MAXHOSTNAMELEN + 1); - if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') { - efree(domain); - domain = NULL; - } + domain = sudo_getdomainname(); initialized = 1; } -#endif /* HAVE_GETDOMAINNAME */ -#ifdef HAVE_INNETGR if (innetgr(netgr, lhost, user, domain)) - return TRUE; + debug_return_bool(true); else if (lhost != shost && innetgr(netgr, shost, user, domain)) - return TRUE; + debug_return_bool(true); #endif /* HAVE_INNETGR */ - return FALSE; + debug_return_bool(false); }