|
version 1.1.1.3, 2012/10/09 09:29:52
|
version 1.1.1.4, 2013/07/22 10:46:12
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * Copyright (c) 1996, 1998-2005, 2007-2012 | * Copyright (c) 1996, 1998-2005, 2007-2013 |
| * Todd C. Miller <Todd.Miller@courtesan.com> |
* 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 |
|
Line 24
|
Line 24
|
| #include <config.h> |
#include <config.h> |
| |
|
| #include <sys/types.h> |
#include <sys/types.h> |
| #include <sys/param.h> |
|
| #include <sys/stat.h> |
#include <sys/stat.h> |
| #include <stdio.h> |
#include <stdio.h> |
| #ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
|
Line 41
|
Line 40
|
| #ifdef HAVE_STRINGS_H |
#ifdef HAVE_STRINGS_H |
| # include <strings.h> |
# include <strings.h> |
| #endif /* HAVE_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 |
#ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
# include <unistd.h> |
| #endif /* HAVE_UNISTD_H */ |
#endif /* HAVE_UNISTD_H */ |
| #ifdef HAVE_FNMATCH |
#ifdef HAVE_FNMATCH |
| # include <fnmatch.h> |
# include <fnmatch.h> |
| |
#else |
| |
# include "compat/fnmatch.h" |
| #endif /* HAVE_FNMATCH */ |
#endif /* HAVE_FNMATCH */ |
| #ifdef HAVE_GLOB | #ifndef SUDOERS_NAME_MATCH |
| # include <glob.h> | # ifdef HAVE_GLOB |
| #endif /* HAVE_GLOB */ | # include <glob.h> |
| | # else |
| | # include "compat/glob.h" |
| | # endif /* HAVE_GLOB */ |
| | #endif /* SUDOERS_NAME_MATCH */ |
| #ifdef HAVE_NETGROUP_H |
#ifdef HAVE_NETGROUP_H |
| # include <netgroup.h> |
# include <netgroup.h> |
| |
#else |
| |
# include <netdb.h> |
| #endif /* HAVE_NETGROUP_H */ |
#endif /* HAVE_NETGROUP_H */ |
| #include <ctype.h> |
|
| #include <pwd.h> |
|
| #include <grp.h> |
|
| #include <netdb.h> |
|
| #ifdef HAVE_DIRENT_H |
#ifdef HAVE_DIRENT_H |
| # include <dirent.h> |
# include <dirent.h> |
| # define NAMLEN(dirent) strlen((dirent)->d_name) |
# define NAMLEN(dirent) strlen((dirent)->d_name) |
|
Line 73
|
Line 81
|
| # include <ndir.h> |
# include <ndir.h> |
| # endif |
# endif |
| #endif |
#endif |
| |
#include <ctype.h> |
| |
#include <pwd.h> |
| |
#include <grp.h> |
| |
#include <errno.h> |
| |
|
| #include "sudoers.h" |
#include "sudoers.h" |
| #include "parse.h" |
#include "parse.h" |
| |
#include "sha2.h" |
| #include <gram.h> |
#include <gram.h> |
| |
|
| #ifndef HAVE_FNMATCH |
|
| # include "compat/fnmatch.h" |
|
| #endif /* HAVE_FNMATCH */ |
|
| #ifndef HAVE_GLOB |
|
| # include "compat/glob.h" |
|
| #endif /* HAVE_GLOB */ |
|
| |
|
| static struct member_list empty; |
static struct member_list empty; |
| |
|
| static bool command_matches_dir(char *, size_t); |
static bool command_matches_dir(char *, size_t); |
| |
#ifndef SUDOERS_NAME_MATCH |
| static bool command_matches_glob(char *, char *); |
static bool command_matches_glob(char *, char *); |
| |
#endif |
| static bool command_matches_fnmatch(char *, char *); |
static bool command_matches_fnmatch(char *, char *); |
| static bool command_matches_normal(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. |
|
Line 101 static bool command_matches_normal(char *, char *);
|
Line 109 static bool command_matches_normal(char *, char *);
|
| * Check for user described by pw in a list of members. |
* Check for user described by pw in a list of members. |
| * Returns ALLOW, DENY or UNSPEC. |
* Returns ALLOW, DENY or UNSPEC. |
| */ |
*/ |
| static int | int |
| _userlist_matches(struct passwd *pw, struct member_list *list) | userlist_matches(struct passwd *pw, struct member_list *list) |
| { |
{ |
| struct member *m; |
struct member *m; |
| struct alias *a; |
struct alias *a; |
| int rval, matched = UNSPEC; |
int rval, matched = UNSPEC; |
| debug_decl(_userlist_matches, SUDO_DEBUG_MATCH) | debug_decl(userlist_matches, SUDO_DEBUG_MATCH) |
| |
|
| tq_foreach_rev(list, m) { |
tq_foreach_rev(list, m) { |
| switch (m->type) { |
switch (m->type) { |
|
Line 123 _userlist_matches(struct passwd *pw, struct member_lis
|
Line 131 _userlist_matches(struct passwd *pw, struct member_lis
|
| matched = !m->negated; |
matched = !m->negated; |
| break; |
break; |
| case ALIAS: |
case ALIAS: |
| if ((a = alias_find(m->name, USERALIAS)) != NULL) { | if ((a = alias_get(m->name, USERALIAS)) != NULL) { |
| rval = _userlist_matches(pw, &a->members); | rval = userlist_matches(pw, &a->members); |
| if (rval != UNSPEC) |
if (rval != UNSPEC) |
| matched = m->negated ? !rval : rval; |
matched = m->negated ? !rval : rval; |
| |
alias_put(a); |
| break; |
break; |
| } |
} |
| /* FALLTHROUGH */ |
/* FALLTHROUGH */ |
|
Line 141 _userlist_matches(struct passwd *pw, struct member_lis
|
Line 150 _userlist_matches(struct passwd *pw, struct member_lis
|
| debug_return_bool(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. |
* Check for user described by pw in a list of members. |
| * If both lists are empty compare against def_runas_default. |
* If both lists are empty compare against def_runas_default. |
| * Returns ALLOW, DENY or UNSPEC. |
* Returns ALLOW, DENY or UNSPEC. |
| */ |
*/ |
| static int | int |
| _runaslist_matches(struct member_list *user_list, | runaslist_matches(struct member_list *user_list, |
| struct member_list *group_list, struct member **matching_user, |
struct member_list *group_list, struct member **matching_user, |
| struct member **matching_group) |
struct member **matching_group) |
| { |
{ |
|
Line 163 _runaslist_matches(struct member_list *user_list,
|
Line 165 _runaslist_matches(struct member_list *user_list,
|
| int rval; |
int rval; |
| int user_matched = UNSPEC; |
int user_matched = UNSPEC; |
| int group_matched = UNSPEC; |
int group_matched = UNSPEC; |
| debug_decl(_runaslist_matches, SUDO_DEBUG_MATCH) | debug_decl(runaslist_matches, SUDO_DEBUG_MATCH) |
| |
|
| if (runas_pw != NULL) { |
if (runas_pw != NULL) { |
| /* If no runas user or runas group listed in sudoers, use default. */ |
/* If no runas user or runas group listed in sudoers, use default. */ |
|
Line 184 _runaslist_matches(struct member_list *user_list,
|
Line 186 _runaslist_matches(struct member_list *user_list,
|
| user_matched = !m->negated; |
user_matched = !m->negated; |
| break; |
break; |
| case ALIAS: |
case ALIAS: |
| if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { | if ((a = alias_get(m->name, RUNASALIAS)) != NULL) { |
| rval = _runaslist_matches(&a->members, &empty, | rval = runaslist_matches(&a->members, &empty, |
| matching_user, NULL); |
matching_user, NULL); |
| if (rval != UNSPEC) |
if (rval != UNSPEC) |
| user_matched = m->negated ? !rval : rval; |
user_matched = m->negated ? !rval : rval; |
| |
alias_put(a); |
| break; |
break; |
| } |
} |
| /* FALLTHROUGH */ |
/* FALLTHROUGH */ |
|
Line 221 _runaslist_matches(struct member_list *user_list,
|
Line 224 _runaslist_matches(struct member_list *user_list,
|
| group_matched = !m->negated; |
group_matched = !m->negated; |
| break; |
break; |
| case ALIAS: |
case ALIAS: |
| if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { | if ((a = alias_get(m->name, RUNASALIAS)) != NULL) { |
| rval = _runaslist_matches(&empty, &a->members, | rval = runaslist_matches(&empty, &a->members, |
| NULL, matching_group); |
NULL, matching_group); |
| if (rval != UNSPEC) |
if (rval != UNSPEC) |
| group_matched = m->negated ? !rval : rval; |
group_matched = m->negated ? !rval : rval; |
| |
alias_put(a); |
| break; |
break; |
| } |
} |
| /* FALLTHROUGH */ |
/* FALLTHROUGH */ |
|
Line 253 _runaslist_matches(struct member_list *user_list,
|
Line 257 _runaslist_matches(struct member_list *user_list,
|
| debug_return_int(UNSPEC); |
debug_return_int(UNSPEC); |
| } |
} |
| |
|
| int |
|
| runaslist_matches(struct member_list *user_list, |
|
| struct member_list *group_list, struct member **matching_user, |
|
| struct member **matching_group) |
|
| { |
|
| alias_seqno++; |
|
| return _runaslist_matches(user_list ? user_list : &empty, |
|
| group_list ? group_list : &empty, matching_user, matching_group); |
|
| } |
|
| |
|
| /* |
/* |
| * Check for host and shost in a list of members. |
* Check for host and shost in a list of members. |
| * Returns ALLOW, DENY or UNSPEC. |
* Returns ALLOW, DENY or UNSPEC. |
| */ |
*/ |
| static int | int |
| _hostlist_matches(struct member_list *list) | hostlist_matches(struct member_list *list) |
| { |
{ |
| struct member *m; |
struct member *m; |
| struct alias *a; |
struct alias *a; |
| int rval, matched = UNSPEC; |
int rval, matched = UNSPEC; |
| debug_decl(_hostlist_matches, SUDO_DEBUG_MATCH) | debug_decl(hostlist_matches, SUDO_DEBUG_MATCH) |
| |
|
| tq_foreach_rev(list, m) { |
tq_foreach_rev(list, m) { |
| switch (m->type) { |
switch (m->type) { |
|
Line 289 _hostlist_matches(struct member_list *list)
|
Line 283 _hostlist_matches(struct member_list *list)
|
| matched = !m->negated; |
matched = !m->negated; |
| break; |
break; |
| case ALIAS: |
case ALIAS: |
| if ((a = alias_find(m->name, HOSTALIAS)) != NULL) { | if ((a = alias_get(m->name, HOSTALIAS)) != NULL) { |
| rval = _hostlist_matches(&a->members); | rval = hostlist_matches(&a->members); |
| if (rval != UNSPEC) |
if (rval != UNSPEC) |
| matched = m->negated ? !rval : rval; |
matched = m->negated ? !rval : rval; |
| |
alias_put(a); |
| break; |
break; |
| } |
} |
| /* FALLTHROUGH */ |
/* FALLTHROUGH */ |
|
Line 307 _hostlist_matches(struct member_list *list)
|
Line 302 _hostlist_matches(struct member_list *list)
|
| debug_return_bool(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. |
* Check for cmnd and args in a list of members. |
| * Returns ALLOW, DENY or UNSPEC. |
* Returns ALLOW, DENY or UNSPEC. |
| */ |
*/ |
| static int | int |
| _cmndlist_matches(struct member_list *list) | cmndlist_matches(struct member_list *list) |
| { |
{ |
| struct member *m; |
struct member *m; |
| int matched = UNSPEC; |
int matched = UNSPEC; |
| debug_decl(_cmndlist_matches, SUDO_DEBUG_MATCH) | debug_decl(cmndlist_matches, SUDO_DEBUG_MATCH) |
| |
|
| tq_foreach_rev(list, m) { |
tq_foreach_rev(list, m) { |
| matched = cmnd_matches(m); |
matched = cmnd_matches(m); |
|
Line 333 _cmndlist_matches(struct member_list *list)
|
Line 321 _cmndlist_matches(struct member_list *list)
|
| debug_return_bool(matched); |
debug_return_bool(matched); |
| } |
} |
| |
|
| int |
|
| cmndlist_matches(struct member_list *list) |
|
| { |
|
| alias_seqno++; |
|
| return _cmndlist_matches(list); |
|
| } |
|
| |
|
| /* |
/* |
| * Check cmnd and args. |
* Check cmnd and args. |
| * Returns ALLOW, DENY or UNSPEC. |
* Returns ALLOW, DENY or UNSPEC. |
|
Line 357 cmnd_matches(struct member *m)
|
Line 338 cmnd_matches(struct member *m)
|
| matched = !m->negated; |
matched = !m->negated; |
| break; |
break; |
| case ALIAS: |
case ALIAS: |
| alias_seqno++; | if ((a = alias_get(m->name, CMNDALIAS)) != NULL) { |
| if ((a = alias_find(m->name, CMNDALIAS)) != NULL) { | rval = cmndlist_matches(&a->members); |
| rval = _cmndlist_matches(&a->members); | |
| if (rval != UNSPEC) |
if (rval != UNSPEC) |
| matched = m->negated ? !rval : rval; |
matched = m->negated ? !rval : rval; |
| |
alias_put(a); |
| } |
} |
| break; |
break; |
| case COMMAND: |
case COMMAND: |
| c = (struct sudo_command *)m->name; |
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; |
matched = !m->negated; |
| break; |
break; |
| } |
} |
|
Line 374 cmnd_matches(struct member *m)
|
Line 355 cmnd_matches(struct member *m)
|
| } |
} |
| |
|
| static bool |
static bool |
| command_args_match(sudoers_cmnd, sudoers_args) | command_args_match(char *sudoers_cmnd, char *sudoers_args) |
| char *sudoers_cmnd; | |
| char *sudoers_args; | |
| { |
{ |
| int flags = 0; |
int flags = 0; |
| debug_decl(command_args_match, SUDO_DEBUG_MATCH) |
debug_decl(command_args_match, SUDO_DEBUG_MATCH) |
|
Line 407 command_args_match(sudoers_cmnd, sudoers_args)
|
Line 386 command_args_match(sudoers_cmnd, sudoers_args)
|
| * otherwise, return true if user_cmnd names one of the inodes in path. |
* otherwise, return true if user_cmnd names one of the inodes in path. |
| */ |
*/ |
| bool |
bool |
| command_matches(char *sudoers_cmnd, char *sudoers_args) | command_matches(char *sudoers_cmnd, char *sudoers_args, struct sudo_digest *digest) |
| { |
{ |
| debug_decl(command_matches, SUDO_DEBUG_MATCH) |
debug_decl(command_matches, SUDO_DEBUG_MATCH) |
| |
|
|
Line 435 command_matches(char *sudoers_cmnd, char *sudoers_args
|
Line 414 command_matches(char *sudoers_cmnd, char *sudoers_args
|
| * If sudoers_cmnd has meta characters in it, we need to |
* If sudoers_cmnd has meta characters in it, we need to |
| * use glob(3) and/or fnmatch(3) to do the matching. |
* 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) |
if (def_fast_glob) |
| debug_return_bool(command_matches_fnmatch(sudoers_cmnd, sudoers_args)); |
debug_return_bool(command_matches_fnmatch(sudoers_cmnd, sudoers_args)); |
| debug_return_bool(command_matches_glob(sudoers_cmnd, sudoers_args)); |
debug_return_bool(command_matches_glob(sudoers_cmnd, sudoers_args)); |
| |
#endif |
| } |
} |
| debug_return_bool(command_matches_normal(sudoers_cmnd, sudoers_args)); | debug_return_bool(command_matches_normal(sudoers_cmnd, sudoers_args, digest)); |
| } |
} |
| |
|
| static bool |
static bool |
|
Line 465 command_matches_fnmatch(char *sudoers_cmnd, char *sudo
|
Line 448 command_matches_fnmatch(char *sudoers_cmnd, char *sudo
|
| debug_return_bool(false); |
debug_return_bool(false); |
| } |
} |
| |
|
| |
#ifndef SUDOERS_NAME_MATCH |
| static bool |
static bool |
| command_matches_glob(char *sudoers_cmnd, char *sudoers_args) |
command_matches_glob(char *sudoers_cmnd, char *sudoers_args) |
| { |
{ |
|
Line 535 command_matches_glob(char *sudoers_cmnd, char *sudoers
|
Line 519 command_matches_glob(char *sudoers_cmnd, char *sudoers
|
| } |
} |
| debug_return_bool(false); |
debug_return_bool(false); |
| } |
} |
| |
#endif /* SUDOERS_NAME_MATCH */ |
| |
|
| |
#ifdef SUDOERS_NAME_MATCH |
| static bool |
static bool |
| command_matches_normal(char *sudoers_cmnd, char *sudoers_args) | 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; |
struct stat sudoers_stat; |
| char *base; |
char *base; |
| size_t dlen; |
size_t dlen; |
|
Line 563 command_matches_normal(char *sudoers_cmnd, char *sudoe
|
Line 672 command_matches_normal(char *sudoers_cmnd, char *sudoe
|
| * a) there are no args in sudoers OR |
* a) there are no args in sudoers OR |
| * b) there are no args on command line and none req by 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 |
* 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 && |
if (user_stat != NULL && |
| (user_stat->st_dev != sudoers_stat.st_dev || |
(user_stat->st_dev != sudoers_stat.st_dev || |
| user_stat->st_ino != sudoers_stat.st_ino)) |
user_stat->st_ino != sudoers_stat.st_ino)) |
| debug_return_bool(false); |
debug_return_bool(false); |
| if (command_args_match(sudoers_cmnd, sudoers_args)) { | if (!command_args_match(sudoers_cmnd, sudoers_args)) |
| efree(safe_cmnd); | debug_return_bool(false); |
| safe_cmnd = estrdup(sudoers_cmnd); | if (digest != NULL && !digest_matches(sudoers_cmnd, digest)) { |
| debug_return_bool(true); | /* XXX - log functions not available but we should log very loudly */ |
| | debug_return_bool(false); |
| } |
} |
| debug_return_bool(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 bool |
static bool |
|
Line 621 command_matches_dir(char *sudoers_dir, size_t dlen)
|
Line 747 command_matches_dir(char *sudoers_dir, size_t dlen)
|
| closedir(dirp); |
closedir(dirp); |
| debug_return_bool(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 |
|
Line 722 done:
|
Line 849 done:
|
| debug_return_bool(matched); |
debug_return_bool(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", |
* Returns true if "host" and "user" belong to the netgroup "netgr", |
| * else return false. Either of "host", "shost" or "user" may be NULL |
* else return false. Either of "host", "shost" or "user" may be NULL |
| * in which case that argument is not checked... |
* in which case that argument is not checked... |
|
Line 732 done:
|
Line 888 done:
|
| bool |
bool |
| netgr_matches(char *netgr, char *lhost, char *shost, char *user) |
netgr_matches(char *netgr, char *lhost, char *shost, char *user) |
| { |
{ |
| |
#ifdef HAVE_INNETGR |
| static char *domain; |
static char *domain; |
| #ifdef HAVE_GETDOMAINNAME |
|
| static int initialized; |
static int initialized; |
| #endif |
#endif |
| debug_decl(netgr_matches, SUDO_DEBUG_MATCH) |
debug_decl(netgr_matches, SUDO_DEBUG_MATCH) |
| |
|
| |
#ifdef HAVE_INNETGR |
| /* make sure we have a valid netgroup, sudo style */ |
/* make sure we have a valid netgroup, sudo style */ |
| if (*netgr++ != '+') |
if (*netgr++ != '+') |
| debug_return_bool(false); |
debug_return_bool(false); |
| |
|
| #ifdef HAVE_GETDOMAINNAME |
|
| /* get the domain name (if any) */ |
/* get the domain name (if any) */ |
| if (!initialized) { |
if (!initialized) { |
| domain = (char *) emalloc(MAXHOSTNAMELEN + 1); | domain = sudo_getdomainname(); |
| if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') { | |
| efree(domain); | |
| domain = NULL; | |
| } | |
| initialized = 1; |
initialized = 1; |
| } |
} |
| #endif /* HAVE_GETDOMAINNAME */ |
|
| |
|
| #ifdef HAVE_INNETGR |
|
| if (innetgr(netgr, lhost, user, domain)) |
if (innetgr(netgr, lhost, user, domain)) |
| debug_return_bool(true); |
debug_return_bool(true); |
| else if (lhost != shost && innetgr(netgr, shost, user, domain)) |
else if (lhost != shost && innetgr(netgr, shost, user, domain)) |