version 1.1.1.2, 2012/05/29 12:26:49
|
version 1.1.1.5, 2013/10/14 07:56:34
|
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, struct member_list *group_list) | runaslist_matches(struct member_list *user_list, |
| struct member_list *group_list, struct member **matching_user, |
| struct member **matching_group) |
{ |
{ |
struct member *m; |
struct member *m; |
struct alias *a; |
struct alias *a; |
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 182 _runaslist_matches(struct member_list *user_list, stru
|
Line 186 _runaslist_matches(struct member_list *user_list, stru
|
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); |
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 193 _runaslist_matches(struct member_list *user_list, stru
|
Line 199 _runaslist_matches(struct member_list *user_list, stru
|
if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) |
if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) |
user_matched = !m->negated; |
user_matched = !m->negated; |
break; |
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; |
break; |
|
} |
} |
} |
} |
} |
|
|
Line 210 _runaslist_matches(struct member_list *user_list, stru
|
Line 224 _runaslist_matches(struct member_list *user_list, stru
|
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); |
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 222 _runaslist_matches(struct member_list *user_list, stru
|
Line 238 _runaslist_matches(struct member_list *user_list, stru
|
group_matched = !m->negated; |
group_matched = !m->negated; |
break; |
break; |
} |
} |
if (group_matched != UNSPEC) | if (group_matched != UNSPEC) { |
| if (matching_group != NULL && m->type != ALIAS) |
| *matching_group = m; |
break; |
break; |
|
} |
} |
} |
if (group_matched == UNSPEC) { |
if (group_matched == UNSPEC) { |
if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid) |
if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid) |
Line 238 _runaslist_matches(struct member_list *user_list, stru
|
Line 257 _runaslist_matches(struct member_list *user_list, stru
|
debug_return_int(UNSPEC); |
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. |
* 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 264 _hostlist_matches(struct member_list *list)
|
Line 275 _hostlist_matches(struct member_list *list)
|
matched = !m->negated; |
matched = !m->negated; |
break; |
break; |
case NETGROUP: |
case NETGROUP: |
if (netgr_matches(m->name, user_host, user_shost, NULL)) | if (netgr_matches(m->name, user_runhost, user_srunhost, NULL)) |
matched = !m->negated; |
matched = !m->negated; |
break; |
break; |
case NTWKADDR: |
case NTWKADDR: |
Line 272 _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 */ |
case WORD: |
case WORD: |
if (hostname_matches(user_shost, user_host, m->name)) | if (hostname_matches(user_srunhost, user_runhost, m->name)) |
matched = !m->negated; |
matched = !m->negated; |
break; |
break; |
} |
} |
Line 290 _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 316 _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 340 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 357 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 390 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 418 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 448 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 518 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 546 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 604 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 700 usergr_matches(char *group, char *user, struct passwd
|
Line 844 usergr_matches(char *group, char *user, struct passwd
|
|
|
done: |
done: |
if (pw0 != NULL) |
if (pw0 != NULL) |
pw_delref(pw0); | sudo_pw_delref(pw0); |
|
|
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 715 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)) |