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:
1
MANIFEST
1
MANIFEST
@@ -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
|
||||||
|
@@ -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 \
|
||||||
|
@@ -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;
|
||||||
|
@@ -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
145
plugins/sudoers/file.c
Normal 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);
|
||||||
|
}
|
@@ -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
|
||||||
*/
|
*/
|
||||||
|
@@ -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. */
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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
@@ -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);
|
||||||
|
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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(".");
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user