Add checks for ldap/sss functions failing due to memory allocation

errors.
This commit is contained in:
Todd C. Miller
2018-05-14 09:05:05 -06:00
parent 904f37e03f
commit d052f8a68b
2 changed files with 218 additions and 84 deletions

View File

@@ -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) {
if (pass != 0) {
/* Check non-unix group in 2nd pass. */
if (pass && !sudo_ldap_check_non_unix_group(ld, entry, pw))
switch (sudo_ldap_check_non_unix_group(ld, entry, pw)) {
case -1:
goto oom;
case false:
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);
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)) {

View File

@@ -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;
switch (handle->fn_get_values(rule, "sudoCommand", &cmnds)) {
case 0:
break;
case ENOENT:
/* Ignore sudoRole without sudoCommand. */
if (handle->fn_get_values(rule, "sudoCommand", &cmnds) != 0)
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);
/* Get sudoRunAsUser / sudoRunAsGroup */
if (handle->fn_get_values(rule, "sudoRunAsUser", &runasusers) != 0) {
handle->fn_get_values(rule, "sudoRunAs", &runasusers);
switch (handle->fn_get_values(rule, "sudoHost", &hosts)) {
case 0:
case ENOENT:
break;
default:
goto cleanup;
}
handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups);
/* Get sudoNotBefore / sudoNotAfter */
handle->fn_get_values(rule, "sudoNotBefore", &notbefore);
handle->fn_get_values(rule, "sudoNotAfter", &notafter);
/* 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", &notbefore)) {
case 0:
case ENOENT:
break;
default:
goto cleanup;
}
/* Get sudoNotAfter */
switch (handle->fn_get_values(rule, "sudoNotAfter", &notafter)) {
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)