From: Arran Cudbard-Bell Date: Tue, 29 Nov 2016 22:04:48 +0000 (-0500) Subject: Split configurations in rlm_ldap into instance and pool specific X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4e6fed753ff166753963d33eccf4199001e68a35;p=thirdparty%2Ffreeradius-server.git Split configurations in rlm_ldap into instance and pool specific --- diff --git a/src/modules/rlm_ldap/clients.c b/src/modules/rlm_ldap/clients.c index a549a4c7ee8..123dd2a517d 100644 --- a/src/modules/rlm_ldap/clients.c +++ b/src/modules/rlm_ldap/clients.c @@ -145,8 +145,9 @@ int rlm_ldap_client_load(rlm_ldap_t const *inst, CONF_SECTION *tmpl, CONF_SECTIO * Perform all searches as the admin user. */ if (conn->rebound) { - status = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password, - &(conn->inst->admin_sasl), true, NULL, NULL, NULL); + status = rlm_ldap_bind(inst, NULL, &conn, + conn->pool_inst->admin_identity, conn->pool_inst->admin_password, + &(conn->pool_inst->admin_sasl), true, NULL, NULL, NULL); if (status != LDAP_PROC_SUCCESS) { ret = -1; goto finish; diff --git a/src/modules/rlm_ldap/directory.c b/src/modules/rlm_ldap/directory.c index 0e4776b79df..34b0075bacf 100644 --- a/src/modules/rlm_ldap/directory.c +++ b/src/modules/rlm_ldap/directory.c @@ -56,7 +56,7 @@ static FR_NAME_NUMBER const ldap_directory_type_table[] = { * - 1 if we failed identifying the directory server. * - -1 on error. */ -int rlm_ldap_directory_alloc(TALLOC_CTX *ctx, ldap_directory_t **out, rlm_ldap_t *inst, ldap_handle_t **pconn) +int rlm_ldap_directory_alloc(TALLOC_CTX *ctx, ldap_directory_t **out, rlm_ldap_t const *inst, ldap_handle_t **pconn) { static char const *attrs[] = { "vendorname", "vendorversion", @@ -115,7 +115,7 @@ int rlm_ldap_directory_alloc(TALLOC_CTX *ctx, ldap_directory_t **out, rlm_ldap_t values = ldap_get_values_len((*pconn)->handle, entry, "vendorname"); if (values) { - directory->vendor_str = rlm_ldap_berval_to_string(inst, values[0]); + directory->vendor_str = rlm_ldap_berval_to_string(directory, values[0]); INFO("Directory vendor: %s", directory->vendor_str); ldap_value_free_len(values); @@ -123,7 +123,7 @@ int rlm_ldap_directory_alloc(TALLOC_CTX *ctx, ldap_directory_t **out, rlm_ldap_t values = ldap_get_values_len((*pconn)->handle, entry, "vendorversion"); if (values) { - directory->version_str = rlm_ldap_berval_to_string(inst, values[0]); + directory->version_str = rlm_ldap_berval_to_string(directory, values[0]); INFO("Directory version: %s", directory->version_str); ldap_value_free_len(values); diff --git a/src/modules/rlm_ldap/ldap.c b/src/modules/rlm_ldap/ldap.c index bd4e8125269..51da42431ed 100644 --- a/src/modules/rlm_ldap/ldap.c +++ b/src/modules/rlm_ldap/ldap.c @@ -921,7 +921,8 @@ ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, *pconn = fr_connection_reconnect(inst->pool, request, *pconn); if (*pconn) { ROPTIONAL(RWDEBUG, WARN, "Bind with %s to %s failed: %s. Got new socket, " - "retrying...", *dn ? dn : "(anonymous)", inst->server, error); + "retrying...", *dn ? dn : "(anonymous)", + (*pconn)->pool_inst->server, error); talloc_free(extra); /* don't leak debug info */ @@ -937,7 +938,7 @@ ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, /* FALL-THROUGH */ default: ROPTIONAL(REDEBUG, ERROR, "Bind with %s to %s failed: %s", *dn ? dn : "(anonymous)", - inst->server, error); + (*pconn)->pool_inst->server, error); LDAP_EXTRA_DEBUG(); break; @@ -1020,8 +1021,8 @@ ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUE * Do all searches as the admin user. */ if ((*pconn)->rebound) { - status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity, - (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true, + status = rlm_ldap_bind(inst, request, pconn, (*pconn)->pool_inst->admin_identity, + (*pconn)->pool_inst->admin_password, &(*pconn)->pool_inst->admin_sasl, true, NULL, NULL, NULL); if (status != LDAP_PROC_SUCCESS) { return LDAP_PROC_ERROR; @@ -1183,8 +1184,8 @@ ldap_rcode_t rlm_ldap_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_hand * Perform all modifications as the admin user. */ if ((*pconn)->rebound) { - status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity, - (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true, + status = rlm_ldap_bind(inst, request, pconn, (*pconn)->pool_inst->admin_identity, + (*pconn)->pool_inst->admin_password, &(*pconn)->pool_inst->admin_sasl, true, NULL, NULL, NULL); if (status != LDAP_PROC_SUCCESS) { return LDAP_PROC_ERROR; @@ -1313,8 +1314,8 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_ha * Perform all searches as the admin user. */ if ((*pconn)->rebound) { - status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity, - (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true, + status = rlm_ldap_bind(inst, request, pconn, (*pconn)->pool_inst->admin_identity, + (*pconn)->pool_inst->admin_password, &(*pconn)->pool_inst->admin_sasl, true, NULL, NULL, NULL); if (status != LDAP_PROC_SUCCESS) { *rcode = RLM_MODULE_FAIL; @@ -1475,7 +1476,7 @@ rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, REQUEST *request, * @param inst rlm_ldap configuration. * @param request Current request. */ -void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request) +void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t const *conn) { /* * More warning messages for people who can't be bothered to read the documentation. @@ -1490,7 +1491,7 @@ void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request) !fr_pair_find_by_num(request->control, 0, PW_USER_PASSWORD, TAG_ANY) && !fr_pair_find_by_num(request->control, 0, PW_PASSWORD_WITH_HEADER, TAG_ANY) && !fr_pair_find_by_num(request->control, 0, PW_CRYPT_PASSWORD, TAG_ANY)) { - switch (inst->directory->type) { + switch (conn->directory->type) { case LDAP_DIRECTORY_ACTIVE_DIRECTORY: RWDEBUG("!!! Found map between LDAP attribute and a FreeRADIUS password attribute"); RWDEBUG("!!! Active Directory does not allow passwords to be read via LDAP"); @@ -1521,13 +1522,13 @@ void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request) break; default: - if (!inst->admin_identity) { + if (!conn->pool_inst->admin_identity) { RWDEBUG("!!! Found map between LDAP attribute and a FreeRADIUS password attribute"); RWDEBUG("!!! but no password attribute found in search result"); RWDEBUG("!!! Either:"); RWDEBUG("!!! - Ensure the user object contains a password attribute, and that "); RWDEBUG("!!! \"%s\" has permission to read that password attribute (recommended)", - inst->admin_identity); + conn->pool_inst->admin_identity); RWDEBUG("!!! - Bind as the user by listing %s in the authenticate section, and", inst->name); RWDEBUG("!!! setting attribute &control:Auth-Type := '%s' in the authorize section", @@ -1565,14 +1566,15 @@ void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request) static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t request, UNUSED ber_int_t msgid, void *ctx) { - ldap_rcode_t status; - ldap_handle_t *conn = talloc_get_type_abort(ctx, ldap_handle_t); - rlm_ldap_t const *inst = conn->inst; + ldap_rcode_t status; + ldap_handle_t *conn = talloc_get_type_abort(ctx, ldap_handle_t); + ldap_pool_inst_t const *pool_inst = conn->pool_inst; + rlm_ldap_t const *inst = conn->inst; - char const *admin_identity = NULL; - char const *admin_password = NULL; + char const *admin_identity = NULL; + char const *admin_password = NULL; - int ldap_errno; + int ldap_errno; conn->referred = true; conn->rebound = true; /* not really, but oh well... */ @@ -1586,7 +1588,7 @@ static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t * SASL mech is inherited from the module that defined the connection * pool. */ - if (inst->use_referral_credentials) { + if (pool_inst->use_referral_credentials) { LDAPURLDesc *ldap_url; int ret; char **ext; @@ -1649,12 +1651,12 @@ static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t } else # endif { - admin_identity = conn->inst->admin_identity; - admin_password = conn->inst->admin_password; + admin_identity = pool_inst->admin_identity; + admin_password = pool_inst->admin_password; } status = rlm_ldap_bind(inst, NULL, &conn, admin_identity, admin_password, - &conn->inst->admin_sasl, false, NULL, NULL, NULL); + &conn->pool_inst->admin_sasl, false, NULL, NULL, NULL); if (status != LDAP_PROC_SUCCESS) { ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); @@ -1746,19 +1748,20 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim int ldap_errno, ldap_version; - rlm_ldap_t *inst = instance; - ldap_handle_t *conn; - LDAP *handle = NULL; + rlm_ldap_t const *inst = talloc_get_type_abort(instance, rlm_ldap_t); + ldap_pool_inst_t const *pool_inst = &inst->pool_inst; + ldap_handle_t *conn; + LDAP *handle = NULL; - DEBUG("Connecting to %s", inst->server); + DEBUG("Connecting to %s", pool_inst->server); #ifdef HAVE_LDAP_INITIALIZE - ldap_errno = ldap_initialize(&handle, inst->server); + ldap_errno = ldap_initialize(&handle, pool_inst->server); if (ldap_errno != LDAP_SUCCESS) { ERROR("ldap_initialize failed: %s", ldap_err2string(ldap_errno)); return NULL; } #else - handle = ldap_init(inst->server, inst->port); + handle = ldap_init(pool_inst->server, pool_inst->port); if (!handle) { ERROR("ldap_init failed"); return NULL; @@ -1771,7 +1774,7 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim conn = talloc_zero(ctx, ldap_handle_t); if (!conn) return NULL; - conn->inst = inst; + conn->pool_inst = pool_inst; conn->handle = handle; conn->rebound = false; conn->referred = false; @@ -1798,18 +1801,18 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim /* * Leave "dereference" unset to use the OpenLDAP default. */ - if (inst->dereference_str) { - do_ldap_option(LDAP_OPT_DEREF, "dereference", &(inst->dereference)); + if (pool_inst->dereference_str) { + do_ldap_option(LDAP_OPT_DEREF, "dereference", &(pool_inst->dereference)); } /* * Leave "chase_referrals" unset to use the OpenLDAP default. */ - if (!inst->chase_referrals_unset) { - if (inst->chase_referrals) { + if (!pool_inst->chase_referrals_unset) { + if (pool_inst->chase_referrals) { do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON); - if (inst->rebind == true) { + if (pool_inst->rebind == true) { #if LDAP_SET_REBIND_PROC_ARGS == 3 ldap_set_rebind_proc(conn->handle, rlm_ldap_rebind, conn); #endif @@ -1821,7 +1824,7 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim #ifdef LDAP_OPT_NETWORK_TIMEOUT /* - * A value of zero results in an instant failure. + * A value of zero results in an pool_instant failure. * * When most people specify zero they mean infinite. * @@ -1836,41 +1839,41 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim } #endif - do_ldap_option(LDAP_OPT_TIMELIMIT, "srv_timelimit", &(inst->srv_timelimit)); + do_ldap_option(LDAP_OPT_TIMELIMIT, "srv_timelimit", &(pool_inst->srv_timelimit)); ldap_version = LDAP_VERSION3; do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version); #ifdef LDAP_OPT_X_KEEPALIVE_IDLE - do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive_idle", &(inst->keepalive_idle)); + do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive_idle", &(pool_inst->keepalive_idle)); #endif #ifdef LDAP_OPT_X_KEEPALIVE_PROBES - do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive_probes", &(inst->keepalive_probes)); + do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive_probes", &(pool_inst->keepalive_probes)); #endif #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL - do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive_interval", &(inst->keepalive_interval)); + do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive_interval", &(pool_inst->keepalive_interval)); #endif #ifdef HAVE_LDAP_START_TLS_S /* * Set all of the TLS options */ - if (inst->tls_mode) do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode)); + if (pool_inst->tls_mode) do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(pool_inst->tls_mode)); - maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE, "ca_file", inst->tls_ca_file); - maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR, "ca_path", inst->tls_ca_path); + maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE, "ca_file", pool_inst->tls_ca_file); + maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR, "ca_path", pool_inst->tls_ca_path); /* * Set certificate options */ - maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE, "certificate_file", inst->tls_certificate_file); - maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE, "private_key_file", inst->tls_private_key_file); + maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE, "certificate_file", pool_inst->tls_certificate_file); + maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE, "private_key_file", pool_inst->tls_private_key_file); # ifdef LDAP_OPT_X_TLS_NEVER - if (inst->tls_require_cert_str) { - do_ldap_option(LDAP_OPT_X_TLS_REQUIRE_CERT, "require_cert", &inst->tls_require_cert); + if (pool_inst->tls_require_cert_str) { + do_ldap_option(LDAP_OPT_X_TLS_REQUIRE_CERT, "require_cert", &pool_inst->tls_require_cert); } # endif @@ -1889,8 +1892,8 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim /* * And finally start the TLS code. */ - if (inst->start_tls) { - if (inst->port == 636) { + if (pool_inst->start_tls) { + if (pool_inst->port == 636) { WARN("Told to Start TLS on LDAPS port this will probably fail, please correct the " "configuration"); } @@ -1904,25 +1907,14 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *tim } #endif /* HAVE_LDAP_START_TLS_S */ - status = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password, - &(conn->inst->admin_sasl), false, timeout, NULL, NULL); + status = rlm_ldap_bind(inst, NULL, &conn, conn->pool_inst->admin_identity, conn->pool_inst->admin_password, + &(conn->pool_inst->admin_sasl), false, timeout, NULL, NULL); if (status != LDAP_PROC_SUCCESS) goto error; /* - * This allows multiple connections to spawn simultaneously, - * but prevents them being used until we've directory - * directory capabilities. + * Only error out on memory allocation errors */ - if (!inst->directory) { - pthread_mutex_lock(&inst->directory_mutex); - if (!inst->directory) { - /* - * Only error out on memory allocation errors - */ - if (rlm_ldap_directory_alloc(NULL, &inst->directory, inst, &conn) < 0) goto error; - pthread_mutex_unlock(&inst->directory_mutex); - } - } + if (rlm_ldap_directory_alloc(conn, &conn->directory, inst, &conn) < 0) goto error; return conn; diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index 6e1feb4d718..dc1b78f759a 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -93,21 +93,21 @@ static CONF_PARSER tls_config[] = { /* * Deprecated attributes */ - { FR_CONF_OFFSET("ca_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_ca_file) }, + { FR_CONF_OFFSET("ca_file", PW_TYPE_FILE_INPUT, ldap_pool_inst_t, tls_ca_file) }, - { FR_CONF_OFFSET("ca_path", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_ca_path) }, + { FR_CONF_OFFSET("ca_path", PW_TYPE_FILE_INPUT, ldap_pool_inst_t, tls_ca_path) }, - { FR_CONF_OFFSET("certificate_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_certificate_file) }, + { FR_CONF_OFFSET("certificate_file", PW_TYPE_FILE_INPUT, ldap_pool_inst_t, tls_certificate_file) }, - { FR_CONF_OFFSET("private_key_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_private_key_file) }, - - { FR_CONF_OFFSET("random_file", PW_TYPE_FILE_EXISTS, rlm_ldap_t, tls_random_file) }, + { FR_CONF_OFFSET("private_key_file", PW_TYPE_FILE_INPUT, ldap_pool_inst_t, tls_private_key_file) }, /* * LDAP Specific TLS attributes */ - { FR_CONF_OFFSET("start_tls", PW_TYPE_BOOLEAN, rlm_ldap_t, start_tls), .dflt = "no" }, - { FR_CONF_OFFSET("require_cert", PW_TYPE_STRING, rlm_ldap_t, tls_require_cert_str) }, + { FR_CONF_OFFSET("start_tls", PW_TYPE_BOOLEAN, ldap_pool_inst_t, start_tls), .dflt = "no" }, + + { FR_CONF_OFFSET("require_cert", PW_TYPE_STRING, ldap_pool_inst_t, tls_require_cert_str) }, + CONF_PARSER_TERMINATOR }; @@ -176,54 +176,67 @@ static const CONF_PARSER acct_section_config[] = { */ static CONF_PARSER option_config[] = { /* - * Debugging flags to the server + * Pool config items */ - { FR_CONF_OFFSET("ldap_debug", PW_TYPE_INTEGER, rlm_ldap_t, ldap_debug), .dflt = "0x0000" }, - - { FR_CONF_OFFSET("dereference", PW_TYPE_STRING, rlm_ldap_t, dereference_str) }, + { FR_CONF_OFFSET("chase_referrals", PW_TYPE_BOOLEAN, rlm_ldap_t, pool_inst.chase_referrals) }, - { FR_CONF_OFFSET("chase_referrals", PW_TYPE_BOOLEAN, rlm_ldap_t, chase_referrals) }, + { FR_CONF_OFFSET("use_referral_credentials", PW_TYPE_BOOLEAN, rlm_ldap_t, pool_inst.use_referral_credentials), .dflt = "no" }, - { FR_CONF_OFFSET("use_referral_credentials", PW_TYPE_BOOLEAN, rlm_ldap_t, use_referral_credentials), .dflt = "no" }, - - { FR_CONF_OFFSET("rebind", PW_TYPE_BOOLEAN, rlm_ldap_t, rebind) }, + { FR_CONF_OFFSET("rebind", PW_TYPE_BOOLEAN, rlm_ldap_t, pool_inst.rebind) }, #ifdef LDAP_CONTROL_X_SESSION_TRACKING - { FR_CONF_OFFSET("session_tracking", PW_TYPE_BOOLEAN, rlm_ldap_t, session_tracking), .dflt = "no" }, + { FR_CONF_OFFSET("session_tracking", PW_TYPE_BOOLEAN, rlm_ldap_t, pool_inst.session_tracking), .dflt = "no" }, #endif #ifdef LDAP_OPT_NETWORK_TIMEOUT /* timeout on network activity */ - { FR_CONF_DEPRECATED("net_timeout", PW_TYPE_INTEGER, rlm_ldap_t, net_timeout), .dflt = "10" }, + { FR_CONF_DEPRECATED("net_timeout", PW_TYPE_INTEGER, rlm_ldap_t, pool_inst.net_timeout), .dflt = "10" }, #endif - /* timeout for search results */ - { FR_CONF_OFFSET("res_timeout", PW_TYPE_INTEGER, rlm_ldap_t, res_timeout), .dflt = "20" }, - - /* allow server unlimited time for search (server-side limit) */ - { FR_CONF_OFFSET("srv_timelimit", PW_TYPE_INTEGER, rlm_ldap_t, srv_timelimit), .dflt = "20" }, - #ifdef LDAP_OPT_X_KEEPALIVE_IDLE - { FR_CONF_OFFSET("idle", PW_TYPE_INTEGER, rlm_ldap_t, keepalive_idle), .dflt = "60" }, + { FR_CONF_OFFSET("idle", PW_TYPE_INTEGER, rlm_ldap_t, pool_inst.keepalive_idle), .dflt = "60" }, #endif #ifdef LDAP_OPT_X_KEEPALIVE_PROBES - { FR_CONF_OFFSET("probes", PW_TYPE_INTEGER, rlm_ldap_t, keepalive_probes), .dflt = "3" }, + { FR_CONF_OFFSET("probes", PW_TYPE_INTEGER, rlm_ldap_t, pool_inst.keepalive_probes), .dflt = "3" }, #endif #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL - { FR_CONF_OFFSET("interval", PW_TYPE_INTEGER, rlm_ldap_t, keepalive_interval), .dflt = "30" }, + { FR_CONF_OFFSET("interval", PW_TYPE_INTEGER, rlm_ldap_t, pool_inst.keepalive_interval), .dflt = "30" }, #endif + + { FR_CONF_OFFSET("dereference", PW_TYPE_STRING, rlm_ldap_t, pool_inst.dereference_str) }, + + /* allow server unlimited time for search (server-side limit) */ + { FR_CONF_OFFSET("srv_timelimit", PW_TYPE_INTEGER, rlm_ldap_t, pool_inst.srv_timelimit), .dflt = "20" }, + + /* + * Instance config items + */ + /* timeout for search results */ + { FR_CONF_OFFSET("res_timeout", PW_TYPE_INTEGER, rlm_ldap_t, res_timeout), .dflt = "20" }, + CONF_PARSER_TERMINATOR }; +static const CONF_PARSER global_config[] = { + { FR_CONF_OFFSET("random_file", PW_TYPE_FILE_EXISTS, rlm_ldap_t, tls_random_file) }, + + { FR_CONF_OFFSET("ldap_debug", PW_TYPE_INTEGER, rlm_ldap_t, ldap_debug), .dflt = "0x0000" }, /* Debugging flags to the server */ + + CONF_PARSER_TERMINATOR +}; static const CONF_PARSER module_config[] = { - { FR_CONF_OFFSET("server", PW_TYPE_STRING | PW_TYPE_MULTI, rlm_ldap_t, config_server) }, /* Do not set to required */ - { FR_CONF_OFFSET("port", PW_TYPE_SHORT, rlm_ldap_t, port) }, + /* + * Pool config items + */ + { FR_CONF_OFFSET("server", PW_TYPE_STRING | PW_TYPE_MULTI, rlm_ldap_t, pool_inst.config_server) }, /* Do not set to required */ + + { FR_CONF_OFFSET("port", PW_TYPE_SHORT, rlm_ldap_t, pool_inst.port) }, - { FR_CONF_OFFSET("identity", PW_TYPE_STRING, rlm_ldap_t, admin_identity) }, - { FR_CONF_OFFSET("password", PW_TYPE_STRING | PW_TYPE_SECRET, rlm_ldap_t, admin_password) }, + { FR_CONF_OFFSET("identity", PW_TYPE_STRING, rlm_ldap_t, pool_inst.admin_identity) }, + { FR_CONF_OFFSET("password", PW_TYPE_STRING | PW_TYPE_SECRET, rlm_ldap_t, pool_inst.admin_password) }, - { FR_CONF_OFFSET("sasl", PW_TYPE_SUBSECTION, rlm_ldap_t, admin_sasl), .subcs = (void const *) sasl_mech_static }, + { FR_CONF_OFFSET("sasl", PW_TYPE_SUBSECTION, rlm_ldap_t, pool_inst.admin_sasl), .subcs = (void const *) sasl_mech_static }, { FR_CONF_OFFSET("valuepair_attribute", PW_TYPE_STRING, rlm_ldap_t, valuepair_attr) }, @@ -250,7 +263,9 @@ static const CONF_PARSER module_config[] = { { FR_CONF_POINTER("options", PW_TYPE_SUBSECTION, NULL), .subcs = (void const *) option_config }, - { FR_CONF_POINTER("tls", PW_TYPE_SUBSECTION, NULL), .subcs = (void const *) tls_config }, + { FR_CONF_POINTER("global", PW_TYPE_SUBSECTION, NULL), .subcs = (void const *) global_config }, + + { FR_CONF_OFFSET("tls", PW_TYPE_SUBSECTION, rlm_ldap_t, pool_inst), .subcs = (void const *) tls_config }, CONF_PARSER_TERMINATOR }; @@ -689,28 +704,28 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, UNUSED void /* * Expand dynamic SASL fields */ - if (conn->inst->user_sasl.mech) { + if (inst->user_sasl.mech) { memset(&sasl, 0, sizeof(sasl)); if (tmpl_expand(&sasl.mech, sasl_mech_buff, sizeof(sasl_mech_buff), request, - conn->inst->user_sasl.mech, rlm_ldap_escape_func, inst) < 0) { + inst->user_sasl.mech, rlm_ldap_escape_func, inst) < 0) { REDEBUG("Failed expanding user.sasl.mech: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto finish; } - if (conn->inst->user_sasl.proxy) { + if (inst->user_sasl.proxy) { if (tmpl_expand(&sasl.proxy, sasl_proxy_buff, sizeof(sasl_proxy_buff), request, - conn->inst->user_sasl.proxy, rlm_ldap_escape_func, inst) < 0) { + inst->user_sasl.proxy, rlm_ldap_escape_func, inst) < 0) { REDEBUG("Failed expanding user.sasl.proxy: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto finish; } } - if (conn->inst->user_sasl.realm) { + if (inst->user_sasl.realm) { if (tmpl_expand(&sasl.realm, sasl_realm_buff, sizeof(sasl_realm_buff), request, - conn->inst->user_sasl.realm, rlm_ldap_escape_func, inst) < 0) { + inst->user_sasl.realm, rlm_ldap_escape_func, inst) < 0) { REDEBUG("Failed expanding user.sasl.realm: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto finish; @@ -731,7 +746,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, UNUSED void } conn->rebound = true; status = rlm_ldap_bind(inst, request, &conn, dn, request->password->vp_strvalue, - conn->inst->user_sasl.mech ? &sasl : NULL, true, NULL, NULL, NULL); + inst->user_sasl.mech ? &sasl : NULL, true, NULL, NULL, NULL); switch (status) { case LDAP_PROC_SUCCESS: rcode = RLM_MODULE_OK; @@ -1066,7 +1081,7 @@ skip_edir: RINDENT(); if (rlm_ldap_map_do(inst, request, conn->handle, &expanded, entry) > 0) rcode = RLM_MODULE_UPDATED; REXDENT(); - rlm_ldap_check_reply(inst, request); + rlm_ldap_check_reply(inst, request, conn); } finish: @@ -1341,11 +1356,8 @@ static int mod_detach(void *instance) if (inst->userobj_sort_ctrl) ldap_control_free(inst->userobj_sort_ctrl); #endif - pthread_mutex_destroy(&inst->directory_mutex); - fr_connection_pool_free(inst->pool); talloc_free(inst->user_map); - talloc_free(inst->directory); return 0; } @@ -1473,7 +1485,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) options = cf_section_sub_find(conf, "options"); if (!options || !cf_pair_find(options, "chase_referrals")) { - inst->chase_referrals_unset = true; /* use OpenLDAP defaults */ + inst->pool_inst.chase_referrals_unset = true; /* use OpenLDAP defaults */ } /* @@ -1504,7 +1516,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) * connection pool. */ if (!cf_pair_find(conf, "pool")) { - if (!inst->config_server) { + if (!inst->pool_inst.config_server) { cf_log_err_cs(conf, "Configuration item 'server' must have a value"); goto error; } @@ -1517,7 +1529,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) goto error; } - if (inst->admin_sasl.mech) { + if (inst->pool_inst.admin_sasl.mech) { cf_log_err_cs(conf, "Configuration item 'sasl.mech' not supported. " "Linked libldap does not provide ldap_sasl_interactive_bind function"); goto error; @@ -1543,8 +1555,8 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) /* * Now iterate over all the 'server' config items */ - for (i = 0; i < talloc_array_length(inst->config_server); i++) { - char const *value = inst->config_server[i]; + for (i = 0; i < talloc_array_length(inst->pool_inst.config_server); i++) { + char const *value = inst->pool_inst.config_server[i]; size_t j; /* @@ -1625,7 +1637,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) */ if (ldap_url->lud_scheme) { if (strcmp(ldap_url->lud_scheme, "ldaps") == 0) { - if (inst->start_tls == true) { + if (inst->pool_inst.start_tls == true) { cf_log_err_cs(conf, "ldaps:// scheme is not compatible " "with 'start_tls'"); goto ldap_url_error; @@ -1641,7 +1653,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) /* * URL port overrides configured port. */ - ldap_url->lud_port = inst->port; + ldap_url->lud_port = inst->pool_inst.port; /* * If there's no URL port, then set it to the default @@ -1656,7 +1668,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) cf_log_err_cs(conf, "Failed recombining URL components"); goto ldap_url_error; } - inst->server = talloc_asprintf_append(inst->server, "%s ", url); + inst->pool_inst.server = talloc_asprintf_append(inst->pool_inst.server, "%s ", url); free(url); } # else @@ -1678,11 +1690,11 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) * port, we use the hard-coded default. */ if (set_port_maybe) { - ldap_url->lud_port = inst->port; + ldap_url->lud_port = inst->pool_inst.port; if (!ldap_url->lud_port) ldap_url->lud_port = default_port; } - inst->server = talloc_asprintf_append(inst->server, "%s:%i ", + inst->pool_inst.server = talloc_asprintf_append(inst->pool_inst.server, "%s:%i ", ldap_url->lud_host ? ldap_url->lud_host : "localhost", ldap_url->lud_port); # endif @@ -1709,7 +1721,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) int port = 0; size_t len; - port = inst->port; + port = inst->pool_inst.port; /* * We don't support URLs if the library didn't provide @@ -1736,39 +1748,44 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) } if (port == 0) port = LDAP_PORT; - inst->server = talloc_asprintf_append(inst->server, "ldap://%.*s:%i ", (int) len, value, port); + inst->pool_inst.server = talloc_asprintf_append(inst->pool_inst.server, "ldap://%.*s:%i ", (int) len, value, port); #else /* * ldap_init takes port, which can be overridden by :port so * we don't need to do any parsing here. */ - inst->server = talloc_asprintf_append(inst->server, "%s ", value); + inst->pool_inst.server = talloc_asprintf_append(inst->pool_inst.server, "%s ", value); #endif } } - if (inst->server) inst->server[talloc_array_length(inst->server) - 2] = '\0'; - DEBUG4("rlm_ldap (%s) - LDAP server string: %s", inst->name, inst->server); + /* + * inst->pool_inst.server be unset if connection pool sharing is used. + */ + if (inst->pool_inst.server) { + inst->pool_inst.server[talloc_array_length(inst->pool_inst.server) - 2] = '\0'; + DEBUG4("rlm_ldap (%s) - LDAP server string: %s", inst->name, inst->pool_inst.server); + } #ifdef LDAP_OPT_X_TLS_NEVER /* * Workaround for servers which support LDAPS but not START TLS */ - if (inst->port == LDAPS_PORT || inst->tls_mode) { - inst->tls_mode = LDAP_OPT_X_TLS_HARD; + if (inst->pool_inst.port == LDAPS_PORT || inst->pool_inst.tls_mode) { + inst->pool_inst.tls_mode = LDAP_OPT_X_TLS_HARD; } else { - inst->tls_mode = 0; + inst->pool_inst.tls_mode = 0; } #endif /* * Convert dereference strings to enumerated constants */ - if (inst->dereference_str) { - inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1); - if (inst->dereference < 0) { + if (inst->pool_inst.dereference_str) { + inst->pool_inst.dereference = fr_str2int(ldap_dereference, inst->pool_inst.dereference_str, -1); + if (inst->pool_inst.dereference < 0) { cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', " - "'finding' or 'always'", inst->dereference_str); + "'finding' or 'always'", inst->pool_inst.dereference_str); goto error; } } @@ -1856,15 +1873,16 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) } #endif - if (inst->tls_require_cert_str) { + if (inst->pool_inst.tls_require_cert_str) { #ifdef LDAP_OPT_X_TLS_NEVER /* * Convert cert strictness to enumerated constants */ - inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1); - if (inst->tls_require_cert < 0) { + inst->pool_inst.tls_require_cert = fr_str2int(ldap_tls_require_cert, + inst->pool_inst.tls_require_cert_str, -1); + if (inst->pool_inst.tls_require_cert < 0) { cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', " - "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str); + "'demand', 'allow', 'try' or 'hard'", inst->pool_inst.tls_require_cert_str); goto error; } #else @@ -1886,11 +1904,6 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) return -1; } - /* - * Initialise the directory mutex - */ - pthread_mutex_init(&inst->directory_mutex, NULL); - /* * Set global options */ diff --git a/src/modules/rlm_ldap/rlm_ldap.h b/src/modules/rlm_ldap/rlm_ldap.h index a958d36038e..14092cbbd00 100644 --- a/src/modules/rlm_ldap/rlm_ldap.h +++ b/src/modules/rlm_ldap/rlm_ldap.h @@ -133,7 +133,7 @@ typedef enum { extern FR_NAME_NUMBER const ldap_supported_extensions[]; -typedef struct ldap_instance rlm_ldap_t; +typedef struct rlm_ldap_s rlm_ldap_t; typedef struct ldap_acct_section { CONF_SECTION *cs; //!< Section configuration. @@ -159,25 +159,6 @@ typedef struct rlm_ldap_control { //!< we've finished using it. } rlm_ldap_control_t; -/** Tracks the state of a libldap connection handle - * - */ -typedef struct ldap_handle { - LDAP *handle; //!< libldap handle. - bool rebound; //!< Whether the connection has been rebound to something - //!< other than the admin user. - bool referred; //!< Whether the connection is now established a server - //!< other than the configured one. - - rlm_ldap_control_t serverctrls[LDAP_MAX_CONTROLS + 1]; //!< Server controls to use for all operations with - //!< this handle. - rlm_ldap_control_t clientctrls[LDAP_MAX_CONTROLS + 1]; //!< Client controls to use for all operations with - //!< this handle. - int serverctrls_cnt; //!< Number of server controls associated with the handle. - int clientctrls_cnt; //!< Number of client controls associated with the handle. - - rlm_ldap_t const *inst; //!< rlm_ldap configuration. -} ldap_handle_t; typedef enum { LDAP_DIRECTORY_UNKNOWN = 0, //!< We can't determine the directory server. @@ -206,14 +187,15 @@ typedef struct ldap_directory { //!< password. } ldap_directory_t; -struct ldap_instance { - char const *name; //!< Instance name. - - CONF_SECTION *cs; //!< Main configuration section for this instance. - fr_connection_pool_t *pool; //!< Connection pool instance. - - char const **config_server; //!< Server set in the config. +/** Pool configuration + * + * Must not be passed into functions except via the connection handle + * this avoids problems with not using the connection pool configuration. + */ +typedef struct { char *server; //!< Initial server to bind to. + char const **config_server; //!< Server set in the config. + uint16_t port; //!< Port to use when binding to the server. char const *admin_identity; //!< Identity we bind as when we need to query the LDAP @@ -222,8 +204,8 @@ struct ldap_instance { ldap_sasl admin_sasl; //!< SASL parameters used when binding as the admin. - char const *dereference_str; //!< When to dereference (never, searching, finding, always) int dereference; //!< libldap value specifying dereferencing behaviour. + char const *dereference_str; //!< When to dereference (never, searching, finding, always) bool chase_referrals; //!< If the LDAP server returns a referral to another server //!< or point in the tree, follow it, establishing new @@ -238,10 +220,65 @@ struct ldap_instance { //!< referrals on the same server, but won't bind to other //!< servers. - uint32_t ldap_debug; //!< Debug flag for the SDK. + /* + * TLS items. + */ + int tls_mode; + bool start_tls; //!< Send the Start TLS message to the LDAP directory + //!< to start encrypted communications using the standard + //!< LDAP port. + + char const *tls_ca_file; //!< Sets the full path to a CA certificate (used to validate + //!< the certificate the server presents). - ldap_directory_t *directory; //!< Server capabilities. - pthread_mutex_t directory_mutex; //!< Sync modifications to directory structure. + char const *tls_ca_path; //!< Sets the path to a directory containing CA certificates. + + char const *tls_certificate_file; //!< Sets the path to the public certificate file we present + //!< to the servers. + + char const *tls_private_key_file; //!< Sets the path to the private key for our public + //!< certificate. + + char const *tls_require_cert_str; //!< Sets requirements for validating the certificate the + //!< server presents. + + int tls_require_cert; //!< OpenLDAP constant representing the require cert string. + + /* + * Options + */ +#ifdef LDAP_CONTROL_X_SESSION_TRACKING + bool session_tracking; //!< Whether we add session tracking controls, which help + //!< identify the autz or acct session the commands were + //!< issued for. +#endif + + /* + * For keep-alives. + */ +#ifdef LDAP_OPT_X_KEEPALIVE_IDLE + uint32_t keepalive_idle; //!< Number of seconds a connections needs to remain idle + //!< before TCP starts sending keepalive probes. +#endif +#ifdef LDAP_OPT_X_KEEPALIVE_PROBES + uint32_t keepalive_probes; //!< Number of missed timeouts before the connection is + //!< dropped. +#endif +#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL + uint32_t keepalive_interval; //!< Interval between keepalive probes. +#endif + + /* + * Search timelimits + */ + uint32_t srv_timelimit; //!< How long the server should spent on a single request + //!< (also bounded by value on the server). +} ldap_pool_inst_t; + +struct rlm_ldap_s { + char const *name; //!< Instance name. + + CONF_SECTION *cs; //!< Main configuration section for this instance. bool expect_password; //!< True if the user_map included a mapping between an LDAP //!< attribute and one of our password reference attributes. @@ -251,6 +288,11 @@ struct ldap_instance { */ vp_map_t *user_map; //!< Attribute map applied to users and profiles. + /* + * Search time limits + */ + uint32_t res_timeout; //!< How long we wait for a result from the server. + /* * User object attributes and filters */ @@ -267,10 +309,11 @@ struct ldap_instance { bool access_positive; //!< If true the presence of the attribute will allow access, //!< else it will deny access. + ldap_sasl_dynamic user_sasl; //!< SASL parameters used when binding as the user. + char const *valuepair_attr; //!< Generic dynamic mapping attribute, contains a RADIUS //!< attribute and value. - ldap_sasl_dynamic user_sasl; //!< SASL parameters used when binding as the user. /* * Group object attributes and filters @@ -333,46 +376,6 @@ struct ldap_instance { ldap_acct_section_t *postauth; //!< Modify mappings for post-auth. ldap_acct_section_t *accounting; //!< Modify mappings for accounting. - /* - * TLS items. We should really normalize these with the - * TLS code in 3.0. - */ - int tls_mode; - bool start_tls; //!< Send the Start TLS message to the LDAP directory - //!< to start encrypted communications using the standard - //!< LDAP port. - - char const *tls_ca_file; //!< Sets the full path to a CA certificate (used to validate - //!< the certificate the server presents). - - char const *tls_ca_path; //!< Sets the path to a directory containing CA certificates. - - char const *tls_certificate_file; //!< Sets the path to the public certificate file we present - //!< to the servers. - - char const *tls_private_key_file; //!< Sets the path to the private key for our public - //!< certificate. - - char const *tls_random_file; //!< Path to the random file if /dev/random and /dev/urandom - //!< are unavailable. - - char const *tls_require_cert_str; //!< Sets requirements for validating the certificate the - //!< server presents. - - int tls_require_cert; //!< OpenLDAP constant representing the require cert string. - - /* - * Options - */ -#ifdef LDAP_CONTROL_X_SESSION_TRACKING - bool session_tracking; //!< Whether we add session tracking controls, which help - //!< identify the autz or acct session the commands were - //!< issued for. -#endif - uint32_t res_timeout; //!< How long we wait for a result from the server. - uint32_t srv_timelimit; //!< How long the server should spent on a single request - //!< (also bounded by value on the server). - #ifdef WITH_EDIR /* * eDir support @@ -382,22 +385,42 @@ struct ldap_instance { bool edir_autz; //!< If true, and we have the Universal Password, bind with it //!< to perform additional authorisation checks. #endif + + fr_connection_pool_t *pool; //!< Connection pool instance. + ldap_pool_inst_t pool_inst; //!< Connection configuration instance. + /* - * For keep-alives. + * Global config */ -#ifdef LDAP_OPT_X_KEEPALIVE_IDLE - uint32_t keepalive_idle; //!< Number of seconds a connections needs to remain idle - //!< before TCP starts sending keepalive probes. -#endif -#ifdef LDAP_OPT_X_KEEPALIVE_PROBES - uint32_t keepalive_probes; //!< Number of missed timeouts before the connection is - //!< dropped. -#endif -#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL - uint32_t keepalive_interval; //!< Interval between keepalive probes. -#endif + char const *tls_random_file; //!< Path to the random file if /dev/random and /dev/urandom + //!< are unavailable. + + uint32_t ldap_debug; //!< Debug flag for the SDK. }; +/** Tracks the state of a libldap connection handle + * + */ +typedef struct ldap_handle { + LDAP *handle; //!< libldap handle. + bool rebound; //!< Whether the connection has been rebound to something + //!< other than the admin user. + bool referred; //!< Whether the connection is now established a server + //!< other than the configured one. + + rlm_ldap_control_t serverctrls[LDAP_MAX_CONTROLS + 1]; //!< Server controls to use for all operations with + //!< this handle. + rlm_ldap_control_t clientctrls[LDAP_MAX_CONTROLS + 1]; //!< Client controls to use for all operations with + //!< this handle. + int serverctrls_cnt; //!< Number of server controls associated with the handle. + int clientctrls_cnt; //!< Number of client controls associated with the handle. + + ldap_directory_t *directory; //!< The type of directory we're connected to. + + ldap_pool_inst_t const *pool_inst; //!< rlm_ldap connection configuration. + rlm_ldap_t const *inst; //!< rlm_ldap pool inst. +} ldap_handle_t; + /** Result of expanding the RHS of a set of maps * * Used to store the array of attributes we'll be querying for. @@ -489,7 +512,7 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_ha rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t const *conn, LDAPMessage *entry); -void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request); +void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t const *conn); /* * ldap.c - Callbacks for the connection pool API. @@ -563,7 +586,7 @@ int rlm_ldap_control_add_session_tracking(ldap_handle_t *conn, REQUEST *request) /* * directory.c - Get directory capabilities from the remote server */ -int rlm_ldap_directory_alloc(TALLOC_CTX *ctx, ldap_directory_t **out, rlm_ldap_t *inst, ldap_handle_t **pconn); +int rlm_ldap_directory_alloc(TALLOC_CTX *ctx, ldap_directory_t **out, rlm_ldap_t const *inst, ldap_handle_t **pconn); /* * edir.c - Magic extensions for Novell