📄 util_ldap.c
字号:
/* * Compare client certificate arrays. * * Returns 1 on compare failure, 0 otherwise. */static int compare_client_certs(apr_array_header_t *srcs, apr_array_header_t *dests){ int i = 0; struct apr_ldap_opt_tls_cert_t *src, *dest; /* arrays both NULL? if so, then equal */ if (srcs == NULL && dests == NULL) { return 0; } /* arrays different length or either NULL? If so, then not equal */ if (srcs == NULL || dests == NULL || srcs->nelts != dests->nelts) { return 1; } /* run an actual comparison */ src = (struct apr_ldap_opt_tls_cert_t *)srcs->elts; dest = (struct apr_ldap_opt_tls_cert_t *)dests->elts; for (i = 0; i < srcs->nelts; i++) { if (strcmp(src[i].path, dest[i].path) || strcmp(src[i].password, dest[i].password) || src[i].type != dest[i].type) { return 1; } } /* if we got here, the cert arrays were identical */ return 0;}/* * Find an existing ldap connection struct that matches the * provided ldap connection parameters. * * If not found in the cache, a new ldc structure will be allocated * from st->pool and returned to the caller. If found in the cache, * a pointer to the existing ldc structure will be returned. */static util_ldap_connection_t * uldap_connection_find(request_rec *r, const char *host, int port, const char *binddn, const char *bindpw, deref_options deref, int secure){ struct util_ldap_connection_t *l, *p; /* To traverse the linked list */ int secureflag = secure; util_ldap_state_t *st = (util_ldap_state_t *)ap_get_module_config(r->server->module_config, &ldap_module);#if APR_HAS_THREADS /* mutex lock this function */ apr_thread_mutex_lock(st->mutex);#endif if (secure < APR_LDAP_NONE) { secureflag = st->secure; } /* Search for an exact connection match in the list that is not * being used. */ for (l=st->connections,p=NULL; l; l=l->next) {#if APR_HAS_THREADS if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {#endif if ( (l->port == port) && (strcmp(l->host, host) == 0) && ((!l->binddn && !binddn) || (l->binddn && binddn && !strcmp(l->binddn, binddn))) && ((!l->bindpw && !bindpw) || (l->bindpw && bindpw && !strcmp(l->bindpw, bindpw))) && (l->deref == deref) && (l->secure == secureflag) && !compare_client_certs(st->client_certs, l->client_certs)) { break; }#if APR_HAS_THREADS /* If this connection didn't match the criteria, then we * need to unlock the mutex so it is available to be reused. */ apr_thread_mutex_unlock(l->lock); }#endif p = l; } /* If nothing found, search again, but we don't care about the * binddn and bindpw this time. */ if (!l) { for (l=st->connections,p=NULL; l; l=l->next) {#if APR_HAS_THREADS if (APR_SUCCESS == apr_thread_mutex_trylock(l->lock)) {#endif if ((l->port == port) && (strcmp(l->host, host) == 0) && (l->deref == deref) && (l->secure == secureflag) && !compare_client_certs(st->client_certs, l->client_certs)) { /* the bind credentials have changed */ l->bound = 0; util_ldap_strdup((char**)&(l->binddn), binddn); util_ldap_strdup((char**)&(l->bindpw), bindpw); break; }#if APR_HAS_THREADS /* If this connection didn't match the criteria, then we * need to unlock the mutex so it is available to be reused. */ apr_thread_mutex_unlock(l->lock); }#endif p = l; } }/* artificially disable cache *//* l = NULL; */ /* If no connection what found after the second search, we * must create one. */ if (!l) { /* * Add the new connection entry to the linked list. Note that we * don't actually establish an LDAP connection yet; that happens * the first time authentication is requested. */ /* create the details to the pool in st */ l = apr_pcalloc(st->pool, sizeof(util_ldap_connection_t)); if (apr_pool_create(&l->pool, st->pool) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, "util_ldap: Failed to create memory pool");#if APR_HAS_THREADS apr_thread_mutex_unlock(st->mutex);#endif return NULL; }#if APR_HAS_THREADS apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, st->pool); apr_thread_mutex_lock(l->lock);#endif l->bound = 0; l->host = apr_pstrdup(st->pool, host); l->port = port; l->deref = deref; util_ldap_strdup((char**)&(l->binddn), binddn); util_ldap_strdup((char**)&(l->bindpw), bindpw); /* The security mode after parsing the URL will always be either * APR_LDAP_NONE (ldap://) or APR_LDAP_SSL (ldaps://). * If the security setting is NONE, override it to the security * setting optionally supplied by the admin using LDAPTrustedMode */ l->secure = secureflag; /* save away a copy of the client cert list that is presently valid */ l->client_certs = apr_array_copy_hdr(l->pool, st->client_certs); /* add the cleanup to the pool */ apr_pool_cleanup_register(l->pool, l, uldap_connection_cleanup, apr_pool_cleanup_null); if (p) { p->next = l; } else { st->connections = l; } }#if APR_HAS_THREADS apr_thread_mutex_unlock(st->mutex);#endif return l;}/* ------------------------------------------------------------------ *//* * Compares two DNs to see if they're equal. The only way to do this correctly * is to search for the dn and then do ldap_get_dn() on the result. This should * match the initial dn, since it would have been also retrieved with * ldap_get_dn(). This is expensive, so if the configuration value * compare_dn_on_server is false, just does an ordinary strcmp. * * The lock for the ldap cache should already be acquired. */static int uldap_cache_comparedn(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *dn, const char *reqdn, int compare_dn_on_server){ int result = 0; util_url_node_t *curl; util_url_node_t curnode; util_dn_compare_node_t *node; util_dn_compare_node_t newnode; int failures = 0; LDAPMessage *res, *entry; char *searchdn; util_ldap_state_t *st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config, &ldap_module); /* get cache entry (or create one) */ LDAP_CACHE_LOCK(); curnode.url = url; curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode); if (curl == NULL) { curl = util_ald_create_caches(st, url); } LDAP_CACHE_UNLOCK(); /* a simple compare? */ if (!compare_dn_on_server) { /* unlock this read lock */ if (strcmp(dn, reqdn)) { ldc->reason = "DN Comparison FALSE (direct strcmp())"; return LDAP_COMPARE_FALSE; } else { ldc->reason = "DN Comparison TRUE (direct strcmp())"; return LDAP_COMPARE_TRUE; } } if (curl) { /* no - it's a server side compare */ LDAP_CACHE_LOCK(); /* is it in the compare cache? */ newnode.reqdn = (char *)reqdn; node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode); if (node != NULL) { /* If it's in the cache, it's good */ /* unlock this read lock */ LDAP_CACHE_UNLOCK(); ldc->reason = "DN Comparison TRUE (cached)"; return LDAP_COMPARE_TRUE; } /* unlock this read lock */ LDAP_CACHE_UNLOCK(); }start_over: if (failures++ > 10) { /* too many failures */ return result; } /* make a server connection */ if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { /* connect to server failed */ return result; } /* search for reqdn */ result = ldap_search_ext_s(ldc->ldap, (char *)reqdn, LDAP_SCOPE_BASE, "(objectclass=*)", NULL, 1, NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &res); if (AP_LDAP_IS_SERVER_DOWN(result)) { ldc->reason = "DN Comparison ldap_search_ext_s() " "failed with server down"; uldap_connection_unbind(ldc); goto start_over; } if (result != LDAP_SUCCESS) { /* search for reqdn failed - no match */ ldc->reason = "DN Comparison ldap_search_ext_s() failed"; return result; } entry = ldap_first_entry(ldc->ldap, res); searchdn = ldap_get_dn(ldc->ldap, entry); ldap_msgfree(res); if (strcmp(dn, searchdn) != 0) { /* compare unsuccessful */ ldc->reason = "DN Comparison FALSE (checked on server)"; result = LDAP_COMPARE_FALSE; } else { if (curl) { /* compare successful - add to the compare cache */ LDAP_CACHE_LOCK(); newnode.reqdn = (char *)reqdn; newnode.dn = (char *)dn; node = util_ald_cache_fetch(curl->dn_compare_cache, &newnode); if ( (node == NULL) || (strcmp(reqdn, node->reqdn) != 0) || (strcmp(dn, node->dn) != 0)) { util_ald_cache_insert(curl->dn_compare_cache, &newnode); } LDAP_CACHE_UNLOCK(); } ldc->reason = "DN Comparison TRUE (checked on server)"; result = LDAP_COMPARE_TRUE; } ldap_memfree(searchdn); return result;}/* * Does an generic ldap_compare operation. It accepts a cache that it will use * to lookup the compare in the cache. We cache two kinds of compares * (require group compares) and (require user compares). Each compare has a different * cache node: require group includes the DN; require user does not because the * require user cache is owned by the * */static int uldap_cache_compare(request_rec *r, util_ldap_connection_t *ldc, const char *url, const char *dn, const char *attrib, const char *value){ int result = 0; util_url_node_t *curl; util_url_node_t curnode; util_compare_node_t *compare_nodep; util_compare_node_t the_compare_node; apr_time_t curtime = 0; /* silence gcc -Wall */ int failures = 0; util_ldap_state_t *st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config, &ldap_module); /* get cache entry (or create one) */ LDAP_CACHE_LOCK(); curnode.url = url; curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode); if (curl == NULL) { curl = util_ald_create_caches(st, url); } LDAP_CACHE_UNLOCK(); if (curl) { /* make a comparison to the cache */ LDAP_CACHE_LOCK(); curtime = apr_time_now(); the_compare_node.dn = (char *)dn; the_compare_node.attrib = (char *)attrib; the_compare_node.value = (char *)value; the_compare_node.result = 0; compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node); if (compare_nodep != NULL) { /* found it... */ if (curtime - compare_nodep->lastcompare > st->compare_cache_ttl) { /* ...but it is too old */ util_ald_cache_remove(curl->compare_cache, compare_nodep); } else { /* ...and it is good */ /* unlock this read lock */ LDAP_CACHE_UNLOCK(); if (LDAP_COMPARE_TRUE == compare_nodep->result) { ldc->reason = "Comparison true (cached)"; return compare_nodep->result; } else if (LDAP_COMPARE_FALSE == compare_nodep->result) { ldc->reason = "Comparison false (cached)"; return compare_nodep->result; } else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) { ldc->reason = "Comparison no such attribute (cached)"; return compare_nodep->result; } else { ldc->reason = "Comparison undefined (cached)"; return compare_nodep->result; } } } /* unlock this read lock */ LDAP_CACHE_UNLOCK(); }start_over: if (failures++ > 10) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -