]> granicus.if.org Git - sudo/commitdiff
Add checks for ldap/sss functions failing due to memory allocation
authorTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 14 May 2018 15:05:05 +0000 (09:05 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 14 May 2018 15:05:05 +0000 (09:05 -0600)
errors.

plugins/sudoers/ldap.c
plugins/sudoers/sssd.c

index 244bf628dff5f5475cf11c148b25221e614c7747..78afd151d7133d31523f1f5db6fd848bbb949573 100644 (file)
 #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)) {
index 92a68c365448ec52264fce481d413273351ad929..7837b8b5965a15dfa5409f5aad95a57369827068 100644 (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;
 
-       /* 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", &notbefore)) {
+       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 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)