X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=ldap.c;h=81d3c408cbfe0173f5e4b4bab9fba3002e2cc090;hb=97bd3ae46779c69fcdab82d0c64bdf05be009ec3;hp=94ea4cbe4ad1afc9069893d06d85e38d7b188a45;hpb=83cad190740ab8312cf2ea953c1bf9dee2e965bf;p=debian%2Fsudo diff --git a/ldap.c b/ldap.c index 94ea4cb..81d3c40 100644 --- a/ldap.c +++ b/ldap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2009 Todd C. Miller + * Copyright (c) 2003-2010 Todd C. Miller * * This code is derived from software contributed by Aaron Spangler. * @@ -33,11 +33,10 @@ #endif /* STDC_HEADERS */ #ifdef HAVE_STRING_H # include -#else -# ifdef HAVE_STRINGS_H -# include -# endif #endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) # include #endif /* HAVE_MALLOC_H && !STDC_HEADERS */ @@ -112,6 +111,7 @@ #define CONF_BOOL 0 #define CONF_INT 1 #define CONF_STR 2 +#define CONF_LIST_STR 4 #define SUDO_LDAP_SSL 1 #define SUDO_LDAP_STARTTLS 2 @@ -124,6 +124,11 @@ struct ldap_config_table { void *valp; /* pointer into ldap_conf */ }; +struct ldap_config_list_str { + struct ldap_config_list_str *next; + char val[1]; +}; + /* ldap configuration structure */ static struct ldap_config { int port; @@ -137,11 +142,11 @@ static struct ldap_config { int rootuse_sasl; int ssl_mode; char *host; - char *uri; + struct ldap_config_list_str *uri; char *binddn; char *bindpw; char *rootbinddn; - char *base; + struct ldap_config_list_str *base; char *ssl; char *tls_cacertfile; char *tls_cacertdir; @@ -161,7 +166,7 @@ static struct ldap_config_table ldap_conf_table[] = { { "port", CONF_INT, FALSE, -1, &ldap_conf.port }, { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl }, { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile }, - { "uri", CONF_STR, FALSE, -1, &ldap_conf.uri }, + { "uri", CONF_LIST_STR, FALSE, -1, &ldap_conf.uri }, #ifdef LDAP_OPT_DEBUG_LEVEL { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug }, #endif @@ -178,6 +183,8 @@ static struct ldap_config_table ldap_conf_table[] = { #ifdef LDAP_OPT_X_TLS_CACERTFILE { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE, &ldap_conf.tls_cacertfile }, + { "tls_cacert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE, + &ldap_conf.tls_cacertfile }, #endif #ifdef LDAP_OPT_X_TLS_CACERTDIR { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR, @@ -214,7 +221,7 @@ static struct ldap_config_table ldap_conf_table[] = { { "binddn", CONF_STR, FALSE, -1, &ldap_conf.binddn }, { "bindpw", CONF_STR, FALSE, -1, &ldap_conf.bindpw }, { "rootbinddn", CONF_STR, FALSE, -1, &ldap_conf.rootbinddn }, - { "sudoers_base", CONF_STR, FALSE, -1, &ldap_conf.base }, + { "sudoers_base", CONF_LIST_STR, FALSE, -1, &ldap_conf.base }, #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S { "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl }, { "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id }, @@ -229,6 +236,21 @@ static struct ldap_config_table ldap_conf_table[] = { { NULL } }; +/* sudo_nss implementation */ +static int sudo_ldap_open __P((struct sudo_nss *nss)); +static int sudo_ldap_close __P((struct sudo_nss *nss)); +static int sudo_ldap_parse __P((struct sudo_nss *nss)); +static int sudo_ldap_setdefs __P((struct sudo_nss *nss)); +static int sudo_ldap_lookup __P((struct sudo_nss *nss, int ret, int pwflag)); +static int sudo_ldap_display_cmnd __P((struct sudo_nss *nss, + struct passwd *pw)); +static int sudo_ldap_display_defaults __P((struct sudo_nss *nss, + struct passwd *pw, struct lbuf *lbuf)); +static int sudo_ldap_display_bound_defaults __P((struct sudo_nss *nss, + struct passwd *pw, struct lbuf *lbuf)); +static int sudo_ldap_display_privs __P((struct sudo_nss *nss, + struct passwd *pw, struct lbuf *lbuf)); + struct sudo_nss sudo_nss_ldap = { &sudo_nss_ldap, NULL, @@ -269,7 +291,8 @@ sudo_ldap_conf_add_ports() if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) goto toobig; /* Append port if there is not one already. */ - if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1])) { + if ((port = strrchr(host, ':')) == NULL || + !isdigit((unsigned char)port[1])) { if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf)) goto toobig; } @@ -292,69 +315,75 @@ toobig: */ static int sudo_ldap_parse_uri(uri_list) - const char *uri_list; + const struct ldap_config_list_str *uri_list; { char *buf, *uri, *host, *cp, *port; char hostbuf[LINE_MAX]; int nldap = 0, nldaps = 0; int rc = -1; - buf = estrdup(uri_list); - hostbuf[0] = '\0'; - for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) { - if (strncasecmp(uri, "ldap://", 7) == 0) { - nldap++; - host = uri + 7; - } else if (strncasecmp(uri, "ldaps://", 8) == 0) { - nldaps++; - host = uri + 8; - } else { - warningx("unsupported LDAP uri type: %s", uri); - goto done; - } + do { + buf = estrdup(uri_list->val); + hostbuf[0] = '\0'; + for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) { + if (strncasecmp(uri, "ldap://", 7) == 0) { + nldap++; + host = uri + 7; + } else if (strncasecmp(uri, "ldaps://", 8) == 0) { + nldaps++; + host = uri + 8; + } else { + warningx("unsupported LDAP uri type: %s", uri); + goto done; + } - /* trim optional trailing slash */ - if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') { - *cp = '\0'; - } + /* trim optional trailing slash */ + if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') { + *cp = '\0'; + } - if (hostbuf[0] != '\0') { - if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - } + if (hostbuf[0] != '\0') { + if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + } - if (*host == '\0') - host = "localhost"; /* no host specified, use localhost */ + if (*host == '\0') + host = "localhost"; /* no host specified, use localhost */ - if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; + if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; - /* If using SSL and no port specified, add port 636 */ - if (nldaps) { - if ((port = strrchr(host, ':')) == NULL || !isdigit(port[1])) - if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; + /* If using SSL and no port specified, add port 636 */ + if (nldaps) { + if ((port = strrchr(host, ':')) == NULL || + !isdigit((unsigned char)port[1])) + if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + } } - } - if (hostbuf[0] == '\0') { - warningx("invalid uri: %s", uri_list); - goto done; - } - - if (nldaps != 0) { - if (nldap != 0) { - warningx("cannot mix ldap and ldaps URIs"); + if (hostbuf[0] == '\0') { + warningx("invalid uri: %s", uri_list); goto done; } - if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { - warningx("cannot mix ldaps and starttls"); - goto done; + + if (nldaps != 0) { + if (nldap != 0) { + warningx("cannot mix ldap and ldaps URIs"); + goto done; + } + if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { + warningx("cannot mix ldaps and starttls"); + goto done; + } + ldap_conf.ssl_mode = SUDO_LDAP_SSL; } - ldap_conf.ssl_mode = SUDO_LDAP_SSL; - } - free(ldap_conf.host); - ldap_conf.host = estrdup(hostbuf); + free(ldap_conf.host); + ldap_conf.host = estrdup(hostbuf); + efree(buf); + } while ((uri_list = uri_list->next)); + + buf = NULL; rc = 0; done: @@ -364,6 +393,31 @@ done: toobig: errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf"); } +#else +static char * +sudo_ldap_join_uri(uri_list) + struct ldap_config_list_str *uri_list; +{ + struct ldap_config_list_str *uri; + size_t len = 0; + char *buf, *cp; + + /* Usually just a single entry. */ + if (uri_list->next == NULL) + return(estrdup(uri_list->val)); + + for (uri = uri_list; uri != NULL; uri = uri->next) { + len += strlen(uri->val) + 1; + } + buf = cp = emalloc(len); + buf[0] = '\0'; + for (uri = uri_list; uri != NULL; uri = uri->next) { + cp += strlcpy(cp, uri->val, len - (cp - buf)); + *cp++ = ' '; + } + cp[-1] = '\0'; + return(buf); +} #endif /* HAVE_LDAP_INITIALIZE */ static int @@ -438,7 +492,7 @@ done: * Walk through search results and return TRUE if we have a matching * netgroup, else FALSE. */ -int +static int sudo_ldap_check_user_netgroup(ld, entry, user) LDAP *ld; LDAPMessage *entry; @@ -475,7 +529,7 @@ sudo_ldap_check_user_netgroup(ld, entry, user) * Walk through search results and return TRUE if we have a * host match, else FALSE. */ -int +static int sudo_ldap_check_host(ld, entry) LDAP *ld; LDAPMessage *entry; @@ -509,7 +563,7 @@ sudo_ldap_check_host(ld, entry) return(ret); } -int +static int sudo_ldap_check_runas_user(ld, entry) LDAP *ld; LDAPMessage *entry; @@ -582,7 +636,7 @@ sudo_ldap_check_runas_user(ld, entry) return(ret); } -int +static int sudo_ldap_check_runas_group(ld, entry) LDAP *ld; LDAPMessage *entry; @@ -618,7 +672,7 @@ sudo_ldap_check_runas_group(ld, entry) * Walk through search results and return TRUE if we have a runas match, * else FALSE. RunAs info is optional. */ -int +static int sudo_ldap_check_runas(ld, entry) LDAP *ld; LDAPMessage *entry; @@ -638,7 +692,7 @@ sudo_ldap_check_runas(ld, entry) * Walk through search results and return TRUE if we have a command match, * FALSE if disallowed and UNSPEC if not matched. */ -int +static int sudo_ldap_check_command(ld, entry, setenv_implied) LDAP *ld; LDAPMessage *entry; @@ -703,7 +757,7 @@ sudo_ldap_check_command(ld, entry, setenv_implied) * Search for boolean "option" in sudoOption. * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC. */ -int +static int sudo_ldap_check_bool(ld, entry, option) LDAP *ld; LDAPMessage *entry; @@ -740,7 +794,7 @@ sudo_ldap_check_bool(ld, entry, option) * Read sudoOption and modify the defaults as we go. This is used once * from the cn=defaults entry and also once when a final sudoRole is matched. */ -void +static void sudo_ldap_parse_options(ld, entry) LDAP *ld; LDAPMessage *entry; @@ -789,7 +843,7 @@ sudo_ldap_parse_options(ld, entry) /* * builds together a filter to check against ldap */ -char * +static char * sudo_ldap_build_pass1(pw) struct passwd *pw; { @@ -845,7 +899,7 @@ sudo_ldap_build_pass1(pw) /* * Map yes/true/on to TRUE, no/false/off to FALSE, else -1 */ -int +static int _atobool(s) const char *s; { @@ -903,7 +957,7 @@ sudo_ldap_read_secret(path) } } -int +static int sudo_ldap_read_config() { FILE *fp; @@ -952,6 +1006,21 @@ sudo_ldap_read_config() efree(*(char **)(cur->valp)); *(char **)(cur->valp) = estrdup(value); break; + case CONF_LIST_STR: + { + struct ldap_config_list_str **p; + size_t len = strlen(value); + + if (len > 0) { + p = (struct ldap_config_list_str **)cur->valp; + while (*p != NULL) + p = &(*p)->next; + *p = emalloc(sizeof(struct ldap_config_list_str) + len); + memcpy((*p)->val, value, len + 1); + (*p)->next = NULL; + } + } + break; } break; } @@ -969,16 +1038,27 @@ sudo_ldap_read_config() fprintf(stderr, "LDAP Config Summary\n"); fprintf(stderr, "===================\n"); if (ldap_conf.uri) { - fprintf(stderr, "uri %s\n", ldap_conf.uri); + struct ldap_config_list_str *uri = ldap_conf.uri; + + do { + fprintf(stderr, "uri %s\n", uri->val); + } while ((uri = uri->next) != NULL); } else { fprintf(stderr, "host %s\n", ldap_conf.host ? ldap_conf.host : "(NONE)"); fprintf(stderr, "port %d\n", ldap_conf.port); } fprintf(stderr, "ldap_version %d\n", ldap_conf.version); + if (ldap_conf.base) { + struct ldap_config_list_str *base = ldap_conf.base; - fprintf(stderr, "sudoers_base %s\n", ldap_conf.base ? - ldap_conf.base : "(NONE) <---Sudo will ignore ldap)"); + do { + fprintf(stderr, "sudoers_base %s\n", base->val); + } while ((base = base->next) != NULL); + } else { + fprintf(stderr, "sudoers_base %s\n", + "(NONE) <---Sudo will ignore ldap)"); + } fprintf(stderr, "binddn %s\n", ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)"); fprintf(stderr, "bindpw %s\n", ldap_conf.bindpw ? @@ -1044,10 +1124,13 @@ sudo_ldap_read_config() #ifndef HAVE_LDAP_INITIALIZE /* Convert uri list to host list if no ldap_initialize(). */ if (ldap_conf.uri) { - if (sudo_ldap_parse_uri(ldap_conf.uri) != 0) + struct ldap_config_list_str *uri = ldap_conf.uri; + if (sudo_ldap_parse_uri(uri) != 0) return(FALSE); - free(ldap_conf.uri); - ldap_conf.uri = NULL; + do { + ldap_conf.uri = uri->next; + efree(uri); + } while ((uri = ldap_conf.uri)); ldap_conf.port = LDAP_PORT; } #endif @@ -1130,59 +1213,64 @@ sudo_ldap_get_first_rdn(ld, entry) /* * Fetch and display the global Options. */ -int +static int sudo_ldap_display_defaults(nss, pw, lbuf) struct sudo_nss *nss; struct passwd *pw; struct lbuf *lbuf; { struct berval **bv, **p; + struct ldap_config_list_str *base; LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry = NULL, *result = NULL; - char *prefix = NULL; + LDAPMessage *entry, *result; + char *prefix; int rc, count = 0; if (ld == NULL) - return(-1); + goto done; - rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, - "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result); - if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv != NULL) { - if (lbuf->len == 0) - prefix = " "; - else - prefix = ", "; - for (p = bv; *p != NULL; p++) { - lbuf_append(lbuf, prefix, (*p)->bv_val, NULL); - prefix = ", "; - count++; + for (base = ldap_conf.base; base != NULL; base = base->next) { + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, + "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result); + if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv != NULL) { + if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) + prefix = " "; + else + prefix = ", "; + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, prefix, (*p)->bv_val, NULL); + prefix = ", "; + count++; + } + ldap_value_free_len(bv); } - ldap_value_free_len(bv); } + if (result) + ldap_msgfree(result); } - if (result) - ldap_msgfree(result); +done: return(count); } /* * STUB */ -int +static int sudo_ldap_display_bound_defaults(nss, pw, lbuf) struct sudo_nss *nss; struct passwd *pw; struct lbuf *lbuf; { - return(1); + return(0); } /* * Print a record in the short form, ala file sudoers. */ -int +static int sudo_ldap_display_entry_short(ld, entry, lbuf) LDAP *ld; LDAPMessage *entry; @@ -1257,15 +1345,15 @@ sudo_ldap_display_entry_short(ld, entry, lbuf) } ldap_value_free_len(bv); } + lbuf_append(lbuf, "\n", NULL); - lbuf_print(lbuf); /* forces a newline */ return(count); } /* * Print a record in the long form. */ -int +static int sudo_ldap_display_entry_long(ld, entry, lbuf) LDAP *ld; LDAPMessage *entry; @@ -1277,9 +1365,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf) /* extract the dn, only show the first rdn */ rdn = sudo_ldap_get_first_rdn(ld, entry); - lbuf_print(lbuf); /* force a newline */ - lbuf_append(lbuf, "LDAP Role: ", rdn ? rdn : "UNKNOWN", NULL); - lbuf_print(lbuf); + lbuf_append(lbuf, "\nLDAP Role: ", rdn ? rdn : "UNKNOWN", "\n", NULL); if (rdn) ldap_memfree(rdn); @@ -1297,7 +1383,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf) ldap_value_free_len(bv); } else lbuf_append(lbuf, def_runas_default, NULL); - lbuf_print(lbuf); + lbuf_append(lbuf, "\n", NULL); /* get the RunAsGroup Values from the entry */ bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); @@ -1309,7 +1395,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf) lbuf_append(lbuf, (*p)->bv_val, NULL); } ldap_value_free_len(bv); - lbuf_print(lbuf); + lbuf_append(lbuf, "\n", NULL); } /* get the Option Values from the entry */ @@ -1322,17 +1408,15 @@ sudo_ldap_display_entry_long(ld, entry, lbuf) lbuf_append(lbuf, (*p)->bv_val, NULL); } ldap_value_free_len(bv); - lbuf_print(lbuf); + lbuf_append(lbuf, "\n", NULL); } /* get the Command Values from the entry */ bv = ldap_get_values_len(ld, entry, "sudoCommand"); if (bv != NULL) { - lbuf_append(lbuf, " Commands:", NULL); - lbuf_print(lbuf); + lbuf_append(lbuf, " Commands:\n", NULL); for (p = bv; *p != NULL; p++) { - lbuf_append(lbuf, "\t", (*p)->bv_val, NULL); - lbuf_print(lbuf); + lbuf_append(lbuf, "\t", (*p)->bv_val, "\n", NULL); count++; } ldap_value_free_len(bv); @@ -1344,19 +1428,20 @@ sudo_ldap_display_entry_long(ld, entry, lbuf) /* * Like sudo_ldap_lookup(), except we just print entries. */ -int +static int sudo_ldap_display_privs(nss, pw, lbuf) struct sudo_nss *nss; struct passwd *pw; struct lbuf *lbuf; { + struct ldap_config_list_str *base; LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry = NULL, *result = NULL; + LDAPMessage *entry, *result; char *filt; int rc, do_netgr, count = 0; if (ld == NULL) - return(-1); + goto done; /* * Okay - time to search for anything that matches this user @@ -1375,37 +1460,41 @@ sudo_ldap_display_privs(nss, pw, lbuf) for (do_netgr = 0; do_netgr < 2; do_netgr++) { filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw); DPRINTF(("ldap search '%s'", filt), 1); - rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt, - NULL, 0, NULL, NULL, NULL, 0, &result); - efree(filt); - if (rc != LDAP_SUCCESS) - continue; /* no entries for this pass */ - - /* print each matching entry */ - LDAP_FOREACH(entry, ld, result) { - if ((!do_netgr || - sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) && - sudo_ldap_check_host(ld, entry)) { + for (base = ldap_conf.base; base != NULL; base = base->next) { + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt, + NULL, 0, NULL, NULL, NULL, 0, &result); + if (rc != LDAP_SUCCESS) + continue; /* no entries for this pass */ - if (long_list) - count += sudo_ldap_display_entry_long(ld, entry, lbuf); - else - count += sudo_ldap_display_entry_short(ld, entry, lbuf); + /* print each matching entry */ + LDAP_FOREACH(entry, ld, result) { + if ((!do_netgr || + sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) && + sudo_ldap_check_host(ld, entry)) { + + if (long_list) + count += sudo_ldap_display_entry_long(ld, entry, lbuf); + else + count += sudo_ldap_display_entry_short(ld, entry, lbuf); + } } + ldap_msgfree(result); } - ldap_msgfree(result); - result = NULL; + efree(filt); } +done: return(count); } -int +static int sudo_ldap_display_cmnd(nss, pw) struct sudo_nss *nss; struct passwd *pw; { + struct ldap_config_list_str *base; LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry = NULL, *result = NULL; /* used for searches */ + LDAPMessage *entry, *result; /* used for searches */ char *filt; /* used to parse attributes */ int rc, found, do_netgr; /* temp/final return values */ @@ -1429,25 +1518,27 @@ sudo_ldap_display_cmnd(nss, pw) for (found = FALSE, do_netgr = 0; !found && do_netgr < 2; do_netgr++) { filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw); DPRINTF(("ldap search '%s'", filt), 1); - rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt, - NULL, 0, NULL, NULL, NULL, 0, &result); - efree(filt); - if (rc != LDAP_SUCCESS) - continue; /* no entries for this pass */ + for (base = ldap_conf.base; base != NULL; base = base->next) { + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt, + NULL, 0, NULL, NULL, NULL, 0, &result); + if (rc != LDAP_SUCCESS) + continue; /* no entries for this pass */ - LDAP_FOREACH(entry, ld, result) { - if ((!do_netgr || - sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) && - sudo_ldap_check_host(ld, entry) && - sudo_ldap_check_command(ld, entry, NULL) && - sudo_ldap_check_runas(ld, entry)) { + LDAP_FOREACH(entry, ld, result) { + if ((!do_netgr || + sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) && + sudo_ldap_check_host(ld, entry) && + sudo_ldap_check_command(ld, entry, NULL) && + sudo_ldap_check_runas(ld, entry)) { - found = TRUE; - break; + found = TRUE; + break; + } } + ldap_msgfree(result); } - ldap_msgfree(result); - result = NULL; + efree(filt); } if (found) @@ -1490,7 +1581,7 @@ sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact) /* * Set LDAP options based on the config table. */ -int +static int sudo_ldap_set_options(ld) LDAP *ld; { @@ -1554,7 +1645,7 @@ sudo_ldap_set_options(ld) (long)tv.tv_sec, ldap_err2string(rc)); return(-1); } - DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)\n", + DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)", (long)tv.tv_sec), 1); } #endif @@ -1568,7 +1659,7 @@ sudo_ldap_set_options(ld) ldap_err2string(rc)); return(-1); } - DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)\n"), 1); + DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1); } #endif return(0); @@ -1582,9 +1673,11 @@ sudo_ldap_bind_s(ld) LDAP *ld; { int rc; +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S const char *old_ccname = user_ccname; -#ifdef HAVE_GSS_KRB5_CCACHE_NAME +# ifdef HAVE_GSS_KRB5_CCACHE_NAME unsigned int status; +# endif #endif #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S @@ -1594,28 +1687,28 @@ sudo_ldap_bind_s(ld) ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id; if (ldap_conf.krb5_ccname != NULL) { -#ifdef HAVE_GSS_KRB5_CCACHE_NAME +# ifdef HAVE_GSS_KRB5_CCACHE_NAME if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname) != GSS_S_COMPLETE) { old_ccname = NULL; DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1); } -#else +# else setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE); -#endif +# endif } rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI", NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id); if (ldap_conf.krb5_ccname != NULL) { -#ifdef HAVE_GSS_KRB5_CCACHE_NAME +# ifdef HAVE_GSS_KRB5_CCACHE_NAME if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE) DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1); -#else +# else if (old_ccname != NULL) setenv("KRB5CCNAME", old_ccname, TRUE); else unsetenv("KRB5CCNAME"); -#endif +# endif } if (rc != LDAP_SUCCESS) { warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc)); @@ -1656,7 +1749,7 @@ sudo_ldap_bind_s(ld) * Open a connection to the LDAP server. * Returns 0 on success and non-zero on failure. */ -int +static int sudo_ldap_open(nss) struct sudo_nss *nss; { @@ -1675,8 +1768,10 @@ sudo_ldap_open(nss) /* Connect to LDAP server */ #ifdef HAVE_LDAP_INITIALIZE if (ldap_conf.uri != NULL) { - DPRINTF(("ldap_initialize(ld, %s)", ldap_conf.uri), 2); - rc = ldap_initialize(&ld, ldap_conf.uri); + char *buf = sudo_ldap_join_uri(ldap_conf.uri); + DPRINTF(("ldap_initialize(ld, %s)", buf), 2); + rc = ldap_initialize(&ld, buf); + efree(buf); } else #endif rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port); @@ -1724,27 +1819,31 @@ sudo_ldap_open(nss) return(0); } -int +static int sudo_ldap_setdefs(nss) struct sudo_nss *nss; { + struct ldap_config_list_str *base; LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry = NULL, *result = NULL; /* used for searches */ + LDAPMessage *entry, *result; /* used for searches */ int rc; /* temp return value */ if (ld == NULL) return(-1); - rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, - "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result); - if (rc == 0 && (entry = ldap_first_entry(ld, result))) { - DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1); - sudo_ldap_parse_options(ld, entry); - } else - DPRINTF(("no default options found!"), 1); - - if (result) - ldap_msgfree(result); + for (base = ldap_conf.base; base != NULL; base = base->next) { + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, + "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result); + if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { + DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1); + sudo_ldap_parse_options(ld, entry); + } else + DPRINTF(("no default options found in %s", base->val), 1); + + if (result) + ldap_msgfree(result); + } return(0); } @@ -1752,14 +1851,15 @@ sudo_ldap_setdefs(nss) /* * like sudoers_lookup() - only LDAP style */ -int +static int sudo_ldap_lookup(nss, ret, pwflag) struct sudo_nss *nss; int ret; int pwflag; { + struct ldap_config_list_str *base; LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry = NULL, *result = NULL; + LDAPMessage *entry, *result; char *filt; int do_netgr, rc, matched; int setenv_implied; @@ -1776,34 +1876,36 @@ sudo_ldap_lookup(nss, ret, pwflag) for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) { filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw); - rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt, - NULL, 0, NULL, NULL, NULL, 0, &result); - efree(filt); - if (rc != LDAP_SUCCESS) - continue; - - LDAP_FOREACH(entry, ld, result) { - /* only verify netgroup matches in pass 2 */ - if (do_netgr && !sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) + for (base = ldap_conf.base; base != NULL; base = base->next) { + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt, + NULL, 0, NULL, NULL, NULL, 0, &result); + if (rc != LDAP_SUCCESS) continue; - ldap_user_matches = TRUE; - if (sudo_ldap_check_host(ld, entry)) { - ldap_host_matches = TRUE; - if ((pwcheck == any && doauth != FALSE) || - (pwcheck == all && doauth == FALSE)) - doauth = sudo_ldap_check_bool(ld, entry, "authenticate"); - /* Only check the command when listing another user. */ - if (user_uid == 0 || list_pw == NULL || - user_uid == list_pw->pw_uid || - sudo_ldap_check_command(ld, entry, NULL)) { - matched = 1; - break; /* end foreach */ + LDAP_FOREACH(entry, ld, result) { + /* only verify netgroup matches in pass 2 */ + if (do_netgr && !sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) + continue; + + ldap_user_matches = TRUE; + if (sudo_ldap_check_host(ld, entry)) { + ldap_host_matches = TRUE; + if ((pwcheck == any && doauth != FALSE) || + (pwcheck == all && doauth == FALSE)) + doauth = sudo_ldap_check_bool(ld, entry, "authenticate"); + /* Only check the command when listing another user. */ + if (user_uid == 0 || list_pw == NULL || + user_uid == list_pw->pw_uid || + sudo_ldap_check_command(ld, entry, NULL)) { + matched = 1; + break; /* end foreach */ + } } } + ldap_msgfree(result); } - ldap_msgfree(result); - result = NULL; + efree(filt); } if (matched || user_uid == 0) { SET(ret, VALIDATE_OK); @@ -1847,14 +1949,16 @@ sudo_ldap_lookup(nss, ret, pwflag) for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) { filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw); DPRINTF(("ldap search '%s'", filt), 1); - rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, filt, - NULL, 0, NULL, NULL, NULL, 0, &result); - if (rc != LDAP_SUCCESS) - DPRINTF(("nothing found for '%s'", filt), 1); - efree(filt); + for (base = ldap_conf.base; base != NULL; base = base->next) { + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt, + NULL, 0, NULL, NULL, NULL, 0, &result); + if (rc != LDAP_SUCCESS) { + DPRINTF(("nothing found for '%s'", filt), 1); + continue; + } - /* parse each entry returned from this most recent search */ - if (rc == LDAP_SUCCESS) { + /* parse each entry returned from this most recent search */ LDAP_FOREACH(entry, ld, result) { DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1); if ( @@ -1898,8 +2002,8 @@ sudo_ldap_lookup(nss, ret, pwflag) } } ldap_msgfree(result); - result = NULL; } + efree(filt); } done: @@ -1923,7 +2027,7 @@ done: /* * shut down LDAP connection */ -int +static int sudo_ldap_close(nss) struct sudo_nss *nss; { @@ -1937,7 +2041,7 @@ sudo_ldap_close(nss) /* * STUB */ -int +static int sudo_ldap_parse(nss) struct sudo_nss *nss; {