/** Parse an accounting sub section. * * Allocate a new ldap_acct_section_t and write the config data into it. * * @param[in] inst rlm_ldap configuration. * @param[in] parent of the config section. * @param[out] config to write the sub section parameters to. * @param[in] comp The section name were parsing the config for. * @return 0 on success, else < 0 on failure. */ static int parse_sub_section(ldap_instance_t *inst, CONF_SECTION *parent, ldap_acct_section_t **config, rlm_components_t comp) { CONF_SECTION *cs; char const *name = section_type_value[comp].section; cs = cf_section_sub_find(parent, name); if (!cs) { INFO("rlm_ldap (%s): Couldn't find configuration for %s, will return NOOP for calls " "from this section", inst->xlat_name, name); return 0; } *config = talloc_zero(inst, ldap_acct_section_t); if (cf_section_parse(cs, *config, acct_section_config) < 0) { LDAP_ERR("Failed parsing configuration for section %s", name); return -1; } (*config)->cs = cs; return 0; }
/** Iterate over pairs in mapping section creating equivalent client pairs from LDAP values * * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too. * * @param[in] inst rlm_ldap configuration. * @param[out] client config section. * @param[in] map section. * @param[in] conn LDAP connection. * @param[in] entry returned from search. * @return 0 on success else -1 on error. */ static int rlm_ldap_client_map_section(ldap_instance_t const *inst, CONF_SECTION *client, CONF_SECTION const *map, ldap_handle_t *conn, LDAPMessage *entry) { CONF_ITEM const *ci; for (ci = cf_item_find_next(map, NULL); ci != NULL; ci = cf_item_find_next(map, ci)) { CONF_PAIR const *cp; char **value; char const *attr; /* * Recursively process map subsection */ if (cf_item_is_section(ci)) { CONF_SECTION *cs, *cc; cs = cf_itemtosection(ci); cc = cf_section_alloc(client, cf_section_name1(cs), cf_section_name2(cs)); if (!cc) return -1; cf_section_add(client, cc); if (rlm_ldap_client_map_section(inst, cc, cs, conn, entry) < 0) return -1; continue; } cp = cf_itemtopair(ci); attr = cf_pair_attr(cp); value = ldap_get_values(conn->handle, entry, cf_pair_value(cp)); if (!value) continue; cp = cf_pair_alloc(client, attr, value[0], T_OP_SET, T_SINGLE_QUOTED_STRING); if (!cp) { LDAP_ERR("Failed allocing pair \"%s\" = \"%s\"", attr, value[0]); return -1; } cf_item_add(client, cf_pairtoitem(cp)); } return 0; }
/** Instantiate the module * * Creates a new instance of the module reading parameters from a configuration section. * * @param conf to parse. * @param instance Where to write pointer to configuration data. * @return 0 on success < 0 on failure. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { static bool version_done; CONF_SECTION *options; ldap_instance_t *inst = instance; inst->cs = conf; options = cf_section_sub_find(conf, "options"); if (!options || !cf_pair_find(options, "chase_referrals")) { inst->chase_referrals_unset = true; /* use OpenLDAP defaults */ } inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } /* * Only needs to be done once, prevents races in environment * initialisation within libldap. * * See: https://github.com/arr2036/ldapperf/issues/2 */ #ifdef HAVE_LDAP_INITIALIZE ldap_initialize(&inst->handle, ""); #else inst->handle = ldap_init("", 0); #endif /* * Get version info from the LDAP API. */ if (!version_done) { static LDAPAPIInfo info; /* static to quiet valgrind about this being uninitialised */ int ldap_errno; version_done = true; ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info); if (ldap_errno == LDAP_OPT_SUCCESS) { if (strcmp(info.ldapai_vendor_name, LDAP_VENDOR_NAME) != 0) { WARN("rlm_ldap: libldap vendor changed since the server was built"); WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME); } if (info.ldapai_vendor_version != LDAP_VENDOR_VERSION) { WARN("rlm_ldap: libldap version changed since the server was built"); WARN("rlm_ldap: linked: %i, built: %i", info.ldapai_vendor_version, LDAP_VENDOR_VERSION); } INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name, info.ldapai_vendor_version); ldap_memfree(info.ldapai_vendor_name); ldap_memfree(info.ldapai_extensions); } else { DEBUG("rlm_ldap: Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO " "returned: %i", ldap_errno); INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH); } } /* * If the configuration parameters can't be parsed, then fail. */ if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) || (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) { cf_log_err_cs(conf, "Failed parsing configuration"); goto error; } /* * Sanity checks for cacheable groups code. */ if (inst->cacheable_group_name && inst->groupobj_membership_filter) { if (!inst->groupobj_name_attr) { cf_log_err_cs(conf, "Directive 'group.name_attribute' must be set if cacheable " "group names are enabled"); goto error; } } /* * Split original server value out into URI, server and port * so whatever initialization function we use later will have * the server information in the format it needs. */ if (ldap_is_ldap_url(inst->server)) { LDAPURLDesc *ldap_url; int port; if (ldap_url_parse(inst->server, &ldap_url)){ cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", inst->server); return -1; } /* * Figure out the port from the URL */ if (ldap_url->lud_port == 0) { if (strcmp(ldap_url->lud_scheme, "ldaps://") == 0) { if (inst->start_tls == true) { start_tls_error: cf_log_err_cs(conf, "ldaps:// scheme is not compatible with 'start_tls'"); return -1; } port = 636; } else { port = 384; } } else { port = ldap_url->lud_port; } inst->uri = inst->server; inst->server = talloc_strdup(inst, ldap_url->lud_host); if ((inst->port != 384) && (port != inst->port)) { WARN("Non-default 'port' directive %i set to %i by LDAP URI", inst->port, port); } inst->port = port; /* * @todo We could set a few other top level * directives using the URL, like base_dn * and scope. */ ldap_free_urldesc(ldap_url); /* * We need to construct an LDAP URI */ } else { switch (inst->port) { default: case 384: inst->uri = talloc_asprintf(inst, "ldap://%s:%i/", inst->server, inst->port); break; case 636: if (inst->start_tls == true) goto start_tls_error; inst->uri = talloc_asprintf(inst, "ldaps://%s:%i/", inst->server, inst->port); break; } } #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; } else { 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) { cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', " "'finding' or 'always'", inst->dereference_str); goto error; } } #if LDAP_SET_REBIND_PROC_ARGS != 3 /* * The 2-argument rebind doesn't take an instance variable. Our rebind function needs the instance * variable for the username, password, etc. */ if (inst->rebind == true) { cf_log_err_cs(conf, "Cannot use 'rebind' directive as this version of libldap " "does not support the API that we need"); goto error; } #endif /* * Convert scope strings to enumerated constants */ inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1); if (inst->userobj_scope < 0) { cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'" #ifdef LDAP_SCOPE_CHILDREN ", 'base' or 'children'" #else " or 'base'" #endif , inst->userobj_scope_str); goto error; } inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1); if (inst->groupobj_scope < 0) { cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'" #ifdef LDAP_SCOPE_CHILDREN ", 'base' or 'children'" #else " or 'base'" #endif , inst->groupobj_scope_str); goto error; } inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1); if (inst->clientobj_scope < 0) { cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'" #ifdef LDAP_SCOPE_CHILDREN ", 'base' or 'children'" #else " or 'base'" #endif , inst->clientobj_scope_str); goto error; } if (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) { cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', " "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str); goto error; } #else cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current " "version of libldap. Please upgrade or substitute current libldap and " "rebuild this module"); goto error; #endif } /* * Build the attribute map */ if (map_afrom_cs(&inst->user_map, cf_section_sub_find(inst->cs, "update"), PAIR_LIST_REPLY, PAIR_LIST_REQUEST, rlm_ldap_map_verify, inst, LDAP_MAX_ATTRMAP) < 0) { return -1; } /* * Group comparison checks. */ if (cf_section_name2(conf)) { static ATTR_FLAGS flags; char buffer[256]; snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name); if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating group attribute: %s", fr_strerror()); return -1; } inst->group_da = dict_attrbyname(buffer); if (!inst->group_da) { LDAP_ERR("Failed creating attribute %s", buffer); goto error; } paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); /* * Were the default instance */ } else { inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0); paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); } xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst); /* * Setup the cache attribute */ if (inst->cache_attribute) { static ATTR_FLAGS flags; if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating cache attribute: %s", fr_strerror()); goto error; } inst->cache_da = dict_attrbyname(inst->cache_attribute); } else { inst->cache_da = inst->group_da; /* Default to the group_da */ } /* * Initialize the socket pool. */ inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL); if (!inst->pool) goto error; /* * Bulk load dynamic clients. */ if (inst->do_clients) { CONF_SECTION *cs; cs = cf_section_sub_find(inst->cs, "client"); if (!cs) { cf_log_err_cs(conf, "Told to load clients but no client section found"); goto error; } cs = cf_section_sub_find(cs, "attribute"); if (!cs) { cf_log_err_cs(conf, "Told to load clients but no attribute section found"); goto error; } if (rlm_ldap_client_load(inst, cs) < 0) { cf_log_err_cs(conf, "Error loading clients"); return -1; } } return 0; error: return -1; }
/** Load clients from LDAP on server start * * @param[in] inst rlm_ldap configuration. * @return -1 on error else 0. */ int rlm_ldap_load_clients(ldap_instance_t const *inst) { int ret = 0; ldap_rcode_t status; ldap_handle_t *conn = NULL; /* This needs to be updated if additional attributes need to be retrieved */ char const *attrs[7]; char const **attrs_p; LDAPMessage *result = NULL; LDAPMessage *entry; RADCLIENT *c; LDAP_DBG("Loading dynamic clients"); /* * Basic sanity checks. */ if (!inst->clientobj_identifier) { LDAP_ERR("Told to load clients but 'client.identifier_attribute' not specified"); return -1; } if (!inst->clientobj_secret) { LDAP_ERR("Told to load clients but 'client.secret_attribute' not specified"); return -1; } if (!inst->clientobj_base_dn) { LDAP_ERR("Told to load clients but 'client.base_dn' not specified"); return -1; } if (!inst->clientobj_filter) { LDAP_ERR("Told to load clients but 'client.filter' not specified"); return -1; } /* * Construct the attribute array */ attrs[0] = inst->clientobj_identifier; attrs[1] = inst->clientobj_secret; attrs_p = attrs + 2; if (inst->clientobj_shortname) { /* 2 */ *attrs_p++ = inst->clientobj_shortname; } if (inst->clientobj_type) { /* 3 */ *attrs_p++ = inst->clientobj_type; } if (inst->clientobj_server) { /* 4 */ *attrs_p++ = inst->clientobj_server; } if (inst->clientobj_require_ma) { /* 5 */ *attrs_p++ = inst->clientobj_require_ma; } *attrs_p = NULL; /* 6 - array needs to be NULL terminated */ conn = rlm_ldap_get_socket(inst, NULL); if (!conn) return -1; /* * Perform all searches as the admin user. */ if (conn->rebound) { status = rlm_ldap_bind(inst, NULL, &conn, inst->admin_dn, inst->password, true); if (status != LDAP_PROC_SUCCESS) { return -1; } rad_assert(conn); conn->rebound = false; } status = rlm_ldap_search(inst, NULL, &conn, inst->clientobj_base_dn, inst->clientobj_scope, inst->clientobj_filter, attrs, &result); switch (status) { case LDAP_PROC_SUCCESS: break; case LDAP_PROC_NO_RESULT: LDAP_INFO("No clients were found in the directory"); return 0; default: return -1; } rad_assert(conn); entry = ldap_first_entry(conn->handle, result); if (!entry) { int ldap_errno; ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno); LDAP_ERR("Failed retrieving entry: %s", ldap_err2string(ldap_errno)); ret = -1; goto finish; } do { char *dn; char **identifier = NULL; char **shortname = NULL; char **secret = NULL; char **type = NULL; char **server = NULL; char **require_ma = NULL; dn = ldap_get_dn(conn->handle, entry); /* * Check for the required attributes first */ identifier = ldap_get_values(conn->handle, entry, inst->clientobj_identifier); if (!identifier) { LDAP_WARN("Client \"%s\" missing required attribute 'identifier', skipping...", dn); goto next; } secret = ldap_get_values(conn->handle, entry, inst->clientobj_secret); if (!secret) { LDAP_WARN("Client \"%s\" missing required attribute 'secret', skipping...", dn); goto next; } if (inst->clientobj_shortname) { shortname = ldap_get_values(conn->handle, entry, inst->clientobj_shortname); if (!shortname) { LDAP_DBG("Client \"%s\" missing optional attribute 'shortname'", dn); } } if (inst->clientobj_type) { type = ldap_get_values(conn->handle, entry, inst->clientobj_type); if (!type) { LDAP_DBG("Client \"%s\" missing optional attribute 'type'", dn); } } if (inst->clientobj_server) { server = ldap_get_values(conn->handle, entry, inst->clientobj_server); if (!server) { LDAP_DBG("Client \"%s\" missing optional attribute 'server'", dn); } } if (inst->clientobj_require_ma) { require_ma = ldap_get_values(conn->handle, entry, inst->clientobj_require_ma); if (!require_ma) { LDAP_DBG("Client \"%s\" missing optional attribute 'require_ma'", dn); } } /* FIXME: We should really pass a proper ctx */ c = client_from_query(NULL, identifier[0], secret[0], shortname ? shortname[0] : NULL, type ? type[0] : NULL, server ? server[0] : NULL, require_ma ? strncmp(require_ma[0], "true", 4) == 0 : false); if (!c) { goto next; } if (!client_add(NULL, c)) { WARN("Failed to add client, possible duplicate?"); client_free(c); goto next; } LDAP_DBG("Client \"%s\" added", dn); next: ldap_memfree(dn); if (identifier) ldap_value_free(identifier); if (shortname) ldap_value_free(shortname); if (secret) ldap_value_free(secret); if (type) ldap_value_free(type); if (server) ldap_value_free(server); } while((entry = ldap_next_entry(conn->handle, entry))); finish: if (result) { ldap_msgfree(result); } return ret; }
/** Instantiate the module * * Creates a new instance of the module reading parameters from a configuration section. * * @param conf to parse. * @param instance Where to write pointer to configuration data. * @return 0 on success < 0 on failure. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { CONF_SECTION *options; ldap_instance_t *inst = instance; inst->cs = conf; options = cf_section_sub_find(conf, "options"); if (!options || !cf_pair_find(options, "chase_referrals")) { inst->chase_referrals_unset = true; /* use OpenLDAP defaults */ } inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } /* * If the configuration parameters can't be parsed, then fail. */ if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) || (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) { LDAP_ERR("Failed parsing configuration"); goto error; } /* * Sanity checks for cacheable groups code. */ if (inst->cacheable_group_name && inst->groupobj_membership_filter) { if (!inst->groupobj_name_attr) { LDAP_ERR("Directive 'group.name_attribute' must be set if cacheable group names are enabled"); goto error; } } /* * Check for URLs. If they're used and the library doesn't support them, then complain. */ inst->is_url = 0; if (ldap_is_ldap_url(inst->server)) { #ifdef HAVE_LDAP_INITIALIZE inst->is_url = 1; inst->port = 0; #else LDAP_ERR("Directive 'server' is in URL form but ldap_initialize() is not available"); goto error; #endif } /* * 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; } else { inst->tls_mode = 0; } #if LDAP_SET_REBIND_PROC_ARGS != 3 /* * The 2-argument rebind doesn't take an instance variable. Our rebind function needs the instance * variable for the username, password, etc. */ if (inst->rebind == true) { LDAP_ERR("Cannot use 'rebind' directive as this version of libldap does not support the API " "that we need"); goto error; } #endif /* * Convert scope strings to enumerated constants */ inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1); if (inst->userobj_scope < 0) { LDAP_ERR("Invalid 'user.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'", inst->userobj_scope_str); goto error; } inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1); if (inst->groupobj_scope < 0) { LDAP_ERR("Invalid 'group.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'", inst->groupobj_scope_str); goto error; } inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1); if (inst->clientobj_scope < 0) { LDAP_ERR("Invalid 'client.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'", inst->clientobj_scope_str); goto error; } if (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) { LDAP_ERR("Invalid 'tls.require_cert' value \"%s\", expected 'never', 'demand', 'allow', " "'try' or 'hard'", inst->tls_require_cert_str); goto error; } #else LDAP_ERR("Modifying 'tls.require_cert' is not supported by current version of libldap. " "Please upgrade libldap and rebuild this module"); goto error; #endif } /* * Build the attribute map */ if (rlm_ldap_map_verify(inst, &(inst->user_map)) < 0) { goto error; } /* * Group comparison checks. */ if (cf_section_name2(conf)) { ATTR_FLAGS flags; char buffer[256]; snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name); memset(&flags, 0, sizeof(flags)); if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating group attribute: %s", fr_strerror()); return -1; } inst->group_da = dict_attrbyname(buffer); if (!inst->group_da) { LDAP_ERR("Failed creating attribute %s", buffer); goto error; } paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); /* * Were the default instance */ } else { inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0); paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); } xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst); /* * Setup the cache attribute */ if (inst->cache_attribute) { ATTR_FLAGS flags; memset(&flags, 0, sizeof(flags)); if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating cache attribute: %s", fr_strerror()); return -1; } inst->cache_da = dict_attrbyname(inst->cache_attribute); } else { inst->cache_da = inst->group_da; /* Default to the group_da */ } /* * Initialize the socket pool. */ inst->pool = fr_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, mod_conn_delete, NULL); if (!inst->pool) { return -1; } /* * Bulk load dynamic clients. */ if (inst->do_clients) { if (rlm_ldap_load_clients(inst) < 0) { LDAP_ERR("Error loading clients"); return -1; } } return 0; error: return -1; }
/** Load clients from LDAP on server start * * @param[in] inst rlm_ldap configuration. * @param[in] cs to load client attribute/LDAP attribute mappings from. * @return -1 on error else 0. */ int rlm_ldap_client_load(ldap_instance_t const *inst, CONF_SECTION *cs) { int ret = 0; ldap_rcode_t status; ldap_handle_t *conn = NULL; char const **attrs = NULL; CONF_PAIR *cp; int count = 0, idx = 0; LDAPMessage *result = NULL; LDAPMessage *entry; char *dn = NULL; RADCLIENT *c; LDAP_DBG("Loading dynamic clients"); rad_assert(inst->clientobj_base_dn); if (!inst->clientobj_filter) { LDAP_ERR("Told to load clients but 'client.filter' not specified"); return -1; } count = cf_pair_count(cs); count++; /* * Create an array of LDAP attributes to feed to rlm_ldap_search. */ attrs = talloc_array(inst, char const *, count); if (rlm_ldap_client_get_attrs(attrs, &idx, cs) < 0) return -1; conn = rlm_ldap_get_socket(inst, NULL); if (!conn) return -1; /* * Perform all searches as the admin user. */ if (conn->rebound) { status = rlm_ldap_bind(inst, NULL, &conn, inst->admin_dn, inst->password, true); if (status != LDAP_PROC_SUCCESS) { ret = -1; goto finish; } rad_assert(conn); conn->rebound = false; } status = rlm_ldap_search(inst, NULL, &conn, inst->clientobj_base_dn, inst->clientobj_scope, inst->clientobj_filter, attrs, &result); switch (status) { case LDAP_PROC_SUCCESS: break; case LDAP_PROC_NO_RESULT: LDAP_INFO("No clients were found in the directory"); ret = 0; goto finish; default: ret = -1; goto finish; } rad_assert(conn); entry = ldap_first_entry(conn->handle, result); if (!entry) { int ldap_errno; ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno); LDAP_ERR("Failed retrieving entry: %s", ldap_err2string(ldap_errno)); ret = -1; goto finish; } do { CONF_SECTION *cc; char *id; char **value; id = dn = ldap_get_dn(conn->handle, entry); cp = cf_pair_find(cs, "identifier"); if (cp) { value = ldap_get_values(conn->handle, entry, cf_pair_value(cp)); if (value) id = value[0]; } /* * Iterate over mapping sections */ cc = cf_section_alloc(NULL, "client", id); if (rlm_ldap_client_map_section(inst, cc, cs, conn, entry) < 0) { talloc_free(cc); ret = -1; goto finish; } /* *@todo these should be parented from something */ c = client_afrom_cs(NULL, cc, false); if (!c) { talloc_free(cc); ret = -1; goto finish; } /* * Client parents the CONF_SECTION which defined it */ talloc_steal(c, cc); if (!client_add(NULL, c)) { LDAP_ERR("Failed to add client \"%s\", possible duplicate?", dn); ret = -1; client_free(c); goto finish; } LDAP_DBG("Client \"%s\" added", dn); ldap_memfree(dn); dn = NULL; } while ((entry = ldap_next_entry(conn->handle, entry))); finish: talloc_free(attrs); if (dn) ldap_memfree(dn); if (result) ldap_msgfree(result); rlm_ldap_release_socket(inst, conn); return ret; }