diff options
author | chinlong <none@none> | 2007-04-16 15:36:28 -0700 |
---|---|---|
committer | chinlong <none@none> | 2007-04-16 15:36:28 -0700 |
commit | a1e4879402b1a0a7c410577cff81f1ce31ace7af (patch) | |
tree | 28d1b9d7317cffd21f75358a3fdffa2a5268ae7d /usr/src/lib/libsldap/common/ns_connect.c | |
parent | a4070553c99750001687496365405ce3c957c521 (diff) | |
download | illumos-gate-a1e4879402b1a0a7c410577cff81f1ce31ace7af.tar.gz |
6496719 connections should fall back to primary server after it comes back
6526896 Native LDAP authentication broken on snv_58
6543897 nscd deadlock after timeshift, not working failover
6545671 Some syslog messages in ns_sasl.c need prefix "libsldap: "
Diffstat (limited to 'usr/src/lib/libsldap/common/ns_connect.c')
-rw-r--r-- | usr/src/lib/libsldap/common/ns_connect.c | 210 |
1 files changed, 204 insertions, 6 deletions
diff --git a/usr/src/lib/libsldap/common/ns_connect.c b/usr/src/lib/libsldap/common/ns_connect.c index 0c221d6215..b2f3fda6f1 100644 --- a/usr/src/lib/libsldap/common/ns_connect.c +++ b/usr/src/lib/libsldap/common/ns_connect.c @@ -55,6 +55,8 @@ extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip); static int openConnection(LDAP **, const char *, const ns_cred_t *, int, ns_ldap_error_t **, int, int); +static void +_DropConnection(ConnectionID cID, int flag, int fini); /* * sessionLock, wait4session, sessionTid * are variables to synchronize the creation/retrieval of a connection. @@ -859,9 +861,13 @@ findConnection(int flags, const char *serverAddr, const ns_cred_t *auth, Connection **conp) { Connection *cp; - int i; + int i, j, conn_server_index, up_server_index, drop_conn; int rc; int try; + ns_server_info_t sinfo; + ns_ldap_error_t *errorp = NULL; + char **servers, *addrType; + void **paramVal = NULL; #ifdef DEBUG thread_t t = thr_self(); #endif /* DEBUG */ @@ -882,7 +888,7 @@ findConnection(int flags, const char *serverAddr, t, serverAddr); else (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t); - printCred(stderr, auth); + printCred(LOG_DEBUG, auth); fflush(stderr); #endif /* DEBUG */ @@ -954,7 +960,7 @@ findConnection(int flags, const char *serverAddr, #ifdef DEBUG (void) fprintf(stderr, "tid= %d: checking connection " "[%d] ....\n", t, i); - printConnection(stderr, cp); + printConnection(LOG_DEBUG, cp); #endif /* DEBUG */ if ((cp->usedBit) || (cp->notAvail) || (cp->auth->auth.type != auth->auth.type) || @@ -975,6 +981,198 @@ findConnection(int flags, const char *serverAddr, ((strcmp(cp->auth->cred.unix_cred.passwd, auth->cred.unix_cred.passwd) != 0)))) continue; + if (!(serverAddr && *serverAddr)) { + /* + * Get preferred server list. + * When preferred servers are merged with default + * servers (S_LDAP_SERVER_P) by __s_api_getServer, + * preferred servers are copied sequencially. + * The order should be the same as the order retrieved + * by __ns_ldap_getParam. + */ + if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P, + ¶mVal, &errorp)) != NS_LDAP_SUCCESS) { + (void) __ns_ldap_freeError(&errorp); + (void) __ns_ldap_freeParam(¶mVal); + (void) rw_unlock(&sessionPoolLock); + return (-1); + } + servers = (char **)paramVal; + /* + * Do fallback only if preferred servers are defined. + */ + if (servers != NULL) { + if (cp->auth->auth.saslmech == + NS_LDAP_SASL_GSSAPI) + addrType = NS_CACHE_ADDR_HOSTNAME; + else + addrType = NS_CACHE_ADDR_IP; + /* + * Find the 1st available server + */ + rc = __s_api_requestServer(NS_CACHE_NEW, NULL, + &sinfo, &errorp, addrType); + if (rc != NS_LDAP_SUCCESS) { + /* + * Drop the connection. + * Pass 1 to fini so it won't be locked + * inside _DropConnection + */ + _DropConnection( + cp->connectionId, + NS_LDAP_NEW_CONN, 1); + (void) rw_unlock( + &sessionPoolLock); + (void) __ns_ldap_freeParam( + (void ***)&servers); + return (-1); + } + + if (sinfo.server) { + /* + * Test if cp->serverAddr is a + * preferred server. + */ + conn_server_index = -1; + for (j = 0; servers[j] != NULL; j++) { + if (strcasecmp(servers[j], + cp->serverAddr) == 0) { + conn_server_index = j; + break; + } + } + /* + * Test if sinfo.server is a preferred + * server. + */ + up_server_index = -1; + for (j = 0; servers[j] != NULL; j++) { + if (strcasecmp(sinfo.server, + servers[j]) == 0) { + up_server_index = j; + break; + } + } + + /* + * The following code is to fall back + * to preferred servers if servers + * are previously down but are up now. + * If cp->serverAddr is a preferred + * server, it falls back to the servers + * ahead of it. If cp->serverAddr is + * not a preferred server, it falls + * back to any of preferred servers + * returned by ldap_cachemgr. + */ + if (conn_server_index >= 0 && + up_server_index >= 0) { + /* + * cp->serverAddr and + * sinfo.server are preferred + * servers. + */ + if (up_server_index == + conn_server_index) + /* + * sinfo.server is the + * same as + * cp->serverAddr. + * Keep the connection. + */ + drop_conn = 0; + else + /* + * 1. + * up_server_index < + * conn_server_index + * + * sinfo is ahead of + * cp->serverAddr in + * Need to fall back. + * 2. + * up_server_index > + * conn_server_index + * cp->serverAddr is + * down. Drop it. + */ + drop_conn = 1; + } else if (conn_server_index >= 0 && + up_server_index == -1) { + /* + * cp->serverAddr is a preferred + * server but sinfo.server is + * not. Preferred servers are + * ahead of default servers. + * This means cp->serverAddr is + * down. Drop it. + */ + drop_conn = 1; + } else if (conn_server_index == -1 && + up_server_index >= 0) { + /* + * cp->serverAddr is not a + * preferred server but + * sinfo.server is. + * Fall back. + */ + drop_conn = 1; + } else { + /* + * Both index are -1 + * cp->serverAddr and + * sinfo.server are not + * preferred servers. + * No fallback. + */ + drop_conn = 0; + } + if (drop_conn) { + /* + * Drop the connection so the + * new conection can fall back + * to a new server later. + * Pass 1 to fini so it won't + * be locked inside + * _DropConnection + */ + _DropConnection( + cp->connectionId, + NS_LDAP_NEW_CONN, 1); + (void) rw_unlock( + &sessionPoolLock); + (void) __ns_ldap_freeParam( + (void ***)&servers); + free(sinfo.server); + __s_api_free2dArray( + sinfo.saslMechanisms); + __s_api_free2dArray( + sinfo.controls); + return (-1); + } else { + /* + * Keep the connection + */ + (void) __ns_ldap_freeParam( + (void ***)&servers); + free(sinfo.server); + __s_api_free2dArray( + sinfo.saslMechanisms); + __s_api_free2dArray( + sinfo.controls); + } + } else { + (void) rw_unlock(&sessionPoolLock); + syslog(LOG_WARNING, "libsldap: Null " + "sinfo.server from " + "__s_api_requestServer"); + (void) __ns_ldap_freeParam( + (void ***)&servers); + return (-1); + } + } + } + /* found an available connection */ if (MTperConn == 0) cp->usedBit = B_TRUE; @@ -1132,7 +1330,8 @@ makeConnection(Connection **conp, const char *serverAddr, sinfo.controls = NULL; sinfo.saslMechanisms = NULL; - if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) { + if ((wait4session == 0 || sessionTid != thr_self()) && + (id = findConnection(flags, serverAddr, auth, &con)) != -1) { /* connection found in cache */ #ifdef DEBUG (void) fprintf(stderr, "tid= %d: connection found in " @@ -1417,8 +1616,7 @@ _DropConnection(ConnectionID cID, int flag, int fini) cp = sessionPool[id]; /* sanity check before removing */ - if (!cp || (!fini && !cp->shared && (!cp->usedBit || - cp->threadID != thr_self()))) { + if (!cp || (!fini && !cp->shared && !cp->usedBit)) { #ifdef DEBUG if (cp == NULL) (void) fprintf(stderr, "tid= %d: no " |