Simplify the nss interface such that each sudoers provider fills

in a per-nss list of userspecs and defaults instead of using separate
lookup and list functions.  This makes it possible to have a single
implementation of the code for sudoers lookup and listing.
This commit is contained in:
Todd C. Miller
2018-05-14 09:05:03 -06:00
parent 71e98d9493
commit f9be3a48a2
17 changed files with 980 additions and 1959 deletions

View File

@@ -278,6 +278,7 @@ plugins/sudoers/digestname.c
plugins/sudoers/editor.c plugins/sudoers/editor.c
plugins/sudoers/env.c plugins/sudoers/env.c
plugins/sudoers/env_pattern.c plugins/sudoers/env_pattern.c
plugins/sudoers/file.c
plugins/sudoers/filedigest.c plugins/sudoers/filedigest.c
plugins/sudoers/filedigest_gcrypt.c plugins/sudoers/filedigest_gcrypt.c
plugins/sudoers/filedigest_openssl.c plugins/sudoers/filedigest_openssl.c

View File

@@ -154,11 +154,11 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo digestname.lo \
timestr.lo toke.lo toke_util.lo timestr.lo toke.lo toke_util.lo
SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \ SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo \
env_pattern.lo find_path.lo fmtsudoers.lo gc.lo goodpath.lo \ env_pattern.lo file.lo find_path.lo fmtsudoers.lo gc.lo \
group_plugin.lo interfaces.lo iolog.lo iolog_path.lo locale.lo \ goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
logging.lo logwrap.lo mkdir_parents.lo parse.lo policy.lo \ iolog_path.lo locale.lo logging.lo logwrap.lo mkdir_parents.lo \
prompt.lo set_perms.lo starttime.lo sudo_nss.lo sudoers.lo \ parse.lo policy.lo prompt.lo set_perms.lo starttime.lo \
timestamp.lo @SUDOERS_OBJS@ sudo_nss.lo sudoers.lo timestamp.lo @SUDOERS_OBJS@
VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o stubs.o sudo_printf.o visudo.o VISUDO_OBJS = editor.o find_path.o goodpath.o locale.o stubs.o sudo_printf.o visudo.o
@@ -1111,6 +1111,15 @@ pam.lo: $(authdir)/pam.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
$(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(authdir)/pam.c $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(authdir)/pam.c
file.lo: $(srcdir)/file.c $(devdir)/def_data.h $(devdir)/gram.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_lbuf.h \
$(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/config.h $(top_builddir)/pathnames.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/file.c
parse.lo: $(srcdir)/parse.c $(devdir)/def_data.h $(devdir)/gram.h \ parse.lo: $(srcdir)/parse.c $(devdir)/def_data.h $(devdir)/gram.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \ $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \

View File

@@ -725,11 +725,11 @@ default_binding_matches(struct defaults *d, int what)
} }
/* /*
* Update the defaults based on what was set by sudoers. * Update the global defaults based on the given defaults list.
* Pass in an OR'd list of which default types to update. * Pass in an OR'd list of which default types to update.
*/ */
bool bool
update_defaults(int what, bool quiet) update_defaults(struct defaults_list *defs, int what, bool quiet)
{ {
struct defaults *d; struct defaults *d;
bool ret = true; bool ret = true;
@@ -741,7 +741,7 @@ update_defaults(int what, bool quiet)
/* /*
* First apply Defaults values marked as early. * First apply Defaults values marked as early.
*/ */
TAILQ_FOREACH(d, &defaults, entries) { TAILQ_FOREACH(d, defs, entries) {
struct early_default *early = is_early_default(d->var); struct early_default *early = is_early_default(d->var);
if (early == NULL) if (early == NULL)
continue; continue;
@@ -763,7 +763,7 @@ update_defaults(int what, bool quiet)
/* /*
* Then set the rest of the defaults. * Then set the rest of the defaults.
*/ */
TAILQ_FOREACH(d, &defaults, entries) { TAILQ_FOREACH(d, defs, entries) {
/* Skip Defaults marked as early, we already did them. */ /* Skip Defaults marked as early, we already did them. */
if (is_early_default(d->var)) if (is_early_default(d->var))
continue; continue;

View File

@@ -122,13 +122,14 @@ struct early_default {
/* /*
* Prototypes * Prototypes
*/ */
struct defaults_list;
void dump_default(void); void dump_default(void);
bool init_defaults(void); bool init_defaults(void);
struct early_default *is_early_default(const char *name); struct early_default *is_early_default(const char *name);
bool run_early_defaults(void); bool run_early_defaults(void);
bool set_early_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet, struct early_default *early); bool set_early_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet, struct early_default *early);
bool set_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet); bool set_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet);
bool update_defaults(int what, bool quiet); bool update_defaults(struct defaults_list *defs, int what, bool quiet);
bool check_defaults(bool quiet); bool check_defaults(bool quiet);
extern struct sudo_defs_types sudo_defs_table[]; extern struct sudo_defs_types sudo_defs_table[];

145
plugins/sudoers/file.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2004-2005, 2007-2018 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include <unistd.h>
#include <ctype.h>
#include <grp.h>
#include <pwd.h>
#include <time.h>
#include "sudoers.h"
#include "parse.h"
#include "sudo_lbuf.h"
#include <gram.h>
/*
* Local prototypes.
*/
static int sudo_file_close(struct sudo_nss *);
static int sudo_file_open(struct sudo_nss *);
static int sudo_file_parse(struct sudo_nss *);
static int sudo_file_query(struct sudo_nss *, struct passwd *pw);
static int sudo_file_getdefs(struct sudo_nss *);
/* sudo_nss implementation */
struct sudo_nss sudo_nss_file = {
{ NULL, NULL },
sudo_file_open,
sudo_file_close,
sudo_file_parse,
sudo_file_query,
sudo_file_getdefs
};
static int
sudo_file_open(struct sudo_nss *nss)
{
debug_decl(sudo_file_open, SUDOERS_DEBUG_NSS)
if (def_ignore_local_sudoers)
debug_return_int(-1);
nss->handle = open_sudoers(sudoers_file, false, NULL);
debug_return_int(nss->handle ? 0 : -1);
}
static int
sudo_file_close(struct sudo_nss *nss)
{
struct member_list *prev_binding = NULL;
struct defaults *def;
struct userspec *us;
debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
if (nss->handle != NULL) {
fclose(nss->handle);
nss->handle = NULL;
sudoersin = NULL;
/* XXX - do in main module? */
while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
TAILQ_REMOVE(&nss->userspecs, us, entries);
free_userspec(us);
}
while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
TAILQ_REMOVE(&nss->defaults, def, entries);
free_default(def, &prev_binding);
}
}
debug_return_int(0);
}
/*
* Parse the specified sudoers file.
*/
static int
sudo_file_parse(struct sudo_nss *nss)
{
debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
if (nss->handle == NULL)
debug_return_int(-1);
sudoersin = nss->handle;
if (sudoersparse() != 0 || parse_error) {
if (errorlineno != -1) {
log_warningx(SLOG_SEND_MAIL, N_("parse error in %s near line %d"),
errorfile, errorlineno);
} else {
log_warningx(SLOG_SEND_MAIL, N_("parse error in %s"), errorfile);
}
debug_return_int(-1);
}
/* Move parsed userspecs and defaults to nss structure. */
TAILQ_CONCAT(&nss->userspecs, &userspecs, entries);
TAILQ_CONCAT(&nss->defaults, &defaults, entries);
debug_return_int(0);
}
/*
* No need for explicit queries for sudoers file, we have it all in memory.
*/
static int
sudo_file_query(struct sudo_nss *nss, struct passwd *pw)
{
debug_decl(sudo_file_query, SUDOERS_DEBUG_NSS)
debug_return_int(0);
}
/*
* No need to get defaults for sudoers file, the parse function handled it.
*/
static int
sudo_file_getdefs(struct sudo_nss *nss)
{
debug_decl(sudo_file_getdefs, SUDOERS_DEBUG_NSS)
debug_return_int(0);
}

View File

@@ -142,31 +142,20 @@ STAILQ_HEAD(ldap_netgroup_list, ldap_netgroup);
static int sudo_ldap_open(struct sudo_nss *nss); static int sudo_ldap_open(struct sudo_nss *nss);
static int sudo_ldap_close(struct sudo_nss *nss); static int sudo_ldap_close(struct sudo_nss *nss);
static int sudo_ldap_parse(struct sudo_nss *nss); static int sudo_ldap_parse(struct sudo_nss *nss);
static int sudo_ldap_setdefs(struct sudo_nss *nss); static int sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw);
static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag); static int sudo_ldap_getdefs(struct sudo_nss *nss);
static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf);
static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss,
struct passwd *pw, struct sudo_lbuf *lbuf);
static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf);
static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss, static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
struct passwd *pw); struct passwd *pw);
static char *sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry); static char *sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry);
/* /*
* LDAP sudo_nss handle. * LDAP sudo_nss handle.
* We store the connection to the LDAP server, the cached ldap_result object * We store the connection to the LDAP server and the passwd struct of the
* (if any), and the name of the user the query was performed for. * user the last query was performed for.
* If a new query is launched with sudo_ldap_result_get() that specifies a
* different user, the old cached result is freed before the new query is run.
*/ */
struct sudo_ldap_handle { struct sudo_ldap_handle {
LDAP *ld; LDAP *ld;
struct ldap_result *result; struct passwd *pw;
const char *username;
struct gid_list *gidlist;
}; };
struct sudo_nss sudo_nss_ldap = { struct sudo_nss sudo_nss_ldap = {
@@ -174,12 +163,8 @@ struct sudo_nss sudo_nss_ldap = {
sudo_ldap_open, sudo_ldap_open,
sudo_ldap_close, sudo_ldap_close,
sudo_ldap_parse, sudo_ldap_parse,
sudo_ldap_setdefs, sudo_ldap_query,
sudo_ldap_lookup, sudo_ldap_getdefs
sudo_ldap_display_cmnd,
sudo_ldap_display_defaults,
sudo_ldap_display_bound_defaults,
sudo_ldap_display_privs
}; };
#ifdef HAVE_LDAP_INITIALIZE #ifdef HAVE_LDAP_INITIALIZE
@@ -397,321 +382,60 @@ sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry, struct passwd *pw)
debug_return_bool(matched == true); debug_return_bool(matched == true);
} }
static int
sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry, int *group_matched)
{
struct berval **bv, **p;
char *val;
bool ret = false;
debug_decl(sudo_ldap_check_runas_user, SUDOERS_DEBUG_LDAP)
/* get the runas user from the entry */
bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
if (bv == NULL)
bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */
if (bv == NULL) {
DPRINTF2("sudoRunAsUser: no result.");
if (*group_matched == UNSPEC) {
/* We haven't check for sudoRunAsGroup yet, check now. */
bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
if (bv != NULL) {
*group_matched = false;
ldap_value_free_len(bv);
}
}
if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED))
debug_return_int(UNSPEC);
switch (*group_matched) {
case UNSPEC:
/*
* No runas user or group entries. Match runas_default
* against what the user specified on the command line.
*/
ret = userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
break;
case true:
/*
* No runas user entries but have a matching runas group entry.
* If trying to run as the invoking user, allow it.
*/
if (userpw_matches(user_name, runas_pw->pw_name, runas_pw))
ret = true;
break;
}
debug_return_int(ret);
}
/*
* BUG:
*
* if runas is not specified on the command line, the only information
* as to which user to run as is in the runas_default option. We should
* check to see if we have the local option present. Unfortunately we
* don't parse these options until after this routine says yes or no.
* The query has already returned, so we could peek at the attribute
* values here though.
*
* For now just require users to always use -u option unless its set
* in the global defaults. This behaviour is no different than the global
* /etc/sudoers.
*
* Sigh - maybe add this feature later
*/
/* walk through values returned, looking for a match */
for (p = bv; *p != NULL && !ret; p++) {
val = (*p)->bv_val;
switch (val[0]) {
case '+':
if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL,
def_netgroup_tuple ? user_srunhost : NULL, runas_pw->pw_name))
ret = true;
break;
case '%':
if (usergr_matches(val, runas_pw->pw_name, runas_pw))
ret = true;
break;
case '\0':
/* Empty RunAsUser means run as the invoking user. */
if (ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) &&
userpw_matches(user_name, runas_pw->pw_name, runas_pw))
ret = true;
break;
case 'A':
if (strcmp(val, "ALL") == 0) {
ret = true;
break;
}
/* FALLTHROUGH */
default:
if (userpw_matches(val, runas_pw->pw_name, runas_pw))
ret = true;
break;
}
DPRINTF2("ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
}
ldap_value_free_len(bv); /* cleanup */
debug_return_int(ret);
}
static int
sudo_ldap_check_runas_group(LDAP *ld, LDAPMessage *entry)
{
struct berval **bv, **p;
char *val;
bool ret = false;
debug_decl(sudo_ldap_check_runas_group, SUDOERS_DEBUG_LDAP)
/* get the values from the entry */
bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
if (bv == NULL) {
DPRINTF2("sudoRunAsGroup: no result.");
if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED)) {
if (runas_pw->pw_gid == runas_gr->gr_gid)
ret = true; /* runas group matches passwd db */
}
debug_return_int(ret);
}
/* walk through values returned, looking for a match */
for (p = bv; *p != NULL && !ret; p++) {
val = (*p)->bv_val;
if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
ret = true;
DPRINTF2("ldap sudoRunAsGroup '%s' ... %s",
val, ret ? "MATCH!" : "not");
}
ldap_value_free_len(bv); /* cleanup */
debug_return_int(ret);
}
/* /*
* Walk through search results and return true if we have a runas match, * Read sudoOption and fill in the defaults list.
* else false. RunAs info is optional. * This is used to parse the cn=defaults entry.
*/ */
static bool static bool
sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry) sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs)
{
int user_matched = UNSPEC;
int group_matched = UNSPEC;
debug_decl(sudo_ldap_check_runas, SUDOERS_DEBUG_LDAP)
if (!entry)
debug_return_bool(false);
if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED))
group_matched = sudo_ldap_check_runas_group(ld, entry);
user_matched = sudo_ldap_check_runas_user(ld, entry, &group_matched);
debug_return_bool(group_matched != false && user_matched != false);
}
/*
* Walk through search results and return true if we have a command match,
* false if disallowed and UNSPEC if not matched.
*/
static int
sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied)
{
struct sudo_digest digest, *allowed_digest = NULL;
struct berval **bv, **p;
char *allowed_cmnd, *allowed_args, *val;
int ret = UNSPEC;
bool negated;
debug_decl(sudo_ldap_check_command, SUDOERS_DEBUG_LDAP)
if (!entry)
debug_return_int(ret);
bv = ldap_get_values_len(ld, entry, "sudoCommand");
if (bv == NULL)
debug_return_int(ret);
for (p = bv; *p != NULL && ret != false; p++) {
val = (*p)->bv_val;
/* Match against ALL ? */
if (strcmp(val, "ALL") == 0) {
ret = true;
if (setenv_implied != NULL)
*setenv_implied = true;
DPRINTF2("ldap sudoCommand '%s' ... MATCH!", val);
continue;
}
/* check for sha-2 digest */
allowed_digest = sudo_ldap_extract_digest(&val, &digest);
/* check for !command */
allowed_cmnd = val;
negated = sudo_ldap_is_negated(&allowed_cmnd);
/* split optional args away from command */
allowed_args = strchr(allowed_cmnd, ' ');
if (allowed_args)
*allowed_args++ = '\0';
/* check the command like normal */
if (command_matches(allowed_cmnd, allowed_args, allowed_digest)) {
/*
* If allowed (no bang) set ret but keep on checking.
* If disallowed (bang), exit loop.
*/
ret = negated ? false : true;
}
if (allowed_args != NULL)
allowed_args[-1] = ' '; /* restore val */
DPRINTF2("ldap sudoCommand '%s' ... %s",
val, ret == true ? "MATCH!" : "not");
if (allowed_digest != NULL)
free(allowed_digest->digest_str);
}
ldap_value_free_len(bv); /* more cleanup */
debug_return_int(ret);
}
/*
* Search for boolean "option" in sudoOption.
* Returns true if found and allowed, false if negated, else UNSPEC.
*/
static int
sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option)
{ {
struct berval **bv, **p; struct berval **bv, **p;
char *var; char *cn, *cp, *source = NULL;
bool negated;
int ret = UNSPEC;
debug_decl(sudo_ldap_check_bool, SUDOERS_DEBUG_LDAP)
if (entry == NULL)
debug_return_int(ret);
bv = ldap_get_values_len(ld, entry, "sudoOption");
if (bv == NULL)
debug_return_int(ret);
/* walk through options */
for (p = bv; *p != NULL; p++) {
var = (*p)->bv_val;
DPRINTF2("ldap sudoOption: '%s'", var);
negated = sudo_ldap_is_negated(&var);
if (strcmp(var, option) == 0)
ret = negated ? false : true;
}
ldap_value_free_len(bv);
debug_return_int(ret);
}
/*
* Read sudoOption and modify the defaults as we go. This is used once
* from the cn=defaults entry and also once when a final sudoRole is matched.
*/
static bool
sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry)
{
struct berval **bv, **p;
char *cn, *var, *val, *source = NULL;
bool ret = false; bool ret = false;
int op;
debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP) debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP)
bv = ldap_get_values_len(ld, entry, "sudoOption"); bv = ldap_get_values_len(ld, entry, "sudoOption");
if (bv == NULL) if (bv == NULL)
debug_return_bool(true); debug_return_bool(true);
/* get the entry's dn for option error reporting */ /* Use sudoRole in place of file name in defaults. */
cn = sudo_ldap_get_first_rdn(ld, entry); cn = sudo_ldap_get_first_rdn(ld, entry);
if (cn != NULL) { if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) {
if (asprintf(&source, "sudoRole %s", cn) == -1) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); goto done;
source = NULL; }
goto done; if ((source = rcstr_dup(cp)) == NULL) {
} sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
free(cp);
goto done;
} }
/* walk through options, early ones first */ /* Walk through options, appending to defs. */
for (p = bv; *p != NULL; p++) { for (p = bv; *p != NULL; p++) {
struct early_default *early; char *copy, *var, *val;
char *copy; int op;
/* Avoid modifying bv as we need to use it again below. */ copy = strdup((*p)->bv_val); /* XXX - should not need to copy */
if ((copy = strdup((*p)->bv_val)) == NULL) { if (copy == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
free(copy);
goto done; goto done;
} }
op = sudo_ldap_parse_option(copy, &var, &val); op = sudo_ldap_parse_option(copy, &var, &val);
early = is_early_default(var); if (!sudo_ldap_add_default(var, val, op, source, defs)) {
if (early != NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
set_early_default(var, val, op, free(copy);
source ? source : "sudoRole UNKNOWN", 0, false, early); goto done;
} }
free(copy); free(copy);
} }
run_early_defaults();
/* walk through options again, skipping early ones */
for (p = bv; *p != NULL; p++) {
op = sudo_ldap_parse_option((*p)->bv_val, &var, &val);
if (is_early_default(var) == NULL) {
set_default(var, val, op,
source ? source : "sudoRole UNKNOWN", 0, false);
}
}
ret = true; ret = true;
done: done:
free(source); rcstr_delref(source);
if (cn) if (cn)
ldap_memfree(cn); ldap_memfree(cn);
ldap_value_free_len(bv); ldap_value_free_len(bv);
@@ -1416,81 +1140,6 @@ sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
#endif #endif
} }
/*
* Fetch and display the global Options.
*/
static int
sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
struct berval **bv, **p;
struct timeval tv, *tvp = NULL;
struct ldap_config_str *base;
struct sudo_ldap_handle *handle = nss->handle;
LDAP *ld;
LDAPMessage *entry, *result;
char *prefix, *filt;
int rc, count = 0;
debug_decl(sudo_ldap_display_defaults, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL)
goto done;
ld = handle->ld;
filt = sudo_ldap_build_default_filter();
if (filt == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
count = -1;
goto done;
}
STAILQ_FOREACH(base, &ldap_conf.base, entries) {
if (ldap_conf.timeout > 0) {
tv.tv_sec = ldap_conf.timeout;
tv.tv_usec = 0;
tvp = &tv;
}
result = NULL;
rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
filt, NULL, 0, NULL, NULL, tvp, 0, &result);
if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
bv = ldap_get_values_len(ld, entry, "sudoOption");
if (bv != NULL) {
if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
prefix = " ";
else
prefix = ", ";
for (p = bv; *p != NULL; p++) {
struct defaults d;
sudo_lbuf_append(lbuf, "%s", prefix);
d.op = sudo_ldap_parse_option((*p)->bv_val, &d.var, &d.val);
sudoers_format_default(lbuf, &d);
prefix = ", ";
count++;
}
ldap_value_free_len(bv);
}
}
ldap_msgfree(result);
}
free(filt);
done:
if (sudo_lbuf_error(lbuf))
debug_return_int(-1);
debug_return_int(count);
}
/*
* STUB
*/
static int
sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
debug_decl(sudo_ldap_display_bound_defaults, SUDOERS_DEBUG_LDAP)
debug_return_int(0);
}
static char * static char *
berval_iter(void **vp) berval_iter(void **vp)
{ {
@@ -1500,19 +1149,15 @@ berval_iter(void **vp)
return *bv ? (*bv)->bv_val : NULL; return *bv ? (*bv)->bv_val : NULL;
} }
static struct userspec_list * static bool
ldap_to_sudoers(LDAP *ld, struct ldap_result *lres) ldap_to_sudoers(LDAP *ld, struct ldap_result *lres,
struct userspec_list *ldap_userspecs)
{ {
struct userspec_list *ldap_userspecs;
struct userspec *us; struct userspec *us;
struct member *m; struct member *m;
unsigned int i; unsigned int i;
debug_decl(ldap_to_sudoers, SUDOERS_DEBUG_LDAP) debug_decl(ldap_to_sudoers, SUDOERS_DEBUG_LDAP)
if ((ldap_userspecs = calloc(1, sizeof(*ldap_userspecs))) == NULL)
goto oom;
TAILQ_INIT(ldap_userspecs);
/* We only have a single userspec */ /* We only have a single userspec */
if ((us = calloc(1, sizeof(*us))) == NULL) if ((us = calloc(1, sizeof(*us))) == NULL)
goto oom; goto oom;
@@ -1586,103 +1231,13 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres)
oom: oom:
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
if (ldap_userspecs != NULL) { while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) { TAILQ_REMOVE(ldap_userspecs, us, entries);
TAILQ_REMOVE(ldap_userspecs, us, entries); free_userspec(us);
free_userspec(us);
}
free(ldap_userspecs);
} }
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
/*
* Like sudo_ldap_lookup(), except we just print entries.
*/
static int
sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
struct sudo_ldap_handle *handle = nss->handle;
struct userspec_list *ldap_userspecs = NULL;
struct ldap_result *lres;
LDAP *ld;
int ret = 0;
debug_decl(sudo_ldap_display_privs, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL)
goto done;
ld = handle->ld;
DPRINTF1("ldap search for command list");
lres = sudo_ldap_result_get(nss, pw);
if (lres == NULL)
goto done;
/* Convert to sudoers parse tree. */
if ((ldap_userspecs = ldap_to_sudoers(ld, lres)) == NULL) {
ret = -1;
goto done;
}
/* Call common display code. */
ret = sudo_display_userspecs(ldap_userspecs, pw, lbuf);
done:
if (ldap_userspecs != NULL) {
struct userspec *us;
while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
TAILQ_REMOVE(ldap_userspecs, us, entries);
free_userspec(us);
}
free(ldap_userspecs);
}
if (sudo_lbuf_error(lbuf))
debug_return_int(-1);
debug_return_int(ret);
}
static int
sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
{
struct sudo_ldap_handle *handle = nss->handle;
LDAP *ld;
struct ldap_result *lres;
LDAPMessage *entry;
bool found = false;
unsigned int i;
debug_decl(sudo_ldap_display_cmnd, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL)
goto done;
ld = handle->ld;
/*
* The sudo_ldap_result_get() function returns all nodes that match
* the user and the host.
*/
DPRINTF1("ldap search for command list");
lres = sudo_ldap_result_get(nss, pw);
if (lres == NULL)
goto done;
for (i = 0; i < lres->nentries; i++) {
entry = lres->entries[i].entry;
if (!sudo_ldap_check_runas(ld, entry))
continue;
if (sudo_ldap_check_command(ld, entry, NULL) == true) {
found = true;
goto done;
}
}
done:
if (found)
sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
safe_cmnd ? safe_cmnd : user_cmnd,
user_args ? " " : "", user_args ? user_args : "");
debug_return_int(!found);
}
#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
static unsigned int (*sudo_gss_krb5_ccache_name)(unsigned int *minor_status, const char *name, const char **old_name); static unsigned int (*sudo_gss_krb5_ccache_name)(unsigned int *minor_status, const char *name, const char **old_name);
@@ -2087,21 +1642,29 @@ done:
} }
static int static int
sudo_ldap_setdefs(struct sudo_nss *nss) sudo_ldap_getdefs(struct sudo_nss *nss)
{ {
struct ldap_config_str *base; struct ldap_config_str *base;
struct sudo_ldap_handle *handle = nss->handle; struct sudo_ldap_handle *handle = nss->handle;
struct member_list *prev_binding = NULL;
struct timeval tv, *tvp = NULL; struct timeval tv, *tvp = NULL;
struct defaults *def;
LDAP *ld; LDAP *ld;
LDAPMessage *entry, *result = NULL; LDAPMessage *entry, *result = NULL;
char *filt; char *filt;
int ret; int rc, ret = -1;
debug_decl(sudo_ldap_setdefs, SUDOERS_DEBUG_LDAP) debug_decl(sudo_ldap_getdefs, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL) if (handle == NULL || handle->ld == NULL)
debug_return_int(-1); debug_return_int(-1);
ld = handle->ld; ld = handle->ld;
/* Free old defaults, if any. */
while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
TAILQ_REMOVE(&nss->defaults, def, entries);
free_default(def, &prev_binding);
}
filt = sudo_ldap_build_default_filter(); filt = sudo_ldap_build_default_filter();
if (filt == NULL) { if (filt == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
@@ -2117,14 +1680,12 @@ sudo_ldap_setdefs(struct sudo_nss *nss)
} }
ldap_msgfree(result); ldap_msgfree(result);
result = NULL; result = NULL;
ret = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE,
filt, NULL, 0, NULL, NULL, tvp, 0, &result); filt, NULL, 0, NULL, NULL, tvp, 0, &result);
if (ret == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
DPRINTF1("found:%s", ldap_get_dn(ld, entry)); DPRINTF1("found:%s", ldap_get_dn(ld, entry));
if (!sudo_ldap_parse_options(ld, entry)) { if (!sudo_ldap_parse_options(ld, entry, &nss->defaults))
ret = -1;
goto done; goto done;
}
} else { } else {
DPRINTF1("no default options found in %s", base->val); DPRINTF1("no default options found in %s", base->val);
} }
@@ -2138,132 +1699,6 @@ done:
debug_return_int(ret); debug_return_int(ret);
} }
/*
* like sudoers_lookup() - only LDAP style
*/
static int
sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag)
{
struct sudo_ldap_handle *handle = nss->handle;
LDAP *ld;
LDAPMessage *entry;
int rc, setenv_implied;
unsigned int i;
struct ldap_result *lres = NULL;
debug_decl(sudo_ldap_lookup, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL)
debug_return_int(ret);
ld = handle->ld;
/* Fetch list of sudoRole entries that match user and host. */
lres = sudo_ldap_result_get(nss, sudo_user.pw);
if (lres == NULL)
debug_return_int(ret);
/*
* The following queries only determine whether or not a password
* is required, so the order of the entries doesn't matter.
*/
if (pwflag) {
int doauth = UNSPEC;
int matched = UNSPEC;
enum def_tuple pwcheck =
(pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
DPRINTF1("perform search for pwflag %d", pwflag);
for (i = 0; i < lres->nentries; i++) {
entry = lres->entries[i].entry;
if ((pwcheck == any && doauth != false) ||
(pwcheck == all && doauth != true)) {
doauth = !!sudo_ldap_check_bool(ld, entry, "authenticate");
}
if (matched == true)
continue;
/* Only check the command when listing another user. */
if (user_uid == 0 || list_pw == NULL ||
user_uid == list_pw->pw_uid ||
sudo_ldap_check_command(ld, entry, NULL) == true) {
matched = true;
}
}
if (matched == true || user_uid == 0) {
SET(ret, VALIDATE_SUCCESS);
CLR(ret, VALIDATE_FAILURE);
switch (pwcheck) {
case always:
SET(ret, FLAG_CHECK_USER);
break;
case all:
case any:
if (doauth == false)
SET(ret, FLAG_NOPASSWD);
else
CLR(ret, FLAG_NOPASSWD);
break;
default:
break;
}
}
goto done;
}
DPRINTF1("searching LDAP for sudoers entries");
setenv_implied = false;
for (i = 0; i < lres->nentries; i++) {
entry = lres->entries[i].entry;
if (!sudo_ldap_check_runas(ld, entry))
continue;
rc = sudo_ldap_check_command(ld, entry, &setenv_implied);
if (rc != UNSPEC) {
/* We have a match. */
DPRINTF1("Command %sallowed", rc == true ? "" : "NOT ");
if (rc == true) {
DPRINTF1("LDAP entry: %p", entry);
/* Apply entry-specific options. */
if (setenv_implied)
def_setenv = true;
if (sudo_ldap_parse_options(ld, entry)) {
#ifdef HAVE_SELINUX
/* Set role and type if not specified on command line. */
if (user_role == NULL)
user_role = def_role;
if (user_type == NULL)
user_type = def_type;
#endif /* HAVE_SELINUX */
SET(ret, VALIDATE_SUCCESS);
CLR(ret, VALIDATE_FAILURE);
} else {
SET(ret, VALIDATE_ERROR);
}
} else {
SET(ret, VALIDATE_FAILURE);
CLR(ret, VALIDATE_SUCCESS);
}
break;
}
}
done:
DPRINTF1("done with LDAP searches");
DPRINTF1("user_matches=%s", lres->user_matches ? "true" : "false");
DPRINTF1("host_matches=%s", lres->host_matches ? "true" : "false");
if (!ISSET(ret, VALIDATE_SUCCESS)) {
/* No matching entries. */
if (pwflag && list_pw == NULL)
SET(ret, FLAG_NO_CHECK);
}
if (pwflag || lres->user_matches)
CLR(ret, FLAG_NO_USER);
if (pwflag || lres->host_matches)
CLR(ret, FLAG_NO_HOST);
DPRINTF1("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret);
debug_return_int(ret);
}
/* /*
* Comparison function for ldap_entry_wrapper structures, descending order. * Comparison function for ldap_entry_wrapper structures, descending order.
*/ */
@@ -2344,27 +1779,36 @@ sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry)
} }
/* /*
* Free the ldap result structure in the sudo_nss handle. * Free the cached results in the sudo_nss handle, if present.
*/ */
static void static void
sudo_ldap_result_free_nss(struct sudo_nss *nss) sudo_ldap_result_free_nss(struct sudo_nss *nss)
{ {
struct sudo_ldap_handle *handle = nss->handle; struct sudo_ldap_handle *handle = nss->handle;
struct member_list *prev_binding = NULL;
struct defaults *def;
struct userspec *us;
debug_decl(sudo_ldap_result_free_nss, SUDOERS_DEBUG_LDAP) debug_decl(sudo_ldap_result_free_nss, SUDOERS_DEBUG_LDAP)
if (handle->result != NULL) { if (handle->pw != NULL)
DPRINTF1("removing reusable search result"); sudo_pw_delref(handle->pw);
sudo_ldap_result_free(handle->result);
handle->username = NULL; /* XXX - do in main module? */
handle->gidlist = NULL; while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
handle->result = NULL; TAILQ_REMOVE(&nss->userspecs, us, entries);
free_userspec(us);
} }
while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
TAILQ_REMOVE(&nss->defaults, def, entries);
free_default(def, &prev_binding);
}
debug_return; debug_return;
} }
/* /*
* Perform the LDAP query for the user or return a cached query if * Perform the LDAP query for the user. The caller is responsible for
* there is one for this user. * freeing the result with sudo_ldap_result_free().
*/ */
static struct ldap_result * static struct ldap_result *
sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw) sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
@@ -2379,23 +1823,6 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
char *filt; char *filt;
debug_decl(sudo_ldap_result_get, SUDOERS_DEBUG_LDAP) debug_decl(sudo_ldap_result_get, SUDOERS_DEBUG_LDAP)
/*
* If we already have a cached result, return it so we don't have to
* have to contact the LDAP server again.
*/
if (handle->result) {
if (handle->gidlist == user_gid_list &&
strcmp(pw->pw_name, handle->username) == 0) {
DPRINTF1("reusing previous result (user %s) with %d entries",
handle->username, handle->result->nentries);
debug_return_ptr(handle->result);
}
/* User mismatch, cached result cannot be used. */
DPRINTF1("removing result (user %s), new search (user %s)",
handle->username, pw->pw_name);
sudo_ldap_result_free_nss(nss);
}
/* /*
* Okay - time to search for anything that matches this user * Okay - time to search for anything that matches this user
* Lets limit it to only two queries of the LDAP server * Lets limit it to only two queries of the LDAP server
@@ -2483,13 +1910,6 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
ldap_entry_compare); ldap_entry_compare);
} }
/* Store everything in the sudo_nss handle. */
/* XXX - store pw and take a reference to it. */
/* XXX - take refs for gidlist and grlist */
handle->result = lres;
handle->username = pw->pw_name;
handle->gidlist = user_gid_list;
debug_return_ptr(lres); debug_return_ptr(lres);
} }
@@ -2503,7 +1923,7 @@ sudo_ldap_close(struct sudo_nss *nss)
debug_decl(sudo_ldap_close, SUDOERS_DEBUG_LDAP) debug_decl(sudo_ldap_close, SUDOERS_DEBUG_LDAP)
if (handle != NULL) { if (handle != NULL) {
/* Free the result before unbinding; it may use the LDAP connection. */ /* Free the cached result. */
sudo_ldap_result_free_nss(nss); sudo_ldap_result_free_nss(nss);
/* Unbind and close the LDAP connection. */ /* Unbind and close the LDAP connection. */
@@ -2519,6 +1939,65 @@ sudo_ldap_close(struct sudo_nss *nss)
debug_return_int(0); debug_return_int(0);
} }
/*
* Perform LDAP query for user and host and convert to sudoers
* parse tree.
*/
static int
sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw)
{
struct sudo_ldap_handle *handle = nss->handle;
struct ldap_result *lres = NULL;
struct userspec *us;
int ret = 0;
LDAP *ld;
debug_decl(sudo_ldap_query, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL)
goto done;
ld = handle->ld;
/* Use cached result if it matches pw. */
if (handle->pw != NULL) {
if (pw == handle->pw)
goto done;
sudo_pw_delref(handle->pw);
handle->pw = NULL;
}
/* Free old userspecs, if any. */
while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
TAILQ_REMOVE(&nss->userspecs, us, entries);
free_userspec(us);
}
DPRINTF1("%s: ldap search user %s, host %s", __func__, pw->pw_name,
user_runhost);
if ((lres = sudo_ldap_result_get(nss, pw)) == NULL)
goto done;
/* Convert to sudoers parse tree. */
if (!ldap_to_sudoers(ld, lres, &nss->userspecs)) {
ret = -1;
goto done;
}
/* Stash a ref to the passwd struct in the handle. */
sudo_pw_addref(pw);
handle->pw = pw;
done:
/* Cleanup. */
sudo_ldap_result_free(lres);
if (ret == -1) {
while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
TAILQ_REMOVE(&nss->userspecs, us, entries);
free_userspec(us);
}
}
debug_return_int(ret);
}
/* /*
* STUB * STUB
*/ */

View File

@@ -241,6 +241,39 @@ oom:
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
bool
sudo_ldap_add_default(const char *var, const char *val, int op,
char *source, struct defaults_list *defs)
{
struct defaults *def;
debug_decl(sudo_ldap_add_default, SUDOERS_DEBUG_LDAP)
if ((def = calloc(1, sizeof(*def))) == NULL)
goto oom;
def->type = DEFAULTS;
def->op = op;
if ((def->var = strdup(var)) == NULL) {
goto oom;
}
if (val != NULL) {
if ((def->val = strdup(val)) == NULL)
goto oom;
}
def->file = source;
rcstr_addref(source);
TAILQ_INSERT_TAIL(defs, def, entries);
debug_return_bool(true);
oom:
if (def != NULL) {
free(def->var);
free(def->val);
free(def);
}
debug_return_bool(false);
}
/* /*
* Convert an LDAP sudoRole to a sudoers privilege. * Convert an LDAP sudoRole to a sudoers privilege.
* Pass in struct berval ** for LDAP or char *** for SSSD. * Pass in struct berval ** for LDAP or char *** for SSSD.
@@ -384,7 +417,15 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
/* Parse sudoOptions. */ /* Parse sudoOptions. */
if (opts != NULL) { if (opts != NULL) {
char *opt; char *opt, *source = NULL;
if (store_options) {
/* Use sudoRole in place of file name in defaults. */
size_t slen = sizeof("sudoRole") + strlen(priv->ldap_role);
if ((source = rcstr_alloc(slen)) == NULL)
goto oom;
snprintf(source, slen, "sudoRole %s", priv->ldap_role);
}
while ((opt = iter(&opts)) != NULL) { while ((opt = iter(&opts)) != NULL) {
char *var, *val; char *var, *val;
@@ -419,23 +460,10 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
} }
#endif /* HAVE_PRIV_SET */ #endif /* HAVE_PRIV_SET */
} else if (store_options) { } else if (store_options) {
struct defaults *def = calloc(1, sizeof(*def)); if (!sudo_ldap_add_default(var, val, op, source,
if (def == NULL) &priv->defaults)) {
goto oom;
def->type = DEFAULTS;
def->op = op;
if ((def->var = strdup(var)) == NULL) {
free(def);
goto oom; goto oom;
} }
if (val != NULL) {
if ((def->val = strdup(val)) == NULL) {
free(def->var);
free(def);
goto oom;
}
}
TAILQ_INSERT_TAIL(&priv->defaults, def, entries);
} else { } else {
/* Convert to tags. */ /* Convert to tags. */
bool handled = true; bool handled = true;
@@ -474,6 +502,7 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
} }
} }
} }
rcstr_delref(source);
} }
/* So we can inherit previous values. */ /* So we can inherit previous values. */

View File

@@ -19,6 +19,7 @@
#include <config.h> #include <config.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
@@ -38,147 +39,57 @@
#include <gram.h> #include <gram.h>
/* /*
* Local prototypes. * Look up the user in the sudoers prase tree for pseudo-commands like
* list, verify and kill.
*/ */
static int display_bound_defaults(int deftype, struct sudo_lbuf *lbuf); static int
static int sudo_file_close(struct sudo_nss *); sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
static int sudo_file_display_bound_defaults(struct sudo_nss *, struct passwd *, struct sudo_lbuf *); int validated, int pwflag)
static int sudo_file_display_cmnd(struct sudo_nss *, struct passwd *);
static int sudo_file_display_defaults(struct sudo_nss *, struct passwd *, struct sudo_lbuf *);
static int sudo_file_display_privs(struct sudo_nss *, struct passwd *, struct sudo_lbuf *);
static int sudo_file_lookup(struct sudo_nss *, int, int);
static int sudo_file_open(struct sudo_nss *);
static int sudo_file_parse(struct sudo_nss *);
static int sudo_file_setdefs(struct sudo_nss *);
/* sudo_nss implementation */
struct sudo_nss sudo_nss_file = {
{ NULL, NULL },
sudo_file_open,
sudo_file_close,
sudo_file_parse,
sudo_file_setdefs,
sudo_file_lookup,
sudo_file_display_cmnd,
sudo_file_display_defaults,
sudo_file_display_bound_defaults,
sudo_file_display_privs
};
int
sudo_file_open(struct sudo_nss *nss)
{ {
debug_decl(sudo_file_open, SUDOERS_DEBUG_NSS) int match;
struct sudo_nss *nss;
if (def_ignore_local_sudoers)
debug_return_int(-1);
nss->handle = open_sudoers(sudoers_file, false, NULL);
debug_return_int(nss->handle ? 0 : -1);
}
int
sudo_file_close(struct sudo_nss *nss)
{
debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
/* Free parser data structures and close sudoers file. */
init_parser(NULL, false);
if (nss->handle != NULL) {
fclose(nss->handle);
nss->handle = NULL;
sudoersin = NULL;
}
debug_return_int(0);
}
/*
* Parse the specified sudoers file.
*/
int
sudo_file_parse(struct sudo_nss *nss)
{
debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS)
if (nss->handle == NULL)
debug_return_int(-1);
init_parser(sudoers_file, false);
sudoersin = nss->handle;
if (sudoersparse() != 0 || parse_error) {
if (errorlineno != -1) {
log_warningx(SLOG_SEND_MAIL, N_("parse error in %s near line %d"),
errorfile, errorlineno);
} else {
log_warningx(SLOG_SEND_MAIL, N_("parse error in %s"), errorfile);
}
debug_return_int(-1);
}
debug_return_int(0);
}
/*
* Wrapper around update_defaults() for nsswitch code.
*/
int
sudo_file_setdefs(struct sudo_nss *nss)
{
debug_decl(sudo_file_setdefs, SUDOERS_DEBUG_NSS)
if (nss->handle == NULL)
debug_return_int(-1);
if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS,
false))
debug_return_int(-1);
debug_return_int(0);
}
/*
* Look up the user in the parsed sudoers file and check to see if they are
* allowed to run the specified command on this host as the target user.
*/
int
sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
{
int match, host_match, runas_match, cmnd_match, timeout;
struct cmndspec *cs; struct cmndspec *cs;
struct cmndtag *tags = NULL;
struct privilege *priv; struct privilege *priv;
struct userspec *us; struct userspec *us;
struct member *matching_user; struct defaults *def;
time_t now; int nopass;
debug_decl(sudo_file_lookup, SUDOERS_DEBUG_NSS) enum def_tuple pwcheck;
debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER)
if (nss->handle == NULL) pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
debug_return_int(validated); nopass = (pwcheck == all) ? true : false;
/* if (list_pw == NULL)
* Only check the actual command if pwflag is not set. SET(validated, FLAG_NO_CHECK);
* It is set for the "validate", "list" and "kill" pseudo-commands. CLR(validated, FLAG_NO_USER);
* Always check the host and user. CLR(validated, FLAG_NO_HOST);
*/ match = DENY;
if (pwflag) { TAILQ_FOREACH(nss, snl, entries) {
int nopass; if (nss->query(nss, pw) == -1) {
enum def_tuple pwcheck; /* The query function should have printed an error message. */
SET(validated, VALIDATE_ERROR);
pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; break;
nopass = (pwcheck == all) ? true : false; }
TAILQ_FOREACH(us, &nss->userspecs, entries) {
if (list_pw == NULL) if (userlist_matches(pw, &us->users) != ALLOW)
SET(validated, FLAG_NO_CHECK);
CLR(validated, FLAG_NO_USER);
CLR(validated, FLAG_NO_HOST);
match = DENY;
TAILQ_FOREACH(us, &userspecs, entries) {
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
continue; continue;
TAILQ_FOREACH(priv, &us->privileges, entries) { TAILQ_FOREACH(priv, &us->privileges, entries) {
if (hostlist_matches(sudo_user.pw, &priv->hostlist) != ALLOW) int priv_nopass = UNSPEC;
if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
continue; continue;
TAILQ_FOREACH(def, &priv->defaults, entries) {
if (strcmp(def->var, "authenticate") == 0)
priv_nopass = def->op;
}
TAILQ_FOREACH(cs, &priv->cmndlist, entries) { TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
if ((pwcheck == any && cs->tags.nopasswd == true) || if (pwcheck == any) {
(pwcheck == all && cs->tags.nopasswd != true)) if (cs->tags.nopasswd == true || priv_nopass == true)
nopass = cs->tags.nopasswd; nopass = true;
} else if (pwcheck == all) {
if (cs->tags.nopasswd != true && priv_nopass != true)
nopass = false;
}
if (match == ALLOW) if (match == ALLOW)
continue; continue;
/* Only check the command when listing another user. */ /* Only check the command when listing another user. */
@@ -189,34 +100,38 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
} }
} }
} }
if (match == ALLOW || user_uid == 0) {
/* User has an entry for this host. */
SET(validated, VALIDATE_SUCCESS);
} else if (match == DENY)
SET(validated, VALIDATE_FAILURE);
if (pwcheck == always && def_authenticate)
SET(validated, FLAG_CHECK_USER);
else if (nopass == true)
SET(validated, FLAG_NOPASSWD);
else
CLR(validated, FLAG_NOPASSWD);
debug_return_int(validated);
} }
if (match == ALLOW || user_uid == 0) {
/* User has an entry for this host. */
SET(validated, VALIDATE_SUCCESS);
} else if (match == DENY)
SET(validated, VALIDATE_FAILURE);
if (pwcheck == always && def_authenticate)
SET(validated, FLAG_CHECK_USER);
else if (nopass == true)
def_authenticate = false;
debug_return_int(validated);
}
/* Need to be runas user while stat'ing things. */ static int
if (!set_perms(PERM_RUNAS)) sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, int *validated,
debug_return_int(validated); struct cmndspec **matching_cs, struct defaults_list **defs, time_t now)
{
int host_match, runas_match, cmnd_match;
struct cmndspec *cs;
struct privilege *priv;
struct userspec *us;
struct member *matching_user;
debug_decl(sudoers_lookup_check, SUDOERS_DEBUG_PARSER)
time(&now); TAILQ_FOREACH_REVERSE(us, &nss->userspecs, userspec_list, entries) {
match = UNSPEC; if (userlist_matches(pw, &us->users) != ALLOW)
TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
continue; continue;
CLR(validated, FLAG_NO_USER); CLR(*validated, FLAG_NO_USER);
TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) { TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
host_match = hostlist_matches(sudo_user.pw, &priv->hostlist); host_match = hostlist_matches(pw, &priv->hostlist);
if (host_match == ALLOW) if (host_match == ALLOW)
CLR(validated, FLAG_NO_HOST); CLR(*validated, FLAG_NO_HOST);
else else
continue; continue;
TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) { TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
@@ -234,63 +149,6 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
if (runas_match == ALLOW) { if (runas_match == ALLOW) {
cmnd_match = cmnd_matches(cs->cmnd); cmnd_match = cmnd_matches(cs->cmnd);
if (cmnd_match != UNSPEC) { if (cmnd_match != UNSPEC) {
match = cmnd_match;
tags = &cs->tags;
timeout = cs->timeout;
#ifdef HAVE_SELINUX
/* Set role and type if not specified on command line. */
if (user_role == NULL) {
if (cs->role != NULL) {
user_role = strdup(cs->role);
if (user_role == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
SET(validated, VALIDATE_ERROR);
goto done;
}
} else {
user_role = def_role;
}
}
if (user_type == NULL) {
if (cs->type != NULL) {
user_type = strdup(cs->type);
if (user_type == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
SET(validated, VALIDATE_ERROR);
goto done;
}
} else {
user_type = def_type;
}
}
#endif /* HAVE_SELINUX */
#ifdef HAVE_PRIV_SET
/* Set Solaris privilege sets */
if (runas_privs == NULL) {
if (cs->privs != NULL) {
runas_privs = strdup(cs->privs);
if (runas_privs == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
SET(validated, VALIDATE_ERROR);
goto done;
}
} else {
runas_privs = def_privs;
}
}
if (runas_limitprivs == NULL) {
if (cs->limitprivs != NULL) {
runas_limitprivs = strdup(cs->limitprivs);
if (runas_limitprivs == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
SET(validated, VALIDATE_ERROR);
goto done;
}
} else {
runas_limitprivs = def_limitprivs;
}
}
#endif /* HAVE_PRIV_SET */
/* /*
* If user is running command as himself, * If user is running command as himself,
* set runas_pw = sudo_user.pw. * set runas_pw = sudo_user.pw.
@@ -301,75 +159,174 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
sudo_pw_addref(sudo_user.pw); sudo_pw_addref(sudo_user.pw);
runas_pw = sudo_user.pw; runas_pw = sudo_user.pw;
} }
goto matched2; *matching_cs = cs;
*defs = &priv->defaults;
debug_return_int(cmnd_match);
} }
} }
} }
} }
} }
matched2: debug_return_int(UNSPEC);
if (match == ALLOW) { }
SET(validated, VALIDATE_SUCCESS);
CLR(validated, VALIDATE_FAILURE); /*
if (timeout > 0) * Apply cmndspec-specific settngs including SELinux role/type,
def_command_timeout = timeout; * Solaris privs, and command tags.
if (tags != NULL) { */
if (tags->nopasswd != UNSPEC) static bool
def_authenticate = !tags->nopasswd; apply_cmndspec(struct cmndspec *cs)
if (tags->noexec != UNSPEC) {
def_noexec = tags->noexec; debug_decl(apply_cmndspec, SUDOERS_DEBUG_PARSER)
if (tags->setenv != UNSPEC)
def_setenv = tags->setenv; if (cs != NULL) {
if (tags->log_input != UNSPEC) #ifdef HAVE_SELINUX
def_log_input = tags->log_input; /* Set role and type if not specified on command line. */
if (tags->log_output != UNSPEC) if (user_role == NULL) {
def_log_output = tags->log_output; if (cs->role != NULL) {
if (tags->send_mail != UNSPEC) { user_role = strdup(cs->role);
if (tags->send_mail) { if (user_role == NULL) {
def_mail_all_cmnds = true; sudo_warnx(U_("%s: %s"), __func__,
} else { U_("unable to allocate memory"));
def_mail_all_cmnds = false; debug_return_bool(false);
def_mail_always = false;
def_mail_no_perms = false;
}
}
if (tags->follow != UNSPEC)
def_sudoedit_follow = tags->follow;
}
} else if (match == DENY) {
SET(validated, VALIDATE_FAILURE);
CLR(validated, VALIDATE_SUCCESS);
if (tags != NULL) {
if (tags->nopasswd != UNSPEC)
def_authenticate = !tags->nopasswd;
if (tags->send_mail != UNSPEC) {
if (tags->send_mail) {
def_mail_all_cmnds = true;
} else {
def_mail_all_cmnds = false;
def_mail_always = false;
def_mail_no_perms = false;
} }
} else {
user_role = def_role;
} }
} }
if (user_type == NULL) {
if (cs->type != NULL) {
user_type = strdup(cs->type);
if (user_type == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
debug_return_bool(false);
}
} else {
user_type = def_type;
}
}
#endif /* HAVE_SELINUX */
#ifdef HAVE_PRIV_SET
/* Set Solaris privilege sets */
if (runas_privs == NULL) {
if (cs->privs != NULL) {
runas_privs = strdup(cs->privs);
if (runas_privs == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
debug_return_bool(false);
}
} else {
runas_privs = def_privs;
}
}
if (runas_limitprivs == NULL) {
if (cs->limitprivs != NULL) {
runas_limitprivs = strdup(cs->limitprivs);
if (runas_limitprivs == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
debug_return_bool(false);
}
} else {
runas_limitprivs = def_limitprivs;
}
}
#endif /* HAVE_PRIV_SET */
if (cs->timeout > 0)
def_command_timeout = cs->timeout;
if (cs->tags.nopasswd != UNSPEC)
def_authenticate = !cs->tags.nopasswd;
if (cs->tags.noexec != UNSPEC)
def_noexec = cs->tags.noexec;
if (cs->tags.setenv != UNSPEC)
def_setenv = cs->tags.setenv;
if (cs->tags.log_input != UNSPEC)
def_log_input = cs->tags.log_input;
if (cs->tags.log_output != UNSPEC)
def_log_output = cs->tags.log_output;
if (cs->tags.send_mail != UNSPEC) {
if (cs->tags.send_mail) {
def_mail_all_cmnds = true;
} else {
def_mail_all_cmnds = false;
def_mail_always = false;
def_mail_no_perms = false;
}
}
if (cs->tags.follow != UNSPEC)
def_sudoedit_follow = cs->tags.follow;
}
debug_return_bool(true);
}
/*
* Look up the user in the sudoers prase tree and check to see if they are
* allowed to run the specified command on this host as the target user.
*/
int
sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated,
int pwflag)
{
struct defaults_list *defs = NULL;
struct cmndspec *cs = NULL;
struct sudo_nss *nss;
int m, match = UNSPEC;
time_t now;
debug_decl(sudoers_lookup, SUDOERS_DEBUG_PARSER)
/*
* Special case checking the "validate", "list" and "kill" pseudo-commands.
*/
if (pwflag)
debug_return_int(sudoers_lookup_pseudo(snl, pw, validated, pwflag));
/* Need to be runas user while stat'ing things. */
if (!set_perms(PERM_RUNAS))
debug_return_int(validated);
/* Query each sudoers source and check the user. */
time(&now);
TAILQ_FOREACH(nss, snl, entries) {
if (nss->query(nss, pw) == -1) {
/* The query function should have printed an error message. */
SET(validated, VALIDATE_ERROR);
break;
}
m = sudoers_lookup_check(nss, pw, &validated, &cs, &defs, now);
if (m != UNSPEC)
match = m;
if (!sudo_nss_can_continue(nss, m))
break;
}
if (defs != NULL)
update_defaults(defs, SETDEF_GENERIC, false);
if (match != UNSPEC) {
if (!apply_cmndspec(cs))
SET(validated, VALIDATE_ERROR);
else if (match == ALLOW)
SET(validated, VALIDATE_SUCCESS);
else
SET(validated, VALIDATE_FAILURE);
} }
#if defined(HAVE_SELINUX) || defined(HAVE_PRIV_SET)
done:
#endif
if (!restore_perms()) if (!restore_perms())
SET(validated, VALIDATE_ERROR); SET(validated, VALIDATE_ERROR);
debug_return_int(validated); debug_return_int(validated);
} }
static int static int
sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, display_priv_short(struct passwd *pw, struct userspec *us,
struct sudo_lbuf *lbuf) struct sudo_lbuf *lbuf)
{ {
struct cmndspec *cs, *prev_cs; struct cmndspec *cs, *prev_cs;
struct member *m; struct member *m;
struct privilege *priv; struct privilege *priv;
int nfound = 0; int nfound = 0;
debug_decl(sudo_file_display_priv_short, SUDOERS_DEBUG_NSS) debug_decl(display_priv_short, SUDOERS_DEBUG_PARSER)
TAILQ_FOREACH(priv, &us->privileges, entries) { TAILQ_FOREACH(priv, &us->privileges, entries) {
if (hostlist_matches(pw, &priv->hostlist) != ALLOW) if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
@@ -421,39 +378,41 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
static bool static bool
new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs) new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs)
{ {
debug_decl(new_long_entry, SUDOERS_DEBUG_PARSER)
if (prev_cs == NULL) if (prev_cs == NULL)
return true; debug_return_bool(true);
if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(prev_cs->tags, cs->tags)) if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(prev_cs->tags, cs->tags))
return true; debug_return_bool(true);
#ifdef HAVE_PRIV_SET #ifdef HAVE_PRIV_SET
if (cs->privs && (!prev_cs->privs || strcmp(cs->privs, prev_cs->privs) != 0)) if (cs->privs && (!prev_cs->privs || strcmp(cs->privs, prev_cs->privs) != 0))
return true; debug_return_bool(true);
if (cs->limitprivs && (!prev_cs->limitprivs || strcmp(cs->limitprivs, prev_cs->limitprivs) != 0)) if (cs->limitprivs && (!prev_cs->limitprivs || strcmp(cs->limitprivs, prev_cs->limitprivs) != 0))
return true; debug_return_bool(true);
#endif /* HAVE_PRIV_SET */ #endif /* HAVE_PRIV_SET */
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
if (cs->role && (!prev_cs->role || strcmp(cs->role, prev_cs->role) != 0)) if (cs->role && (!prev_cs->role || strcmp(cs->role, prev_cs->role) != 0))
return true; debug_return_bool(true);
if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0)) if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0))
return true; debug_return_bool(true);
#endif /* HAVE_SELINUX */ #endif /* HAVE_SELINUX */
if (cs->timeout != prev_cs->timeout) if (cs->timeout != prev_cs->timeout)
return true; debug_return_bool(true);
if (cs->notbefore != prev_cs->notbefore) if (cs->notbefore != prev_cs->notbefore)
return true; debug_return_bool(true);
if (cs->notafter != prev_cs->notafter) if (cs->notafter != prev_cs->notafter)
return true; debug_return_bool(true);
return false; debug_return_bool(false);
} }
static int static int
sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, display_priv_long(struct passwd *pw, struct userspec *us,
struct sudo_lbuf *lbuf) struct sudo_lbuf *lbuf)
{ {
struct cmndspec *cs, *prev_cs; struct cmndspec *cs, *prev_cs;
struct privilege *priv; struct privilege *priv;
int nfound = 0, olen; int nfound = 0, olen;
debug_decl(sudo_file_display_priv_long, SUDOERS_DEBUG_NSS) debug_decl(display_priv_long, SUDOERS_DEBUG_PARSER)
TAILQ_FOREACH(priv, &us->privileges, entries) { TAILQ_FOREACH(priv, &us->privileges, entries) {
if (hostlist_matches(pw, &priv->hostlist) != ALLOW) if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
@@ -559,65 +518,46 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
debug_return_int(nfound); debug_return_int(nfound);
} }
/* XXX - better naming */ static int
int
sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw,
struct sudo_lbuf *lbuf) struct sudo_lbuf *lbuf)
{ {
struct userspec *us; struct userspec *us;
int nfound = 0; int nfound = 0;
debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_NSS) debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_PARSER)
TAILQ_FOREACH(us, usl, entries) { TAILQ_FOREACH(us, usl, entries) {
if (userlist_matches(pw, &us->users) != ALLOW) if (userlist_matches(pw, &us->users) != ALLOW)
continue; continue;
if (long_list) if (long_list)
nfound += sudo_file_display_priv_long(pw, us, lbuf); nfound += display_priv_long(pw, us, lbuf);
else else
nfound += sudo_file_display_priv_short(pw, us, lbuf); nfound += display_priv_short(pw, us, lbuf);
} }
if (sudo_lbuf_error(lbuf)) if (sudo_lbuf_error(lbuf))
debug_return_int(-1); debug_return_int(-1);
debug_return_int(nfound); debug_return_int(nfound);
} }
/*
* Returns the number of matching privileges or -1 on error.
*/
static int
sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
debug_decl(sudo_file_display_priv, SUDOERS_DEBUG_NSS)
if (nss->handle == NULL)
debug_return_int(0);
debug_return_int(sudo_display_userspecs(&userspecs, pw, lbuf));
}
/* /*
* Display matching Defaults entries for the given user on this host. * Display matching Defaults entries for the given user on this host.
*/ */
int static int
sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw, display_defaults(struct defaults_list *defs, struct passwd *pw,
struct sudo_lbuf *lbuf) struct sudo_lbuf *lbuf)
{ {
struct defaults *d; struct defaults *d;
char *prefix; char *prefix;
int nfound = 0; int nfound = 0;
debug_decl(sudo_file_display_defaults, SUDOERS_DEBUG_NSS) debug_decl(display_defaults, SUDOERS_DEBUG_PARSER)
if (nss->handle == NULL)
goto done;
if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
prefix = " "; prefix = " ";
else else
prefix = ", "; prefix = ", ";
TAILQ_FOREACH(d, &defaults, entries) { TAILQ_FOREACH(d, defs, entries) {
switch (d->type) { switch (d->type) {
case DEFAULTS_HOST: case DEFAULTS_HOST:
if (hostlist_matches(pw, d->binding) != ALLOW) if (hostlist_matches(pw, d->binding) != ALLOW)
@@ -636,26 +576,6 @@ sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
prefix = ", "; prefix = ", ";
nfound++; nfound++;
} }
if (sudo_lbuf_error(lbuf))
debug_return_int(-1);
done:
debug_return_int(nfound);
}
/*
* Display Defaults entries that are per-runas or per-command
*/
int
sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
int nfound = 0;
debug_decl(sudo_file_display_bound_defaults, SUDOERS_DEBUG_NSS)
/* XXX - should only print ones that match what the user can do. */
nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
if (sudo_lbuf_error(lbuf)) if (sudo_lbuf_error(lbuf))
debug_return_int(-1); debug_return_int(-1);
debug_return_int(nfound); debug_return_int(nfound);
@@ -665,14 +585,15 @@ sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
* Display Defaults entries of the given type. * Display Defaults entries of the given type.
*/ */
static int static int
display_bound_defaults(int deftype, struct sudo_lbuf *lbuf) display_bound_defaults_by_type(struct defaults_list *defs, int deftype,
struct sudo_lbuf *lbuf)
{ {
struct defaults *d; struct defaults *d;
struct member_list *binding = NULL; struct member_list *binding = NULL;
struct member *m; struct member *m;
char *dsep; char *dsep;
int atype, nfound = 0; int atype, nfound = 0;
debug_decl(display_bound_defaults, SUDOERS_DEBUG_NSS) debug_decl(display_bound_defaults_by_type, SUDOERS_DEBUG_PARSER)
switch (deftype) { switch (deftype) {
case DEFAULTS_HOST: case DEFAULTS_HOST:
@@ -694,7 +615,7 @@ display_bound_defaults(int deftype, struct sudo_lbuf *lbuf)
default: default:
debug_return_int(-1); debug_return_int(-1);
} }
TAILQ_FOREACH(d, &defaults, entries) { TAILQ_FOREACH(d, defs, entries) {
if (d->type != deftype) if (d->type != deftype)
continue; continue;
@@ -721,51 +642,208 @@ display_bound_defaults(int deftype, struct sudo_lbuf *lbuf)
} }
/* /*
* Returns 0 if the command is allowed, 1 if not or -1 on error. * Display Defaults entries that are per-runas or per-command
*/
static int
display_bound_defaults(struct defaults_list *defs, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
int nfound = 0;
debug_decl(display_bound_defaults, SUDOERS_DEBUG_PARSER)
/* XXX - should only print ones that match what the user can do. */
nfound += display_bound_defaults_by_type(defs, DEFAULTS_RUNAS, lbuf);
nfound += display_bound_defaults_by_type(defs, DEFAULTS_CMND, lbuf);
if (sudo_lbuf_error(lbuf))
debug_return_int(-1);
debug_return_int(nfound);
}
static int
output(const char *buf)
{
struct sudo_conv_message msg;
struct sudo_conv_reply repl;
debug_decl(output, SUDOERS_DEBUG_NSS)
/* Call conversation function */
memset(&msg, 0, sizeof(msg));
msg.msg_type = SUDO_CONV_INFO_MSG;
msg.msg = buf;
memset(&repl, 0, sizeof(repl));
if (sudo_conv(1, &msg, &repl, NULL) == -1)
debug_return_int(0);
debug_return_int(strlen(buf));
}
/*
* Print out privileges for the specified user.
* Returns true on success or -1 on error.
*/ */
int int
sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw) display_privs(struct sudo_nss_list *snl, struct passwd *pw)
{ {
struct sudo_nss *nss;
struct sudo_lbuf def_buf, priv_buf;
struct stat sb;
int cols, count, olen, n;
debug_decl(display_privs, SUDOERS_DEBUG_PARSER)
/* Query all sudoers sources first. */
TAILQ_FOREACH(nss, snl, entries) {
if (nss->query(nss, pw) == -1) {
/* The query function should have printed an error message. */
debug_return_int(-1);
}
}
cols = sudo_user.cols;
if (fstat(STDOUT_FILENO, &sb) == 0 && S_ISFIFO(sb.st_mode))
cols = 0;
sudo_lbuf_init(&def_buf, output, 4, NULL, cols);
sudo_lbuf_init(&priv_buf, output, 8, NULL, cols);
sudo_lbuf_append(&def_buf, _("Matching Defaults entries for %s on %s:\n"),
pw->pw_name, user_srunhost);
count = 0;
TAILQ_FOREACH(nss, snl, entries) {
n = display_defaults(&nss->defaults, pw, &def_buf);
if (n == -1)
goto bad;
count += n;
}
if (count != 0) {
sudo_lbuf_append(&def_buf, "\n\n");
} else {
/* Undo Defaults header. */
def_buf.len = 0;
}
/* Display Runas and Cmnd-specific defaults. */
olen = def_buf.len;
sudo_lbuf_append(&def_buf, _("Runas and Command-specific defaults for %s:\n"),
pw->pw_name);
count = 0;
TAILQ_FOREACH(nss, snl, entries) {
n = display_bound_defaults(&nss->defaults, pw, &def_buf);
if (n == -1)
goto bad;
count += n;
}
if (count != 0) {
sudo_lbuf_append(&def_buf, "\n\n");
} else {
/* Undo Defaults header. */
def_buf.len = olen;
}
/* Display privileges from all sources. */
sudo_lbuf_append(&priv_buf,
_("User %s may run the following commands on %s:\n"),
pw->pw_name, user_srunhost);
count = 0;
TAILQ_FOREACH(nss, snl, entries) {
n = sudo_display_userspecs(&nss->userspecs, pw, &priv_buf);
if (n == -1)
goto bad;
count += n;
}
if (count == 0) {
def_buf.len = 0;
priv_buf.len = 0;
sudo_lbuf_append(&priv_buf,
_("User %s is not allowed to run sudo on %s.\n"),
pw->pw_name, user_shost);
}
if (sudo_lbuf_error(&def_buf) || sudo_lbuf_error(&priv_buf))
goto bad;
sudo_lbuf_print(&def_buf);
sudo_lbuf_print(&priv_buf);
sudo_lbuf_destroy(&def_buf);
sudo_lbuf_destroy(&priv_buf);
debug_return_int(true);
bad:
sudo_lbuf_destroy(&def_buf);
sudo_lbuf_destroy(&priv_buf);
debug_return_int(-1);
}
static int
display_cmnd_check(struct sudo_nss *nss, struct passwd *pw, time_t now)
{
int host_match, runas_match, cmnd_match;
struct cmndspec *cs; struct cmndspec *cs;
struct member *match;
struct privilege *priv; struct privilege *priv;
struct userspec *us; struct userspec *us;
int ret = 1; debug_decl(display_cmnd_check, SUDOERS_DEBUG_PARSER)
int host_match, runas_match, cmnd_match;
debug_decl(sudo_file_display_cmnd, SUDOERS_DEBUG_NSS)
if (nss->handle == NULL) TAILQ_FOREACH_REVERSE(us, &nss->userspecs, userspec_list, entries) {
goto done;
match = NULL;
TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
if (userlist_matches(pw, &us->users) != ALLOW) if (userlist_matches(pw, &us->users) != ALLOW)
continue; continue;
TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) { TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
host_match = hostlist_matches(pw, &priv->hostlist); host_match = hostlist_matches(pw, &priv->hostlist);
if (host_match != ALLOW) if (host_match != ALLOW)
continue; continue;
TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) { TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
if (cs->notbefore != UNSPEC) {
if (now < cs->notbefore)
continue;
}
if (cs->notafter != UNSPEC) {
if (now > cs->notafter)
continue;
}
runas_match = runaslist_matches(cs->runasuserlist, runas_match = runaslist_matches(cs->runasuserlist,
cs->runasgrouplist, NULL, NULL); cs->runasgrouplist, NULL, NULL);
if (runas_match == ALLOW) { if (runas_match == ALLOW) {
cmnd_match = cmnd_matches(cs->cmnd); cmnd_match = cmnd_matches(cs->cmnd);
if (cmnd_match != UNSPEC) { if (cmnd_match != UNSPEC)
if (cmnd_match == ALLOW) debug_return_int(cmnd_match);
match = cs->cmnd;
goto matched;
}
} }
} }
} }
} }
matched: debug_return_int(UNSPEC);
if (match != NULL && !match->negated) { }
/*
* Check user_cmnd against sudoers and print the matching entry if the
* command is allowed.
* Returns true if the command is allowed, false if not or -1 on error.
*/
int
display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
{
struct sudo_nss *nss;
int m, match = UNSPEC;
int ret = false;
time_t now;
debug_decl(display_cmnd, SUDOERS_DEBUG_PARSER)
/* Iterate over each source, checking for the command. */
time(&now);
TAILQ_FOREACH(nss, snl, entries) {
if (nss->query(nss, pw) == -1) {
/* The query function should have printed an error message. */
debug_return_int(-1);
}
m = display_cmnd_check(nss, pw, now);
if (m != UNSPEC)
match = m;
if (!sudo_nss_can_continue(nss, m))
break;
}
if (match == ALLOW) {
const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
safe_cmnd, user_args ? " " : "", user_args ? user_args : ""); safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
ret = len < 0 ? -1 : 0; ret = len < 0 ? -1 : true;
} }
done:
debug_return_int(ret); debug_return_int(ret);
} }

View File

@@ -318,10 +318,13 @@ unsigned char *sudo_filedigest(int fd, const char *file, int digest_type, size_t
const char *digest_type_to_name(int digest_type); const char *digest_type_to_name(int digest_type);
/* parse.c */ /* parse.c */
struct sudo_lbuf; struct sudo_nss_list;
int sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, struct sudo_lbuf *lbuf); int sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, int pwflag);
int display_privs(struct sudo_nss_list *snl, struct passwd *pw);
int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw);
/* fmtsudoers.c */ /* fmtsudoers.c */
struct sudo_lbuf;
bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, struct cmndspec *prev_cs, bool expand_aliases); bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, struct cmndspec *prev_cs, bool expand_aliases);
bool sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d); bool sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d);
bool sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, struct defaults **next, bool expand_aliases); bool sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, struct defaults **next, bool expand_aliases);

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,9 @@
/* Iterators used by sudo_ldap_role_to_priv() to handle bervar ** or char ** */ /* Iterators used by sudo_ldap_role_to_priv() to handle bervar ** or char ** */
typedef char * (*sudo_ldap_iter_t)(void **); typedef char * (*sudo_ldap_iter_t)(void **);
/* ldap_common.c */ /* ldap_util.c */
bool sudo_ldap_is_negated(char **valp); bool sudo_ldap_is_negated(char **valp);
bool sudo_ldap_add_default(const char *var, const char *val, int op, char *source, struct defaults_list *defs);
int sudo_ldap_parse_option(char *optstr, char **varp, char **valp); int sudo_ldap_parse_option(char *optstr, char **varp, char **valp);
struct privilege *sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, bool warnings, bool store_options, sudo_ldap_iter_t iter); struct privilege *sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, void *runasgroups, void *cmnds, void *opts, const char *notbefore, const char *notafter, bool warnings, bool store_options, sudo_ldap_iter_t iter);
struct sudo_digest *sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest); struct sudo_digest *sudo_ldap_extract_digest(char **cmnd, struct sudo_digest *digest);

View File

@@ -43,6 +43,18 @@ extern struct sudo_nss sudo_nss_ldap;
extern struct sudo_nss sudo_nss_sss; extern struct sudo_nss sudo_nss_sss;
#endif #endif
static void
sudo_nss_insert(struct sudo_nss_list *snl, struct sudo_nss *nss)
{
debug_decl(sudo_nss_insert, SUDOERS_DEBUG_NSS)
TAILQ_INIT(&nss->userspecs);
TAILQ_INIT(&nss->defaults);
TAILQ_INSERT_TAIL(snl, nss, entries);
debug_return;
}
/* Make sure we have not already inserted the nss entry. */ /* Make sure we have not already inserted the nss entry. */
#define SUDO_NSS_CHECK_UNUSED(nss, tag) \ #define SUDO_NSS_CHECK_UNUSED(nss, tag) \
if (nss.entries.tqe_next != NULL || nss.entries.tqe_prev != NULL) { \ if (nss.entries.tqe_next != NULL || nss.entries.tqe_prev != NULL) { \
@@ -91,18 +103,18 @@ sudo_read_nss(void)
for ((cp = strtok_r(line + 8, " \t", &last)); cp != NULL; (cp = strtok_r(NULL, " \t", &last))) { for ((cp = strtok_r(line + 8, " \t", &last)); cp != NULL; (cp = strtok_r(NULL, " \t", &last))) {
if (strcasecmp(cp, "files") == 0 && !saw_files) { if (strcasecmp(cp, "files") == 0 && !saw_files) {
SUDO_NSS_CHECK_UNUSED(sudo_nss_file, "files"); SUDO_NSS_CHECK_UNUSED(sudo_nss_file, "files");
TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries); sudo_nss_insert(&snl, &sudo_nss_file);
got_match = saw_files = true; got_match = saw_files = true;
#ifdef HAVE_LDAP #ifdef HAVE_LDAP
} else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) { } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
SUDO_NSS_CHECK_UNUSED(sudo_nss_ldap, "ldap"); SUDO_NSS_CHECK_UNUSED(sudo_nss_ldap, "ldap");
TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries); sudo_nss_insert(&snl, &sudo_nss_ldap);
got_match = saw_ldap = true; got_match = saw_ldap = true;
#endif #endif
#ifdef HAVE_SSSD #ifdef HAVE_SSSD
} else if (strcasecmp(cp, "sss") == 0 && !saw_sss) { } else if (strcasecmp(cp, "sss") == 0 && !saw_sss) {
SUDO_NSS_CHECK_UNUSED(sudo_nss_sss, "sss"); SUDO_NSS_CHECK_UNUSED(sudo_nss_sss, "sss");
TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries); sudo_nss_insert(&snl, &sudo_nss_sss);
got_match = saw_sss = true; got_match = saw_sss = true;
#endif #endif
} else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) { } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
@@ -125,7 +137,7 @@ sudo_read_nss(void)
nomatch: nomatch:
/* Default to files only if no matches */ /* Default to files only if no matches */
if (TAILQ_EMPTY(&snl)) if (TAILQ_EMPTY(&snl))
TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries); sudo_nss_insert(&snl, &sudo_nss_file);
debug_return_ptr(&snl); debug_return_ptr(&snl);
} }
@@ -178,20 +190,20 @@ sudo_read_nss(void)
if (!saw_files && strncasecmp(cp, "files", 5) == 0 && if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
(isspace((unsigned char)cp[5]) || cp[5] == '\0')) { (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries); sudo_nss_insert(&snl, &sudo_nss_file);
got_match = saw_files = true; got_match = saw_files = true;
ep = &cp[5]; ep = &cp[5];
#ifdef HAVE_LDAP #ifdef HAVE_LDAP
} else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 && } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
(isspace((unsigned char)cp[4]) || cp[4] == '\0')) { (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries); sudo_nss_insert(&snl, &sudo_nss_ldap);
got_match = saw_ldap = true; got_match = saw_ldap = true;
ep = &cp[4]; ep = &cp[4];
#endif #endif
#ifdef HAVE_SSSD #ifdef HAVE_SSSD
} else if (!saw_sss && strncasecmp(cp, "sss", 3) == 0 && } else if (!saw_sss && strncasecmp(cp, "sss", 3) == 0 &&
(isspace((unsigned char)cp[3]) || cp[3] == '\0')) { (isspace((unsigned char)cp[3]) || cp[3] == '\0')) {
TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries); sudo_nss_insert(&snl, &sudo_nss_sss);
got_match = saw_sss = true; got_match = saw_sss = true;
ep = &cp[3]; ep = &cp[3];
#endif #endif
@@ -218,7 +230,7 @@ sudo_read_nss(void)
nomatch: nomatch:
/* Default to files only if no matches */ /* Default to files only if no matches */
if (TAILQ_EMPTY(&snl)) if (TAILQ_EMPTY(&snl))
TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries); sudo_nss_insert(&snl, &sudo_nss_file);
debug_return_ptr(&snl); debug_return_ptr(&snl);
} }
@@ -235,12 +247,12 @@ sudo_read_nss(void)
debug_decl(sudo_read_nss, SUDOERS_DEBUG_NSS) debug_decl(sudo_read_nss, SUDOERS_DEBUG_NSS)
# ifdef HAVE_SSSD # ifdef HAVE_SSSD
TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries); sudo_nss_insert(&snl, &sudo_nss_sss);
# endif # endif
# ifdef HAVE_LDAP # ifdef HAVE_LDAP
TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries); sudo_nss_insert(&snl, &sudo_nss_ldap);
# endif # endif
TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries); sudo_nss_insert(&snl, &sudo_nss_file);
debug_return_ptr(&snl); debug_return_ptr(&snl);
} }
@@ -249,132 +261,18 @@ sudo_read_nss(void)
#endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */ #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
static int bool
output(const char *buf) sudo_nss_can_continue(struct sudo_nss *nss, int match)
{ {
struct sudo_conv_message msg; debug_decl(sudo_nss_should_continue, SUDOERS_DEBUG_NSS)
struct sudo_conv_reply repl;
debug_decl(output, SUDOERS_DEBUG_NSS)
/* Call conversation function */ /* Handle [NOTFOUND=return] */
memset(&msg, 0, sizeof(msg)); if (nss->ret_if_notfound && match == UNSPEC)
msg.msg_type = SUDO_CONV_INFO_MSG; debug_return_bool(false);
msg.msg = buf;
memset(&repl, 0, sizeof(repl)); /* Handle [SUCCESS=return] */
if (sudo_conv(1, &msg, &repl, NULL) == -1) if (nss->ret_if_found && match != UNSPEC)
debug_return_int(0); debug_return_bool(false);
debug_return_int(strlen(buf));
} debug_return_bool(true);
/*
* Print out privileges for the specified user.
* Returns true on success or -1 on error.
*/
int
display_privs(struct sudo_nss_list *snl, struct passwd *pw)
{
struct sudo_nss *nss;
struct sudo_lbuf defs, privs;
struct stat sb;
int cols, count, olen;
debug_decl(display_privs, SUDOERS_DEBUG_NSS)
cols = sudo_user.cols;
if (fstat(STDOUT_FILENO, &sb) == 0 && S_ISFIFO(sb.st_mode))
cols = 0;
sudo_lbuf_init(&defs, output, 4, NULL, cols);
sudo_lbuf_init(&privs, output, 8, NULL, cols);
/* Display defaults from all sources. */
sudo_lbuf_append(&defs, _("Matching Defaults entries for %s on %s:\n"),
pw->pw_name, user_srunhost);
count = 0;
TAILQ_FOREACH(nss, snl, entries) {
const int n = nss->display_defaults(nss, pw, &defs);
if (n == -1)
goto bad;
count += n;
}
if (count) {
sudo_lbuf_append(&defs, "\n\n");
} else {
/* Undo Defaults header. */
defs.len = 0;
}
/* Display Runas and Cmnd-specific defaults from all sources. */
olen = defs.len;
sudo_lbuf_append(&defs, _("Runas and Command-specific defaults for %s:\n"),
pw->pw_name);
count = 0;
TAILQ_FOREACH(nss, snl, entries) {
const int n = nss->display_bound_defaults(nss, pw, &defs);
if (n == -1)
goto bad;
count += n;
}
if (count) {
sudo_lbuf_append(&defs, "\n\n");
} else {
/* Undo Defaults header. */
defs.len = olen;
}
/* Display privileges from all sources. */
sudo_lbuf_append(&privs,
_("User %s may run the following commands on %s:\n"),
pw->pw_name, user_srunhost);
count = 0;
TAILQ_FOREACH(nss, snl, entries) {
const int n = nss->display_privs(nss, pw, &privs);
if (n == -1)
goto bad;
count += n;
}
if (count == 0) {
defs.len = 0;
privs.len = 0;
sudo_lbuf_append(&privs,
_("User %s is not allowed to run sudo on %s.\n"),
pw->pw_name, user_shost);
}
if (sudo_lbuf_error(&defs) || sudo_lbuf_error(&privs))
goto bad;
sudo_lbuf_print(&defs);
sudo_lbuf_print(&privs);
sudo_lbuf_destroy(&defs);
sudo_lbuf_destroy(&privs);
debug_return_int(true);
bad:
sudo_lbuf_destroy(&defs);
sudo_lbuf_destroy(&privs);
debug_return_int(-1);
}
/*
* Check user_cmnd against sudoers and print the matching entry if the
* command is allowed.
* Returns true if the command is allowed, false if not or -1 on error.
*/
int
display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
{
struct sudo_nss *nss;
debug_decl(display_cmnd, SUDOERS_DEBUG_NSS)
/* XXX - display_cmnd return value is backwards */
/* XXX - doesn't handle commands allowed by one backend denied by another. */
TAILQ_FOREACH(nss, snl, entries) {
switch (nss->display_cmnd(nss, pw)) {
case 0:
debug_return_int(true);
case -1:
debug_return_int(-1);
}
}
debug_return_int(false);
} }

View File

@@ -25,19 +25,18 @@ struct sudo_nss {
int (*open)(struct sudo_nss *nss); int (*open)(struct sudo_nss *nss);
int (*close)(struct sudo_nss *nss); int (*close)(struct sudo_nss *nss);
int (*parse)(struct sudo_nss *nss); int (*parse)(struct sudo_nss *nss);
int (*setdefs)(struct sudo_nss *nss); int (*query)(struct sudo_nss *nss, struct passwd *pw);
int (*lookup)(struct sudo_nss *nss, int, int); int (*getdefs)(struct sudo_nss *nss);
int (*display_cmnd)(struct sudo_nss *nss, struct passwd *);
int (*display_defaults)(struct sudo_nss *nss, struct passwd *, struct sudo_lbuf *);
int (*display_bound_defaults)(struct sudo_nss *nss, struct passwd *, struct sudo_lbuf *);
int (*display_privs)(struct sudo_nss *nss, struct passwd *, struct sudo_lbuf *);
void *handle; void *handle;
short ret_if_found; bool ret_if_found;
short ret_if_notfound; bool ret_if_notfound;
struct defaults_list defaults;
struct userspec_list userspecs;
}; };
TAILQ_HEAD(sudo_nss_list, sudo_nss); TAILQ_HEAD(sudo_nss_list, sudo_nss);
struct sudo_nss_list *sudo_read_nss(void); struct sudo_nss_list *sudo_read_nss(void);
bool sudo_nss_can_continue(struct sudo_nss *nss, int match);
#endif /* SUDOERS_NSS_H */ #endif /* SUDOERS_NSS_H */

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1993-1996, 1998-2017 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 1993-1996, 1998-2018 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -59,6 +59,7 @@
#include <ctype.h> #include <ctype.h>
#include "sudoers.h" #include "sudoers.h"
#include "parse.h"
#include "auth/sudo_auth.h" #include "auth/sudo_auth.h"
#ifndef HAVE_GETADDRINFO #ifndef HAVE_GETADDRINFO
@@ -189,11 +190,13 @@ sudoers_policy_init(void *info, char * const envp[])
*/ */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
sudo_warn_set_locale_func(sudoers_warn_setlocale); sudo_warn_set_locale_func(sudoers_warn_setlocale);
init_parser(sudoers_file, false);
TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) { TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
if (nss->open(nss) == 0 && nss->parse(nss) == 0) { if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
sources++; sources++;
if (nss->setdefs(nss) != 0) { if (nss->getdefs(nss) != 0 || !update_defaults(&nss->defaults,
log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR, SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
N_("problem with defaults entries")); N_("problem with defaults entries"));
} }
} else { } else {
@@ -228,7 +231,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
char *iolog_path = NULL; char *iolog_path = NULL;
mode_t cmnd_umask = ACCESSPERMS; mode_t cmnd_umask = ACCESSPERMS;
struct sudo_nss *nss; struct sudo_nss *nss;
int nopass = -1;
int cmnd_status = -1, oldlocale, validated; int cmnd_status = -1, oldlocale, validated;
int ret = -1; int ret = -1;
debug_decl(sudoers_policy_main, SUDOERS_DEBUG_PLUGIN) debug_decl(sudoers_policy_main, SUDOERS_DEBUG_PLUGIN)
@@ -307,54 +309,12 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
* Check sudoers sources, using the locale specified in sudoers. * Check sudoers sources, using the locale specified in sudoers.
*/ */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
validated = FLAG_NO_USER | FLAG_NO_HOST; validated = sudoers_lookup(snl, sudo_user.pw, FLAG_NO_USER | FLAG_NO_HOST,
TAILQ_FOREACH(nss, snl, entries) { pwflag);
validated = nss->lookup(nss, validated, pwflag); if (ISSET(validated, VALIDATE_ERROR)) {
/* The lookup function should have printed an error. */
/* goto done;
* The NOPASSWD tag needs special handling among all sources
* in -l or -v mode.
*/
if (pwflag) {
enum def_tuple pwcheck =
(pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
switch (pwcheck) {
case all:
if (!ISSET(validated, FLAG_NOPASSWD))
nopass = false;
else if (nopass == -1)
nopass = true;
break;
case any:
if (ISSET(validated, FLAG_NOPASSWD))
nopass = true;
break;
case never:
nopass = true;
break;
case always:
nopass = false;
break;
default:
break;
}
}
if (ISSET(validated, VALIDATE_ERROR)) {
/* The lookup function should have printed an error. */
goto done;
} else if (ISSET(validated, VALIDATE_SUCCESS)) {
/* Handle [SUCCESS=return] */
if (nss->ret_if_found)
break;
} else {
/* Handle [NOTFOUND=return] */
if (nss->ret_if_notfound)
break;
}
} }
if (pwflag && nopass == true)
def_authenticate = false;
/* Restore user's locale. */ /* Restore user's locale. */
sudoers_setlocale(oldlocale, NULL); sudoers_setlocale(oldlocale, NULL);
@@ -546,6 +506,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
} }
if (def_group_plugin) if (def_group_plugin)
group_plugin_unload(); group_plugin_unload();
init_parser(NULL, false);
if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) { if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
/* ret already set appropriately */ /* ret already set appropriately */
@@ -801,8 +762,9 @@ init_vars(char * const envp[])
static int static int
set_cmnd(void) set_cmnd(void)
{ {
int ret = FOUND; struct sudo_nss *nss;
char *path = user_path; char *path = user_path;
int ret = FOUND;
debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN) debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN)
/* Allocate user_stat for find_path() and match functions. */ /* Allocate user_stat for find_path() and match functions. */
@@ -890,9 +852,11 @@ set_cmnd(void)
else else
user_base = user_cmnd; user_base = user_cmnd;
if (!update_defaults(SETDEF_CMND, false)) { TAILQ_FOREACH(nss, snl, entries) {
log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR, if (!update_defaults(&nss->defaults, SETDEF_CMND, false)) {
N_("problem with defaults entries")); log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
N_("problem with defaults entries"));
}
} }
debug_return_int(ret); debug_return_int(ret);

View File

@@ -137,7 +137,6 @@ struct sudo_user {
#define FLAG_NO_CHECK 0x080 #define FLAG_NO_CHECK 0x080
#define FLAG_NON_INTERACTIVE 0x100 #define FLAG_NON_INTERACTIVE 0x100
#define FLAG_BAD_PASSWORD 0x200 #define FLAG_BAD_PASSWORD 0x200
#define FLAG_NOPASSWD 0x400
/* /*
* find_path()/set_cmnd() return values * find_path()/set_cmnd() return values
@@ -300,10 +299,6 @@ void dump_auth_methods(void);
/* getspwuid.c */ /* getspwuid.c */
char *sudo_getepw(const struct passwd *); char *sudo_getepw(const struct passwd *);
/* sudo_nss.c */
int display_privs(struct sudo_nss_list *, struct passwd *);
int display_cmnd(struct sudo_nss_list *, struct passwd *);
/* pwutil.c */ /* pwutil.c */
typedef struct cache_item * (*sudo_make_pwitem_t)(uid_t uid, const char *user); typedef struct cache_item * (*sudo_make_pwitem_t)(uid_t uid, const char *user);
typedef struct cache_item * (*sudo_make_gritem_t)(gid_t gid, const char *group); typedef struct cache_item * (*sudo_make_gritem_t)(gid_t gid, const char *group);

View File

@@ -285,7 +285,7 @@ main(int argc, char *argv[])
(void) fputs("Parses OK", stdout); (void) fputs("Parses OK", stdout);
} }
if (!update_defaults(SETDEF_ALL, false)) if (!update_defaults(&defaults, SETDEF_ALL, false))
(void) fputs(" (problem with defaults entries)", stdout); (void) fputs(" (problem with defaults entries)", stdout);
puts("."); puts(".");

View File

@@ -246,7 +246,8 @@ main(int argc, char *argv[])
init_parser(sudoers_file, quiet); init_parser(sudoers_file, quiet);
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
(void) sudoersparse(); (void) sudoersparse();
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, quiet); (void) update_defaults(&defaults, SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER,
quiet);
sudoers_setlocale(oldlocale, NULL); sudoers_setlocale(oldlocale, NULL);
editor = get_editor(&editor_argc, &editor_argv); editor = get_editor(&editor_argc, &editor_argv);
@@ -601,7 +602,8 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv,
} }
fclose(sudoersin); fclose(sudoersin);
if (!parse_error) { if (!parse_error) {
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true); (void) update_defaults(&defaults,
SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true);
check_defaults_and_aliases(strict, quiet); check_defaults_and_aliases(strict, quiet);
} }
sudoers_setlocale(oldlocale, NULL); sudoers_setlocale(oldlocale, NULL);
@@ -918,7 +920,8 @@ check_syntax(const char *sudoers_file, bool quiet, bool strict, bool oldperms)
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
} }
if (!parse_error) { if (!parse_error) {
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true); (void) update_defaults(&defaults,
SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true);
check_defaults_and_aliases(strict, quiet); check_defaults_and_aliases(strict, quiet);
} }
sudoers_setlocale(oldlocale, NULL); sudoers_setlocale(oldlocale, NULL);