diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 14:37:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 14:37:38 +0000 |
commit | ae581a19fbe896a797450b9d9573fb66f2735227 (patch) | |
tree | 56c40be8518a29c9351364d13a9676aa83932dc0 /plugins/sudoers/sssd.c | |
parent | Initial commit. (diff) | |
download | sudo-upstream.tar.xz sudo-upstream.zip |
Adding upstream version 1.9.13p3.upstream/1.9.13p3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | plugins/sudoers/sssd.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c new file mode 100644 index 0000000..d4c70b9 --- /dev/null +++ b/plugins/sudoers/sssd.c @@ -0,0 +1,813 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2003-2022 Todd C. Miller <Todd.Miller@sudo.ws> + * Copyright (c) 2011 Daniel Kopecek <dkopecek@redhat.com> + * + * This code is derived from software contributed by Aaron Spangler. + * + * 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. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include <config.h> + +#ifdef HAVE_SSSD + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif /* HAVE_STRINGS_H */ +#include <ctype.h> +#include <errno.h> +#include <pwd.h> + +#include "sudoers.h" +#include "sudo_lbuf.h" +#include "sudo_ldap.h" +#include "sudo_dso.h" + +/* SSSD <--> SUDO interface - do not change */ +struct sss_sudo_attr { + char *name; + char **values; + unsigned int num_values; +}; + +struct sss_sudo_rule { + unsigned int num_attrs; + struct sss_sudo_attr *attrs; +}; + +struct sss_sudo_result { + unsigned int num_rules; + struct sss_sudo_rule *rules; +}; + +typedef int (*sss_sudo_send_recv_t)(uid_t, const char*, const char*, + uint32_t*, struct sss_sudo_result**); + +typedef int (*sss_sudo_send_recv_defaults_t)(uid_t, const char*, uint32_t*, + char**, struct sss_sudo_result**); + +typedef void (*sss_sudo_free_result_t)(struct sss_sudo_result*); + +typedef int (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*, + char***); + +typedef void (*sss_sudo_free_values_t)(char**); + +/* sudo_nss handle */ +struct sudo_sss_handle { + char *domainname; + char *ipa_host; + char *ipa_shost; + struct passwd *pw; + void *ssslib; + struct sudoers_parse_tree parse_tree; + sss_sudo_send_recv_t fn_send_recv; + sss_sudo_send_recv_defaults_t fn_send_recv_defaults; + sss_sudo_free_result_t fn_free_result; + sss_sudo_get_values_t fn_get_values; + sss_sudo_free_values_t fn_free_values; +}; + +static int +get_ipa_hostname(char **shostp, char **lhostp) +{ + size_t linesize = 0; + char *lhost = NULL; + char *shost = NULL; + char *line = NULL; + int ret = false; + ssize_t len; + FILE *fp; + debug_decl(get_ipa_hostname, SUDOERS_DEBUG_SSSD); + + fp = fopen(_PATH_SSSD_CONF, "r"); + if (fp != NULL) { + while ((len = getdelim(&line, &linesize, '\n', fp)) != -1) { + char *cp = line; + + /* Trim trailing and leading spaces. */ + while (len > 0 && isspace((unsigned char)line[len - 1])) + line[--len] = '\0'; + while (isspace((unsigned char)*cp)) + cp++; + + /* + * Match ipa_hostname = foo + * Note: currently ignores the domain (XXX) + */ + if (strncmp(cp, "ipa_hostname", 12) == 0) { + cp += 12; + /* Trim " = " after "ipa_hostname" */ + while (isblank((unsigned char)*cp)) + cp++; + if (*cp++ != '=') + continue; + while (isblank((unsigned char)*cp)) + cp++; + /* Ignore empty value */ + if (*cp == '\0') + continue; + lhost = strdup(cp); + if (lhost != NULL && (cp = strchr(lhost, '.')) != NULL) { + shost = strndup(lhost, (size_t)(cp - lhost)); + } else { + shost = lhost; + } + if (shost != NULL && lhost != NULL) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "ipa_hostname %s overrides %s", lhost, user_host); + *shostp = shost; + *lhostp = lhost; + ret = true; + } else { + sudo_warnx(U_("%s: %s"), __func__, + U_("unable to allocate memory")); + free(shost); + free(lhost); + ret = -1; + } + break; + } + } + fclose(fp); + free(line); + } + debug_return_int(ret); +} + +/* + * SSSD doesn't handle netgroups, we have to ensure they are correctly filtered + * in sudo. The rules may contain mixed sudoUser specification so we have to + * check not only for netgroup membership but also for user and group matches. + * Otherwise, a netgroup non-match could override a user/group match. + */ +static bool +sudo_sss_check_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule) +{ + const char *host = handle->ipa_host ? handle->ipa_host : user_runhost; + const char *shost = handle->ipa_shost ? handle->ipa_shost : user_srunhost; + char **val_array; + int i, rc, ret = false; + debug_decl(sudo_sss_check_user, SUDOERS_DEBUG_SSSD); + + if (rule == NULL) + debug_return_bool(false); + + rc = handle->fn_get_values(rule, "sudoUser", &val_array); + switch (rc) { + case 0: + break; + case ENOENT: + sudo_debug_printf(SUDO_DEBUG_INFO, "No result."); + debug_return_bool(false); + case ENOMEM: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + FALLTHROUGH; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR, + "handle->fn_get_values(sudoOption): rc=%d", rc); + debug_return_bool(false); + } + + /* Walk through sudoUser values. */ + for (i = 0; val_array[i] != NULL && !ret; ++i) { + const char *val = val_array[i]; + bool negated = false; + + sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val); + if (*val == '!') { + val++; + negated = true; + } + switch (*val) { + case '+': + /* Netgroup spec found, check membership. */ + if (netgr_matches(val, def_netgroup_tuple ? host : NULL, + def_netgroup_tuple ? shost : NULL, handle->pw->pw_name)) { + ret = true; + } + break; + case '%': + /* User group found, check membership. */ + if (usergr_matches(val, handle->pw->pw_name, handle->pw)) { + ret = true; + } + break; + default: + /* Not a netgroup or user group. */ + if (strcmp(val, "ALL") == 0 || + userpw_matches(val, handle->pw->pw_name, handle->pw)) { + ret = true; + } + break; + } + sudo_debug_printf(SUDO_DEBUG_DIAG, + "sssd/ldap sudoUser '%s%s' ... %s (%s)", negated ? "!" : "", + val, ret ? "MATCH!" : "not", handle->pw->pw_name); + + /* A negated match overrides all other entries. */ + if (ret && negated) { + ret = false; + break; + } + } + handle->fn_free_values(val_array); + debug_return_bool(ret); +} + +static char * +val_array_iter(void **vp) +{ + char **val_array = *vp; + + *vp = val_array + 1; + + return *val_array; +} + +/* + * Wrapper for sudo_ldap_role_to_priv() that takes an sss rule.. + * Returns a struct privilege on success or NULL on failure. + */ +static struct privilege * +sss_rule_to_priv(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule, + int *rc_out) +{ + char **cmnds = NULL, **runasusers = NULL, **runasgroups = NULL; + char **opts = NULL, **notbefore = NULL, **notafter = NULL; + char **hosts = NULL, **cn_array = NULL, *cn = NULL; + struct privilege *priv = NULL; + int rc; + debug_decl(sss_rule_to_priv, SUDOERS_DEBUG_SSSD); + + /* Ignore sudoRole without sudoCommand or sudoHost. */ + rc = handle->fn_get_values(rule, "sudoCommand", &cmnds); + if (rc != 0) + goto cleanup; + rc = handle->fn_get_values(rule, "sudoHost", &hosts); + if (rc != 0) + goto cleanup; + + /* Get the entry's dn for long format printing. */ + rc = handle->fn_get_values(rule, "cn", &cn_array); + if (rc != 0) + goto cleanup; + cn = cn_array[0]; + + /* Get sudoRunAsUser / sudoRunAs */ + rc = handle->fn_get_values(rule, "sudoRunAsUser", &runasusers); + switch (rc) { + case 0: + break; + case ENOENT: + rc = handle->fn_get_values(rule, "sudoRunAs", &runasusers); + switch (rc) { + case 0: + case ENOENT: + break; + default: + goto cleanup; + } + break; + default: + goto cleanup; + } + + /* Get sudoRunAsGroup */ + rc = handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups); + switch (rc) { + case 0: + case ENOENT: + break; + default: + goto cleanup; + } + + /* Get sudoNotBefore */ + rc = handle->fn_get_values(rule, "sudoNotBefore", ¬before); + switch (rc) { + case 0: + case ENOENT: + break; + default: + goto cleanup; + } + + /* Get sudoNotAfter */ + rc = handle->fn_get_values(rule, "sudoNotAfter", ¬after); + switch (rc) { + case 0: + case ENOENT: + break; + default: + goto cleanup; + } + + /* Parse sudoOptions. */ + rc = handle->fn_get_values(rule, "sudoOption", &opts); + switch (rc) { + case 0: + case ENOENT: + break; + default: + goto cleanup; + } + + priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups, + cmnds, opts, notbefore ? notbefore[0] : NULL, + notafter ? notafter[0] : NULL, false, true, val_array_iter); + if (priv == NULL) { + rc = ENOMEM; + goto cleanup; + } + rc = 0; + +cleanup: + handle->fn_free_values(cn_array); + handle->fn_free_values(cmnds); + handle->fn_free_values(hosts); + handle->fn_free_values(runasusers); + handle->fn_free_values(runasgroups); + handle->fn_free_values(opts); + handle->fn_free_values(notbefore); + handle->fn_free_values(notafter); + + *rc_out = rc; + + debug_return_ptr(priv); +} + +static bool +sss_to_sudoers(struct sudo_sss_handle *handle, + struct sss_sudo_result *sss_result) +{ + struct userspec *us; + struct member *m; + unsigned int i; + debug_decl(sss_to_sudoers, SUDOERS_DEBUG_SSSD); + + /* We only have a single userspec */ + if ((us = calloc(1, sizeof(*us))) == NULL) + goto oom; + us->file = sudo_rcstr_dup("SSSD"); + TAILQ_INIT(&us->users); + TAILQ_INIT(&us->privileges); + STAILQ_INIT(&us->comments); + TAILQ_INSERT_TAIL(&handle->parse_tree.userspecs, us, entries); + + /* We only include rules where the user matches. */ + if ((m = sudo_ldap_new_member_all()) == NULL) + goto oom; + TAILQ_INSERT_TAIL(&us->users, m, entries); + + /* + * Treat each rule as a separate privilege. + * + * Sssd has already sorted the rules in descending order. + * The conversion to a sudoers parse tree requires that entries be + * in *ascending* order so we we iterate from last to first. + */ + for (i = sss_result->num_rules; i-- > 0; ) { + struct sss_sudo_rule *rule = sss_result->rules + i; + struct privilege *priv; + int rc; + + /* + * We don't know whether a rule was included due to a user/group + * match or because it contained a netgroup. + */ + if (!sudo_sss_check_user(handle, rule)) + continue; + + if ((priv = sss_rule_to_priv(handle, rule, &rc)) == NULL) { + if (rc == ENOMEM) + goto oom; + continue; + } + TAILQ_INSERT_TAIL(&us->privileges, priv, entries); + } + + debug_return_bool(true); + +oom: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + free_userspecs(&handle->parse_tree.userspecs); + debug_return_bool(false); +} + +static bool +sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule, struct defaults_list *defs) +{ + int i, rc; + char *source = NULL; + bool ret = false; + char **val_array = NULL; + char **cn_array = NULL; + debug_decl(sudo_sss_parse_options, SUDOERS_DEBUG_SSSD); + + if (rule == NULL) + debug_return_bool(true); + + rc = handle->fn_get_values(rule, "sudoOption", &val_array); + switch (rc) { + case 0: + break; + case ENOENT: + sudo_debug_printf(SUDO_DEBUG_INFO, "No result."); + debug_return_bool(true); + case ENOMEM: + goto oom; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR, + "handle->fn_get_values(sudoOption): rc=%d", rc); + debug_return_bool(false); + } + + /* Use sudoRole in place of file name in defaults. */ + if (handle->fn_get_values(rule, "cn", &cn_array) == 0) { + if (cn_array[0] != NULL) { + char *cp; + if (asprintf(&cp, "sudoRole %s", cn_array[0]) == -1) + goto oom; + source = sudo_rcstr_dup(cp); + free(cp); + if (source == NULL) + goto oom; + } + handle->fn_free_values(cn_array); + cn_array = NULL; + } + if (source == NULL) { + if ((source = sudo_rcstr_dup("sudoRole UNKNOWN")) == NULL) + goto oom; + } + + /* Walk through options, appending to defs. */ + for (i = 0; val_array[i] != NULL; i++) { + char *var, *val; + int op; + + op = sudo_ldap_parse_option(val_array[i], &var, &val); + if (!append_default(var, val, op, source, defs)) + goto oom; + } + ret = true; + goto done; + +oom: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + +done: + sudo_rcstr_delref(source); + handle->fn_free_values(val_array); + debug_return_bool(ret); +} + +static struct sss_sudo_result * +sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw) +{ + struct sudo_sss_handle *handle = nss->handle; + struct sss_sudo_result *sss_result = NULL; + uint32_t sss_error = 0, rc; + debug_decl(sudo_sss_result_get, SUDOERS_DEBUG_SSSD); + + sudo_debug_printf(SUDO_DEBUG_DIAG, " username=%s", pw->pw_name); + sudo_debug_printf(SUDO_DEBUG_DIAG, "domainname=%s", + handle->domainname ? handle->domainname : "NULL"); + + rc = handle->fn_send_recv(pw->pw_uid, pw->pw_name, + handle->domainname, &sss_error, &sss_result); + switch (rc) { + case 0: + break; + case ENOMEM: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + FALLTHROUGH; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR, "handle->fn_send_recv: rc=%d", rc); + debug_return_ptr(NULL); + } + + switch (sss_error) { + case 0: + if (sss_result != NULL) { + sudo_debug_printf(SUDO_DEBUG_INFO, "Received %u rule(s)", + sss_result->num_rules); + } else { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "Internal error: sss_result == NULL && sss_error == 0"); + debug_return_ptr(NULL); + } + break; + case ENOENT: + sudo_debug_printf(SUDO_DEBUG_INFO, "The user was not found in SSSD."); + debug_return_ptr(NULL); + default: + sudo_debug_printf(SUDO_DEBUG_ERROR, "sss_error=%u\n", sss_error); + debug_return_ptr(NULL); + } + + debug_return_ptr(sss_result); +} + +/* sudo_nss implementation */ +static int +sudo_sss_close(struct sudo_nss *nss) +{ + struct sudo_sss_handle *handle = nss->handle; + debug_decl(sudo_sss_close, SUDOERS_DEBUG_SSSD); + + if (handle != NULL) { + sudo_dso_unload(handle->ssslib); + if (handle->pw != NULL) + sudo_pw_delref(handle->pw); + free_parse_tree(&handle->parse_tree); + free(handle); + nss->handle = NULL; + } + debug_return_int(0); +} + +static int +sudo_sss_open(struct sudo_nss *nss) +{ + struct sudo_sss_handle *handle; + static const char path[] = _PATH_SSSD_LIB"/libsss_sudo.so"; + debug_decl(sudo_sss_open, SUDOERS_DEBUG_SSSD); + + if (nss->handle != NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "%s: called with non-NULL handle %p", __func__, nss->handle); + sudo_sss_close(nss); + } + + /* Create a handle container. */ + handle = calloc(1, sizeof(struct sudo_sss_handle)); + if (handle == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_int(ENOMEM); + } + + /* Load symbols */ + handle->ssslib = sudo_dso_load(path, SUDO_DSO_LAZY); + if (handle->ssslib == NULL) { + const char *errstr = sudo_dso_strerror(); + sudo_warnx(U_("unable to load %s: %s"), path, + errstr ? errstr : "unknown error"); + sudo_warnx("%s", + U_("unable to initialize SSS source. Is SSSD installed on your machine?")); + free(handle); + debug_return_int(EFAULT); + } + + handle->fn_send_recv = + sudo_dso_findsym(handle->ssslib, "sss_sudo_send_recv"); + if (handle->fn_send_recv == NULL) { + sudo_warnx(U_("unable to find symbol \"%s\" in %s"), path, + "sss_sudo_send_recv"); + free(handle); + debug_return_int(EFAULT); + } + + handle->fn_send_recv_defaults = + sudo_dso_findsym(handle->ssslib, "sss_sudo_send_recv_defaults"); + if (handle->fn_send_recv_defaults == NULL) { + sudo_warnx(U_("unable to find symbol \"%s\" in %s"), path, + "sss_sudo_send_recv_defaults"); + free(handle); + debug_return_int(EFAULT); + } + + handle->fn_free_result = + sudo_dso_findsym(handle->ssslib, "sss_sudo_free_result"); + if (handle->fn_free_result == NULL) { + sudo_warnx(U_("unable to find symbol \"%s\" in %s"), path, + "sss_sudo_free_result"); + free(handle); + debug_return_int(EFAULT); + } + + handle->fn_get_values = + sudo_dso_findsym(handle->ssslib, "sss_sudo_get_values"); + if (handle->fn_get_values == NULL) { + sudo_warnx(U_("unable to find symbol \"%s\" in %s"), path, + "sss_sudo_get_values"); + free(handle); + debug_return_int(EFAULT); + } + + handle->fn_free_values = + sudo_dso_findsym(handle->ssslib, "sss_sudo_free_values"); + if (handle->fn_free_values == NULL) { + sudo_warnx(U_("unable to find symbol \"%s\" in %s"), path, + "sss_sudo_free_values"); + free(handle); + debug_return_int(EFAULT); + } + + /* + * If runhost is the same as the local host, check for ipa_hostname + * in sssd.conf and use it in preference to user_runhost. + */ + if (strcasecmp(user_runhost, user_host) == 0) { + if (get_ipa_hostname(&handle->ipa_shost, &handle->ipa_host) == -1) { + free(handle); + debug_return_int(ENOMEM); + } + } + + /* The "parse tree" contains userspecs, defaults, aliases and hostnames. */ + init_parse_tree(&handle->parse_tree, handle->ipa_host, handle->ipa_shost); + nss->handle = handle; + + sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle); + + 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; + int ret = 0; + debug_decl(sudo_sss_query, SUDOERS_DEBUG_SSSD); + + if (handle == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "%s: called with NULL handle", __func__); + debug_return_int(-1); + } + + /* 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. */ + free_userspecs(&handle->parse_tree.userspecs); + + /* 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); + + /* Stash a ref to the passwd struct in the handle. */ + sudo_pw_addref(pw); + handle->pw = pw; + + /* Convert to sudoers parse tree if the user was found. */ + if (sss_result != NULL) { + if (!sss_to_sudoers(handle, sss_result)) { + ret = -1; + goto done; + } + } + +done: + /* Cleanup */ + handle->fn_free_result(sss_result); + if (ret == -1) { + free_userspecs(&handle->parse_tree.userspecs); + if (handle->pw != NULL) { + sudo_pw_delref(handle->pw); + handle->pw = NULL; + } + } + + sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches"); + + debug_return_int(ret); +} + +/* + * Return the initialized (but empty) sudoers parse tree. + * The contents will be populated by the getdefs() and query() functions. + */ +static struct sudoers_parse_tree * +sudo_sss_parse(struct sudo_nss *nss) +{ + struct sudo_sss_handle *handle = nss->handle; + debug_decl(sudo_sss_parse, SUDOERS_DEBUG_SSSD); + + if (handle == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "%s: called with NULL handle", __func__); + debug_return_ptr(NULL); + } + + debug_return_ptr(&handle->parse_tree); +} + +static int +sudo_sss_getdefs(struct sudo_nss *nss) +{ + struct sudo_sss_handle *handle = nss->handle; + struct sss_sudo_result *sss_result = NULL; + static bool cached; + uint32_t sss_error; + unsigned int i; + int rc; + debug_decl(sudo_sss_getdefs, SUDOERS_DEBUG_SSSD); + + if (handle == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "%s: called with NULL handle", __func__); + debug_return_int(-1); + } + + /* Use cached result if present. */ + if (cached) + debug_return_int(0); + + sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults"); + + /* NOTE: these are global defaults, user-ID and name are not used. */ + rc = handle->fn_send_recv_defaults(sudo_user.pw->pw_uid, + sudo_user.pw->pw_name, &sss_error, &handle->domainname, &sss_result); + switch (rc) { + case 0: + break; + case ENOMEM: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_int(-1); + default: + /* + * Unable to connect to the sudo SSSD connector. + * SSSD may not be configured for sudo, treat as non-fatal. + */ + sudo_debug_printf(SUDO_DEBUG_ERROR, + "handle->fn_send_recv_defaults: rc=%d, sss_error=%u", rc, sss_error); + debug_return_int(0); + } + + switch (sss_error) { + case 0: + /* Success */ + for (i = 0; i < sss_result->num_rules; ++i) { + struct sss_sudo_rule *sss_rule = sss_result->rules + i; + sudo_debug_printf(SUDO_DEBUG_DIAG, + "Parsing cn=defaults, %d/%d", i, sss_result->num_rules); + if (!sudo_sss_parse_options(handle, sss_rule, + &handle->parse_tree.defaults)) + goto bad; + } + break; + case ENOENT: + sudo_debug_printf(SUDO_DEBUG_INFO, + "No global defaults entry found in SSSD."); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR, "sss_error=%u\n", sss_error); + goto bad; + } + handle->fn_free_result(sss_result); + cached = true; + debug_return_int(0); + +bad: + handle->fn_free_result(sss_result); + debug_return_int(-1); +} + +/* sudo_nss implementation */ +struct sudo_nss sudo_nss_sss = { + { NULL, NULL }, + "sss", + sudo_sss_open, + sudo_sss_close, + sudo_sss_parse, + sudo_sss_query, + sudo_sss_getdefs +}; + +#endif /* HAVE_SSSD */ |