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