/*
- * Copyright (c) 1996, 1998-2005, 2007-2011
+ * Copyright (c) 1996, 1998-2005, 2007-2013
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
#include <config.h>
#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef STDC_HEADERS
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_FNMATCH
# include <fnmatch.h>
+#else
+# include "compat/fnmatch.h"
#endif /* HAVE_FNMATCH */
-#ifdef HAVE_EXTENDED_GLOB
-# include <glob.h>
-#endif /* HAVE_EXTENDED_GLOB */
+#ifndef SUDOERS_NAME_MATCH
+# ifdef HAVE_GLOB
+# include <glob.h>
+# else
+# include "compat/glob.h"
+# endif /* HAVE_GLOB */
+#endif /* SUDOERS_NAME_MATCH */
#ifdef HAVE_NETGROUP_H
# include <netgroup.h>
+#else
+# include <netdb.h>
#endif /* HAVE_NETGROUP_H */
-#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
# include <ndir.h>
# endif
#endif
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
#include "sudoers.h"
-#include "interfaces.h"
#include "parse.h"
+#include "sha2.h"
#include <gram.h>
-#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)
* 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) {
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 */
if (matched != UNSPEC)
break;
}
- return matched;
-}
-
-int
-userlist_matches(struct passwd *pw, struct member_list *list)
-{
- alias_seqno++;
- return _userlist_matches(pw, list);
+ debug_return_bool(matched);
}
/*
* 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) {
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 */
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;
+ }
}
}
group_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(&empty, &a->members,
+ NULL, matching_group);
if (rval != UNSPEC)
group_matched = m->negated ? !rval : rval;
+ alias_put(a);
break;
}
/* FALLTHROUGH */
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)
}
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;
-}
-
-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);
+ debug_return_int(user_matched);
+ debug_return_int(UNSPEC);
}
/*
* 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) {
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 */
if (matched != UNSPEC)
break;
}
- return matched;
-}
-
-int
-hostlist_matches(struct member_list *list)
-{
- alias_seqno++;
- return _hostlist_matches(list);
+ debug_return_bool(matched);
}
/*
* 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;
-}
-
-int
-cmndlist_matches(struct member_list *list)
-{
- alias_seqno++;
- return _cmndlist_matches(list);
+ debug_return_bool(matched);
}
/*
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.
*/
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.
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] != '/') {
/*
*/
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)) {
* 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
* 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).
if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
base++;
if (!has_meta(base) && strcmp(user_base, base) != 0)
- return FALSE;
+ debug_return_bool(false);
}
}
/*
* 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++) {
dlen = strlen(cp);
if (cp[dlen - 1] == '/') {
if (command_matches_dir(cp, dlen))
- return TRUE;
+ debug_return_bool(true);
continue;
}
}
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);
+ }
+ debug_return_bool(false);
+}
+#endif /* SUDOERS_NAME_MATCH */
+
+#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);
+ }
}
- return FALSE;
+ 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 int
-command_matches_normal(char *sudoers_cmnd, char *sudoers_args)
+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)
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 begins with sudoers_dir, else false.
+ * Note that sudoers_dir include the trailing '/'
+ */
+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.
+ * Return true if user_cmnd names one of the inodes in dir, else false.
*/
-static int
+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) */
}
closedir(dirp);
- return dent != NULL;
-}
-
-static int
-addr_matches_if(char *n)
-{
- union sudo_in_addr_un addr;
- struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
- int j;
-#endif
- int family;
-
-#ifdef HAVE_IN6_ADDR
- if (inet_pton(AF_INET6, n, &addr.ip6) > 0) {
- family = AF_INET6;
- } else
-#endif
- {
- family = AF_INET;
- addr.ip4.s_addr = inet_addr(n);
- }
-
- for (ifp = interfaces; ifp != NULL; ifp = ifp->next) {
- if (ifp->family != family)
- continue;
- switch(family) {
- case AF_INET:
- if (ifp->addr.ip4.s_addr == addr.ip4.s_addr ||
- (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr)
- == addr.ip4.s_addr)
- return TRUE;
- break;
-#ifdef HAVE_IN6_ADDR
- case AF_INET6:
- if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr,
- sizeof(addr.ip6.s6_addr)) == 0)
- return TRUE;
- for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
- if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
- break;
- }
- if (j == sizeof(addr.ip6.s6_addr))
- return TRUE;
-#endif
- }
- }
-
- return FALSE;
-}
-
-static int
-addr_matches_if_netmask(char *n, char *m)
-{
- int i;
- union sudo_in_addr_un addr, mask;
- struct interface *ifp;
-#ifdef HAVE_IN6_ADDR
- int j;
-#endif
- int family;
-
-#ifdef HAVE_IN6_ADDR
- if (inet_pton(AF_INET6, n, &addr.ip6) > 0)
- family = AF_INET6;
- else
-#endif
- {
- family = AF_INET;
- addr.ip4.s_addr = inet_addr(n);
- }
-
- if (family == AF_INET) {
- if (strchr(m, '.'))
- mask.ip4.s_addr = inet_addr(m);
- else {
- i = 32 - atoi(m);
- mask.ip4.s_addr = 0xffffffff;
- mask.ip4.s_addr >>= i;
- mask.ip4.s_addr <<= i;
- mask.ip4.s_addr = htonl(mask.ip4.s_addr);
- }
- }
-#ifdef HAVE_IN6_ADDR
- else {
- if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) {
- j = atoi(m);
- for (i = 0; i < 16; i++) {
- if (j < i * 8)
- mask.ip6.s6_addr[i] = 0;
- else if (i * 8 + 8 <= j)
- mask.ip6.s6_addr[i] = 0xff;
- else
- mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8);
- }
- }
- }
-#endif /* HAVE_IN6_ADDR */
-
- for (ifp = interfaces; ifp != NULL; ifp = ifp->next) {
- if (ifp->family != family)
- continue;
- switch(family) {
- case AF_INET:
- if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr)
- return TRUE;
-#ifdef HAVE_IN6_ADDR
- case AF_INET6:
- for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
- if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j])
- break;
- }
- if (j == sizeof(addr.ip6.s6_addr))
- return TRUE;
-#endif /* HAVE_IN6_ADDR */
- }
- }
-
- return FALSE;
-}
-
-/*
- * Returns TRUE if "n" is one of our ip addresses or if
- * "n" is a network that we are on, else returns FALSE.
- */
-int
-addr_matches(char *n)
-{
- char *m;
- int retval;
-
- /* If there's an explicit netmask, use it. */
- if ((m = strchr(n, '/'))) {
- *m++ = '\0';
- retval = addr_matches_if_netmask(n, m);
- *(m - 1) = '/';
- } else
- retval = addr_matches_if(n);
-
- return retval;
+ 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++ != '%')
}
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);
+
+ debug_return_bool(matched);
+}
- return matched;
+#ifdef HAVE_INNETGR
+/*
+ * 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
+ * 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);
}