From: Todd C. Miller Date: Mon, 28 May 2018 13:35:51 +0000 (-0600) Subject: Reorder things to avoid the need to declare static functions. X-Git-Tag: SUDO_1_8_24^2~58 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e401f92830c4f2cc1d8a6e5d480f3b49c23ba0d2;p=sudo Reorder things to avoid the need to declare static functions. --- diff --git a/plugins/sudoers/file.c b/plugins/sudoers/file.c index c604f47b2..71e498392 100644 --- a/plugins/sudoers/file.c +++ b/plugins/sudoers/file.c @@ -38,25 +38,6 @@ #include "sudo_lbuf.h" #include -/* - * 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) { @@ -134,3 +115,13 @@ sudo_file_getdefs(struct sudo_nss *nss) debug_decl(sudo_file_getdefs, SUDOERS_DEBUG_NSS) debug_return_int(0); } + +/* 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 +}; diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index f0b0b36d9..c3f34f401 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -144,16 +144,6 @@ struct ldap_netgroup { }; STAILQ_HEAD(ldap_netgroup_list, ldap_netgroup); -/* sudo_nss implementation */ -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_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 and the passwd struct of the @@ -164,15 +154,6 @@ struct sudo_ldap_handle { struct passwd *pw; }; -struct sudo_nss sudo_nss_ldap = { - { NULL, NULL }, - sudo_ldap_open, - sudo_ldap_close, - sudo_ldap_parse, - sudo_ldap_query, - sudo_ldap_getdefs -}; - #ifdef HAVE_LDAP_INITIALIZE static char * sudo_ldap_join_uri(struct ldap_config_str_list *uri_list) @@ -369,6 +350,37 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw) debug_return_bool(ret); } +/* + * Extract the dn from an entry and return the first rdn from it. + */ +static char * +sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry) +{ +#ifdef HAVE_LDAP_STR2DN + char *dn, *rdn = NULL; + LDAPDN tmpDN; + debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP) + + if ((dn = ldap_get_dn(ld, entry)) == NULL) + debug_return_str(NULL); + if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) { + ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN); + ldap_dnfree(tmpDN); + } + ldap_memfree(dn); + debug_return_str(rdn); +#else + char *dn, **edn; + debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP) + + if ((dn = ldap_get_dn(ld, entry)) == NULL) + debug_return_str(NULL); + edn = ldap_explode_dn(dn, 1); + ldap_memfree(dn); + debug_return_str(edn ? edn[0] : NULL); +#endif +} + /* * Read sudoOption and fill in the defaults list. * This is used to parse the cn=defaults entry. @@ -1106,37 +1118,6 @@ sudo_ldap_build_pass2(void) debug_return_str(filt); } -/* - * Extract the dn from an entry and return the first rdn from it. - */ -static char * -sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry) -{ -#ifdef HAVE_LDAP_STR2DN - char *dn, *rdn = NULL; - LDAPDN tmpDN; - debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP) - - if ((dn = ldap_get_dn(ld, entry)) == NULL) - debug_return_str(NULL); - if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) { - ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN); - ldap_dnfree(tmpDN); - } - ldap_memfree(dn); - debug_return_str(rdn); -#else - char *dn, **edn; - debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP) - - if ((dn = ldap_get_dn(ld, entry)) == NULL) - debug_return_str(NULL); - edn = ldap_explode_dn(dn, 1); - ldap_memfree(dn); - debug_return_str(edn ? edn[0] : NULL); -#endif -} - static char * berval_iter(void **vp) { @@ -2055,3 +2036,13 @@ sudo_ldap_result_from_search(LDAP *ldap, LDAPMessage *searchresult) return result; } #endif + +/* sudo_nss implementation */ +struct sudo_nss sudo_nss_ldap = { + { NULL, NULL }, + sudo_ldap_open, + sudo_ldap_close, + sudo_ldap_parse, + sudo_ldap_query, + sudo_ldap_getdefs +}; diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index 9ecdd4109..da69f32ec 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -76,8 +76,7 @@ typedef int (*sss_sudo_get_values_t)(struct sss_sudo_rule*, const char*, typedef void (*sss_sudo_free_values_t)(char**); -/* sudo_nss implementation */ - +/* sudo_nss handle */ struct sudo_sss_handle { char *domainname; char *ipa_host; @@ -91,24 +90,6 @@ struct sudo_sss_handle { sss_sudo_free_values_t fn_free_values; }; -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_getdefs(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, - struct defaults_list *defs); - - -static struct sss_sudo_result *sudo_sss_result_get(struct sudo_nss *nss, - 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 int get_ipa_hostname(char **shostp, char **lhostp) { @@ -176,253 +157,6 @@ get_ipa_hostname(char **shostp, char **lhostp) debug_return_int(ret); } -struct sudo_nss sudo_nss_sss = { - { NULL, NULL }, - sudo_sss_open, - sudo_sss_close, - sudo_sss_parse, - sudo_sss_query, - sudo_sss_getdefs -}; - -/* sudo_nss implementation */ -// ok -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); - - /* 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(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); - } - - nss->handle = handle; - - /* - * 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); - } - } - - sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle); - - debug_return_int(0); -} - -// ok -static int -sudo_sss_close(struct sudo_nss *nss) -{ - 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? */ - free_userspecs(&nss->userspecs); - free_defaults(&nss->defaults); - } - 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); - - /* 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(&nss->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); - - if (sss_result == NULL) - goto done; - - /* Stash a ref to the passwd struct in the handle. */ - sudo_pw_addref(pw); - handle->pw = pw; - - /* Convert to sudoers parse tree. */ - if (!sss_to_sudoers(handle, sss_result, &nss->userspecs)) { - ret = -1; - goto done; - } - -done: - /* Cleanup */ - handle->fn_free_result(sss_result); - if (ret == -1) { - free_userspecs(&nss->userspecs); - sudo_pw_delref(handle->pw); - handle->pw = NULL; - } - - sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches"); - - debug_return_int(ret); -} - -// ok -static int -sudo_sss_parse(struct sudo_nss *nss) -{ - debug_decl(sudo_sss_parse, SUDOERS_DEBUG_SSSD); - debug_return_int(0); -} - -static int -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; - uint32_t sss_error; - unsigned int i; - int rc; - debug_decl(sudo_sss_getdefs, SUDOERS_DEBUG_SSSD); - - if (handle == NULL) - debug_return_int(-1); - - /* Free old defaults, if any. */ - free_defaults(&nss->defaults); - - 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")); - /* FALLTHROUGH */ - default: - sudo_debug_printf(SUDO_DEBUG_INFO, - "handle->fn_send_recv_defaults: rc=%d, sss_error=%u", rc, sss_error); - debug_return_int(-1); - } - if (sss_error != 0) { - if (sss_error == ENOENT) { - sudo_debug_printf(SUDO_DEBUG_INFO, - "The user was not found in SSSD."); - goto done; - } - sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error); - goto bad; - } - - for (i = 0; i < sss_result->num_rules; ++i) { - 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, &nss->defaults)) - goto bad; - } - -done: - handle->fn_free_result(sss_result); - debug_return_int(0); -bad: - handle->fn_free_result(sss_result); - debug_return_int(-1); -} - /* * 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 @@ -488,125 +222,6 @@ sudo_sss_check_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule) 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: - 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_INFO, - "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_INFO, "sss_error=%u\n", sss_error); - debug_return_ptr(NULL); - } - break; - case ENOMEM: - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - /* FALLTHROUGH */ - default: - sudo_debug_printf(SUDO_DEBUG_INFO, - "handle->fn_send_recv: rc=%d", rc); - debug_return_ptr(NULL); - } - - debug_return_ptr(sss_result); -} - -static bool -sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule, struct defaults_list *defs) -{ - int i; - 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); - - switch (handle->fn_get_values(rule, "sudoOption", &val_array)) { - 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_INFO, "handle->fn_get_values(sudoOption): != 0"); - 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 = rcstr_dup(cp); - free(cp); - if (source == NULL) - goto oom; - } - handle->fn_free_values(cn_array); - cn_array = NULL; - } - if (source == NULL) { - if ((source = rcstr_dup("sudoRole UNKNOWN")) == NULL) - goto oom; - } - - /* Walk through options, appending to defs. */ - for (i = 0; val_array[i] != NULL; i++) { - 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 (!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: - rcstr_delref(source); - handle->fn_free_values(val_array); - debug_return_bool(ret); -} - static char * val_array_iter(void **vp) { @@ -618,7 +233,8 @@ val_array_iter(void **vp) } static bool -sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_result, struct userspec_list *sss_userspecs) +sss_to_sudoers(struct sudo_sss_handle *handle, + struct sss_sudo_result *sss_result, struct userspec_list *sss_userspecs) { struct userspec *us; struct member *m; @@ -771,4 +387,372 @@ oom: free_userspecs(sss_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; + 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); + + switch (handle->fn_get_values(rule, "sudoOption", &val_array)) { + 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_INFO, "handle->fn_get_values(sudoOption): != 0"); + 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 = rcstr_dup(cp); + free(cp); + if (source == NULL) + goto oom; + } + handle->fn_free_values(cn_array); + cn_array = NULL; + } + if (source == NULL) { + if ((source = rcstr_dup("sudoRole UNKNOWN")) == NULL) + goto oom; + } + + /* Walk through options, appending to defs. */ + for (i = 0; val_array[i] != NULL; i++) { + 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 (!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: + 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: + 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_INFO, + "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_INFO, "sss_error=%u\n", sss_error); + debug_return_ptr(NULL); + } + break; + case ENOMEM: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + /* FALLTHROUGH */ + default: + sudo_debug_printf(SUDO_DEBUG_INFO, + "handle->fn_send_recv: rc=%d", rc); + debug_return_ptr(NULL); + } + + debug_return_ptr(sss_result); +} + +/* sudo_nss implementation */ +// ok +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); + + /* 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(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); + } + + nss->handle = handle; + + /* + * 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); + } + } + + sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle); + + debug_return_int(0); +} + +// ok +static int +sudo_sss_close(struct sudo_nss *nss) +{ + 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? */ + free_userspecs(&nss->userspecs); + free_defaults(&nss->defaults); + } + 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); + + /* 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(&nss->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); + + if (sss_result == NULL) + goto done; + + /* Stash a ref to the passwd struct in the handle. */ + sudo_pw_addref(pw); + handle->pw = pw; + + /* Convert to sudoers parse tree. */ + if (!sss_to_sudoers(handle, sss_result, &nss->userspecs)) { + ret = -1; + goto done; + } + +done: + /* Cleanup */ + handle->fn_free_result(sss_result); + if (ret == -1) { + free_userspecs(&nss->userspecs); + sudo_pw_delref(handle->pw); + handle->pw = NULL; + } + + sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches"); + + debug_return_int(ret); +} + +// ok +static int +sudo_sss_parse(struct sudo_nss *nss) +{ + debug_decl(sudo_sss_parse, SUDOERS_DEBUG_SSSD); + debug_return_int(0); +} + +static int +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; + uint32_t sss_error; + unsigned int i; + int rc; + debug_decl(sudo_sss_getdefs, SUDOERS_DEBUG_SSSD); + + if (handle == NULL) + debug_return_int(-1); + + /* Free old defaults, if any. */ + free_defaults(&nss->defaults); + + 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")); + /* FALLTHROUGH */ + default: + sudo_debug_printf(SUDO_DEBUG_INFO, + "handle->fn_send_recv_defaults: rc=%d, sss_error=%u", rc, sss_error); + debug_return_int(-1); + } + if (sss_error != 0) { + if (sss_error == ENOENT) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "The user was not found in SSSD."); + goto done; + } + sudo_debug_printf(SUDO_DEBUG_INFO, "sss_error=%u\n", sss_error); + goto bad; + } + + for (i = 0; i < sss_result->num_rules; ++i) { + 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, &nss->defaults)) + goto bad; + } + +done: + handle->fn_free_result(sss_result); + 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 }, + sudo_sss_open, + sudo_sss_close, + sudo_sss_parse, + sudo_sss_query, + sudo_sss_getdefs +}; + #endif /* HAVE_SSSD */