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