cachemgr_getldap.c revision 2830:5228d1267a01
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
54static rwlock_t	ldap_lock = DEFAULTRWLOCK;
55static int	sighup_update = FALSE;
56extern admin_t	current_admin;
57
58/* variables used for SIGHUP wakeup on sleep */
59static mutex_t			sighuplock;
60static cond_t			cond;
61
62/* refresh time statistics */
63static time_t	prev_refresh_time = 0;
64
65/* variables used for signaling parent process */
66static mutex_t	sig_mutex;
67static int	signal_done = FALSE;
68
69/* TCP connection timeout (in milliseconds) */
70static int tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
71/* search timeout (in seconds) */
72static int search_timeout = NS_DEFAULT_SEARCH_TIMEOUT;
73
74#ifdef SLP
75extern 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
89typedef 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
98typedef enum {
99	INFO_RW_UNKNOWN		= 0,
100	INFO_RW_READONLY	= 1,
101	INFO_RW_WRITEABLE	= 2
102} info_rw_t;
103
104typedef 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
113typedef 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
120typedef 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
128typedef enum {
129	CACHE_MAP_UNKNOWN	= 0,
130	CACHE_MAP_DN2DOMAIN	= 1
131} cache_type_t;
132
133typedef 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
144typedef 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
151typedef struct cache_hash {
152	cache_type_t		type;
153	char			*from;
154	char			*to;
155	struct cache_hash	*next;
156} cache_hash_t;
157
158static 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 */
167static int
168load_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
194static unsigned long
195getldap_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
215static cache_hash_t *
216getldap_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 */
235static cache_hash_t *
236getldap_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 */
252static int
253getldap_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
283static int
284getldap_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 */
440static void
441sync_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
498static void *
499getldap_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
754static int
755getldap_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
839static int
840getldap_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
877static int
878getldap_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 */
973static int
974getldap_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 */
1106static int
1107getldap_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 */
1310static int
1311getldap_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 */
1370static int
1371getldap_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 */
1494static int
1495getldap_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
1579static int
1580getldap_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 */
1654static int
1655getldap_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
1820static int
1821getldap_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
2174void
2175getldap_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
2198void
2199getldap_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
2249void
2250getldap_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
2292void
2293getldap_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
2342void
2343getldap_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
2390static int
2391checkupdate(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
2403static int
2404update_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
2539int
2540getldap_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
2576static void
2577perform_update(void)
2578{
2579	ns_ldap_error_t	*error;
2580	struct timeval	tp;
2581	char		buf[20];
2582	int		rc, rc1;
2583	ns_ldap_self_gssapi_config_t	config;
2584
2585	if (current_admin.debug_level >= DBG_ALL) {
2586		logit("perform_update()...\n");
2587	}
2588
2589	(void) __ns_ldap_setServer(TRUE);
2590
2591	if (gettimeofday(&tp, NULL) != 0)
2592		return;
2593
2594	/*
2595	 * set the profile TTL parameter, just
2596	 * in case that the downloading of
2597	 * the profile from server would fail
2598	 */
2599	if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2600		logit("perform_update: current profile TTL is %d seconds\n",
2601			current_admin.ldap_stat.ldap_ttl);
2602	}
2603	/*
2604	 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2605	 * It depends on NS_LDAP_CACHETTL_P to set it's value
2606	 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2607	 * can be set.
2608	 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2609	 * downloaded from the server, so is NS_LDAP_EXP_P.
2610	 */
2611	buf[19] = '\0'; /* null terminated the buffer */
2612	if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P,
2613		lltostr((long long)current_admin.ldap_stat.ldap_ttl, &buf[19]),
2614		&error) != NS_LDAP_SUCCESS) {
2615		logit("Error: __ns_ldap_setParam failed, status: %d "
2616			"message: %s\n", error->status, error->message);
2617		(void)  __ns_ldap_freeError(&error);
2618		return;
2619	}
2620
2621	(void) rw_wrlock(&ldap_lock);
2622	sighup_update = FALSE;
2623	(void) rw_unlock(&ldap_lock);
2624
2625	do {
2626		rc = update_from_profile();
2627		if (rc != 0) {
2628			logit("Error: Unable to update from profile\n");
2629		}
2630	} while (checkupdate(sighup_update) == TRUE);
2631
2632	/*
2633	 * recreate the server info list
2634	 */
2635	if (rc == 0) {
2636		(void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2637
2638		/* flush the data cache */
2639		(void) getldap_cache_op(CACHE_OP_DELETE,
2640				0, NULL, NULL);
2641
2642		/* statistics: previous refresh time */
2643		prev_refresh_time = tp.tv_sec;
2644	}
2645	rc1 = __ns_ldap_self_gssapi_config(&config);
2646	if (rc1 == NS_LDAP_SUCCESS) {
2647		if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) {
2648			rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error);
2649			(void)  __ns_ldap_freeError(&error);
2650			if (rc1 != NS_LDAP_SUCCESS) {
2651				logit("Error: Check on self credential "
2652					"prerquesites failed: %d\n",
2653					rc1);
2654				exit(rc1);
2655			}
2656		}
2657	} else {
2658		logit("Error: Failed to get self credential configuration %d\n",
2659					rc1);
2660			exit(rc1);
2661	}
2662
2663	(void) rw_rdlock(&ldap_lock);
2664	if ((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) {
2665		logit("Error: __ns_ldap_DumpConfiguration(\"%s\") failed, "
2666		    "status: %d "
2667		    "message: %s\n", NSCONFIGREFRESH,
2668		    error->status, error->message);
2669		__ns_ldap_freeError(&error);
2670	}
2671	if ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL) {
2672		logit("Error: __ns_ldap_DumpConfiguration(\"%s\") failed, "
2673		    "status: %d "
2674		    "message: %s\n", NSCREDREFRESH,
2675		    error->status, error->message);
2676		__ns_ldap_freeError(&error);
2677	}
2678	if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0)
2679		logit("Error: unlink failed - errno: %d\n", errno);
2680	if (rename(NSCREDREFRESH, NSCREDFILE) != 0)
2681		logit("Error: unlink failed - errno: %d\n", errno);
2682
2683	(void) rw_unlock(&ldap_lock);
2684
2685}
2686
2687void
2688getldap_refresh()
2689{
2690	struct timespec	timeout;
2691	int		sleeptime;
2692	struct timeval	tp;
2693	long		expire = 0;
2694	void		**paramVal = NULL;
2695	ns_ldap_error_t	*errorp;
2696	int		always = 1, err;
2697	int		first_time = 1;
2698	int		sig_done = 0;
2699	int		dbg_level;
2700
2701	if (current_admin.debug_level >= DBG_ALL) {
2702		logit("getldap_refresh()...\n");
2703	}
2704
2705	/*
2706	 * wait for an available server
2707	 */
2708	while (sig_done == 0) {
2709		(void) mutex_lock(&sig_mutex);
2710		sig_done = signal_done;
2711		(void) mutex_unlock(&sig_mutex);
2712	}
2713
2714	(void) __ns_ldap_setServer(TRUE);
2715	while (always) {
2716		dbg_level = current_admin.debug_level;
2717		(void) rw_rdlock(&ldap_lock);
2718		sleeptime = current_admin.ldap_stat.ldap_ttl;
2719		if (dbg_level >= DBG_PROFILE_REFRESH) {
2720			logit("getldap_refresh: current profile TTL is %d "
2721			"seconds\n", current_admin.ldap_stat.ldap_ttl);
2722		}
2723		if (gettimeofday(&tp, NULL) == 0) {
2724			if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
2725			    &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
2726			    paramVal != NULL &&
2727			    (char *)*paramVal != NULL) {
2728				errno = 0;
2729				expire = atol((char *)*paramVal);
2730				(void) __ns_ldap_freeParam(&paramVal);
2731				if (errno == 0) {
2732					if (expire == 0) {
2733						first_time = 0;
2734						(void) rw_unlock(&ldap_lock);
2735						(void) cond_init(&cond,
2736							NULL, NULL);
2737						(void) mutex_lock(&sighuplock);
2738						timeout.tv_sec =
2739							CACHESLEEPTIME;
2740						timeout.tv_nsec = 0;
2741						if (dbg_level >=
2742							DBG_PROFILE_REFRESH) {
2743						    logit("getldap_refresh: "
2744						    "(1)about to sleep for %d "
2745						    "seconds\n",
2746						    CACHESLEEPTIME);
2747						}
2748						err = cond_reltimedwait(&cond,
2749							&sighuplock, &timeout);
2750						(void) cond_destroy(&cond);
2751						(void) mutex_unlock(
2752							&sighuplock);
2753						/*
2754						 * if woke up by
2755						 * getldap_revalidate(),
2756						 * do update right away
2757						 */
2758						if (err == ETIME)
2759							continue;
2760						else {
2761							/*
2762							 * if load
2763							 * configuration failed
2764							 * don't do update
2765							 */
2766							if (load_config())
2767							    perform_update();
2768							continue;
2769						}
2770					}
2771					sleeptime = expire - tp.tv_sec;
2772					if (dbg_level >= DBG_PROFILE_REFRESH) {
2773					    logit("getldap_refresh: expire time"
2774						" = %ld\n", expire);
2775					}
2776
2777				}
2778			}
2779		}
2780
2781		(void) rw_unlock(&ldap_lock);
2782
2783		/*
2784		 * if this is the first time downloading
2785		 * the profile or expire time already passed,
2786		 * do not wait, do update
2787		 */
2788		if (first_time == 0 && sleeptime > 0) {
2789			if (dbg_level >= DBG_PROFILE_REFRESH) {
2790				logit("getldap_refresh: (2)about to sleep "
2791				"for %d seconds\n", sleeptime);
2792			}
2793			(void) cond_init(&cond, NULL, NULL);
2794			(void) mutex_lock(&sighuplock);
2795			timeout.tv_sec = sleeptime;
2796			timeout.tv_nsec = 0;
2797			err = cond_reltimedwait(&cond,
2798				&sighuplock, &timeout);
2799			(void) cond_destroy(&cond);
2800			(void) mutex_unlock(&sighuplock);
2801		}
2802		/*
2803		 * if load concfiguration failed
2804		 * don't do update
2805		 */
2806		if (load_config())
2807			perform_update();
2808		first_time = 0;
2809	}
2810}
2811
2812void
2813getldap_revalidate()
2814{
2815	if (current_admin.debug_level >= DBG_ALL) {
2816		logit("getldap_revalidate()...\n");
2817	}
2818	/* block signal SIGHUP */
2819	(void) sighold(SIGHUP);
2820
2821	/* now awake the sleeping refresh thread */
2822	(void) cond_signal(&cond);
2823
2824	/* release signal SIGHUP */
2825	(void) sigrelse(SIGHUP);
2826
2827}
2828
2829void
2830getldap_lookup(ldap_return_t *out, ldap_call_t *in)
2831{
2832	LineBuf		configinfo;
2833	ns_ldap_error_t	*error;
2834
2835	if (current_admin.debug_level >= DBG_ALL) {
2836		logit("getldap_lookup()...\n");
2837	}
2838
2839	(void) rw_rdlock(&ldap_lock);
2840	if ((error = __ns_ldap_LoadDoorInfo(&configinfo, in->ldap_u.domainname))
2841		!= NULL) {
2842		if (error != NULL && error->message != NULL)
2843			logit("Error: ldap_lookup: %s\n", error->message);
2844		(void) __ns_ldap_freeError(&error);
2845		out->ldap_errno = -1;
2846		out->ldap_return_code = NOTFOUND;
2847		out->ldap_bufferbytesused = sizeof (*out);
2848
2849	} else {
2850		out->ldap_bufferbytesused = sizeof (ldap_return_t);
2851		(void) strncpy(out->ldap_u.config,
2852			configinfo.str, configinfo.len);
2853		out->ldap_return_code = SUCCESS;
2854		out->ldap_errno = 0;
2855	}
2856
2857	if (configinfo.str != NULL) {
2858		free(configinfo.str);
2859		configinfo.str = NULL;
2860		configinfo.alloc = 0;
2861		configinfo.len = 0;
2862	}
2863
2864	(void) rw_unlock(&ldap_lock);
2865}
2866