diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2014-10-04 16:13:03 -0400 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2014-10-04 16:13:03 -0400 |
commit | c9618dfe442305531ee6cab9660333f4a697e094 (patch) | |
tree | 63da3cf1c107fdebd82987519b858f0d98c12d23 /nslcd/myldap.c | |
parent | be4588009b7106859e1beae6038aaea8d7f85825 (diff) |
foo
Diffstat (limited to 'nslcd/myldap.c')
-rw-r--r-- | nslcd/myldap.c | 432 |
1 files changed, 6 insertions, 426 deletions
diff --git a/nslcd/myldap.c b/nslcd/myldap.c index cf16dd6..095e8e6 100644 --- a/nslcd/myldap.c +++ b/nslcd/myldap.c @@ -1226,440 +1226,20 @@ void myldap_session_close(MYLDAP_SESSION *session) free(session); } -/* mutex for updating the times in the uri */ -pthread_mutex_t uris_mutex = PTHREAD_MUTEX_INITIALIZER; -static int do_retry_search(MYLDAP_SEARCH *search) -{ - int sleeptime = 0; - int start_uri; - time_t endtime; - time_t nexttry; - time_t t; - int rc = LDAP_UNAVAILABLE; - struct myldap_uri *current_uri; - int dotry[NSS_LDAP_CONFIG_MAX_URIS]; - int do_invalidate = 0; - /* clear time stamps */ - for (start_uri = 0; start_uri < NSS_LDAP_CONFIG_MAX_URIS; start_uri++) - dotry[start_uri] = 1; - /* keep trying until we time out */ - endtime = time(NULL) + nslcd_cfg->reconnect_retrytime; - while (1) - { - nexttry = endtime; - /* try each configured URL once */ - pthread_mutex_lock(&uris_mutex); - start_uri = search->session->current_uri; - do - { - current_uri = &(nslcd_cfg->uris[search->session->current_uri]); - /* only try this URI if we should */ - if (!dotry[search->session->current_uri]) - { /* skip this URI */ } - else if ((current_uri->lastfail > (current_uri->firstfail + nslcd_cfg->reconnect_retrytime)) && - ((t = time(NULL)) < (current_uri->lastfail + nslcd_cfg->reconnect_retrytime))) - { - /* we are in a hard fail state and have retried not long ago */ - log_log(LOG_DEBUG, "not retrying server %s which failed just %d second(s) ago and has been failing for %d seconds", - current_uri->uri, (int)(t - current_uri->lastfail), - (int)(t - current_uri->firstfail)); - dotry[search->session->current_uri] = 0; - } - else - { - /* try to start the search */ - pthread_mutex_unlock(&uris_mutex); - rc = do_try_search(search); - if (rc == LDAP_SUCCESS) - { - pthread_mutex_lock(&uris_mutex); - /* check if we are coming back from an error */ - if ((current_uri->lastfail > 0) || (search->session->current_uri != start_uri)) - { - log_log(LOG_INFO, "connected to LDAP server %s", current_uri->uri); - do_invalidate = 1; - } - if (first_search) - { - do_invalidate = 1; - first_search = 0; - } - /* update ok time */ - current_uri->firstfail = 0; - current_uri->lastfail = 0; - pthread_mutex_unlock(&uris_mutex); - /* flag the search as valid */ - search->valid = 1; - /* signal external invalidation of configured caches */ - if (do_invalidate) - invalidator_do(LM_NONE); - return LDAP_SUCCESS; - } - /* close the current connection */ - do_close(search->session); - /* update time of failure and figure out when we should retry */ - pthread_mutex_lock(&uris_mutex); - t = time(NULL); - /* update timestaps unless we are doing an authentication search */ - if (search->session->binddn[0] == '\0') - { - if (current_uri->firstfail == 0) - current_uri->firstfail = t; - current_uri->lastfail = t; - } - /* if it is one of these, retrying this URI is not going to help */ - if ((rc == LDAP_INVALID_CREDENTIALS) || (rc == LDAP_INSUFFICIENT_ACCESS) || - (rc == LDAP_AUTH_METHOD_NOT_SUPPORTED)) - dotry[search->session->current_uri] = 0; - /* check when we should try this URI again */ - else if (t <= (current_uri->firstfail + nslcd_cfg->reconnect_retrytime)) - { - t += nslcd_cfg->reconnect_sleeptime; - if (t < nexttry) - nexttry = t; - } - } - /* try the next URI (with wrap-around) */ - search->session->current_uri++; - if (nslcd_cfg->uris[search->session->current_uri].uri == NULL) - search->session->current_uri = 0; - } - while (search->session->current_uri != start_uri); - pthread_mutex_unlock(&uris_mutex); - /* see if it is any use sleeping */ - if (nexttry >= endtime) - { - if (search->session->binddn[0] == '\0') - myldap_err(LOG_ERR, search->session->ld, rc, "no available LDAP server found"); - return rc; - } - /* sleep between tries */ - sleeptime = nexttry - time(NULL); - if (sleeptime > 0) - { - log_log(LOG_WARNING, "no available LDAP server found, sleeping %d seconds", - sleeptime); - (void)sleep(sleeptime); - } - } -} - -/* force quick retries of all failing LDAP servers */ -void myldap_immediate_reconnect(void) -{ - int i; - time_t t; - t = time(NULL) - nslcd_cfg->reconnect_retrytime; - pthread_mutex_lock(&uris_mutex); - for (i = 0; i < (NSS_LDAP_CONFIG_MAX_URIS + 1); i++) - { - /* only adjust failing connections that are in a hard fail state */ - if ((nslcd_cfg->uris[i].lastfail > t) && - (nslcd_cfg->uris[i].lastfail > (nslcd_cfg->uris[i].firstfail + nslcd_cfg->reconnect_retrytime))) - { - /* move lastfail back to ensure quick retry */ - log_log(LOG_DEBUG, "moving lastfail of %s %d second(s) back to force retry", - nslcd_cfg->uris[i].uri, (int)(nslcd_cfg->uris[i].lastfail - t)); - nslcd_cfg->uris[i].lastfail = t; - } - } - pthread_mutex_unlock(&uris_mutex); -} - -MYLDAP_SEARCH *myldap_search(MYLDAP_SESSION *session, - const char *base, int scope, const char *filter, - const char **attrs, int *rcp) +void myldap_search_close(MYLDAP_SEARCH *search) { - MYLDAP_SEARCH *search; - int i; - int rc; - /* check parameters */ - if ((session == NULL) || (base == NULL) || (filter == NULL) || (attrs == NULL)) - { - log_log(LOG_ERR, "myldap_search(): invalid parameter passed"); - errno = EINVAL; - if (rcp != NULL) - *rcp = LDAP_OPERATIONS_ERROR; - return NULL; - } - /* log the call */ - log_log(LOG_DEBUG, "myldap_search(base=\"%s\", filter=\"%s\")", - base, filter); - /* check if the idle time for the connection has expired */ - myldap_session_check(session); - /* allocate a new search entry */ - search = myldap_search_new(session, base, scope, filter, attrs); - /* find a place in the session where we can register our search */ - for (i = 0; (session->searches[i] != NULL) && (i < MAX_SEARCHES_IN_SESSION); i++) - /* nothing */ ; - if (i >= MAX_SEARCHES_IN_SESSION) - { - log_log(LOG_ERR, "myldap_search(): too many searches registered with session (max %d)", - MAX_SEARCHES_IN_SESSION); - myldap_search_close(search); - if (rcp != NULL) - *rcp = LDAP_OPERATIONS_ERROR; - return NULL; - } - /* register search with the session so we can free it later on */ - session->searches[i] = search; - /* do the search with retries to all configured servers */ - rc = do_retry_search(search); - if (rc != LDAP_SUCCESS) - { - myldap_search_close(search); - if (rcp != NULL) - *rcp = rc; - return NULL; - } - if (rcp != NULL) - *rcp = LDAP_SUCCESS; - return search; + search->close(search); } -void myldap_search_close(MYLDAP_SEARCH *search) -{ - int i; - if (search == NULL) - return; - /* free any messages */ - if (search->msg != NULL) - { - ldap_msgfree(search->msg); - search->msg = NULL; - } - /* abandon the search if there were more results to fetch */ - if ((search->session->ld != NULL) && (search->msgid != -1)) - { - ldap_abandon(search->session->ld, search->msgid); - search->msgid = -1; - } - /* find the reference to this search in the session */ - for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++) - { - if (search->session->searches[i] == search) - search->session->searches[i] = NULL; - } - /* free any search entries */ - if (search->entry != NULL) - myldap_entry_free(search->entry); - /* clean up cookie */ - if (search->cookie != NULL) - ber_bvfree(search->cookie); - /* free read messages */ - if (search->msg != NULL) - ldap_msgfree(search->msg); - /* free the storage we allocated */ - free(search); +struct myldap_search { + MYLDAP_ENTRY *(*get_entry)(void *data, int *rcp); + void *data; } MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search, int *rcp) { - int rc; - int parserc; - struct timeval tv, *tvp; - LDAPControl **resultcontrols; - ber_int_t count; - /* check parameters */ - if ((search == NULL) || (search->session == NULL) || (search->session->ld == NULL)) - { - log_log(LOG_ERR, "myldap_get_entry(): invalid search passed"); - errno = EINVAL; - if (rcp != NULL) - *rcp = LDAP_OPERATIONS_ERROR; - return NULL; - } - /* check if the connection wasn't closed in another search */ - if (!search->valid) - { - log_log(LOG_WARNING, "myldap_get_entry(): connection was closed"); - /* retry the search */ - if (search->may_retry_search) - { - log_log(LOG_DEBUG, "myldap_get_entry(): retry search"); - search->may_retry_search = 0; - if (do_retry_search(search) == LDAP_SUCCESS) - return myldap_get_entry(search, rcp); - } - myldap_search_close(search); - if (rcp != NULL) - *rcp = LDAP_SERVER_DOWN; - return NULL; - } - /* set up a timelimit value for operations */ - if (nslcd_cfg->timelimit == LDAP_NO_LIMIT) - tvp = NULL; - else - { - tv.tv_sec = nslcd_cfg->timelimit; - tv.tv_usec = 0; - tvp = &tv; - } - /* if we have an existing result entry, free it */ - if (search->entry != NULL) - { - myldap_entry_free(search->entry); - search->entry = NULL; - } - /* try to parse results until we have a final error or ok */ - while (1) - { - /* free the previous message if there was any */ - if (search->msg != NULL) - { - ldap_msgfree(search->msg); - search->msg = NULL; - } - /* get the next result */ - rc = ldap_result(search->session->ld, search->msgid, LDAP_MSG_ONE, tvp, - &(search->msg)); - /* handle result */ - switch (rc) - { - case LDAP_RES_SEARCH_ENTRY: - /* we have a normal search entry, update timestamp and return result */ - time(&(search->session->lastactivity)); - search->entry = myldap_entry_new(search); - if (rcp != NULL) - *rcp = LDAP_SUCCESS; - /* log the first couple of dns in the result (but not all, to - prevent swamping the log) */ - if (search->count < MAX_DEBUG_LOG_DNS) - log_log(LOG_DEBUG, "ldap_result(): %s", myldap_get_dn(search->entry)); - search->count++; - search->may_retry_search = 0; - return search->entry; - case LDAP_RES_SEARCH_RESULT: - /* we have a search result, parse it */ - resultcontrols = NULL; - if (search->cookie != NULL) - { - ber_bvfree(search->cookie); - search->cookie = NULL; - } - /* NB: this frees search->msg */ - parserc = ldap_parse_result(search->session->ld, search->msg, &rc, - NULL, NULL, NULL, &resultcontrols, 1); - search->msg = NULL; - /* check for errors during parsing */ - if ((parserc != LDAP_SUCCESS) && (parserc != LDAP_MORE_RESULTS_TO_RETURN)) - { - if (resultcontrols != NULL) - ldap_controls_free(resultcontrols); - myldap_err(LOG_ERR, search->session->ld, parserc, "ldap_parse_result() failed"); - myldap_search_close(search); - if (rcp != NULL) - *rcp = parserc; - return NULL; - } - /* check for errors in message */ - if ((rc != LDAP_SUCCESS) && (rc != LDAP_MORE_RESULTS_TO_RETURN)) - { - if (resultcontrols != NULL) - ldap_controls_free(resultcontrols); - myldap_err(LOG_ERR, search->session->ld, rc, "ldap_result() failed"); - /* close connection on connection problems */ - if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN)) - do_close(search->session); - myldap_search_close(search); - if (rcp != NULL) - *rcp = rc; - return NULL; - } - /* handle result controls */ - if (resultcontrols != NULL) - { - /* see if there are any more pages to come */ - rc = ldap_parse_page_control(search->session->ld, resultcontrols, - &count, &(search->cookie)); - if (rc != LDAP_SUCCESS) - { - if (rc != LDAP_CONTROL_NOT_FOUND) - myldap_err(LOG_WARNING, search->session->ld, rc, "ldap_parse_page_control() failed"); - /* clear error flag */ - rc = LDAP_SUCCESS; - if (ldap_set_option(search->session->ld, LDAP_OPT_ERROR_NUMBER, - &rc) != LDAP_SUCCESS) - log_log(LOG_WARNING, "failed to clear the error flag"); - } - /* TODO: handle the above return code?? */ - ldap_controls_free(resultcontrols); - } - search->msgid = -1; - /* check if there are more pages to come */ - if ((search->cookie == NULL) || (search->cookie->bv_len == 0)) - { - if (search->count > MAX_DEBUG_LOG_DNS) - log_log(LOG_DEBUG, "ldap_result(): ... %d more results", - search->count - MAX_DEBUG_LOG_DNS); - log_log(LOG_DEBUG, "ldap_result(): end of results (%d total)", - search->count); - /* we are at the end of the search, no more results */ - myldap_search_close(search); - if (rcp != NULL) - *rcp = LDAP_SUCCESS; - return NULL; - } - /* try the next page */ - rc = do_try_search(search); - if (rc != LDAP_SUCCESS) - { - /* close connection on connection problems */ - if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN)) - do_close(search->session); - myldap_search_close(search); - if (rcp != NULL) - *rcp = rc; - return NULL; - } - /* we continue with another pass */ - break; - case LDAP_RES_SEARCH_REFERENCE: - break; /* just ignore search references */ - default: - /* we have some error condition, find out which */ - switch (rc) - { - case -1: - /* try to get error code */ - if (ldap_get_option(search->session->ld, LDAP_OPT_ERROR_NUMBER, - &rc) != LDAP_SUCCESS) - rc = LDAP_UNAVAILABLE; - myldap_err(LOG_ERR, search->session->ld, rc, "ldap_result() failed"); - break; - case 0: - /* the timeout expired */ - log_log(LOG_ERR, "ldap_result() timed out"); - rc = LDAP_TIMELIMIT_EXCEEDED; - break; - default: - /* unknown code */ - log_log(LOG_WARNING, "ldap_result() returned unexpected result type"); - rc = LDAP_PROTOCOL_ERROR; - } - /* close connection on some connection problems */ - if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN) || - (rc == LDAP_SUCCESS) || (rc == LDAP_TIMELIMIT_EXCEEDED) || - (rc == LDAP_OPERATIONS_ERROR) || (rc == LDAP_PROTOCOL_ERROR)) - { - do_close(search->session); - /* retry once if no data has been received yet */ - if (search->may_retry_search) - { - log_log(LOG_DEBUG, "myldap_get_entry(): retry search"); - search->may_retry_search = 0; - if (do_retry_search(search) == LDAP_SUCCESS) - return myldap_get_entry(search, rcp); - } - } - /* close search */ - myldap_search_close(search); - if (rcp != NULL) - *rcp = rc; - return NULL; - } - } + return search->get_entry(search->data, rcp); } /* Get the DN from the entry. This function only returns NULL (and sets |