xref: /illumos-gate/usr/src/cmd/ldapcachemgr/cachemgr_getldap.c (revision bcd524b5c10222cf2a1ef37ac7ea8bf1baa3a2ee)
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 2006 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) + 2;
674 							(void) snprintf(
675 								rootDSE +
676 								strlen(rootDSE),
677 								len, "%s=%s%s",
678 								a, vals[i],
679 								DOORLINESEP);
680 						}
681 						ldap_value_free(vals);
682 					}
683 					ldap_memfree(a);
684 				}
685 				if (ber != NULL)
686 					ber_free(ber, 0);
687 			} else
688 				len = 0;
689 		}
690 	}
691 
692 	/* error, if no root DSE data */
693 	(void) mutex_lock(&serverInfo->mutex[1]);
694 	if (len == 0) {
695 		serverInfo->sinfo[1].errormsg =
696 			strdup(gettext("No root DSE data returned."));
697 		if (current_admin.debug_level >= DBG_ALL) {
698 			logit("getldap_get_rootDSE: %s.\n",
699 				serverInfo->sinfo[1].errormsg);
700 		}
701 		serverInfo->sinfo[1].type
702 				= INFO_RW_UNKNOWN;
703 		serverInfo->sinfo[1].info_status
704 				= INFO_STATUS_ERROR;
705 		serverInfo->sinfo[1].server_status 	= INFO_SERVER_ERROR;
706 		exitrc = -1;
707 	} else {
708 		/* assume writeable, i.e., can do modify */
709 		serverInfo->sinfo[1].type	= INFO_RW_WRITEABLE;
710 		serverInfo->sinfo[1].server_status
711 			= INFO_SERVER_UP;
712 		serverInfo->sinfo[1].info_status	= INFO_STATUS_NEW;
713 		/* remove the last DOORLINESEP */
714 		*(rootDSE+strlen(rootDSE)-1) = '\0';
715 		serverInfo->sinfo[1].rootDSE_data = rootDSE;
716 
717 		server_found = 1;
718 
719 		exitrc = NS_LDAP_SUCCESS;
720 	}
721 	(void) mutex_unlock(&serverInfo->mutex[1]);
722 
723 	if (resultMsg)
724 		ldap_msgfree(resultMsg);
725 	ldap_unbind(ld);
726 
727 	/*
728 	 * sync sinfo copies in the serverInfo.
729 	 * protected by mutex
730 	 */
731 	sync_current_with_update_copy(serverInfo);
732 	/*
733 	 * signal that the ldap_cachemgr parent process
734 	 * should exit now, if it is still waiting
735 	 */
736 	(void) mutex_lock(&sig_mutex);
737 	if (signal_done == FALSE && server_found) {
738 		ppid = getppid();
739 		(void) kill(ppid, SIGUSR1);
740 		if (current_admin.debug_level >= DBG_ALL) {
741 			logit("getldap_get_rootDSE(): "
742 				"SIGUSR1 signal sent to "
743 				"parent process(%ld).\n", ppid);
744 		}
745 		signal_done = TRUE;
746 	}
747 	(void) mutex_unlock(&sig_mutex);
748 
749 	thr_exit((void *) exitrc);
750 
751 	return ((void *) NULL);
752 }
753 
754 static int
755 getldap_init_serverInfo(server_info_t **head)
756 {
757 	char		**servers = NULL;
758 	int		rc = 0, i, exitrc = NS_LDAP_SUCCESS;
759 	ns_ldap_error_t *errorp = NULL;
760 	server_info_t	*info, *tail = NULL;
761 
762 	*head = NULL;
763 	if (current_admin.debug_level >= DBG_ALL) {
764 		logit("getldap_init_serverInfo()...\n");
765 	}
766 	rc = __s_api_getServers(&servers, &errorp);
767 
768 	if (rc != NS_LDAP_SUCCESS) {
769 		logit("getldap_init_serverInfo: "
770 			"__s_api_getServers failed.\n");
771 		if (errorp)
772 			__ns_ldap_freeError(&errorp);
773 		return (-1);
774 	}
775 	for (i = 0; servers[i] != NULL; i++) {
776 		info = (server_info_t *)calloc(1, sizeof (server_info_t));
777 		if (info == NULL) {
778 			logit("getldap_init_serverInfo: "
779 				"not enough memory.\n");
780 			exitrc = NS_LDAP_MEMORY;
781 			break;
782 		}
783 		if (i == 0) {
784 			*head = info;
785 			tail  = info;
786 		} else {
787 			tail->next = info;
788 			tail  = info;
789 		}
790 
791 		info->sinfo[0].addr		= strdup(servers[i]);
792 		if (info->sinfo[0].addr == NULL) {
793 			logit("getldap_init_serverInfo: "
794 				"not enough memory.\n");
795 			exitrc = NS_LDAP_MEMORY;
796 			break;
797 		}
798 		info->sinfo[1].addr		= strdup(servers[i]);
799 		if (info->sinfo[1].addr == NULL) {
800 			logit("getldap_init_serverInfo: "
801 				"not enough memory.\n");
802 			exitrc = NS_LDAP_MEMORY;
803 			break;
804 		}
805 
806 		info->sinfo[0].type 		= INFO_RW_UNKNOWN;
807 		info->sinfo[1].type 		= INFO_RW_UNKNOWN;
808 		info->sinfo[0].info_status	= INFO_STATUS_UNKNOWN;
809 		info->sinfo[1].info_status	= INFO_STATUS_UNKNOWN;
810 		info->sinfo[0].server_status	= INFO_SERVER_UNKNOWN;
811 		info->sinfo[1].server_status	= INFO_SERVER_UNKNOWN;
812 
813 		/*
814 		 * Assume at startup or after the configuration
815 		 * profile is refreshed, all servers are good.
816 		 */
817 		info->sinfo[0].prev_server_status =
818 					INFO_SERVER_UP;
819 		info->sinfo[1].prev_server_status =
820 					INFO_SERVER_UP;
821 		info->sinfo[0].hostname		= NULL;
822 		info->sinfo[1].hostname		= NULL;
823 		info->sinfo[0].rootDSE_data	= NULL;
824 		info->sinfo[1].rootDSE_data	= NULL;
825 		info->sinfo[0].errormsg 	= NULL;
826 		info->sinfo[1].errormsg 	= NULL;
827 		info->next 		= NULL;
828 	}
829 	__s_api_free2dArray(servers);
830 	if (exitrc != NS_LDAP_SUCCESS) {
831 		if (head && *head) {
832 			(void) getldap_destroy_serverInfo(*head);
833 			*head = NULL;
834 		}
835 	}
836 	return (exitrc);
837 }
838 
839 static int
840 getldap_destroy_serverInfo(server_info_t *head)
841 {
842 	server_info_t	*info, *next;
843 
844 	if (current_admin.debug_level >= DBG_ALL) {
845 		logit("getldap_destroy_serverInfo()...\n");
846 	}
847 
848 	if (head == NULL) {
849 		logit("getldap_destroy_serverInfo: "
850 			"invalid serverInfo list.\n");
851 		return (-1);
852 	}
853 
854 	for (info = head; info; info = next) {
855 		if (info->sinfo[0].addr)
856 			free(info->sinfo[0].addr);
857 		if (info->sinfo[1].addr)
858 			free(info->sinfo[1].addr);
859 		if (info->sinfo[0].hostname)
860 			free(info->sinfo[0].hostname);
861 		if (info->sinfo[1].hostname)
862 			free(info->sinfo[1].hostname);
863 		if (info->sinfo[0].rootDSE_data)
864 			free(info->sinfo[0].rootDSE_data);
865 		if (info->sinfo[1].rootDSE_data)
866 			free(info->sinfo[1].rootDSE_data);
867 		if (info->sinfo[0].errormsg)
868 			free(info->sinfo[0].errormsg);
869 		if (info->sinfo[1].errormsg)
870 			free(info->sinfo[1].errormsg);
871 		next = info->next;
872 		free(info);
873 	}
874 	return (NS_LDAP_SUCCESS);
875 }
876 
877 static int
878 getldap_set_serverInfo(server_info_t *head,
879 		int reset_bindtime)
880 {
881 	server_info_t	*info;
882 	int 		atleast1 = 0;
883 	thread_t	*tid;
884 	int 		num_threads = 0, i, j;
885 	void		*status;
886 	void		**paramVal = NULL;
887 	ns_ldap_error_t	*error = NULL;
888 
889 	if (current_admin.debug_level >= DBG_ALL) {
890 		logit("getldap_set_serverInfo()...\n");
891 	}
892 
893 	if (head == NULL) {
894 		logit("getldap_set_serverInfo: "
895 			"invalid serverInfo list.\n");
896 		return (-1);
897 	}
898 
899 	/* Get the bind timeout value */
900 	if (reset_bindtime == 1) {
901 		tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
902 		(void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P,
903 			&paramVal, &error);
904 		if (paramVal != NULL && *paramVal != NULL) {
905 			/* convert to milliseconds */
906 			tcptimeout = **((int **)paramVal);
907 			tcptimeout *= 1000;
908 			(void) __ns_ldap_freeParam(&paramVal);
909 		}
910 		if (error)
911 			(void) __ns_ldap_freeError(&error);
912 
913 		/* get search timeout value */
914 		search_timeout = NS_DEFAULT_SEARCH_TIMEOUT;
915 		(void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P,
916 			&paramVal, &error);
917 		if (paramVal != NULL && *paramVal != NULL) {
918 			search_timeout = **((int **)paramVal);
919 			(void) __ns_ldap_freeParam(&paramVal);
920 		}
921 		if (error)
922 			(void) __ns_ldap_freeError(&error);
923 
924 	}
925 
926 	for (info = head; info; info = info->next)
927 		num_threads++;
928 
929 	if (num_threads == 0) {
930 		logit("getldap_set_serverInfo: "
931 			"empty serverInfo list.\n");
932 		return (-1);
933 	}
934 
935 	tid = (thread_t *) calloc(1, sizeof (thread_t) * num_threads);
936 	if (tid == NULL) {
937 		logit("getldap_set_serverInfo: "
938 			"No memory to create thread ID list.\n");
939 		return (-1);
940 	}
941 
942 	for (info = head, i = 0; info; info = info->next, i++) {
943 		if (thr_create(NULL, 0,
944 			(void *(*)(void*))getldap_get_rootDSE,
945 			(void *)info, 0, &tid[i])) {
946 			logit("getldap_set_serverInfo: "
947 				"can not create thread %d.\n", i + 1);
948 			for (j = 0; j < i; j++)
949 				(void) thr_join(tid[j], NULL, NULL);
950 			free(tid);
951 			return (-1);
952 		}
953 	}
954 
955 	for (i = 0; i < num_threads; i++) {
956 		if (thr_join(tid[i], NULL, &status) == 0) {
957 			if ((int)status == NS_LDAP_SUCCESS)
958 				atleast1 = 1;
959 		}
960 	}
961 
962 	free(tid);
963 
964 	if (atleast1)
965 		return (NS_LDAP_SUCCESS);
966 	else
967 		return (-1);
968 }
969 
970 /*
971  * Convert an IP to a host name
972  */
973 static int
974 getldap_ip2hostname(char *ipaddr, char **hostname) {
975 	struct in_addr	in;
976 	struct in6_addr	in6;
977 	struct hostent	*hp = NULL;
978 	char	*start = NULL, *end = NULL, delim = '\0';
979 	char	*port = NULL, *addr = NULL;
980 	int	error_num = 0, len = 0;
981 
982 	if (ipaddr == NULL || hostname == NULL)
983 		return (NS_LDAP_INVALID_PARAM);
984 	*hostname = NULL;
985 	if ((addr = strdup(ipaddr)) == NULL)
986 		return (NS_LDAP_MEMORY);
987 
988 	if (addr[0] == '[') {
989 		/*
990 		 * Assume it's [ipv6]:port
991 		 * Extract ipv6 IP
992 		 */
993 		start = &addr[1];
994 		if ((end = strchr(addr, ']')) != NULL) {
995 			*end = '\0';
996 			delim = ']';
997 			if (*(end + 1) == ':')
998 				/* extract port */
999 				port = end + 2;
1000 		} else {
1001 			return (NS_LDAP_INVALID_PARAM);
1002 		}
1003 	} else if ((end = strchr(addr, ':')) != NULL) {
1004 		/* assume it's ipv4:port */
1005 		*end = '\0';
1006 		delim = ':';
1007 		start = addr;
1008 		port = end + 1;
1009 	} else
1010 		/* No port */
1011 		start = addr;
1012 
1013 
1014 	if (inet_pton(AF_INET, start, &in) == 1) {
1015 		/* IPv4 */
1016 		hp = getipnodebyaddr((char *)&in,
1017 			sizeof (struct in_addr), AF_INET, &error_num);
1018 		if (hp && hp->h_name) {
1019 			/* hostname + '\0' */
1020 			len = strlen(hp->h_name) + 1;
1021 			if (port)
1022 				/* ':' + port */
1023 				len += strlen(port) + 1;
1024 			if ((*hostname = malloc(len)) == NULL) {
1025 				free(addr);
1026 				freehostent(hp);
1027 				return (NS_LDAP_MEMORY);
1028 			}
1029 
1030 			if (port)
1031 				(void) snprintf(*hostname, len, "%s:%s",
1032 						hp->h_name, port);
1033 			else
1034 				(void) strlcpy(*hostname, hp->h_name, len);
1035 
1036 			free(addr);
1037 			freehostent(hp);
1038 			return (NS_LDAP_SUCCESS);
1039 		} else {
1040 			return (NS_LDAP_NOTFOUND);
1041 		}
1042 	} else if (inet_pton(AF_INET6, start, &in6) == 1) {
1043 		/* IPv6 */
1044 		hp = getipnodebyaddr((char *)&in6,
1045 			sizeof (struct in6_addr), AF_INET6, &error_num);
1046 		if (hp && hp->h_name) {
1047 			/* hostname + '\0' */
1048 			len = strlen(hp->h_name) + 1;
1049 			if (port)
1050 				/* ':' + port */
1051 				len += strlen(port) + 1;
1052 			if ((*hostname = malloc(len)) == NULL) {
1053 				free(addr);
1054 				freehostent(hp);
1055 				return (NS_LDAP_MEMORY);
1056 			}
1057 
1058 			if (port)
1059 				(void) snprintf(*hostname, len, "%s:%s",
1060 						hp->h_name, port);
1061 			else
1062 				(void) strlcpy(*hostname, hp->h_name, len);
1063 
1064 			free(addr);
1065 			freehostent(hp);
1066 			return (NS_LDAP_SUCCESS);
1067 		} else {
1068 			return (NS_LDAP_NOTFOUND);
1069 		}
1070 	} else {
1071 		/*
1072 		 * A hostname
1073 		 * Return it as is
1074 		 */
1075 		if (end)
1076 			*end = delim;
1077 		*hostname = addr;
1078 		return (NS_LDAP_SUCCESS);
1079 	}
1080 }
1081 /*
1082  * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
1083  * to this function from getldap_serverInfo_op().
1084  * input:
1085  *   a buffer containing an empty string (e.g., input[0]='\0';) or a string
1086  *   as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
1087  *   addr);
1088  *   where addr is the address of a server and
1089  *   req is one of the following:
1090  *   NS_CACHE_NEW:    send a new server address, addr is ignored.
1091  *   NS_CACHE_NORESP: send the next one, remove addr from list.
1092  *   NS_CACHE_NEXT:   send the next one, keep addr on list.
1093  *   NS_CACHE_WRITE:  send a non-replica server, if possible, if not, same
1094  *                    as NS_CACHE_NEXT.
1095  *   addrtype:
1096  *   NS_CACHE_ADDR_IP: return server address as is, this is default.
1097  *   NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
1098  *                           self credential case requires such format.
1099  * output:
1100  *   a buffer containing server info in the following format:
1101  *   serveraddress DOORLINESEP [ attr=value [DOORLINESEP attr=value ]...]
1102  *   for example: ( here | used as DOORLINESEP for visual purposes)
1103  *   1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
1104  *   NOTE: caller should free this buffer when done using it
1105  */
1106 static int
1107 getldap_get_serverInfo(server_info_t *head, char *input,
1108 		char **output, int *svr_removed)
1109 {
1110 	server_info_t	*info 	= NULL;
1111 	server_info_t	*server	= NULL;
1112 	char 		*addr	= NULL;
1113 	char 		*req	= NULL;
1114 	char 		req_new[] = NS_CACHE_NEW;
1115 	char 		addr_type[] = NS_CACHE_ADDR_IP;
1116 	int		matched = FALSE, len, rc = 0;
1117 	char		*ret_addr = NULL;
1118 
1119 	if (current_admin.debug_level >= DBG_ALL) {
1120 		logit("getldap_get_serverInfo()...\n");
1121 	}
1122 
1123 	if (input == NULL || output == NULL) {
1124 		logit("getldap_get_serverInfo: "
1125 			"No input or output buffer.\n");
1126 		return (-1);
1127 	}
1128 
1129 	*output = NULL;
1130 	*svr_removed = FALSE;
1131 
1132 	if (head == NULL) {
1133 		logit("getldap_get_serverInfo: "
1134 			"invalid serverInfo list.\n");
1135 		return (-1);
1136 	}
1137 	/*
1138 	 * parse the input string to get req and addr,
1139 	 * if input is empty, i.e., input[0] == '\0',
1140 	 * treat it as an NS_CACHE_NEW request
1141 	 */
1142 	req = req_new;
1143 	if (input[0] != '\0') {
1144 		req = input;
1145 		/* Save addr type flag */
1146 		addr_type[0] = input[1];
1147 		input[strlen(NS_CACHE_NEW)] = '\0';
1148 		/* skip acion type flag, addr type flag and DOORLINESEP */
1149 		addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW)
1150 			+ strlen(NS_CACHE_ADDR_IP);
1151 	}
1152 	/*
1153 	 * if NS_CACHE_NEW,
1154 	 * or the server info is new,
1155 	 * starts from the
1156 	 * beginning of the list
1157 	 */
1158 	if ((strcmp(req, NS_CACHE_NEW) == 0) ||
1159 		(head->sinfo[0].info_status == INFO_STATUS_NEW))
1160 		matched = TRUE;
1161 	for (info = head; info; info = info->next) {
1162 		/*
1163 		 * make sure the server info stays the same
1164 		 * while the data is being processed
1165 		 */
1166 
1167 		/*
1168 		 * This function is called to get server info list
1169 		 * and pass it back to door call clients.
1170 		 * Access the current copy (sinfo[0]) to get such
1171 		 * information
1172 		 */
1173 		(void) mutex_lock(&info->mutex[0]);
1174 
1175 		if (matched == FALSE &&
1176 			strcmp(info->sinfo[0].addr, addr) == 0) {
1177 			matched = TRUE;
1178 			if (strcmp(req, NS_CACHE_NORESP) == 0) {
1179 
1180 				/*
1181 				 * if the server has already been removed,
1182 				 * don't bother
1183 				 */
1184 				if (info->sinfo[0].server_status ==
1185 						INFO_SERVER_REMOVED) {
1186 					(void) mutex_unlock(&info->mutex[0]);
1187 					continue;
1188 				}
1189 
1190 				/*
1191 				 * if the information is new,
1192 				 * give this server one more chance
1193 				 */
1194 				if (info->sinfo[0].info_status ==
1195 						INFO_STATUS_NEW &&
1196 					info->sinfo[0].server_status  ==
1197 							INFO_SERVER_UP) {
1198 					server = info;
1199 					break;
1200 				} else {
1201 					/*
1202 					 * it is recommended that
1203 					 * before removing the
1204 					 * server from the list,
1205 					 * the server should be
1206 					 * contacted one more time
1207 					 * to make sure that it is
1208 					 * really unavailable.
1209 					 * For now, just trust the client
1210 					 * (i.e., the sldap library)
1211 					 * that it knows what it is
1212 					 * doing and would not try
1213 					 * to mess up the server
1214 					 * list.
1215 					 */
1216 					info->sinfo[0].prev_server_status =
1217 						info->sinfo[0].server_status;
1218 					info->sinfo[0].server_status  =
1219 						INFO_SERVER_REMOVED;
1220 					/*
1221 					 * make sure this will be seen
1222 					 * if a user query the server
1223 					 * status via the ldap_cachemgr's
1224 					 * -g option
1225 					 */
1226 					info->sinfo[1].server_status  =
1227 						INFO_SERVER_REMOVED;
1228 					*svr_removed = TRUE;
1229 					(void) mutex_unlock(&info->mutex[0]);
1230 					continue;
1231 				}
1232 			} else {
1233 				/*
1234 				 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
1235 				 */
1236 				(void) mutex_unlock(&info->mutex[0]);
1237 				continue;
1238 			}
1239 		}
1240 
1241 		if (matched) {
1242 			if (strcmp(req, NS_CACHE_WRITE) == 0) {
1243 				if (info->sinfo[0].type ==
1244 					INFO_RW_WRITEABLE &&
1245 					info->sinfo[0].server_status  ==
1246 						INFO_SERVER_UP) {
1247 					server = info;
1248 					break;
1249 				}
1250 			} else if (info->sinfo[0].server_status ==
1251 					INFO_SERVER_UP) {
1252 				server = info;
1253 				break;
1254 			}
1255 		}
1256 
1257 		(void) mutex_unlock(&info->mutex[0]);
1258 	}
1259 
1260 	if (server) {
1261 		if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) {
1262 			/*
1263 			 * In SASL/GSSAPI case, a hostname is required for
1264 			 * Kerberos's service principal.
1265 			 * e.g.
1266 			 * ldap/foo.sun.com@SUN.COM
1267 			 */
1268 			if (server->sinfo[0].hostname == NULL) {
1269 				rc = getldap_ip2hostname(server->sinfo[0].addr,
1270 					&server->sinfo[0].hostname);
1271 				if (rc != NS_LDAP_SUCCESS) {
1272 					(void) mutex_unlock(&info->mutex[0]);
1273 					return (rc);
1274 				}
1275 				if (current_admin.debug_level >= DBG_ALL) {
1276 					logit("getldap_get_serverInfo: "
1277 						"%s is converted to %s\n",
1278 						server->sinfo[0].addr,
1279 						server->sinfo[0].hostname);
1280 				}
1281 			}
1282 			ret_addr = server->sinfo[0].hostname;
1283 
1284 		} else
1285 			ret_addr = server->sinfo[0].addr;
1286 
1287 
1288 		len = strlen(ret_addr) +
1289 			strlen(server->sinfo[0].rootDSE_data) +
1290 			strlen(DOORLINESEP) + 1;
1291 		*output = (char *)malloc(len);
1292 		if (*output == NULL) {
1293 			(void) mutex_unlock(&info->mutex[0]);
1294 			return (NS_LDAP_MEMORY);
1295 		}
1296 		(void) snprintf(*output, len, "%s%s%s",
1297 			ret_addr, DOORLINESEP,
1298 			server->sinfo[0].rootDSE_data);
1299 		server->sinfo[0].info_status = INFO_STATUS_OLD;
1300 		(void) mutex_unlock(&info->mutex[0]);
1301 		return (NS_LDAP_SUCCESS);
1302 	}
1303 	else
1304 		return (-99);
1305 }
1306 
1307 /*
1308  * Format previous and next refresh time
1309  */
1310 static int
1311 getldap_format_refresh_time(char **output, time_t *prev, time_t *next)
1312 {
1313 #define	TIME_FORMAT	"%Y/%m/%d %H:%M:%S"
1314 #define	TIME_HEADER1	"  Previous refresh time: "
1315 #define	TIME_HEADER2	"  Next refresh time:     "
1316 	int		hdr1_len = strlen(gettext(TIME_HEADER1));
1317 	int		hdr2_len = strlen(gettext(TIME_HEADER2));
1318 	struct	tm 	tm;
1319 	char		nbuf[256];
1320 	char		pbuf[256];
1321 	int		len;
1322 
1323 	if (current_admin.debug_level >= DBG_ALL) {
1324 		logit("getldap_format_refresh_time()...\n");
1325 	}
1326 
1327 	*output = NULL;
1328 
1329 	/* format the time of previous refresh  */
1330 	if (*prev != 0) {
1331 		(void) localtime_r(prev, &tm);
1332 		(void) strftime(pbuf, sizeof (pbuf) - 1, TIME_FORMAT, &tm);
1333 	} else {
1334 		(void) strcpy(pbuf, gettext("NOT DONE"));
1335 	}
1336 
1337 	/* format the time of next refresh  */
1338 	if (*next != 0) {
1339 		(void) localtime_r(next, &tm);
1340 		(void) strftime(nbuf, sizeof (nbuf) - 1, TIME_FORMAT, &tm);
1341 	} else {
1342 		(void) strcpy(nbuf, gettext("NOT SET"));
1343 	}
1344 
1345 	len = hdr1_len + hdr2_len + strlen(nbuf) +
1346 			strlen(pbuf) + 2 * strlen(DOORLINESEP) + 1;
1347 
1348 	*output = malloc(len);
1349 	if (*output == NULL)
1350 		return (-1);
1351 
1352 	(void) snprintf(*output, len, "%s%s%s%s%s%s",
1353 		gettext(TIME_HEADER1), pbuf, DOORLINESEP,
1354 		gettext(TIME_HEADER2), nbuf, DOORLINESEP);
1355 
1356 	return (NS_LDAP_SUCCESS);
1357 }
1358 
1359 /*
1360  * getldap_get_server_stat processes the GETSTAT request passed
1361  * to this function from getldap_serverInfo_op().
1362  * output:
1363  *   a buffer containing info for all the servers.
1364  *   For each server, the data is in the following format:
1365  *   server: server address or name, status: unknown|up|down|removed DOORLINESEP
1366  *   for example: ( here | used as DOORLINESEP for visual purposes)
1367  *   server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1368  *   NOTE: caller should free this buffer when done using it
1369  */
1370 static int
1371 getldap_get_server_stat(server_info_t *head, char **output,
1372 		time_t *prev, time_t *next)
1373 {
1374 #define	S_HEADER	"Server information: "
1375 #define	S_FORMAT	"  server: %s, status: %s%s"
1376 #define	S_ERROR		"    error message: %s%s"
1377 	server_info_t	*info 	= NULL;
1378 	int	header_len = strlen(gettext(S_HEADER));
1379 	int	format_len = strlen(gettext(S_FORMAT));
1380 	int	error_len = strlen(gettext(S_ERROR));
1381 	int	len = header_len + strlen(DOORLINESEP);
1382 	int	len1 = 0;
1383 	char	*status, *output1 = NULL, *tmpptr;
1384 
1385 	*output = NULL;
1386 
1387 	if (current_admin.debug_level >= DBG_ALL) {
1388 		logit("getldap_get_server_stat()...\n");
1389 	}
1390 
1391 	if (head == NULL) {
1392 		logit("getldap_get_server_stat: "
1393 			"invalid serverInfo list.\n");
1394 		return (-1);
1395 	}
1396 
1397 	/* format previous and next refresh time */
1398 	(void) getldap_format_refresh_time(&output1, prev, next);
1399 	if (output1 == NULL)
1400 		return (-1);
1401 	len += strlen(output1);
1402 	len1 = len + strlen(DOORLINESEP) + 1;
1403 
1404 	*output = (char *)calloc(1, len1);
1405 	if (*output == NULL) {
1406 		free(output1);
1407 		return (-1);
1408 	}
1409 
1410 	/* insert header string and refresh time info */
1411 	(void) snprintf(*output, len1, "%s%s%s",
1412 		gettext(S_HEADER), DOORLINESEP, output1);
1413 
1414 	for (info = head; info; info = info->next) {
1415 
1416 		/*
1417 		 * make sure the server info stays the same
1418 		 * while the data is being processed
1419 		 */
1420 		(void) mutex_lock(&info->mutex[1]);
1421 
1422 		/*
1423 		 * When the updating process is under way(getldap_get_rootDSE)
1424 		 * the update copy(sinfo[1] is the latest copy.
1425 		 * When the updating process
1426 		 * is done, the current copy (sinfo[0]) has the latest status,
1427 		 * which is still identical to the update copy.
1428 		 * So update copy has the latest status.
1429 		 * Use the update copy(sinfo[1]) to show status
1430 		 * (ldap_cachemgr -g).
1431 		 *
1432 		 */
1433 
1434 		switch (info->sinfo[1].server_status) {
1435 		case INFO_SERVER_UNKNOWN:
1436 			status = gettext("UNKNOWN");
1437 			break;
1438 		case INFO_SERVER_CONNECTING:
1439 			status = gettext("CONNECTING");
1440 			break;
1441 		case INFO_SERVER_UP:
1442 			status = gettext("UP");
1443 			break;
1444 		case INFO_SERVER_ERROR:
1445 			status = gettext("ERROR");
1446 			break;
1447 		case INFO_SERVER_REMOVED:
1448 			status = gettext("REMOVED");
1449 			break;
1450 		}
1451 
1452 		len += format_len + strlen(status) +
1453 			strlen(info->sinfo[1].addr) +
1454 			strlen(DOORLINESEP);
1455 		if (info->sinfo[1].errormsg != NULL)
1456 			len += error_len +
1457 				strlen(info->sinfo[1].errormsg) +
1458 				strlen(DOORLINESEP);
1459 
1460 		tmpptr = (char *)realloc(*output, len);
1461 		if (tmpptr == NULL) {
1462 			free(output1);
1463 			free(*output);
1464 			*output = NULL;
1465 			(void) mutex_unlock(&info->mutex[1]);
1466 			return (-1);
1467 		} else
1468 			*output = tmpptr;
1469 
1470 		/* insert server IP addr or name and status */
1471 		len1 = len - strlen(*output);
1472 		(void) snprintf(*output + strlen(*output), len1,
1473 			gettext(S_FORMAT), info->sinfo[1].addr,
1474 				status, DOORLINESEP);
1475 		/* insert error message if any */
1476 		len1 = len - strlen(*output);
1477 		if (info->sinfo[1].errormsg != NULL)
1478 			(void) snprintf(*output + strlen(*output), len1,
1479 				gettext(S_ERROR),
1480 					info->sinfo[1].errormsg,
1481 					DOORLINESEP);
1482 
1483 		(void) mutex_unlock(&info->mutex[1]);
1484 
1485 	}
1486 
1487 	free(output1);
1488 	return (NS_LDAP_SUCCESS);
1489 }
1490 
1491 /*
1492  * Format and return the refresh time statistics
1493  */
1494 static int
1495 getldap_get_refresh_stat(char **output)
1496 {
1497 #define	R_HEADER0	"Configuration refresh information: "
1498 #define	R_HEADER1	"  Configured to NO REFRESH."
1499 	int		hdr0_len = strlen(gettext(R_HEADER0));
1500 	int		hdr1_len = strlen(gettext(R_HEADER1));
1501 	int		cache_ttl = -1, len = 0;
1502 	time_t 		expire = 0;
1503 	void		**paramVal = NULL;
1504 	ns_ldap_error_t	*errorp = NULL;
1505 	char		*output1 = NULL;
1506 
1507 	if (current_admin.debug_level >= DBG_ALL) {
1508 		logit("getldap_get_refresh_stat()...\n");
1509 	}
1510 
1511 	*output = NULL;
1512 
1513 	/* get configured cache TTL */
1514 	if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1515 		&paramVal, &errorp) == NS_LDAP_SUCCESS) &&
1516 		paramVal != NULL &&
1517 		(char *)*paramVal != NULL) {
1518 			cache_ttl = atol((char *)*paramVal);
1519 	} else {
1520 		if (errorp)
1521 			__ns_ldap_freeError(&errorp);
1522 	}
1523 	(void) __ns_ldap_freeParam(&paramVal);
1524 
1525 	/* cound not get cache TTL */
1526 	if (cache_ttl == -1)
1527 		return (-1);
1528 
1529 	if (cache_ttl == 0) {
1530 		len = hdr0_len + hdr1_len +
1531 			2 * strlen(DOORLINESEP) + 1;
1532 		*output = malloc(len);
1533 		if (*output == NULL)
1534 			return (-1);
1535 		(void) snprintf(*output, len, "%s%s%s%s",
1536 			gettext(R_HEADER0), DOORLINESEP,
1537 			gettext(R_HEADER1), DOORLINESEP);
1538 	} else {
1539 
1540 		/* get configuration expiration time */
1541 		if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
1542 			&paramVal, &errorp) == NS_LDAP_SUCCESS) &&
1543 			paramVal != NULL &&
1544 			(char *)*paramVal != NULL) {
1545 				expire = (time_t)atol((char *)*paramVal);
1546 		} else {
1547 			if (errorp)
1548 				__ns_ldap_freeError(&errorp);
1549 		}
1550 
1551 		(void) __ns_ldap_freeParam(&paramVal);
1552 
1553 		/* cound not get expiration time */
1554 		if (expire == -1)
1555 			return (-1);
1556 
1557 		/* format previous and next refresh time */
1558 		(void) getldap_format_refresh_time(&output1,
1559 			&prev_refresh_time, &expire);
1560 		if (output1 == NULL)
1561 			return (-1);
1562 
1563 		len = hdr0_len + strlen(output1) +
1564 				2 * strlen(DOORLINESEP) + 1;
1565 		*output = malloc(len);
1566 		if (*output == NULL) {
1567 			free(output1);
1568 			return (-1);
1569 		}
1570 		(void) snprintf(*output, len, "%s%s%s%s",
1571 			gettext(R_HEADER0), DOORLINESEP,
1572 			output1, DOORLINESEP);
1573 		free(output1);
1574 	}
1575 
1576 	return (NS_LDAP_SUCCESS);
1577 }
1578 
1579 static int
1580 getldap_get_cacheTTL()
1581 {
1582 	void		**paramVal = NULL;
1583 	ns_ldap_error_t	*error;
1584 	int		rc = 0, cachettl;
1585 
1586 
1587 	if (current_admin.debug_level >= DBG_ALL) {
1588 		logit("getldap_get_cacheTTL()....\n");
1589 	}
1590 
1591 	if ((rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1592 		&paramVal, &error)) != NS_LDAP_SUCCESS) {
1593 		if (error != NULL && error->message != NULL)
1594 			logit("Error: Unable to get configuration "
1595 				"refresh TTL: %s\n",
1596 				error->message);
1597 		else {
1598 			char *tmp;
1599 
1600 			__ns_ldap_err2str(rc, &tmp);
1601 			logit("Error: Unable to get configuration "
1602 				"refresh TTL: %s\n", tmp);
1603 		}
1604 		(void) __ns_ldap_freeParam(&paramVal);
1605 		(void) __ns_ldap_freeError(&error);
1606 		return (-1);
1607 	}
1608 	if (paramVal == NULL || (char *)*paramVal == NULL)
1609 			return (-1);
1610 	cachettl = atol((char *)*paramVal);
1611 	(void) __ns_ldap_freeParam(&paramVal);
1612 	return (cachettl);
1613 }
1614 
1615 
1616 /*
1617  * This function implements the adaptive server list refresh
1618  * algorithm used by ldap_cachemgr. The idea is to have the
1619  * refresh TTL adjust itself between maximum and minimum
1620  * values. If the server list has been walked three times
1621  * in a row without errors, the TTL will be doubled. This will
1622  * be done repeatedly until the maximum value is reached
1623  * or passed. If passed, the maximum value will be used.
1624  * If any time a server is found to be down/bad, either
1625  * after another server list walk or informed by libsldap via
1626  * the GETLDAPSERVER door calls, the TTL will be set to half
1627  * of its value, again repeatedly, but no less than the minimum
1628  * value. Also, at any time, if all the servers on the list
1629  * are found to be down/bad, the TTL will be set to minimum,
1630  * so that a "no-server" refresh loop should be entered to try
1631  * to find a good server as soon as possible. The caller
1632  * could check the no_gd_server flag for this situation.
1633  * The maximum and minimum values are initialized when the input
1634  * refresh_ttl is set to zero, this should occur during
1635  * ldap_cachemgr startup or every time the server list is
1636  * recreated after the configuration profile is refreshed
1637  * from an LDAP server. The maximum is set to the value of
1638  * the NS_LDAP_CACHETTL parameter (configuration profile
1639  * refresh TTL), but if it is zero (never refreshed) or can
1640  * not be retrieved, the maximum is set to the macro
1641  * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1642  * set to REFRESHTTL_MIN, which is the TCP connection timeout
1643  * (tcptimeout) set via the LDAP API ldap_set_option()
1644  * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1645  * This accounts for the maximum possible timeout value for an
1646  * LDAP TCP connect call.The first refresh TTL, initial value of
1647  * refresh_ttl, will be set to the smaller of the two,
1648  * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1649  * The idea is to have a low starting value and have the value
1650  * stay low if the network/server is unstable, but eventually
1651  * the value will move up to maximum and stay there if the
1652  * network/server is stable.
1653  */
1654 static int
1655 getldap_set_refresh_ttl(server_info_t *head, int *refresh_ttl,
1656 		int *no_gd_server)
1657 {
1658 #define	REFRESHTTL_REGULAR	600
1659 #define	REFRESHTTL_MAX		43200
1660 /* tcptimeout is in milliseconds */
1661 #define	REFRESHTTL_MIN		(tcptimeout/1000) + 10
1662 #define	UP_REFRESH_TTL_NUM	2
1663 
1664 	static mutex_t		refresh_mutex;
1665 	static int		refresh_ttl_max = 0;
1666 	static int		refresh_ttl_min = 0;
1667 	static int		num_walked_ok = 0;
1668 	int			num_servers = 0;
1669 	int			num_good_servers = 0;
1670 	int			num_prev_good_servers = 0;
1671 	server_info_t		*info;
1672 
1673 	/* allow one thread at a time */
1674 	(void) mutex_lock(&refresh_mutex);
1675 
1676 	if (current_admin.debug_level >= DBG_ALL) {
1677 		logit("getldap_set_refresh_ttl()...\n");
1678 	}
1679 
1680 	if (!head || !refresh_ttl || !no_gd_server) {
1681 		logit("getldap_set_refresh_ttl: head is "
1682 			"NULL or refresh_ttl is NULL or "
1683 			"no_gd_server is NULL");
1684 		(void) mutex_unlock(&refresh_mutex);
1685 		return (-1);
1686 	}
1687 	*no_gd_server = FALSE;
1688 
1689 	/*
1690 	 * init max. min. TTLs if first time through or a fresh one
1691 	 */
1692 	if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1693 		logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1694 			"seconds\n", *refresh_ttl);
1695 	}
1696 	if (*refresh_ttl == 0) {
1697 		num_walked_ok = 0;
1698 		/*
1699 		 * init cache manager server list TTL:
1700 		 *
1701 		 * init the min. TTL to
1702 		 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1703 		 */
1704 		refresh_ttl_min = REFRESHTTL_MIN;
1705 
1706 		/*
1707 		 * try to set the max. TTL to
1708 		 * configuration refresh TTL (NS_LDAP_CACHETTL),
1709 		 * if error (-1), or never refreshed (0),
1710 		 * set it to REFRESHTTL_MAX (12 hours)
1711 		 */
1712 		refresh_ttl_max = getldap_get_cacheTTL();
1713 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1714 			logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1715 				"seconds\n", *refresh_ttl);
1716 			logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1717 				"min ttl is %d seconds\n",
1718 				refresh_ttl_max, refresh_ttl_min);
1719 		}
1720 		if (refresh_ttl_max <= 0)
1721 			refresh_ttl_max = REFRESHTTL_MAX;
1722 		else if (refresh_ttl_max < refresh_ttl_min)
1723 			refresh_ttl_max = refresh_ttl_min;
1724 
1725 		/*
1726 		 * init the first TTL to the smaller of the two:
1727 		 * REFRESHTTL_REGULAR ( 10 minutes),
1728 		 * (refresh_ttl_max + refresh_ttl_min)/2
1729 		 */
1730 		*refresh_ttl = REFRESHTTL_REGULAR;
1731 		if (*refresh_ttl > (refresh_ttl_max + refresh_ttl_min) / 2)
1732 			*refresh_ttl = (refresh_ttl_max + refresh_ttl_min) / 2;
1733 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1734 			logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1735 				"seconds\n", *refresh_ttl);
1736 			logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1737 				"min ttl is %d seconds\n",
1738 				refresh_ttl_max, refresh_ttl_min);
1739 		}
1740 	}
1741 
1742 	/*
1743 	 * get the servers statistics:
1744 	 * number of servers on list
1745 	 * number of good servers on list
1746 	 * number of pevious good servers on list
1747 	 */
1748 	for (info = head; info; info = info->next) {
1749 		num_servers++;
1750 		(void) mutex_lock(&info->mutex[0]);
1751 		if (info->sinfo[0].server_status  == INFO_SERVER_UP)
1752 			num_good_servers++;
1753 		/*
1754 		 * Server's previous status could be UNKNOWN
1755 		 * only between the very first and second
1756 		 * refresh. Treat that UNKNOWN status as up
1757 		 */
1758 		if (info->sinfo[0].prev_server_status
1759 				== INFO_SERVER_UP ||
1760 			info->sinfo[0].prev_server_status
1761 				== INFO_SERVER_UNKNOWN)
1762 			num_prev_good_servers++;
1763 		(void) mutex_unlock(&info->mutex[0]);
1764 	}
1765 
1766 	/*
1767 	 * if the server list is walked three times in a row
1768 	 * without problems, double the refresh TTL but no more
1769 	 * than the max. refresh TTL
1770 	 */
1771 	if (num_good_servers == num_servers) {
1772 		num_walked_ok++;
1773 		if (num_walked_ok > UP_REFRESH_TTL_NUM)  {
1774 
1775 			*refresh_ttl = *refresh_ttl * 2;
1776 			if (*refresh_ttl > refresh_ttl_max)
1777 				*refresh_ttl = refresh_ttl_max;
1778 
1779 			num_walked_ok = 0;
1780 		}
1781 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1782 			logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1783 				"seconds\n", *refresh_ttl);
1784 		}
1785 	} else if (num_good_servers == 0) {
1786 		/*
1787 		 * if no good server found,
1788 		 * set refresh TTL to miminum
1789 		 */
1790 		*refresh_ttl = refresh_ttl_min;
1791 		*no_gd_server = TRUE;
1792 		num_walked_ok = 0;
1793 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1794 			logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1795 				"seconds\n", *refresh_ttl);
1796 		}
1797 	} else if (num_prev_good_servers > num_good_servers) {
1798 		/*
1799 		 * if more down/bad servers found,
1800 		 * decrease the refresh TTL by half
1801 		 * but no less than the min. refresh TTL
1802 		 */
1803 		*refresh_ttl = *refresh_ttl / 2;
1804 		if (*refresh_ttl < refresh_ttl_min)
1805 			*refresh_ttl = refresh_ttl_min;
1806 		num_walked_ok = 0;
1807 		logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1808 			"seconds\n", *refresh_ttl);
1809 
1810 	}
1811 
1812 	if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1813 		logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1814 			*refresh_ttl);
1815 	}
1816 	(void) mutex_unlock(&refresh_mutex);
1817 	return (0);
1818 }
1819 
1820 static int
1821 getldap_serverInfo_op(info_op_t op, char *input, char **output)
1822 {
1823 
1824 	static rwlock_t 	info_lock = DEFAULTRWLOCK;
1825 	static rwlock_t 	info_lock_old = DEFAULTRWLOCK;
1826 	static mutex_t		info_mutex;
1827 	static cond_t		info_cond;
1828 	static int		creating = FALSE;
1829 	static int		refresh_ttl = 0;
1830 	static int		sec_to_refresh = 0;
1831 	static int		in_no_server_mode = FALSE;
1832 
1833 	static server_info_t 	*serverInfo = NULL;
1834 	static server_info_t 	*serverInfo_old = NULL;
1835 	server_info_t 		*serverInfo_1;
1836 	int 			is_creating;
1837 	int 			err, no_server_good = FALSE;
1838 	int 			server_removed = FALSE;
1839 	static struct timespec	timeout;
1840 	struct timespec		new_timeout;
1841 	struct timeval		tp;
1842 	static time_t		prev_refresh = 0, next_refresh = 0;
1843 
1844 	if (current_admin.debug_level >= DBG_ALL) {
1845 		logit("getldap_serverInfo_op()...\n");
1846 	}
1847 	switch (op) {
1848 	case INFO_OP_CREATE:
1849 		if (current_admin.debug_level >= DBG_ALL) {
1850 			logit("operation is INFO_OP_CREATE...\n");
1851 		}
1852 
1853 		/*
1854 		 * indicate that the server info is being
1855 		 * (re)created, so that the refresh thread
1856 		 * will not refresh the info list right
1857 		 * after the list got (re)created
1858 		 */
1859 		(void) mutex_lock(&info_mutex);
1860 		is_creating = creating;
1861 		creating = TRUE;
1862 		(void) mutex_unlock(&info_mutex);
1863 
1864 		if (is_creating)
1865 			break;
1866 		/*
1867 		 * create an empty info list
1868 		 */
1869 		(void) getldap_init_serverInfo(&serverInfo_1);
1870 		/*
1871 		 * exit if list not created
1872 		 */
1873 		if (serverInfo_1 == NULL) {
1874 			(void) mutex_lock(&info_mutex);
1875 			creating = FALSE;
1876 			(void) mutex_unlock(&info_mutex);
1877 			break;
1878 		}
1879 		/*
1880 		 * make the new server info available:
1881 		 * use writer lock here, so that the switch
1882 		 * is done after all the reader locks have
1883 		 * been released.
1884 		 */
1885 		(void) rw_wrlock(&info_lock);
1886 		serverInfo = serverInfo_1;
1887 		/*
1888 		 * if this is the first time
1889 		 * the server list is being created,
1890 		 * (i.e., serverInfo_old is NULL)
1891 		 * make the old list same as the new
1892 		 * so the GETSERVER code can do its work
1893 		 */
1894 		if (serverInfo_old == NULL)
1895 			serverInfo_old = serverInfo_1;
1896 		(void) rw_unlock(&info_lock);
1897 
1898 		/*
1899 		 * fill the new info list
1900 		 */
1901 		(void) rw_rdlock(&info_lock);
1902 		/* reset bind time (tcptimeout) */
1903 		(void) getldap_set_serverInfo(serverInfo, 1);
1904 
1905 		(void) mutex_lock(&info_mutex);
1906 		/*
1907 		 * set cache manager server list TTL,
1908 		 * set refresh_ttl to zero to indicate a fresh one
1909 		 */
1910 		refresh_ttl = 0;
1911 		(void) getldap_set_refresh_ttl(serverInfo,
1912 				&refresh_ttl, &no_server_good);
1913 		sec_to_refresh = refresh_ttl;
1914 
1915 		/* statistics: previous refresh time */
1916 		if (gettimeofday(&tp, NULL) == 0)
1917 			prev_refresh = tp.tv_sec;
1918 
1919 		creating = FALSE;
1920 
1921 		/*
1922 		 * if no server found or available,
1923 		 * tell the server info refresh thread
1924 		 * to start the "no-server" refresh loop
1925 		 * otherwise reset the in_no_server_mode flag
1926 		 */
1927 		if (no_server_good) {
1928 			sec_to_refresh = 0;
1929 			in_no_server_mode = TRUE;
1930 		} else
1931 			in_no_server_mode = FALSE;
1932 		/*
1933 		 * awake the sleeping refresh thread
1934 		 */
1935 		(void) cond_signal(&info_cond);
1936 
1937 		(void) mutex_unlock(&info_mutex);
1938 		(void) rw_unlock(&info_lock);
1939 
1940 		/*
1941 		 * delete the old server info
1942 		 */
1943 		(void) rw_wrlock(&info_lock_old);
1944 		if (serverInfo_old != serverInfo)
1945 			(void) getldap_destroy_serverInfo(serverInfo_old);
1946 		/*
1947 		 * serverInfo_old needs to be the same as
1948 		 * serverinfo now.
1949 		 * it will be used by GETSERVER processing.
1950 		 */
1951 		serverInfo_old = serverInfo;
1952 		(void) rw_unlock(&info_lock_old);
1953 		break;
1954 	case INFO_OP_DELETE:
1955 		if (current_admin.debug_level >= DBG_ALL) {
1956 			logit("operation is INFO_OP_DELETE...\n");
1957 		}
1958 		/*
1959 		 * use writer lock here, so that the delete would
1960 		 * not start until all the reader locks have
1961 		 * been released.
1962 		 */
1963 		(void) rw_wrlock(&info_lock);
1964 		if (serverInfo)
1965 			(void) getldap_destroy_serverInfo(serverInfo);
1966 		serverInfo = NULL;
1967 		(void) rw_unlock(&info_lock);
1968 		break;
1969 	case INFO_OP_REFRESH:
1970 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1971 			logit("operation is INFO_OP_REFRESH...\n");
1972 		}
1973 		/*
1974 		 * if server info is currently being
1975 		 * (re)created, do nothing
1976 		 */
1977 		(void) mutex_lock(&info_mutex);
1978 		is_creating = creating;
1979 		(void) mutex_unlock(&info_mutex);
1980 		if (is_creating)
1981 			break;
1982 
1983 		(void) rw_rdlock(&info_lock);
1984 		if (serverInfo) {
1985 			/* do not reset bind time (tcptimeout) */
1986 			(void) getldap_set_serverInfo(serverInfo, 0);
1987 
1988 			(void) mutex_lock(&info_mutex);
1989 
1990 			/* statistics: previous refresh time */
1991 			if (gettimeofday(&tp, NULL) == 0)
1992 				prev_refresh = tp.tv_sec;
1993 			/*
1994 			 * set cache manager server list TTL
1995 			 */
1996 			(void) getldap_set_refresh_ttl(serverInfo,
1997 				&refresh_ttl, &no_server_good);
1998 			/*
1999 			 * if no good server found,
2000 			 * tell the server info refresh thread
2001 			 * to start the "no-server" refresh loop
2002 			 * otherwise reset the in_no_server_mode flag
2003 			 */
2004 			if (no_server_good) {
2005 				in_no_server_mode = TRUE;
2006 				sec_to_refresh = 0;
2007 			} else {
2008 				in_no_server_mode = FALSE;
2009 				sec_to_refresh = refresh_ttl;
2010 			}
2011 			if (current_admin.debug_level >=
2012 				DBG_SERVER_LIST_REFRESH) {
2013 				logit("getldap_serverInfo_op("
2014 				"INFO_OP_REFRESH):"
2015 				" seconds refresh: %d second(s)....\n",
2016 				sec_to_refresh);
2017 			}
2018 			(void) mutex_unlock(&info_mutex);
2019 		}
2020 		(void) rw_unlock(&info_lock);
2021 
2022 		break;
2023 	case INFO_OP_REFRESH_WAIT:
2024 		if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
2025 			logit("operation is INFO_OP_REFRESH_WAIT...\n");
2026 		}
2027 		(void) cond_init(&info_cond, NULL, NULL);
2028 		(void) mutex_lock(&info_mutex);
2029 		err = 0;
2030 		while (err != ETIME) {
2031 			int sleeptime;
2032 			/*
2033 			 * if need to go into the "no-server" refresh
2034 			 * loop, set timout value to
2035 			 * REFRESH_DELAY_WHEN_NO_SERVER
2036 			 */
2037 			if (sec_to_refresh == 0) {
2038 				sec_to_refresh = refresh_ttl;
2039 				timeout.tv_sec = time(NULL) +
2040 					REFRESH_DELAY_WHEN_NO_SERVER;
2041 				sleeptime = REFRESH_DELAY_WHEN_NO_SERVER;
2042 				if (current_admin.debug_level >=
2043 					DBG_SERVER_LIST_REFRESH) {
2044 					logit("getldap_serverInfo_op("
2045 					"INFO_OP_REFRESH_WAIT):"
2046 					" entering no-server "
2047 					"refresh loop...\n");
2048 				}
2049 			} else {
2050 				timeout.tv_sec = time(NULL) + sec_to_refresh;
2051 				sleeptime = sec_to_refresh;
2052 			}
2053 			timeout.tv_nsec = 0;
2054 
2055 			/* statistics: next refresh time */
2056 			next_refresh = timeout.tv_sec;
2057 
2058 			if (current_admin.debug_level >=
2059 				DBG_SERVER_LIST_REFRESH) {
2060 				logit("getldap_serverInfo_op("
2061 				"INFO_OP_REFRESH_WAIT):"
2062 				" about to sleep for %d second(s)...\n",
2063 				sleeptime);
2064 			}
2065 			err = cond_timedwait(&info_cond,
2066 				&info_mutex, &timeout);
2067 		}
2068 		(void) cond_destroy(&info_cond);
2069 		(void) mutex_unlock(&info_mutex);
2070 		break;
2071 	case INFO_OP_GETSERVER:
2072 		if (current_admin.debug_level >= DBG_ALL) {
2073 			logit("operation is INFO_OP_GETSERVER...\n");
2074 		}
2075 		*output = NULL;
2076 		/*
2077 		 * GETSERVER processing always use
2078 		 * serverInfo_old to retrieve server infomation.
2079 		 * serverInfo_old is equal to serverInfo
2080 		 * most of the time, except when a new
2081 		 * server list is being created.
2082 		 * This is why the check for is_creating
2083 		 * is needed below.
2084 		 */
2085 		(void) rw_rdlock(&info_lock_old);
2086 
2087 		if (serverInfo_old == NULL) {
2088 			(void) rw_unlock(&info_lock_old);
2089 			break;
2090 		} else
2091 			(void) getldap_get_serverInfo(serverInfo_old,
2092 				input, output, &server_removed);
2093 		(void) rw_unlock(&info_lock_old);
2094 
2095 		/*
2096 		 * if server info is currently being
2097 		 * (re)created, do nothing
2098 		 */
2099 
2100 		(void) mutex_lock(&info_mutex);
2101 		is_creating = creating;
2102 		(void) mutex_unlock(&info_mutex);
2103 		if (is_creating)
2104 			break;
2105 
2106 		/*
2107 		 * set cache manager server list TTL if necessary
2108 		 */
2109 		if (*output == NULL || server_removed) {
2110 			(void) rw_rdlock(&info_lock);
2111 			(void) mutex_lock(&info_mutex);
2112 
2113 			(void) getldap_set_refresh_ttl(serverInfo,
2114 				&refresh_ttl, &no_server_good);
2115 
2116 			/*
2117 			 * if no good server found, need to go into
2118 			 * the "no-server" refresh loop
2119 			 * to find a server as soon as possible
2120 			 * otherwise reset the in_no_server_mode flag
2121 			 */
2122 			if (no_server_good) {
2123 				/*
2124 				 * if already in no-server mode,
2125 				 * don't brother
2126 				 */
2127 				if (in_no_server_mode == FALSE) {
2128 					sec_to_refresh = 0;
2129 					in_no_server_mode = TRUE;
2130 					(void) cond_signal(&info_cond);
2131 				}
2132 				(void) mutex_unlock(&info_mutex);
2133 				(void) rw_unlock(&info_lock);
2134 				break;
2135 			} else {
2136 				in_no_server_mode = FALSE;
2137 				sec_to_refresh = refresh_ttl;
2138 			}
2139 			/*
2140 			 * if the refresh thread will be timed out
2141 			 * longer than refresh_ttl seconds,
2142 			 * wake it up to make it wait on the new
2143 			 * time out value
2144 			 */
2145 			new_timeout.tv_sec = time(NULL) + refresh_ttl;
2146 			if (new_timeout.tv_sec < timeout.tv_sec)
2147 				(void) cond_signal(&info_cond);
2148 
2149 			(void) mutex_unlock(&info_mutex);
2150 			(void) rw_unlock(&info_lock);
2151 		}
2152 		break;
2153 	case INFO_OP_GETSTAT:
2154 		if (current_admin.debug_level >= DBG_ALL) {
2155 			logit("operation is INFO_OP_GETSTAT...\n");
2156 		}
2157 		*output = NULL;
2158 		(void) rw_rdlock(&info_lock);
2159 		if (serverInfo) {
2160 			(void) getldap_get_server_stat(serverInfo,
2161 				output, &prev_refresh, &next_refresh);
2162 		}
2163 		(void) rw_unlock(&info_lock);
2164 		break;
2165 	default:
2166 		logit("getldap_serverInfo_op(): "
2167 			"invalid operation code (%d).\n", op);
2168 		return (-1);
2169 		break;
2170 	}
2171 	return (NS_LDAP_SUCCESS);
2172 }
2173 
2174 void
2175 getldap_serverInfo_refresh()
2176 {
2177 	int always = 1;
2178 
2179 	if (current_admin.debug_level >= DBG_ALL) {
2180 		logit("getldap_serverInfo_refresh()...\n");
2181 	}
2182 
2183 	/* create the server info list */
2184 	(void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2185 
2186 	while (always) {
2187 		/*
2188 		 * the operation INFO_OP_REFRESH_WAIT
2189 		 * causes this thread to wait until
2190 		 * it is time to do refresh,
2191 		 * see getldap_serverInfo_op() for details
2192 		 */
2193 		(void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT, NULL, NULL);
2194 		(void) getldap_serverInfo_op(INFO_OP_REFRESH, NULL, NULL);
2195 	}
2196 }
2197 
2198 void
2199 getldap_getserver(ldap_return_t *out, ldap_call_t *in)
2200 {
2201 	char 		*outstr = NULL;
2202 	char 		req[] = "0";
2203 
2204 	if (current_admin.debug_level >= DBG_ALL) {
2205 		logit("getldap_getserver()...\n");
2206 	}
2207 
2208 	/* assume no server found */
2209 	out->ldap_errno = -1;
2210 	out->ldap_return_code = NOTFOUND;
2211 	out->ldap_bufferbytesused = sizeof (*out);
2212 
2213 	/* make sure the request is valid */
2214 	req[0] = (in->ldap_u.servername)[0];
2215 	if ((req[0] != '\0') &&
2216 		(strcmp(req, NS_CACHE_NEW) != 0) &&
2217 		(strcmp(req, NS_CACHE_NORESP)  != 0) &&
2218 		(strcmp(req, NS_CACHE_NEXT)    != 0) &&
2219 		(strcmp(req, NS_CACHE_WRITE)   != 0)) {
2220 		return;
2221 	}
2222 
2223 	(void) getldap_serverInfo_op(INFO_OP_GETSERVER,
2224 			in->ldap_u.domainname, &outstr);
2225 
2226 	if (outstr == NULL)
2227 		return;
2228 
2229 	out->ldap_bufferbytesused = sizeof (ldap_return_t);
2230 	(void) strncpy(out->ldap_u.config, outstr, strlen(outstr)+1);
2231 
2232 	if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2233 		/* Log server IP */
2234 		char *ptr;
2235 		ptr = strstr(outstr, DOORLINESEP);
2236 		if (ptr) {
2237 			*ptr = '\0';
2238 			logit("getldap_getserver: got server %s\n", outstr);
2239 		} else
2240 			logit("getldap_getserver: Missing %s."
2241 				" Internal error\n", DOORLINESEP);
2242 	}
2243 	free(outstr);
2244 	out->ldap_return_code = SUCCESS;
2245 	out->ldap_errno = 0;
2246 
2247 }
2248 
2249 void
2250 getldap_get_cacheData(ldap_return_t *out, ldap_call_t *in)
2251 {
2252 	char	*outstr = NULL, *instr = NULL;
2253 	int	datatype = CACHE_MAP_UNKNOWN;
2254 
2255 	if (current_admin.debug_level >= DBG_ALL) {
2256 		logit("getldap_get_cacheData()...\n");
2257 	}
2258 
2259 	/* assume no cache data found */
2260 	out->ldap_errno = -1;
2261 	out->ldap_return_code = NOTFOUND;
2262 	out->ldap_bufferbytesused = sizeof (*out);
2263 
2264 	/* make sure the request is valid */
2265 	if (strncmp(in->ldap_u.servername,
2266 		NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2267 		datatype = CACHE_MAP_DN2DOMAIN;
2268 
2269 	if (datatype == CACHE_MAP_UNKNOWN)
2270 		return;
2271 
2272 	instr = strstr(in->ldap_u.servername, DOORLINESEP);
2273 	if (instr == NULL)
2274 		return;
2275 	instr += strlen(DOORLINESEP);
2276 	if (*instr == '\0')
2277 		return;
2278 
2279 	(void) getldap_cache_op(CACHE_OP_FIND, datatype,
2280 			instr, &outstr);
2281 
2282 	if (outstr == NULL)
2283 		return;
2284 
2285 	out->ldap_bufferbytesused = sizeof (ldap_return_t);
2286 	(void) strncpy(out->ldap_u.config, outstr, strlen(outstr)+1);
2287 	free(outstr);
2288 	out->ldap_return_code = SUCCESS;
2289 	out->ldap_errno = 0;
2290 }
2291 
2292 void
2293 getldap_set_cacheData(ldap_return_t *out, ldap_call_t *in)
2294 {
2295 	char	*instr1 = NULL;
2296 	char	*instr2 = NULL;
2297 	int	datatype = CACHE_MAP_UNKNOWN;
2298 	int	rc = 0;
2299 
2300 	if (current_admin.debug_level >= DBG_ALL) {
2301 		logit("getldap_set_cacheData()...\n");
2302 	}
2303 
2304 	/* assume error */
2305 	out->ldap_errno = -1;
2306 	out->ldap_return_code = NOTFOUND;
2307 	out->ldap_bufferbytesused = sizeof (*out);
2308 
2309 	/* make sure the request is valid */
2310 	if (strncmp(in->ldap_u.servername,
2311 		NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2312 		datatype = CACHE_MAP_DN2DOMAIN;
2313 
2314 	if (datatype == CACHE_MAP_UNKNOWN)
2315 		return;
2316 
2317 	instr1 = strstr(in->ldap_u.servername, DOORLINESEP);
2318 	if (instr1 == NULL)
2319 		return;
2320 	*instr1 = '\0';
2321 	instr1 += strlen(DOORLINESEP);
2322 	if (*instr1 == '\0')
2323 		return;
2324 	instr2 = strstr(instr1, DOORLINESEP);
2325 	if (instr2 == NULL)
2326 		return;
2327 	*instr2 = '\0';
2328 	instr2 += strlen(DOORLINESEP);
2329 	if (*instr2 == '\0')
2330 		return;
2331 
2332 	rc = getldap_cache_op(CACHE_OP_ADD, datatype,
2333 			instr1, &instr2);
2334 	if (rc != NS_LDAP_SUCCESS)
2335 		return;
2336 
2337 	out->ldap_bufferbytesused = sizeof (ldap_return_t);
2338 	out->ldap_return_code = SUCCESS;
2339 	out->ldap_errno = 0;
2340 }
2341 
2342 void
2343 getldap_get_cacheStat(ldap_return_t *out)
2344 {
2345 	char	*foutstr = NULL;
2346 	char	*soutstr = NULL;
2347 	char	*coutstr = NULL;
2348 
2349 	if (current_admin.debug_level >= DBG_ALL) {
2350 		logit("getldap_get_cacheStat()...\n");
2351 	}
2352 
2353 	/* setup for error return */
2354 	out->ldap_errno = -1;
2355 	out->ldap_return_code = NOTFOUND;
2356 	out->ldap_bufferbytesused = sizeof (*out);
2357 
2358 	/* get refersh statisitcs */
2359 	(void) getldap_get_refresh_stat(&foutstr);
2360 	if (foutstr == NULL)
2361 		return;
2362 
2363 	/* get server statisitcs */
2364 	(void) getldap_serverInfo_op(INFO_OP_GETSTAT, NULL, &soutstr);
2365 	if (soutstr == NULL) {
2366 		free(foutstr);
2367 		return;
2368 	}
2369 	/* get cache data statisitcs */
2370 	(void) getldap_cache_op(CACHE_OP_GETSTAT, NULL, NULL, &coutstr);
2371 	if (coutstr == NULL) {
2372 		free(foutstr);
2373 		free(soutstr);
2374 		return;
2375 	}
2376 
2377 	out->ldap_bufferbytesused = sizeof (ldap_return_t);
2378 	(void) strncpy(out->ldap_u.config, foutstr, strlen(foutstr) + 1);
2379 	(void) strncat(out->ldap_u.config, soutstr, strlen(soutstr) + 1);
2380 	(void) strncat(out->ldap_u.config, coutstr, strlen(coutstr) + 1);
2381 
2382 	free(foutstr);
2383 	free(soutstr);
2384 	free(coutstr);
2385 
2386 	out->ldap_return_code = SUCCESS;
2387 	out->ldap_errno = 0;
2388 }
2389 
2390 static int
2391 checkupdate(int sighup)
2392 {
2393 	int	value;
2394 
2395 	(void) rw_wrlock(&ldap_lock);
2396 	value = sighup;
2397 	(void) rw_unlock(&ldap_lock);
2398 
2399 	return (value == TRUE);
2400 }
2401 
2402 
2403 static int
2404 update_from_profile()
2405 {
2406 	ns_ldap_result_t *result = NULL;
2407 	char		searchfilter[BUFSIZ];
2408 	ns_ldap_error_t	*error;
2409 	int		rc;
2410 	void		**paramVal = NULL;
2411 	ns_config_t	*ptr = NULL;
2412 	char		*profile = NULL;
2413 	char		errstr[MAXERROR];
2414 
2415 	if (current_admin.debug_level >= DBG_ALL) {
2416 		logit("update_from_profile....\n");
2417 	}
2418 	do {
2419 		(void) rw_wrlock(&ldap_lock);
2420 		sighup_update = FALSE;
2421 		(void) rw_unlock(&ldap_lock);
2422 
2423 		if ((rc = __ns_ldap_getParam(NS_LDAP_PROFILE_P,
2424 			&paramVal, &error)) != NS_LDAP_SUCCESS) {
2425 			if (error != NULL && error->message != NULL)
2426 				logit("Error: Unable to  profile name: %s\n",
2427 					error->message);
2428 			else {
2429 				char *tmp;
2430 
2431 				__ns_ldap_err2str(rc, &tmp);
2432 				logit("Error: Unable to  profile name: %s\n",
2433 					tmp);
2434 			}
2435 			(void) __ns_ldap_freeParam(&paramVal);
2436 			(void) __ns_ldap_freeError(&error);
2437 			return (-1);
2438 		}
2439 
2440 		if (paramVal && *paramVal)
2441 			profile = strdup((char *)*paramVal);
2442 		(void) __ns_ldap_freeParam(&paramVal);
2443 
2444 		if (profile == NULL) {
2445 			return (-1);
2446 		}
2447 
2448 		(void) snprintf(searchfilter, BUFSIZ, _PROFILE_FILTER,
2449 		    _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
2450 
2451 		if ((rc = __ns_ldap_list(_PROFILE_CONTAINER,
2452 		    (const char *)searchfilter, NULL,
2453 		    NULL, NULL, 0,
2454 		    &result, &error, NULL, NULL)) != NS_LDAP_SUCCESS) {
2455 
2456 			/*
2457 			 * Is profile name the DEFAULTCONFIGNAME?
2458 			 * syslog Warning, otherwise syslog error.
2459 			 */
2460 			if (strcmp(profile, DEFAULTCONFIGNAME) == 0) {
2461 				syslog(LOG_WARNING,
2462 				    "Ignoring attempt to refresh nonexistent "
2463 				    "default profile: %s.\n",
2464 				    profile);
2465 				logit("Ignoring attempt to refresh nonexistent "
2466 				    "default profile: %s.\n",
2467 				    profile);
2468 			} else if ((error != NULL) &&
2469 			    (error->message != NULL)) {
2470 				syslog(LOG_ERR,
2471 				    "Error: Unable to refresh profile:%s:"
2472 				    " %s\n", profile, error->message);
2473 				logit("Error: Unable to refresh profile:"
2474 					"%s:%s\n", profile, error->message);
2475 			} else {
2476 				syslog(LOG_ERR, "Error: Unable to refresh "
2477 					"from profile:%s. (error=%d)\n",
2478 					profile, rc);
2479 				logit("Error: Unable to refresh from profile "
2480 					"%s (error=%d)\n", profile, rc);
2481 			}
2482 
2483 			(void) __ns_ldap_freeError(&error);
2484 			(void) __ns_ldap_freeResult(&result);
2485 			free(profile);
2486 			return (-1);
2487 		}
2488 		free(profile);
2489 
2490 
2491 	} while (checkupdate(sighup_update) == TRUE);
2492 
2493 	(void) rw_wrlock(&ldap_lock);
2494 
2495 	ptr = __ns_ldap_make_config(result);
2496 	(void) __ns_ldap_freeResult(&result);
2497 
2498 	if (ptr == NULL) {
2499 		logit("Error: __ns_ldap_make_config failed.\n");
2500 		(void) rw_unlock(&ldap_lock);
2501 		return (-1);
2502 	}
2503 
2504 	/*
2505 	 * cross check the config parameters
2506 	 */
2507 	if (__s_api_crosscheck(ptr, errstr, B_TRUE) == NS_SUCCESS) {
2508 		/*
2509 		 * reset the local profile TTL
2510 		 */
2511 		if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc)
2512 			current_admin.ldap_stat.ldap_ttl =
2513 			atol(ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc);
2514 
2515 		if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2516 			logit("update_from_profile: reset profile TTL to %d"
2517 				"  seconds\n",
2518 				current_admin.ldap_stat.ldap_ttl);
2519 			logit("update_from_profile: expire time %ld "
2520 				"seconds\n",
2521 				ptr->paramList[NS_LDAP_EXP_P].ns_tm);
2522 		}
2523 
2524 		/* set ptr as current_config */
2525 		__s_api_init_config(ptr);
2526 		rc = 0;
2527 	} else {
2528 		__s_api_destroy_config(ptr);
2529 		logit("Error: downloaded profile failed to pass "
2530 			"crosscheck (%s).\n", errstr);
2531 		syslog(LOG_ERR, "ldap_cachemgr: %s", errstr);
2532 		rc = -1;
2533 	}
2534 	(void) rw_unlock(&ldap_lock);
2535 
2536 	return (rc);
2537 }
2538 
2539 int
2540 getldap_init()
2541 {
2542 	ns_ldap_error_t	*error;
2543 	struct timeval	tp;
2544 
2545 	if (current_admin.debug_level >= DBG_ALL) {
2546 		logit("getldap_init()...\n");
2547 	}
2548 
2549 	(void) __ns_ldap_setServer(TRUE);
2550 
2551 	(void) rw_wrlock(&ldap_lock);
2552 	if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
2553 		logit("Error: Unable to read '%s': %s\n",
2554 			NSCONFIGFILE, error->message);
2555 		(void) fprintf(stderr,
2556 			gettext("\nError: Unable to read '%s': %s\n"),
2557 			NSCONFIGFILE, error->message);
2558 		__ns_ldap_freeError(&error);
2559 		(void) rw_unlock(&ldap_lock);
2560 		return (-1);
2561 	}
2562 	(void) rw_unlock(&ldap_lock);
2563 
2564 	if (gettimeofday(&tp, NULL) == 0) {
2565 		/* statistics: previous refresh time */
2566 		prev_refresh_time = tp.tv_sec;
2567 	}
2568 
2569 	/* initialize the data cache */
2570 	(void) getldap_cache_op(CACHE_OP_CREATE,
2571 			0, NULL, NULL);
2572 
2573 	return (0);
2574 }
2575 
2576 static void
2577 perform_update(void)
2578 {
2579 	ns_ldap_error_t	*error = NULL;
2580 	struct timeval	tp;
2581 	char		buf[20];
2582 	int		rc, rc1;
2583 	void		**paramVal = NULL;
2584 	ns_ldap_self_gssapi_config_t	config;
2585 
2586 	if (current_admin.debug_level >= DBG_ALL) {
2587 		logit("perform_update()...\n");
2588 	}
2589 
2590 	(void) __ns_ldap_setServer(TRUE);
2591 
2592 	if (gettimeofday(&tp, NULL) != 0)
2593 		return;
2594 
2595 	rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, &paramVal, &error);
2596 
2597 	if (rc == NS_LDAP_SUCCESS && paramVal != NULL) {
2598 		current_admin.ldap_stat.ldap_ttl = atol((char *)*paramVal);
2599 	}
2600 
2601 	if (error != NULL)
2602 		(void) __ns_ldap_freeError(&error);
2603 
2604 	if (paramVal != NULL)
2605 		(void) __ns_ldap_freeParam(&paramVal);
2606 
2607 	if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2608 		logit("perform_update: current profile TTL is %d seconds\n",
2609 		    current_admin.ldap_stat.ldap_ttl);
2610 	}
2611 
2612 	if (current_admin.ldap_stat.ldap_ttl > 0) {
2613 		/*
2614 		 * set the profile TTL parameter, just
2615 		 * in case that the downloading of
2616 		 * the profile from server would fail
2617 		 */
2618 
2619 		/*
2620 		 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2621 		 * It depends on NS_LDAP_CACHETTL_P to set it's value
2622 		 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2623 		 * can be set.
2624 		 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2625 		 * downloaded from the server, so is NS_LDAP_EXP_P.
2626 		 */
2627 		buf[19] = '\0'; /* null terminated the buffer */
2628 		if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P,
2629 			lltostr((long long)current_admin.ldap_stat.ldap_ttl,
2630 			    &buf[19]),
2631 			&error) != NS_LDAP_SUCCESS) {
2632 			logit("Error: __ns_ldap_setParam failed, status: %d "
2633 			    "message: %s\n", error->status, error->message);
2634 			(void)  __ns_ldap_freeError(&error);
2635 			return;
2636 		}
2637 
2638 		(void) rw_wrlock(&ldap_lock);
2639 		sighup_update = FALSE;
2640 		(void) rw_unlock(&ldap_lock);
2641 
2642 		do {
2643 			rc = update_from_profile();
2644 			if (rc != 0) {
2645 				logit("Error: Unable to update from profile\n");
2646 			}
2647 		} while (checkupdate(sighup_update) == TRUE);
2648 	} else {
2649 		rc = 0;
2650 	}
2651 
2652 	/*
2653 	 * recreate the server info list
2654 	 */
2655 	if (rc == 0) {
2656 		(void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2657 
2658 		/* flush the data cache */
2659 		(void) getldap_cache_op(CACHE_OP_DELETE,
2660 				0, NULL, NULL);
2661 
2662 		/* statistics: previous refresh time */
2663 		prev_refresh_time = tp.tv_sec;
2664 	}
2665 	rc1 = __ns_ldap_self_gssapi_config(&config);
2666 	if (rc1 == NS_LDAP_SUCCESS) {
2667 		if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) {
2668 			rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error);
2669 			(void)  __ns_ldap_freeError(&error);
2670 			if (rc1 != NS_LDAP_SUCCESS) {
2671 				logit("Error: Check on self credential "
2672 					"prerquesites failed: %d\n",
2673 					rc1);
2674 				exit(rc1);
2675 			}
2676 		}
2677 	} else {
2678 		logit("Error: Failed to get self credential configuration %d\n",
2679 					rc1);
2680 			exit(rc1);
2681 	}
2682 
2683 	(void) rw_rdlock(&ldap_lock);
2684 	if ((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) {
2685 		logit("Error: __ns_ldap_DumpConfiguration(\"%s\") failed, "
2686 		    "status: %d "
2687 		    "message: %s\n", NSCONFIGREFRESH,
2688 		    error->status, error->message);
2689 		__ns_ldap_freeError(&error);
2690 	}
2691 	if ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL) {
2692 		logit("Error: __ns_ldap_DumpConfiguration(\"%s\") failed, "
2693 		    "status: %d "
2694 		    "message: %s\n", NSCREDREFRESH,
2695 		    error->status, error->message);
2696 		__ns_ldap_freeError(&error);
2697 	}
2698 	if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0)
2699 		logit("Error: unlink failed - errno: %d\n", errno);
2700 	if (rename(NSCREDREFRESH, NSCREDFILE) != 0)
2701 		logit("Error: unlink failed - errno: %d\n", errno);
2702 
2703 	(void) rw_unlock(&ldap_lock);
2704 
2705 }
2706 
2707 void
2708 getldap_refresh()
2709 {
2710 	struct timespec	timeout;
2711 	int		sleeptime;
2712 	struct timeval	tp;
2713 	long		expire = 0;
2714 	void		**paramVal = NULL;
2715 	ns_ldap_error_t	*errorp;
2716 	int		always = 1, err;
2717 	int		first_time = 1;
2718 	int		sig_done = 0;
2719 	int		dbg_level;
2720 
2721 	if (current_admin.debug_level >= DBG_ALL) {
2722 		logit("getldap_refresh()...\n");
2723 	}
2724 
2725 	/*
2726 	 * wait for an available server
2727 	 */
2728 	while (sig_done == 0) {
2729 		(void) mutex_lock(&sig_mutex);
2730 		sig_done = signal_done;
2731 		(void) mutex_unlock(&sig_mutex);
2732 	}
2733 
2734 	(void) __ns_ldap_setServer(TRUE);
2735 	while (always) {
2736 		dbg_level = current_admin.debug_level;
2737 		(void) rw_rdlock(&ldap_lock);
2738 		sleeptime = current_admin.ldap_stat.ldap_ttl;
2739 		if (dbg_level >= DBG_PROFILE_REFRESH) {
2740 			logit("getldap_refresh: current profile TTL is %d "
2741 			"seconds\n", current_admin.ldap_stat.ldap_ttl);
2742 		}
2743 		if (gettimeofday(&tp, NULL) == 0) {
2744 			if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
2745 			    &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
2746 			    paramVal != NULL &&
2747 			    (char *)*paramVal != NULL) {
2748 				errno = 0;
2749 				expire = atol((char *)*paramVal);
2750 				(void) __ns_ldap_freeParam(&paramVal);
2751 				if (errno == 0) {
2752 					if (expire == 0) {
2753 						first_time = 0;
2754 						(void) rw_unlock(&ldap_lock);
2755 						(void) cond_init(&cond,
2756 							NULL, NULL);
2757 						(void) mutex_lock(&sighuplock);
2758 						timeout.tv_sec =
2759 							CACHESLEEPTIME;
2760 						timeout.tv_nsec = 0;
2761 						if (dbg_level >=
2762 							DBG_PROFILE_REFRESH) {
2763 						    logit("getldap_refresh: "
2764 						    "(1)about to sleep for %d "
2765 						    "seconds\n",
2766 						    CACHESLEEPTIME);
2767 						}
2768 						err = cond_reltimedwait(&cond,
2769 							&sighuplock, &timeout);
2770 						(void) cond_destroy(&cond);
2771 						(void) mutex_unlock(
2772 							&sighuplock);
2773 						/*
2774 						 * if woke up by
2775 						 * getldap_revalidate(),
2776 						 * do update right away
2777 						 */
2778 						if (err == ETIME)
2779 							continue;
2780 						else {
2781 							/*
2782 							 * if load
2783 							 * configuration failed
2784 							 * don't do update
2785 							 */
2786 							if (load_config())
2787 							    perform_update();
2788 							continue;
2789 						}
2790 					}
2791 					sleeptime = expire - tp.tv_sec;
2792 					if (dbg_level >= DBG_PROFILE_REFRESH) {
2793 					    logit("getldap_refresh: expire time"
2794 						" = %ld\n", expire);
2795 					}
2796 
2797 				}
2798 			}
2799 		}
2800 
2801 		(void) rw_unlock(&ldap_lock);
2802 
2803 		/*
2804 		 * if this is the first time downloading
2805 		 * the profile or expire time already passed,
2806 		 * do not wait, do update
2807 		 */
2808 		if (first_time == 0 && sleeptime > 0) {
2809 			if (dbg_level >= DBG_PROFILE_REFRESH) {
2810 				logit("getldap_refresh: (2)about to sleep "
2811 				"for %d seconds\n", sleeptime);
2812 			}
2813 			(void) cond_init(&cond, NULL, NULL);
2814 			(void) mutex_lock(&sighuplock);
2815 			timeout.tv_sec = sleeptime;
2816 			timeout.tv_nsec = 0;
2817 			err = cond_reltimedwait(&cond,
2818 				&sighuplock, &timeout);
2819 			(void) cond_destroy(&cond);
2820 			(void) mutex_unlock(&sighuplock);
2821 		}
2822 		/*
2823 		 * if load concfiguration failed
2824 		 * don't do update
2825 		 */
2826 		if (load_config())
2827 			perform_update();
2828 		first_time = 0;
2829 	}
2830 }
2831 
2832 void
2833 getldap_revalidate()
2834 {
2835 	if (current_admin.debug_level >= DBG_ALL) {
2836 		logit("getldap_revalidate()...\n");
2837 	}
2838 	/* block signal SIGHUP */
2839 	(void) sighold(SIGHUP);
2840 
2841 	/* now awake the sleeping refresh thread */
2842 	(void) cond_signal(&cond);
2843 
2844 	/* release signal SIGHUP */
2845 	(void) sigrelse(SIGHUP);
2846 
2847 }
2848 
2849 void
2850 getldap_lookup(ldap_return_t *out, ldap_call_t *in)
2851 {
2852 	LineBuf		configinfo;
2853 	ns_ldap_error_t	*error;
2854 
2855 	if (current_admin.debug_level >= DBG_ALL) {
2856 		logit("getldap_lookup()...\n");
2857 	}
2858 
2859 	(void) rw_rdlock(&ldap_lock);
2860 	if ((error = __ns_ldap_LoadDoorInfo(&configinfo, in->ldap_u.domainname))
2861 		!= NULL) {
2862 		if (error != NULL && error->message != NULL)
2863 			logit("Error: ldap_lookup: %s\n", error->message);
2864 		(void) __ns_ldap_freeError(&error);
2865 		out->ldap_errno = -1;
2866 		out->ldap_return_code = NOTFOUND;
2867 		out->ldap_bufferbytesused = sizeof (*out);
2868 
2869 	} else {
2870 		out->ldap_bufferbytesused = sizeof (ldap_return_t);
2871 		(void) strncpy(out->ldap_u.config,
2872 			configinfo.str, configinfo.len);
2873 		out->ldap_return_code = SUCCESS;
2874 		out->ldap_errno = 0;
2875 	}
2876 
2877 	if (configinfo.str != NULL) {
2878 		free(configinfo.str);
2879 		configinfo.str = NULL;
2880 		configinfo.alloc = 0;
2881 		configinfo.len = 0;
2882 	}
2883 
2884 	(void) rw_unlock(&ldap_lock);
2885 }
2886