From 4fcd065de21165f417f6a5ba38a9b36c1e37ec0b Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 17 May 2012 10:58:44 -0400 Subject: [PATCH] Split global and per-connection LDAP options into separate arrays. Set global LDAP options before calling ldap_initialize() or ldap_init(). After we have an LDAP handle, set the per-connection options. Fixes a problem with OpenLDAP using the nss crypto backend; bug #342 --HG-- branch : 1.7 --- ldap.c | 287 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 169 insertions(+), 118 deletions(-) diff --git a/ldap.c b/ldap.c index 7ec35a91d..c318739f1 100644 --- a/ldap.c +++ b/ldap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Todd C. Miller + * Copyright (c) 2003-2012 Todd C. Miller * * This code is derived from software contributed by Aaron Spangler. * @@ -176,8 +176,7 @@ struct ldap_result { struct ldap_config_table { const char *conf_str; /* config file string */ - short type; /* CONF_BOOL, CONF_INT, CONF_STR */ - short connected; /* connection-specific value? */ + int type; /* CONF_BOOL, CONF_INT, CONF_STR */ int opt_val; /* LDAP_OPT_* (or -1 for sudo internal) */ void *valp; /* pointer into ldap_conf */ }; @@ -222,92 +221,96 @@ static struct ldap_config { char *krb5_ccname; } ldap_conf; -static struct ldap_config_table ldap_conf_table[] = { - { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug }, - { "host", CONF_STR, FALSE, -1, &ldap_conf.host }, - { "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_LIST_STR, FALSE, -1, &ldap_conf.uri }, +static struct ldap_config_table ldap_conf_global[] = { + { "sudoers_debug", CONF_INT, -1, &ldap_conf.debug }, + { "host", CONF_STR, -1, &ldap_conf.host }, + { "port", CONF_INT, -1, &ldap_conf.port }, + { "ssl", CONF_STR, -1, &ldap_conf.ssl }, + { "sslpath", CONF_STR, -1, &ldap_conf.tls_certfile }, + { "uri", CONF_LIST_STR, -1, &ldap_conf.uri }, #ifdef LDAP_OPT_DEBUG_LEVEL - { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug }, -#endif -#ifdef LDAP_OPT_PROTOCOL_VERSION - { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION, - &ldap_conf.version }, + { "debug", CONF_INT, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug }, #endif #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT - { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT, + { "tls_checkpeer", CONF_BOOL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_conf.tls_checkpeer }, #else - { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer }, + { "tls_checkpeer", CONF_BOOL, -1, &ldap_conf.tls_checkpeer }, #endif #ifdef LDAP_OPT_X_TLS_CACERTFILE - { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE, + { "tls_cacertfile", CONF_STR, LDAP_OPT_X_TLS_CACERTFILE, &ldap_conf.tls_cacertfile }, - { "tls_cacert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE, + { "tls_cacert", CONF_STR, 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, + { "tls_cacertdir", CONF_STR, LDAP_OPT_X_TLS_CACERTDIR, &ldap_conf.tls_cacertdir }, #endif #ifdef LDAP_OPT_X_TLS_RANDOM_FILE - { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE, + { "tls_randfile", CONF_STR, LDAP_OPT_X_TLS_RANDOM_FILE, &ldap_conf.tls_random_file }, #endif #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE - { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE, + { "tls_ciphers", CONF_STR, LDAP_OPT_X_TLS_CIPHER_SUITE, &ldap_conf.tls_cipher_suite }, #endif #ifdef LDAP_OPT_X_TLS_CERTFILE - { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE, + { "tls_cert", CONF_STR, LDAP_OPT_X_TLS_CERTFILE, &ldap_conf.tls_certfile }, #else - { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile }, + { "tls_cert", CONF_STR, -1, &ldap_conf.tls_certfile }, #endif #ifdef LDAP_OPT_X_TLS_KEYFILE - { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE, + { "tls_key", CONF_STR, LDAP_OPT_X_TLS_KEYFILE, &ldap_conf.tls_keyfile }, #else - { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile }, + { "tls_key", CONF_STR, -1, &ldap_conf.tls_keyfile }, +#endif + { "binddn", CONF_STR, -1, &ldap_conf.binddn }, + { "bindpw", CONF_STR, -1, &ldap_conf.bindpw }, + { "rootbinddn", CONF_STR, -1, &ldap_conf.rootbinddn }, + { "sudoers_base", CONF_LIST_STR, -1, &ldap_conf.base }, + { "sudoers_timed", CONF_BOOL, -1, &ldap_conf.timed }, + { "sudoers_search_filter", CONF_STR, -1, &ldap_conf.search_filter }, +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + { "use_sasl", CONF_BOOL, -1, &ldap_conf.use_sasl }, + { "sasl_auth_id", CONF_STR, -1, &ldap_conf.sasl_auth_id }, + { "rootuse_sasl", CONF_BOOL, -1, &ldap_conf.rootuse_sasl }, + { "rootsasl_auth_id", CONF_STR, -1, &ldap_conf.rootsasl_auth_id }, + { "krb5_ccname", CONF_STR, -1, &ldap_conf.krb5_ccname }, +#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ + { NULL } +}; + +static struct ldap_config_table ldap_conf_conn[] = { +#ifdef LDAP_OPT_PROTOCOL_VERSION + { "ldap_version", CONF_INT, LDAP_OPT_PROTOCOL_VERSION, + &ldap_conf.version }, #endif #ifdef LDAP_OPT_NETWORK_TIMEOUT - { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */, + { "bind_timelimit", CONF_INT, -1 /* needs timeval, set manually */, &ldap_conf.bind_timelimit }, - { "network_timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */, + { "network_timeout", CONF_INT, -1 /* needs timeval, set manually */, &ldap_conf.bind_timelimit }, #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT) - { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT, + { "bind_timelimit", CONF_INT, LDAP_X_OPT_CONNECT_TIMEOUT, &ldap_conf.bind_timelimit }, - { "network_timeout", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT, + { "network_timeout", CONF_INT, LDAP_X_OPT_CONNECT_TIMEOUT, &ldap_conf.bind_timelimit }, #endif - { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit }, + { "timelimit", CONF_INT, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit }, #ifdef LDAP_OPT_TIMEOUT - { "timeout", CONF_INT, TRUE, -1 /* needs timeval, set manually */, + { "timeout", CONF_INT, -1 /* needs timeval, set manually */, &ldap_conf.timeout }, #endif #ifdef LDAP_OPT_DEREF - { "deref", CONF_DEREF_VAL, TRUE, LDAP_OPT_DEREF, &ldap_conf.deref }, + { "deref", CONF_DEREF_VAL, LDAP_OPT_DEREF, &ldap_conf.deref }, #endif - { "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_LIST_STR, FALSE, -1, &ldap_conf.base }, - { "sudoers_timed", CONF_BOOL, FALSE, -1, &ldap_conf.timed }, - { "sudoers_search_filter", CONF_STR, FALSE, -1, &ldap_conf.search_filter }, -#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 }, - { "rootuse_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.rootuse_sasl }, - { "rootsasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.rootsasl_auth_id }, -# ifdef LDAP_OPT_X_SASL_SECPROPS - { "sasl_secprops", CONF_STR, TRUE, LDAP_OPT_X_SASL_SECPROPS, +#ifdef LDAP_OPT_X_SASL_SECPROPS + { "sasl_secprops", CONF_STR, LDAP_OPT_X_SASL_SECPROPS, &ldap_conf.sasl_secprops }, -# endif - { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname }, -#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ +#endif { NULL } }; @@ -1277,12 +1280,69 @@ sudo_ldap_read_secret(path) } } +/* + * Look up keyword in config tables. + * Returns TRUE if found, else FALSE. + */ +static int +sudo_ldap_parse_keyword(keyword, value, table) + const char *keyword; + const char *value; + struct ldap_config_table *table; +{ + struct ldap_config_table *cur; + + /* Look up keyword in config tables */ + for (cur = table; cur->conf_str != NULL; cur++) { + if (strcasecmp(keyword, cur->conf_str) == 0) { + switch (cur->type) { + case CONF_DEREF_VAL: + if (strcasecmp(value, "searching") == 0) + *(int *)(cur->valp) = LDAP_DEREF_SEARCHING; + else if (strcasecmp(value, "finding") == 0) + *(int *)(cur->valp) = LDAP_DEREF_FINDING; + else if (strcasecmp(value, "always") == 0) + *(int *)(cur->valp) = LDAP_DEREF_ALWAYS; + else + *(int *)(cur->valp) = LDAP_DEREF_NEVER; + break; + case CONF_BOOL: + *(int *)(cur->valp) = _atobool(value) == TRUE; + break; + case CONF_INT: + *(int *)(cur->valp) = atoi(value); + break; + case CONF_STR: + 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; + } + return TRUE; + } + } + return FALSE; +} + static int sudo_ldap_read_config() { FILE *fp; char *cp, *keyword, *value; - struct ldap_config_table *cur; /* defaults */ ldap_conf.version = 3; @@ -1314,49 +1374,9 @@ sudo_ldap_read_config() cp++; value = cp; - /* Look up keyword in config table. */ - for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) { - if (strcasecmp(keyword, cur->conf_str) == 0) { - switch (cur->type) { - case CONF_DEREF_VAL: - if (strcasecmp(value, "searching") == 0) - *(int *)(cur->valp) = LDAP_DEREF_SEARCHING; - else if (strcasecmp(value, "finding") == 0) - *(int *)(cur->valp) = LDAP_DEREF_FINDING; - else if (strcasecmp(value, "always") == 0) - *(int *)(cur->valp) = LDAP_DEREF_ALWAYS; - else - *(int *)(cur->valp) = LDAP_DEREF_NEVER; - break; - case CONF_BOOL: - *(int *)(cur->valp) = _atobool(value); - break; - case CONF_INT: - *(int *)(cur->valp) = atoi(value); - break; - case CONF_STR: - 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; - } - } + /* Look up keyword in config tables. */ + if (!sudo_ldap_parse_keyword(keyword, value, ldap_conf_global)) + sudo_ldap_parse_keyword(keyword, value, ldap_conf_conn); } fclose(fp); @@ -1883,37 +1903,27 @@ sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact) #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ /* - * Set LDAP options based on the config table. + * Set LDAP options from the specified options table */ static int -sudo_ldap_set_options(ld) +sudo_ldap_set_options_table(ld, table) LDAP *ld; + struct ldap_config_table *table; { struct ldap_config_table *cur; - int rc; - - /* Set ber options */ -#ifdef LBER_OPT_DEBUG_LEVEL - if (ldap_conf.ldap_debug) - ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug); -#endif - - /* Set simple LDAP options */ - for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) { - LDAP *conn; - int ival; - char *sval; + int ival, rc; + char *sval; + for (cur = table; cur->conf_str != NULL; cur++) { if (cur->opt_val == -1) continue; - conn = cur->connected ? ld : NULL; switch (cur->type) { case CONF_BOOL: case CONF_INT: ival = *(int *)(cur->valp); if (ival >= 0) { - rc = ldap_set_option(conn, cur->opt_val, &ival); + rc = ldap_set_option(ld, cur->opt_val, &ival); if (rc != LDAP_OPT_SUCCESS) { warningx("ldap_set_option: %s -> %d: %s", cur->conf_str, ival, ldap_err2string(rc)); @@ -1925,7 +1935,7 @@ sudo_ldap_set_options(ld) case CONF_STR: sval = *(char **)(cur->valp); if (sval != NULL) { - rc = ldap_set_option(conn, cur->opt_val, sval); + rc = ldap_set_option(ld, cur->opt_val, sval); if (rc != LDAP_OPT_SUCCESS) { warningx("ldap_set_option: %s -> %s: %s", cur->conf_str, sval, ldap_err2string(rc)); @@ -1936,6 +1946,43 @@ sudo_ldap_set_options(ld) break; } } + return 0; +} + +/* + * Set LDAP options based on the global config table. + */ +static int +sudo_ldap_set_options_global() +{ + int rc; + + /* Set ber options */ +#ifdef LBER_OPT_DEBUG_LEVEL + if (ldap_conf.ldap_debug) + ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug); +#endif + + /* Parse global LDAP options table. */ + rc = sudo_ldap_set_options_table(NULL, ldap_conf_global); + if (rc == -1) + return -1; + return 0; +} + +/* + * Set LDAP options based on the per-connection config table. + */ +static int +sudo_ldap_set_options_conn(ld) + LDAP *ld; +{ + int rc; + + /* Parse per-connection LDAP options table. */ + rc = sudo_ldap_set_options_table(ld, ldap_conf_conn); + if (rc == -1) + return -1; #ifdef LDAP_OPT_TIMEOUT /* Convert timeout to a timeval */ @@ -2147,6 +2194,10 @@ sudo_ldap_open(nss) setenv("LDAPNOINIT", "1", TRUE); } + /* Set global LDAP options */ + if (sudo_ldap_set_options_global() < 0) + return -1; + /* Connect to LDAP server */ #ifdef HAVE_LDAP_INITIALIZE if (ldap_conf.uri != NULL) { @@ -2154,21 +2205,21 @@ sudo_ldap_open(nss) DPRINTF(("ldap_initialize(ld, %s)", buf), 2); rc = ldap_initialize(&ld, buf); efree(buf); + if (rc != LDAP_SUCCESS) + warningx("unable to initialize LDAP: %s", ldap_err2string(rc)); } else #endif rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port); - if (rc != LDAP_SUCCESS) { - warningx("unable to initialize LDAP: %s", ldap_err2string(rc)); + if (rc != LDAP_SUCCESS) + return -1; + + /* Set LDAP per-connection options */ + if (sudo_ldap_set_options_conn(ld) < 0) return -1; - } if (ldapnoinit) unsetenv("LDAPNOINIT"); - /* Set LDAP options */ - if (sudo_ldap_set_options(ld) < 0) - return -1; - if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { #if defined(HAVE_LDAP_START_TLS_S) rc = ldap_start_tls_s(ld, NULL, NULL); -- 2.40.0