dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / ldapcachemgr / cachemgr_getldap.c
blob967664aad7e67904fe79ead93d7ad3d7f9ae9cdc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <assert.h>
26 #include <errno.h>
27 #include <memory.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <libintl.h>
33 #include <syslog.h>
34 #include <sys/door.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <synch.h>
40 #include <pthread.h>
41 #include <unistd.h>
42 #include <lber.h>
43 #include <ldap.h>
44 #include <ctype.h> /* tolower */
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <ucred.h>
49 #include "cachemgr.h"
50 #include "solaris-priv.h"
51 #include "ns_connmgmt.h"
53 static rwlock_t ldap_lock = DEFAULTRWLOCK;
54 static int sighup_update = FALSE;
55 extern admin_t current_admin;
57 extern int is_root_or_all_privs(char *dc_str, ucred_t **ucp);
59 /* variables used for SIGHUP wakeup on sleep */
60 static mutex_t sighuplock;
61 static cond_t cond;
63 /* refresh time statistics */
64 static time_t prev_refresh_time = 0;
66 /* variables used for signaling parent process */
67 static mutex_t sig_mutex;
68 static int signal_done = FALSE;
70 /* TCP connection timeout (in milliseconds) */
71 static int tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
73 /* nis domain information */
74 #define _NIS_FILTER "objectclass=nisDomainObject"
75 #define _NIS_DOMAIN "nisdomain"
77 #define CACHESLEEPTIME 600
79 * server list refresh delay when in "no server" mode
80 * (1 second)
82 #define REFRESH_DELAY_WHEN_NO_SERVER 1
84 typedef enum {
85 INFO_OP_CREATE = 0,
86 INFO_OP_DELETE = 1,
87 INFO_OP_REFRESH = 2,
88 INFO_OP_REFRESH_WAIT = 3,
89 INFO_OP_GETSERVER = 4,
90 INFO_OP_GETSTAT = 5,
91 INFO_OP_REMOVESERVER = 6
92 } info_op_t;
94 typedef enum {
95 INFO_RW_UNKNOWN = 0,
96 INFO_RW_READONLY = 1,
97 INFO_RW_WRITEABLE = 2
98 } info_rw_t;
100 typedef enum {
101 INFO_SERVER_JUST_INITED = -1,
102 INFO_SERVER_UNKNOWN = 0,
103 INFO_SERVER_CONNECTING = 1,
104 INFO_SERVER_UP = 2,
105 INFO_SERVER_ERROR = 3,
106 INFO_SERVER_REMOVED = 4
107 } info_server_t;
109 typedef enum {
110 INFO_STATUS_UNKNOWN = 0,
111 INFO_STATUS_ERROR = 1,
112 INFO_STATUS_NEW = 2,
113 INFO_STATUS_OLD = 3
114 } info_status_t;
116 typedef enum {
117 CACHE_OP_CREATE = 0,
118 CACHE_OP_DELETE = 1,
119 CACHE_OP_FIND = 2,
120 CACHE_OP_ADD = 3,
121 CACHE_OP_GETSTAT = 4
122 } cache_op_t;
124 typedef enum {
125 CACHE_MAP_UNKNOWN = 0,
126 CACHE_MAP_DN2DOMAIN = 1
127 } cache_type_t;
129 typedef struct server_info_ext {
130 char *addr;
131 char *hostname;
132 char *rootDSE_data;
133 char *errormsg;
134 info_rw_t type;
135 info_server_t server_status;
136 info_server_t prev_server_status;
137 info_status_t info_status;
138 ns_server_status_t change;
139 } server_info_ext_t;
141 typedef struct server_info {
142 struct server_info *next;
143 mutex_t mutex[2]; /* 0: current copy lock */
144 /* 1: update copy lock */
145 server_info_ext_t sinfo[2]; /* 0: current, 1: update copy */
146 } server_info_t;
148 typedef struct cache_hash {
149 cache_type_t type;
150 char *from;
151 char *to;
152 struct cache_hash *next;
153 } cache_hash_t;
156 * The status of a server to be removed. It can be up or down.
158 typedef struct rm_svr {
159 char *addr;
160 int up; /* 1: up, 0: down */
161 } rm_svr_t;
163 static int getldap_destroy_serverInfo(server_info_t *head);
164 static void test_server_change(server_info_t *head);
165 static void remove_server(char *addr);
166 static ns_server_status_t set_server_status(char *input, server_info_t *head);
167 static void create_buf_and_notify(char *input, ns_server_status_t st);
170 * Load configuration
171 * The code was in signal handler getldap_revalidate
172 * It's moved out of the handler because it could cause deadlock
173 * return: 1 SUCCESS
174 * 0 FAIL
176 static int
177 load_config() {
178 ns_ldap_error_t *error;
179 int rc = 1;
181 (void) __ns_ldap_setServer(TRUE);
183 (void) rw_wrlock(&ldap_lock);
184 if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
185 logit("Error: Unable to read '%s': %s\n",
186 NSCONFIGFILE, error->message);
187 __ns_ldap_freeError(&error);
188 rc = 0; /* FAIL */
189 } else
190 sighup_update = TRUE;
192 (void) rw_unlock(&ldap_lock);
194 return (rc);
198 * Calculate a hash for a string
199 * Based on elf_hash algorithm, hash is case insensitive
200 * Uses tolower instead of _tolower because of I18N
203 static unsigned long
204 getldap_hash(const char *str)
206 unsigned int hval = 0;
208 while (*str) {
209 unsigned int g;
211 hval = (hval << 4) + tolower(*str++);
212 if ((g = (hval & 0xf0000000)) != 0)
213 hval ^= g >> 24;
214 hval &= ~g;
216 return ((unsigned long)hval);
220 * Remove a hash table entry.
221 * This function expects a lock in place when called.
224 static cache_hash_t *
225 getldap_free_hash(cache_hash_t *p)
227 cache_hash_t *next;
229 p->type = CACHE_MAP_UNKNOWN;
230 free(p->from);
231 free(p->to);
232 next = p->next;
233 p->next = NULL;
234 free(p);
235 return (next);
239 * Scan a hash table hit for a matching hash entry.
240 * This function expects a lock in place when called.
242 static cache_hash_t *
243 getldap_scan_hash(cache_type_t type, char *from,
244 cache_hash_t *idx)
246 while (idx) {
247 if (idx->type == type &&
248 strcasecmp(from, idx->from) == 0) {
249 return (idx);
251 idx = idx->next;
253 return ((cache_hash_t *)NULL);
257 * Format and return the cache data statistics
259 static int
260 getldap_get_cacheData_stat(int max, int current, char **output)
262 #define C_HEADER0 "Cache data information: "
263 #define C_HEADER1 " Maximum cache entries: "
264 #define C_HEADER2 " Number of cache entries: "
265 int hdr0_len = strlen(gettext(C_HEADER0));
266 int hdr1_len = strlen(gettext(C_HEADER1));
267 int hdr2_len = strlen(gettext(C_HEADER2));
268 int len;
270 if (current_admin.debug_level >= DBG_ALL) {
271 logit("getldap_get_cacheData_stat()...\n");
274 *output = NULL;
276 len = hdr0_len + hdr1_len + hdr2_len +
277 3 * strlen(DOORLINESEP) + 21;
278 *output = malloc(len);
279 if (*output == NULL)
280 return (-1);
282 (void) snprintf(*output, len, "%s%s%s%10d%s%s%10d%s",
283 gettext(C_HEADER0), DOORLINESEP,
284 gettext(C_HEADER1), max, DOORLINESEP,
285 gettext(C_HEADER2), current, DOORLINESEP);
287 return (NS_LDAP_SUCCESS);
290 static int
291 getldap_cache_op(cache_op_t op, cache_type_t type,
292 char *from, char **to)
294 #define CACHE_HASH_MAX 257
295 #define CACHE_HASH_MAX_ENTRY 256
296 static cache_hash_t *hashTbl[CACHE_HASH_MAX];
297 cache_hash_t *next, *idx, *newp;
298 unsigned long hash;
299 static rwlock_t cache_lock = DEFAULTRWLOCK;
300 int i;
301 static int entry_num = 0;
303 if (current_admin.debug_level >= DBG_ALL) {
304 logit("getldap_cache_op()...\n");
306 switch (op) {
307 case CACHE_OP_CREATE:
308 if (current_admin.debug_level >= DBG_ALL) {
309 logit("operation is CACHE_OP_CREATE...\n");
311 (void) rw_wrlock(&cache_lock);
313 for (i = 0; i < CACHE_HASH_MAX; i++) {
314 hashTbl[i] = NULL;
316 entry_num = 0;
318 (void) rw_unlock(&cache_lock);
319 break;
321 case CACHE_OP_DELETE:
322 if (current_admin.debug_level >= DBG_ALL) {
323 logit("operation is CACHE_OP_DELETE...\n");
325 (void) rw_wrlock(&cache_lock);
327 for (i = 0; i < CACHE_HASH_MAX; i++) {
328 next = hashTbl[i];
329 while (next != NULL) {
330 next = getldap_free_hash(next);
332 hashTbl[i] = NULL;
334 entry_num = 0;
336 (void) rw_unlock(&cache_lock);
337 break;
339 case CACHE_OP_ADD:
340 if (current_admin.debug_level >= DBG_ALL) {
341 logit("operation is CACHE_OP_ADD...\n");
343 if (from == NULL || to == NULL || *to == NULL)
344 return (-1);
345 hash = getldap_hash(from) % CACHE_HASH_MAX;
346 (void) rw_wrlock(&cache_lock);
347 idx = hashTbl[hash];
349 * replace old "to" value with new one
350 * if an entry with same "from"
351 * already exists
353 if (idx) {
354 newp = getldap_scan_hash(type, from, idx);
355 if (newp) {
356 free(newp->to);
357 newp->to = strdup(*to);
358 (void) rw_unlock(&cache_lock);
359 return (NS_LDAP_SUCCESS);
363 if (entry_num > CACHE_HASH_MAX_ENTRY) {
364 (void) rw_unlock(&cache_lock);
365 return (-1);
368 newp = (cache_hash_t *)malloc(sizeof (cache_hash_t));
369 if (newp == NULL) {
370 (void) rw_unlock(&cache_lock);
371 return (NS_LDAP_MEMORY);
373 newp->type = type;
374 newp->from = strdup(from);
375 newp->to = strdup(*to);
376 newp->next = idx;
377 hashTbl[hash] = newp;
378 entry_num++;
379 (void) rw_unlock(&cache_lock);
380 break;
382 case CACHE_OP_FIND:
383 if (current_admin.debug_level >= DBG_ALL) {
384 logit("operation is CACHE_OP_FIND...\n");
386 if (from == NULL || to == NULL)
387 return (-1);
388 *to = NULL;
389 hash = getldap_hash(from) % CACHE_HASH_MAX;
390 (void) rw_rdlock(&cache_lock);
391 idx = hashTbl[hash];
392 idx = getldap_scan_hash(type, from, idx);
393 if (idx)
394 *to = strdup(idx->to);
395 (void) rw_unlock(&cache_lock);
396 if (idx == NULL)
397 return (-1);
398 break;
400 case CACHE_OP_GETSTAT:
401 if (current_admin.debug_level >= DBG_ALL) {
402 logit("operation is CACHE_OP_GETSTAT...\n");
404 if (to == NULL)
405 return (-1);
407 return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY,
408 entry_num, to));
409 break;
411 default:
412 logit("getldap_cache_op(): "
413 "invalid operation code (%d).\n", op);
414 return (-1);
415 break;
417 return (NS_LDAP_SUCCESS);
420 * Function: sync_current_with_update_copy
422 * This function syncs up the 2 sinfo copies in info.
424 * The 2 copies are identical most of time.
425 * The update copy(sinfo[1]) could be different when
426 * getldap_serverInfo_refresh thread is refreshing the server list
427 * and calls getldap_get_rootDSE to update info. getldap_get_rootDSE
428 * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
429 * The calling sequence is
430 * getldap_serverInfo_refresh->
431 * getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
432 * getldap_set_serverInfo->
433 * getldap_get_rootDSE
435 * The original server_info_t has one copy of server info. When libsldap
436 * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
437 * is updating the server info, it would hit a unprotected window in
438 * getldap_rootDSE. The door call will not get server info and libsldap
439 * fails at making ldap connection.
441 * The new server_info_t provides GETLDAPSERVER thread with a current
442 * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
443 * and syncs up 2 copies before thr_exit. This will close the window in
444 * getldap_get_rootDSE.
447 static void
448 sync_current_with_update_copy(server_info_t *info)
450 if (current_admin.debug_level >= DBG_ALL) {
451 logit("sync_current_with_update_copy()...\n");
454 (void) mutex_lock(&info->mutex[1]);
455 (void) mutex_lock(&info->mutex[0]);
457 if (info->sinfo[1].server_status == INFO_SERVER_UP &&
458 info->sinfo[0].server_status != INFO_SERVER_UP)
459 info->sinfo[1].change = NS_SERVER_UP;
460 else if (info->sinfo[1].server_status != INFO_SERVER_UP &&
461 info->sinfo[0].server_status == INFO_SERVER_UP)
462 info->sinfo[1].change = NS_SERVER_DOWN;
463 else
464 info->sinfo[1].change = 0;
467 /* free memory in current copy first */
468 free(info->sinfo[0].addr);
469 info->sinfo[0].addr = NULL;
471 free(info->sinfo[0].hostname);
472 info->sinfo[0].hostname = NULL;
474 free(info->sinfo[0].rootDSE_data);
475 info->sinfo[0].rootDSE_data = NULL;
477 free(info->sinfo[0].errormsg);
478 info->sinfo[0].errormsg = NULL;
481 * make current and update copy identical
483 info->sinfo[0] = info->sinfo[1];
486 * getldap_get_server_stat() reads the update copy sinfo[1]
487 * so it can't be freed or nullified yet at this point.
489 * The sinfo[0] and sinfo[1] have identical string pointers.
490 * strdup the strings to avoid the double free problem.
491 * The strings of sinfo[1] are freed in
492 * getldap_get_rootDSE() and the strings of sinfo[0]
493 * are freed earlier in this function. If the pointers are the
494 * same, they will be freed twice.
496 if (info->sinfo[1].addr)
497 info->sinfo[0].addr = strdup(info->sinfo[1].addr);
498 if (info->sinfo[1].hostname)
499 info->sinfo[0].hostname = strdup(info->sinfo[1].hostname);
500 if (info->sinfo[1].rootDSE_data)
501 info->sinfo[0].rootDSE_data =
502 strdup(info->sinfo[1].rootDSE_data);
503 if (info->sinfo[1].errormsg)
504 info->sinfo[0].errormsg = strdup(info->sinfo[1].errormsg);
506 (void) mutex_unlock(&info->mutex[0]);
507 (void) mutex_unlock(&info->mutex[1]);
511 static void *
512 getldap_get_rootDSE(void *arg)
514 server_info_t *serverInfo = (server_info_t *)arg;
515 char *rootDSE;
516 int exitrc = NS_LDAP_SUCCESS;
517 pid_t ppid;
518 int server_found = 0;
519 char errmsg[MAXERROR];
520 ns_ldap_return_code rc;
521 ns_ldap_error_t *error = NULL;
523 if (current_admin.debug_level >= DBG_ALL) {
524 logit("getldap_get_rootDSE()....\n");
527 /* initialize the server info element */
528 (void) mutex_lock(&serverInfo->mutex[1]);
529 serverInfo->sinfo[1].type = INFO_RW_UNKNOWN;
530 serverInfo->sinfo[1].info_status =
531 INFO_STATUS_UNKNOWN;
533 * When the sever list is refreshed over and over,
534 * this function is called each time it is refreshed.
535 * The previous server status of the update copy(sinfo[1])
536 * is the status of the current copy
538 (void) mutex_lock(&serverInfo->mutex[0]);
539 serverInfo->sinfo[1].prev_server_status =
540 serverInfo->sinfo[0].server_status;
541 (void) mutex_unlock(&serverInfo->mutex[0]);
543 serverInfo->sinfo[1].server_status =
544 INFO_SERVER_UNKNOWN;
545 free(serverInfo->sinfo[1].rootDSE_data);
546 serverInfo->sinfo[1].rootDSE_data = NULL;
547 free(serverInfo->sinfo[1].errormsg);
548 serverInfo->sinfo[1].errormsg = NULL;
549 (void) mutex_unlock(&serverInfo->mutex[1]);
551 (void) mutex_lock(&serverInfo->mutex[1]);
552 serverInfo->sinfo[1].server_status = INFO_SERVER_CONNECTING;
553 (void) mutex_unlock(&serverInfo->mutex[1]);
556 * WARNING: anon_fallback == 1 (last argument) means that when
557 * __ns_ldap_getRootDSE is unable to bind using the configured
558 * credentials, it will try to fall back to using anonymous, non-SSL
559 * mode of operation.
561 * This is for backward compatibility reasons - we might have machines
562 * in the field with broken configuration (invalid credentials) and we
563 * don't want them to be disturbed.
565 if (rc = __ns_ldap_getRootDSE(serverInfo->sinfo[1].addr,
566 &rootDSE,
567 &error,
568 SA_ALLOW_FALLBACK) != NS_LDAP_SUCCESS) {
569 (void) mutex_lock(&serverInfo->mutex[1]);
570 serverInfo->sinfo[1].server_status = INFO_SERVER_ERROR;
571 serverInfo->sinfo[1].info_status = INFO_STATUS_ERROR;
572 if (error && error->message) {
573 serverInfo->sinfo[1].errormsg = strdup(error->message);
574 } else {
575 (void) snprintf(errmsg, sizeof (errmsg), "%s %s "
576 "(rc = %d)", gettext("Can not get the root DSE from"
577 " server"), serverInfo->sinfo[1].addr, rc);
578 serverInfo->sinfo[1].errormsg = strdup(errmsg);
581 if (error != NULL) {
582 (void) __ns_ldap_freeError(&error);
585 if (current_admin.debug_level >= DBG_ALL) {
586 logit("getldap_get_rootDSE: %s.\n",
587 serverInfo->sinfo[1].errormsg);
589 (void) mutex_unlock(&serverInfo->mutex[1]);
591 * sync sinfo copies in the serverInfo.
592 * protected by mutex
594 sync_current_with_update_copy(serverInfo);
595 thr_exit((void *) -1);
598 (void) mutex_lock(&serverInfo->mutex[1]);
600 /* assume writeable, i.e., can do modify */
601 serverInfo->sinfo[1].type = INFO_RW_WRITEABLE;
602 serverInfo->sinfo[1].server_status = INFO_SERVER_UP;
603 serverInfo->sinfo[1].info_status = INFO_STATUS_NEW;
604 /* remove the last DOORLINESEP */
605 *(rootDSE+strlen(rootDSE)-1) = '\0';
606 serverInfo->sinfo[1].rootDSE_data = rootDSE;
608 server_found = 1;
610 (void) mutex_unlock(&serverInfo->mutex[1]);
613 * sync sinfo copies in the serverInfo.
614 * protected by mutex
616 sync_current_with_update_copy(serverInfo);
618 * signal that the ldap_cachemgr parent process
619 * should exit now, if it is still waiting
621 (void) mutex_lock(&sig_mutex);
622 if (signal_done == FALSE && server_found) {
623 ppid = getppid();
624 (void) kill(ppid, SIGUSR1);
625 if (current_admin.debug_level >= DBG_ALL) {
626 logit("getldap_get_rootDSE(): "
627 "SIGUSR1 signal sent to "
628 "parent process(%ld).\n", ppid);
630 signal_done = TRUE;
632 (void) mutex_unlock(&sig_mutex);
634 thr_exit((void *) exitrc);
636 return (NULL);
639 static int
640 getldap_init_serverInfo(server_info_t **head)
642 char **servers = NULL;
643 int rc = 0, i, exitrc = NS_LDAP_SUCCESS;
644 ns_ldap_error_t *errorp = NULL;
645 server_info_t *info, *tail = NULL;
647 *head = NULL;
648 if (current_admin.debug_level >= DBG_ALL) {
649 logit("getldap_init_serverInfo()...\n");
651 rc = __s_api_getServers(&servers, &errorp);
653 if (rc != NS_LDAP_SUCCESS) {
654 logit("getldap_init_serverInfo: "
655 "__s_api_getServers failed.\n");
656 if (errorp)
657 __ns_ldap_freeError(&errorp);
658 return (-1);
660 for (i = 0; servers[i] != NULL; i++) {
661 info = (server_info_t *)calloc(1, sizeof (server_info_t));
662 if (info == NULL) {
663 logit("getldap_init_serverInfo: "
664 "not enough memory.\n");
665 exitrc = NS_LDAP_MEMORY;
666 break;
668 if (i == 0) {
669 *head = info;
670 tail = info;
671 } else {
672 tail->next = info;
673 tail = info;
676 info->sinfo[0].addr = strdup(servers[i]);
677 if (info->sinfo[0].addr == NULL) {
678 logit("getldap_init_serverInfo: "
679 "not enough memory.\n");
680 exitrc = NS_LDAP_MEMORY;
681 break;
683 info->sinfo[1].addr = strdup(servers[i]);
684 if (info->sinfo[1].addr == NULL) {
685 logit("getldap_init_serverInfo: "
686 "not enough memory.\n");
687 exitrc = NS_LDAP_MEMORY;
688 break;
691 info->sinfo[0].type = INFO_RW_UNKNOWN;
692 info->sinfo[1].type = INFO_RW_UNKNOWN;
693 info->sinfo[0].info_status = INFO_STATUS_UNKNOWN;
694 info->sinfo[1].info_status = INFO_STATUS_UNKNOWN;
695 info->sinfo[0].server_status = INFO_SERVER_UNKNOWN;
696 info->sinfo[1].server_status = INFO_SERVER_UNKNOWN;
699 * Assume at startup or after the configuration
700 * profile is refreshed, all servers are good.
702 info->sinfo[0].prev_server_status =
703 INFO_SERVER_UP;
704 info->sinfo[1].prev_server_status =
705 INFO_SERVER_UP;
706 info->sinfo[0].hostname = NULL;
707 info->sinfo[1].hostname = NULL;
708 info->sinfo[0].rootDSE_data = NULL;
709 info->sinfo[1].rootDSE_data = NULL;
710 info->sinfo[0].errormsg = NULL;
711 info->sinfo[1].errormsg = NULL;
712 info->next = NULL;
714 __s_api_free2dArray(servers);
715 if (exitrc != NS_LDAP_SUCCESS) {
716 if (head && *head) {
717 (void) getldap_destroy_serverInfo(*head);
718 *head = NULL;
721 return (exitrc);
724 static int
725 getldap_destroy_serverInfo(server_info_t *head)
727 server_info_t *info, *next;
729 if (current_admin.debug_level >= DBG_ALL) {
730 logit("getldap_destroy_serverInfo()...\n");
733 if (head == NULL) {
734 logit("getldap_destroy_serverInfo: "
735 "invalid serverInfo list.\n");
736 return (-1);
739 for (info = head; info; info = next) {
740 free(info->sinfo[0].addr);
741 free(info->sinfo[1].addr);
742 free(info->sinfo[0].hostname);
743 free(info->sinfo[1].hostname);
744 free(info->sinfo[0].rootDSE_data);
745 free(info->sinfo[1].rootDSE_data);
746 free(info->sinfo[0].errormsg);
747 free(info->sinfo[1].errormsg);
748 next = info->next;
749 free(info);
751 return (NS_LDAP_SUCCESS);
754 static int
755 getldap_set_serverInfo(server_info_t *head, int reset_bindtime, info_op_t op)
757 server_info_t *info;
758 int atleast1 = 0;
759 thread_t *tid;
760 int num_threads = 0, i, j;
761 void *status;
762 void **paramVal = NULL;
763 ns_ldap_error_t *error = NULL;
765 if (current_admin.debug_level >= DBG_ALL) {
766 logit("getldap_set_serverInfo()...\n");
769 if (head == NULL) {
770 logit("getldap_set_serverInfo: "
771 "invalid serverInfo list.\n");
772 return (-1);
775 /* Get the bind timeout value */
776 if (reset_bindtime == 1) {
777 tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
778 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P,
779 &paramVal, &error);
780 if (paramVal != NULL && *paramVal != NULL) {
781 /* convert to milliseconds */
782 tcptimeout = **((int **)paramVal);
783 tcptimeout *= 1000;
784 (void) __ns_ldap_freeParam(&paramVal);
786 if (error)
787 (void) __ns_ldap_freeError(&error);
790 for (info = head; info; info = info->next)
791 num_threads++;
793 if (num_threads == 0) {
794 logit("getldap_set_serverInfo: "
795 "empty serverInfo list.\n");
796 return (-1);
799 tid = (thread_t *) calloc(1, sizeof (thread_t) * num_threads);
800 if (tid == NULL) {
801 logit("getldap_set_serverInfo: "
802 "No memory to create thread ID list.\n");
803 return (-1);
806 for (info = head, i = 0; info; info = info->next, i++) {
807 if (thr_create(NULL, 0,
808 (void *(*)(void*))getldap_get_rootDSE,
809 (void *)info, 0, &tid[i])) {
810 logit("getldap_set_serverInfo: "
811 "can not create thread %d.\n", i + 1);
812 for (j = 0; j < i; j++)
813 (void) thr_join(tid[j], NULL, NULL);
814 free(tid);
815 return (-1);
819 for (i = 0; i < num_threads; i++) {
820 if (thr_join(tid[i], NULL, &status) == 0) {
821 if ((int)status == NS_LDAP_SUCCESS)
822 atleast1 = 1;
826 free(tid);
828 if (op == INFO_OP_REFRESH)
829 test_server_change(head);
830 if (atleast1) {
831 return (NS_LDAP_SUCCESS);
832 } else
833 return (-1);
837 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
838 * to this function from getldap_serverInfo_op().
839 * input:
840 * a buffer containing an empty string (e.g., input[0]='\0';) or a string
841 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
842 * addr);
843 * where addr is the address of a server and
844 * req is one of the following:
845 * NS_CACHE_NEW: send a new server address, addr is ignored.
846 * NS_CACHE_NORESP: send the next one, remove addr from list.
847 * NS_CACHE_NEXT: send the next one, keep addr on list.
848 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same
849 * as NS_CACHE_NEXT.
850 * addrtype:
851 * NS_CACHE_ADDR_IP: return server address as is, this is default.
852 * NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
853 * only self credential case requires such format.
854 * output:
855 * a buffer containing server info in the following format:
856 * serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
857 * [ attr=value [DOORLINESEP attr=value ]...]
858 * For example: ( here | used as DOORLINESEP for visual purposes)
859 * 1) simple bind and sasl/DIGEST-MD5 bind :
860 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
861 * supportedSASLmechanisms=GSSAPI
862 * 2) sasl/GSSAPI bind (self credential):
863 * 1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
864 * supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
865 * NOTE: caller should free this buffer when done using it
867 static int
868 getldap_get_serverInfo(server_info_t *head, char *input,
869 char **output, int *svr_removed)
871 server_info_t *info = NULL;
872 server_info_t *server = NULL;
873 char *addr = NULL;
874 char *req = NULL;
875 char req_new[] = NS_CACHE_NEW;
876 char addr_type[] = NS_CACHE_ADDR_IP;
877 int matched = FALSE, len = 0, rc = 0;
878 char *ret_addr = NULL, *ret_addrFQDN = NULL;
879 char *new_addr = NULL;
880 pid_t pid;
882 if (current_admin.debug_level >= DBG_ALL) {
883 logit("getldap_get_serverInfo()...\n");
886 if (input == NULL || output == NULL) {
887 logit("getldap_get_serverInfo: "
888 "No input or output buffer.\n");
889 return (-1);
892 *output = NULL;
893 *svr_removed = FALSE;
895 if (head == NULL) {
896 logit("getldap_get_serverInfo: "
897 "invalid serverInfo list.\n");
898 return (-1);
901 * parse the input string to get req and addr,
902 * if input is empty, i.e., input[0] == '\0',
903 * treat it as an NS_CACHE_NEW request
905 req = req_new;
906 if (input[0] != '\0') {
907 req = input;
908 /* Save addr type flag */
909 addr_type[0] = input[1];
910 input[strlen(NS_CACHE_NEW)] = '\0';
911 /* skip acion type flag, addr type flag and DOORLINESEP */
912 addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW)
913 + strlen(NS_CACHE_ADDR_IP);
916 * if NS_CACHE_NEW,
917 * or the server info is new,
918 * starts from the
919 * beginning of the list
921 if ((strcmp(req, NS_CACHE_NEW) == 0) ||
922 (head->sinfo[0].info_status == INFO_STATUS_NEW))
923 matched = TRUE;
924 for (info = head; info; info = info->next) {
926 * make sure the server info stays the same
927 * while the data is being processed
931 * This function is called to get server info list
932 * and pass it back to door call clients.
933 * Access the current copy (sinfo[0]) to get such
934 * information
936 (void) mutex_lock(&info->mutex[0]);
938 if (matched == FALSE &&
939 strcmp(info->sinfo[0].addr, addr) == 0) {
940 matched = TRUE;
941 if (strcmp(req, NS_CACHE_NORESP) == 0) {
942 if (chg_is_called_from_nscd_or_peruser_nscd(
943 "REMOVE SERVER", &pid) == 0) {
944 (void) mutex_unlock(&info->mutex[0]);
945 if (current_admin.debug_level >=
946 DBG_ALL)
947 logit("Only nscd can remove "
948 "servers. pid %ld", pid);
949 continue;
953 * if the information is new,
954 * give this server one more chance
956 if (info->sinfo[0].info_status ==
957 INFO_STATUS_NEW &&
958 info->sinfo[0].server_status ==
959 INFO_SERVER_UP) {
960 server = info;
961 break;
962 } else {
964 * it is recommended that
965 * before removing the
966 * server from the list,
967 * the server should be
968 * contacted one more time
969 * to make sure that it is
970 * really unavailable.
971 * For now, just trust the client
972 * (i.e., the sldap library)
973 * that it knows what it is
974 * doing and would not try
975 * to mess up the server
976 * list.
979 * Make a copy of addr to contact
980 * it later. It's not doing it here
981 * to avoid long wait and possible
982 * recursion to contact an LDAP server.
984 new_addr = strdup(info->sinfo[0].addr);
985 if (new_addr)
986 remove_server(new_addr);
987 *svr_removed = TRUE;
988 (void) mutex_unlock(&info->mutex[0]);
989 break;
991 } else {
993 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
995 (void) mutex_unlock(&info->mutex[0]);
996 continue;
1000 if (matched) {
1001 if (strcmp(req, NS_CACHE_WRITE) == 0) {
1002 if (info->sinfo[0].type ==
1003 INFO_RW_WRITEABLE &&
1004 info->sinfo[0].server_status ==
1005 INFO_SERVER_UP) {
1006 server = info;
1007 break;
1009 } else if (info->sinfo[0].server_status ==
1010 INFO_SERVER_UP) {
1011 server = info;
1012 break;
1016 (void) mutex_unlock(&info->mutex[0]);
1019 if (server) {
1020 if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) {
1022 * In SASL/GSSAPI case, a hostname is required for
1023 * Kerberos's service principal.
1024 * e.g.
1025 * ldap/foo.sun.com@SUN.COM
1027 if (server->sinfo[0].hostname == NULL) {
1028 rc = __s_api_ip2hostname(server->sinfo[0].addr,
1029 &server->sinfo[0].hostname);
1030 if (rc != NS_LDAP_SUCCESS) {
1031 (void) mutex_unlock(&info->mutex[0]);
1032 return (rc);
1034 if (current_admin.debug_level >= DBG_ALL) {
1035 logit("getldap_get_serverInfo: "
1036 "%s is converted to %s\n",
1037 server->sinfo[0].addr,
1038 server->sinfo[0].hostname);
1041 ret_addr = server->sinfo[0].addr;
1042 ret_addrFQDN = server->sinfo[0].hostname;
1044 } else
1045 ret_addr = server->sinfo[0].addr;
1048 len = strlen(ret_addr) +
1049 strlen(server->sinfo[0].rootDSE_data) +
1050 strlen(DOORLINESEP) + 1;
1051 if (ret_addrFQDN != NULL)
1052 len += strlen(ret_addrFQDN) + strlen(DOORLINESEP);
1053 *output = (char *)malloc(len);
1054 if (*output == NULL) {
1055 (void) mutex_unlock(&info->mutex[0]);
1056 return (NS_LDAP_MEMORY);
1058 if (ret_addrFQDN == NULL)
1059 (void) snprintf(*output, len, "%s%s%s",
1060 ret_addr, DOORLINESEP,
1061 server->sinfo[0].rootDSE_data);
1062 else
1063 (void) snprintf(*output, len, "%s%s%s%s%s",
1064 ret_addr, DOORLINESEP,
1065 ret_addrFQDN, DOORLINESEP,
1066 server->sinfo[0].rootDSE_data);
1067 server->sinfo[0].info_status = INFO_STATUS_OLD;
1068 (void) mutex_unlock(&info->mutex[0]);
1069 return (NS_LDAP_SUCCESS);
1071 else
1072 return (-99);
1076 * Format previous and next refresh time
1078 static int
1079 getldap_format_refresh_time(char **output, time_t *prev, time_t *next)
1081 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S"
1082 #define TIME_HEADER1 " Previous refresh time: "
1083 #define TIME_HEADER2 " Next refresh time: "
1084 int hdr1_len = strlen(gettext(TIME_HEADER1));
1085 int hdr2_len = strlen(gettext(TIME_HEADER2));
1086 struct tm tm;
1087 char nbuf[256];
1088 char pbuf[256];
1089 int len;
1091 if (current_admin.debug_level >= DBG_ALL) {
1092 logit("getldap_format_refresh_time()...\n");
1095 *output = NULL;
1097 /* format the time of previous refresh */
1098 if (*prev != 0) {
1099 (void) localtime_r(prev, &tm);
1100 (void) strftime(pbuf, sizeof (pbuf) - 1, TIME_FORMAT, &tm);
1101 } else {
1102 (void) strcpy(pbuf, gettext("NOT DONE"));
1105 /* format the time of next refresh */
1106 if (*next != 0) {
1107 (void) localtime_r(next, &tm);
1108 (void) strftime(nbuf, sizeof (nbuf) - 1, TIME_FORMAT, &tm);
1109 } else {
1110 (void) strcpy(nbuf, gettext("NOT SET"));
1113 len = hdr1_len + hdr2_len + strlen(nbuf) +
1114 strlen(pbuf) + 2 * strlen(DOORLINESEP) + 1;
1116 *output = malloc(len);
1117 if (*output == NULL)
1118 return (-1);
1120 (void) snprintf(*output, len, "%s%s%s%s%s%s",
1121 gettext(TIME_HEADER1), pbuf, DOORLINESEP,
1122 gettext(TIME_HEADER2), nbuf, DOORLINESEP);
1124 return (NS_LDAP_SUCCESS);
1128 * getldap_get_server_stat processes the GETSTAT request passed
1129 * to this function from getldap_serverInfo_op().
1130 * output:
1131 * a buffer containing info for all the servers.
1132 * For each server, the data is in the following format:
1133 * server: server address or name, status: unknown|up|down|removed DOORLINESEP
1134 * for example: ( here | used as DOORLINESEP for visual purposes)
1135 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1136 * NOTE: caller should free this buffer when done using it
1138 static int
1139 getldap_get_server_stat(server_info_t *head, char **output,
1140 time_t *prev, time_t *next)
1142 #define S_HEADER "Server information: "
1143 #define S_FORMAT " server: %s, status: %s%s"
1144 #define S_ERROR " error message: %s%s"
1145 server_info_t *info = NULL;
1146 int header_len = strlen(gettext(S_HEADER));
1147 int format_len = strlen(gettext(S_FORMAT));
1148 int error_len = strlen(gettext(S_ERROR));
1149 int len = header_len + strlen(DOORLINESEP);
1150 int len1 = 0;
1151 char *status, *output1 = NULL, *tmpptr;
1153 *output = NULL;
1155 if (current_admin.debug_level >= DBG_ALL) {
1156 logit("getldap_get_server_stat()...\n");
1159 if (head == NULL) {
1160 logit("getldap_get_server_stat: "
1161 "invalid serverInfo list.\n");
1162 return (-1);
1165 /* format previous and next refresh time */
1166 (void) getldap_format_refresh_time(&output1, prev, next);
1167 if (output1 == NULL)
1168 return (-1);
1169 len += strlen(output1);
1170 len1 = len + strlen(DOORLINESEP) + 1;
1172 *output = (char *)calloc(1, len1);
1173 if (*output == NULL) {
1174 free(output1);
1175 return (-1);
1178 /* insert header string and refresh time info */
1179 (void) snprintf(*output, len1, "%s%s%s",
1180 gettext(S_HEADER), DOORLINESEP, output1);
1182 for (info = head; info; info = info->next) {
1185 * make sure the server info stays the same
1186 * while the data is being processed
1188 (void) mutex_lock(&info->mutex[1]);
1191 * When the updating process is under way(getldap_get_rootDSE)
1192 * the update copy(sinfo[1] is the latest copy.
1193 * When the updating process
1194 * is done, the current copy (sinfo[0]) has the latest status,
1195 * which is still identical to the update copy.
1196 * So update copy has the latest status.
1197 * Use the update copy(sinfo[1]) to show status
1198 * (ldap_cachemgr -g).
1202 switch (info->sinfo[1].server_status) {
1203 case INFO_SERVER_UNKNOWN:
1204 status = gettext("UNKNOWN");
1205 break;
1206 case INFO_SERVER_CONNECTING:
1207 status = gettext("CONNECTING");
1208 break;
1209 case INFO_SERVER_UP:
1210 status = gettext("UP");
1211 break;
1212 case INFO_SERVER_ERROR:
1213 status = gettext("ERROR");
1214 break;
1215 case INFO_SERVER_REMOVED:
1216 status = gettext("REMOVED");
1217 break;
1220 len += format_len + strlen(status) +
1221 strlen(info->sinfo[1].addr) +
1222 strlen(DOORLINESEP);
1223 if (info->sinfo[1].errormsg != NULL)
1224 len += error_len +
1225 strlen(info->sinfo[1].errormsg) +
1226 strlen(DOORLINESEP);
1228 tmpptr = (char *)realloc(*output, len);
1229 if (tmpptr == NULL) {
1230 free(output1);
1231 free(*output);
1232 *output = NULL;
1233 (void) mutex_unlock(&info->mutex[1]);
1234 return (-1);
1235 } else
1236 *output = tmpptr;
1238 /* insert server IP addr or name and status */
1239 len1 = len - strlen(*output);
1240 (void) snprintf(*output + strlen(*output), len1,
1241 gettext(S_FORMAT), info->sinfo[1].addr,
1242 status, DOORLINESEP);
1243 /* insert error message if any */
1244 len1 = len - strlen(*output);
1245 if (info->sinfo[1].errormsg != NULL)
1246 (void) snprintf(*output + strlen(*output), len1,
1247 gettext(S_ERROR),
1248 info->sinfo[1].errormsg,
1249 DOORLINESEP);
1251 (void) mutex_unlock(&info->mutex[1]);
1255 free(output1);
1256 return (NS_LDAP_SUCCESS);
1260 * Format and return the refresh time statistics
1262 static int
1263 getldap_get_refresh_stat(char **output)
1265 #define R_HEADER0 "Configuration refresh information: "
1266 #define R_HEADER1 " Configured to NO REFRESH."
1267 int hdr0_len = strlen(gettext(R_HEADER0));
1268 int hdr1_len = strlen(gettext(R_HEADER1));
1269 int cache_ttl = -1, len = 0;
1270 time_t expire = 0;
1271 void **paramVal = NULL;
1272 ns_ldap_error_t *errorp = NULL;
1273 char *output1 = NULL;
1275 if (current_admin.debug_level >= DBG_ALL) {
1276 logit("getldap_get_refresh_stat()...\n");
1279 *output = NULL;
1281 /* get configured cache TTL */
1282 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1283 &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
1284 paramVal != NULL &&
1285 (char *)*paramVal != NULL) {
1286 cache_ttl = atol((char *)*paramVal);
1287 } else {
1288 if (errorp)
1289 __ns_ldap_freeError(&errorp);
1291 (void) __ns_ldap_freeParam(&paramVal);
1293 /* cound not get cache TTL */
1294 if (cache_ttl == -1)
1295 return (-1);
1297 if (cache_ttl == 0) {
1298 len = hdr0_len + hdr1_len +
1299 2 * strlen(DOORLINESEP) + 1;
1300 *output = malloc(len);
1301 if (*output == NULL)
1302 return (-1);
1303 (void) snprintf(*output, len, "%s%s%s%s",
1304 gettext(R_HEADER0), DOORLINESEP,
1305 gettext(R_HEADER1), DOORLINESEP);
1306 } else {
1308 /* get configuration expiration time */
1309 if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
1310 &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
1311 paramVal != NULL &&
1312 (char *)*paramVal != NULL) {
1313 expire = (time_t)atol((char *)*paramVal);
1314 } else {
1315 if (errorp)
1316 __ns_ldap_freeError(&errorp);
1319 (void) __ns_ldap_freeParam(&paramVal);
1321 /* cound not get expiration time */
1322 if (expire == -1)
1323 return (-1);
1325 /* format previous and next refresh time */
1326 (void) getldap_format_refresh_time(&output1,
1327 &prev_refresh_time, &expire);
1328 if (output1 == NULL)
1329 return (-1);
1331 len = hdr0_len + strlen(output1) +
1332 2 * strlen(DOORLINESEP) + 1;
1333 *output = malloc(len);
1334 if (*output == NULL) {
1335 free(output1);
1336 return (-1);
1338 (void) snprintf(*output, len, "%s%s%s%s",
1339 gettext(R_HEADER0), DOORLINESEP,
1340 output1, DOORLINESEP);
1341 free(output1);
1344 return (NS_LDAP_SUCCESS);
1347 static int
1348 getldap_get_cacheTTL()
1350 void **paramVal = NULL;
1351 ns_ldap_error_t *error;
1352 int rc = 0, cachettl;
1355 if (current_admin.debug_level >= DBG_ALL) {
1356 logit("getldap_get_cacheTTL()....\n");
1359 if ((rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1360 &paramVal, &error)) != NS_LDAP_SUCCESS) {
1361 if (error != NULL && error->message != NULL)
1362 logit("Error: Unable to get configuration "
1363 "refresh TTL: %s\n",
1364 error->message);
1365 else {
1366 char *tmp;
1368 __ns_ldap_err2str(rc, &tmp);
1369 logit("Error: Unable to get configuration "
1370 "refresh TTL: %s\n", tmp);
1372 (void) __ns_ldap_freeParam(&paramVal);
1373 (void) __ns_ldap_freeError(&error);
1374 return (-1);
1376 if (paramVal == NULL || (char *)*paramVal == NULL)
1377 return (-1);
1378 cachettl = atol((char *)*paramVal);
1379 (void) __ns_ldap_freeParam(&paramVal);
1380 return (cachettl);
1385 * This function implements the adaptive server list refresh
1386 * algorithm used by ldap_cachemgr. The idea is to have the
1387 * refresh TTL adjust itself between maximum and minimum
1388 * values. If the server list has been walked three times
1389 * in a row without errors, the TTL will be doubled. This will
1390 * be done repeatedly until the maximum value is reached
1391 * or passed. If passed, the maximum value will be used.
1392 * If any time a server is found to be down/bad, either
1393 * after another server list walk or informed by libsldap via
1394 * the GETLDAPSERVER door calls, the TTL will be set to half
1395 * of its value, again repeatedly, but no less than the minimum
1396 * value. Also, at any time, if all the servers on the list
1397 * are found to be down/bad, the TTL will be set to minimum,
1398 * so that a "no-server" refresh loop should be entered to try
1399 * to find a good server as soon as possible. The caller
1400 * could check the no_gd_server flag for this situation.
1401 * The maximum and minimum values are initialized when the input
1402 * refresh_ttl is set to zero, this should occur during
1403 * ldap_cachemgr startup or every time the server list is
1404 * recreated after the configuration profile is refreshed
1405 * from an LDAP server. The maximum is set to the value of
1406 * the NS_LDAP_CACHETTL parameter (configuration profile
1407 * refresh TTL), but if it is zero (never refreshed) or can
1408 * not be retrieved, the maximum is set to the macro
1409 * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1410 * set to REFRESHTTL_MIN, which is the TCP connection timeout
1411 * (tcptimeout) set via the LDAP API ldap_set_option()
1412 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1413 * This accounts for the maximum possible timeout value for an
1414 * LDAP TCP connect call.The first refresh TTL, initial value of
1415 * refresh_ttl, will be set to the smaller of the two,
1416 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1417 * The idea is to have a low starting value and have the value
1418 * stay low if the network/server is unstable, but eventually
1419 * the value will move up to maximum and stay there if the
1420 * network/server is stable.
1422 static int
1423 getldap_set_refresh_ttl(server_info_t *head, int *refresh_ttl,
1424 int *no_gd_server)
1426 #define REFRESHTTL_REGULAR 600
1427 #define REFRESHTTL_MAX 43200
1428 /* tcptimeout is in milliseconds */
1429 #define REFRESHTTL_MIN (tcptimeout/1000) + 10
1430 #define UP_REFRESH_TTL_NUM 2
1432 static mutex_t refresh_mutex;
1433 static int refresh_ttl_max = 0;
1434 static int refresh_ttl_min = 0;
1435 static int num_walked_ok = 0;
1436 int num_servers = 0;
1437 int num_good_servers = 0;
1438 int num_prev_good_servers = 0;
1439 server_info_t *info;
1441 /* allow one thread at a time */
1442 (void) mutex_lock(&refresh_mutex);
1444 if (current_admin.debug_level >= DBG_ALL) {
1445 logit("getldap_set_refresh_ttl()...\n");
1448 if (!head || !refresh_ttl || !no_gd_server) {
1449 logit("getldap_set_refresh_ttl: head is "
1450 "NULL or refresh_ttl is NULL or "
1451 "no_gd_server is NULL");
1452 (void) mutex_unlock(&refresh_mutex);
1453 return (-1);
1455 *no_gd_server = FALSE;
1458 * init max. min. TTLs if first time through or a fresh one
1460 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1461 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1462 "seconds\n", *refresh_ttl);
1464 if (*refresh_ttl == 0) {
1465 num_walked_ok = 0;
1467 * init cache manager server list TTL:
1469 * init the min. TTL to
1470 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1472 refresh_ttl_min = REFRESHTTL_MIN;
1475 * try to set the max. TTL to
1476 * configuration refresh TTL (NS_LDAP_CACHETTL),
1477 * if error (-1), or never refreshed (0),
1478 * set it to REFRESHTTL_MAX (12 hours)
1480 refresh_ttl_max = getldap_get_cacheTTL();
1481 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1482 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1483 "seconds\n", *refresh_ttl);
1484 logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1485 "min ttl is %d seconds\n",
1486 refresh_ttl_max, refresh_ttl_min);
1488 if (refresh_ttl_max <= 0)
1489 refresh_ttl_max = REFRESHTTL_MAX;
1490 else if (refresh_ttl_max < refresh_ttl_min)
1491 refresh_ttl_max = refresh_ttl_min;
1494 * init the first TTL to the smaller of the two:
1495 * REFRESHTTL_REGULAR ( 10 minutes),
1496 * (refresh_ttl_max + refresh_ttl_min)/2
1498 *refresh_ttl = REFRESHTTL_REGULAR;
1499 if (*refresh_ttl > (refresh_ttl_max + refresh_ttl_min) / 2)
1500 *refresh_ttl = (refresh_ttl_max + refresh_ttl_min) / 2;
1501 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1502 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1503 "seconds\n", *refresh_ttl);
1504 logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1505 "min ttl is %d seconds\n",
1506 refresh_ttl_max, refresh_ttl_min);
1511 * get the servers statistics:
1512 * number of servers on list
1513 * number of good servers on list
1514 * number of pevious good servers on list
1516 for (info = head; info; info = info->next) {
1517 num_servers++;
1518 (void) mutex_lock(&info->mutex[0]);
1519 if (info->sinfo[0].server_status == INFO_SERVER_UP)
1520 num_good_servers++;
1522 * Server's previous status could be UNKNOWN
1523 * only between the very first and second
1524 * refresh. Treat that UNKNOWN status as up
1526 if (info->sinfo[0].prev_server_status
1527 == INFO_SERVER_UP ||
1528 info->sinfo[0].prev_server_status
1529 == INFO_SERVER_UNKNOWN)
1530 num_prev_good_servers++;
1531 (void) mutex_unlock(&info->mutex[0]);
1535 * if the server list is walked three times in a row
1536 * without problems, double the refresh TTL but no more
1537 * than the max. refresh TTL
1539 if (num_good_servers == num_servers) {
1540 num_walked_ok++;
1541 if (num_walked_ok > UP_REFRESH_TTL_NUM) {
1543 *refresh_ttl = *refresh_ttl * 2;
1544 if (*refresh_ttl > refresh_ttl_max)
1545 *refresh_ttl = refresh_ttl_max;
1547 num_walked_ok = 0;
1549 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1550 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1551 "seconds\n", *refresh_ttl);
1553 } else if (num_good_servers == 0) {
1555 * if no good server found,
1556 * set refresh TTL to miminum
1558 *refresh_ttl = refresh_ttl_min;
1559 *no_gd_server = TRUE;
1560 num_walked_ok = 0;
1561 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1562 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1563 "seconds\n", *refresh_ttl);
1565 } else if (num_prev_good_servers > num_good_servers) {
1567 * if more down/bad servers found,
1568 * decrease the refresh TTL by half
1569 * but no less than the min. refresh TTL
1571 *refresh_ttl = *refresh_ttl / 2;
1572 if (*refresh_ttl < refresh_ttl_min)
1573 *refresh_ttl = refresh_ttl_min;
1574 num_walked_ok = 0;
1575 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1576 "seconds\n", *refresh_ttl);
1580 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1581 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1582 *refresh_ttl);
1584 (void) mutex_unlock(&refresh_mutex);
1585 return (0);
1588 static int
1589 getldap_serverInfo_op(info_op_t op, char *input, char **output)
1592 static rwlock_t info_lock = DEFAULTRWLOCK;
1593 static rwlock_t info_lock_old = DEFAULTRWLOCK;
1594 static mutex_t info_mutex;
1595 static cond_t info_cond;
1596 static int creating = FALSE;
1597 static int refresh_ttl = 0;
1598 static int sec_to_refresh = 0;
1599 static int in_no_server_mode = FALSE;
1601 static server_info_t *serverInfo = NULL;
1602 static server_info_t *serverInfo_old = NULL;
1603 server_info_t *serverInfo_1;
1604 int is_creating;
1605 int err, no_server_good = FALSE;
1606 int server_removed = FALSE;
1607 int fall_thru = FALSE;
1608 static struct timespec timeout;
1609 struct timespec new_timeout;
1610 struct timeval tp;
1611 static time_t prev_refresh = 0, next_refresh = 0;
1612 ns_server_status_t changed = 0;
1614 if (current_admin.debug_level >= DBG_ALL) {
1615 logit("getldap_serverInfo_op()...\n");
1617 switch (op) {
1618 case INFO_OP_CREATE:
1619 if (current_admin.debug_level >= DBG_ALL) {
1620 logit("operation is INFO_OP_CREATE...\n");
1624 * indicate that the server info is being
1625 * (re)created, so that the refresh thread
1626 * will not refresh the info list right
1627 * after the list got (re)created
1629 (void) mutex_lock(&info_mutex);
1630 is_creating = creating;
1631 creating = TRUE;
1632 (void) mutex_unlock(&info_mutex);
1634 if (is_creating)
1635 break;
1637 * create an empty info list
1639 (void) getldap_init_serverInfo(&serverInfo_1);
1641 * exit if list not created
1643 if (serverInfo_1 == NULL) {
1644 (void) mutex_lock(&info_mutex);
1645 creating = FALSE;
1646 (void) mutex_unlock(&info_mutex);
1647 break;
1650 * make the new server info available:
1651 * use writer lock here, so that the switch
1652 * is done after all the reader locks have
1653 * been released.
1655 (void) rw_wrlock(&info_lock);
1656 serverInfo = serverInfo_1;
1658 * if this is the first time
1659 * the server list is being created,
1660 * (i.e., serverInfo_old is NULL)
1661 * make the old list same as the new
1662 * so the GETSERVER code can do its work
1664 if (serverInfo_old == NULL)
1665 serverInfo_old = serverInfo_1;
1666 (void) rw_unlock(&info_lock);
1669 * fill the new info list
1671 (void) rw_rdlock(&info_lock);
1672 /* reset bind time (tcptimeout) */
1673 (void) getldap_set_serverInfo(serverInfo, 1, INFO_OP_CREATE);
1675 (void) mutex_lock(&info_mutex);
1677 * set cache manager server list TTL,
1678 * set refresh_ttl to zero to indicate a fresh one
1680 refresh_ttl = 0;
1681 (void) getldap_set_refresh_ttl(serverInfo,
1682 &refresh_ttl, &no_server_good);
1683 sec_to_refresh = refresh_ttl;
1685 /* statistics: previous refresh time */
1686 if (gettimeofday(&tp, NULL) == 0)
1687 prev_refresh = tp.tv_sec;
1689 creating = FALSE;
1692 * if no server found or available,
1693 * tell the server info refresh thread
1694 * to start the "no-server" refresh loop
1695 * otherwise reset the in_no_server_mode flag
1697 if (no_server_good) {
1698 sec_to_refresh = 0;
1699 in_no_server_mode = TRUE;
1700 } else
1701 in_no_server_mode = FALSE;
1703 * awake the sleeping refresh thread
1705 (void) cond_signal(&info_cond);
1707 (void) mutex_unlock(&info_mutex);
1708 (void) rw_unlock(&info_lock);
1711 * delete the old server info
1713 (void) rw_wrlock(&info_lock_old);
1714 if (serverInfo_old != serverInfo)
1715 (void) getldap_destroy_serverInfo(serverInfo_old);
1717 * serverInfo_old needs to be the same as
1718 * serverinfo now.
1719 * it will be used by GETSERVER processing.
1721 serverInfo_old = serverInfo;
1722 (void) rw_unlock(&info_lock_old);
1723 break;
1724 case INFO_OP_DELETE:
1725 if (current_admin.debug_level >= DBG_ALL) {
1726 logit("operation is INFO_OP_DELETE...\n");
1729 * use writer lock here, so that the delete would
1730 * not start until all the reader locks have
1731 * been released.
1733 (void) rw_wrlock(&info_lock);
1734 if (serverInfo)
1735 (void) getldap_destroy_serverInfo(serverInfo);
1736 serverInfo = NULL;
1737 (void) rw_unlock(&info_lock);
1738 break;
1739 case INFO_OP_REFRESH:
1740 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1741 logit("operation is INFO_OP_REFRESH...\n");
1744 * if server info is currently being
1745 * (re)created, do nothing
1747 (void) mutex_lock(&info_mutex);
1748 is_creating = creating;
1749 (void) mutex_unlock(&info_mutex);
1750 if (is_creating)
1751 break;
1753 (void) rw_rdlock(&info_lock);
1754 if (serverInfo) {
1755 /* do not reset bind time (tcptimeout) */
1756 (void) getldap_set_serverInfo(serverInfo, 0,
1757 INFO_OP_REFRESH);
1759 (void) mutex_lock(&info_mutex);
1761 /* statistics: previous refresh time */
1762 if (gettimeofday(&tp, NULL) == 0)
1763 prev_refresh = tp.tv_sec;
1765 * set cache manager server list TTL
1767 (void) getldap_set_refresh_ttl(serverInfo,
1768 &refresh_ttl, &no_server_good);
1770 * if no good server found,
1771 * tell the server info refresh thread
1772 * to start the "no-server" refresh loop
1773 * otherwise reset the in_no_server_mode flag
1775 if (no_server_good) {
1776 in_no_server_mode = TRUE;
1777 sec_to_refresh = 0;
1778 } else {
1779 in_no_server_mode = FALSE;
1780 sec_to_refresh = refresh_ttl;
1782 if (current_admin.debug_level >=
1783 DBG_SERVER_LIST_REFRESH) {
1784 logit("getldap_serverInfo_op("
1785 "INFO_OP_REFRESH):"
1786 " seconds refresh: %d second(s)....\n",
1787 sec_to_refresh);
1789 (void) mutex_unlock(&info_mutex);
1791 (void) rw_unlock(&info_lock);
1793 break;
1794 case INFO_OP_REFRESH_WAIT:
1795 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1796 logit("operation is INFO_OP_REFRESH_WAIT...\n");
1798 (void) cond_init(&info_cond, 0, NULL);
1799 (void) mutex_lock(&info_mutex);
1800 err = 0;
1801 while (err != ETIME) {
1802 int sleeptime;
1804 * if need to go into the "no-server" refresh
1805 * loop, set timout value to
1806 * REFRESH_DELAY_WHEN_NO_SERVER
1808 if (sec_to_refresh == 0) {
1809 sec_to_refresh = refresh_ttl;
1810 timeout.tv_sec = time(NULL) +
1811 REFRESH_DELAY_WHEN_NO_SERVER;
1812 sleeptime = REFRESH_DELAY_WHEN_NO_SERVER;
1813 if (current_admin.debug_level >=
1814 DBG_SERVER_LIST_REFRESH) {
1815 logit("getldap_serverInfo_op("
1816 "INFO_OP_REFRESH_WAIT):"
1817 " entering no-server "
1818 "refresh loop...\n");
1820 } else {
1821 timeout.tv_sec = time(NULL) + sec_to_refresh;
1822 sleeptime = sec_to_refresh;
1824 timeout.tv_nsec = 0;
1826 /* statistics: next refresh time */
1827 next_refresh = timeout.tv_sec;
1829 if (current_admin.debug_level >=
1830 DBG_SERVER_LIST_REFRESH) {
1831 logit("getldap_serverInfo_op("
1832 "INFO_OP_REFRESH_WAIT):"
1833 " about to sleep for %d second(s)...\n",
1834 sleeptime);
1836 err = cond_timedwait(&info_cond,
1837 &info_mutex, &timeout);
1839 (void) cond_destroy(&info_cond);
1840 (void) mutex_unlock(&info_mutex);
1841 break;
1842 case INFO_OP_GETSERVER:
1843 if (current_admin.debug_level >= DBG_ALL) {
1844 logit("operation is INFO_OP_GETSERVER...\n");
1846 *output = NULL;
1848 * GETSERVER processing always use
1849 * serverInfo_old to retrieve server infomation.
1850 * serverInfo_old is equal to serverInfo
1851 * most of the time, except when a new
1852 * server list is being created.
1853 * This is why the check for is_creating
1854 * is needed below.
1856 (void) rw_rdlock(&info_lock_old);
1858 if (serverInfo_old == NULL) {
1859 (void) rw_unlock(&info_lock_old);
1860 break;
1861 } else
1862 (void) getldap_get_serverInfo(serverInfo_old,
1863 input, output, &server_removed);
1864 (void) rw_unlock(&info_lock_old);
1867 * Return here and let remove server thread do its job in
1868 * another thread. It executes INFO_OP_REMOVESERVER code later.
1870 if (server_removed)
1871 break;
1873 fall_thru = TRUE;
1875 /* FALL THROUGH */
1877 case INFO_OP_REMOVESERVER:
1879 * INFO_OP_GETSERVER and INFO_OP_REMOVESERVER share the
1880 * following code except (!fall thru) part.
1884 * if server info is currently being
1885 * (re)created, do nothing
1888 (void) mutex_lock(&info_mutex);
1889 is_creating = creating;
1890 (void) mutex_unlock(&info_mutex);
1891 if (is_creating)
1892 break;
1894 if (!fall_thru) {
1895 if (current_admin.debug_level >= DBG_ALL)
1896 logit("operation is INFO_OP_REMOVESERVER...\n");
1897 (void) rw_rdlock(&info_lock_old);
1898 changed = set_server_status(input, serverInfo_old);
1899 (void) rw_unlock(&info_lock_old);
1900 if (changed)
1901 create_buf_and_notify(input, changed);
1902 else
1903 break;
1907 * set cache manager server list TTL if necessary
1909 if (*output == NULL || changed) {
1910 (void) rw_rdlock(&info_lock);
1911 (void) mutex_lock(&info_mutex);
1913 (void) getldap_set_refresh_ttl(serverInfo,
1914 &refresh_ttl, &no_server_good);
1917 * if no good server found, need to go into
1918 * the "no-server" refresh loop
1919 * to find a server as soon as possible
1920 * otherwise reset the in_no_server_mode flag
1922 if (no_server_good) {
1924 * if already in no-server mode,
1925 * don't brother
1927 if (in_no_server_mode == FALSE) {
1928 sec_to_refresh = 0;
1929 in_no_server_mode = TRUE;
1930 (void) cond_signal(&info_cond);
1932 (void) mutex_unlock(&info_mutex);
1933 (void) rw_unlock(&info_lock);
1934 break;
1935 } else {
1936 in_no_server_mode = FALSE;
1937 sec_to_refresh = refresh_ttl;
1940 * if the refresh thread will be timed out
1941 * longer than refresh_ttl seconds,
1942 * wake it up to make it wait on the new
1943 * time out value
1945 new_timeout.tv_sec = time(NULL) + refresh_ttl;
1946 if (new_timeout.tv_sec < timeout.tv_sec)
1947 (void) cond_signal(&info_cond);
1949 (void) mutex_unlock(&info_mutex);
1950 (void) rw_unlock(&info_lock);
1952 break;
1953 case INFO_OP_GETSTAT:
1954 if (current_admin.debug_level >= DBG_ALL) {
1955 logit("operation is INFO_OP_GETSTAT...\n");
1957 *output = NULL;
1958 (void) rw_rdlock(&info_lock);
1959 if (serverInfo) {
1960 (void) getldap_get_server_stat(serverInfo,
1961 output, &prev_refresh, &next_refresh);
1963 (void) rw_unlock(&info_lock);
1964 break;
1965 default:
1966 logit("getldap_serverInfo_op(): "
1967 "invalid operation code (%d).\n", op);
1968 return (-1);
1969 break;
1971 return (NS_LDAP_SUCCESS);
1974 void
1975 getldap_serverInfo_refresh()
1977 int always = 1;
1979 if (current_admin.debug_level >= DBG_ALL) {
1980 logit("getldap_serverInfo_refresh()...\n");
1983 /* create the server info list */
1984 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
1986 while (always) {
1988 * the operation INFO_OP_REFRESH_WAIT
1989 * causes this thread to wait until
1990 * it is time to do refresh,
1991 * see getldap_serverInfo_op() for details
1993 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT, NULL, NULL);
1994 (void) getldap_serverInfo_op(INFO_OP_REFRESH, NULL, NULL);
1998 void
1999 getldap_getserver(LineBuf *config_info, ldap_call_t *in)
2001 char req[] = "0";
2003 if (current_admin.debug_level >= DBG_ALL) {
2004 logit("getldap_getserver()...\n");
2007 config_info->len = 0;
2009 /* make sure the request is valid */
2010 req[0] = (in->ldap_u.servername)[0];
2011 if ((req[0] != '\0') &&
2012 (strcmp(req, NS_CACHE_NEW) != 0) &&
2013 (strcmp(req, NS_CACHE_NORESP) != 0) &&
2014 (strcmp(req, NS_CACHE_NEXT) != 0) &&
2015 (strcmp(req, NS_CACHE_WRITE) != 0)) {
2016 return;
2019 (void) getldap_serverInfo_op(INFO_OP_GETSERVER,
2020 in->ldap_u.domainname, &config_info->str);
2022 if (config_info->str == NULL)
2023 return;
2025 config_info->len = strlen(config_info->str) + 1;
2027 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2028 /* Log server IP */
2029 char *ptr,
2030 separator;
2031 ptr = strstr(config_info->str, DOORLINESEP);
2032 if (ptr) {
2033 separator = *ptr;
2034 *ptr = '\0';
2035 logit("getldap_getserver: got server %s\n",
2036 config_info->str);
2037 *ptr = separator;
2038 } else
2039 logit("getldap_getserver: Missing %s."
2040 " Internal error\n", DOORLINESEP);
2044 void
2045 getldap_get_cacheData(LineBuf *config_info, ldap_call_t *in)
2047 char *instr = NULL;
2048 int datatype = CACHE_MAP_UNKNOWN;
2050 if (current_admin.debug_level >= DBG_ALL) {
2051 logit("getldap_get_cacheData()...\n");
2054 config_info->len = 0;
2055 config_info->str = NULL;
2057 /* make sure the request is valid */
2058 if (strncmp(in->ldap_u.servername,
2059 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2060 datatype = CACHE_MAP_DN2DOMAIN;
2062 if (datatype == CACHE_MAP_UNKNOWN)
2063 return;
2065 instr = strstr(in->ldap_u.servername, DOORLINESEP);
2066 if (instr == NULL)
2067 return;
2068 instr += strlen(DOORLINESEP);
2069 if (*instr == '\0')
2070 return;
2072 (void) getldap_cache_op(CACHE_OP_FIND, datatype,
2073 instr, &config_info->str);
2075 if (config_info->str != NULL) {
2076 config_info->len = strlen(config_info->str) + 1;
2081 getldap_set_cacheData(ldap_call_t *in)
2083 char *instr1 = NULL;
2084 char *instr2 = NULL;
2085 int datatype = CACHE_MAP_UNKNOWN;
2086 int rc = 0;
2088 if (current_admin.debug_level >= DBG_ALL) {
2089 logit("getldap_set_cacheData()...\n");
2092 /* make sure the request is valid */
2093 if (strncmp(in->ldap_u.servername,
2094 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2095 datatype = CACHE_MAP_DN2DOMAIN;
2097 if (datatype == CACHE_MAP_UNKNOWN)
2098 return (-1);
2100 instr1 = strstr(in->ldap_u.servername, DOORLINESEP);
2101 if (instr1 == NULL)
2102 return (-1);
2103 *instr1 = '\0';
2104 instr1 += strlen(DOORLINESEP);
2105 if (*instr1 == '\0')
2106 return (-1);
2107 instr2 = strstr(instr1, DOORLINESEP);
2108 if (instr2 == NULL)
2109 return (-1);
2110 *instr2 = '\0';
2111 instr2 += strlen(DOORLINESEP);
2112 if (*instr2 == '\0')
2113 return (-1);
2115 rc = getldap_cache_op(CACHE_OP_ADD, datatype,
2116 instr1, &instr2);
2117 if (rc != NS_LDAP_SUCCESS)
2118 return (-1);
2120 return (0);
2123 void
2124 getldap_get_cacheStat(LineBuf *stat_info)
2126 char *foutstr = NULL;
2127 char *soutstr = NULL;
2128 char *coutstr = NULL;
2129 int infoSize;
2131 if (current_admin.debug_level >= DBG_ALL) {
2132 logit("getldap_get_cacheStat()...\n");
2135 stat_info->str = NULL;
2136 stat_info->len = 0;
2138 /* get refersh statisitcs */
2139 (void) getldap_get_refresh_stat(&foutstr);
2140 if (foutstr == NULL)
2141 return;
2143 /* get server statisitcs */
2144 (void) getldap_serverInfo_op(INFO_OP_GETSTAT, NULL, &soutstr);
2145 if (soutstr == NULL) {
2146 free(foutstr);
2147 return;
2149 /* get cache data statisitcs */
2150 (void) getldap_cache_op(CACHE_OP_GETSTAT, 0, NULL, &coutstr);
2151 if (coutstr == NULL) {
2152 free(foutstr);
2153 free(soutstr);
2154 return;
2157 infoSize = strlen(foutstr) + strlen(soutstr) + strlen(coutstr) + 3;
2158 stat_info->str = calloc(infoSize, sizeof (char));
2159 if (stat_info->str != NULL) {
2160 (void) strncpy(stat_info->str,
2161 foutstr,
2162 strlen(foutstr) + 1);
2163 (void) strncat(stat_info->str,
2164 soutstr,
2165 strlen(soutstr) + 1);
2166 (void) strncat(stat_info->str,
2167 coutstr,
2168 strlen(coutstr) + 1);
2169 stat_info->len = infoSize;
2172 free(foutstr);
2173 free(soutstr);
2174 free(coutstr);
2177 static int
2178 checkupdate(int sighup)
2180 int value;
2182 (void) rw_wrlock(&ldap_lock);
2183 value = sighup;
2184 (void) rw_unlock(&ldap_lock);
2186 return (value == TRUE);
2190 static int
2191 update_from_profile(int *change_status)
2193 ns_ldap_result_t *result = NULL;
2194 char searchfilter[BUFSIZ];
2195 ns_ldap_error_t *error;
2196 int rc;
2197 void **paramVal = NULL;
2198 ns_config_t *ptr = NULL;
2199 char *profile = NULL;
2200 char errstr[MAXERROR];
2202 if (current_admin.debug_level >= DBG_ALL) {
2203 logit("update_from_profile....\n");
2205 do {
2206 (void) rw_wrlock(&ldap_lock);
2207 sighup_update = FALSE;
2208 (void) rw_unlock(&ldap_lock);
2210 if ((rc = __ns_ldap_getParam(NS_LDAP_PROFILE_P,
2211 &paramVal, &error)) != NS_LDAP_SUCCESS) {
2212 if (error != NULL && error->message != NULL)
2213 logit("Error: Unable to profile name: %s\n",
2214 error->message);
2215 else {
2216 char *tmp;
2218 __ns_ldap_err2str(rc, &tmp);
2219 logit("Error: Unable to profile name: %s\n",
2220 tmp);
2222 (void) __ns_ldap_freeParam(&paramVal);
2223 (void) __ns_ldap_freeError(&error);
2224 return (-1);
2227 if (paramVal && *paramVal)
2228 profile = strdup((char *)*paramVal);
2229 (void) __ns_ldap_freeParam(&paramVal);
2231 if (profile == NULL) {
2232 return (-1);
2235 (void) snprintf(searchfilter, BUFSIZ, _PROFILE_FILTER,
2236 _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
2238 if ((rc = __ns_ldap_list(_PROFILE_CONTAINER,
2239 (const char *)searchfilter, NULL,
2240 NULL, NULL, 0,
2241 &result, &error, NULL, NULL)) != NS_LDAP_SUCCESS) {
2244 * Is profile name the DEFAULTCONFIGNAME?
2245 * syslog Warning, otherwise syslog error.
2247 if (strcmp(profile, DEFAULTCONFIGNAME) == 0) {
2248 syslog(LOG_WARNING,
2249 "Ignoring attempt to refresh nonexistent "
2250 "default profile: %s.\n",
2251 profile);
2252 logit("Ignoring attempt to refresh nonexistent "
2253 "default profile: %s.\n",
2254 profile);
2255 } else if ((error != NULL) &&
2256 (error->message != NULL)) {
2257 syslog(LOG_ERR,
2258 "Error: Unable to refresh profile:%s:"
2259 " %s\n", profile, error->message);
2260 logit("Error: Unable to refresh profile:"
2261 "%s:%s\n", profile, error->message);
2262 } else {
2263 syslog(LOG_ERR, "Error: Unable to refresh "
2264 "from profile:%s. (error=%d)\n",
2265 profile, rc);
2266 logit("Error: Unable to refresh from profile "
2267 "%s (error=%d)\n", profile, rc);
2270 (void) __ns_ldap_freeError(&error);
2271 (void) __ns_ldap_freeResult(&result);
2272 free(profile);
2273 return (-1);
2275 free(profile);
2278 } while (checkupdate(sighup_update) == TRUE);
2280 (void) rw_wrlock(&ldap_lock);
2282 ptr = __ns_ldap_make_config(result);
2283 (void) __ns_ldap_freeResult(&result);
2285 if (ptr == NULL) {
2286 logit("Error: __ns_ldap_make_config failed.\n");
2287 (void) rw_unlock(&ldap_lock);
2288 return (-1);
2292 * cross check the config parameters
2294 if (__s_api_crosscheck(ptr, errstr, B_TRUE) == NS_SUCCESS) {
2296 * reset the local profile TTL
2298 if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc)
2299 current_admin.ldap_stat.ldap_ttl =
2300 atol(ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc);
2302 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2303 logit("update_from_profile: reset profile TTL to %d"
2304 " seconds\n",
2305 current_admin.ldap_stat.ldap_ttl);
2306 logit("update_from_profile: expire time %ld "
2307 "seconds\n",
2308 ptr->paramList[NS_LDAP_EXP_P].ns_tm);
2311 /* set ptr as current_config if the config is changed */
2312 chg_test_config_change(ptr, change_status);
2313 rc = 0;
2314 } else {
2315 __s_api_destroy_config(ptr);
2316 logit("Error: downloaded profile failed to pass "
2317 "crosscheck (%s).\n", errstr);
2318 syslog(LOG_ERR, "ldap_cachemgr: %s", errstr);
2319 rc = -1;
2321 (void) rw_unlock(&ldap_lock);
2323 return (rc);
2327 getldap_init()
2329 ns_ldap_error_t *error;
2330 struct timeval tp;
2331 ldap_get_chg_cookie_t cookie;
2333 if (current_admin.debug_level >= DBG_ALL) {
2334 logit("getldap_init()...\n");
2337 (void) __ns_ldap_setServer(TRUE);
2339 (void) rw_wrlock(&ldap_lock);
2340 if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
2341 logit("Error: Unable to read '%s': %s\n",
2342 NSCONFIGFILE, error->message);
2343 (void) fprintf(stderr,
2344 gettext("\nError: Unable to read '%s': %s\n"),
2345 NSCONFIGFILE, error->message);
2346 __ns_ldap_freeError(&error);
2347 (void) rw_unlock(&ldap_lock);
2348 return (-1);
2350 (void) rw_unlock(&ldap_lock);
2352 if (gettimeofday(&tp, NULL) == 0) {
2353 /* statistics: previous refresh time */
2354 prev_refresh_time = tp.tv_sec;
2357 /* initialize the data cache */
2358 (void) getldap_cache_op(CACHE_OP_CREATE,
2359 0, NULL, NULL);
2361 cookie.mgr_pid = getpid();
2362 cookie.seq_num = 0;
2363 chg_config_cookie_set(&cookie);
2364 return (0);
2367 static void
2368 perform_update(void)
2370 ns_ldap_error_t *error = NULL;
2371 struct timeval tp;
2372 char buf[20];
2373 int rc, rc1;
2374 int changed = 0;
2375 void **paramVal = NULL;
2376 ns_ldap_self_gssapi_config_t config;
2378 if (current_admin.debug_level >= DBG_ALL) {
2379 logit("perform_update()...\n");
2382 (void) __ns_ldap_setServer(TRUE);
2384 if (gettimeofday(&tp, NULL) != 0)
2385 return;
2387 rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, &paramVal, &error);
2389 if (rc == NS_LDAP_SUCCESS && paramVal != NULL) {
2390 current_admin.ldap_stat.ldap_ttl = atol((char *)*paramVal);
2393 if (error != NULL)
2394 (void) __ns_ldap_freeError(&error);
2396 if (paramVal != NULL)
2397 (void) __ns_ldap_freeParam(&paramVal);
2399 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2400 logit("perform_update: current profile TTL is %d seconds\n",
2401 current_admin.ldap_stat.ldap_ttl);
2404 if (current_admin.ldap_stat.ldap_ttl > 0) {
2406 * set the profile TTL parameter, just
2407 * in case that the downloading of
2408 * the profile from server would fail
2412 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2413 * It depends on NS_LDAP_CACHETTL_P to set it's value
2414 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2415 * can be set.
2416 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2417 * downloaded from the server, so is NS_LDAP_EXP_P.
2419 buf[19] = '\0'; /* null terminated the buffer */
2420 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P,
2421 lltostr((long long)current_admin.ldap_stat.ldap_ttl,
2422 &buf[19]),
2423 &error) != NS_LDAP_SUCCESS) {
2424 logit("Error: __ns_ldap_setParam failed, status: %d "
2425 "message: %s\n", error->status, error->message);
2426 (void) __ns_ldap_freeError(&error);
2427 return;
2430 (void) rw_wrlock(&ldap_lock);
2431 sighup_update = FALSE;
2432 (void) rw_unlock(&ldap_lock);
2434 do {
2435 rc = update_from_profile(&changed);
2436 if (rc != 0) {
2437 logit("Error: Unable to update from profile\n");
2439 } while (checkupdate(sighup_update) == TRUE);
2440 } else {
2441 rc = 0;
2445 * recreate the server info list
2447 if (rc == 0) {
2448 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2450 /* flush the data cache */
2451 (void) getldap_cache_op(CACHE_OP_DELETE,
2452 0, NULL, NULL);
2454 /* statistics: previous refresh time */
2455 prev_refresh_time = tp.tv_sec;
2457 rc1 = __ns_ldap_self_gssapi_config(&config);
2458 if (rc1 == NS_LDAP_SUCCESS) {
2459 if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) {
2460 rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error);
2461 (void) __ns_ldap_freeError(&error);
2462 if (rc1 != NS_LDAP_SUCCESS) {
2463 logit("Error: Check on self credential "
2464 "prerquesites failed: %d\n",
2465 rc1);
2466 exit(rc1);
2469 } else {
2470 logit("Error: Failed to get self credential configuration %d\n",
2471 rc1);
2472 exit(rc1);
2475 if (!changed)
2476 return;
2478 (void) rw_rdlock(&ldap_lock);
2479 if (((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) ||
2480 ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL)) {
2481 logit("Error: __ns_ldap_DumpConfiguration failed, "
2482 "status: %d message: %s\n", error->status, error->message);
2483 __ns_ldap_freeError(&error);
2484 (void) rw_unlock(&ldap_lock);
2485 return;
2487 if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0) {
2488 logit("Error: unlink failed - errno: %s\n", strerror(errno));
2489 syslog(LOG_ERR, "Unable to refresh profile, LDAP configuration"
2490 "files not written");
2491 (void) rw_unlock(&ldap_lock);
2492 return;
2494 if (rename(NSCREDREFRESH, NSCREDFILE) != 0) {
2496 * We probably have inconsistent configuration at this point.
2497 * If we were to create a backup file and rename it here, that
2498 * operation might also fail. Consequently there is no safe way
2499 * to roll back.
2501 logit("Error: unlink failed - errno: %s\n", strerror(errno));
2502 syslog(LOG_ERR, "Unable to refresh profile consistently, "
2503 "LDAP configuration files inconsistent");
2504 (void) rw_unlock(&ldap_lock);
2505 return;
2508 (void) rw_unlock(&ldap_lock);
2511 void
2512 getldap_refresh()
2514 struct timespec timeout;
2515 int sleeptime;
2516 struct timeval tp;
2517 long expire = 0;
2518 void **paramVal = NULL;
2519 ns_ldap_error_t *errorp;
2520 int always = 1, err;
2521 int first_time = 1;
2522 int sig_done = 0;
2523 int dbg_level;
2525 if (current_admin.debug_level >= DBG_ALL) {
2526 logit("getldap_refresh()...\n");
2530 * wait for an available server
2532 while (sig_done == 0) {
2533 (void) mutex_lock(&sig_mutex);
2534 sig_done = signal_done;
2535 (void) mutex_unlock(&sig_mutex);
2538 (void) __ns_ldap_setServer(TRUE);
2539 while (always) {
2540 dbg_level = current_admin.debug_level;
2541 (void) rw_rdlock(&ldap_lock);
2542 sleeptime = current_admin.ldap_stat.ldap_ttl;
2543 if (dbg_level >= DBG_PROFILE_REFRESH) {
2544 logit("getldap_refresh: current profile TTL is %d "
2545 "seconds\n", current_admin.ldap_stat.ldap_ttl);
2547 if (gettimeofday(&tp, NULL) == 0) {
2548 if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
2549 &paramVal, &errorp) == NS_LDAP_SUCCESS) &&
2550 paramVal != NULL &&
2551 (char *)*paramVal != NULL) {
2552 errno = 0;
2553 expire = atol((char *)*paramVal);
2554 (void) __ns_ldap_freeParam(&paramVal);
2555 if (errno == 0) {
2556 if (expire == 0) {
2557 first_time = 0;
2558 (void) rw_unlock(&ldap_lock);
2559 (void) cond_init(&cond,
2560 0, NULL);
2561 (void) mutex_lock(&sighuplock);
2562 timeout.tv_sec =
2563 CACHESLEEPTIME;
2564 timeout.tv_nsec = 0;
2565 if (dbg_level >=
2566 DBG_PROFILE_REFRESH) {
2567 logit("getldap_refresh:"
2568 "(1)about to sleep"
2569 " for %d seconds\n",
2570 CACHESLEEPTIME);
2572 err = cond_reltimedwait(&cond,
2573 &sighuplock, &timeout);
2574 (void) cond_destroy(&cond);
2575 (void) mutex_unlock(
2576 &sighuplock);
2578 * if woke up by
2579 * getldap_revalidate(),
2580 * do update right away
2582 if (err == ETIME)
2583 continue;
2584 else {
2586 * if load
2587 * configuration failed
2588 * don't do update
2590 if (load_config())
2591 perform_update
2593 continue;
2596 sleeptime = expire - tp.tv_sec;
2597 if (dbg_level >= DBG_PROFILE_REFRESH) {
2598 logit("getldap_refresh: expire "
2599 "time = %ld\n", expire);
2606 (void) rw_unlock(&ldap_lock);
2609 * if this is the first time downloading
2610 * the profile or expire time already passed,
2611 * do not wait, do update
2613 if (first_time == 0 && sleeptime > 0) {
2614 if (dbg_level >= DBG_PROFILE_REFRESH) {
2615 logit("getldap_refresh: (2)about to sleep "
2616 "for %d seconds\n", sleeptime);
2618 (void) cond_init(&cond, 0, NULL);
2619 (void) mutex_lock(&sighuplock);
2620 timeout.tv_sec = sleeptime;
2621 timeout.tv_nsec = 0;
2622 err = cond_reltimedwait(&cond,
2623 &sighuplock, &timeout);
2624 (void) cond_destroy(&cond);
2625 (void) mutex_unlock(&sighuplock);
2628 * if load concfiguration failed
2629 * don't do update
2631 if (load_config())
2632 perform_update();
2633 first_time = 0;
2637 void
2638 getldap_revalidate()
2640 if (current_admin.debug_level >= DBG_ALL) {
2641 logit("getldap_revalidate()...\n");
2643 /* block signal SIGHUP */
2644 (void) sighold(SIGHUP);
2646 /* now awake the sleeping refresh thread */
2647 (void) cond_signal(&cond);
2649 /* release signal SIGHUP */
2650 (void) sigrelse(SIGHUP);
2654 void
2655 getldap_admincred(LineBuf *config_info, ldap_call_t *in)
2657 ns_ldap_error_t *error;
2658 ldap_config_out_t *cout;
2659 ucred_t *uc = NULL;
2661 if (current_admin.debug_level >= DBG_ALL) {
2662 logit("getldap_admincred()...\n");
2664 /* check privileges */
2665 if (is_root_or_all_privs("GETADMINCRED", &uc) == 0) {
2666 logit("admin credential requested by a non-root and no ALL "
2667 "privilege user not allowed");
2668 config_info->str = NULL;
2669 config_info->len = 0;
2670 } else {
2671 (void) rw_rdlock(&ldap_lock);
2672 if ((error = __ns_ldap_LoadDoorInfo(config_info,
2673 in->ldap_u.domainname, NULL, 1)) != NULL) {
2674 if (error != NULL && error->message != NULL)
2675 logit("Error: ldap_lookup: %s\n",
2676 error->message);
2677 (void) __ns_ldap_freeError(&error);
2679 config_info->str = NULL;
2680 config_info->len = 0;
2682 /* set change cookie */
2683 cout = (ldap_config_out_t *)config_info->str;
2684 if (cout)
2685 cout->cookie = chg_config_cookie_get();
2686 (void) rw_unlock(&ldap_lock);
2690 void
2691 getldap_lookup(LineBuf *config_info, ldap_call_t *in)
2693 ns_ldap_error_t *error;
2694 ldap_config_out_t *cout;
2696 if (current_admin.debug_level >= DBG_ALL) {
2697 logit("getldap_lookup()...\n");
2699 (void) rw_rdlock(&ldap_lock);
2700 if ((error = __ns_ldap_LoadDoorInfo(config_info,
2701 in->ldap_u.domainname, NULL, 0)) != NULL) {
2702 if (error != NULL && error->message != NULL)
2703 logit("Error: ldap_lookup: %s\n", error->message);
2704 (void) __ns_ldap_freeError(&error);
2706 config_info->str = NULL;
2707 config_info->len = 0;
2709 /* set change cookie */
2710 cout = (ldap_config_out_t *)config_info->str;
2711 if (cout)
2712 cout->cookie = chg_config_cookie_get();
2713 (void) rw_unlock(&ldap_lock);
2716 * It creates the header and data stream to be door returned and notify
2717 * chg_get_statusChange() threads.
2718 * This is called after all getldap_get_rootDSE() threads are joined.
2720 void
2721 test_server_change(server_info_t *head)
2723 server_info_t *info;
2724 int len = 0, num = 0, ds_len = 0, new_len = 0, tlen = 0;
2725 char *tmp_buf = NULL, *ptr = NULL, *status = NULL;
2726 ldap_get_change_out_t *cout;
2728 ds_len = strlen(DOORLINESEP);
2730 for (info = head; info; info = info->next) {
2731 (void) mutex_lock(&info->mutex[0]);
2732 if (info->sinfo[0].change != 0) {
2733 /* "9.9.9.9|NS_SERVER_CHANGE_UP|" */
2734 len += 2 * ds_len + strlen(info->sinfo[0].addr) +
2735 strlen(NS_SERVER_CHANGE_UP);
2736 num++;
2738 (void) mutex_unlock(&info->mutex[0]);
2741 if (len == 0)
2742 return;
2744 len++; /* '\0' */
2746 tlen = sizeof (ldap_get_change_out_t) - sizeof (int) + len;
2747 if ((tmp_buf = malloc(tlen)) == NULL)
2748 return;
2750 cout = (ldap_get_change_out_t *)tmp_buf;
2751 cout->type = NS_STATUS_CHANGE_TYPE_SERVER;
2752 /* cout->cookie is set by chg_notify_statusChange */
2753 cout->server_count = num;
2754 cout->data_size = len;
2756 /* Create IP|UP or DOWN|IP|UP or DOWN| ... */
2757 ptr = cout->data;
2758 new_len = len;
2759 for (info = head; info; info = info->next) {
2760 (void) mutex_lock(&info->mutex[0]);
2761 if (info->sinfo[0].change == 0) {
2762 (void) mutex_unlock(&info->mutex[0]);
2763 continue;
2766 if (info->sinfo[0].change == NS_SERVER_UP)
2767 status = NS_SERVER_CHANGE_UP;
2768 else if (info->sinfo[0].change == NS_SERVER_DOWN)
2769 status = NS_SERVER_CHANGE_DOWN;
2770 else {
2771 syslog(LOG_WARNING, gettext("Bad change value %d"),
2772 info->sinfo[0].change);
2773 (void) mutex_unlock(&info->mutex[0]);
2774 free(tmp_buf);
2775 return;
2778 if ((snprintf(ptr, new_len, "%s%s%s%s",
2779 info->sinfo[0].addr, DOORLINESEP,
2780 status, DOORLINESEP)) >= new_len) {
2781 (void) mutex_unlock(&info->mutex[0]);
2782 break;
2784 new_len -= strlen(ptr);
2785 ptr += strlen(ptr);
2787 (void) mutex_unlock(&info->mutex[0]);
2789 (void) chg_notify_statusChange(tmp_buf);
2792 * It creates the header and data stream to be door returned and notify
2793 * chg_get_statusChange() threads.
2794 * This is called in removing server case.
2796 static void
2797 create_buf_and_notify(char *input, ns_server_status_t st)
2799 rm_svr_t *rms = (rm_svr_t *)input;
2800 char *tmp_buf, *ptr, *status;
2801 int len, tlen;
2802 ldap_get_change_out_t *cout;
2804 /* IP|UP or DOWN| */
2805 len = 2 * strlen(DOORLINESEP) + strlen(rms->addr) +
2806 strlen(NS_SERVER_CHANGE_UP) + 1;
2808 tlen = sizeof (ldap_get_change_out_t) - sizeof (int) + len;
2810 if ((tmp_buf = malloc(tlen)) == NULL)
2811 return;
2813 cout = (ldap_get_change_out_t *)tmp_buf;
2814 cout->type = NS_STATUS_CHANGE_TYPE_SERVER;
2815 /* cout->cookie is set by chg_notify_statusChange */
2816 cout->server_count = 1;
2817 cout->data_size = len;
2819 /* Create IP|DOWN| */
2820 ptr = cout->data;
2821 if (st == NS_SERVER_UP)
2822 status = NS_SERVER_CHANGE_UP;
2823 else if (st == NS_SERVER_DOWN)
2824 status = NS_SERVER_CHANGE_DOWN;
2826 (void) snprintf(ptr, len, "%s%s%s%s",
2827 rms->addr, DOORLINESEP, status, DOORLINESEP);
2829 (void) chg_notify_statusChange(tmp_buf);
2834 * Return: 0 server is down, 1 server is up
2836 static int
2837 contact_server(char *addr)
2839 char *rootDSE = NULL;
2840 ns_ldap_error_t *error = NULL;
2841 int rc;
2843 if (__ns_ldap_getRootDSE(addr, &rootDSE, &error,
2844 SA_ALLOW_FALLBACK) != NS_LDAP_SUCCESS) {
2845 if (current_admin.debug_level >= DBG_ALL)
2846 logit("get rootDSE %s failed. %s", addr,
2847 error->message ? error->message : "");
2848 rc = 0;
2849 } else
2850 rc = 1;
2852 free(rootDSE);
2853 if (error)
2854 (void) __ns_ldap_freeError(&error);
2856 return (rc);
2860 * The thread is spawned to do contact_server() so it won't be blocking
2861 * getldap_serverInfo_op(INFO_OP_GETSERVER, ...) case.
2862 * After contact_server() is done, it calls
2863 * getldap_serverInfo_op(INFO_OP_REMOVESERVER, ...) to return to the remaining
2864 * program flow. It's meant to maintain the original program flow yet be
2865 * non-blocking when it's contacting server.
2867 static void *
2868 remove_server_thread(void *arg)
2870 char *addr = (char *)arg, *out = NULL;
2871 int up;
2872 rm_svr_t rms;
2874 up = contact_server(addr);
2876 rms.addr = addr;
2877 rms.up = up;
2879 (void) getldap_serverInfo_op(INFO_OP_REMOVESERVER, (char *)&rms, &out);
2881 free(addr);
2883 thr_exit(NULL);
2884 return (NULL);
2887 * addr is allocated and is freed by remove_server_thread
2888 * It starts a thread to contact server and remove server to avoid long wait
2889 * or recursion.
2891 static void
2892 remove_server(char *addr)
2894 if (thr_create(NULL, 0, remove_server_thread,
2895 (void *)addr, THR_BOUND|THR_DETACHED, NULL) != 0) {
2896 free(addr);
2897 syslog(LOG_ERR, "thr_create failed for remove_server_thread");
2901 * Compare the server_status and mark it up or down accordingly.
2902 * This is called in removing server case.
2904 static ns_server_status_t
2905 set_server_status(char *input, server_info_t *head)
2907 rm_svr_t *rms = (rm_svr_t *)input;
2908 ns_server_status_t changed = 0;
2909 server_info_t *info;
2911 for (info = head; info != NULL; info = info->next) {
2912 (void) mutex_lock(&info->mutex[0]);
2913 if (strcmp(info->sinfo[0].addr, rms->addr) == 0) {
2914 if (info->sinfo[0].server_status == INFO_SERVER_UP &&
2915 rms->up == FALSE) {
2916 info->sinfo[0].prev_server_status =
2917 info->sinfo[0].server_status;
2918 info->sinfo[0].server_status =
2919 INFO_SERVER_ERROR;
2920 info->sinfo[0].change = NS_SERVER_DOWN;
2921 changed = NS_SERVER_DOWN;
2923 } else if (info->sinfo[0].server_status ==
2924 INFO_SERVER_ERROR && rms->up == TRUE) {
2926 * It should be INFO_SERVER_UP, but check here
2928 info->sinfo[0].prev_server_status =
2929 info->sinfo[0].server_status;
2930 info->sinfo[0].server_status =
2931 INFO_SERVER_UP;
2932 info->sinfo[0].change = NS_SERVER_UP;
2933 changed = NS_SERVER_UP;
2935 (void) mutex_unlock(&info->mutex[0]);
2936 break;
2938 (void) mutex_unlock(&info->mutex[0]);
2940 if (changed) {
2941 /* ldap_cachemgr -g option looks up [1] */
2942 (void) mutex_lock(&info->mutex[1]);
2943 info->sinfo[1].prev_server_status =
2944 info->sinfo[1].server_status;
2945 if (changed == NS_SERVER_DOWN)
2946 info->sinfo[1].server_status = INFO_SERVER_ERROR;
2947 else if (changed == NS_SERVER_UP)
2948 info->sinfo[1].server_status = INFO_SERVER_UP;
2949 (void) mutex_unlock(&info->mutex[1]);
2951 return (changed);