xref: /titanic_50/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c (revision 567cc2e6a4ceb0e421e1cf9bead0f43c55603d27)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <assert.h>
29 #include <errno.h>
30 #include <memory.h>
31 #include <signal.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <libintl.h>
36 #include <syslog.h>
37 #include <sys/door.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <synch.h>
43 #include <pthread.h>
44 #include <unistd.h>
45 #include <lber.h>
46 #include <ldap.h>
47 #include <ctype.h>	/* tolower */
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include "cachemgr.h"
52 #include "solaris-priv.h"
53 
54 static rwlock_t	ldap_lock = DEFAULTRWLOCK;
55 static int	sighup_update = FALSE;
56 extern admin_t	current_admin;
57 
58 /* variables used for SIGHUP wakeup on sleep */
59 static mutex_t			sighuplock;
60 static cond_t			cond;
61 
62 /* refresh time statistics */
63 static time_t	prev_refresh_time = 0;
64 
65 /* variables used for signaling parent process */
66 static mutex_t	sig_mutex;
67 static int	signal_done = FALSE;
68 
69 /* TCP connection timeout (in milliseconds) */
70 static int tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
71 /* search timeout (in seconds) */
72 static int search_timeout = NS_DEFAULT_SEARCH_TIMEOUT;
73 
74 #ifdef SLP
75 extern int	use_slp;
76 #endif /* SLP */
77 
78 /* nis domain information */
79 #define	_NIS_FILTER		"objectclass=nisDomainObject"
80 #define	_NIS_DOMAIN		"nisdomain"
81 
82 #define	CACHESLEEPTIME		600
83 /*
84  * server list refresh delay when in "no server" mode
85  * (1 second)
86  */
87 #define	REFRESH_DELAY_WHEN_NO_SERVER	1
88 
89 typedef enum {
90 	INFO_OP_CREATE		= 0,
91 	INFO_OP_DELETE		= 1,
92 	INFO_OP_REFRESH		= 2,
93 	INFO_OP_REFRESH_WAIT	= 3,
94 	INFO_OP_GETSERVER	= 4,
95 	INFO_OP_GETSTAT		= 5
96 } info_op_t;
97 
98 typedef enum {
99 	INFO_RW_UNKNOWN		= 0,
100 	INFO_RW_READONLY	= 1,
101 	INFO_RW_WRITEABLE	= 2
102 } info_rw_t;
103 
104 typedef enum {
105 	INFO_SERVER_JUST_INITED	= -1,
106 	INFO_SERVER_UNKNOWN	= 0,
107 	INFO_SERVER_CONNECTING	= 1,
108 	INFO_SERVER_UP		= 2,
109 	INFO_SERVER_ERROR 	= 3,
110 	INFO_SERVER_REMOVED	= 4
111 } info_server_t;
112 
113 typedef enum {
114 	INFO_STATUS_UNKNOWN	= 0,
115 	INFO_STATUS_ERROR 	= 1,
116 	INFO_STATUS_NEW   	= 2,
117 	INFO_STATUS_OLD		= 3
118 } info_status_t;
119 
120 typedef enum {
121 	CACHE_OP_CREATE		= 0,
122 	CACHE_OP_DELETE		= 1,
123 	CACHE_OP_FIND		= 2,
124 	CACHE_OP_ADD		= 3,
125 	CACHE_OP_GETSTAT	= 4
126 } cache_op_t;
127 
128 typedef enum {
129 	CACHE_MAP_UNKNOWN	= 0,
130 	CACHE_MAP_DN2DOMAIN	= 1
131 } cache_type_t;
132 
133 typedef struct server_info_ext {
134 	char			*addr;
135 	char			*hostname;
136 	char			*rootDSE_data;
137 	char			*errormsg;
138 	info_rw_t		type;
139 	info_server_t		server_status;
140 	info_server_t		prev_server_status;
141 	info_status_t 		info_status;
142 } server_info_ext_t;
143 
144 typedef struct server_info {
145 	struct server_info 	*next;
146 	mutex_t			mutex[2];	/* 0: current copy lock */
147 						/* 1: update copy lock */
148 	server_info_ext_t	sinfo[2]; /* 0: current, 1:  update copy */
149 } server_info_t;
150 
151 typedef struct cache_hash {
152 	cache_type_t		type;
153 	char			*from;
154 	char			*to;
155 	struct cache_hash	*next;
156 } cache_hash_t;
157 
158 static int getldap_destroy_serverInfo(server_info_t *head);
159 
160 /*
161  * Load configuration
162  * The code was in signal handler getldap_revalidate
163  * It's moved out of the handler because it could cause deadlock
164  * return: 1 SUCCESS
165  *         0 FAIL
166  */
167 static int
168 load_config() {
169 	ns_ldap_error_t *error;
170 	int		rc = 1;
171 
172 	(void) __ns_ldap_setServer(TRUE);
173 
174 	(void) rw_wrlock(&ldap_lock);
175 	if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
176 		logit("Error: Unable to read '%s': %s\n",
177 			NSCONFIGFILE, error->message);
178 		__ns_ldap_freeError(&error);
179 		rc = 0; /* FAIL */
180 	} else
181 		sighup_update = TRUE;
182 
183 	(void) rw_unlock(&ldap_lock);
184 
185 	return (rc);
186 }
187 
188 /*
189  * Calculate a hash for a string
190  * Based on elf_hash algorithm, hash is case insensitive
191  * Uses tolower instead of _tolower because of I18N
192  */
193 
194 static unsigned long
195 getldap_hash(const char *str)
196 {
197 	unsigned int	hval = 0;
198 
199 	while (*str) {
200 		unsigned int	g;
201 
202 		hval = (hval << 4) + tolower(*str++);
203 		if ((g = (hval & 0xf0000000)) != 0)
204 			hval ^= g >> 24;
205 		hval &= ~g;
206 	}
207 	return ((unsigned long)hval);
208 }
209 
210 /*
211  * Remove a hash table entry.
212  * This function expects a lock in place when called.
213  */
214 
215 static cache_hash_t *
216 getldap_free_hash(cache_hash_t *p)
217 {
218 	cache_hash_t	*next;
219 
220 	p->type = CACHE_MAP_UNKNOWN;
221 	if (p->from)
222 		free(p->from);
223 	if (p->to)
224 		free(p->to);
225 	next = p->next;
226 	p->next = NULL;
227 	free(p);
228 	return (next);
229 }
230 
231 /*
232  * Scan a hash table hit for a matching hash entry.
233  * This function expects a lock in place when called.
234  */
235 static cache_hash_t *
236 getldap_scan_hash(cache_type_t type, char *from,
237 		cache_hash_t *idx)
238 {
239 	while (idx) {
240 		if (idx->type == type &&
241 		    strcasecmp(from, idx->from) == 0) {
242 			return (idx);
243 		}
244 		idx = idx->next;
245 	}
246 	return ((cache_hash_t *)NULL);
247 }
248 
249 /*
250  * Format and return the cache data statistics
251  */
252 static int
253 getldap_get_cacheData_stat(int max, int current, char **output)
254 {
255 #define	C_HEADER0	"Cache data information: "
256 #define	C_HEADER1	"  Maximum cache entries:   "
257 #define	C_HEADER2	"  Number of cache entries: "
258 	int		hdr0_len = strlen(gettext(C_HEADER0));
259 	int		hdr1_len = strlen(gettext(C_HEADER1));
260 	int		hdr2_len = strlen(gettext(C_HEADER2));
261 	int		len;
262 
263 	if (current_admin.debug_level >= DBG_ALL) {
264 		logit("getldap_get_cacheData_stat()...\n");
265 	}
266 
267 	*output = NULL;
268 
269 	len = hdr0_len + hdr1_len + hdr2_len +
270 	    3 * strlen(DOORLINESEP) + 21;
271 	*output = malloc(len);
272 	if (*output == NULL)
273 		return (-1);
274 
275 	(void) snprintf(*output, len, "%s%s%s%10d%s%s%10d%s",
276 	    gettext(C_HEADER0), DOORLINESEP,
277 	    gettext(C_HEADER1), max, DOORLINESEP,
278 	    gettext(C_HEADER2), current, DOORLINESEP);
279 
280 	return (NS_LDAP_SUCCESS);
281 }
282 
283 static int
284 getldap_cache_op(cache_op_t op, cache_type_t type,
285 			char *from, char **to)
286 {
287 #define	CACHE_HASH_MAX		257
288 #define	CACHE_HASH_MAX_ENTRY	256
289 	static cache_hash_t	*hashTbl[CACHE_HASH_MAX];
290 	cache_hash_t		*next, *idx, *newp;
291 	unsigned long		hash;
292 	static rwlock_t 	cache_lock = DEFAULTRWLOCK;
293 	int 			i;
294 	static int		entry_num = 0;
295 
296 	if (current_admin.debug_level >= DBG_ALL) {
297 		logit("getldap_cache_op()...\n");
298 	}
299 	switch (op) {
300 	case CACHE_OP_CREATE:
301 		if (current_admin.debug_level >= DBG_ALL) {
302 			logit("operation is CACHE_OP_CREATE...\n");
303 		}
304 		(void) rw_wrlock(&cache_lock);
305 
306 		for (i = 0; i < CACHE_HASH_MAX; i++) {
307 			hashTbl[i] = NULL;
308 		}
309 		entry_num = 0;
310 
311 		(void) rw_unlock(&cache_lock);
312 		break;
313 
314 	case CACHE_OP_DELETE:
315 		if (current_admin.debug_level >= DBG_ALL) {
316 			logit("operation is CACHE_OP_DELETE...\n");
317 		}
318 		(void) rw_wrlock(&cache_lock);
319 
320 		for (i = 0; i < CACHE_HASH_MAX; i++) {
321 			next = hashTbl[i];
322 			while (next != NULL) {
323 				next = getldap_free_hash(next);
324 			}
325 			hashTbl[i] = NULL;
326 		}
327 		entry_num = 0;
328 
329 		(void) rw_unlock(&cache_lock);
330 		break;
331 
332 	case CACHE_OP_ADD:
333 		if (current_admin.debug_level >= DBG_ALL) {
334 			logit("operation is CACHE_OP_ADD...\n");
335 		}
336 		if (from == NULL || to == NULL || *to == NULL)
337 			return (-1);
338 		hash = getldap_hash(from) % CACHE_HASH_MAX;
339 		(void) rw_wrlock(&cache_lock);
340 		idx = hashTbl[hash];
341 		/*
342 		 * replace old "to" value with new one
343 		 * if an entry with same "from"
344 		 * already exists
345 		 */
346 		if (idx) {
347 			newp = getldap_scan_hash(type, from, idx);
348 			if (newp) {
349 				free(newp->to);
350 				newp->to = strdup(*to);
351 				(void) rw_unlock(&cache_lock);
352 				return (NS_LDAP_SUCCESS);
353 			}
354 		}
355 
356 		if (entry_num > CACHE_HASH_MAX_ENTRY) {
357 			(void) rw_unlock(&cache_lock);
358 			return (-1);
359 		}
360 
361 		newp = (cache_hash_t *)malloc(sizeof (cache_hash_t));
362 		if (newp == NULL) {
363 			(void) rw_unlock(&cache_lock);
364 			return (NS_LDAP_MEMORY);
365 		}
366 		newp->type = type;
367 		newp->from = strdup(from);
368 		newp->to = strdup(*to);
369 		newp->next = idx;
370 		hashTbl[hash] = newp;
371 		entry_num++;
372 		(void) rw_unlock(&cache_lock);
373 		break;
374 
375 	case CACHE_OP_FIND:
376 		if (current_admin.debug_level >= DBG_ALL) {
377 			logit("operation is CACHE_OP_FIND...\n");
378 		}
379 		if (from == NULL || to == NULL)
380 			return (-1);
381 		*to = NULL;
382 		hash = getldap_hash(from) % CACHE_HASH_MAX;
383 		(void) rw_rdlock(&cache_lock);
384 		idx = hashTbl[hash];
385 		idx = getldap_scan_hash(type, from, idx);
386 		if (idx)
387 			*to = strdup(idx->to);
388 		(void) rw_unlock(&cache_lock);
389 		if (idx == NULL)
390 			return (-1);
391 		break;
392 
393 	case CACHE_OP_GETSTAT:
394 		if (current_admin.debug_level >= DBG_ALL) {
395 			logit("operation is CACHE_OP_GETSTAT...\n");
396 		}
397 		if (to == NULL)
398 			return (-1);
399 
400 		return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY,
401 		    entry_num, to));
402 		break;
403 
404 	default:
405 		logit("getldap_cache_op(): "
406 		    "invalid operation code (%d).\n", op);
407 		return (-1);
408 		break;
409 	}
410 	return (NS_LDAP_SUCCESS);
411 }
412 /*
413  * Function: sync_current_with_update_copy
414  *
415  * This function syncs up the 2 sinfo copies in info.
416  *
417  * The 2 copies are identical most of time.
418  * The update copy(sinfo[1]) could be different when
419  * getldap_serverInfo_refresh thread is refreshing the server list
420  * and calls getldap_get_rootDSE to update info.  getldap_get_rootDSE
421  * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
422  * The calling sequence is
423  *  getldap_serverInfo_refresh->
424  *  getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
425  *  getldap_set_serverInfo->
426  *  getldap_get_rootDSE
427  *
428  * The original server_info_t has one copy of server info. When libsldap
429  * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
430  * is updating the server info, it would hit a unprotected window in
431  * getldap_rootDSE. The door call  will not get server info and libsldap
432  * fails at making ldap connection.
433  *
434  * The new server_info_t provides GETLDAPSERVER thread with a current
435  * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
436  * and syncs up 2 copies before thr_exit. This will close the window in
437  * getldap_get_rootDSE.
438  *
439  */
440 static void
441 sync_current_with_update_copy(server_info_t *info)
442 {
443 	if (current_admin.debug_level >= DBG_ALL) {
444 		logit("sync_current_with_update_copy()...\n");
445 	}
446 
447 	(void) mutex_lock(&info->mutex[1]);
448 	(void) mutex_lock(&info->mutex[0]);
449 
450 	/* free memory in current copy first */
451 	if (info->sinfo[0].addr)
452 		free(info->sinfo[0].addr);
453 	info->sinfo[0].addr = NULL;
454 
455 	if (info->sinfo[0].hostname)
456 		free(info->sinfo[0].hostname);
457 	info->sinfo[0].hostname = NULL;
458 
459 	if (info->sinfo[0].rootDSE_data)
460 		free(info->sinfo[0].rootDSE_data);
461 	info->sinfo[0].rootDSE_data = NULL;
462 
463 	if (info->sinfo[0].errormsg)
464 		free(info->sinfo[0].errormsg);
465 	info->sinfo[0].errormsg = NULL;
466 
467 	/*
468 	 * make current and update copy identical
469 	 */
470 	info->sinfo[0] = info->sinfo[1];
471 
472 	/*
473 	 * getldap_get_server_stat() reads the update copy sinfo[1]
474 	 * so it can't be freed or nullified yet at this point.
475 	 *
476 	 * The sinfo[0] and sinfo[1] have identical string pointers.
477 	 * strdup the strings to avoid the double free problem.
478 	 * The strings of sinfo[1] are freed in
479 	 * getldap_get_rootDSE() and the strings of sinfo[0]
480 	 * are freed earlier in this function. If the pointers are the
481 	 * same, they will be freed twice.
482 	 */
483 	if (info->sinfo[1].addr)
484 		info->sinfo[0].addr = strdup(info->sinfo[1].addr);
485 	if (info->sinfo[1].hostname)
486 		info->sinfo[0].hostname = strdup(info->sinfo[1].hostname);
487 	if (info->sinfo[1].rootDSE_data)
488 		info->sinfo[0].rootDSE_data =
489 		    strdup(info->sinfo[1].rootDSE_data);
490 	if (info->sinfo[1].errormsg)
491 		info->sinfo[0].errormsg = strdup(info->sinfo[1].errormsg);
492 
493 	(void) mutex_unlock(&info->mutex[0]);
494 	(void) mutex_unlock(&info->mutex[1]);
495 
496 }
497 
498 static void *
499 getldap_get_rootDSE(void *arg)
500 {
501 	server_info_t	*serverInfo = (server_info_t *)arg;
502 	int 		ldapVersion = LDAP_VERSION3;
503 	LDAP		*ld;
504 	LDAPMessage	*resultMsg = NULL;
505 	LDAPMessage	*e;
506 	BerElement	*ber;
507 	char		errmsg[MAXERROR];
508 	char		*rootDSE;
509 	char		*attrs[3];
510 	char		*a;
511 	char		**vals;
512 	int		ldaperrno = 0;
513 	int		rc = 0, exitrc = NS_LDAP_SUCCESS;
514 	int		i = 0, len = 0;
515 	pid_t		ppid;
516 	struct timeval	tv;
517 	int		server_found = 0;
518 
519 	if (current_admin.debug_level >= DBG_ALL) {
520 		logit("getldap_get_rootDSE()....\n");
521 	}
522 
523 	/* initialize the server info element */
524 	(void) mutex_lock(&serverInfo->mutex[1]);
525 	serverInfo->sinfo[1].type	= INFO_RW_UNKNOWN;
526 	serverInfo->sinfo[1].info_status =
527 	    INFO_STATUS_UNKNOWN;
528 	/*
529 	 * When the sever list is refreshed over and over,
530 	 * this function is called each time it is refreshed.
531 	 * The previous server status of the update copy(sinfo[1])
532 	 * is the status of the current copy
533 	 */
534 	(void) mutex_lock(&serverInfo->mutex[0]);
535 	serverInfo->sinfo[1].prev_server_status =
536 	    serverInfo->sinfo[0].server_status;
537 	(void) mutex_unlock(&serverInfo->mutex[0]);
538 
539 	serverInfo->sinfo[1].server_status =
540 	    INFO_SERVER_UNKNOWN;
541 	if (serverInfo->sinfo[1].rootDSE_data)
542 		free(serverInfo->sinfo[1].rootDSE_data);
543 	serverInfo->sinfo[1].rootDSE_data	= NULL;
544 	if (serverInfo->sinfo[1].errormsg)
545 		free(serverInfo->sinfo[1].errormsg);
546 	serverInfo->sinfo[1].errormsg 		= NULL;
547 	(void) mutex_unlock(&serverInfo->mutex[1]);
548 
549 	if ((ld = ldap_init(serverInfo->sinfo[1].addr,
550 	    LDAP_PORT)) == NULL ||
551 		/* SKIP ldap data base to prevent recursion */
552 		/* in gethostbyname when resolving hostname */
553 	    0 != ldap_set_option(ld, LDAP_X_OPT_DNS_SKIPDB, "ldap")) {
554 
555 		(void) mutex_lock(&serverInfo->mutex[1]);
556 		serverInfo->sinfo[1].server_status =
557 		    INFO_SERVER_ERROR;
558 		serverInfo->sinfo[1].info_status =
559 		    INFO_STATUS_ERROR;
560 		serverInfo->sinfo[1].errormsg =
561 		    strdup(gettext("ldap_init failed"));
562 
563 		if (current_admin.debug_level >= DBG_ALL) {
564 			logit("getldap_get_rootDSE: %s.\n",
565 			    serverInfo->sinfo[1].errormsg);
566 		}
567 		(void) mutex_unlock(&serverInfo->mutex[1]);
568 		/*
569 		 * sync sinfo copies in the serverInfo.
570 		 * protected by mutex
571 		 */
572 		sync_current_with_update_copy(serverInfo);
573 		thr_exit((void *) -1);
574 	}
575 	ldap_set_option(ld,
576 	    LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
577 	ldap_set_option(ld,
578 	    LDAP_X_OPT_CONNECT_TIMEOUT, &tcptimeout);
579 
580 	/* currently, only interested in two attributes */
581 	attrs[0] = "supportedControl";
582 	attrs[1] = "supportedsaslmechanisms";
583 	attrs[2] = NULL;
584 
585 	(void) mutex_lock(&serverInfo->mutex[1]);
586 	serverInfo->sinfo[1].server_status = INFO_SERVER_CONNECTING;
587 	(void) mutex_unlock(&serverInfo->mutex[1]);
588 
589 	tv.tv_sec = search_timeout;
590 	tv.tv_usec = 0;
591 
592 	rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE,
593 	    "(objectclass=*)",
594 	    attrs, 0, NULL, NULL, &tv, 0, &resultMsg);
595 
596 	switch (rc) {
597 		/* If successful, the root DSE was found. */
598 		case LDAP_SUCCESS:
599 			break;
600 		/*
601 		 * If the root DSE was not found, the server does
602 		 * not comply with the LDAP v3 protocol.
603 		 */
604 		default:
605 			ldap_get_option(ld,
606 			    LDAP_OPT_ERROR_NUMBER, &ldaperrno);
607 			(void) snprintf(errmsg, sizeof (errmsg),
608 			    gettext(ldap_err2string(ldaperrno)));
609 			if (current_admin.debug_level >= DBG_ALL) {
610 			logit("getldap_get_rootDSE: Root DSE not found."
611 			    " %s is not an LDAPv3 server (%s).\n",
612 			    serverInfo->sinfo[1].addr, errmsg);
613 			}
614 			(void) mutex_lock(&serverInfo->mutex[1]);
615 			serverInfo->sinfo[1].errormsg
616 			    = strdup(errmsg);
617 			serverInfo->sinfo[1].info_status
618 			    = INFO_STATUS_ERROR;
619 			serverInfo->sinfo[1].server_status
620 			    = INFO_SERVER_ERROR;
621 			(void) mutex_unlock(&serverInfo->mutex[1]);
622 			if (resultMsg)
623 				ldap_msgfree(resultMsg);
624 			ldap_unbind(ld);
625 			/*
626 			 * sync sinfo copies in the serverInfo.
627 			 * protected by mutex
628 			 */
629 			sync_current_with_update_copy(serverInfo);
630 			thr_exit((void *) -1);
631 			break;
632 	}
633 
634 
635 	if ((e = ldap_first_entry(ld, resultMsg)) != NULL) {
636 		/* calculate length of root DSE data */
637 		for (a = ldap_first_attribute(ld, e, &ber);
638 		    a != NULL;
639 		    a = ldap_next_attribute(ld, e, ber)) {
640 
641 			if ((vals = ldap_get_values(ld, e, a)) != NULL) {
642 				for (i = 0; vals[i] != NULL; i++) {
643 					len +=  strlen(a) +
644 					    strlen(vals[i]) +
645 					    strlen(DOORLINESEP) +1;
646 				}
647 				ldap_value_free(vals);
648 			}
649 			ldap_memfree(a);
650 		}
651 		if (ber != NULL)
652 			ber_free(ber, 0);
653 		/* copy root DSE data */
654 		if (len) {
655 			/* add 1 for the last '\0' */
656 			rootDSE  = (char *)malloc(len + 1);
657 			if (rootDSE != NULL) {
658 				/* make it an empty string first */
659 				*rootDSE = '\0';
660 				for (a = ldap_first_attribute(ld, e, &ber);
661 				    a != NULL;
662 				    a = ldap_next_attribute(
663 				    ld, e, ber)) {
664 
665 					if ((vals = ldap_get_values(
666 					    ld, e, a)) != NULL) {
667 						for (i = 0; vals[i] != NULL;
668 						    i++) {
669 							int len;
670 
671 							len = strlen(a) +
672 							    strlen(vals[i]) +
673 							    strlen(DOORLINESEP)
674 							    + 2;
675 							(void) snprintf(
676 							    rootDSE +
677 							    strlen(rootDSE),
678 							    len, "%s=%s%s",
679 							    a, vals[i],
680 							    DOORLINESEP);
681 						}
682 						ldap_value_free(vals);
683 					}
684 					ldap_memfree(a);
685 				}
686 				if (ber != NULL)
687 					ber_free(ber, 0);
688 			} else
689 				len = 0;
690 		}
691 	}
692 
693 	/* error, if no root DSE data */
694 	(void) mutex_lock(&serverInfo->mutex[1]);
695 	if (len == 0) {
696 		serverInfo->sinfo[1].errormsg =
697 		    strdup(gettext("No root DSE data returned."));
698 		if (current_admin.debug_level >= DBG_ALL) {
699 			logit("getldap_get_rootDSE: %s.\n",
700 			    serverInfo->sinfo[1].errormsg);
701 		}
702 		serverInfo->sinfo[1].type
703 		    = INFO_RW_UNKNOWN;
704 		serverInfo->sinfo[1].info_status
705 		    = INFO_STATUS_ERROR;
706 		serverInfo->sinfo[1].server_status 	= INFO_SERVER_ERROR;
707 		exitrc = -1;
708 	} else {
709 		/* assume writeable, i.e., can do modify */
710 		serverInfo->sinfo[1].type	= INFO_RW_WRITEABLE;
711 		serverInfo->sinfo[1].server_status
712 		    = INFO_SERVER_UP;
713 		serverInfo->sinfo[1].info_status	= INFO_STATUS_NEW;
714 		/* remove the last DOORLINESEP */
715 		*(rootDSE+strlen(rootDSE)-1) = '\0';
716 		serverInfo->sinfo[1].rootDSE_data = rootDSE;
717 
718 		server_found = 1;
719 
720 		exitrc = NS_LDAP_SUCCESS;
721 	}
722 	(void) mutex_unlock(&serverInfo->mutex[1]);
723 
724 	if (resultMsg)
725 		ldap_msgfree(resultMsg);
726 	ldap_unbind(ld);
727 
728 	/*
729 	 * sync sinfo copies in the serverInfo.
730 	 * protected by mutex
731 	 */
732 	sync_current_with_update_copy(serverInfo);
733 	/*
734 	 * signal that the ldap_cachemgr parent process
735 	 * should exit now, if it is still waiting
736 	 */
737 	(void) mutex_lock(&sig_mutex);
738 	if (signal_done == FALSE && server_found) {
739 		ppid = getppid();
740 		(void) kill(ppid, SIGUSR1);
741 		if (current_admin.debug_level >= DBG_ALL) {
742 			logit("getldap_get_rootDSE(): "
743 			    "SIGUSR1 signal sent to "
744 			    "parent process(%ld).\n", ppid);
745 		}
746 		signal_done = TRUE;
747 	}
748 	(void) mutex_unlock(&sig_mutex);
749 
750 	thr_exit((void *) exitrc);
751 
752 	return ((void *) NULL);
753 }
754 
755 static int
756 getldap_init_serverInfo(server_info_t **head)
757 {
758 	char		**servers = NULL;
759 	int		rc = 0, i, exitrc = NS_LDAP_SUCCESS;
760 	ns_ldap_error_t *errorp = NULL;
761 	server_info_t	*info, *tail = NULL;
762 
763 	*head = NULL;
764 	if (current_admin.debug_level >= DBG_ALL) {
765 		logit("getldap_init_serverInfo()...\n");
766 	}
767 	rc = __s_api_getServers(&servers, &errorp);
768 
769 	if (rc != NS_LDAP_SUCCESS) {
770 		logit("getldap_init_serverInfo: "
771 		    "__s_api_getServers failed.\n");
772 		if (errorp)
773 			__ns_ldap_freeError(&errorp);
774 		return (-1);
775 	}
776 	for (i = 0; servers[i] != NULL; i++) {
777 		info = (server_info_t *)calloc(1, sizeof (server_info_t));
778 		if (info == NULL) {
779 			logit("getldap_init_serverInfo: "
780 			    "not enough memory.\n");
781 			exitrc = NS_LDAP_MEMORY;
782 			break;
783 		}
784 		if (i == 0) {
785 			*head = info;
786 			tail  = info;
787 		} else {
788 			tail->next = info;
789 			tail  = info;
790 		}
791 
792 		info->sinfo[0].addr		= strdup(servers[i]);
793 		if (info->sinfo[0].addr == NULL) {
794 			logit("getldap_init_serverInfo: "
795 			    "not enough memory.\n");
796 			exitrc = NS_LDAP_MEMORY;
797 			break;
798 		}
799 		info->sinfo[1].addr		= strdup(servers[i]);
800 		if (info->sinfo[1].addr == NULL) {
801 			logit("getldap_init_serverInfo: "
802 			    "not enough memory.\n");
803 			exitrc = NS_LDAP_MEMORY;
804 			break;
805 		}
806 
807 		info->sinfo[0].type 		= INFO_RW_UNKNOWN;
808 		info->sinfo[1].type 		= INFO_RW_UNKNOWN;
809 		info->sinfo[0].info_status	= INFO_STATUS_UNKNOWN;
810 		info->sinfo[1].info_status	= INFO_STATUS_UNKNOWN;
811 		info->sinfo[0].server_status	= INFO_SERVER_UNKNOWN;
812 		info->sinfo[1].server_status	= INFO_SERVER_UNKNOWN;
813 
814 		/*
815 		 * Assume at startup or after the configuration
816 		 * profile is refreshed, all servers are good.
817 		 */
818 		info->sinfo[0].prev_server_status =
819 		    INFO_SERVER_UP;
820 		info->sinfo[1].prev_server_status =
821 		    INFO_SERVER_UP;
822 		info->sinfo[0].hostname		= NULL;
823 		info->sinfo[1].hostname		= NULL;
824 		info->sinfo[0].rootDSE_data	= NULL;
825 		info->sinfo[1].rootDSE_data	= NULL;
826 		info->sinfo[0].errormsg 	= NULL;
827 		info->sinfo[1].errormsg 	= NULL;
828 		info->next 		= NULL;
829 	}
830 	__s_api_free2dArray(servers);
831 	if (exitrc != NS_LDAP_SUCCESS) {
832 		if (head && *head) {
833 			(void) getldap_destroy_serverInfo(*head);
834 			*head = NULL;
835 		}
836 	}
837 	return (exitrc);
838 }
839 
840 static int
841 getldap_destroy_serverInfo(server_info_t *head)
842 {
843 	server_info_t	*info, *next;
844 
845 	if (current_admin.debug_level >= DBG_ALL) {
846 		logit("getldap_destroy_serverInfo()...\n");
847 	}
848 
849 	if (head == NULL) {
850 		logit("getldap_destroy_serverInfo: "
851 		    "invalid serverInfo list.\n");
852 		return (-1);
853 	}
854 
855 	for (info = head; info; info = next) {
856 		if (info->sinfo[0].addr)
857 			free(info->sinfo[0].addr);
858 		if (info->sinfo[1].addr)
859 			free(info->sinfo[1].addr);
860 		if (info->sinfo[0].hostname)
861 			free(info->sinfo[0].hostname);
862 		if (info->sinfo[1].hostname)
863 			free(info->sinfo[1].hostname);
864 		if (info->sinfo[0].rootDSE_data)
865 			free(info->sinfo[0].rootDSE_data);
866 		if (info->sinfo[1].rootDSE_data)
867 			free(info->sinfo[1].rootDSE_data);
868 		if (info->sinfo[0].errormsg)
869 			free(info->sinfo[0].errormsg);
870 		if (info->sinfo[1].errormsg)
871 			free(info->sinfo[1].errormsg);
872 		next = info->next;
873 		free(info);
874 	}
875 	return (NS_LDAP_SUCCESS);
876 }
877 
878 static int
879 getldap_set_serverInfo(server_info_t *head,
880 		int reset_bindtime)
881 {
882 	server_info_t	*info;
883 	int 		atleast1 = 0;
884 	thread_t	*tid;
885 	int 		num_threads = 0, i, j;
886 	void		*status;
887 	void		**paramVal = NULL;
888 	ns_ldap_error_t	*error = NULL;
889 
890 	if (current_admin.debug_level >= DBG_ALL) {
891 		logit("getldap_set_serverInfo()...\n");
892 	}
893 
894 	if (head == NULL) {
895 		logit("getldap_set_serverInfo: "
896 		    "invalid serverInfo list.\n");
897 		return (-1);
898 	}
899 
900 	/* Get the bind timeout value */
901 	if (reset_bindtime == 1) {
902 		tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
903 		(void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P,
904 		    &paramVal, &error);
905 		if (paramVal != NULL && *paramVal != NULL) {
906 			/* convert to milliseconds */
907 			tcptimeout = **((int **)paramVal);
908 			tcptimeout *= 1000;
909 			(void) __ns_ldap_freeParam(&paramVal);
910 		}
911 		if (error)
912 			(void) __ns_ldap_freeError(&error);
913 
914 		/* get search timeout value */
915 		search_timeout = NS_DEFAULT_SEARCH_TIMEOUT;
916 		(void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P,
917 		    &paramVal, &error);
918 		if (paramVal != NULL && *paramVal != NULL) {
919 			search_timeout = **((int **)paramVal);
920 			(void) __ns_ldap_freeParam(&paramVal);
921 		}
922 		if (error)
923 			(void) __ns_ldap_freeError(&error);
924 
925 	}
926 
927 	for (info = head; info; info = info->next)
928 		num_threads++;
929 
930 	if (num_threads == 0) {
931 		logit("getldap_set_serverInfo: "
932 		    "empty serverInfo list.\n");
933 		return (-1);
934 	}
935 
936 	tid = (thread_t *) calloc(1, sizeof (thread_t) * num_threads);
937 	if (tid == NULL) {
938 		logit("getldap_set_serverInfo: "
939 		    "No memory to create thread ID list.\n");
940 		return (-1);
941 	}
942 
943 	for (info = head, i = 0; info; info = info->next, i++) {
944 		if (thr_create(NULL, 0,
945 		    (void *(*)(void*))getldap_get_rootDSE,
946 		    (void *)info, 0, &tid[i])) {
947 			logit("getldap_set_serverInfo: "
948 			    "can not create thread %d.\n", i + 1);
949 			for (j = 0; j < i; j++)
950 				(void) thr_join(tid[j], NULL, NULL);
951 			free(tid);
952 			return (-1);
953 		}
954 	}
955 
956 	for (i = 0; i < num_threads; i++) {
957 		if (thr_join(tid[i], NULL, &status) == 0) {
958 			if ((int)status == NS_LDAP_SUCCESS)
959 				atleast1 = 1;
960 		}
961 	}
962 
963 	free(tid);
964 
965 	if (atleast1)
966 		return (NS_LDAP_SUCCESS);
967 	else
968 		return (-1);
969 }
970 
971 /*
972  * Convert an IP to a host name
973  */
974 static int
975 getldap_ip2hostname(char *ipaddr, char **hostname) {
976 	struct in_addr	in;
977 	struct in6_addr	in6;
978 	struct hostent	*hp = NULL;
979 	char	*start = NULL, *end = NULL, delim = '\0';
980 	char	*port = NULL, *addr = NULL;
981 	int	error_num = 0, len = 0;
982 
983 	if (ipaddr == NULL || hostname == NULL)
984 		return (NS_LDAP_INVALID_PARAM);
985 	*hostname = NULL;
986 	if ((addr = strdup(ipaddr)) == NULL)
987 		return (NS_LDAP_MEMORY);
988 
989 	if (addr[0] == '[') {
990 		/*
991 		 * Assume it's [ipv6]:port
992 		 * Extract ipv6 IP
993 		 */
994 		start = &addr[1];
995 		if ((end = strchr(addr, ']')) != NULL) {
996 			*end = '\0';
997 			delim = ']';
998 			if (*(end + 1) == ':')
999 				/* extract port */
1000 				port = end + 2;
1001 		} else {
1002 			return (NS_LDAP_INVALID_PARAM);
1003 		}
1004 	} else if ((end = strchr(addr, ':')) != NULL) {
1005 		/* assume it's ipv4:port */
1006 		*end = '\0';
1007 		delim = ':';
1008 		start = addr;
1009 		port = end + 1;
1010 	} else
1011 		/* No port */
1012 		start = addr;
1013 
1014 
1015 	if (inet_pton(AF_INET, start, &in) == 1) {
1016 		/* IPv4 */
1017 		hp = getipnodebyaddr((char *)&in,
1018 			sizeof (struct in_addr), AF_INET, &error_num);
1019 		if (hp && hp->h_name) {
1020 			/* hostname + '\0' */
1021 			len = strlen(hp->h_name) + 1;
1022 			if (port)
1023 				/* ':' + port */
1024 				len += strlen(port) + 1;
1025 			if ((*hostname = malloc(len)) == NULL) {
1026 				free(addr);
1027 				freehostent(hp);
1028 				return (NS_LDAP_MEMORY);
1029 			}
1030 
1031 			if (port)
1032 				(void) snprintf(*hostname, len, "%s:%s",
1033 						hp->h_name, port);
1034 			else
1035 				(void) strlcpy(*hostname, hp->h_name, len);
1036 
1037 			free(addr);
1038 			freehostent(hp);
1039 			return (NS_LDAP_SUCCESS);
1040 		} else {
1041 			return (NS_LDAP_NOTFOUND);
1042 		}
1043 	} else if (inet_pton(AF_INET6, start, &in6) == 1) {
1044 		/* IPv6 */
1045 		hp = getipnodebyaddr((char *)&in6,
1046 			sizeof (struct in6_addr), AF_INET6, &error_num);
1047 		if (hp && hp->h_name) {
1048 			/* hostname + '\0' */
1049 			len = strlen(hp->h_name) + 1;
1050 			if (port)
1051 				/* ':' + port */
1052 				len += strlen(port) + 1;
1053 			if ((*hostname = malloc(len)) == NULL) {
1054 				free(addr);
1055 				freehostent(hp);
1056 				return (NS_LDAP_MEMORY);
1057 			}
1058 
1059 			if (port)
1060 				(void) snprintf(*hostname, len, "%s:%s",
1061 						hp->h_name, port);
1062 			else
1063 				(void) strlcpy(*hostname, hp->h_name, len);
1064 
1065 			free(addr);
1066 			freehostent(hp);
1067 			return (NS_LDAP_SUCCESS);
1068 		} else {
1069 			return (NS_LDAP_NOTFOUND);
1070 		}
1071 	} else {
1072 		/*
1073 		 * A hostname
1074 		 * Return it as is
1075 		 */
1076 		if (end)
1077 			*end = delim;
1078 		*hostname = addr;
1079 		return (NS_LDAP_SUCCESS);
1080 	}
1081 }
1082 /*
1083  * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
1084  * to this function from getldap_serverInfo_op().
1085  * input:
1086  *   a buffer containing an empty string (e.g., input[0]='\0';) or a string
1087  *   as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
1088  *   addr);
1089  *   where addr is the address of a server and
1090  *   req is one of the following:
1091  *   NS_CACHE_NEW:    send a new server address, addr is ignored.
1092  *   NS_CACHE_NORESP: send the next one, remove addr from list.
1093  *   NS_CACHE_NEXT:   send the next one, keep addr on list.
1094  *   NS_CACHE_WRITE:  send a non-replica server, if possible, if not, same
1095  *                    as NS_CACHE_NEXT.
1096  *   addrtype:
1097  *   NS_CACHE_ADDR_IP: return server address as is, this is default.
1098  *   NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
1099  *			only self credential case requires such format.
1100  * output:
1101  *   a buffer containing server info in the following format:
1102  *   serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
1103  *   [ attr=value [DOORLINESEP attr=value ]...]
1104  *   For example: ( here | used as DOORLINESEP for visual purposes)
1105  *   1) simple bind and sasl/DIGEST-MD5 bind :
1106  *   1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
1107  *   supportedSASLmechanisms=GSSAPI
1108  *   2) sasl/GSSAPI bind (self credential):
1109  *   1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
1110  *   supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
1111  *   NOTE: caller should free this buffer when done using it
1112  */
1113 static int
1114 getldap_get_serverInfo(server_info_t *head, char *input,
1115 		char **output, int *svr_removed)
1116 {
1117 	server_info_t	*info 	= NULL;
1118 	server_info_t	*server	= NULL;
1119 	char 		*addr	= NULL;
1120 	char 		*req	= NULL;
1121 	char 		req_new[] = NS_CACHE_NEW;
1122 	char 		addr_type[] = NS_CACHE_ADDR_IP;
1123 	int		matched = FALSE, len, rc = 0;
1124 	char		*ret_addr = NULL, *ret_addrFQDN = NULL;
1125 
1126 	if (current_admin.debug_level >= DBG_ALL) {
1127 		logit("getldap_get_serverInfo()...\n");
1128 	}
1129 
1130 	if (input == NULL || output == NULL) {
1131 		logit("getldap_get_serverInfo: "
1132 		    "No input or output buffer.\n");
1133 		return (-1);
1134 	}
1135 
1136 	*output = NULL;
1137 	*svr_removed = FALSE;
1138 
1139 	if (head == NULL) {
1140 		logit("getldap_get_serverInfo: "
1141 		    "invalid serverInfo list.\n");
1142 		return (-1);
1143 	}
1144 	/*
1145 	 * parse the input string to get req and addr,
1146 	 * if input is empty, i.e., input[0] == '\0',
1147 	 * treat it as an NS_CACHE_NEW request
1148 	 */
1149 	req = req_new;
1150 	if (input[0] != '\0') {
1151 		req = input;
1152 		/* Save addr type flag */
1153 		addr_type[0] = input[1];
1154 		input[strlen(NS_CACHE_NEW)] = '\0';
1155 		/* skip acion type flag, addr type flag and DOORLINESEP */
1156 		addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW)
1157 		    + strlen(NS_CACHE_ADDR_IP);
1158 	}
1159 	/*
1160 	 * if NS_CACHE_NEW,
1161 	 * or the server info is new,
1162 	 * starts from the
1163 	 * beginning of the list
1164 	 */
1165 	if ((strcmp(req, NS_CACHE_NEW) == 0) ||
1166 	    (head->sinfo[0].info_status == INFO_STATUS_NEW))
1167 		matched = TRUE;
1168 	for (info = head; info; info = info->next) {
1169 		/*
1170 		 * make sure the server info stays the same
1171 		 * while the data is being processed
1172 		 */
1173 
1174 		/*
1175 		 * This function is called to get server info list
1176 		 * and pass it back to door call clients.
1177 		 * Access the current copy (sinfo[0]) to get such
1178 		 * information
1179 		 */
1180 		(void) mutex_lock(&info->mutex[0]);
1181 
1182 		if (matched == FALSE &&
1183 		    strcmp(info->sinfo[0].addr, addr) == 0) {
1184 			matched = TRUE;
1185 			if (strcmp(req, NS_CACHE_NORESP) == 0) {
1186 
1187 				/*
1188 				 * if the server has already been removed,
1189 				 * don't bother
1190 				 */
1191 				if (info->sinfo[0].server_status ==
1192 				    INFO_SERVER_REMOVED) {
1193 					(void) mutex_unlock(&info->mutex[0]);
1194 					continue;
1195 				}
1196 
1197 				/*
1198 				 * if the information is new,
1199 				 * give this server one more chance
1200 				 */
1201 				if (info->sinfo[0].info_status ==
1202 				    INFO_STATUS_NEW &&
1203 				    info->sinfo[0].server_status  ==
1204 				    INFO_SERVER_UP) {
1205 					server = info;
1206 					break;
1207 				} else {
1208 					/*
1209 					 * it is recommended that
1210 					 * before removing the
1211 					 * server from the list,
1212 					 * the server should be
1213 					 * contacted one more time
1214 					 * to make sure that it is
1215 					 * really unavailable.
1216 					 * For now, just trust the client
1217 					 * (i.e., the sldap library)
1218 					 * that it knows what it is
1219 					 * doing and would not try
1220 					 * to mess up the server
1221 					 * list.
1222 					 */
1223 					info->sinfo[0].prev_server_status =
1224 					    info->sinfo[0].server_status;
1225 					info->sinfo[0].server_status  =
1226 					    INFO_SERVER_REMOVED;
1227 					/*
1228 					 * make sure this will be seen
1229 					 * if a user query the server
1230 					 * status via the ldap_cachemgr's
1231 					 * -g option
1232 					 */
1233 					info->sinfo[1].server_status  =
1234 					    INFO_SERVER_REMOVED;
1235 					*svr_removed = TRUE;
1236 					(void) mutex_unlock(&info->mutex[0]);
1237 					continue;
1238 				}
1239 			} else {
1240 				/*
1241 				 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
1242 				 */
1243 				(void) mutex_unlock(&info->mutex[0]);
1244 				continue;
1245 			}
1246 		}
1247 
1248 		if (matched) {
1249 			if (strcmp(req, NS_CACHE_WRITE) == 0) {
1250 				if (info->sinfo[0].type ==
1251 				    INFO_RW_WRITEABLE &&
1252 				    info->sinfo[0].server_status  ==
1253 				    INFO_SERVER_UP) {
1254 					server = info;
1255 					break;
1256 				}
1257 			} else if (info->sinfo[0].server_status ==
1258 			    INFO_SERVER_UP) {
1259 				server = info;
1260 				break;
1261 			}
1262 		}
1263 
1264 		(void) mutex_unlock(&info->mutex[0]);
1265 	}
1266 
1267 	if (server) {
1268 		if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) {
1269 			/*
1270 			 * In SASL/GSSAPI case, a hostname is required for
1271 			 * Kerberos's service principal.
1272 			 * e.g.
1273 			 * ldap/foo.sun.com@SUN.COM
1274 			 */
1275 			if (server->sinfo[0].hostname == NULL) {
1276 				rc = getldap_ip2hostname(server->sinfo[0].addr,
1277 				    &server->sinfo[0].hostname);
1278 				if (rc != NS_LDAP_SUCCESS) {
1279 					(void) mutex_unlock(&info->mutex[0]);
1280 					return (rc);
1281 				}
1282 				if (current_admin.debug_level >= DBG_ALL) {
1283 					logit("getldap_get_serverInfo: "
1284 					    "%s is converted to %s\n",
1285 					    server->sinfo[0].addr,
1286 					    server->sinfo[0].hostname);
1287 				}
1288 			}
1289 			ret_addr = server->sinfo[0].addr;
1290 			ret_addrFQDN = server->sinfo[0].hostname;
1291 
1292 		} else
1293 			ret_addr = server->sinfo[0].addr;
1294 
1295 
1296 		len = strlen(ret_addr) +
1297 		    strlen(server->sinfo[0].rootDSE_data) +
1298 		    strlen(DOORLINESEP) + 1;
1299 		if (ret_addrFQDN != NULL)
1300 			len += strlen(ret_addrFQDN) + strlen(DOORLINESEP);
1301 		*output = (char *)malloc(len);
1302 		if (*output == NULL) {
1303 			(void) mutex_unlock(&info->mutex[0]);
1304 			return (NS_LDAP_MEMORY);
1305 		}
1306 		if (ret_addrFQDN == NULL)
1307 			(void) snprintf(*output, len, "%s%s%s",
1308 			    ret_addr, DOORLINESEP,
1309 			    server->sinfo[0].rootDSE_data);
1310 		else
1311 			(void) snprintf(*output, len, "%s%s%s%s%s",
1312 			    ret_addr, DOORLINESEP,
1313 			    ret_addrFQDN, DOORLINESEP,
1314 			    server->sinfo[0].rootDSE_data);
1315 		server->sinfo[0].info_status = INFO_STATUS_OLD;
1316 		(void) mutex_unlock(&info->mutex[0]);
1317 		return (NS_LDAP_SUCCESS);
1318 	}
1319 	else
1320 		return (-99);
1321 }
1322 
1323 /*
1324  * Format previous and next refresh time
1325  */
1326 static int
1327 getldap_format_refresh_time(char **output, time_t *prev, time_t *next)
1328 {
1329 #define	TIME_FORMAT	"%Y/%m/%d %H:%M:%S"
1330 #define	TIME_HEADER1	"  Previous refresh time: "
1331 #define	TIME_HEADER2	"  Next refresh time:     "
1332 	int		hdr1_len = strlen(gettext(TIME_HEADER1));
1333 	int		hdr2_len = strlen(gettext(TIME_HEADER2));
1334 	struct	tm 	tm;
1335 	char		nbuf[256];
1336 	char		pbuf[256];
1337 	int		len;
1338 
1339 	if (current_admin.debug_level >= DBG_ALL) {
1340 		logit("getldap_format_refresh_time()...\n");
1341 	}
1342 
1343 	*output = NULL;
1344 
1345 	/* format the time of previous refresh  */
1346 	if (*prev != 0) {
1347 		(void) localtime_r(prev, &tm);
1348 		(void) strftime(pbuf, sizeof (pbuf) - 1, TIME_FORMAT, &tm);
1349 	} else {
1350 		(void) strcpy(pbuf, gettext("NOT DONE"));
1351 	}
1352 
1353 	/* format the time of next refresh  */
1354 	if (*next != 0) {
1355 		(void) localtime_r(next, &tm);
1356 		(void) strftime(nbuf, sizeof (nbuf) - 1, TIME_FORMAT, &tm);
1357 	} else {
1358 		(void) strcpy(nbuf, gettext("NOT SET"));
1359 	}
1360 
1361 	len = hdr1_len + hdr2_len + strlen(nbuf) +
1362 	    strlen(pbuf) + 2 * strlen(DOORLINESEP) + 1;
1363 
1364 	*output = malloc(len);
1365 	if (*output == NULL)
1366 		return (-1);
1367 
1368 	(void) snprintf(*output, len, "%s%s%s%s%s%s",
1369 	    gettext(TIME_HEADER1), pbuf, DOORLINESEP,
1370 	    gettext(TIME_HEADER2), nbuf, DOORLINESEP);
1371 
1372 	return (NS_LDAP_SUCCESS);
1373 }
1374 
1375 /*
1376  * getldap_get_server_stat processes the GETSTAT request passed
1377  * to this function from getldap_serverInfo_op().
1378  * output:
1379  *   a buffer containing info for all the servers.
1380  *   For each server, the data is in the following format:
1381  *   server: server address or name, status: unknown|up|down|removed DOORLINESEP
1382  *   for example: ( here | used as DOORLINESEP for visual purposes)
1383  *   server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1384  *   NOTE: caller should free this buffer when done using it
1385  */
1386 static int
1387 getldap_get_server_stat(server_info_t *head, char **output,
1388 		time_t *prev, time_t *next)
1389 {
1390 #define	S_HEADER	"Server information: "
1391 #define	S_FORMAT	"  server: %s, status: %s%s"
1392 #define	S_ERROR		"    error message: %s%s"
1393 	server_info_t	*info 	= NULL;
1394 	int	header_len = strlen(gettext(S_HEADER));
1395 	int	format_len = strlen(gettext(S_FORMAT));
1396 	int	error_len = strlen(gettext(S_ERROR));
1397 	int	len = header_len + strlen(DOORLINESEP);
1398 	int	len1 = 0;
1399 	char	*status, *output1 = NULL, *tmpptr;
1400 
1401 	*output = NULL;
1402 
1403 	if (current_admin.debug_level >= DBG_ALL) {
1404 		logit("getldap_get_server_stat()...\n");
1405 	}
1406 
1407 	if (head == NULL) {
1408 		logit("getldap_get_server_stat: "
1409 		    "invalid serverInfo list.\n");
1410 		return (-1);
1411 	}
1412 
1413 	/* format previous and next refresh time */
1414 	(void) getldap_format_refresh_time(&output1, prev, next);
1415 	if (output1 == NULL)
1416 		return (-1);
1417 	len += strlen(output1);
1418 	len1 = len + strlen(DOORLINESEP) + 1;
1419 
1420 	*output = (char *)calloc(1, len1);
1421 	if (*output == NULL) {
1422 		free(output1);
1423 		return (-1);
1424 	}
1425 
1426 	/* insert header string and refresh time info */
1427 	(void) snprintf(*output, len1, "%s%s%s",
1428 	    gettext(S_HEADER), DOORLINESEP, output1);
1429 
1430 	for (info = head; info; info = info->next) {
1431 
1432 		/*
1433 		 * make sure the server info stays the same
1434 		 * while the data is being processed
1435 		 */
1436 		(void) mutex_lock(&info->mutex[1]);
1437 
1438 		/*
1439 		 * When the updating process is under way(getldap_get_rootDSE)
1440 		 * the update copy(sinfo[1] is the latest copy.
1441 		 * When the updating process
1442 		 * is done, the current copy (sinfo[0]) has the latest status,
1443 		 * which is still identical to the update copy.
1444 		 * So update copy has the latest status.
1445 		 * Use the update copy(sinfo[1]) to show status
1446 		 * (ldap_cachemgr -g).
1447 		 *
1448 		 */
1449 
1450 		switch (info->sinfo[1].server_status) {
1451 		case INFO_SERVER_UNKNOWN:
1452 			status = gettext("UNKNOWN");
1453 			break;
1454 		case INFO_SERVER_CONNECTING:
1455 			status = gettext("CONNECTING");
1456 			break;
1457 		case INFO_SERVER_UP:
1458 			status = gettext("UP");
1459 			break;
1460 		case INFO_SERVER_ERROR:
1461 			status = gettext("ERROR");
1462 			break;
1463 		case INFO_SERVER_REMOVED:
1464 			status = gettext("REMOVED");
1465 			break;
1466 		}
1467 
1468 		len += format_len + strlen(status) +
1469 		    strlen(info->sinfo[1].addr) +
1470 		    strlen(DOORLINESEP);
1471 		if (info->sinfo[1].errormsg != NULL)
1472 			len += error_len +
1473 			    strlen(info->sinfo[1].errormsg) +
1474 			    strlen(DOORLINESEP);
1475 
1476 		tmpptr = (char *)realloc(*output, len);
1477 		if (tmpptr == NULL) {
1478 			free(output1);
1479 			free(*output);
1480 			*output = NULL;
1481 			(void) mutex_unlock(&info->mutex[1]);
1482 			return (-1);
1483 		} else
1484 			*output = tmpptr;
1485 
1486 		/* insert server IP addr or name and status */
1487 		len1 = len - strlen(*output);
1488 		(void) snprintf(*output + strlen(*output), len1,
1489 		    gettext(S_FORMAT), info->sinfo[1].addr,
1490 		    status, DOORLINESEP);
1491 		/* insert error message if any */
1492 		len1 = len - strlen(*output);
1493 		if (info->sinfo[1].errormsg != NULL)
1494 			(void) snprintf(*output + strlen(*output), len1,
1495 			    gettext(S_ERROR),
1496 			    info->sinfo[1].errormsg,
1497 			    DOORLINESEP);
1498 
1499 		(void) mutex_unlock(&info->mutex[1]);
1500 
1501 	}
1502 
1503 	free(output1);
1504 	return (NS_LDAP_SUCCESS);
1505 }
1506 
1507 /*
1508  * Format and return the refresh time statistics
1509  */
1510 static int
1511 getldap_get_refresh_stat(char **output)
1512 {
1513 #define	R_HEADER0	"Configuration refresh information: "
1514 #define	R_HEADER1	"  Configured to NO REFRESH."
1515 	int		hdr0_len = strlen(gettext(R_HEADER0));
1516 	int		hdr1_len = strlen(gettext(R_HEADER1));
1517 	int		cache_ttl = -1, len = 0;
1518 	time_t 		expire = 0;
1519 	void		**paramVal = NULL;
1520 	ns_ldap_error_t	*errorp = NULL;
1521 	char		*output1 = NULL;
1522 
1523 	if (current_admin.debug_level >= DBG_ALL) {
1524 		logit("getldap_get_refresh_stat()...\n");
1525 	}
1526 
1527 	*output = NULL;
1528 
1529 	/* get configured cache TTL */
1530 	if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1531 	    &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
1532 	    paramVal != NULL &&
1533 	    (char *)*paramVal != NULL) {
1534 			cache_ttl = atol((char *)*paramVal);
1535 	} else {
1536 		if (errorp)
1537 			__ns_ldap_freeError(&errorp);
1538 	}
1539 	(void) __ns_ldap_freeParam(&paramVal);
1540 
1541 	/* cound not get cache TTL */
1542 	if (cache_ttl == -1)
1543 		return (-1);
1544 
1545 	if (cache_ttl == 0) {
1546 		len = hdr0_len + hdr1_len +
1547 		    2 * strlen(DOORLINESEP) + 1;
1548 		*output = malloc(len);
1549 		if (*output == NULL)
1550 			return (-1);
1551 		(void) snprintf(*output, len, "%s%s%s%s",
1552 		    gettext(R_HEADER0), DOORLINESEP,
1553 		    gettext(R_HEADER1), DOORLINESEP);
1554 	} else {
1555 
1556 		/* get configuration expiration time */
1557 		if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
1558 		    &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
1559 		    paramVal != NULL &&
1560 		    (char *)*paramVal != NULL) {
1561 				expire = (time_t)atol((char *)*paramVal);
1562 		} else {
1563 			if (errorp)
1564 				__ns_ldap_freeError(&errorp);
1565 		}
1566 
1567 		(void) __ns_ldap_freeParam(&paramVal);
1568 
1569 		/* cound not get expiration time */
1570 		if (expire == -1)
1571 			return (-1);
1572 
1573 		/* format previous and next refresh time */
1574 		(void) getldap_format_refresh_time(&output1,
1575 		    &prev_refresh_time, &expire);
1576 		if (output1 == NULL)
1577 			return (-1);
1578 
1579 		len = hdr0_len + strlen(output1) +
1580 		    2 * strlen(DOORLINESEP) + 1;
1581 		*output = malloc(len);
1582 		if (*output == NULL) {
1583 			free(output1);
1584 			return (-1);
1585 		}
1586 		(void) snprintf(*output, len, "%s%s%s%s",
1587 		    gettext(R_HEADER0), DOORLINESEP,
1588 		    output1, DOORLINESEP);
1589 		free(output1);
1590 	}
1591 
1592 	return (NS_LDAP_SUCCESS);
1593 }
1594 
1595 static int
1596 getldap_get_cacheTTL()
1597 {
1598 	void		**paramVal = NULL;
1599 	ns_ldap_error_t	*error;
1600 	int		rc = 0, cachettl;
1601 
1602 
1603 	if (current_admin.debug_level >= DBG_ALL) {
1604 		logit("getldap_get_cacheTTL()....\n");
1605 	}
1606 
1607 	if ((rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1608 	    &paramVal, &error)) != NS_LDAP_SUCCESS) {
1609 		if (error != NULL && error->message != NULL)
1610 			logit("Error: Unable to get configuration "
1611 			    "refresh TTL: %s\n",
1612 			    error->message);
1613 		else {
1614 			char *tmp;
1615 
1616 			__ns_ldap_err2str(rc, &tmp);
1617 			logit("Error: Unable to get configuration "
1618 			    "refresh TTL: %s\n", tmp);
1619 		}
1620 		(void) __ns_ldap_freeParam(&paramVal);
1621 		(void) __ns_ldap_freeError(&error);
1622 		return (-1);
1623 	}
1624 	if (paramVal == NULL || (char *)*paramVal == NULL)
1625 			return (-1);
1626 	cachettl = atol((char *)*paramVal);
1627 	(void) __ns_ldap_freeParam(&paramVal);
1628 	return (cachettl);
1629 }
1630 
1631 
1632 /*
1633  * This function implements the adaptive server list refresh
1634  * algorithm used by ldap_cachemgr. The idea is to have the
1635  * refresh TTL adjust itself between maximum and minimum
1636  * values. If the server list has been walked three times
1637  * in a row without errors, the TTL will be doubled. This will
1638  * be done repeatedly until the maximum value is reached
1639  * or passed. If passed, the maximum value will be used.
1640  * If any time a server is found to be down/bad, either
1641  * after another server list walk or informed by libsldap via
1642  * the GETLDAPSERVER door calls, the TTL will be set to half
1643  * of its value, again repeatedly, but no less than the minimum
1644  * value. Also, at any time, if all the servers on the list
1645  * are found to be down/bad, the TTL will be set to minimum,
1646  * so that a "no-server" refresh loop should be entered to try
1647  * to find a good server as soon as possible. The caller
1648  * could check the no_gd_server flag for this situation.
1649  * The maximum and minimum values are initialized when the input
1650  * refresh_ttl is set to zero, this should occur during
1651  * ldap_cachemgr startup or every time the server list is
1652  * recreated after the configuration profile is refreshed
1653  * from an LDAP server. The maximum is set to the value of
1654  * the NS_LDAP_CACHETTL parameter (configuration profile
1655  * refresh TTL), but if it is zero (never refreshed) or can
1656  * not be retrieved, the maximum is set to the macro
1657  * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1658  * set to REFRESHTTL_MIN, which is the TCP connection timeout
1659  * (tcptimeout) set via the LDAP API ldap_set_option()
1660  * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1661  * This accounts for the maximum possible timeout value for an
1662  * LDAP TCP connect call.The first refresh TTL, initial value of
1663  * refresh_ttl, will be set to the smaller of the two,
1664  * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1665  * The idea is to have a low starting value and have the value
1666  * stay low if the network/server is unstable, but eventually
1667  * the value will move up to maximum and stay there if the
1668  * network/server is stable.
1669  */
1670 static int
1671 getldap_set_refresh_ttl(server_info_t *head, int *refresh_ttl,
1672 		int *no_gd_server)
1673 {
1674 #define	REFRESHTTL_REGULAR	600
1675 #define	REFRESHTTL_MAX		43200
1676 /* tcptimeout is in milliseconds */
1677 #define	REFRESHTTL_MIN		(tcptimeout/1000) + 10
1678 #define	UP_REFRESH_TTL_NUM	2
1679 
1680 	static mutex_t		refresh_mutex;
1681 	static int		refresh_ttl_max = 0;
1682 	static int		refresh_ttl_min = 0;
1683 	static int		num_walked_ok = 0;
1684 	int			num_servers = 0;
1685 	int			num_good_servers = 0;
1686 	int			num_prev_good_servers = 0;
1687 	server_info_t		*info;
1688 
1689 	/* allow one thread at a time */
1690 	(void) mutex_lock(&refresh_mutex);
1691 
1692 	if (current_admin.debug_level >= DBG_ALL) {
1693 		logit("getldap_set_refresh_ttl()...\n");
1694 	}
1695 
1696 	if (!head || !refresh_ttl || !no_gd_server) {
1697 		logit("getldap_set_refresh_ttl: head is "
1698 		    "NULL or refresh_ttl is NULL or "
1699 		    "no_gd_server is NULL");
1700 		(void) mutex_unlock(&refresh_mutex);
1701 		return (-1);
1702 	}
1703 	*no_gd_server = FALSE;
1704 
1705 	/*
1706 	 * init max. min. TTLs if first time through or a fresh one
1707 	 */
1708 	if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1709 		logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1710 		    "seconds\n", *refresh_ttl);
1711 	}
1712 	if (*refresh_ttl == 0) {
1713 		num_walked_ok = 0;
1714 		/*
1715 		 * init cache manager server list TTL:
1716 		 *
1717 		 * init the min. TTL to
1718 		 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1719 		 */
1720 		refresh_ttl_min = REFRESHTTL_MIN;
1721 
1722 		/*
1723 		 * try to set the max. TTL to
1724 		 * configuration refresh TTL (NS_LDAP_CACHETTL),
1725 		 * if error (-1), or never refreshed (0),
1726 		 * set it to REFRESHTTL_MAX (12 hours)
1727 		 */
1728 		refresh_ttl_max = getldap_get_cacheTTL();
1729 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1730 			logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1731 			    "seconds\n", *refresh_ttl);
1732 			logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1733 			    "min ttl is %d seconds\n",
1734 			    refresh_ttl_max, refresh_ttl_min);
1735 		}
1736 		if (refresh_ttl_max <= 0)
1737 			refresh_ttl_max = REFRESHTTL_MAX;
1738 		else if (refresh_ttl_max < refresh_ttl_min)
1739 			refresh_ttl_max = refresh_ttl_min;
1740 
1741 		/*
1742 		 * init the first TTL to the smaller of the two:
1743 		 * REFRESHTTL_REGULAR ( 10 minutes),
1744 		 * (refresh_ttl_max + refresh_ttl_min)/2
1745 		 */
1746 		*refresh_ttl = REFRESHTTL_REGULAR;
1747 		if (*refresh_ttl > (refresh_ttl_max + refresh_ttl_min) / 2)
1748 			*refresh_ttl = (refresh_ttl_max + refresh_ttl_min) / 2;
1749 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1750 			logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1751 			    "seconds\n", *refresh_ttl);
1752 			logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1753 			    "min ttl is %d seconds\n",
1754 			    refresh_ttl_max, refresh_ttl_min);
1755 		}
1756 	}
1757 
1758 	/*
1759 	 * get the servers statistics:
1760 	 * number of servers on list
1761 	 * number of good servers on list
1762 	 * number of pevious good servers on list
1763 	 */
1764 	for (info = head; info; info = info->next) {
1765 		num_servers++;
1766 		(void) mutex_lock(&info->mutex[0]);
1767 		if (info->sinfo[0].server_status  == INFO_SERVER_UP)
1768 			num_good_servers++;
1769 		/*
1770 		 * Server's previous status could be UNKNOWN
1771 		 * only between the very first and second
1772 		 * refresh. Treat that UNKNOWN status as up
1773 		 */
1774 		if (info->sinfo[0].prev_server_status
1775 		    == INFO_SERVER_UP ||
1776 		    info->sinfo[0].prev_server_status
1777 		    == INFO_SERVER_UNKNOWN)
1778 			num_prev_good_servers++;
1779 		(void) mutex_unlock(&info->mutex[0]);
1780 	}
1781 
1782 	/*
1783 	 * if the server list is walked three times in a row
1784 	 * without problems, double the refresh TTL but no more
1785 	 * than the max. refresh TTL
1786 	 */
1787 	if (num_good_servers == num_servers) {
1788 		num_walked_ok++;
1789 		if (num_walked_ok > UP_REFRESH_TTL_NUM)  {
1790 
1791 			*refresh_ttl = *refresh_ttl * 2;
1792 			if (*refresh_ttl > refresh_ttl_max)
1793 				*refresh_ttl = refresh_ttl_max;
1794 
1795 			num_walked_ok = 0;
1796 		}
1797 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1798 			logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1799 			    "seconds\n", *refresh_ttl);
1800 		}
1801 	} else if (num_good_servers == 0) {
1802 		/*
1803 		 * if no good server found,
1804 		 * set refresh TTL to miminum
1805 		 */
1806 		*refresh_ttl = refresh_ttl_min;
1807 		*no_gd_server = TRUE;
1808 		num_walked_ok = 0;
1809 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1810 			logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1811 			    "seconds\n", *refresh_ttl);
1812 		}
1813 	} else if (num_prev_good_servers > num_good_servers) {
1814 		/*
1815 		 * if more down/bad servers found,
1816 		 * decrease the refresh TTL by half
1817 		 * but no less than the min. refresh TTL
1818 		 */
1819 		*refresh_ttl = *refresh_ttl / 2;
1820 		if (*refresh_ttl < refresh_ttl_min)
1821 			*refresh_ttl = refresh_ttl_min;
1822 		num_walked_ok = 0;
1823 		logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1824 		    "seconds\n", *refresh_ttl);
1825 
1826 	}
1827 
1828 	if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1829 		logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1830 		    *refresh_ttl);
1831 	}
1832 	(void) mutex_unlock(&refresh_mutex);
1833 	return (0);
1834 }
1835 
1836 static int
1837 getldap_serverInfo_op(info_op_t op, char *input, char **output)
1838 {
1839 
1840 	static rwlock_t 	info_lock = DEFAULTRWLOCK;
1841 	static rwlock_t 	info_lock_old = DEFAULTRWLOCK;
1842 	static mutex_t		info_mutex;
1843 	static cond_t		info_cond;
1844 	static int		creating = FALSE;
1845 	static int		refresh_ttl = 0;
1846 	static int		sec_to_refresh = 0;
1847 	static int		in_no_server_mode = FALSE;
1848 
1849 	static server_info_t 	*serverInfo = NULL;
1850 	static server_info_t 	*serverInfo_old = NULL;
1851 	server_info_t 		*serverInfo_1;
1852 	int 			is_creating;
1853 	int 			err, no_server_good = FALSE;
1854 	int 			server_removed = FALSE;
1855 	static struct timespec	timeout;
1856 	struct timespec		new_timeout;
1857 	struct timeval		tp;
1858 	static time_t		prev_refresh = 0, next_refresh = 0;
1859 
1860 	if (current_admin.debug_level >= DBG_ALL) {
1861 		logit("getldap_serverInfo_op()...\n");
1862 	}
1863 	switch (op) {
1864 	case INFO_OP_CREATE:
1865 		if (current_admin.debug_level >= DBG_ALL) {
1866 			logit("operation is INFO_OP_CREATE...\n");
1867 		}
1868 
1869 		/*
1870 		 * indicate that the server info is being
1871 		 * (re)created, so that the refresh thread
1872 		 * will not refresh the info list right
1873 		 * after the list got (re)created
1874 		 */
1875 		(void) mutex_lock(&info_mutex);
1876 		is_creating = creating;
1877 		creating = TRUE;
1878 		(void) mutex_unlock(&info_mutex);
1879 
1880 		if (is_creating)
1881 			break;
1882 		/*
1883 		 * create an empty info list
1884 		 */
1885 		(void) getldap_init_serverInfo(&serverInfo_1);
1886 		/*
1887 		 * exit if list not created
1888 		 */
1889 		if (serverInfo_1 == NULL) {
1890 			(void) mutex_lock(&info_mutex);
1891 			creating = FALSE;
1892 			(void) mutex_unlock(&info_mutex);
1893 			break;
1894 		}
1895 		/*
1896 		 * make the new server info available:
1897 		 * use writer lock here, so that the switch
1898 		 * is done after all the reader locks have
1899 		 * been released.
1900 		 */
1901 		(void) rw_wrlock(&info_lock);
1902 		serverInfo = serverInfo_1;
1903 		/*
1904 		 * if this is the first time
1905 		 * the server list is being created,
1906 		 * (i.e., serverInfo_old is NULL)
1907 		 * make the old list same as the new
1908 		 * so the GETSERVER code can do its work
1909 		 */
1910 		if (serverInfo_old == NULL)
1911 			serverInfo_old = serverInfo_1;
1912 		(void) rw_unlock(&info_lock);
1913 
1914 		/*
1915 		 * fill the new info list
1916 		 */
1917 		(void) rw_rdlock(&info_lock);
1918 		/* reset bind time (tcptimeout) */
1919 		(void) getldap_set_serverInfo(serverInfo, 1);
1920 
1921 		(void) mutex_lock(&info_mutex);
1922 		/*
1923 		 * set cache manager server list TTL,
1924 		 * set refresh_ttl to zero to indicate a fresh one
1925 		 */
1926 		refresh_ttl = 0;
1927 		(void) getldap_set_refresh_ttl(serverInfo,
1928 		    &refresh_ttl, &no_server_good);
1929 		sec_to_refresh = refresh_ttl;
1930 
1931 		/* statistics: previous refresh time */
1932 		if (gettimeofday(&tp, NULL) == 0)
1933 			prev_refresh = tp.tv_sec;
1934 
1935 		creating = FALSE;
1936 
1937 		/*
1938 		 * if no server found or available,
1939 		 * tell the server info refresh thread
1940 		 * to start the "no-server" refresh loop
1941 		 * otherwise reset the in_no_server_mode flag
1942 		 */
1943 		if (no_server_good) {
1944 			sec_to_refresh = 0;
1945 			in_no_server_mode = TRUE;
1946 		} else
1947 			in_no_server_mode = FALSE;
1948 		/*
1949 		 * awake the sleeping refresh thread
1950 		 */
1951 		(void) cond_signal(&info_cond);
1952 
1953 		(void) mutex_unlock(&info_mutex);
1954 		(void) rw_unlock(&info_lock);
1955 
1956 		/*
1957 		 * delete the old server info
1958 		 */
1959 		(void) rw_wrlock(&info_lock_old);
1960 		if (serverInfo_old != serverInfo)
1961 			(void) getldap_destroy_serverInfo(serverInfo_old);
1962 		/*
1963 		 * serverInfo_old needs to be the same as
1964 		 * serverinfo now.
1965 		 * it will be used by GETSERVER processing.
1966 		 */
1967 		serverInfo_old = serverInfo;
1968 		(void) rw_unlock(&info_lock_old);
1969 		break;
1970 	case INFO_OP_DELETE:
1971 		if (current_admin.debug_level >= DBG_ALL) {
1972 			logit("operation is INFO_OP_DELETE...\n");
1973 		}
1974 		/*
1975 		 * use writer lock here, so that the delete would
1976 		 * not start until all the reader locks have
1977 		 * been released.
1978 		 */
1979 		(void) rw_wrlock(&info_lock);
1980 		if (serverInfo)
1981 			(void) getldap_destroy_serverInfo(serverInfo);
1982 		serverInfo = NULL;
1983 		(void) rw_unlock(&info_lock);
1984 		break;
1985 	case INFO_OP_REFRESH:
1986 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1987 			logit("operation is INFO_OP_REFRESH...\n");
1988 		}
1989 		/*
1990 		 * if server info is currently being
1991 		 * (re)created, do nothing
1992 		 */
1993 		(void) mutex_lock(&info_mutex);
1994 		is_creating = creating;
1995 		(void) mutex_unlock(&info_mutex);
1996 		if (is_creating)
1997 			break;
1998 
1999 		(void) rw_rdlock(&info_lock);
2000 		if (serverInfo) {
2001 			/* do not reset bind time (tcptimeout) */
2002 			(void) getldap_set_serverInfo(serverInfo, 0);
2003 
2004 			(void) mutex_lock(&info_mutex);
2005 
2006 			/* statistics: previous refresh time */
2007 			if (gettimeofday(&tp, NULL) == 0)
2008 				prev_refresh = tp.tv_sec;
2009 			/*
2010 			 * set cache manager server list TTL
2011 			 */
2012 			(void) getldap_set_refresh_ttl(serverInfo,
2013 			    &refresh_ttl, &no_server_good);
2014 			/*
2015 			 * if no good server found,
2016 			 * tell the server info refresh thread
2017 			 * to start the "no-server" refresh loop
2018 			 * otherwise reset the in_no_server_mode flag
2019 			 */
2020 			if (no_server_good) {
2021 				in_no_server_mode = TRUE;
2022 				sec_to_refresh = 0;
2023 			} else {
2024 				in_no_server_mode = FALSE;
2025 				sec_to_refresh = refresh_ttl;
2026 			}
2027 			if (current_admin.debug_level >=
2028 			    DBG_SERVER_LIST_REFRESH) {
2029 				logit("getldap_serverInfo_op("
2030 				    "INFO_OP_REFRESH):"
2031 				    " seconds refresh: %d second(s)....\n",
2032 				    sec_to_refresh);
2033 			}
2034 			(void) mutex_unlock(&info_mutex);
2035 		}
2036 		(void) rw_unlock(&info_lock);
2037 
2038 		break;
2039 	case INFO_OP_REFRESH_WAIT:
2040 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
2041 			logit("operation is INFO_OP_REFRESH_WAIT...\n");
2042 		}
2043 		(void) cond_init(&info_cond, NULL, NULL);
2044 		(void) mutex_lock(&info_mutex);
2045 		err = 0;
2046 		while (err != ETIME) {
2047 			int sleeptime;
2048 			/*
2049 			 * if need to go into the "no-server" refresh
2050 			 * loop, set timout value to
2051 			 * REFRESH_DELAY_WHEN_NO_SERVER
2052 			 */
2053 			if (sec_to_refresh == 0) {
2054 				sec_to_refresh = refresh_ttl;
2055 				timeout.tv_sec = time(NULL) +
2056 				    REFRESH_DELAY_WHEN_NO_SERVER;
2057 				sleeptime = REFRESH_DELAY_WHEN_NO_SERVER;
2058 				if (current_admin.debug_level >=
2059 				    DBG_SERVER_LIST_REFRESH) {
2060 					logit("getldap_serverInfo_op("
2061 					    "INFO_OP_REFRESH_WAIT):"
2062 					    " entering no-server "
2063 					    "refresh loop...\n");
2064 				}
2065 			} else {
2066 				timeout.tv_sec = time(NULL) + sec_to_refresh;
2067 				sleeptime = sec_to_refresh;
2068 			}
2069 			timeout.tv_nsec = 0;
2070 
2071 			/* statistics: next refresh time */
2072 			next_refresh = timeout.tv_sec;
2073 
2074 			if (current_admin.debug_level >=
2075 			    DBG_SERVER_LIST_REFRESH) {
2076 				logit("getldap_serverInfo_op("
2077 				    "INFO_OP_REFRESH_WAIT):"
2078 				    " about to sleep for %d second(s)...\n",
2079 				    sleeptime);
2080 			}
2081 			err = cond_timedwait(&info_cond,
2082 			    &info_mutex, &timeout);
2083 		}
2084 		(void) cond_destroy(&info_cond);
2085 		(void) mutex_unlock(&info_mutex);
2086 		break;
2087 	case INFO_OP_GETSERVER:
2088 		if (current_admin.debug_level >= DBG_ALL) {
2089 			logit("operation is INFO_OP_GETSERVER...\n");
2090 		}
2091 		*output = NULL;
2092 		/*
2093 		 * GETSERVER processing always use
2094 		 * serverInfo_old to retrieve server infomation.
2095 		 * serverInfo_old is equal to serverInfo
2096 		 * most of the time, except when a new
2097 		 * server list is being created.
2098 		 * This is why the check for is_creating
2099 		 * is needed below.
2100 		 */
2101 		(void) rw_rdlock(&info_lock_old);
2102 
2103 		if (serverInfo_old == NULL) {
2104 			(void) rw_unlock(&info_lock_old);
2105 			break;
2106 		} else
2107 			(void) getldap_get_serverInfo(serverInfo_old,
2108 			    input, output, &server_removed);
2109 		(void) rw_unlock(&info_lock_old);
2110 
2111 		/*
2112 		 * if server info is currently being
2113 		 * (re)created, do nothing
2114 		 */
2115 
2116 		(void) mutex_lock(&info_mutex);
2117 		is_creating = creating;
2118 		(void) mutex_unlock(&info_mutex);
2119 		if (is_creating)
2120 			break;
2121 
2122 		/*
2123 		 * set cache manager server list TTL if necessary
2124 		 */
2125 		if (*output == NULL || server_removed) {
2126 			(void) rw_rdlock(&info_lock);
2127 			(void) mutex_lock(&info_mutex);
2128 
2129 			(void) getldap_set_refresh_ttl(serverInfo,
2130 			    &refresh_ttl, &no_server_good);
2131 
2132 			/*
2133 			 * if no good server found, need to go into
2134 			 * the "no-server" refresh loop
2135 			 * to find a server as soon as possible
2136 			 * otherwise reset the in_no_server_mode flag
2137 			 */
2138 			if (no_server_good) {
2139 				/*
2140 				 * if already in no-server mode,
2141 				 * don't brother
2142 				 */
2143 				if (in_no_server_mode == FALSE) {
2144 					sec_to_refresh = 0;
2145 					in_no_server_mode = TRUE;
2146 					(void) cond_signal(&info_cond);
2147 				}
2148 				(void) mutex_unlock(&info_mutex);
2149 				(void) rw_unlock(&info_lock);
2150 				break;
2151 			} else {
2152 				in_no_server_mode = FALSE;
2153 				sec_to_refresh = refresh_ttl;
2154 			}
2155 			/*
2156 			 * if the refresh thread will be timed out
2157 			 * longer than refresh_ttl seconds,
2158 			 * wake it up to make it wait on the new
2159 			 * time out value
2160 			 */
2161 			new_timeout.tv_sec = time(NULL) + refresh_ttl;
2162 			if (new_timeout.tv_sec < timeout.tv_sec)
2163 				(void) cond_signal(&info_cond);
2164 
2165 			(void) mutex_unlock(&info_mutex);
2166 			(void) rw_unlock(&info_lock);
2167 		}
2168 		break;
2169 	case INFO_OP_GETSTAT:
2170 		if (current_admin.debug_level >= DBG_ALL) {
2171 			logit("operation is INFO_OP_GETSTAT...\n");
2172 		}
2173 		*output = NULL;
2174 		(void) rw_rdlock(&info_lock);
2175 		if (serverInfo) {
2176 			(void) getldap_get_server_stat(serverInfo,
2177 			    output, &prev_refresh, &next_refresh);
2178 		}
2179 		(void) rw_unlock(&info_lock);
2180 		break;
2181 	default:
2182 		logit("getldap_serverInfo_op(): "
2183 		    "invalid operation code (%d).\n", op);
2184 		return (-1);
2185 		break;
2186 	}
2187 	return (NS_LDAP_SUCCESS);
2188 }
2189 
2190 void
2191 getldap_serverInfo_refresh()
2192 {
2193 	int always = 1;
2194 
2195 	if (current_admin.debug_level >= DBG_ALL) {
2196 		logit("getldap_serverInfo_refresh()...\n");
2197 	}
2198 
2199 	/* create the server info list */
2200 	(void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2201 
2202 	while (always) {
2203 		/*
2204 		 * the operation INFO_OP_REFRESH_WAIT
2205 		 * causes this thread to wait until
2206 		 * it is time to do refresh,
2207 		 * see getldap_serverInfo_op() for details
2208 		 */
2209 		(void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT, NULL, NULL);
2210 		(void) getldap_serverInfo_op(INFO_OP_REFRESH, NULL, NULL);
2211 	}
2212 }
2213 
2214 void
2215 getldap_getserver(LineBuf *config_info, ldap_call_t *in)
2216 {
2217 	char 		req[] = "0";
2218 
2219 	if (current_admin.debug_level >= DBG_ALL) {
2220 		logit("getldap_getserver()...\n");
2221 	}
2222 
2223 	config_info->len = 0;
2224 
2225 	/* make sure the request is valid */
2226 	req[0] = (in->ldap_u.servername)[0];
2227 	if ((req[0] != '\0') &&
2228 	    (strcmp(req, NS_CACHE_NEW) != 0) &&
2229 	    (strcmp(req, NS_CACHE_NORESP)  != 0) &&
2230 	    (strcmp(req, NS_CACHE_NEXT)    != 0) &&
2231 	    (strcmp(req, NS_CACHE_WRITE)   != 0)) {
2232 		return;
2233 	}
2234 
2235 	(void) getldap_serverInfo_op(INFO_OP_GETSERVER,
2236 	    in->ldap_u.domainname, &config_info->str);
2237 
2238 	if (config_info->str == NULL)
2239 		return;
2240 
2241 	config_info->len = strlen(config_info->str) + 1;
2242 
2243 	if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2244 		/* Log server IP */
2245 		char	*ptr,
2246 		    separator;
2247 		ptr = strstr(config_info->str, DOORLINESEP);
2248 		if (ptr) {
2249 			separator = *ptr;
2250 			*ptr = '\0';
2251 			logit("getldap_getserver: got server %s\n",
2252 			    config_info->str);
2253 			*ptr = separator;
2254 		} else
2255 			logit("getldap_getserver: Missing %s."
2256 			    " Internal error\n", DOORLINESEP);
2257 	}
2258 }
2259 
2260 void
2261 getldap_get_cacheData(LineBuf *config_info, ldap_call_t *in)
2262 {
2263 	char	*instr = NULL;
2264 	int	datatype = CACHE_MAP_UNKNOWN;
2265 
2266 	if (current_admin.debug_level >= DBG_ALL) {
2267 		logit("getldap_get_cacheData()...\n");
2268 	}
2269 
2270 	config_info->len = 0;
2271 	config_info->str = NULL;
2272 
2273 	/* make sure the request is valid */
2274 	if (strncmp(in->ldap_u.servername,
2275 	    NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2276 		datatype = CACHE_MAP_DN2DOMAIN;
2277 
2278 	if (datatype == CACHE_MAP_UNKNOWN)
2279 		return;
2280 
2281 	instr = strstr(in->ldap_u.servername, DOORLINESEP);
2282 	if (instr == NULL)
2283 		return;
2284 	instr += strlen(DOORLINESEP);
2285 	if (*instr == '\0')
2286 		return;
2287 
2288 	(void) getldap_cache_op(CACHE_OP_FIND, datatype,
2289 	    instr, &config_info->str);
2290 
2291 	if (config_info->str != NULL) {
2292 		config_info->len = strlen(config_info->str) + 1;
2293 	}
2294 }
2295 
2296 int
2297 getldap_set_cacheData(ldap_call_t *in)
2298 {
2299 	char	*instr1 = NULL;
2300 	char	*instr2 = NULL;
2301 	int	datatype = CACHE_MAP_UNKNOWN;
2302 	int	rc = 0;
2303 
2304 	if (current_admin.debug_level >= DBG_ALL) {
2305 		logit("getldap_set_cacheData()...\n");
2306 	}
2307 
2308 	/* make sure the request is valid */
2309 	if (strncmp(in->ldap_u.servername,
2310 	    NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2311 		datatype = CACHE_MAP_DN2DOMAIN;
2312 
2313 	if (datatype == CACHE_MAP_UNKNOWN)
2314 		return (-1);
2315 
2316 	instr1 = strstr(in->ldap_u.servername, DOORLINESEP);
2317 	if (instr1 == NULL)
2318 		return (-1);
2319 	*instr1 = '\0';
2320 	instr1 += strlen(DOORLINESEP);
2321 	if (*instr1 == '\0')
2322 		return (-1);
2323 	instr2 = strstr(instr1, DOORLINESEP);
2324 	if (instr2 == NULL)
2325 		return (-1);
2326 	*instr2 = '\0';
2327 	instr2 += strlen(DOORLINESEP);
2328 	if (*instr2 == '\0')
2329 		return (-1);
2330 
2331 	rc = getldap_cache_op(CACHE_OP_ADD, datatype,
2332 	    instr1, &instr2);
2333 	if (rc != NS_LDAP_SUCCESS)
2334 		return (-1);
2335 
2336 	return (0);
2337 }
2338 
2339 void
2340 getldap_get_cacheStat(LineBuf *stat_info)
2341 {
2342 	char	*foutstr = NULL;
2343 	char	*soutstr = NULL;
2344 	char	*coutstr = NULL;
2345 	int	infoSize;
2346 
2347 	if (current_admin.debug_level >= DBG_ALL) {
2348 		logit("getldap_get_cacheStat()...\n");
2349 	}
2350 
2351 	stat_info->str = NULL;
2352 	stat_info->len = 0;
2353 
2354 	/* get refersh statisitcs */
2355 	(void) getldap_get_refresh_stat(&foutstr);
2356 	if (foutstr == NULL)
2357 		return;
2358 
2359 	/* get server statisitcs */
2360 	(void) getldap_serverInfo_op(INFO_OP_GETSTAT, NULL, &soutstr);
2361 	if (soutstr == NULL) {
2362 		free(foutstr);
2363 		return;
2364 	}
2365 	/* get cache data statisitcs */
2366 	(void) getldap_cache_op(CACHE_OP_GETSTAT, NULL, NULL, &coutstr);
2367 	if (coutstr == NULL) {
2368 		free(foutstr);
2369 		free(soutstr);
2370 		return;
2371 	}
2372 
2373 	infoSize = strlen(foutstr) + strlen(soutstr) + strlen(coutstr) + 3;
2374 	stat_info->str = calloc(infoSize, sizeof (char));
2375 	if (stat_info->str != NULL) {
2376 		(void) strncpy(stat_info->str,
2377 		    foutstr,
2378 		    strlen(foutstr) + 1);
2379 		(void) strncat(stat_info->str,
2380 		    soutstr,
2381 		    strlen(soutstr) + 1);
2382 		(void) strncat(stat_info->str,
2383 		    coutstr,
2384 		    strlen(coutstr) + 1);
2385 		stat_info->len = infoSize;
2386 	}
2387 
2388 	free(foutstr);
2389 	free(soutstr);
2390 	free(coutstr);
2391 }
2392 
2393 static int
2394 checkupdate(int sighup)
2395 {
2396 	int	value;
2397 
2398 	(void) rw_wrlock(&ldap_lock);
2399 	value = sighup;
2400 	(void) rw_unlock(&ldap_lock);
2401 
2402 	return (value == TRUE);
2403 }
2404 
2405 
2406 static int
2407 update_from_profile()
2408 {
2409 	ns_ldap_result_t *result = NULL;
2410 	char		searchfilter[BUFSIZ];
2411 	ns_ldap_error_t	*error;
2412 	int		rc;
2413 	void		**paramVal = NULL;
2414 	ns_config_t	*ptr = NULL;
2415 	char		*profile = NULL;
2416 	char		errstr[MAXERROR];
2417 
2418 	if (current_admin.debug_level >= DBG_ALL) {
2419 		logit("update_from_profile....\n");
2420 	}
2421 	do {
2422 		(void) rw_wrlock(&ldap_lock);
2423 		sighup_update = FALSE;
2424 		(void) rw_unlock(&ldap_lock);
2425 
2426 		if ((rc = __ns_ldap_getParam(NS_LDAP_PROFILE_P,
2427 		    &paramVal, &error)) != NS_LDAP_SUCCESS) {
2428 			if (error != NULL && error->message != NULL)
2429 				logit("Error: Unable to  profile name: %s\n",
2430 				    error->message);
2431 			else {
2432 				char *tmp;
2433 
2434 				__ns_ldap_err2str(rc, &tmp);
2435 				logit("Error: Unable to  profile name: %s\n",
2436 				    tmp);
2437 			}
2438 			(void) __ns_ldap_freeParam(&paramVal);
2439 			(void) __ns_ldap_freeError(&error);
2440 			return (-1);
2441 		}
2442 
2443 		if (paramVal && *paramVal)
2444 			profile = strdup((char *)*paramVal);
2445 		(void) __ns_ldap_freeParam(&paramVal);
2446 
2447 		if (profile == NULL) {
2448 			return (-1);
2449 		}
2450 
2451 		(void) snprintf(searchfilter, BUFSIZ, _PROFILE_FILTER,
2452 		    _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
2453 
2454 		if ((rc = __ns_ldap_list(_PROFILE_CONTAINER,
2455 		    (const char *)searchfilter, NULL,
2456 		    NULL, NULL, 0,
2457 		    &result, &error, NULL, NULL)) != NS_LDAP_SUCCESS) {
2458 
2459 			/*
2460 			 * Is profile name the DEFAULTCONFIGNAME?
2461 			 * syslog Warning, otherwise syslog error.
2462 			 */
2463 			if (strcmp(profile, DEFAULTCONFIGNAME) == 0) {
2464 				syslog(LOG_WARNING,
2465 				    "Ignoring attempt to refresh nonexistent "
2466 				    "default profile: %s.\n",
2467 				    profile);
2468 				logit("Ignoring attempt to refresh nonexistent "
2469 				    "default profile: %s.\n",
2470 				    profile);
2471 			} else if ((error != NULL) &&
2472 			    (error->message != NULL)) {
2473 				syslog(LOG_ERR,
2474 				    "Error: Unable to refresh profile:%s:"
2475 				    " %s\n", profile, error->message);
2476 				logit("Error: Unable to refresh profile:"
2477 				    "%s:%s\n", profile, error->message);
2478 			} else {
2479 				syslog(LOG_ERR, "Error: Unable to refresh "
2480 				    "from profile:%s. (error=%d)\n",
2481 				    profile, rc);
2482 				logit("Error: Unable to refresh from profile "
2483 				    "%s (error=%d)\n", profile, rc);
2484 			}
2485 
2486 			(void) __ns_ldap_freeError(&error);
2487 			(void) __ns_ldap_freeResult(&result);
2488 			free(profile);
2489 			return (-1);
2490 		}
2491 		free(profile);
2492 
2493 
2494 	} while (checkupdate(sighup_update) == TRUE);
2495 
2496 	(void) rw_wrlock(&ldap_lock);
2497 
2498 	ptr = __ns_ldap_make_config(result);
2499 	(void) __ns_ldap_freeResult(&result);
2500 
2501 	if (ptr == NULL) {
2502 		logit("Error: __ns_ldap_make_config failed.\n");
2503 		(void) rw_unlock(&ldap_lock);
2504 		return (-1);
2505 	}
2506 
2507 	/*
2508 	 * cross check the config parameters
2509 	 */
2510 	if (__s_api_crosscheck(ptr, errstr, B_TRUE) == NS_SUCCESS) {
2511 		/*
2512 		 * reset the local profile TTL
2513 		 */
2514 		if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc)
2515 			current_admin.ldap_stat.ldap_ttl =
2516 			    atol(ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc);
2517 
2518 		if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2519 			logit("update_from_profile: reset profile TTL to %d"
2520 			    "  seconds\n",
2521 			    current_admin.ldap_stat.ldap_ttl);
2522 			logit("update_from_profile: expire time %ld "
2523 			    "seconds\n",
2524 			    ptr->paramList[NS_LDAP_EXP_P].ns_tm);
2525 		}
2526 
2527 		/* set ptr as current_config */
2528 		__s_api_init_config(ptr);
2529 		rc = 0;
2530 	} else {
2531 		__s_api_destroy_config(ptr);
2532 		logit("Error: downloaded profile failed to pass "
2533 		    "crosscheck (%s).\n", errstr);
2534 		syslog(LOG_ERR, "ldap_cachemgr: %s", errstr);
2535 		rc = -1;
2536 	}
2537 	(void) rw_unlock(&ldap_lock);
2538 
2539 	return (rc);
2540 }
2541 
2542 int
2543 getldap_init()
2544 {
2545 	ns_ldap_error_t	*error;
2546 	struct timeval	tp;
2547 
2548 	if (current_admin.debug_level >= DBG_ALL) {
2549 		logit("getldap_init()...\n");
2550 	}
2551 
2552 	(void) __ns_ldap_setServer(TRUE);
2553 
2554 	(void) rw_wrlock(&ldap_lock);
2555 	if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
2556 		logit("Error: Unable to read '%s': %s\n",
2557 		    NSCONFIGFILE, error->message);
2558 		(void) fprintf(stderr,
2559 		    gettext("\nError: Unable to read '%s': %s\n"),
2560 		    NSCONFIGFILE, error->message);
2561 		__ns_ldap_freeError(&error);
2562 		(void) rw_unlock(&ldap_lock);
2563 		return (-1);
2564 	}
2565 	(void) rw_unlock(&ldap_lock);
2566 
2567 	if (gettimeofday(&tp, NULL) == 0) {
2568 		/* statistics: previous refresh time */
2569 		prev_refresh_time = tp.tv_sec;
2570 	}
2571 
2572 	/* initialize the data cache */
2573 	(void) getldap_cache_op(CACHE_OP_CREATE,
2574 	    0, NULL, NULL);
2575 
2576 	return (0);
2577 }
2578 
2579 static void
2580 perform_update(void)
2581 {
2582 	ns_ldap_error_t	*error = NULL;
2583 	struct timeval	tp;
2584 	char		buf[20];
2585 	int		rc, rc1;
2586 	void		**paramVal = NULL;
2587 	ns_ldap_self_gssapi_config_t	config;
2588 
2589 	if (current_admin.debug_level >= DBG_ALL) {
2590 		logit("perform_update()...\n");
2591 	}
2592 
2593 	(void) __ns_ldap_setServer(TRUE);
2594 
2595 	if (gettimeofday(&tp, NULL) != 0)
2596 		return;
2597 
2598 	rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, &paramVal, &error);
2599 
2600 	if (rc == NS_LDAP_SUCCESS && paramVal != NULL) {
2601 		current_admin.ldap_stat.ldap_ttl = atol((char *)*paramVal);
2602 	}
2603 
2604 	if (error != NULL)
2605 		(void) __ns_ldap_freeError(&error);
2606 
2607 	if (paramVal != NULL)
2608 		(void) __ns_ldap_freeParam(&paramVal);
2609 
2610 	if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2611 		logit("perform_update: current profile TTL is %d seconds\n",
2612 		    current_admin.ldap_stat.ldap_ttl);
2613 	}
2614 
2615 	if (current_admin.ldap_stat.ldap_ttl > 0) {
2616 		/*
2617 		 * set the profile TTL parameter, just
2618 		 * in case that the downloading of
2619 		 * the profile from server would fail
2620 		 */
2621 
2622 		/*
2623 		 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2624 		 * It depends on NS_LDAP_CACHETTL_P to set it's value
2625 		 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2626 		 * can be set.
2627 		 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2628 		 * downloaded from the server, so is NS_LDAP_EXP_P.
2629 		 */
2630 		buf[19] = '\0'; /* null terminated the buffer */
2631 		if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P,
2632 		    lltostr((long long)current_admin.ldap_stat.ldap_ttl,
2633 		    &buf[19]),
2634 		    &error) != NS_LDAP_SUCCESS) {
2635 			logit("Error: __ns_ldap_setParam failed, status: %d "
2636 			    "message: %s\n", error->status, error->message);
2637 			(void)  __ns_ldap_freeError(&error);
2638 			return;
2639 		}
2640 
2641 		(void) rw_wrlock(&ldap_lock);
2642 		sighup_update = FALSE;
2643 		(void) rw_unlock(&ldap_lock);
2644 
2645 		do {
2646 			rc = update_from_profile();
2647 			if (rc != 0) {
2648 				logit("Error: Unable to update from profile\n");
2649 			}
2650 		} while (checkupdate(sighup_update) == TRUE);
2651 	} else {
2652 		rc = 0;
2653 	}
2654 
2655 	/*
2656 	 * recreate the server info list
2657 	 */
2658 	if (rc == 0) {
2659 		(void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2660 
2661 		/* flush the data cache */
2662 		(void) getldap_cache_op(CACHE_OP_DELETE,
2663 		    0, NULL, NULL);
2664 
2665 		/* statistics: previous refresh time */
2666 		prev_refresh_time = tp.tv_sec;
2667 	}
2668 	rc1 = __ns_ldap_self_gssapi_config(&config);
2669 	if (rc1 == NS_LDAP_SUCCESS) {
2670 		if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) {
2671 			rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error);
2672 			(void)  __ns_ldap_freeError(&error);
2673 			if (rc1 != NS_LDAP_SUCCESS) {
2674 				logit("Error: Check on self credential "
2675 				    "prerquesites failed: %d\n",
2676 				    rc1);
2677 				exit(rc1);
2678 			}
2679 		}
2680 	} else {
2681 		logit("Error: Failed to get self credential configuration %d\n",
2682 		    rc1);
2683 			exit(rc1);
2684 	}
2685 
2686 	(void) rw_rdlock(&ldap_lock);
2687 	if (((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) ||
2688 	    ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL)) {
2689 		logit("Error: __ns_ldap_DumpConfiguration failed, "
2690 		    "status: %d message: %s\n", error->status, error->message);
2691 		__ns_ldap_freeError(&error);
2692 		(void) rw_unlock(&ldap_lock);
2693 		return;
2694 	}
2695 	if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0) {
2696 		logit("Error: unlink failed - errno: %s\n", strerror(errno));
2697 		syslog(LOG_ERR, "Unable to refresh profile, LDAP configuration"
2698 		    "files not written");
2699 		(void) rw_unlock(&ldap_lock);
2700 		return;
2701 	}
2702 	if (rename(NSCREDREFRESH, NSCREDFILE) != 0) {
2703 		/*
2704 		 * We probably have inconsistent configuration at this point.
2705 		 * If we were to create a backup file and rename it here, that
2706 		 * operation might also fail. Consequently there is no safe way
2707 		 * to roll back.
2708 		 */
2709 		logit("Error: unlink failed - errno: %s\n", strerror(errno));
2710 		syslog(LOG_ERR, "Unable to refresh profile consistently, "
2711 		    "LDAP configuration files inconsistent");
2712 		(void) rw_unlock(&ldap_lock);
2713 		return;
2714 	}
2715 
2716 	(void) rw_unlock(&ldap_lock);
2717 }
2718 
2719 void
2720 getldap_refresh()
2721 {
2722 	struct timespec	timeout;
2723 	int		sleeptime;
2724 	struct timeval	tp;
2725 	long		expire = 0;
2726 	void		**paramVal = NULL;
2727 	ns_ldap_error_t	*errorp;
2728 	int		always = 1, err;
2729 	int		first_time = 1;
2730 	int		sig_done = 0;
2731 	int		dbg_level;
2732 
2733 	if (current_admin.debug_level >= DBG_ALL) {
2734 		logit("getldap_refresh()...\n");
2735 	}
2736 
2737 	/*
2738 	 * wait for an available server
2739 	 */
2740 	while (sig_done == 0) {
2741 		(void) mutex_lock(&sig_mutex);
2742 		sig_done = signal_done;
2743 		(void) mutex_unlock(&sig_mutex);
2744 	}
2745 
2746 	(void) __ns_ldap_setServer(TRUE);
2747 	while (always) {
2748 		dbg_level = current_admin.debug_level;
2749 		(void) rw_rdlock(&ldap_lock);
2750 		sleeptime = current_admin.ldap_stat.ldap_ttl;
2751 		if (dbg_level >= DBG_PROFILE_REFRESH) {
2752 			logit("getldap_refresh: current profile TTL is %d "
2753 			"seconds\n", current_admin.ldap_stat.ldap_ttl);
2754 		}
2755 		if (gettimeofday(&tp, NULL) == 0) {
2756 			if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
2757 			    &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
2758 			    paramVal != NULL &&
2759 			    (char *)*paramVal != NULL) {
2760 				errno = 0;
2761 				expire = atol((char *)*paramVal);
2762 				(void) __ns_ldap_freeParam(&paramVal);
2763 				if (errno == 0) {
2764 					if (expire == 0) {
2765 						first_time = 0;
2766 						(void) rw_unlock(&ldap_lock);
2767 						(void) cond_init(&cond,
2768 						    NULL, NULL);
2769 						(void) mutex_lock(&sighuplock);
2770 						timeout.tv_sec =
2771 						    CACHESLEEPTIME;
2772 						timeout.tv_nsec = 0;
2773 						if (dbg_level >=
2774 						    DBG_PROFILE_REFRESH) {
2775 							logit("getldap_refresh:"
2776 							    "(1)about to sleep"
2777 							    " for %d seconds\n",
2778 							    CACHESLEEPTIME);
2779 						}
2780 						err = cond_reltimedwait(&cond,
2781 						    &sighuplock, &timeout);
2782 						(void) cond_destroy(&cond);
2783 						(void) mutex_unlock(
2784 						    &sighuplock);
2785 						/*
2786 						 * if woke up by
2787 						 * getldap_revalidate(),
2788 						 * do update right away
2789 						 */
2790 						if (err == ETIME)
2791 							continue;
2792 						else {
2793 							/*
2794 							 * if load
2795 							 * configuration failed
2796 							 * don't do update
2797 							 */
2798 							if (load_config())
2799 								perform_update
2800 								    ();
2801 							continue;
2802 						}
2803 					}
2804 					sleeptime = expire - tp.tv_sec;
2805 					if (dbg_level >= DBG_PROFILE_REFRESH) {
2806 						logit("getldap_refresh: expire "
2807 						    "time = %ld\n", expire);
2808 					}
2809 
2810 				}
2811 			}
2812 		}
2813 
2814 		(void) rw_unlock(&ldap_lock);
2815 
2816 		/*
2817 		 * if this is the first time downloading
2818 		 * the profile or expire time already passed,
2819 		 * do not wait, do update
2820 		 */
2821 		if (first_time == 0 && sleeptime > 0) {
2822 			if (dbg_level >= DBG_PROFILE_REFRESH) {
2823 				logit("getldap_refresh: (2)about to sleep "
2824 				"for %d seconds\n", sleeptime);
2825 			}
2826 			(void) cond_init(&cond, NULL, NULL);
2827 			(void) mutex_lock(&sighuplock);
2828 			timeout.tv_sec = sleeptime;
2829 			timeout.tv_nsec = 0;
2830 			err = cond_reltimedwait(&cond,
2831 			    &sighuplock, &timeout);
2832 			(void) cond_destroy(&cond);
2833 			(void) mutex_unlock(&sighuplock);
2834 		}
2835 		/*
2836 		 * if load concfiguration failed
2837 		 * don't do update
2838 		 */
2839 		if (load_config())
2840 			perform_update();
2841 		first_time = 0;
2842 	}
2843 }
2844 
2845 void
2846 getldap_revalidate()
2847 {
2848 	if (current_admin.debug_level >= DBG_ALL) {
2849 		logit("getldap_revalidate()...\n");
2850 	}
2851 	/* block signal SIGHUP */
2852 	(void) sighold(SIGHUP);
2853 
2854 	/* now awake the sleeping refresh thread */
2855 	(void) cond_signal(&cond);
2856 
2857 	/* release signal SIGHUP */
2858 	(void) sigrelse(SIGHUP);
2859 
2860 }
2861 
2862 void
2863 getldap_lookup(LineBuf *config_info, ldap_call_t *in)
2864 {
2865 	ns_ldap_error_t	*error;
2866 
2867 	if (current_admin.debug_level >= DBG_ALL) {
2868 		logit("getldap_lookup()...\n");
2869 	}
2870 
2871 	(void) rw_rdlock(&ldap_lock);
2872 	if ((error = __ns_ldap_LoadDoorInfo(config_info,
2873 	    in->ldap_u.domainname)) != NULL) {
2874 		if (error != NULL && error->message != NULL)
2875 			logit("Error: ldap_lookup: %s\n", error->message);
2876 		(void) __ns_ldap_freeError(&error);
2877 
2878 		config_info->str = NULL;
2879 		config_info->len = 0;
2880 	}
2881 
2882 	(void) rw_unlock(&ldap_lock);
2883 }
2884