plugins/sudoers/editor.c
plugins/sudoers/env.c
plugins/sudoers/env_pattern.c
+plugins/sudoers/file.c
plugins/sudoers/filedigest.c
plugins/sudoers/filedigest_gcrypt.c
plugins/sudoers/filedigest_openssl.c
timestr.lo toke.lo toke_util.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 \
- group_plugin.lo interfaces.lo iolog.lo iolog_path.lo locale.lo \
- logging.lo logwrap.lo mkdir_parents.lo parse.lo policy.lo \
- prompt.lo set_perms.lo starttime.lo sudo_nss.lo sudoers.lo \
- timestamp.lo @SUDOERS_OBJS@
+ env_pattern.lo file.lo find_path.lo fmtsudoers.lo gc.lo \
+ goodpath.lo group_plugin.lo interfaces.lo iolog.lo \
+ iolog_path.lo locale.lo logging.lo logwrap.lo mkdir_parents.lo \
+ parse.lo policy.lo prompt.lo set_perms.lo starttime.lo \
+ 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
$(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) $(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 \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
}
/*
- * 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.
*/
bool
-update_defaults(int what, bool quiet)
+update_defaults(struct defaults_list *defs, int what, bool quiet)
{
struct defaults *d;
bool ret = true;
/*
* 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);
if (early == NULL)
continue;
/*
* 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. */
if (is_early_default(d->var))
continue;
/*
* Prototypes
*/
+struct defaults_list;
void dump_default(void);
bool init_defaults(void);
struct early_default *is_early_default(const char *name);
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_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);
extern struct sudo_defs_types sudo_defs_table[];
--- /dev/null
+/*
+ * 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);
+}
static int sudo_ldap_open(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_setdefs(struct sudo_nss *nss);
-static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag);
-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 int sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw);
+static int sudo_ldap_getdefs(struct sudo_nss *nss);
static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss,
struct passwd *pw);
static char *sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry);
/*
* LDAP sudo_nss handle.
- * We store the connection to the LDAP server, the cached ldap_result object
- * (if any), and the name of the user the 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.
+ * We store the connection to the LDAP server and the passwd struct of the
+ * user the last query was performed for.
*/
struct sudo_ldap_handle {
LDAP *ld;
- struct ldap_result *result;
- const char *username;
- struct gid_list *gidlist;
+ struct passwd *pw;
};
struct sudo_nss sudo_nss_ldap = {
sudo_ldap_open,
sudo_ldap_close,
sudo_ldap_parse,
- sudo_ldap_setdefs,
- sudo_ldap_lookup,
- sudo_ldap_display_cmnd,
- sudo_ldap_display_defaults,
- sudo_ldap_display_bound_defaults,
- sudo_ldap_display_privs
+ sudo_ldap_query,
+ sudo_ldap_getdefs
};
#ifdef HAVE_LDAP_INITIALIZE
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,
- * else false. RunAs info is optional.
+ * Read sudoOption and fill in the defaults list.
+ * This is used to parse the cn=defaults entry.
*/
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;
- char *var;
- 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;
+ char *cn, *cp, *source = NULL;
bool ret = false;
- int op;
debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP)
bv = ldap_get_values_len(ld, entry, "sudoOption");
if (bv == NULL)
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);
- if (cn != NULL) {
- if (asprintf(&source, "sudoRole %s", cn) == -1) {
- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
- source = NULL;
- goto done;
- }
+ if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) {
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+ 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++) {
- struct early_default *early;
- char *copy;
+ char *copy, *var, *val;
+ int op;
- /* Avoid modifying bv as we need to use it again below. */
- if ((copy = strdup((*p)->bv_val)) == NULL) {
+ copy = strdup((*p)->bv_val); /* XXX - should not need to copy */
+ if (copy == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+ free(copy);
goto done;
}
+
op = sudo_ldap_parse_option(copy, &var, &val);
- early = is_early_default(var);
- if (early != NULL) {
- set_early_default(var, val, op,
- source ? source : "sudoRole UNKNOWN", 0, false, early);
+ if (!sudo_ldap_add_default(var, val, op, source, defs)) {
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+ free(copy);
+ goto done;
}
+
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;
done:
- free(source);
+ rcstr_delref(source);
if (cn)
ldap_memfree(cn);
ldap_value_free_len(bv);
#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 *
berval_iter(void **vp)
{
return *bv ? (*bv)->bv_val : NULL;
}
-static struct userspec_list *
-ldap_to_sudoers(LDAP *ld, struct ldap_result *lres)
+static bool
+ldap_to_sudoers(LDAP *ld, struct ldap_result *lres,
+ struct userspec_list *ldap_userspecs)
{
- struct userspec_list *ldap_userspecs;
struct userspec *us;
struct member *m;
unsigned int i;
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 */
if ((us = calloc(1, sizeof(*us))) == NULL)
goto oom;
oom:
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
- if (ldap_userspecs != NULL) {
- while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
- TAILQ_REMOVE(ldap_userspecs, us, entries);
- free_userspec(us);
- }
- free(ldap_userspecs);
+ while ((us = TAILQ_FIRST(ldap_userspecs)) != NULL) {
+ TAILQ_REMOVE(ldap_userspecs, us, entries);
+ free_userspec(us);
}
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
static unsigned int (*sudo_gss_krb5_ccache_name)(unsigned int *minor_status, const char *name, const char **old_name);
}
static int
-sudo_ldap_setdefs(struct sudo_nss *nss)
+sudo_ldap_getdefs(struct sudo_nss *nss)
{
struct ldap_config_str *base;
struct sudo_ldap_handle *handle = nss->handle;
+ struct member_list *prev_binding = NULL;
struct timeval tv, *tvp = NULL;
+ struct defaults *def;
LDAP *ld;
LDAPMessage *entry, *result = NULL;
char *filt;
- int ret;
- debug_decl(sudo_ldap_setdefs, SUDOERS_DEBUG_LDAP)
+ int rc, ret = -1;
+ debug_decl(sudo_ldap_getdefs, SUDOERS_DEBUG_LDAP)
if (handle == NULL || handle->ld == NULL)
debug_return_int(-1);
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();
if (filt == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
}
ldap_msgfree(result);
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);
- 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));
- if (!sudo_ldap_parse_options(ld, entry)) {
- ret = -1;
+ if (!sudo_ldap_parse_options(ld, entry, &nss->defaults))
goto done;
- }
} else {
DPRINTF1("no default options found in %s", base->val);
}
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.
*/
}
/*
- * Free the ldap result structure in the sudo_nss handle.
+ * Free the cached results in the sudo_nss handle, if present.
*/
static void
sudo_ldap_result_free_nss(struct sudo_nss *nss)
{
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)
- if (handle->result != NULL) {
- DPRINTF1("removing reusable search result");
- sudo_ldap_result_free(handle->result);
- handle->username = NULL;
- handle->gidlist = NULL;
- handle->result = NULL;
+ if (handle->pw != NULL)
+ sudo_pw_delref(handle->pw);
+
+ /* 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;
}
/*
- * Perform the LDAP query for the user or return a cached query if
- * there is one for this user.
+ * Perform the LDAP query for the user. The caller is responsible for
+ * freeing the result with sudo_ldap_result_free().
*/
static struct ldap_result *
sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
char *filt;
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
* Lets limit it to only two queries of the LDAP server
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_decl(sudo_ldap_close, SUDOERS_DEBUG_LDAP)
if (handle != NULL) {
- /* Free the result before unbinding; it may use the LDAP connection. */
+ /* Free the cached result. */
sudo_ldap_result_free_nss(nss);
/* Unbind and close the LDAP connection. */
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
*/
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.
* Pass in struct berval ** for LDAP or char *** for SSSD.
/* Parse sudoOptions. */
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) {
char *var, *val;
}
#endif /* HAVE_PRIV_SET */
} else if (store_options) {
- struct defaults *def = calloc(1, sizeof(*def));
- if (def == NULL)
+ if (!sudo_ldap_add_default(var, val, op, source,
+ &priv->defaults)) {
goto oom;
- def->type = DEFAULTS;
- def->op = op;
- if ((def->var = strdup(var)) == NULL) {
- free(def);
- 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 {
/* Convert to tags. */
bool handled = true;
}
}
}
+ rcstr_delref(source);
}
/* So we can inherit previous values. */
#include <config.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_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 sudo_file_close(struct sudo_nss *);
-static int sudo_file_display_bound_defaults(struct sudo_nss *, struct passwd *, struct sudo_lbuf *);
-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)
-
- 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)
+static int
+sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw,
+ int validated, int pwflag)
{
- int match, host_match, runas_match, cmnd_match, timeout;
+ int match;
+ struct sudo_nss *nss;
struct cmndspec *cs;
- struct cmndtag *tags = NULL;
struct privilege *priv;
struct userspec *us;
- struct member *matching_user;
- time_t now;
- debug_decl(sudo_file_lookup, SUDOERS_DEBUG_NSS)
-
- if (nss->handle == NULL)
- debug_return_int(validated);
-
- /*
- * Only check the actual command if pwflag is not set.
- * It is set for the "validate", "list" and "kill" pseudo-commands.
- * Always check the host and user.
- */
- if (pwflag) {
- int nopass;
- enum def_tuple pwcheck;
-
- pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
- nopass = (pwcheck == all) ? true : false;
-
- if (list_pw == NULL)
- 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)
+ struct defaults *def;
+ int nopass;
+ enum def_tuple pwcheck;
+ debug_decl(sudoers_lookup_pseudo, SUDOERS_DEBUG_PARSER)
+
+ pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
+ nopass = (pwcheck == all) ? true : false;
+
+ if (list_pw == NULL)
+ SET(validated, FLAG_NO_CHECK);
+ CLR(validated, FLAG_NO_USER);
+ CLR(validated, FLAG_NO_HOST);
+ match = DENY;
+ 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;
+ }
+ TAILQ_FOREACH(us, &nss->userspecs, entries) {
+ if (userlist_matches(pw, &us->users) != ALLOW)
continue;
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;
+ TAILQ_FOREACH(def, &priv->defaults, entries) {
+ if (strcmp(def->var, "authenticate") == 0)
+ priv_nopass = def->op;
+ }
TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
- if ((pwcheck == any && cs->tags.nopasswd == true) ||
- (pwcheck == all && cs->tags.nopasswd != true))
- nopass = cs->tags.nopasswd;
+ if (pwcheck == any) {
+ if (cs->tags.nopasswd == true || priv_nopass == true)
+ nopass = true;
+ } else if (pwcheck == all) {
+ if (cs->tags.nopasswd != true && priv_nopass != true)
+ nopass = false;
+ }
if (match == ALLOW)
continue;
/* Only check the command when listing another user. */
}
}
}
- 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. */
- if (!set_perms(PERM_RUNAS))
- debug_return_int(validated);
+static int
+sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, 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);
- match = UNSPEC;
- TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
- if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
+ TAILQ_FOREACH_REVERSE(us, &nss->userspecs, userspec_list, entries) {
+ if (userlist_matches(pw, &us->users) != ALLOW)
continue;
- CLR(validated, FLAG_NO_USER);
+ CLR(*validated, FLAG_NO_USER);
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)
- CLR(validated, FLAG_NO_HOST);
+ CLR(*validated, FLAG_NO_HOST);
else
continue;
TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
if (runas_match == ALLOW) {
cmnd_match = cmnd_matches(cs->cmnd);
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,
* set runas_pw = sudo_user.pw.
sudo_pw_addref(sudo_user.pw);
runas_pw = sudo_user.pw;
}
- goto matched2;
+ *matching_cs = cs;
+ *defs = &priv->defaults;
+ debug_return_int(cmnd_match);
}
}
}
}
}
- matched2:
- if (match == ALLOW) {
- SET(validated, VALIDATE_SUCCESS);
- CLR(validated, VALIDATE_FAILURE);
- if (timeout > 0)
- def_command_timeout = timeout;
- if (tags != NULL) {
- if (tags->nopasswd != UNSPEC)
- def_authenticate = !tags->nopasswd;
- if (tags->noexec != UNSPEC)
- def_noexec = tags->noexec;
- if (tags->setenv != UNSPEC)
- def_setenv = tags->setenv;
- if (tags->log_input != UNSPEC)
- def_log_input = tags->log_input;
- if (tags->log_output != UNSPEC)
- def_log_output = tags->log_output;
- 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;
+ debug_return_int(UNSPEC);
+}
+
+/*
+ * Apply cmndspec-specific settngs including SELinux role/type,
+ * Solaris privs, and command tags.
+ */
+static bool
+apply_cmndspec(struct cmndspec *cs)
+{
+ debug_decl(apply_cmndspec, SUDOERS_DEBUG_PARSER)
+
+ if (cs != NULL) {
+#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"));
+ debug_return_bool(false);
}
+ } else {
+ user_role = def_role;
}
- 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;
+ 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())
SET(validated, VALIDATE_ERROR);
debug_return_int(validated);
}
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 cmndspec *cs, *prev_cs;
struct member *m;
struct privilege *priv;
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) {
if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
static bool
new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs)
{
+ debug_decl(new_long_entry, SUDOERS_DEBUG_PARSER)
+
if (prev_cs == NULL)
- return true;
+ debug_return_bool(true);
if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(prev_cs->tags, cs->tags))
- return true;
+ debug_return_bool(true);
#ifdef HAVE_PRIV_SET
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))
- return true;
+ debug_return_bool(true);
#endif /* HAVE_PRIV_SET */
#ifdef HAVE_SELINUX
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))
- return true;
+ debug_return_bool(true);
#endif /* HAVE_SELINUX */
if (cs->timeout != prev_cs->timeout)
- return true;
+ debug_return_bool(true);
if (cs->notbefore != prev_cs->notbefore)
- return true;
+ debug_return_bool(true);
if (cs->notafter != prev_cs->notafter)
- return true;
- return false;
+ debug_return_bool(true);
+ debug_return_bool(false);
}
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 cmndspec *cs, *prev_cs;
struct privilege *priv;
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) {
if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
debug_return_int(nfound);
}
-/* XXX - better naming */
-int
+static int
sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
struct userspec *us;
int nfound = 0;
- debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_NSS)
+ debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_PARSER)
TAILQ_FOREACH(us, usl, entries) {
if (userlist_matches(pw, &us->users) != ALLOW)
continue;
if (long_list)
- nfound += sudo_file_display_priv_long(pw, us, lbuf);
+ nfound += display_priv_long(pw, us, lbuf);
else
- nfound += sudo_file_display_priv_short(pw, us, lbuf);
+ nfound += display_priv_short(pw, us, lbuf);
}
if (sudo_lbuf_error(lbuf))
debug_return_int(-1);
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.
*/
-int
-sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
+static int
+display_defaults(struct defaults_list *defs, struct passwd *pw,
struct sudo_lbuf *lbuf)
{
struct defaults *d;
char *prefix;
int nfound = 0;
- debug_decl(sudo_file_display_defaults, SUDOERS_DEBUG_NSS)
-
- if (nss->handle == NULL)
- goto done;
+ debug_decl(display_defaults, SUDOERS_DEBUG_PARSER)
if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
prefix = " ";
else
prefix = ", ";
- TAILQ_FOREACH(d, &defaults, entries) {
+ TAILQ_FOREACH(d, defs, entries) {
switch (d->type) {
case DEFAULTS_HOST:
if (hostlist_matches(pw, d->binding) != ALLOW)
prefix = ", ";
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))
debug_return_int(-1);
debug_return_int(nfound);
* Display Defaults entries of the given type.
*/
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 member_list *binding = NULL;
struct member *m;
char *dsep;
int atype, nfound = 0;
- debug_decl(display_bound_defaults, SUDOERS_DEBUG_NSS)
+ debug_decl(display_bound_defaults_by_type, SUDOERS_DEBUG_PARSER)
switch (deftype) {
case DEFAULTS_HOST:
default:
debug_return_int(-1);
}
- TAILQ_FOREACH(d, &defaults, entries) {
+ TAILQ_FOREACH(d, defs, entries) {
if (d->type != deftype)
continue;
}
/*
- * 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
-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 member *match;
struct privilege *priv;
struct userspec *us;
- int ret = 1;
- int host_match, runas_match, cmnd_match;
- debug_decl(sudo_file_display_cmnd, SUDOERS_DEBUG_NSS)
-
- if (nss->handle == NULL)
- goto done;
+ debug_decl(display_cmnd_check, SUDOERS_DEBUG_PARSER)
- match = NULL;
- TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
+ TAILQ_FOREACH_REVERSE(us, &nss->userspecs, userspec_list, entries) {
if (userlist_matches(pw, &us->users) != ALLOW)
continue;
-
TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
host_match = hostlist_matches(pw, &priv->hostlist);
if (host_match != ALLOW)
continue;
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,
cs->runasgrouplist, NULL, NULL);
if (runas_match == ALLOW) {
cmnd_match = cmnd_matches(cs->cmnd);
- if (cmnd_match != UNSPEC) {
- if (cmnd_match == ALLOW)
- match = cs->cmnd;
- goto matched;
- }
+ if (cmnd_match != UNSPEC)
+ debug_return_int(cmnd_match);
}
}
}
}
- matched:
- if (match != NULL && !match->negated) {
+ debug_return_int(UNSPEC);
+}
+
+/*
+ * 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",
safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
- ret = len < 0 ? -1 : 0;
+ ret = len < 0 ? -1 : true;
}
-done:
debug_return_int(ret);
}
const char *digest_type_to_name(int digest_type);
/* parse.c */
-struct sudo_lbuf;
-int sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, struct sudo_lbuf *lbuf);
+struct sudo_nss_list;
+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 */
+struct sudo_lbuf;
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_line(struct sudo_lbuf *lbuf, struct defaults *d, struct defaults **next, bool expand_aliases);
static int sudo_sss_open(struct sudo_nss *nss);
static int sudo_sss_close(struct sudo_nss *nss);
static int sudo_sss_parse(struct sudo_nss *nss);
+static int sudo_sss_query(struct sudo_nss *nss, struct passwd *pw);
static bool sudo_sss_parse_options(struct sudo_sss_handle *handle,
- struct sss_sudo_rule *rule);
-static int sudo_sss_setdefs(struct sudo_nss *nss);
-static int sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag);
-static int sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw);
-static int sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
- struct sudo_lbuf *lbuf);
-
-static int sudo_sss_display_bound_defaults(struct sudo_nss *nss,
- struct passwd *pw, struct sudo_lbuf *lbuf);
-
-static int sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
- struct sudo_lbuf *sudo_lbuf);
+ struct sss_sudo_rule *rule,
+ struct defaults_list *defs);
+static int sudo_sss_getdefs(struct sudo_nss *nss);
static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss,
- struct passwd *pw,
- uint32_t *state);
+ struct passwd *pw);
+
+static bool sss_to_sudoers(struct sudo_sss_handle *handle,
+ struct sss_sudo_result *sss_result,
+ struct userspec_list *sss_userspecs);
static void
sudo_sss_attrfree(struct sss_sudo_attr *attr)
#define SUDO_SSS_FILTER_INCLUDE 0
#define SUDO_SSS_FILTER_EXCLUDE 1
-#define SUDO_SSS_STATE_HOSTMATCH 0x01
-#define SUDO_SSS_STATE_USERMATCH 0x02
-
+/* XXX - insted of filtering result, include user and host in sudoers parse tree */
static struct sss_sudo_result *
sudo_sss_filter_result(struct sudo_sss_handle *handle,
struct sss_sudo_result *in_res,
sudo_sss_open,
sudo_sss_close,
sudo_sss_parse,
- sudo_sss_setdefs,
- sudo_sss_lookup,
- sudo_sss_display_cmnd,
- sudo_sss_display_defaults,
- sudo_sss_display_bound_defaults,
- sudo_sss_display_privs
+ sudo_sss_query,
+ sudo_sss_getdefs
};
/* sudo_nss implementation */
debug_return_int(EFAULT);
}
- handle->pw = sudo_user.pw;
nss->handle = handle;
/*
static int
sudo_sss_close(struct sudo_nss *nss)
{
+ struct member_list *prev_binding = NULL;
+ struct defaults *def;
+ struct userspec *us;
struct sudo_sss_handle *handle;
debug_decl(sudo_sss_close, SUDOERS_DEBUG_SSSD);
if (nss && nss->handle) {
handle = nss->handle;
sudo_dso_unload(handle->ssslib);
+ if (handle->pw != NULL)
+ sudo_pw_delref(handle->pw);
free(handle->ipa_host);
if (handle->ipa_host != handle->ipa_shost)
free(handle->ipa_shost);
free(handle);
nss->handle = 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);
}
+/*
+ * Perform query for user and host and convert to sudoers parse tree.
+ */
+static int
+sudo_sss_query(struct sudo_nss *nss, struct passwd *pw)
+{
+ struct sudo_sss_handle *handle = nss->handle;
+ struct sss_sudo_result *sss_result = NULL;
+ struct userspec *us;
+ int ret = 0;
+ debug_decl(sudo_sss_query, SUDOERS_DEBUG_SSSD);
+
+ /* 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);
+ }
+
+ /* Fetch list of sudoRole entries that match user and host. */
+ sss_result = sudo_sss_result_get(nss, pw);
+
+ sudo_debug_printf(SUDO_DEBUG_DIAG,
+ "searching SSSD/LDAP for sudoers entries for user %s, host %s",
+ pw->pw_name, user_runhost);
+
+ if (sss_result == NULL)
+ goto done;
+
+ /* Convert to sudoers parse tree. */
+ if (!sss_to_sudoers(handle, sss_result, &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 */
+ handle->fn_free_result(sss_result);
+ if (ret == -1) {
+ while ((us = TAILQ_FIRST(&nss->userspecs)) != NULL) {
+ TAILQ_REMOVE(&nss->userspecs, us, entries);
+ free_userspec(us);
+ }
+ }
+
+ sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
+
+ debug_return_int(ret);
+}
+
// ok
static int
sudo_sss_parse(struct sudo_nss *nss)
}
static int
-sudo_sss_setdefs(struct sudo_nss *nss)
+sudo_sss_getdefs(struct sudo_nss *nss)
{
struct sudo_sss_handle *handle = nss->handle;
struct sss_sudo_result *sss_result = NULL;
struct sss_sudo_rule *sss_rule;
+ struct member_list *prev_binding = NULL;
+ struct defaults *def;
uint32_t sss_error;
unsigned int i;
- debug_decl(sudo_sss_setdefs, SUDOERS_DEBUG_SSSD);
+ debug_decl(sudo_sss_getdefs, SUDOERS_DEBUG_SSSD);
if (handle == NULL)
debug_return_int(-1);
+ /* Free old defaults, if any. */
+ while ((def = TAILQ_FIRST(&nss->defaults)) != NULL) {
+ TAILQ_REMOVE(&nss->defaults, def, entries);
+ free_default(def, &prev_binding);
+ }
+
sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults");
- if (handle->fn_send_recv_defaults(handle->pw->pw_uid, handle->pw->pw_name,
- &sss_error, &handle->domainname,
- &sss_result) != 0) {
+ /* NOTE: these are global defaults, user ID and name are not used. */
+ if (handle->fn_send_recv_defaults(sudo_user.pw->pw_uid,
+ sudo_user.pw->pw_name, &sss_error,
+ &handle->domainname, &sss_result) != 0) {
sudo_debug_printf(SUDO_DEBUG_INFO,
"handle->fn_send_recv_defaults: != 0, sss_error=%u", sss_error);
debug_return_int(-1);
sudo_debug_printf(SUDO_DEBUG_DIAG,
"Parsing cn=defaults, %d/%d", i, sss_result->num_rules);
sss_rule = sss_result->rules + i;
- if (!sudo_sss_parse_options(handle, sss_rule))
+ if (!sudo_sss_parse_options(handle, sss_rule, &nss->defaults))
goto bad;
}
debug_return_int(-1);
}
-static int
-sudo_sss_checkpw(struct sudo_nss *nss, struct passwd *pw)
-{
- struct sudo_sss_handle *handle = nss->handle;
- debug_decl(sudo_sss_checkpw, SUDOERS_DEBUG_SSSD);
-
- if (pw->pw_name != handle->pw->pw_name ||
- pw->pw_uid != handle->pw->pw_uid) {
- sudo_debug_printf(SUDO_DEBUG_DIAG,
- "Requested name or uid don't match the initial once, reinitializing...");
- handle->pw = pw;
-
- if (sudo_sss_setdefs(nss) != 0)
- debug_return_int(-1);
- }
-
- debug_return_int(0);
-}
-
-static int
-sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *sss_rule, int *group_matched)
-{
- const char *host = handle->ipa_host ? handle->ipa_host : user_runhost;
- const char *shost = handle->ipa_shost ? handle->ipa_shost : user_srunhost;
- char *val, **val_array = NULL;
- int ret = false, i;
- debug_decl(sudo_sss_check_runas_user, SUDOERS_DEBUG_SSSD);
-
- /* get the runas user from the entry */
- i = handle->fn_get_values(sss_rule, "sudoRunAsUser", &val_array);
- if (i == ENOENT) {
- sudo_debug_printf(SUDO_DEBUG_INFO,
- "sudoRunAsUser: no result, trying sudoRunAs");
- i = handle->fn_get_values(sss_rule, "sudoRunAs", &val_array);
- }
- switch (i) {
- case 0:
- break;
- case ENOENT:
- sudo_debug_printf(SUDO_DEBUG_INFO, "sudoRunAsUser: no result.");
- if (*group_matched == UNSPEC) {
- /* We haven't check for sudoRunAsGroup yet, check now. */
- i = handle->fn_get_values(sss_rule, "sudoRunAsGroup", &val_array);
- if (i == 0) {
- *group_matched = false;
- handle->fn_free_values(val_array);
- }
- }
- 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.
- */
- sudo_debug_printf(SUDO_DEBUG_INFO, "Matching against runas_default");
- 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.
- */
- sudo_debug_printf(SUDO_DEBUG_INFO, "Matching against user_name");
- if (userpw_matches(user_name, runas_pw->pw_name, runas_pw))
- ret = true;
- break;
- }
- debug_return_int(ret);
- default:
- sudo_debug_printf(SUDO_DEBUG_INFO,
- "handle->fn_get_values(sudoRunAsUser): %d", i);
- debug_return_int(false);
- }
-
- /*
- * 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 (i = 0; val_array[i] != NULL && !ret; ++i) {
- val = val_array[i];
-
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-
- switch (val[0]) {
- case '+':
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "netgr_");
- if (netgr_matches(val, def_netgroup_tuple ? host : NULL,
- def_netgroup_tuple ? shost : NULL, runas_pw->pw_name)) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
- ret = true;
- }
- break;
- case '%':
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "usergr_");
- if (usergr_matches(val, runas_pw->pw_name, runas_pw)) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
- 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) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "ALL => match");
- ret = true;
- break;
- }
- /* FALLTHROUGH */
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "FALLTHROUGH");
- default:
- if (userpw_matches(val, runas_pw->pw_name, runas_pw)) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG,
- "%s == %s (pw_name) => match", val, runas_pw->pw_name);
- ret = true;
- }
- break;
- }
-
- sudo_debug_printf(SUDO_DEBUG_INFO,
- "sssd/ldap sudoRunAsUser '%s' ... %s", val, ret ? "MATCH!" : "not");
- }
-
- handle->fn_free_values(val_array); /* cleanup */
-
- debug_return_int(ret);
-}
-
-static int
-sudo_sss_check_runas_group(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
-{
- char **val_array = NULL;
- char *val;
- int ret = false, i;
- debug_decl(sudo_sss_check_runas_group, SUDOERS_DEBUG_SSSD);
-
- /* get the values from the entry */
- i = handle->fn_get_values(rule, "sudoRunAsGroup", &val_array);
- switch (i) {
- case 0:
- break;
- case ENOENT:
- sudo_debug_printf(SUDO_DEBUG_INFO, "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);
- default:
- sudo_debug_printf(SUDO_DEBUG_INFO,
- "handle->fn_get_values(sudoRunAsGroup): %d", i);
- debug_return_int(false);
- }
-
- /* walk through values returned, looking for a match */
- for (i = 0; val_array[i] != NULL; ++i) {
- val = val_array[i];
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-
- if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr))
- ret = true;
-
- sudo_debug_printf(SUDO_DEBUG_INFO,
- "sssd/ldap sudoRunAsGroup '%s' ... %s", val, ret ? "MATCH!" : "not");
- }
-
- handle->fn_free_values(val_array);
-
- debug_return_int(ret);
-}
-
-/*
- * Walk through search results and return true if we have a runas match,
- * else false. RunAs info is optional.
- */
-static bool
-sudo_sss_check_runas(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
-{
- int user_matched = UNSPEC;
- int group_matched = UNSPEC;
- debug_decl(sudo_sss_check_runas, SUDOERS_DEBUG_SSSD);
-
- if (rule == NULL)
- debug_return_bool(false);
-
- if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED))
- group_matched = sudo_sss_check_runas_group(handle, rule);
- user_matched = sudo_sss_check_runas_user(handle, rule, &group_matched);
-
- debug_return_bool(group_matched != false && user_matched != false);
-}
-
static bool
sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
{
debug_return_bool(ret);
}
+/* XXX - insted of filtering result, include user and host in sudoers parse tree */
static int
sudo_sss_result_filterp(struct sudo_sss_handle *handle,
struct sss_sudo_rule *rule, void *unused)
}
static struct sss_sudo_result *
-sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw, uint32_t *state)
+sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw)
{
struct sudo_sss_handle *handle = nss->handle;
struct sss_sudo_result *u_sss_result, *f_sss_result;
uint32_t sss_error = 0, ret;
debug_decl(sudo_sss_result_get, SUDOERS_DEBUG_SSSD);
- if (sudo_sss_checkpw(nss, pw) != 0)
- debug_return_ptr(NULL);
-
- sudo_debug_printf(SUDO_DEBUG_DIAG, " username=%s", handle->pw->pw_name);
+ sudo_debug_printf(SUDO_DEBUG_DIAG, " username=%s", pw->pw_name);
sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s",
handle->domainname ? handle->domainname : "NULL");
u_sss_result = f_sss_result = NULL;
- ret = handle->fn_send_recv(handle->pw->pw_uid, handle->pw->pw_name,
+ ret = handle->fn_send_recv(pw->pw_uid, pw->pw_name,
handle->domainname, &sss_error, &u_sss_result);
switch (ret) {
switch (sss_error) {
case 0:
if (u_sss_result != NULL) {
- if (state != NULL) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= USERMATCH");
- *state |= SUDO_SSS_STATE_USERMATCH;
- }
sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)",
u_sss_result->num_rules);
} else {
debug_return_ptr(NULL);
}
+ /* XXX - insted of filtering result, include user and host in sudoers parse tree */
f_sss_result = sudo_sss_filter_result(handle, u_sss_result,
sudo_sss_result_filterp, SUDO_SSS_FILTER_INCLUDE, NULL);
if (f_sss_result != NULL) {
- if (f_sss_result->num_rules > 0) {
- if (state != NULL) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "state |= HOSTMATCH");
- *state |= SUDO_SSS_STATE_HOSTMATCH;
- }
- }
sudo_debug_printf(SUDO_DEBUG_DEBUG,
"u_sss_result=(%p, %u) => f_sss_result=(%p, %u)", u_sss_result,
u_sss_result->num_rules, f_sss_result, f_sss_result->num_rules);
debug_return_ptr(f_sss_result);
}
-/*
- * Search for boolean "option" in sudoOption.
- * Returns true if found and allowed, false if negated, else UNSPEC.
- */
-static int
-sudo_sss_check_bool(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
- char *option)
-{
- char *var, **val_array = NULL;
- int i, ret = UNSPEC;
- bool negated;
- debug_decl(sudo_sss_check_bool, SUDOERS_DEBUG_SSSD);
-
- if (rule == NULL)
- debug_return_int(ret);
-
- switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
- case 0:
- break;
- case ENOENT:
- sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
- debug_return_int(ret);
- default:
- sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
- debug_return_int(ret);
- }
-
- /* walk through options */
- for (i = 0; val_array[i] != NULL; ++i) {
- var = val_array[i];
- sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoOption: '%s'", var);
-
- negated = sudo_ldap_is_negated(&var);
- if (strcmp(var, option) == 0)
- ret = negated ? false : true;
- }
-
- handle->fn_free_values(val_array);
-
- debug_return_int(ret);
-}
-
-/*
- * Walk through search results and return true if we have a command match,
- * false if disallowed and UNSPEC if not matched.
- */
-static int
-sudo_sss_check_command(struct sudo_sss_handle *handle,
- struct sss_sudo_rule *rule, int *setenv_implied)
-{
- char **val_array = NULL, *val;
- char *allowed_cmnd, *allowed_args;
- int ret = UNSPEC;
- bool negated;
- unsigned int i;
- struct sudo_digest digest, *allowed_digest = NULL;
- debug_decl(sudo_sss_check_command, SUDOERS_DEBUG_SSSD);
-
- if (rule == NULL)
- debug_return_int(ret);
-
- switch (handle->fn_get_values(rule, "sudoCommand", &val_array)) {
- case 0:
- break;
- case ENOENT:
- sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
- debug_return_int(ret);
- default:
- sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
- debug_return_int(ret);
- }
-
- for (i = 0; val_array[i] != NULL && ret != false; ++i) {
- val = val_array[i];
-
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-
- /* Match against ALL ? */
- if (strcmp(val, "ALL") == 0) {
- ret = true;
- if (setenv_implied != NULL)
- *setenv_implied = true;
- sudo_debug_printf(SUDO_DEBUG_INFO,
- "sssd/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 */
-
- sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap sudoCommand '%s' ... %s",
- val, ret == true ? "MATCH!" : "not");
- if (allowed_digest != NULL)
- free(allowed_digest->digest_str);
- }
-
- handle->fn_free_values(val_array); /* more cleanup */
-
- debug_return_int(ret);
-}
-
static bool
-sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
+sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule, struct defaults_list *defs)
{
- int i, op;
- char *copy, *var, *val, *source = NULL;
+ int i;
+ char *source = NULL;
bool ret = false;
char **val_array = NULL;
char **cn_array = NULL;
debug_return_bool(false);
}
- /* get the entry's cn for option error reporting */
+ /* Use sudoRole in place of file name in defaults. */
if (handle->fn_get_values(rule, "cn", &cn_array) == 0) {
if (cn_array[0] != NULL) {
- if (asprintf(&source, "sudoRole %s", cn_array[0]) == -1) {
- sudo_warnx(U_("%s: %s"), __func__,
- U_("unable to allocate memory"));
- source = NULL;
- goto done;
- }
+ char *cp;
+ if (asprintf(&cp, "sudoRole %s", cn_array[0]) == -1)
+ goto oom;
+ source = rcstr_dup(cp);
+ free(cp);
+ if (source == NULL)
+ goto oom;
}
handle->fn_free_values(cn_array);
cn_array = NULL;
}
-
- /* walk through options, early ones first */
- for (i = 0; val_array[i] != NULL; i++) {
- struct early_default *early;
-
- if ((copy = strdup(val_array[i])) == NULL) {
- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
- goto done;
- }
- op = sudo_ldap_parse_option(copy, &var, &val);
- early = is_early_default(var);
- if (early != NULL) {
- set_early_default(var, val, op,
- source ? source : "sudoRole UNKNOWN", 0, false, early);
- }
- free(copy);
+ if (source == NULL) {
+ if ((source = rcstr_dup("sudoRole UNKNOWN")) == NULL)
+ goto oom;
}
- run_early_defaults();
- /* walk through options again, skipping early ones */
+ /* Walk through options, appending to defs. */
for (i = 0; val_array[i] != NULL; i++) {
- if ((copy = strdup(val_array[i])) == NULL) {
- sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
- goto done;
- }
+ char *copy, *var, *val;
+ int op;
+
+ /* XXX - should not need to copy */
+ if ((copy = strdup(val_array[i])) == NULL)
+ goto oom;
op = sudo_ldap_parse_option(copy, &var, &val);
- if (is_early_default(var) == NULL) {
- set_default(var, val, op,
- source ? source : "sudoRole UNKNOWN", 0, false);
+ if (!sudo_ldap_add_default(var, val, op, source, defs)) {
+ free(copy);
+ goto oom;
}
free(copy);
}
ret = true;
+ goto done;
+
+oom:
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
done:
- free(source);
+ rcstr_delref(source);
handle->fn_free_values(val_array);
debug_return_bool(ret);
}
-static int
-sudo_sss_lookup(struct sudo_nss *nss, int ret, int pwflag)
-{
- int rc, setenv_implied;
-
- struct sudo_sss_handle *handle = nss->handle;
- struct sss_sudo_result *sss_result = NULL;
- struct sss_sudo_rule *rule;
- uint32_t i, state = 0;
- debug_decl(sudo_sss_lookup, SUDOERS_DEBUG_SSSD);
-
- /* Fetch list of sudoRole entries that match user and host. */
- sss_result = sudo_sss_result_get(nss, sudo_user.pw, &state);
-
- /*
- * The following queries are 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;
-
- sudo_debug_printf(SUDO_DEBUG_INFO, "perform search for pwflag %d", pwflag);
- if (sss_result != NULL) {
- for (i = 0; i < sss_result->num_rules; i++) {
- rule = sss_result->rules + i;
- if ((pwcheck == any && doauth != false) ||
- (pwcheck == all && doauth != true)) {
- doauth = !!sudo_sss_check_bool(handle, rule, "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_sss_check_command(handle, rule, 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;
- }
-
- sudo_debug_printf(SUDO_DEBUG_DIAG,
- "searching SSSD/LDAP for sudoers entries");
-
- setenv_implied = false;
- if (sss_result != NULL) {
- for (i = 0; i < sss_result->num_rules; i++) {
- rule = sss_result->rules + i;
- if (!sudo_sss_check_runas(handle, rule))
- continue;
- rc = sudo_sss_check_command(handle, rule, &setenv_implied);
- if (rc != UNSPEC) {
- /* We have a match. */
- sudo_debug_printf(SUDO_DEBUG_DIAG, "Command %sallowed",
- rc == true ? "" : "NOT ");
- if (rc == true) {
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "SSSD rule: %p", rule);
- /* Apply entry-specific options. */
- if (setenv_implied)
- def_setenv = true;
- if (sudo_sss_parse_options(handle, rule)) {
-#ifdef HAVE_SELINUX
- /* Set role/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:
- handle->fn_free_result(sss_result);
-
- sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches");
-
- if (!ISSET(ret, VALIDATE_SUCCESS)) {
- /* No matching entries. */
- if (pwflag && list_pw == NULL)
- SET(ret, FLAG_NO_CHECK);
- }
-
- if (pwflag || ISSET(state, SUDO_SSS_STATE_USERMATCH))
- CLR(ret, FLAG_NO_USER);
- if (pwflag || ISSET(state, SUDO_SSS_STATE_HOSTMATCH))
- CLR(ret, FLAG_NO_HOST);
-
- sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_sss_lookup(%d)=0x%02x",
- pwflag, ret);
-
- debug_return_int(ret);
-}
-
-static int
-sudo_sss_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
-{
- struct sudo_sss_handle *handle = nss->handle;
- struct sss_sudo_result *sss_result = NULL;
- struct sss_sudo_rule *rule;
- unsigned int i;
- bool found = false;
- debug_decl(sudo_sss_display_cmnd, SUDOERS_DEBUG_SSSD);
-
- if (handle == NULL)
- debug_return_int(-1);
- if (sudo_sss_checkpw(nss, pw) != 0)
- debug_return_int(-1);
-
- /*
- * The sudo_sss_result_get() function returns all nodes that match
- * the user and the host.
- */
- sudo_debug_printf(SUDO_DEBUG_DIAG, "sssd/ldap search for command list");
- sss_result = sudo_sss_result_get(nss, pw, NULL);
-
- if (sss_result == NULL)
- goto done;
-
- for (i = 0; i < sss_result->num_rules; i++) {
- rule = sss_result->rules + i;
- if (!sudo_sss_check_runas(handle, rule))
- continue;
- if (sudo_sss_check_command(handle, rule, 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 : "");
-
- handle->fn_free_result(sss_result);
-
- debug_return_int(!found);
-}
-
-static int
-sudo_sss_display_defaults(struct sudo_nss *nss, struct passwd *pw,
- struct sudo_lbuf *lbuf)
-{
- struct sudo_sss_handle *handle = nss->handle;
- struct sss_sudo_rule *rule;
- struct sss_sudo_result *sss_result = NULL;
- uint32_t sss_error = 0;
- char *prefix, **val_array = NULL;
- unsigned int i, j;
- int count = 0;
- debug_decl(sudo_sss_display_defaults, SUDOERS_DEBUG_SSSD);
-
- if (handle == NULL)
- goto done;
-
- if (handle->fn_send_recv_defaults(pw->pw_uid, pw->pw_name,
- &sss_error, &handle->domainname,
- &sss_result) != 0) {
- sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_send_recv_defaults: !=0, sss_error=%u", sss_error);
- goto done;
- }
-
- if (sss_error == ENOENT) {
- sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD.");
- goto done;
- } else if(sss_error != 0) {
- sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error);
- goto done;
- }
-
- handle->pw = pw;
-
- for (i = 0; i < sss_result->num_rules; ++i) {
- rule = sss_result->rules + i;
-
- switch (handle->fn_get_values(rule, "sudoOption", &val_array)) {
- case 0:
- break;
- case ENOENT:
- sudo_debug_printf(SUDO_DEBUG_INFO, "No result.");
- continue;
- default:
- sudo_debug_printf(SUDO_DEBUG_INFO, "handle->fn_get_values: != 0");
- continue;
- }
-
- if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
- prefix = " ";
- else
- prefix = ", ";
-
- for (j = 0; val_array[j] != NULL; ++j) {
- struct defaults d;
-
- sudo_lbuf_append(lbuf, "%s", prefix);
- d.op = sudo_ldap_parse_option(val_array[j], &d.var, &d.val);
- sudoers_format_default(lbuf, &d);
- prefix = ", ";
- count++;
- }
-
- handle->fn_free_values(val_array);
- val_array = NULL;
- }
-
- handle->fn_free_result(sss_result);
-done:
- if (sudo_lbuf_error(lbuf))
- debug_return_int(-1);
- debug_return_int(count);
-}
-
-// ok
-static int
-sudo_sss_display_bound_defaults(struct sudo_nss *nss,
- struct passwd *pw, struct sudo_lbuf *lbuf)
-{
- debug_decl(sudo_sss_display_bound_defaults, SUDOERS_DEBUG_SSSD);
- debug_return_int(0);
-}
-
static char *
val_array_iter(void **vp)
{
return *val_array;
}
-static struct userspec_list *
-sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_result)
+static bool
+sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_result, struct userspec_list *sss_userspecs)
{
- struct userspec_list *sss_userspecs;
struct userspec *us;
struct member *m;
unsigned int i;
debug_decl(sss_to_sudoers, SUDOERS_DEBUG_SSSD)
- if ((sss_userspecs = calloc(1, sizeof(*sss_userspecs))) == NULL)
- goto oom;
- TAILQ_INIT(sss_userspecs);
-
/* We only have a single userspec */
if ((us = calloc(1, sizeof(*us))) == NULL)
goto oom;
TAILQ_INSERT_TAIL(sss_userspecs, us, entries);
/* The user has already matched, use ALL as wildcard. */
+ /* XXX - remove filtering and include sudoUser and host in userspec */
if ((m = calloc(1, sizeof(*m))) == NULL)
goto oom;
m->type = ALL;
TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
}
- debug_return_ptr(sss_userspecs);
+ debug_return_bool(true);
oom:
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
- if (sss_userspecs != NULL) {
- while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
- TAILQ_REMOVE(sss_userspecs, us, entries);
- free_userspec(us);
- }
- free(sss_userspecs);
- }
- debug_return_ptr(NULL);
-}
-
-static int
-sudo_sss_display_privs(struct sudo_nss *nss, struct passwd *pw,
- struct sudo_lbuf *lbuf)
-{
- struct sudo_sss_handle *handle = nss->handle;
- struct userspec_list *sss_userspecs = NULL;
- struct sss_sudo_result *sss_result = NULL;
- int ret = 0;
- debug_decl(sudo_sss_display_privs, SUDOERS_DEBUG_SSSD);
-
- if (handle == NULL)
- debug_return_int(-1);
- if (sudo_sss_checkpw(nss, pw) != 0)
- debug_return_int(-1);
-
- sudo_debug_printf(SUDO_DEBUG_INFO, "sssd/ldap search for command list");
-
- sss_result = sudo_sss_result_get(nss, pw, NULL);
-
- if (sss_result == NULL)
- debug_return_int(ret);
-
- /* Convert to sudoers parse tree. */
- if ((sss_userspecs = sss_to_sudoers(handle, sss_result)) == NULL) {
- ret = -1;
- goto done;
- }
-
- /* Call common display code. */
- ret = sudo_display_userspecs(sss_userspecs, pw, lbuf);
-
-done:
- /* Cleanup */
- handle->fn_free_result(sss_result);
- if (sss_userspecs != NULL) {
- struct userspec *us;
- while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
- TAILQ_REMOVE(sss_userspecs, us, entries);
- free_userspec(us);
- }
- free(sss_userspecs);
+ while ((us = TAILQ_FIRST(sss_userspecs)) != NULL) {
+ TAILQ_REMOVE(sss_userspecs, us, entries);
+ free_userspec(us);
}
- if (sudo_lbuf_error(lbuf))
- debug_return_int(-1);
- debug_return_int(ret);
+ debug_return_bool(false);
}
#endif /* HAVE_SSSD */
/* Iterators used by sudo_ldap_role_to_priv() to handle bervar ** or char ** */
typedef char * (*sudo_ldap_iter_t)(void **);
-/* ldap_common.c */
+/* ldap_util.c */
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);
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);
extern struct sudo_nss sudo_nss_sss;
#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. */
#define SUDO_NSS_CHECK_UNUSED(nss, tag) \
if (nss.entries.tqe_next != NULL || nss.entries.tqe_prev != NULL) { \
for ((cp = strtok_r(line + 8, " \t", &last)); cp != NULL; (cp = strtok_r(NULL, " \t", &last))) {
if (strcasecmp(cp, "files") == 0 && !saw_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;
#ifdef HAVE_LDAP
} else if (strcasecmp(cp, "ldap") == 0 && !saw_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;
#endif
#ifdef HAVE_SSSD
} else if (strcasecmp(cp, "sss") == 0 && !saw_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;
#endif
} else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
nomatch:
/* Default to files only if no matches */
if (TAILQ_EMPTY(&snl))
- TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+ sudo_nss_insert(&snl, &sudo_nss_file);
debug_return_ptr(&snl);
}
if (!saw_files && strncasecmp(cp, "files", 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;
ep = &cp[5];
#ifdef HAVE_LDAP
} else if (!saw_ldap && strncasecmp(cp, "ldap", 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;
ep = &cp[4];
#endif
#ifdef HAVE_SSSD
} else if (!saw_sss && strncasecmp(cp, "sss", 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;
ep = &cp[3];
#endif
nomatch:
/* Default to files only if no matches */
if (TAILQ_EMPTY(&snl))
- TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+ sudo_nss_insert(&snl, &sudo_nss_file);
debug_return_ptr(&snl);
}
debug_decl(sudo_read_nss, SUDOERS_DEBUG_NSS)
# ifdef HAVE_SSSD
- TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
+ sudo_nss_insert(&snl, &sudo_nss_sss);
# endif
# ifdef HAVE_LDAP
- TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
+ sudo_nss_insert(&snl, &sudo_nss_ldap);
# endif
- TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
+ sudo_nss_insert(&snl, &sudo_nss_file);
debug_return_ptr(&snl);
}
#endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
-static int
-output(const char *buf)
+bool
+sudo_nss_can_continue(struct sudo_nss *nss, int match)
{
- 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
-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;
- }
+ debug_decl(sudo_nss_should_continue, SUDOERS_DEBUG_NSS)
- /* 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;
+ /* Handle [NOTFOUND=return] */
+ if (nss->ret_if_notfound && match == UNSPEC)
+ debug_return_bool(false);
- sudo_lbuf_print(&defs);
- sudo_lbuf_print(&privs);
+ /* Handle [SUCCESS=return] */
+ if (nss->ret_if_found && match != UNSPEC)
+ debug_return_bool(false);
- 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);
+ debug_return_bool(true);
}
int (*open)(struct sudo_nss *nss);
int (*close)(struct sudo_nss *nss);
int (*parse)(struct sudo_nss *nss);
- int (*setdefs)(struct sudo_nss *nss);
- int (*lookup)(struct sudo_nss *nss, int, int);
- 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 *);
+ int (*query)(struct sudo_nss *nss, struct passwd *pw);
+ int (*getdefs)(struct sudo_nss *nss);
void *handle;
- short ret_if_found;
- short ret_if_notfound;
+ bool ret_if_found;
+ bool ret_if_notfound;
+ struct defaults_list defaults;
+ struct userspec_list userspecs;
};
TAILQ_HEAD(sudo_nss_list, sudo_nss);
struct sudo_nss_list *sudo_read_nss(void);
+bool sudo_nss_can_continue(struct sudo_nss *nss, int match);
#endif /* SUDOERS_NSS_H */
/*
- * 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
* purpose with or without fee is hereby granted, provided that the above
#include <ctype.h>
#include "sudoers.h"
+#include "parse.h"
#include "auth/sudo_auth.h"
#ifndef HAVE_GETADDRINFO
*/
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
sudo_warn_set_locale_func(sudoers_warn_setlocale);
+ init_parser(sudoers_file, false);
TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
sources++;
- if (nss->setdefs(nss) != 0) {
- log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
+ if (nss->getdefs(nss) != 0 || !update_defaults(&nss->defaults,
+ SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) {
+ log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
N_("problem with defaults entries"));
}
} else {
char *iolog_path = NULL;
mode_t cmnd_umask = ACCESSPERMS;
struct sudo_nss *nss;
- int nopass = -1;
int cmnd_status = -1, oldlocale, validated;
int ret = -1;
debug_decl(sudoers_policy_main, SUDOERS_DEBUG_PLUGIN)
* Check sudoers sources, using the locale specified in sudoers.
*/
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
- validated = FLAG_NO_USER | FLAG_NO_HOST;
- TAILQ_FOREACH(nss, snl, entries) {
- validated = nss->lookup(nss, validated, pwflag);
-
- /*
- * 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;
- }
+ validated = sudoers_lookup(snl, sudo_user.pw, FLAG_NO_USER | FLAG_NO_HOST,
+ pwflag);
+ if (ISSET(validated, VALIDATE_ERROR)) {
+ /* The lookup function should have printed an error. */
+ goto done;
}
- if (pwflag && nopass == true)
- def_authenticate = false;
/* Restore user's locale. */
sudoers_setlocale(oldlocale, NULL);
}
if (def_group_plugin)
group_plugin_unload();
+ init_parser(NULL, false);
if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
/* ret already set appropriately */
static int
set_cmnd(void)
{
- int ret = FOUND;
+ struct sudo_nss *nss;
char *path = user_path;
+ int ret = FOUND;
debug_decl(set_cmnd, SUDOERS_DEBUG_PLUGIN)
/* Allocate user_stat for find_path() and match functions. */
else
user_base = user_cmnd;
- if (!update_defaults(SETDEF_CMND, false)) {
- log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
- N_("problem with defaults entries"));
+ TAILQ_FOREACH(nss, snl, entries) {
+ if (!update_defaults(&nss->defaults, SETDEF_CMND, false)) {
+ log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR,
+ N_("problem with defaults entries"));
+ }
}
debug_return_int(ret);
#define FLAG_NO_CHECK 0x080
#define FLAG_NON_INTERACTIVE 0x100
#define FLAG_BAD_PASSWORD 0x200
-#define FLAG_NOPASSWD 0x400
/*
* find_path()/set_cmnd() return values
/* getspwuid.c */
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 */
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);
(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);
puts(".");
init_parser(sudoers_file, quiet);
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
(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);
editor = get_editor(&editor_argc, &editor_argv);
}
fclose(sudoersin);
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);
}
sudoers_setlocale(oldlocale, NULL);
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
}
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);
}
sudoers_setlocale(oldlocale, NULL);