diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index 7fd1dec29..f0ec3c532 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2003-2019 Todd C. Miller + * Copyright (c) 2003-2020 Todd C. Miller * * This code is derived from software contributed by Aaron Spangler. * @@ -361,16 +361,21 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw) * Extract the dn from an entry and return the first rdn from it. */ static char * -sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry) +sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry, int *rc) { #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) + if ((dn = ldap_get_dn(ld, entry)) == NULL) { + int optrc = ldap_get_option(ld, LDAP_OPT_RESULT_CODE, rc); + if (optrc != LDAP_OPT_SUCCESS) + *rc = optrc; debug_return_str(NULL); - if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) { + } + *rc = ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP); + if (*rc == LDAP_SUCCESS) { ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN); ldap_dnfree(tmpDN); } @@ -380,11 +385,20 @@ sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry) char *dn, **edn; debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP); - if ((dn = ldap_get_dn(ld, entry)) == NULL) + if ((dn = ldap_get_dn(ld, entry)) == NULL) { + int optrc = ldap_get_option(ld, LDAP_OPT_RESULT_CODE, rc); + if (optrc != LDAP_OPT_SUCCESS) + *rc = optrc; debug_return_str(NULL); + } edn = ldap_explode_dn(dn, 1); ldap_memfree(dn); - debug_return_str(edn ? edn[0] : NULL); + if (edn == NULL) { + *rc = LDAP_NO_MEMORY; + debug_return_str(NULL); + } + *rc = LDAP_SUCCESS; + debug_return_str(edn[0]); #endif } @@ -403,13 +417,21 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs bv = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc); if (bv == NULL) { - if (rc == LDAP_NO_MEMORY) + if (rc == LDAP_NO_MEMORY) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_bool(false); + } debug_return_bool(true); } /* Use sudoRole in place of file name in defaults. */ - cn = sudo_ldap_get_first_rdn(ld, entry); + cn = sudo_ldap_get_first_rdn(ld, entry, &rc); + if (cn == NULL) { + if (rc == LDAP_NO_MEMORY) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + goto done; + } + } if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); goto done; @@ -1131,6 +1153,88 @@ berval_iter(void **vp) return *bv ? (*bv)->bv_val : NULL; } +/* + * Wrapper for sudo_ldap_role_to_priv() that takes an LDAPMessage. + * Returns a struct privilege on success or NULL on failure. + */ +static struct privilege * +ldap_entry_to_priv(LDAP *ld, LDAPMessage *entry, int *rc_out) +{ + struct berval **cmnds = NULL, **hosts = NULL; + struct berval **runasusers = NULL, **runasgroups = NULL; + struct berval **opts = NULL, **notbefore = NULL, **notafter = NULL; + struct privilege *priv = NULL; + char *cn = NULL; + int rc; + debug_decl(ldap_entry_to_priv, SUDOERS_DEBUG_LDAP); + + /* Ignore sudoRole without sudoCommand or sudoHost. */ + cmnds = sudo_ldap_get_values_len(ld, entry, "sudoCommand", &rc); + if (cmnds == NULL) + goto cleanup; + hosts = sudo_ldap_get_values_len(ld, entry, "sudoHost", &rc); + if (hosts == NULL) + goto cleanup; + + /* Get the entry's dn for long format printing. */ + if ((cn = sudo_ldap_get_first_rdn(ld, entry, &rc)) == NULL) + goto cleanup; + + /* Get sudoRunAsUser / sudoRunAsGroup */ + runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAsUser", &rc); + if (runasusers == NULL) { + if (rc != LDAP_NO_MEMORY) + runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAs", &rc); + if (rc == LDAP_NO_MEMORY) + goto cleanup; + } + runasgroups = sudo_ldap_get_values_len(ld, entry, "sudoRunAsGroup", &rc); + if (rc == LDAP_NO_MEMORY) + goto cleanup; + + /* Get sudoNotBefore / sudoNotAfter */ + notbefore = sudo_ldap_get_values_len(ld, entry, "sudoNotBefore", &rc); + if (rc == LDAP_NO_MEMORY) + goto cleanup; + notafter = sudo_ldap_get_values_len(ld, entry, "sudoNotAfter", &rc); + if (rc == LDAP_NO_MEMORY) + goto cleanup; + + /* Parse sudoOptions. */ + opts = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc); + if (rc == LDAP_NO_MEMORY) + goto cleanup; + + priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups, + cmnds, opts, notbefore ? notbefore[0]->bv_val : NULL, + notafter ? notafter[0]->bv_val : NULL, false, true, berval_iter); + if (priv == NULL) { + rc = LDAP_NO_MEMORY; + goto cleanup; + } + +cleanup: + if (cn != NULL) + ldap_memfree(cn); + if (cmnds != NULL) + ldap_value_free_len(cmnds); + if (hosts != NULL) + ldap_value_free_len(hosts); + if (runasusers != NULL) + ldap_value_free_len(runasusers); + if (runasgroups != NULL) + ldap_value_free_len(runasgroups); + if (opts != NULL) + ldap_value_free_len(opts); + if (notbefore != NULL) + ldap_value_free_len(notbefore); + if (notafter != NULL) + ldap_value_free_len(notafter); + + *rc_out = rc; + debug_return_ptr(priv); +} + static bool ldap_to_sudoers(LDAP *ld, struct ldap_result *lres, struct userspec_list *ldap_userspecs) @@ -1155,81 +1259,16 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres, m->type = ALL; TAILQ_INSERT_TAIL(&us->users, m, entries); - /* Treat each sudoRole as a separate privilege. */ + /* Treat each entry as a separate privilege. */ for (i = 0; i < lres->nentries; i++) { - LDAPMessage *entry = lres->entries[i].entry; - struct berval **cmnds = NULL, **hosts = NULL; - struct berval **runasusers = NULL, **runasgroups = NULL; - struct berval **opts = NULL, **notbefore = NULL, **notafter = NULL; - struct privilege *priv = NULL; - char *cn = NULL; + struct privilege *priv; - /* Ignore sudoRole without sudoCommand. */ - cmnds = sudo_ldap_get_values_len(ld, entry, "sudoCommand", &rc); - if (cmnds == NULL) { + priv = ldap_entry_to_priv(ld, lres->entries[i].entry, &rc); + if (priv == NULL) { if (rc == LDAP_NO_MEMORY) - goto cleanup; + goto oom; continue; } - - /* Get the entry's dn for long format printing. */ - if ((cn = sudo_ldap_get_first_rdn(ld, entry)) == NULL) - goto cleanup; - - /* Get sudoHost */ - hosts = sudo_ldap_get_values_len(ld, entry, "sudoHost", &rc); - if (rc == LDAP_NO_MEMORY) - goto cleanup; - - /* Get sudoRunAsUser / sudoRunAsGroup */ - runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAsUser", &rc); - if (runasusers == NULL) { - if (rc != LDAP_NO_MEMORY) - runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAs", &rc); - if (rc == LDAP_NO_MEMORY) - goto cleanup; - } - runasgroups = sudo_ldap_get_values_len(ld, entry, "sudoRunAsGroup", &rc); - if (rc == LDAP_NO_MEMORY) - goto cleanup; - - /* Get sudoNotBefore / sudoNotAfter */ - notbefore = sudo_ldap_get_values_len(ld, entry, "sudoNotBefore", &rc); - if (rc == LDAP_NO_MEMORY) - goto cleanup; - notafter = sudo_ldap_get_values_len(ld, entry, "sudoNotAfter", &rc); - if (rc == LDAP_NO_MEMORY) - goto cleanup; - - /* Parse sudoOptions. */ - opts = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc); - if (rc == LDAP_NO_MEMORY) - goto cleanup; - - priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups, - cmnds, opts, notbefore ? notbefore[0]->bv_val : NULL, - notafter ? notafter[0]->bv_val : NULL, false, true, berval_iter); - - cleanup: - if (cn != NULL) - ldap_memfree(cn); - if (cmnds != NULL) - ldap_value_free_len(cmnds); - if (hosts != NULL) - ldap_value_free_len(hosts); - if (runasusers != NULL) - ldap_value_free_len(runasusers); - if (runasgroups != NULL) - ldap_value_free_len(runasgroups); - if (opts != NULL) - ldap_value_free_len(opts); - if (notbefore != NULL) - ldap_value_free_len(notbefore); - if (notafter != NULL) - ldap_value_free_len(notafter); - - if (priv == NULL) - goto oom; TAILQ_INSERT_TAIL(&us->privileges, priv, entries); } diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index f65766bbb..3000ca7e0 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2003-2018 Todd C. Miller + * Copyright (c) 2003-2020 Todd C. Miller * Copyright (c) 2011 Daniel Kopecek * * This code is derived from software contributed by Aaron Spangler. @@ -232,6 +232,126 @@ val_array_iter(void **vp) 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, **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: + if (cn_array != NULL) + handle->fn_free_values(cn_array); + if (cmnds != NULL) + handle->fn_free_values(cmnds); + if (hosts != NULL) + handle->fn_free_values(hosts); + if (runasusers != NULL) + handle->fn_free_values(runasusers); + if (runasgroups != NULL) + handle->fn_free_values(runasgroups); + if (opts != NULL) + handle->fn_free_values(opts); + if (notbefore != NULL) + handle->fn_free_values(notbefore); + if (notafter != NULL) + 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) @@ -256,7 +376,7 @@ sss_to_sudoers(struct sudo_sss_handle *handle, TAILQ_INSERT_TAIL(&us->users, m, entries); /* - * Treat each sudoRole as a separate privilege. + * 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 @@ -264,10 +384,8 @@ sss_to_sudoers(struct sudo_sss_handle *handle, */ for (i = sss_result->num_rules; i-- > 0; ) { struct sss_sudo_rule *rule = sss_result->rules + i; - char **cmnds, **runasusers = NULL, **runasgroups = NULL; - char **opts = NULL, **notbefore = NULL, **notafter = NULL; - char **hosts = NULL, **cn_array = NULL, *cn = NULL; - struct privilege *priv = NULL; + struct privilege *priv; + int rc; /* * We don't know whether a rule was included due to a user/group @@ -276,113 +394,11 @@ sss_to_sudoers(struct sudo_sss_handle *handle, if (!sudo_sss_check_user(handle, rule)) continue; - switch (handle->fn_get_values(rule, "sudoCommand", &cmnds)) { - case 0: - break; - case ENOENT: - /* Ignore sudoRole without sudoCommand. */ + if ((priv = sss_rule_to_priv(handle, rule, &rc)) == NULL) { + if (rc == ENOMEM) + goto oom; continue; - default: - goto cleanup; } - - /* Get the entry's dn for long format printing. */ - switch (handle->fn_get_values(rule, "cn", &cn_array)) { - case 0: - cn = cn_array[0]; - break; - case ENOENT: - break; - default: - goto cleanup; - } - - /* Get sudoHost */ - switch (handle->fn_get_values(rule, "sudoHost", &hosts)) { - case 0: - case ENOENT: - break; - default: - goto cleanup; - } - - /* Get sudoRunAsUser / sudoRunAs */ - switch (handle->fn_get_values(rule, "sudoRunAsUser", &runasusers)) { - case 0: - break; - case ENOENT: - switch (handle->fn_get_values(rule, "sudoRunAs", &runasusers)) { - case 0: - case ENOENT: - break; - default: - goto cleanup; - } - break; - default: - goto cleanup; - } - - /* Get sudoRunAsGroup */ - switch (handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups)) { - case 0: - case ENOENT: - break; - default: - goto cleanup; - } - - /* Get sudoNotBefore */ - switch (handle->fn_get_values(rule, "sudoNotBefore", ¬before)) { - case 0: - case ENOENT: - break; - default: - goto cleanup; - } - - /* Get sudoNotAfter */ - switch (handle->fn_get_values(rule, "sudoNotAfter", ¬after)) { - case 0: - case ENOENT: - break; - default: - goto cleanup; - } - - /* Parse sudoOptions. */ - switch (handle->fn_get_values(rule, "sudoOption", &opts)) { - 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); - - cleanup: - if (cn_array != NULL) - handle->fn_free_values(cn_array); - if (cmnds != NULL) - handle->fn_free_values(cmnds); - if (hosts != NULL) - handle->fn_free_values(hosts); - if (runasusers != NULL) - handle->fn_free_values(runasusers); - if (runasgroups != NULL) - handle->fn_free_values(runasgroups); - if (opts != NULL) - handle->fn_free_values(opts); - if (notbefore != NULL) - handle->fn_free_values(notbefore); - if (notafter != NULL) - handle->fn_free_values(notafter); - - if (priv == NULL) - goto oom; TAILQ_INSERT_TAIL(&us->privileges, priv, entries); }