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]
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2018 Joyent, Inc.
39 #include <sys/types.h>
46 #include <ctype.h> /* tolower */
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
52 #include "solaris-priv.h"
53 #include "ns_connmgmt.h"
55 static rwlock_t ldap_lock
= DEFAULTRWLOCK
;
56 static int sighup_update
= FALSE
;
57 extern admin_t current_admin
;
59 extern int is_root_or_all_privs(char *dc_str
, ucred_t
**ucp
);
61 /* variables used for SIGHUP wakeup on sleep */
62 static mutex_t sighuplock
;
65 /* refresh time statistics */
66 static time_t prev_refresh_time
= 0;
68 /* variables used for signaling parent process */
69 static mutex_t sig_mutex
;
70 static int signal_done
= FALSE
;
72 /* TCP connection timeout (in milliseconds) */
73 static int tcptimeout
= NS_DEFAULT_BIND_TIMEOUT
* 1000;
79 /* nis domain information */
80 #define _NIS_FILTER "objectclass=nisDomainObject"
81 #define _NIS_DOMAIN "nisdomain"
83 #define CACHESLEEPTIME 600
85 * server list refresh delay when in "no server" mode
88 #define REFRESH_DELAY_WHEN_NO_SERVER 1
94 INFO_OP_REFRESH_WAIT
= 3,
95 INFO_OP_GETSERVER
= 4,
97 INFO_OP_REMOVESERVER
= 6
102 INFO_RW_READONLY
= 1,
103 INFO_RW_WRITEABLE
= 2
107 INFO_SERVER_JUST_INITED
= -1,
108 INFO_SERVER_UNKNOWN
= 0,
109 INFO_SERVER_CONNECTING
= 1,
111 INFO_SERVER_ERROR
= 3,
112 INFO_SERVER_REMOVED
= 4
116 INFO_STATUS_UNKNOWN
= 0,
117 INFO_STATUS_ERROR
= 1,
131 CACHE_MAP_UNKNOWN
= 0,
132 CACHE_MAP_DN2DOMAIN
= 1
135 typedef struct server_info_ext
{
141 info_server_t server_status
;
142 info_server_t prev_server_status
;
143 info_status_t info_status
;
144 ns_server_status_t change
;
147 typedef struct server_info
{
148 struct server_info
*next
;
149 mutex_t mutex
[2]; /* 0: current copy lock */
150 /* 1: update copy lock */
151 server_info_ext_t sinfo
[2]; /* 0: current, 1: update copy */
154 typedef struct cache_hash
{
158 struct cache_hash
*next
;
162 * The status of a server to be removed. It can be up or down.
164 typedef struct rm_svr
{
166 int up
; /* 1: up, 0: down */
169 static int getldap_destroy_serverInfo(server_info_t
*head
);
170 static void test_server_change(server_info_t
*head
);
171 static void remove_server(char *addr
);
172 static ns_server_status_t
set_server_status(char *input
, server_info_t
*head
);
173 static void create_buf_and_notify(char *input
, ns_server_status_t st
);
177 * The code was in signal handler getldap_revalidate
178 * It's moved out of the handler because it could cause deadlock
184 ns_ldap_error_t
*error
;
187 (void) __ns_ldap_setServer(TRUE
);
189 (void) rw_wrlock(&ldap_lock
);
190 if ((error
= __ns_ldap_LoadConfiguration()) != NULL
) {
191 logit("Error: Unable to read '%s': %s\n",
192 NSCONFIGFILE
, error
->message
);
193 __ns_ldap_freeError(&error
);
196 sighup_update
= TRUE
;
198 (void) rw_unlock(&ldap_lock
);
204 * Calculate a hash for a string
205 * Based on elf_hash algorithm, hash is case insensitive
206 * Uses tolower instead of _tolower because of I18N
210 getldap_hash(const char *str
)
212 unsigned int hval
= 0;
217 hval
= (hval
<< 4) + tolower(*str
++);
218 if ((g
= (hval
& 0xf0000000)) != 0)
222 return ((unsigned long)hval
);
226 * Remove a hash table entry.
227 * This function expects a lock in place when called.
230 static cache_hash_t
*
231 getldap_free_hash(cache_hash_t
*p
)
235 p
->type
= CACHE_MAP_UNKNOWN
;
247 * Scan a hash table hit for a matching hash entry.
248 * This function expects a lock in place when called.
250 static cache_hash_t
*
251 getldap_scan_hash(cache_type_t type
, char *from
,
255 if (idx
->type
== type
&&
256 strcasecmp(from
, idx
->from
) == 0) {
261 return ((cache_hash_t
*)NULL
);
265 * Format and return the cache data statistics
268 getldap_get_cacheData_stat(int max
, int current
, char **output
)
270 #define C_HEADER0 "Cache data information: "
271 #define C_HEADER1 " Maximum cache entries: "
272 #define C_HEADER2 " Number of cache entries: "
273 int hdr0_len
= strlen(gettext(C_HEADER0
));
274 int hdr1_len
= strlen(gettext(C_HEADER1
));
275 int hdr2_len
= strlen(gettext(C_HEADER2
));
278 if (current_admin
.debug_level
>= DBG_ALL
) {
279 logit("getldap_get_cacheData_stat()...\n");
284 len
= hdr0_len
+ hdr1_len
+ hdr2_len
+
285 3 * strlen(DOORLINESEP
) + 21;
286 *output
= malloc(len
);
290 (void) snprintf(*output
, len
, "%s%s%s%10d%s%s%10d%s",
291 gettext(C_HEADER0
), DOORLINESEP
,
292 gettext(C_HEADER1
), max
, DOORLINESEP
,
293 gettext(C_HEADER2
), current
, DOORLINESEP
);
295 return (NS_LDAP_SUCCESS
);
299 getldap_cache_op(cache_op_t op
, cache_type_t type
,
300 char *from
, char **to
)
302 #define CACHE_HASH_MAX 257
303 #define CACHE_HASH_MAX_ENTRY 256
304 static cache_hash_t
*hashTbl
[CACHE_HASH_MAX
];
305 cache_hash_t
*next
, *idx
, *newp
;
307 static rwlock_t cache_lock
= DEFAULTRWLOCK
;
309 static int entry_num
= 0;
311 if (current_admin
.debug_level
>= DBG_ALL
) {
312 logit("getldap_cache_op()...\n");
315 case CACHE_OP_CREATE
:
316 if (current_admin
.debug_level
>= DBG_ALL
) {
317 logit("operation is CACHE_OP_CREATE...\n");
319 (void) rw_wrlock(&cache_lock
);
321 for (i
= 0; i
< CACHE_HASH_MAX
; i
++) {
326 (void) rw_unlock(&cache_lock
);
329 case CACHE_OP_DELETE
:
330 if (current_admin
.debug_level
>= DBG_ALL
) {
331 logit("operation is CACHE_OP_DELETE...\n");
333 (void) rw_wrlock(&cache_lock
);
335 for (i
= 0; i
< CACHE_HASH_MAX
; i
++) {
337 while (next
!= NULL
) {
338 next
= getldap_free_hash(next
);
344 (void) rw_unlock(&cache_lock
);
348 if (current_admin
.debug_level
>= DBG_ALL
) {
349 logit("operation is CACHE_OP_ADD...\n");
351 if (from
== NULL
|| to
== NULL
|| *to
== NULL
)
353 hash
= getldap_hash(from
) % CACHE_HASH_MAX
;
354 (void) rw_wrlock(&cache_lock
);
357 * replace old "to" value with new one
358 * if an entry with same "from"
362 newp
= getldap_scan_hash(type
, from
, idx
);
365 newp
->to
= strdup(*to
);
366 (void) rw_unlock(&cache_lock
);
367 return (NS_LDAP_SUCCESS
);
371 if (entry_num
> CACHE_HASH_MAX_ENTRY
) {
372 (void) rw_unlock(&cache_lock
);
376 newp
= (cache_hash_t
*)malloc(sizeof (cache_hash_t
));
378 (void) rw_unlock(&cache_lock
);
379 return (NS_LDAP_MEMORY
);
382 newp
->from
= strdup(from
);
383 newp
->to
= strdup(*to
);
385 hashTbl
[hash
] = newp
;
387 (void) rw_unlock(&cache_lock
);
391 if (current_admin
.debug_level
>= DBG_ALL
) {
392 logit("operation is CACHE_OP_FIND...\n");
394 if (from
== NULL
|| to
== NULL
)
397 hash
= getldap_hash(from
) % CACHE_HASH_MAX
;
398 (void) rw_rdlock(&cache_lock
);
400 idx
= getldap_scan_hash(type
, from
, idx
);
402 *to
= strdup(idx
->to
);
403 (void) rw_unlock(&cache_lock
);
408 case CACHE_OP_GETSTAT
:
409 if (current_admin
.debug_level
>= DBG_ALL
) {
410 logit("operation is CACHE_OP_GETSTAT...\n");
415 return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY
,
420 logit("getldap_cache_op(): "
421 "invalid operation code (%d).\n", op
);
425 return (NS_LDAP_SUCCESS
);
428 * Function: sync_current_with_update_copy
430 * This function syncs up the 2 sinfo copies in info.
432 * The 2 copies are identical most of time.
433 * The update copy(sinfo[1]) could be different when
434 * getldap_serverInfo_refresh thread is refreshing the server list
435 * and calls getldap_get_rootDSE to update info. getldap_get_rootDSE
436 * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
437 * The calling sequence is
438 * getldap_serverInfo_refresh->
439 * getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
440 * getldap_set_serverInfo->
441 * getldap_get_rootDSE
443 * The original server_info_t has one copy of server info. When libsldap
444 * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
445 * is updating the server info, it would hit a unprotected window in
446 * getldap_rootDSE. The door call will not get server info and libsldap
447 * fails at making ldap connection.
449 * The new server_info_t provides GETLDAPSERVER thread with a current
450 * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
451 * and syncs up 2 copies before thr_exit. This will close the window in
452 * getldap_get_rootDSE.
456 sync_current_with_update_copy(server_info_t
*info
)
458 if (current_admin
.debug_level
>= DBG_ALL
) {
459 logit("sync_current_with_update_copy()...\n");
462 (void) mutex_lock(&info
->mutex
[1]);
463 (void) mutex_lock(&info
->mutex
[0]);
465 if (info
->sinfo
[1].server_status
== INFO_SERVER_UP
&&
466 info
->sinfo
[0].server_status
!= INFO_SERVER_UP
)
467 info
->sinfo
[1].change
= NS_SERVER_UP
;
468 else if (info
->sinfo
[1].server_status
!= INFO_SERVER_UP
&&
469 info
->sinfo
[0].server_status
== INFO_SERVER_UP
)
470 info
->sinfo
[1].change
= NS_SERVER_DOWN
;
472 info
->sinfo
[1].change
= 0;
475 /* free memory in current copy first */
476 if (info
->sinfo
[0].addr
)
477 free(info
->sinfo
[0].addr
);
478 info
->sinfo
[0].addr
= NULL
;
480 if (info
->sinfo
[0].hostname
)
481 free(info
->sinfo
[0].hostname
);
482 info
->sinfo
[0].hostname
= NULL
;
484 if (info
->sinfo
[0].rootDSE_data
)
485 free(info
->sinfo
[0].rootDSE_data
);
486 info
->sinfo
[0].rootDSE_data
= NULL
;
488 if (info
->sinfo
[0].errormsg
)
489 free(info
->sinfo
[0].errormsg
);
490 info
->sinfo
[0].errormsg
= NULL
;
493 * make current and update copy identical
495 info
->sinfo
[0] = info
->sinfo
[1];
498 * getldap_get_server_stat() reads the update copy sinfo[1]
499 * so it can't be freed or nullified yet at this point.
501 * The sinfo[0] and sinfo[1] have identical string pointers.
502 * strdup the strings to avoid the double free problem.
503 * The strings of sinfo[1] are freed in
504 * getldap_get_rootDSE() and the strings of sinfo[0]
505 * are freed earlier in this function. If the pointers are the
506 * same, they will be freed twice.
508 if (info
->sinfo
[1].addr
)
509 info
->sinfo
[0].addr
= strdup(info
->sinfo
[1].addr
);
510 if (info
->sinfo
[1].hostname
)
511 info
->sinfo
[0].hostname
= strdup(info
->sinfo
[1].hostname
);
512 if (info
->sinfo
[1].rootDSE_data
)
513 info
->sinfo
[0].rootDSE_data
=
514 strdup(info
->sinfo
[1].rootDSE_data
);
515 if (info
->sinfo
[1].errormsg
)
516 info
->sinfo
[0].errormsg
= strdup(info
->sinfo
[1].errormsg
);
518 (void) mutex_unlock(&info
->mutex
[0]);
519 (void) mutex_unlock(&info
->mutex
[1]);
524 getldap_get_rootDSE(void *arg
)
526 server_info_t
*serverInfo
= (server_info_t
*)arg
;
528 int exitrc
= NS_LDAP_SUCCESS
;
530 int server_found
= 0;
531 char errmsg
[MAXERROR
];
532 ns_ldap_return_code rc
;
533 ns_ldap_error_t
*error
= NULL
;
535 if (current_admin
.debug_level
>= DBG_ALL
) {
536 logit("getldap_get_rootDSE()....\n");
539 /* initialize the server info element */
540 (void) mutex_lock(&serverInfo
->mutex
[1]);
541 serverInfo
->sinfo
[1].type
= INFO_RW_UNKNOWN
;
542 serverInfo
->sinfo
[1].info_status
=
545 * When the sever list is refreshed over and over,
546 * this function is called each time it is refreshed.
547 * The previous server status of the update copy(sinfo[1])
548 * is the status of the current copy
550 (void) mutex_lock(&serverInfo
->mutex
[0]);
551 serverInfo
->sinfo
[1].prev_server_status
=
552 serverInfo
->sinfo
[0].server_status
;
553 (void) mutex_unlock(&serverInfo
->mutex
[0]);
555 serverInfo
->sinfo
[1].server_status
=
557 if (serverInfo
->sinfo
[1].rootDSE_data
)
558 free(serverInfo
->sinfo
[1].rootDSE_data
);
559 serverInfo
->sinfo
[1].rootDSE_data
= NULL
;
560 if (serverInfo
->sinfo
[1].errormsg
)
561 free(serverInfo
->sinfo
[1].errormsg
);
562 serverInfo
->sinfo
[1].errormsg
= NULL
;
563 (void) mutex_unlock(&serverInfo
->mutex
[1]);
565 (void) mutex_lock(&serverInfo
->mutex
[1]);
566 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_CONNECTING
;
567 (void) mutex_unlock(&serverInfo
->mutex
[1]);
570 * WARNING: anon_fallback == 1 (last argument) means that when
571 * __ns_ldap_getRootDSE is unable to bind using the configured
572 * credentials, it will try to fall back to using anonymous, non-SSL
575 * This is for backward compatibility reasons - we might have machines
576 * in the field with broken configuration (invalid credentials) and we
577 * don't want them to be disturbed.
579 if (rc
= __ns_ldap_getRootDSE(serverInfo
->sinfo
[1].addr
,
582 SA_ALLOW_FALLBACK
) != NS_LDAP_SUCCESS
) {
583 (void) mutex_lock(&serverInfo
->mutex
[1]);
584 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_ERROR
;
585 serverInfo
->sinfo
[1].info_status
= INFO_STATUS_ERROR
;
586 if (error
&& error
->message
) {
587 serverInfo
->sinfo
[1].errormsg
= strdup(error
->message
);
589 (void) snprintf(errmsg
, sizeof (errmsg
), "%s %s "
590 "(rc = %d)", gettext("Can not get the root DSE from"
591 " server"), serverInfo
->sinfo
[1].addr
, rc
);
592 serverInfo
->sinfo
[1].errormsg
= strdup(errmsg
);
596 (void) __ns_ldap_freeError(&error
);
599 if (current_admin
.debug_level
>= DBG_ALL
) {
600 logit("getldap_get_rootDSE: %s.\n",
601 serverInfo
->sinfo
[1].errormsg
);
603 (void) mutex_unlock(&serverInfo
->mutex
[1]);
605 * sync sinfo copies in the serverInfo.
608 sync_current_with_update_copy(serverInfo
);
609 thr_exit((void *) -1);
612 (void) mutex_lock(&serverInfo
->mutex
[1]);
614 /* assume writeable, i.e., can do modify */
615 serverInfo
->sinfo
[1].type
= INFO_RW_WRITEABLE
;
616 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_UP
;
617 serverInfo
->sinfo
[1].info_status
= INFO_STATUS_NEW
;
618 /* remove the last DOORLINESEP */
619 *(rootDSE
+strlen(rootDSE
)-1) = '\0';
620 serverInfo
->sinfo
[1].rootDSE_data
= rootDSE
;
624 (void) mutex_unlock(&serverInfo
->mutex
[1]);
627 * sync sinfo copies in the serverInfo.
630 sync_current_with_update_copy(serverInfo
);
632 * signal that the ldap_cachemgr parent process
633 * should exit now, if it is still waiting
635 (void) mutex_lock(&sig_mutex
);
636 if (signal_done
== FALSE
&& server_found
) {
638 (void) kill(ppid
, SIGUSR1
);
639 if (current_admin
.debug_level
>= DBG_ALL
) {
640 logit("getldap_get_rootDSE(): "
641 "SIGUSR1 signal sent to "
642 "parent process(%ld).\n", ppid
);
646 (void) mutex_unlock(&sig_mutex
);
648 thr_exit((void *) exitrc
);
650 return ((void *) NULL
);
654 getldap_init_serverInfo(server_info_t
**head
)
656 char **servers
= NULL
;
657 int rc
= 0, i
, exitrc
= NS_LDAP_SUCCESS
;
658 ns_ldap_error_t
*errorp
= NULL
;
659 server_info_t
*info
, *tail
= NULL
;
662 if (current_admin
.debug_level
>= DBG_ALL
) {
663 logit("getldap_init_serverInfo()...\n");
665 rc
= __s_api_getServers(&servers
, &errorp
);
667 if (rc
!= NS_LDAP_SUCCESS
) {
668 logit("getldap_init_serverInfo: "
669 "__s_api_getServers failed.\n");
671 __ns_ldap_freeError(&errorp
);
674 for (i
= 0; servers
[i
] != NULL
; i
++) {
675 info
= (server_info_t
*)calloc(1, sizeof (server_info_t
));
677 logit("getldap_init_serverInfo: "
678 "not enough memory.\n");
679 exitrc
= NS_LDAP_MEMORY
;
690 info
->sinfo
[0].addr
= strdup(servers
[i
]);
691 if (info
->sinfo
[0].addr
== NULL
) {
692 logit("getldap_init_serverInfo: "
693 "not enough memory.\n");
694 exitrc
= NS_LDAP_MEMORY
;
697 info
->sinfo
[1].addr
= strdup(servers
[i
]);
698 if (info
->sinfo
[1].addr
== NULL
) {
699 logit("getldap_init_serverInfo: "
700 "not enough memory.\n");
701 exitrc
= NS_LDAP_MEMORY
;
705 info
->sinfo
[0].type
= INFO_RW_UNKNOWN
;
706 info
->sinfo
[1].type
= INFO_RW_UNKNOWN
;
707 info
->sinfo
[0].info_status
= INFO_STATUS_UNKNOWN
;
708 info
->sinfo
[1].info_status
= INFO_STATUS_UNKNOWN
;
709 info
->sinfo
[0].server_status
= INFO_SERVER_UNKNOWN
;
710 info
->sinfo
[1].server_status
= INFO_SERVER_UNKNOWN
;
713 * Assume at startup or after the configuration
714 * profile is refreshed, all servers are good.
716 info
->sinfo
[0].prev_server_status
=
718 info
->sinfo
[1].prev_server_status
=
720 info
->sinfo
[0].hostname
= NULL
;
721 info
->sinfo
[1].hostname
= NULL
;
722 info
->sinfo
[0].rootDSE_data
= NULL
;
723 info
->sinfo
[1].rootDSE_data
= NULL
;
724 info
->sinfo
[0].errormsg
= NULL
;
725 info
->sinfo
[1].errormsg
= NULL
;
728 __s_api_free2dArray(servers
);
729 if (exitrc
!= NS_LDAP_SUCCESS
) {
731 (void) getldap_destroy_serverInfo(*head
);
739 getldap_destroy_serverInfo(server_info_t
*head
)
741 server_info_t
*info
, *next
;
743 if (current_admin
.debug_level
>= DBG_ALL
) {
744 logit("getldap_destroy_serverInfo()...\n");
748 logit("getldap_destroy_serverInfo: "
749 "invalid serverInfo list.\n");
753 for (info
= head
; info
; info
= next
) {
754 if (info
->sinfo
[0].addr
)
755 free(info
->sinfo
[0].addr
);
756 if (info
->sinfo
[1].addr
)
757 free(info
->sinfo
[1].addr
);
758 if (info
->sinfo
[0].hostname
)
759 free(info
->sinfo
[0].hostname
);
760 if (info
->sinfo
[1].hostname
)
761 free(info
->sinfo
[1].hostname
);
762 if (info
->sinfo
[0].rootDSE_data
)
763 free(info
->sinfo
[0].rootDSE_data
);
764 if (info
->sinfo
[1].rootDSE_data
)
765 free(info
->sinfo
[1].rootDSE_data
);
766 if (info
->sinfo
[0].errormsg
)
767 free(info
->sinfo
[0].errormsg
);
768 if (info
->sinfo
[1].errormsg
)
769 free(info
->sinfo
[1].errormsg
);
773 return (NS_LDAP_SUCCESS
);
777 getldap_set_serverInfo(server_info_t
*head
, int reset_bindtime
, info_op_t op
)
782 int num_threads
= 0, i
, j
;
784 void **paramVal
= NULL
;
785 ns_ldap_error_t
*error
= NULL
;
787 if (current_admin
.debug_level
>= DBG_ALL
) {
788 logit("getldap_set_serverInfo()...\n");
792 logit("getldap_set_serverInfo: "
793 "invalid serverInfo list.\n");
797 /* Get the bind timeout value */
798 if (reset_bindtime
== 1) {
799 tcptimeout
= NS_DEFAULT_BIND_TIMEOUT
* 1000;
800 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P
,
802 if (paramVal
!= NULL
&& *paramVal
!= NULL
) {
803 /* convert to milliseconds */
804 tcptimeout
= **((int **)paramVal
);
806 (void) __ns_ldap_freeParam(¶mVal
);
809 (void) __ns_ldap_freeError(&error
);
812 for (info
= head
; info
; info
= info
->next
)
815 if (num_threads
== 0) {
816 logit("getldap_set_serverInfo: "
817 "empty serverInfo list.\n");
821 tid
= (thread_t
*) calloc(1, sizeof (thread_t
) * num_threads
);
823 logit("getldap_set_serverInfo: "
824 "No memory to create thread ID list.\n");
828 for (info
= head
, i
= 0; info
; info
= info
->next
, i
++) {
829 if (thr_create(NULL
, 0,
830 (void *(*)(void*))getldap_get_rootDSE
,
831 (void *)info
, 0, &tid
[i
])) {
832 logit("getldap_set_serverInfo: "
833 "can not create thread %d.\n", i
+ 1);
834 for (j
= 0; j
< i
; j
++)
835 (void) thr_join(tid
[j
], NULL
, NULL
);
841 for (i
= 0; i
< num_threads
; i
++) {
842 if (thr_join(tid
[i
], NULL
, &status
) == 0) {
843 if ((int)status
== NS_LDAP_SUCCESS
)
850 if (op
== INFO_OP_REFRESH
)
851 test_server_change(head
);
853 return (NS_LDAP_SUCCESS
);
859 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
860 * to this function from getldap_serverInfo_op().
862 * a buffer containing an empty string (e.g., input[0]='\0';) or a string
863 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
865 * where addr is the address of a server and
866 * req is one of the following:
867 * NS_CACHE_NEW: send a new server address, addr is ignored.
868 * NS_CACHE_NORESP: send the next one, remove addr from list.
869 * NS_CACHE_NEXT: send the next one, keep addr on list.
870 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same
873 * NS_CACHE_ADDR_IP: return server address as is, this is default.
874 * NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
875 * only self credential case requires such format.
877 * a buffer containing server info in the following format:
878 * serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
879 * [ attr=value [DOORLINESEP attr=value ]...]
880 * For example: ( here | used as DOORLINESEP for visual purposes)
881 * 1) simple bind and sasl/DIGEST-MD5 bind :
882 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
883 * supportedSASLmechanisms=GSSAPI
884 * 2) sasl/GSSAPI bind (self credential):
885 * 1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
886 * supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
887 * NOTE: caller should free this buffer when done using it
890 getldap_get_serverInfo(server_info_t
*head
, char *input
,
891 char **output
, int *svr_removed
)
893 server_info_t
*info
= NULL
;
894 server_info_t
*server
= NULL
;
897 char req_new
[] = NS_CACHE_NEW
;
898 char addr_type
[] = NS_CACHE_ADDR_IP
;
899 int matched
= FALSE
, len
= 0, rc
= 0;
900 char *ret_addr
= NULL
, *ret_addrFQDN
= NULL
;
901 char *new_addr
= NULL
;
904 if (current_admin
.debug_level
>= DBG_ALL
) {
905 logit("getldap_get_serverInfo()...\n");
908 if (input
== NULL
|| output
== NULL
) {
909 logit("getldap_get_serverInfo: "
910 "No input or output buffer.\n");
915 *svr_removed
= FALSE
;
918 logit("getldap_get_serverInfo: "
919 "invalid serverInfo list.\n");
923 * parse the input string to get req and addr,
924 * if input is empty, i.e., input[0] == '\0',
925 * treat it as an NS_CACHE_NEW request
928 if (input
[0] != '\0') {
930 /* Save addr type flag */
931 addr_type
[0] = input
[1];
932 input
[strlen(NS_CACHE_NEW
)] = '\0';
933 /* skip acion type flag, addr type flag and DOORLINESEP */
934 addr
= input
+ strlen(DOORLINESEP
) + strlen(NS_CACHE_NEW
)
935 + strlen(NS_CACHE_ADDR_IP
);
939 * or the server info is new,
941 * beginning of the list
943 if ((strcmp(req
, NS_CACHE_NEW
) == 0) ||
944 (head
->sinfo
[0].info_status
== INFO_STATUS_NEW
))
946 for (info
= head
; info
; info
= info
->next
) {
948 * make sure the server info stays the same
949 * while the data is being processed
953 * This function is called to get server info list
954 * and pass it back to door call clients.
955 * Access the current copy (sinfo[0]) to get such
958 (void) mutex_lock(&info
->mutex
[0]);
960 if (matched
== FALSE
&&
961 strcmp(info
->sinfo
[0].addr
, addr
) == 0) {
963 if (strcmp(req
, NS_CACHE_NORESP
) == 0) {
964 if (chg_is_called_from_nscd_or_peruser_nscd(
965 "REMOVE SERVER", &pid
) == 0) {
966 (void) mutex_unlock(&info
->mutex
[0]);
967 if (current_admin
.debug_level
>=
969 logit("Only nscd can remove "
970 "servers. pid %ld", pid
);
975 * if the information is new,
976 * give this server one more chance
978 if (info
->sinfo
[0].info_status
==
980 info
->sinfo
[0].server_status
==
986 * it is recommended that
987 * before removing the
988 * server from the list,
989 * the server should be
990 * contacted one more time
991 * to make sure that it is
992 * really unavailable.
993 * For now, just trust the client
994 * (i.e., the sldap library)
995 * that it knows what it is
996 * doing and would not try
997 * to mess up the server
1001 * Make a copy of addr to contact
1002 * it later. It's not doing it here
1003 * to avoid long wait and possible
1004 * recursion to contact an LDAP server.
1006 new_addr
= strdup(info
->sinfo
[0].addr
);
1008 remove_server(new_addr
);
1009 *svr_removed
= TRUE
;
1010 (void) mutex_unlock(&info
->mutex
[0]);
1015 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
1017 (void) mutex_unlock(&info
->mutex
[0]);
1023 if (strcmp(req
, NS_CACHE_WRITE
) == 0) {
1024 if (info
->sinfo
[0].type
==
1025 INFO_RW_WRITEABLE
&&
1026 info
->sinfo
[0].server_status
==
1031 } else if (info
->sinfo
[0].server_status
==
1038 (void) mutex_unlock(&info
->mutex
[0]);
1042 if (strcmp(addr_type
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
1044 * In SASL/GSSAPI case, a hostname is required for
1045 * Kerberos's service principal.
1047 * ldap/foo.sun.com@SUN.COM
1049 if (server
->sinfo
[0].hostname
== NULL
) {
1050 rc
= __s_api_ip2hostname(server
->sinfo
[0].addr
,
1051 &server
->sinfo
[0].hostname
);
1052 if (rc
!= NS_LDAP_SUCCESS
) {
1053 (void) mutex_unlock(&info
->mutex
[0]);
1056 if (current_admin
.debug_level
>= DBG_ALL
) {
1057 logit("getldap_get_serverInfo: "
1058 "%s is converted to %s\n",
1059 server
->sinfo
[0].addr
,
1060 server
->sinfo
[0].hostname
);
1063 ret_addr
= server
->sinfo
[0].addr
;
1064 ret_addrFQDN
= server
->sinfo
[0].hostname
;
1067 ret_addr
= server
->sinfo
[0].addr
;
1070 len
= strlen(ret_addr
) +
1071 strlen(server
->sinfo
[0].rootDSE_data
) +
1072 strlen(DOORLINESEP
) + 1;
1073 if (ret_addrFQDN
!= NULL
)
1074 len
+= strlen(ret_addrFQDN
) + strlen(DOORLINESEP
);
1075 *output
= (char *)malloc(len
);
1076 if (*output
== NULL
) {
1077 (void) mutex_unlock(&info
->mutex
[0]);
1078 return (NS_LDAP_MEMORY
);
1080 if (ret_addrFQDN
== NULL
)
1081 (void) snprintf(*output
, len
, "%s%s%s",
1082 ret_addr
, DOORLINESEP
,
1083 server
->sinfo
[0].rootDSE_data
);
1085 (void) snprintf(*output
, len
, "%s%s%s%s%s",
1086 ret_addr
, DOORLINESEP
,
1087 ret_addrFQDN
, DOORLINESEP
,
1088 server
->sinfo
[0].rootDSE_data
);
1089 server
->sinfo
[0].info_status
= INFO_STATUS_OLD
;
1090 (void) mutex_unlock(&info
->mutex
[0]);
1091 return (NS_LDAP_SUCCESS
);
1098 * Format previous and next refresh time
1101 getldap_format_refresh_time(char **output
, time_t *prev
, time_t *next
)
1103 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S"
1104 #define TIME_HEADER1 " Previous refresh time: "
1105 #define TIME_HEADER2 " Next refresh time: "
1106 int hdr1_len
= strlen(gettext(TIME_HEADER1
));
1107 int hdr2_len
= strlen(gettext(TIME_HEADER2
));
1113 if (current_admin
.debug_level
>= DBG_ALL
) {
1114 logit("getldap_format_refresh_time()...\n");
1119 /* format the time of previous refresh */
1121 (void) localtime_r(prev
, &tm
);
1122 (void) strftime(pbuf
, sizeof (pbuf
) - 1, TIME_FORMAT
, &tm
);
1124 (void) strcpy(pbuf
, gettext("NOT DONE"));
1127 /* format the time of next refresh */
1129 (void) localtime_r(next
, &tm
);
1130 (void) strftime(nbuf
, sizeof (nbuf
) - 1, TIME_FORMAT
, &tm
);
1132 (void) strcpy(nbuf
, gettext("NOT SET"));
1135 len
= hdr1_len
+ hdr2_len
+ strlen(nbuf
) +
1136 strlen(pbuf
) + 2 * strlen(DOORLINESEP
) + 1;
1138 *output
= malloc(len
);
1139 if (*output
== NULL
)
1142 (void) snprintf(*output
, len
, "%s%s%s%s%s%s",
1143 gettext(TIME_HEADER1
), pbuf
, DOORLINESEP
,
1144 gettext(TIME_HEADER2
), nbuf
, DOORLINESEP
);
1146 return (NS_LDAP_SUCCESS
);
1150 * getldap_get_server_stat processes the GETSTAT request passed
1151 * to this function from getldap_serverInfo_op().
1153 * a buffer containing info for all the servers.
1154 * For each server, the data is in the following format:
1155 * server: server address or name, status: unknown|up|down|removed DOORLINESEP
1156 * for example: ( here | used as DOORLINESEP for visual purposes)
1157 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1158 * NOTE: caller should free this buffer when done using it
1161 getldap_get_server_stat(server_info_t
*head
, char **output
,
1162 time_t *prev
, time_t *next
)
1164 #define S_HEADER "Server information: "
1165 #define S_FORMAT " server: %s, status: %s%s"
1166 #define S_ERROR " error message: %s%s"
1167 server_info_t
*info
= NULL
;
1168 int header_len
= strlen(gettext(S_HEADER
));
1169 int format_len
= strlen(gettext(S_FORMAT
));
1170 int error_len
= strlen(gettext(S_ERROR
));
1171 int len
= header_len
+ strlen(DOORLINESEP
);
1173 char *status
, *output1
= NULL
, *tmpptr
;
1177 if (current_admin
.debug_level
>= DBG_ALL
) {
1178 logit("getldap_get_server_stat()...\n");
1182 logit("getldap_get_server_stat: "
1183 "invalid serverInfo list.\n");
1187 /* format previous and next refresh time */
1188 (void) getldap_format_refresh_time(&output1
, prev
, next
);
1189 if (output1
== NULL
)
1191 len
+= strlen(output1
);
1192 len1
= len
+ strlen(DOORLINESEP
) + 1;
1194 *output
= (char *)calloc(1, len1
);
1195 if (*output
== NULL
) {
1200 /* insert header string and refresh time info */
1201 (void) snprintf(*output
, len1
, "%s%s%s",
1202 gettext(S_HEADER
), DOORLINESEP
, output1
);
1204 for (info
= head
; info
; info
= info
->next
) {
1207 * make sure the server info stays the same
1208 * while the data is being processed
1210 (void) mutex_lock(&info
->mutex
[1]);
1213 * When the updating process is under way(getldap_get_rootDSE)
1214 * the update copy(sinfo[1] is the latest copy.
1215 * When the updating process
1216 * is done, the current copy (sinfo[0]) has the latest status,
1217 * which is still identical to the update copy.
1218 * So update copy has the latest status.
1219 * Use the update copy(sinfo[1]) to show status
1220 * (ldap_cachemgr -g).
1224 switch (info
->sinfo
[1].server_status
) {
1225 case INFO_SERVER_UNKNOWN
:
1226 status
= gettext("UNKNOWN");
1228 case INFO_SERVER_CONNECTING
:
1229 status
= gettext("CONNECTING");
1231 case INFO_SERVER_UP
:
1232 status
= gettext("UP");
1234 case INFO_SERVER_ERROR
:
1235 status
= gettext("ERROR");
1237 case INFO_SERVER_REMOVED
:
1238 status
= gettext("REMOVED");
1242 len
+= format_len
+ strlen(status
) +
1243 strlen(info
->sinfo
[1].addr
) +
1244 strlen(DOORLINESEP
);
1245 if (info
->sinfo
[1].errormsg
!= NULL
)
1247 strlen(info
->sinfo
[1].errormsg
) +
1248 strlen(DOORLINESEP
);
1250 tmpptr
= (char *)realloc(*output
, len
);
1251 if (tmpptr
== NULL
) {
1255 (void) mutex_unlock(&info
->mutex
[1]);
1260 /* insert server IP addr or name and status */
1261 len1
= len
- strlen(*output
);
1262 (void) snprintf(*output
+ strlen(*output
), len1
,
1263 gettext(S_FORMAT
), info
->sinfo
[1].addr
,
1264 status
, DOORLINESEP
);
1265 /* insert error message if any */
1266 len1
= len
- strlen(*output
);
1267 if (info
->sinfo
[1].errormsg
!= NULL
)
1268 (void) snprintf(*output
+ strlen(*output
), len1
,
1270 info
->sinfo
[1].errormsg
,
1273 (void) mutex_unlock(&info
->mutex
[1]);
1278 return (NS_LDAP_SUCCESS
);
1282 * Format and return the refresh time statistics
1285 getldap_get_refresh_stat(char **output
)
1287 #define R_HEADER0 "Configuration refresh information: "
1288 #define R_HEADER1 " Configured to NO REFRESH."
1289 int hdr0_len
= strlen(gettext(R_HEADER0
));
1290 int hdr1_len
= strlen(gettext(R_HEADER1
));
1291 int cache_ttl
= -1, len
= 0;
1293 void **paramVal
= NULL
;
1294 ns_ldap_error_t
*errorp
= NULL
;
1295 char *output1
= NULL
;
1297 if (current_admin
.debug_level
>= DBG_ALL
) {
1298 logit("getldap_get_refresh_stat()...\n");
1303 /* get configured cache TTL */
1304 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P
,
1305 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
1307 (char *)*paramVal
!= NULL
) {
1308 cache_ttl
= atol((char *)*paramVal
);
1311 __ns_ldap_freeError(&errorp
);
1313 (void) __ns_ldap_freeParam(¶mVal
);
1315 /* cound not get cache TTL */
1316 if (cache_ttl
== -1)
1319 if (cache_ttl
== 0) {
1320 len
= hdr0_len
+ hdr1_len
+
1321 2 * strlen(DOORLINESEP
) + 1;
1322 *output
= malloc(len
);
1323 if (*output
== NULL
)
1325 (void) snprintf(*output
, len
, "%s%s%s%s",
1326 gettext(R_HEADER0
), DOORLINESEP
,
1327 gettext(R_HEADER1
), DOORLINESEP
);
1330 /* get configuration expiration time */
1331 if ((__ns_ldap_getParam(NS_LDAP_EXP_P
,
1332 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
1334 (char *)*paramVal
!= NULL
) {
1335 expire
= (time_t)atol((char *)*paramVal
);
1338 __ns_ldap_freeError(&errorp
);
1341 (void) __ns_ldap_freeParam(¶mVal
);
1343 /* cound not get expiration time */
1347 /* format previous and next refresh time */
1348 (void) getldap_format_refresh_time(&output1
,
1349 &prev_refresh_time
, &expire
);
1350 if (output1
== NULL
)
1353 len
= hdr0_len
+ strlen(output1
) +
1354 2 * strlen(DOORLINESEP
) + 1;
1355 *output
= malloc(len
);
1356 if (*output
== NULL
) {
1360 (void) snprintf(*output
, len
, "%s%s%s%s",
1361 gettext(R_HEADER0
), DOORLINESEP
,
1362 output1
, DOORLINESEP
);
1366 return (NS_LDAP_SUCCESS
);
1370 getldap_get_cacheTTL()
1372 void **paramVal
= NULL
;
1373 ns_ldap_error_t
*error
;
1374 int rc
= 0, cachettl
;
1377 if (current_admin
.debug_level
>= DBG_ALL
) {
1378 logit("getldap_get_cacheTTL()....\n");
1381 if ((rc
= __ns_ldap_getParam(NS_LDAP_CACHETTL_P
,
1382 ¶mVal
, &error
)) != NS_LDAP_SUCCESS
) {
1383 if (error
!= NULL
&& error
->message
!= NULL
)
1384 logit("Error: Unable to get configuration "
1385 "refresh TTL: %s\n",
1390 __ns_ldap_err2str(rc
, &tmp
);
1391 logit("Error: Unable to get configuration "
1392 "refresh TTL: %s\n", tmp
);
1394 (void) __ns_ldap_freeParam(¶mVal
);
1395 (void) __ns_ldap_freeError(&error
);
1398 if (paramVal
== NULL
|| (char *)*paramVal
== NULL
)
1400 cachettl
= atol((char *)*paramVal
);
1401 (void) __ns_ldap_freeParam(¶mVal
);
1407 * This function implements the adaptive server list refresh
1408 * algorithm used by ldap_cachemgr. The idea is to have the
1409 * refresh TTL adjust itself between maximum and minimum
1410 * values. If the server list has been walked three times
1411 * in a row without errors, the TTL will be doubled. This will
1412 * be done repeatedly until the maximum value is reached
1413 * or passed. If passed, the maximum value will be used.
1414 * If any time a server is found to be down/bad, either
1415 * after another server list walk or informed by libsldap via
1416 * the GETLDAPSERVER door calls, the TTL will be set to half
1417 * of its value, again repeatedly, but no less than the minimum
1418 * value. Also, at any time, if all the servers on the list
1419 * are found to be down/bad, the TTL will be set to minimum,
1420 * so that a "no-server" refresh loop should be entered to try
1421 * to find a good server as soon as possible. The caller
1422 * could check the no_gd_server flag for this situation.
1423 * The maximum and minimum values are initialized when the input
1424 * refresh_ttl is set to zero, this should occur during
1425 * ldap_cachemgr startup or every time the server list is
1426 * recreated after the configuration profile is refreshed
1427 * from an LDAP server. The maximum is set to the value of
1428 * the NS_LDAP_CACHETTL parameter (configuration profile
1429 * refresh TTL), but if it is zero (never refreshed) or can
1430 * not be retrieved, the maximum is set to the macro
1431 * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1432 * set to REFRESHTTL_MIN, which is the TCP connection timeout
1433 * (tcptimeout) set via the LDAP API ldap_set_option()
1434 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1435 * This accounts for the maximum possible timeout value for an
1436 * LDAP TCP connect call.The first refresh TTL, initial value of
1437 * refresh_ttl, will be set to the smaller of the two,
1438 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1439 * The idea is to have a low starting value and have the value
1440 * stay low if the network/server is unstable, but eventually
1441 * the value will move up to maximum and stay there if the
1442 * network/server is stable.
1445 getldap_set_refresh_ttl(server_info_t
*head
, int *refresh_ttl
,
1448 #define REFRESHTTL_REGULAR 600
1449 #define REFRESHTTL_MAX 43200
1450 /* tcptimeout is in milliseconds */
1451 #define REFRESHTTL_MIN (tcptimeout/1000) + 10
1452 #define UP_REFRESH_TTL_NUM 2
1454 static mutex_t refresh_mutex
;
1455 static int refresh_ttl_max
= 0;
1456 static int refresh_ttl_min
= 0;
1457 static int num_walked_ok
= 0;
1458 int num_servers
= 0;
1459 int num_good_servers
= 0;
1460 int num_prev_good_servers
= 0;
1461 server_info_t
*info
;
1463 /* allow one thread at a time */
1464 (void) mutex_lock(&refresh_mutex
);
1466 if (current_admin
.debug_level
>= DBG_ALL
) {
1467 logit("getldap_set_refresh_ttl()...\n");
1470 if (!head
|| !refresh_ttl
|| !no_gd_server
) {
1471 logit("getldap_set_refresh_ttl: head is "
1472 "NULL or refresh_ttl is NULL or "
1473 "no_gd_server is NULL");
1474 (void) mutex_unlock(&refresh_mutex
);
1477 *no_gd_server
= FALSE
;
1480 * init max. min. TTLs if first time through or a fresh one
1482 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1483 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1484 "seconds\n", *refresh_ttl
);
1486 if (*refresh_ttl
== 0) {
1489 * init cache manager server list TTL:
1491 * init the min. TTL to
1492 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1494 refresh_ttl_min
= REFRESHTTL_MIN
;
1497 * try to set the max. TTL to
1498 * configuration refresh TTL (NS_LDAP_CACHETTL),
1499 * if error (-1), or never refreshed (0),
1500 * set it to REFRESHTTL_MAX (12 hours)
1502 refresh_ttl_max
= getldap_get_cacheTTL();
1503 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1504 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1505 "seconds\n", *refresh_ttl
);
1506 logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1507 "min ttl is %d seconds\n",
1508 refresh_ttl_max
, refresh_ttl_min
);
1510 if (refresh_ttl_max
<= 0)
1511 refresh_ttl_max
= REFRESHTTL_MAX
;
1512 else if (refresh_ttl_max
< refresh_ttl_min
)
1513 refresh_ttl_max
= refresh_ttl_min
;
1516 * init the first TTL to the smaller of the two:
1517 * REFRESHTTL_REGULAR ( 10 minutes),
1518 * (refresh_ttl_max + refresh_ttl_min)/2
1520 *refresh_ttl
= REFRESHTTL_REGULAR
;
1521 if (*refresh_ttl
> (refresh_ttl_max
+ refresh_ttl_min
) / 2)
1522 *refresh_ttl
= (refresh_ttl_max
+ refresh_ttl_min
) / 2;
1523 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1524 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1525 "seconds\n", *refresh_ttl
);
1526 logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1527 "min ttl is %d seconds\n",
1528 refresh_ttl_max
, refresh_ttl_min
);
1533 * get the servers statistics:
1534 * number of servers on list
1535 * number of good servers on list
1536 * number of pevious good servers on list
1538 for (info
= head
; info
; info
= info
->next
) {
1540 (void) mutex_lock(&info
->mutex
[0]);
1541 if (info
->sinfo
[0].server_status
== INFO_SERVER_UP
)
1544 * Server's previous status could be UNKNOWN
1545 * only between the very first and second
1546 * refresh. Treat that UNKNOWN status as up
1548 if (info
->sinfo
[0].prev_server_status
1549 == INFO_SERVER_UP
||
1550 info
->sinfo
[0].prev_server_status
1551 == INFO_SERVER_UNKNOWN
)
1552 num_prev_good_servers
++;
1553 (void) mutex_unlock(&info
->mutex
[0]);
1557 * if the server list is walked three times in a row
1558 * without problems, double the refresh TTL but no more
1559 * than the max. refresh TTL
1561 if (num_good_servers
== num_servers
) {
1563 if (num_walked_ok
> UP_REFRESH_TTL_NUM
) {
1565 *refresh_ttl
= *refresh_ttl
* 2;
1566 if (*refresh_ttl
> refresh_ttl_max
)
1567 *refresh_ttl
= refresh_ttl_max
;
1571 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1572 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1573 "seconds\n", *refresh_ttl
);
1575 } else if (num_good_servers
== 0) {
1577 * if no good server found,
1578 * set refresh TTL to miminum
1580 *refresh_ttl
= refresh_ttl_min
;
1581 *no_gd_server
= TRUE
;
1583 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1584 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1585 "seconds\n", *refresh_ttl
);
1587 } else if (num_prev_good_servers
> num_good_servers
) {
1589 * if more down/bad servers found,
1590 * decrease the refresh TTL by half
1591 * but no less than the min. refresh TTL
1593 *refresh_ttl
= *refresh_ttl
/ 2;
1594 if (*refresh_ttl
< refresh_ttl_min
)
1595 *refresh_ttl
= refresh_ttl_min
;
1597 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1598 "seconds\n", *refresh_ttl
);
1602 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1603 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1606 (void) mutex_unlock(&refresh_mutex
);
1611 getldap_serverInfo_op(info_op_t op
, char *input
, char **output
)
1614 static rwlock_t info_lock
= DEFAULTRWLOCK
;
1615 static rwlock_t info_lock_old
= DEFAULTRWLOCK
;
1616 static mutex_t info_mutex
;
1617 static cond_t info_cond
;
1618 static int creating
= FALSE
;
1619 static int refresh_ttl
= 0;
1620 static int sec_to_refresh
= 0;
1621 static int in_no_server_mode
= FALSE
;
1623 static server_info_t
*serverInfo
= NULL
;
1624 static server_info_t
*serverInfo_old
= NULL
;
1625 server_info_t
*serverInfo_1
;
1627 int err
, no_server_good
= FALSE
;
1628 int server_removed
= FALSE
;
1629 int fall_thru
= FALSE
;
1630 static struct timespec timeout
;
1631 struct timespec new_timeout
;
1633 static time_t prev_refresh
= 0, next_refresh
= 0;
1634 ns_server_status_t changed
= 0;
1636 (void) pthread_setname_np(pthread_self(), "getldap_serverinfo");
1638 if (current_admin
.debug_level
>= DBG_ALL
) {
1639 logit("getldap_serverInfo_op()...\n");
1642 case INFO_OP_CREATE
:
1643 if (current_admin
.debug_level
>= DBG_ALL
) {
1644 logit("operation is INFO_OP_CREATE...\n");
1648 * indicate that the server info is being
1649 * (re)created, so that the refresh thread
1650 * will not refresh the info list right
1651 * after the list got (re)created
1653 (void) mutex_lock(&info_mutex
);
1654 is_creating
= creating
;
1656 (void) mutex_unlock(&info_mutex
);
1661 * create an empty info list
1663 (void) getldap_init_serverInfo(&serverInfo_1
);
1665 * exit if list not created
1667 if (serverInfo_1
== NULL
) {
1668 (void) mutex_lock(&info_mutex
);
1670 (void) mutex_unlock(&info_mutex
);
1674 * make the new server info available:
1675 * use writer lock here, so that the switch
1676 * is done after all the reader locks have
1679 (void) rw_wrlock(&info_lock
);
1680 serverInfo
= serverInfo_1
;
1682 * if this is the first time
1683 * the server list is being created,
1684 * (i.e., serverInfo_old is NULL)
1685 * make the old list same as the new
1686 * so the GETSERVER code can do its work
1688 if (serverInfo_old
== NULL
)
1689 serverInfo_old
= serverInfo_1
;
1690 (void) rw_unlock(&info_lock
);
1693 * fill the new info list
1695 (void) rw_rdlock(&info_lock
);
1696 /* reset bind time (tcptimeout) */
1697 (void) getldap_set_serverInfo(serverInfo
, 1, INFO_OP_CREATE
);
1699 (void) mutex_lock(&info_mutex
);
1701 * set cache manager server list TTL,
1702 * set refresh_ttl to zero to indicate a fresh one
1705 (void) getldap_set_refresh_ttl(serverInfo
,
1706 &refresh_ttl
, &no_server_good
);
1707 sec_to_refresh
= refresh_ttl
;
1709 /* statistics: previous refresh time */
1710 if (gettimeofday(&tp
, NULL
) == 0)
1711 prev_refresh
= tp
.tv_sec
;
1716 * if no server found or available,
1717 * tell the server info refresh thread
1718 * to start the "no-server" refresh loop
1719 * otherwise reset the in_no_server_mode flag
1721 if (no_server_good
) {
1723 in_no_server_mode
= TRUE
;
1725 in_no_server_mode
= FALSE
;
1727 * awake the sleeping refresh thread
1729 (void) cond_signal(&info_cond
);
1731 (void) mutex_unlock(&info_mutex
);
1732 (void) rw_unlock(&info_lock
);
1735 * delete the old server info
1737 (void) rw_wrlock(&info_lock_old
);
1738 if (serverInfo_old
!= serverInfo
)
1739 (void) getldap_destroy_serverInfo(serverInfo_old
);
1741 * serverInfo_old needs to be the same as
1743 * it will be used by GETSERVER processing.
1745 serverInfo_old
= serverInfo
;
1746 (void) rw_unlock(&info_lock_old
);
1748 case INFO_OP_DELETE
:
1749 if (current_admin
.debug_level
>= DBG_ALL
) {
1750 logit("operation is INFO_OP_DELETE...\n");
1753 * use writer lock here, so that the delete would
1754 * not start until all the reader locks have
1757 (void) rw_wrlock(&info_lock
);
1759 (void) getldap_destroy_serverInfo(serverInfo
);
1761 (void) rw_unlock(&info_lock
);
1763 case INFO_OP_REFRESH
:
1764 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1765 logit("operation is INFO_OP_REFRESH...\n");
1768 * if server info is currently being
1769 * (re)created, do nothing
1771 (void) mutex_lock(&info_mutex
);
1772 is_creating
= creating
;
1773 (void) mutex_unlock(&info_mutex
);
1777 (void) rw_rdlock(&info_lock
);
1779 /* do not reset bind time (tcptimeout) */
1780 (void) getldap_set_serverInfo(serverInfo
, 0,
1783 (void) mutex_lock(&info_mutex
);
1785 /* statistics: previous refresh time */
1786 if (gettimeofday(&tp
, NULL
) == 0)
1787 prev_refresh
= tp
.tv_sec
;
1789 * set cache manager server list TTL
1791 (void) getldap_set_refresh_ttl(serverInfo
,
1792 &refresh_ttl
, &no_server_good
);
1794 * if no good server found,
1795 * tell the server info refresh thread
1796 * to start the "no-server" refresh loop
1797 * otherwise reset the in_no_server_mode flag
1799 if (no_server_good
) {
1800 in_no_server_mode
= TRUE
;
1803 in_no_server_mode
= FALSE
;
1804 sec_to_refresh
= refresh_ttl
;
1806 if (current_admin
.debug_level
>=
1807 DBG_SERVER_LIST_REFRESH
) {
1808 logit("getldap_serverInfo_op("
1810 " seconds refresh: %d second(s)....\n",
1813 (void) mutex_unlock(&info_mutex
);
1815 (void) rw_unlock(&info_lock
);
1818 case INFO_OP_REFRESH_WAIT
:
1819 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1820 logit("operation is INFO_OP_REFRESH_WAIT...\n");
1822 (void) cond_init(&info_cond
, NULL
, NULL
);
1823 (void) mutex_lock(&info_mutex
);
1825 while (err
!= ETIME
) {
1828 * if need to go into the "no-server" refresh
1829 * loop, set timout value to
1830 * REFRESH_DELAY_WHEN_NO_SERVER
1832 if (sec_to_refresh
== 0) {
1833 sec_to_refresh
= refresh_ttl
;
1834 timeout
.tv_sec
= time(NULL
) +
1835 REFRESH_DELAY_WHEN_NO_SERVER
;
1836 sleeptime
= REFRESH_DELAY_WHEN_NO_SERVER
;
1837 if (current_admin
.debug_level
>=
1838 DBG_SERVER_LIST_REFRESH
) {
1839 logit("getldap_serverInfo_op("
1840 "INFO_OP_REFRESH_WAIT):"
1841 " entering no-server "
1842 "refresh loop...\n");
1845 timeout
.tv_sec
= time(NULL
) + sec_to_refresh
;
1846 sleeptime
= sec_to_refresh
;
1848 timeout
.tv_nsec
= 0;
1850 /* statistics: next refresh time */
1851 next_refresh
= timeout
.tv_sec
;
1853 if (current_admin
.debug_level
>=
1854 DBG_SERVER_LIST_REFRESH
) {
1855 logit("getldap_serverInfo_op("
1856 "INFO_OP_REFRESH_WAIT):"
1857 " about to sleep for %d second(s)...\n",
1860 err
= cond_timedwait(&info_cond
,
1861 &info_mutex
, &timeout
);
1863 (void) cond_destroy(&info_cond
);
1864 (void) mutex_unlock(&info_mutex
);
1866 case INFO_OP_GETSERVER
:
1867 if (current_admin
.debug_level
>= DBG_ALL
) {
1868 logit("operation is INFO_OP_GETSERVER...\n");
1872 * GETSERVER processing always use
1873 * serverInfo_old to retrieve server infomation.
1874 * serverInfo_old is equal to serverInfo
1875 * most of the time, except when a new
1876 * server list is being created.
1877 * This is why the check for is_creating
1880 (void) rw_rdlock(&info_lock_old
);
1882 if (serverInfo_old
== NULL
) {
1883 (void) rw_unlock(&info_lock_old
);
1886 (void) getldap_get_serverInfo(serverInfo_old
,
1887 input
, output
, &server_removed
);
1888 (void) rw_unlock(&info_lock_old
);
1891 * Return here and let remove server thread do its job in
1892 * another thread. It executes INFO_OP_REMOVESERVER code later.
1901 case INFO_OP_REMOVESERVER
:
1903 * INFO_OP_GETSERVER and INFO_OP_REMOVESERVER share the
1904 * following code except (!fall thru) part.
1908 * if server info is currently being
1909 * (re)created, do nothing
1912 (void) mutex_lock(&info_mutex
);
1913 is_creating
= creating
;
1914 (void) mutex_unlock(&info_mutex
);
1919 if (current_admin
.debug_level
>= DBG_ALL
)
1920 logit("operation is INFO_OP_REMOVESERVER...\n");
1921 (void) rw_rdlock(&info_lock_old
);
1922 changed
= set_server_status(input
, serverInfo_old
);
1923 (void) rw_unlock(&info_lock_old
);
1925 create_buf_and_notify(input
, changed
);
1931 * set cache manager server list TTL if necessary
1933 if (*output
== NULL
|| changed
) {
1934 (void) rw_rdlock(&info_lock
);
1935 (void) mutex_lock(&info_mutex
);
1937 (void) getldap_set_refresh_ttl(serverInfo
,
1938 &refresh_ttl
, &no_server_good
);
1941 * if no good server found, need to go into
1942 * the "no-server" refresh loop
1943 * to find a server as soon as possible
1944 * otherwise reset the in_no_server_mode flag
1946 if (no_server_good
) {
1948 * if already in no-server mode,
1951 if (in_no_server_mode
== FALSE
) {
1953 in_no_server_mode
= TRUE
;
1954 (void) cond_signal(&info_cond
);
1956 (void) mutex_unlock(&info_mutex
);
1957 (void) rw_unlock(&info_lock
);
1960 in_no_server_mode
= FALSE
;
1961 sec_to_refresh
= refresh_ttl
;
1964 * if the refresh thread will be timed out
1965 * longer than refresh_ttl seconds,
1966 * wake it up to make it wait on the new
1969 new_timeout
.tv_sec
= time(NULL
) + refresh_ttl
;
1970 if (new_timeout
.tv_sec
< timeout
.tv_sec
)
1971 (void) cond_signal(&info_cond
);
1973 (void) mutex_unlock(&info_mutex
);
1974 (void) rw_unlock(&info_lock
);
1977 case INFO_OP_GETSTAT
:
1978 if (current_admin
.debug_level
>= DBG_ALL
) {
1979 logit("operation is INFO_OP_GETSTAT...\n");
1982 (void) rw_rdlock(&info_lock
);
1984 (void) getldap_get_server_stat(serverInfo
,
1985 output
, &prev_refresh
, &next_refresh
);
1987 (void) rw_unlock(&info_lock
);
1990 logit("getldap_serverInfo_op(): "
1991 "invalid operation code (%d).\n", op
);
1995 return (NS_LDAP_SUCCESS
);
1999 getldap_serverInfo_refresh()
2003 if (current_admin
.debug_level
>= DBG_ALL
) {
2004 logit("getldap_serverInfo_refresh()...\n");
2007 /* create the server info list */
2008 (void) getldap_serverInfo_op(INFO_OP_CREATE
, NULL
, NULL
);
2012 * the operation INFO_OP_REFRESH_WAIT
2013 * causes this thread to wait until
2014 * it is time to do refresh,
2015 * see getldap_serverInfo_op() for details
2017 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT
, NULL
, NULL
);
2018 (void) getldap_serverInfo_op(INFO_OP_REFRESH
, NULL
, NULL
);
2023 getldap_getserver(LineBuf
*config_info
, ldap_call_t
*in
)
2027 if (current_admin
.debug_level
>= DBG_ALL
) {
2028 logit("getldap_getserver()...\n");
2031 config_info
->len
= 0;
2033 /* make sure the request is valid */
2034 req
[0] = (in
->ldap_u
.servername
)[0];
2035 if ((req
[0] != '\0') &&
2036 (strcmp(req
, NS_CACHE_NEW
) != 0) &&
2037 (strcmp(req
, NS_CACHE_NORESP
) != 0) &&
2038 (strcmp(req
, NS_CACHE_NEXT
) != 0) &&
2039 (strcmp(req
, NS_CACHE_WRITE
) != 0)) {
2043 (void) getldap_serverInfo_op(INFO_OP_GETSERVER
,
2044 in
->ldap_u
.domainname
, &config_info
->str
);
2046 if (config_info
->str
== NULL
)
2049 config_info
->len
= strlen(config_info
->str
) + 1;
2051 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2055 ptr
= strstr(config_info
->str
, DOORLINESEP
);
2059 logit("getldap_getserver: got server %s\n",
2063 logit("getldap_getserver: Missing %s."
2064 " Internal error\n", DOORLINESEP
);
2069 getldap_get_cacheData(LineBuf
*config_info
, ldap_call_t
*in
)
2072 int datatype
= CACHE_MAP_UNKNOWN
;
2074 if (current_admin
.debug_level
>= DBG_ALL
) {
2075 logit("getldap_get_cacheData()...\n");
2078 config_info
->len
= 0;
2079 config_info
->str
= NULL
;
2081 /* make sure the request is valid */
2082 if (strncmp(in
->ldap_u
.servername
,
2083 NS_CACHE_DN2DOMAIN
, strlen(NS_CACHE_DN2DOMAIN
)) == 0)
2084 datatype
= CACHE_MAP_DN2DOMAIN
;
2086 if (datatype
== CACHE_MAP_UNKNOWN
)
2089 instr
= strstr(in
->ldap_u
.servername
, DOORLINESEP
);
2092 instr
+= strlen(DOORLINESEP
);
2096 (void) getldap_cache_op(CACHE_OP_FIND
, datatype
,
2097 instr
, &config_info
->str
);
2099 if (config_info
->str
!= NULL
) {
2100 config_info
->len
= strlen(config_info
->str
) + 1;
2105 getldap_set_cacheData(ldap_call_t
*in
)
2107 char *instr1
= NULL
;
2108 char *instr2
= NULL
;
2109 int datatype
= CACHE_MAP_UNKNOWN
;
2112 if (current_admin
.debug_level
>= DBG_ALL
) {
2113 logit("getldap_set_cacheData()...\n");
2116 /* make sure the request is valid */
2117 if (strncmp(in
->ldap_u
.servername
,
2118 NS_CACHE_DN2DOMAIN
, strlen(NS_CACHE_DN2DOMAIN
)) == 0)
2119 datatype
= CACHE_MAP_DN2DOMAIN
;
2121 if (datatype
== CACHE_MAP_UNKNOWN
)
2124 instr1
= strstr(in
->ldap_u
.servername
, DOORLINESEP
);
2128 instr1
+= strlen(DOORLINESEP
);
2129 if (*instr1
== '\0')
2131 instr2
= strstr(instr1
, DOORLINESEP
);
2135 instr2
+= strlen(DOORLINESEP
);
2136 if (*instr2
== '\0')
2139 rc
= getldap_cache_op(CACHE_OP_ADD
, datatype
,
2141 if (rc
!= NS_LDAP_SUCCESS
)
2148 getldap_get_cacheStat(LineBuf
*stat_info
)
2150 char *foutstr
= NULL
;
2151 char *soutstr
= NULL
;
2152 char *coutstr
= NULL
;
2155 if (current_admin
.debug_level
>= DBG_ALL
) {
2156 logit("getldap_get_cacheStat()...\n");
2159 stat_info
->str
= NULL
;
2162 /* get refersh statisitcs */
2163 (void) getldap_get_refresh_stat(&foutstr
);
2164 if (foutstr
== NULL
)
2167 /* get server statisitcs */
2168 (void) getldap_serverInfo_op(INFO_OP_GETSTAT
, NULL
, &soutstr
);
2169 if (soutstr
== NULL
) {
2173 /* get cache data statisitcs */
2174 (void) getldap_cache_op(CACHE_OP_GETSTAT
, NULL
, NULL
, &coutstr
);
2175 if (coutstr
== NULL
) {
2181 infoSize
= strlen(foutstr
) + strlen(soutstr
) + strlen(coutstr
) + 3;
2182 stat_info
->str
= calloc(infoSize
, sizeof (char));
2183 if (stat_info
->str
!= NULL
) {
2184 (void) strncpy(stat_info
->str
,
2186 strlen(foutstr
) + 1);
2187 (void) strncat(stat_info
->str
,
2189 strlen(soutstr
) + 1);
2190 (void) strncat(stat_info
->str
,
2192 strlen(coutstr
) + 1);
2193 stat_info
->len
= infoSize
;
2202 checkupdate(int sighup
)
2206 (void) rw_wrlock(&ldap_lock
);
2208 (void) rw_unlock(&ldap_lock
);
2210 return (value
== TRUE
);
2215 update_from_profile(int *change_status
)
2217 ns_ldap_result_t
*result
= NULL
;
2218 char searchfilter
[BUFSIZ
];
2219 ns_ldap_error_t
*error
;
2221 void **paramVal
= NULL
;
2222 ns_config_t
*ptr
= NULL
;
2223 char *profile
= NULL
;
2224 char errstr
[MAXERROR
];
2226 if (current_admin
.debug_level
>= DBG_ALL
) {
2227 logit("update_from_profile....\n");
2230 (void) rw_wrlock(&ldap_lock
);
2231 sighup_update
= FALSE
;
2232 (void) rw_unlock(&ldap_lock
);
2234 if ((rc
= __ns_ldap_getParam(NS_LDAP_PROFILE_P
,
2235 ¶mVal
, &error
)) != NS_LDAP_SUCCESS
) {
2236 if (error
!= NULL
&& error
->message
!= NULL
)
2237 logit("Error: Unable to profile name: %s\n",
2242 __ns_ldap_err2str(rc
, &tmp
);
2243 logit("Error: Unable to profile name: %s\n",
2246 (void) __ns_ldap_freeParam(¶mVal
);
2247 (void) __ns_ldap_freeError(&error
);
2251 if (paramVal
&& *paramVal
)
2252 profile
= strdup((char *)*paramVal
);
2253 (void) __ns_ldap_freeParam(¶mVal
);
2255 if (profile
== NULL
) {
2259 (void) snprintf(searchfilter
, BUFSIZ
, _PROFILE_FILTER
,
2260 _PROFILE1_OBJECTCLASS
, _PROFILE2_OBJECTCLASS
, profile
);
2262 if ((rc
= __ns_ldap_list(_PROFILE_CONTAINER
,
2263 (const char *)searchfilter
, NULL
,
2265 &result
, &error
, NULL
, NULL
)) != NS_LDAP_SUCCESS
) {
2268 * Is profile name the DEFAULTCONFIGNAME?
2269 * syslog Warning, otherwise syslog error.
2271 if (strcmp(profile
, DEFAULTCONFIGNAME
) == 0) {
2273 "Ignoring attempt to refresh nonexistent "
2274 "default profile: %s.\n",
2276 logit("Ignoring attempt to refresh nonexistent "
2277 "default profile: %s.\n",
2279 } else if ((error
!= NULL
) &&
2280 (error
->message
!= NULL
)) {
2282 "Error: Unable to refresh profile:%s:"
2283 " %s\n", profile
, error
->message
);
2284 logit("Error: Unable to refresh profile:"
2285 "%s:%s\n", profile
, error
->message
);
2287 syslog(LOG_ERR
, "Error: Unable to refresh "
2288 "from profile:%s. (error=%d)\n",
2290 logit("Error: Unable to refresh from profile "
2291 "%s (error=%d)\n", profile
, rc
);
2294 (void) __ns_ldap_freeError(&error
);
2295 (void) __ns_ldap_freeResult(&result
);
2302 } while (checkupdate(sighup_update
) == TRUE
);
2304 (void) rw_wrlock(&ldap_lock
);
2306 ptr
= __ns_ldap_make_config(result
);
2307 (void) __ns_ldap_freeResult(&result
);
2310 logit("Error: __ns_ldap_make_config failed.\n");
2311 (void) rw_unlock(&ldap_lock
);
2316 * cross check the config parameters
2318 if (__s_api_crosscheck(ptr
, errstr
, B_TRUE
) == NS_SUCCESS
) {
2320 * reset the local profile TTL
2322 if (ptr
->paramList
[NS_LDAP_CACHETTL_P
].ns_pc
)
2323 current_admin
.ldap_stat
.ldap_ttl
=
2324 atol(ptr
->paramList
[NS_LDAP_CACHETTL_P
].ns_pc
);
2326 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2327 logit("update_from_profile: reset profile TTL to %d"
2329 current_admin
.ldap_stat
.ldap_ttl
);
2330 logit("update_from_profile: expire time %ld "
2332 ptr
->paramList
[NS_LDAP_EXP_P
].ns_tm
);
2335 /* set ptr as current_config if the config is changed */
2336 chg_test_config_change(ptr
, change_status
);
2339 __s_api_destroy_config(ptr
);
2340 logit("Error: downloaded profile failed to pass "
2341 "crosscheck (%s).\n", errstr
);
2342 syslog(LOG_ERR
, "ldap_cachemgr: %s", errstr
);
2345 (void) rw_unlock(&ldap_lock
);
2353 ns_ldap_error_t
*error
;
2355 ldap_get_chg_cookie_t cookie
;
2357 if (current_admin
.debug_level
>= DBG_ALL
) {
2358 logit("getldap_init()...\n");
2361 (void) __ns_ldap_setServer(TRUE
);
2363 (void) rw_wrlock(&ldap_lock
);
2364 if ((error
= __ns_ldap_LoadConfiguration()) != NULL
) {
2365 logit("Error: Unable to read '%s': %s\n",
2366 NSCONFIGFILE
, error
->message
);
2367 (void) fprintf(stderr
,
2368 gettext("\nError: Unable to read '%s': %s\n"),
2369 NSCONFIGFILE
, error
->message
);
2370 __ns_ldap_freeError(&error
);
2371 (void) rw_unlock(&ldap_lock
);
2374 (void) rw_unlock(&ldap_lock
);
2376 if (gettimeofday(&tp
, NULL
) == 0) {
2377 /* statistics: previous refresh time */
2378 prev_refresh_time
= tp
.tv_sec
;
2381 /* initialize the data cache */
2382 (void) getldap_cache_op(CACHE_OP_CREATE
,
2385 cookie
.mgr_pid
= getpid();
2387 chg_config_cookie_set(&cookie
);
2392 perform_update(void)
2394 ns_ldap_error_t
*error
= NULL
;
2399 void **paramVal
= NULL
;
2400 ns_ldap_self_gssapi_config_t config
;
2402 if (current_admin
.debug_level
>= DBG_ALL
) {
2403 logit("perform_update()...\n");
2406 (void) __ns_ldap_setServer(TRUE
);
2408 if (gettimeofday(&tp
, NULL
) != 0)
2411 rc
= __ns_ldap_getParam(NS_LDAP_CACHETTL_P
, ¶mVal
, &error
);
2413 if (rc
== NS_LDAP_SUCCESS
&& paramVal
!= NULL
) {
2414 current_admin
.ldap_stat
.ldap_ttl
= atol((char *)*paramVal
);
2418 (void) __ns_ldap_freeError(&error
);
2420 if (paramVal
!= NULL
)
2421 (void) __ns_ldap_freeParam(¶mVal
);
2423 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2424 logit("perform_update: current profile TTL is %d seconds\n",
2425 current_admin
.ldap_stat
.ldap_ttl
);
2428 if (current_admin
.ldap_stat
.ldap_ttl
> 0) {
2430 * set the profile TTL parameter, just
2431 * in case that the downloading of
2432 * the profile from server would fail
2436 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2437 * It depends on NS_LDAP_CACHETTL_P to set it's value
2438 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2440 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2441 * downloaded from the server, so is NS_LDAP_EXP_P.
2443 buf
[19] = '\0'; /* null terminated the buffer */
2444 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P
,
2445 lltostr((long long)current_admin
.ldap_stat
.ldap_ttl
,
2447 &error
) != NS_LDAP_SUCCESS
) {
2448 logit("Error: __ns_ldap_setParam failed, status: %d "
2449 "message: %s\n", error
->status
, error
->message
);
2450 (void) __ns_ldap_freeError(&error
);
2454 (void) rw_wrlock(&ldap_lock
);
2455 sighup_update
= FALSE
;
2456 (void) rw_unlock(&ldap_lock
);
2459 rc
= update_from_profile(&changed
);
2461 logit("Error: Unable to update from profile\n");
2463 } while (checkupdate(sighup_update
) == TRUE
);
2469 * recreate the server info list
2472 (void) getldap_serverInfo_op(INFO_OP_CREATE
, NULL
, NULL
);
2474 /* flush the data cache */
2475 (void) getldap_cache_op(CACHE_OP_DELETE
,
2478 /* statistics: previous refresh time */
2479 prev_refresh_time
= tp
.tv_sec
;
2481 rc1
= __ns_ldap_self_gssapi_config(&config
);
2482 if (rc1
== NS_LDAP_SUCCESS
) {
2483 if (config
!= NS_LDAP_SELF_GSSAPI_CONFIG_NONE
) {
2484 rc1
= __ns_ldap_check_all_preq(0, 0, 0, config
, &error
);
2485 (void) __ns_ldap_freeError(&error
);
2486 if (rc1
!= NS_LDAP_SUCCESS
) {
2487 logit("Error: Check on self credential "
2488 "prerquesites failed: %d\n",
2494 logit("Error: Failed to get self credential configuration %d\n",
2502 (void) rw_rdlock(&ldap_lock
);
2503 if (((error
= __ns_ldap_DumpConfiguration(NSCONFIGREFRESH
)) != NULL
) ||
2504 ((error
= __ns_ldap_DumpConfiguration(NSCREDREFRESH
)) != NULL
)) {
2505 logit("Error: __ns_ldap_DumpConfiguration failed, "
2506 "status: %d message: %s\n", error
->status
, error
->message
);
2507 __ns_ldap_freeError(&error
);
2508 (void) rw_unlock(&ldap_lock
);
2511 if (rename(NSCONFIGREFRESH
, NSCONFIGFILE
) != 0) {
2512 logit("Error: unlink failed - errno: %s\n", strerror(errno
));
2513 syslog(LOG_ERR
, "Unable to refresh profile, LDAP configuration"
2514 "files not written");
2515 (void) rw_unlock(&ldap_lock
);
2518 if (rename(NSCREDREFRESH
, NSCREDFILE
) != 0) {
2520 * We probably have inconsistent configuration at this point.
2521 * If we were to create a backup file and rename it here, that
2522 * operation might also fail. Consequently there is no safe way
2525 logit("Error: unlink failed - errno: %s\n", strerror(errno
));
2526 syslog(LOG_ERR
, "Unable to refresh profile consistently, "
2527 "LDAP configuration files inconsistent");
2528 (void) rw_unlock(&ldap_lock
);
2532 (void) rw_unlock(&ldap_lock
);
2538 struct timespec timeout
;
2542 void **paramVal
= NULL
;
2543 ns_ldap_error_t
*errorp
;
2544 int always
= 1, err
;
2549 (void) pthread_setname_np(pthread_self(), "getldap_refresh");
2551 if (current_admin
.debug_level
>= DBG_ALL
) {
2552 logit("getldap_refresh()...\n");
2556 * wait for an available server
2558 while (sig_done
== 0) {
2559 (void) mutex_lock(&sig_mutex
);
2560 sig_done
= signal_done
;
2561 (void) mutex_unlock(&sig_mutex
);
2564 (void) __ns_ldap_setServer(TRUE
);
2566 dbg_level
= current_admin
.debug_level
;
2567 (void) rw_rdlock(&ldap_lock
);
2568 sleeptime
= current_admin
.ldap_stat
.ldap_ttl
;
2569 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2570 logit("getldap_refresh: current profile TTL is %d "
2571 "seconds\n", current_admin
.ldap_stat
.ldap_ttl
);
2573 if (gettimeofday(&tp
, NULL
) == 0) {
2574 if ((__ns_ldap_getParam(NS_LDAP_EXP_P
,
2575 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
2577 (char *)*paramVal
!= NULL
) {
2579 expire
= atol((char *)*paramVal
);
2580 (void) __ns_ldap_freeParam(¶mVal
);
2584 (void) rw_unlock(&ldap_lock
);
2585 (void) cond_init(&cond
,
2587 (void) mutex_lock(&sighuplock
);
2590 timeout
.tv_nsec
= 0;
2592 DBG_PROFILE_REFRESH
) {
2593 logit("getldap_refresh:"
2595 " for %d seconds\n",
2598 err
= cond_reltimedwait(&cond
,
2599 &sighuplock
, &timeout
);
2600 (void) cond_destroy(&cond
);
2601 (void) mutex_unlock(
2605 * getldap_revalidate(),
2606 * do update right away
2613 * configuration failed
2622 sleeptime
= expire
- tp
.tv_sec
;
2623 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2624 logit("getldap_refresh: expire "
2625 "time = %ld\n", expire
);
2632 (void) rw_unlock(&ldap_lock
);
2635 * if this is the first time downloading
2636 * the profile or expire time already passed,
2637 * do not wait, do update
2639 if (first_time
== 0 && sleeptime
> 0) {
2640 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2641 logit("getldap_refresh: (2)about to sleep "
2642 "for %d seconds\n", sleeptime
);
2644 (void) cond_init(&cond
, NULL
, NULL
);
2645 (void) mutex_lock(&sighuplock
);
2646 timeout
.tv_sec
= sleeptime
;
2647 timeout
.tv_nsec
= 0;
2648 err
= cond_reltimedwait(&cond
,
2649 &sighuplock
, &timeout
);
2650 (void) cond_destroy(&cond
);
2651 (void) mutex_unlock(&sighuplock
);
2654 * if load concfiguration failed
2664 getldap_revalidate()
2666 if (current_admin
.debug_level
>= DBG_ALL
) {
2667 logit("getldap_revalidate()...\n");
2669 /* block signal SIGHUP */
2670 (void) sighold(SIGHUP
);
2672 /* now awake the sleeping refresh thread */
2673 (void) cond_signal(&cond
);
2675 /* release signal SIGHUP */
2676 (void) sigrelse(SIGHUP
);
2681 getldap_admincred(LineBuf
*config_info
, ldap_call_t
*in
)
2683 ns_ldap_error_t
*error
;
2684 ldap_config_out_t
*cout
;
2687 if (current_admin
.debug_level
>= DBG_ALL
) {
2688 logit("getldap_admincred()...\n");
2690 /* check privileges */
2691 if (is_root_or_all_privs("GETADMINCRED", &uc
) == 0) {
2692 logit("admin credential requested by a non-root and no ALL "
2693 "privilege user not allowed");
2694 config_info
->str
= NULL
;
2695 config_info
->len
= 0;
2697 (void) rw_rdlock(&ldap_lock
);
2698 if ((error
= __ns_ldap_LoadDoorInfo(config_info
,
2699 in
->ldap_u
.domainname
, NULL
, 1)) != NULL
) {
2700 if (error
!= NULL
&& error
->message
!= NULL
)
2701 logit("Error: ldap_lookup: %s\n",
2703 (void) __ns_ldap_freeError(&error
);
2705 config_info
->str
= NULL
;
2706 config_info
->len
= 0;
2708 /* set change cookie */
2709 cout
= (ldap_config_out_t
*)config_info
->str
;
2711 cout
->cookie
= chg_config_cookie_get();
2712 (void) rw_unlock(&ldap_lock
);
2717 getldap_lookup(LineBuf
*config_info
, ldap_call_t
*in
)
2719 ns_ldap_error_t
*error
;
2720 ldap_config_out_t
*cout
;
2722 if (current_admin
.debug_level
>= DBG_ALL
) {
2723 logit("getldap_lookup()...\n");
2725 (void) rw_rdlock(&ldap_lock
);
2726 if ((error
= __ns_ldap_LoadDoorInfo(config_info
,
2727 in
->ldap_u
.domainname
, NULL
, 0)) != NULL
) {
2728 if (error
!= NULL
&& error
->message
!= NULL
)
2729 logit("Error: ldap_lookup: %s\n", error
->message
);
2730 (void) __ns_ldap_freeError(&error
);
2732 config_info
->str
= NULL
;
2733 config_info
->len
= 0;
2735 /* set change cookie */
2736 cout
= (ldap_config_out_t
*)config_info
->str
;
2738 cout
->cookie
= chg_config_cookie_get();
2739 (void) rw_unlock(&ldap_lock
);
2742 * It creates the header and data stream to be door returned and notify
2743 * chg_get_statusChange() threads.
2744 * This is called after all getldap_get_rootDSE() threads are joined.
2747 test_server_change(server_info_t
*head
)
2749 server_info_t
*info
;
2750 int len
= 0, num
= 0, ds_len
= 0, new_len
= 0, tlen
= 0;
2751 char *tmp_buf
= NULL
, *ptr
= NULL
, *status
= NULL
;
2752 ldap_get_change_out_t
*cout
;
2754 ds_len
= strlen(DOORLINESEP
);
2756 for (info
= head
; info
; info
= info
->next
) {
2757 (void) mutex_lock(&info
->mutex
[0]);
2758 if (info
->sinfo
[0].change
!= 0) {
2759 /* "9.9.9.9|NS_SERVER_CHANGE_UP|" */
2760 len
+= 2 * ds_len
+ strlen(info
->sinfo
[0].addr
) +
2761 strlen(NS_SERVER_CHANGE_UP
);
2764 (void) mutex_unlock(&info
->mutex
[0]);
2772 tlen
= sizeof (ldap_get_change_out_t
) - sizeof (int) + len
;
2773 if ((tmp_buf
= malloc(tlen
)) == NULL
)
2776 cout
= (ldap_get_change_out_t
*)tmp_buf
;
2777 cout
->type
= NS_STATUS_CHANGE_TYPE_SERVER
;
2778 /* cout->cookie is set by chg_notify_statusChange */
2779 cout
->server_count
= num
;
2780 cout
->data_size
= len
;
2782 /* Create IP|UP or DOWN|IP|UP or DOWN| ... */
2785 for (info
= head
; info
; info
= info
->next
) {
2786 (void) mutex_lock(&info
->mutex
[0]);
2787 if (info
->sinfo
[0].change
== 0) {
2788 (void) mutex_unlock(&info
->mutex
[0]);
2792 if (info
->sinfo
[0].change
== NS_SERVER_UP
)
2793 status
= NS_SERVER_CHANGE_UP
;
2794 else if (info
->sinfo
[0].change
== NS_SERVER_DOWN
)
2795 status
= NS_SERVER_CHANGE_DOWN
;
2797 syslog(LOG_WARNING
, gettext("Bad change value %d"),
2798 info
->sinfo
[0].change
);
2799 (void) mutex_unlock(&info
->mutex
[0]);
2804 if ((snprintf(ptr
, new_len
, "%s%s%s%s",
2805 info
->sinfo
[0].addr
, DOORLINESEP
,
2806 status
, DOORLINESEP
)) >= new_len
) {
2807 (void) mutex_unlock(&info
->mutex
[0]);
2810 new_len
-= strlen(ptr
);
2813 (void) mutex_unlock(&info
->mutex
[0]);
2815 (void) chg_notify_statusChange(tmp_buf
);
2818 * It creates the header and data stream to be door returned and notify
2819 * chg_get_statusChange() threads.
2820 * This is called in removing server case.
2823 create_buf_and_notify(char *input
, ns_server_status_t st
)
2825 rm_svr_t
*rms
= (rm_svr_t
*)input
;
2826 char *tmp_buf
, *ptr
, *status
;
2828 ldap_get_change_out_t
*cout
;
2830 /* IP|UP or DOWN| */
2831 len
= 2 * strlen(DOORLINESEP
) + strlen(rms
->addr
) +
2832 strlen(NS_SERVER_CHANGE_UP
) + 1;
2834 tlen
= sizeof (ldap_get_change_out_t
) - sizeof (int) + len
;
2836 if ((tmp_buf
= malloc(tlen
)) == NULL
)
2839 cout
= (ldap_get_change_out_t
*)tmp_buf
;
2840 cout
->type
= NS_STATUS_CHANGE_TYPE_SERVER
;
2841 /* cout->cookie is set by chg_notify_statusChange */
2842 cout
->server_count
= 1;
2843 cout
->data_size
= len
;
2845 /* Create IP|DOWN| */
2847 if (st
== NS_SERVER_UP
)
2848 status
= NS_SERVER_CHANGE_UP
;
2849 else if (st
== NS_SERVER_DOWN
)
2850 status
= NS_SERVER_CHANGE_DOWN
;
2852 (void) snprintf(ptr
, len
, "%s%s%s%s",
2853 rms
->addr
, DOORLINESEP
, status
, DOORLINESEP
);
2855 (void) chg_notify_statusChange(tmp_buf
);
2860 * Return: 0 server is down, 1 server is up
2863 contact_server(char *addr
)
2865 char *rootDSE
= NULL
;
2866 ns_ldap_error_t
*error
= NULL
;
2869 if (__ns_ldap_getRootDSE(addr
, &rootDSE
, &error
,
2870 SA_ALLOW_FALLBACK
) != NS_LDAP_SUCCESS
) {
2871 if (current_admin
.debug_level
>= DBG_ALL
)
2872 logit("get rootDSE %s failed. %s", addr
,
2873 error
->message
? error
->message
: "");
2881 (void) __ns_ldap_freeError(&error
);
2887 * The thread is spawned to do contact_server() so it won't be blocking
2888 * getldap_serverInfo_op(INFO_OP_GETSERVER, ...) case.
2889 * After contact_server() is done, it calls
2890 * getldap_serverInfo_op(INFO_OP_REMOVESERVER, ...) to return to the remaining
2891 * program flow. It's meant to maintain the original program flow yet be
2892 * non-blocking when it's contacting server.
2895 remove_server_thread(void *arg
)
2897 char *addr
= (char *)arg
, *out
= NULL
;
2901 (void) pthread_setname_np(pthread_self(), "remove_server");
2903 up
= contact_server(addr
);
2908 (void) getldap_serverInfo_op(INFO_OP_REMOVESERVER
, (char *)&rms
, &out
);
2916 * addr is allocated and is freed by remove_server_thread
2917 * It starts a thread to contact server and remove server to avoid long wait
2921 remove_server(char *addr
)
2923 if (thr_create(NULL
, 0, remove_server_thread
,
2924 (void *)addr
, THR_BOUND
|THR_DETACHED
, NULL
) != 0) {
2926 syslog(LOG_ERR
, "thr_create failed for remove_server_thread");
2930 * Compare the server_status and mark it up or down accordingly.
2931 * This is called in removing server case.
2933 static ns_server_status_t
2934 set_server_status(char *input
, server_info_t
*head
)
2936 rm_svr_t
*rms
= (rm_svr_t
*)input
;
2937 ns_server_status_t changed
= 0;
2938 server_info_t
*info
;
2940 for (info
= head
; info
!= NULL
; info
= info
->next
) {
2941 (void) mutex_lock(&info
->mutex
[0]);
2942 if (strcmp(info
->sinfo
[0].addr
, rms
->addr
) == 0) {
2943 if (info
->sinfo
[0].server_status
== INFO_SERVER_UP
&&
2945 info
->sinfo
[0].prev_server_status
=
2946 info
->sinfo
[0].server_status
;
2947 info
->sinfo
[0].server_status
=
2949 info
->sinfo
[0].change
= NS_SERVER_DOWN
;
2950 changed
= NS_SERVER_DOWN
;
2952 } else if (info
->sinfo
[0].server_status
==
2953 INFO_SERVER_ERROR
&& rms
->up
== TRUE
) {
2955 * It should be INFO_SERVER_UP, but check here
2957 info
->sinfo
[0].prev_server_status
=
2958 info
->sinfo
[0].server_status
;
2959 info
->sinfo
[0].server_status
=
2961 info
->sinfo
[0].change
= NS_SERVER_UP
;
2962 changed
= NS_SERVER_UP
;
2964 (void) mutex_unlock(&info
->mutex
[0]);
2967 (void) mutex_unlock(&info
->mutex
[0]);
2970 /* ldap_cachemgr -g option looks up [1] */
2971 (void) mutex_lock(&info
->mutex
[1]);
2972 info
->sinfo
[1].prev_server_status
=
2973 info
->sinfo
[1].server_status
;
2974 if (changed
== NS_SERVER_DOWN
)
2975 info
->sinfo
[1].server_status
= INFO_SERVER_ERROR
;
2976 else if (changed
== NS_SERVER_UP
)
2977 info
->sinfo
[1].server_status
= INFO_SERVER_UP
;
2978 (void) mutex_unlock(&info
->mutex
[1]);