From: Todd C. Miller Date: Mon, 14 May 2018 15:05:05 +0000 (-0600) Subject: Add checks for ldap/sss functions failing due to memory allocation X-Git-Tag: SUDO_1_8_24^2~85 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d052f8a68b0a87d8842d2ad29785b231d2c6259c;p=sudo Add checks for ldap/sss functions failing due to memory allocation errors. --- diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index 244bf628d..78afd151d 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -60,6 +60,14 @@ #include "sudo_ldap_conf.h" #include "sudo_dso.h" +#ifndef LDAP_OPT_RESULT_CODE +# define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER +#endif + +#ifndef LDAP_OPT_SUCCESS +# define LDAP_OPT_SUCCESS LDAP_SUCCESS +#endif + #if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET) # define LDAP_SASL_QUIET 0 #endif @@ -295,25 +303,49 @@ done: debug_return_int(ret); } +/* + * Wrapper for ldap_get_values_len() that fills in the response code + * on error. + */ +static struct berval ** +sudo_ldap_get_values_len(LDAP *ld, LDAPMessage *entry, char *attr, int *rc) +{ + struct berval **bval; + + bval = ldap_get_values_len(ld, entry, attr); + if (bval == NULL) { + int optrc = ldap_get_option(ld, LDAP_OPT_RESULT_CODE, rc); + if (optrc != LDAP_OPT_SUCCESS) + *rc = optrc; + } else { + *rc = LDAP_SUCCESS; + } + return bval; +} + /* * Walk through search results and return true if we have a matching * non-Unix group (including netgroups), else false. */ -static bool +static int sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw) { struct berval **bv, **p; - char *val; bool ret = false; + char *val; + int rc; debug_decl(sudo_ldap_check_non_unix_group, SUDOERS_DEBUG_LDAP) if (!entry) debug_return_bool(ret); /* get the values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoUser"); - if (bv == NULL) - debug_return_bool(ret); + bv = sudo_ldap_get_values_len(ld, entry, "sudoUser", &rc); + if (bv == NULL) { + if (rc == LDAP_NO_MEMORY) + debug_return_int(-1); + debug_return_bool(false); + } /* walk through values */ for (p = bv; *p != NULL && !ret; p++) { @@ -347,11 +379,15 @@ sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry, struct defaults_list *defs struct berval **bv, **p; char *cn, *cp, *source = NULL; bool ret = false; + int rc; debug_decl(sudo_ldap_parse_options, SUDOERS_DEBUG_LDAP) - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv == NULL) + bv = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc); + if (bv == NULL) { + if (rc == LDAP_NO_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); @@ -447,6 +483,7 @@ sudo_ldap_timefilter(char *buffer, size_t buffersize) timebuffer, timebuffer); if (len <= 0 || (size_t)len >= buffersize) { sudo_warnx(U_("internal error, %s overflow"), __func__); + errno = EOVERFLOW; len = -1; } @@ -633,8 +670,11 @@ sudo_netgroup_lookup_nested(LDAP *ld, char *base, struct timeval *timeout, LDAP_FOREACH(entry, ld, result) { struct berval **bv; - bv = ldap_get_values_len(ld, entry, "cn"); - if (bv != NULL) { + bv = sudo_ldap_get_values_len(ld, entry, "cn", &rc); + if (bv == NULL) { + if (rc == LDAP_NO_MEMORY) + goto oom; + } else { /* Don't add a netgroup twice. */ STAILQ_FOREACH(ng, netgroups, entries) { /* Assumes only one cn per entry. */ @@ -792,8 +832,11 @@ sudo_netgroup_lookup(LDAP *ld, struct passwd *pw, LDAP_FOREACH(entry, ld, result) { struct berval **bv; - bv = ldap_get_values_len(ld, entry, "cn"); - if (bv != NULL) { + bv = sudo_ldap_get_values_len(ld, entry, "cn", &rc); + if (bv == NULL) { + if (rc == LDAP_NO_MEMORY) + goto oom; + } else { /* Don't add a netgroup twice. */ STAILQ_FOREACH(ng, netgroups, entries) { /* Assumes only one cn per entry. */ @@ -910,10 +953,8 @@ sudo_ldap_build_pass1(LDAP *ld, struct passwd *pw) /* If timed, add space for time limits. */ if (ldap_conf.timed) sz += TIMEFILTER_LENGTH; - if ((buf = malloc(sz)) == NULL) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + if ((buf = malloc(sz)) == NULL) goto bad; - } *buf = '\0'; /* @@ -1004,6 +1045,7 @@ overflow: free(ng->name); free(ng); } + errno = EOVERFLOW; bad: while ((ng = STAILQ_FIRST(&netgroups)) != NULL) { STAILQ_REMOVE_HEAD(&netgroups, entries); @@ -1059,7 +1101,7 @@ sudo_ldap_build_pass2(void) ldap_conf.timed ? timebuffer : ""); } if (len == -1) - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + filt = NULL; debug_return_str(filt); } @@ -1088,7 +1130,7 @@ sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry) debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP) if ((dn = ldap_get_dn(ld, entry)) == NULL) - return NULL; + debug_return_str(NULL); edn = ldap_explode_dn(dn, 1); ldap_memfree(dn); debug_return_str(edn ? edn[0] : NULL); @@ -1111,6 +1153,7 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres, struct userspec *us; struct member *m; unsigned int i; + int rc; debug_decl(ldap_to_sudoers, SUDOERS_DEBUG_LDAP) /* We only have a single userspec */ @@ -1130,43 +1173,60 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres, /* Treat each sudoRole as a separate privilege. */ for (i = 0; i < lres->nentries; i++) { LDAPMessage *entry = lres->entries[i].entry; - struct berval **cmnds, **runasusers, **runasgroups, **hosts; - struct berval **opts, **notbefore, **notafter; - struct privilege *priv; + 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; - /* XXX - check for errors, e.g. ld->ld_errno == LDAP_NO_MEMORY */ - /* Ignore sudoRole without sudoCommand. */ - cmnds = ldap_get_values_len(ld, entry, "sudoCommand"); - if (cmnds == NULL) + cmnds = sudo_ldap_get_values_len(ld, entry, "sudoCommand", &rc); + if (cmnds == NULL) { + if (rc == LDAP_NO_MEMORY) + goto oom; continue; + } /* Get the entry's dn for long format printing. */ - cn = sudo_ldap_get_first_rdn(ld, entry); + if ((cn = sudo_ldap_get_first_rdn(ld, entry)) == NULL) + goto cleanup; /* Get sudoHost */ - hosts = ldap_get_values_len(ld, entry, "sudoHost"); + hosts = sudo_ldap_get_values_len(ld, entry, "sudoHost", &rc); + if (rc == LDAP_NO_MEMORY) + goto cleanup; /* Get sudoRunAsUser / sudoRunAsGroup */ - runasusers = ldap_get_values_len(ld, entry, "sudoRunAsUser"); - if (runasusers == NULL) - runasusers = ldap_get_values_len(ld, entry, "sudoRunAs"); - runasgroups = ldap_get_values_len(ld, entry, "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 = ldap_get_values_len(ld, entry, "sudoNotBefore"); + if (rc == LDAP_NO_MEMORY) + goto cleanup; notafter = ldap_get_values_len(ld, entry, "sudoNotAfter"); + if (rc == LDAP_NO_MEMORY) + goto cleanup; /* Parse sudoOptions. */ opts = ldap_get_values_len(ld, entry, "sudoOption"); + 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, long_list, berval_iter); - /* Cleanup */ + cleanup: if (cn != NULL) ldap_memfree(cn); if (cmnds != NULL) @@ -1697,13 +1757,17 @@ sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry) struct berval **bv; double order = 0.0; char *ep; + int rc; debug_decl(sudo_ldap_result_add_entry, SUDOERS_DEBUG_LDAP) /* Determine whether the entry has the sudoOrder attribute. */ last = sudo_ldap_result_last_search(lres); if (last != NULL) { - bv = ldap_get_values_len(last->ldap, entry, "sudoOrder"); - if (bv != NULL) { + bv = sudo_ldap_get_values_len(last->ldap, entry, "sudoOrder", &rc); + if (rc == LDAP_NO_MEMORY) { + /* XXX - return error */ + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + } else { if (ldap_count_values_len(bv) > 0) { /* Get the value of this attribute, 0 if not present. */ DPRINTF2("order attribute raw: %s", (*bv)->bv_val); @@ -1781,8 +1845,8 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw) struct timeval tv, *tvp = NULL; LDAPMessage *entry, *result; LDAP *ld = handle->ld; + char *filt = NULL; int pass, rc; - char *filt; debug_decl(sudo_ldap_result_get, SUDOERS_DEBUG_LDAP) /* @@ -1804,10 +1868,8 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw) * an ldap_result object. The results are then sorted by sudoOrder. */ lres = sudo_ldap_result_alloc(); - if (lres == NULL) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - debug_return_ptr(NULL); - } + if (lres == NULL) + goto oom; for (pass = 0; pass < 2; pass++) { filt = pass ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(ld, pw); if (filt != NULL) { @@ -1831,32 +1893,30 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw) /* Add the search result to list of search results. */ DPRINTF1("adding search result"); - if (sudo_ldap_result_add_search(lres, ld, result) == NULL) { - sudo_warnx(U_("%s: %s"), __func__, - U_("unable to allocate memory")); - free(filt); - sudo_ldap_result_free(lres); - debug_return_ptr(NULL); - } + if (sudo_ldap_result_add_search(lres, ld, result) == NULL) + goto oom; LDAP_FOREACH(entry, ld, result) { - /* Check non-unix group in 2nd pass. */ - if (pass && !sudo_ldap_check_non_unix_group(ld, entry, pw)) - continue; - if (sudo_ldap_result_add_entry(lres, entry) == NULL) { - sudo_warnx(U_("%s: %s"), __func__, - U_("unable to allocate memory")); - free(filt); - sudo_ldap_result_free(lres); - debug_return_ptr(NULL); + if (pass != 0) { + /* Check non-unix group in 2nd pass. */ + switch (sudo_ldap_check_non_unix_group(ld, entry, pw)) { + case -1: + goto oom; + case false: + continue; + default: + break; + } } + if (sudo_ldap_result_add_entry(lres, entry) == NULL) + goto oom; } DPRINTF1("result now has %d entries", lres->nentries); } free(filt); + filt = NULL; } else if (errno != ENOENT) { /* Out of memory? */ - sudo_ldap_result_free(lres); - debug_return_ptr(NULL); + goto oom; } } @@ -1868,6 +1928,11 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw) } debug_return_ptr(lres); +oom: + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + free(filt); + sudo_ldap_result_free(lres); + debug_return_ptr(NULL); } /* @@ -1930,8 +1995,10 @@ sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw) DPRINTF1("%s: ldap search user %s, host %s", __func__, pw->pw_name, user_runhost); - if ((lres = sudo_ldap_result_get(nss, pw)) == NULL) + if ((lres = sudo_ldap_result_get(nss, pw)) == NULL) { + ret = -1; goto done; + } /* Convert to sudoers parse tree. */ if (!ldap_to_sudoers(ld, lres, &nss->userspecs)) { diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index 92a68c365..7837b8b59 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -388,6 +388,7 @@ sudo_sss_getdefs(struct sudo_nss *nss) struct defaults *def; uint32_t sss_error; unsigned int i; + int rc; debug_decl(sudo_sss_getdefs, SUDOERS_DEBUG_SSSD); if (handle == NULL) @@ -402,11 +403,17 @@ sudo_sss_getdefs(struct sudo_nss *nss) sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults"); /* 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) { + 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: != 0, sss_error=%u", sss_error); + "handle->fn_send_recv_defaults: rc=%d, sss_error=%u", rc, sss_error); debug_return_int(-1); } if (sss_error != 0) { @@ -504,17 +511,16 @@ 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, ret; + 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"); - ret = handle->fn_send_recv(pw->pw_uid, pw->pw_name, + rc = handle->fn_send_recv(pw->pw_uid, pw->pw_name, handle->domainname, &sss_error, &sss_result); - - switch (ret) { + switch (rc) { case 0: switch (sss_error) { case 0: @@ -535,9 +541,12 @@ sudo_sss_result_get(struct sudo_nss *nss, struct passwd *pw) 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: != 0: ret=%d", ret); + "handle->fn_send_recv: rc=%d", rc); debug_return_ptr(NULL); } @@ -563,6 +572,8 @@ sudo_sss_parse_options(struct sudo_sss_handle *handle, struct sss_sudo_rule *rul 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); @@ -651,45 +662,101 @@ sss_to_sudoers(struct sudo_sss_handle *handle, struct sss_sudo_result *sss_resul 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; - char *cn = NULL; - struct privilege *priv; - - /* XXX - check for error vs. ENOENT */ + char **hosts = NULL, **cn_array = NULL, *cn = NULL; + struct privilege *priv = NULL; /* Only include matching user roles (XXX). */ if (!sudo_sss_check_user(handle, rule)) continue; - /* Ignore sudoRole without sudoCommand. */ - if (handle->fn_get_values(rule, "sudoCommand", &cmnds) != 0) + switch (handle->fn_get_values(rule, "sudoCommand", &cmnds)) { + case 0: + break; + case ENOENT: + /* Ignore sudoRole without sudoCommand. */ continue; + default: + goto cleanup; + } /* Get the entry's dn for long format printing. */ - if (handle->fn_get_values(rule, "cn", &cn_array) == 0) + switch (handle->fn_get_values(rule, "cn", &cn_array)) { + case 0: cn = cn_array[0]; + break; + case ENOENT: + break; + default: + goto cleanup; + } /* Get sudoHost */ - handle->fn_get_values(rule, "sudoHost", &hosts); + 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 sudoRunAsUser / sudoRunAsGroup */ - if (handle->fn_get_values(rule, "sudoRunAsUser", &runasusers) != 0) { - handle->fn_get_values(rule, "sudoRunAs", &runasusers); + /* 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; } - handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups); - /* Get sudoNotBefore / sudoNotAfter */ - handle->fn_get_values(rule, "sudoNotBefore", ¬before); - handle->fn_get_values(rule, "sudoNotAfter", ¬after); + /* Get sudoNotAfter */ + switch (handle->fn_get_values(rule, "sudoNotAfter", ¬after)) { + case 0: + case ENOENT: + break; + default: + goto cleanup; + } /* Parse sudoOptions. */ - handle->fn_get_values(rule, "sudoOption", &opts); + 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, long_list, val_array_iter); - /* Cleanup */ + cleanup: if (cn_array != NULL) handle->fn_free_values(cn_array); if (cmnds != NULL)