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.
37 #include <sys/types.h>
44 #include <ctype.h> /* tolower */
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.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
;
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;
77 /* nis domain information */
78 #define _NIS_FILTER "objectclass=nisDomainObject"
79 #define _NIS_DOMAIN "nisdomain"
81 #define CACHESLEEPTIME 600
83 * server list refresh delay when in "no server" mode
86 #define REFRESH_DELAY_WHEN_NO_SERVER 1
92 INFO_OP_REFRESH_WAIT
= 3,
93 INFO_OP_GETSERVER
= 4,
95 INFO_OP_REMOVESERVER
= 6
100 INFO_RW_READONLY
= 1,
101 INFO_RW_WRITEABLE
= 2
105 INFO_SERVER_JUST_INITED
= -1,
106 INFO_SERVER_UNKNOWN
= 0,
107 INFO_SERVER_CONNECTING
= 1,
109 INFO_SERVER_ERROR
= 3,
110 INFO_SERVER_REMOVED
= 4
114 INFO_STATUS_UNKNOWN
= 0,
115 INFO_STATUS_ERROR
= 1,
129 CACHE_MAP_UNKNOWN
= 0,
130 CACHE_MAP_DN2DOMAIN
= 1
133 typedef struct server_info_ext
{
139 info_server_t server_status
;
140 info_server_t prev_server_status
;
141 info_status_t info_status
;
142 ns_server_status_t change
;
145 typedef struct server_info
{
146 struct server_info
*next
;
147 mutex_t mutex
[2]; /* 0: current copy lock */
148 /* 1: update copy lock */
149 server_info_ext_t sinfo
[2]; /* 0: current, 1: update copy */
152 typedef struct cache_hash
{
156 struct cache_hash
*next
;
160 * The status of a server to be removed. It can be up or down.
162 typedef struct rm_svr
{
164 int up
; /* 1: up, 0: down */
167 static int getldap_destroy_serverInfo(server_info_t
*head
);
168 static void test_server_change(server_info_t
*head
);
169 static void remove_server(char *addr
);
170 static ns_server_status_t
set_server_status(char *input
, server_info_t
*head
);
171 static void create_buf_and_notify(char *input
, ns_server_status_t st
);
175 * The code was in signal handler getldap_revalidate
176 * It's moved out of the handler because it could cause deadlock
182 ns_ldap_error_t
*error
;
185 (void) __ns_ldap_setServer(TRUE
);
187 (void) rw_wrlock(&ldap_lock
);
188 if ((error
= __ns_ldap_LoadConfiguration()) != NULL
) {
189 logit("Error: Unable to read '%s': %s\n",
190 NSCONFIGFILE
, error
->message
);
191 __ns_ldap_freeError(&error
);
194 sighup_update
= TRUE
;
196 (void) rw_unlock(&ldap_lock
);
202 * Calculate a hash for a string
203 * Based on elf_hash algorithm, hash is case insensitive
204 * Uses tolower instead of _tolower because of I18N
208 getldap_hash(const char *str
)
210 unsigned int hval
= 0;
215 hval
= (hval
<< 4) + tolower(*str
++);
216 if ((g
= (hval
& 0xf0000000)) != 0)
220 return ((unsigned long)hval
);
224 * Remove a hash table entry.
225 * This function expects a lock in place when called.
228 static cache_hash_t
*
229 getldap_free_hash(cache_hash_t
*p
)
233 p
->type
= CACHE_MAP_UNKNOWN
;
245 * Scan a hash table hit for a matching hash entry.
246 * This function expects a lock in place when called.
248 static cache_hash_t
*
249 getldap_scan_hash(cache_type_t type
, char *from
,
253 if (idx
->type
== type
&&
254 strcasecmp(from
, idx
->from
) == 0) {
259 return ((cache_hash_t
*)NULL
);
263 * Format and return the cache data statistics
266 getldap_get_cacheData_stat(int max
, int current
, char **output
)
268 #define C_HEADER0 "Cache data information: "
269 #define C_HEADER1 " Maximum cache entries: "
270 #define C_HEADER2 " Number of cache entries: "
271 int hdr0_len
= strlen(gettext(C_HEADER0
));
272 int hdr1_len
= strlen(gettext(C_HEADER1
));
273 int hdr2_len
= strlen(gettext(C_HEADER2
));
276 if (current_admin
.debug_level
>= DBG_ALL
) {
277 logit("getldap_get_cacheData_stat()...\n");
282 len
= hdr0_len
+ hdr1_len
+ hdr2_len
+
283 3 * strlen(DOORLINESEP
) + 21;
284 *output
= malloc(len
);
288 (void) snprintf(*output
, len
, "%s%s%s%10d%s%s%10d%s",
289 gettext(C_HEADER0
), DOORLINESEP
,
290 gettext(C_HEADER1
), max
, DOORLINESEP
,
291 gettext(C_HEADER2
), current
, DOORLINESEP
);
293 return (NS_LDAP_SUCCESS
);
297 getldap_cache_op(cache_op_t op
, cache_type_t type
,
298 char *from
, char **to
)
300 #define CACHE_HASH_MAX 257
301 #define CACHE_HASH_MAX_ENTRY 256
302 static cache_hash_t
*hashTbl
[CACHE_HASH_MAX
];
303 cache_hash_t
*next
, *idx
, *newp
;
305 static rwlock_t cache_lock
= DEFAULTRWLOCK
;
307 static int entry_num
= 0;
309 if (current_admin
.debug_level
>= DBG_ALL
) {
310 logit("getldap_cache_op()...\n");
313 case CACHE_OP_CREATE
:
314 if (current_admin
.debug_level
>= DBG_ALL
) {
315 logit("operation is CACHE_OP_CREATE...\n");
317 (void) rw_wrlock(&cache_lock
);
319 for (i
= 0; i
< CACHE_HASH_MAX
; i
++) {
324 (void) rw_unlock(&cache_lock
);
327 case CACHE_OP_DELETE
:
328 if (current_admin
.debug_level
>= DBG_ALL
) {
329 logit("operation is CACHE_OP_DELETE...\n");
331 (void) rw_wrlock(&cache_lock
);
333 for (i
= 0; i
< CACHE_HASH_MAX
; i
++) {
335 while (next
!= NULL
) {
336 next
= getldap_free_hash(next
);
342 (void) rw_unlock(&cache_lock
);
346 if (current_admin
.debug_level
>= DBG_ALL
) {
347 logit("operation is CACHE_OP_ADD...\n");
349 if (from
== NULL
|| to
== NULL
|| *to
== NULL
)
351 hash
= getldap_hash(from
) % CACHE_HASH_MAX
;
352 (void) rw_wrlock(&cache_lock
);
355 * replace old "to" value with new one
356 * if an entry with same "from"
360 newp
= getldap_scan_hash(type
, from
, idx
);
363 newp
->to
= strdup(*to
);
364 (void) rw_unlock(&cache_lock
);
365 return (NS_LDAP_SUCCESS
);
369 if (entry_num
> CACHE_HASH_MAX_ENTRY
) {
370 (void) rw_unlock(&cache_lock
);
374 newp
= (cache_hash_t
*)malloc(sizeof (cache_hash_t
));
376 (void) rw_unlock(&cache_lock
);
377 return (NS_LDAP_MEMORY
);
380 newp
->from
= strdup(from
);
381 newp
->to
= strdup(*to
);
383 hashTbl
[hash
] = newp
;
385 (void) rw_unlock(&cache_lock
);
389 if (current_admin
.debug_level
>= DBG_ALL
) {
390 logit("operation is CACHE_OP_FIND...\n");
392 if (from
== NULL
|| to
== NULL
)
395 hash
= getldap_hash(from
) % CACHE_HASH_MAX
;
396 (void) rw_rdlock(&cache_lock
);
398 idx
= getldap_scan_hash(type
, from
, idx
);
400 *to
= strdup(idx
->to
);
401 (void) rw_unlock(&cache_lock
);
406 case CACHE_OP_GETSTAT
:
407 if (current_admin
.debug_level
>= DBG_ALL
) {
408 logit("operation is CACHE_OP_GETSTAT...\n");
413 return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY
,
418 logit("getldap_cache_op(): "
419 "invalid operation code (%d).\n", op
);
423 return (NS_LDAP_SUCCESS
);
426 * Function: sync_current_with_update_copy
428 * This function syncs up the 2 sinfo copies in info.
430 * The 2 copies are identical most of time.
431 * The update copy(sinfo[1]) could be different when
432 * getldap_serverInfo_refresh thread is refreshing the server list
433 * and calls getldap_get_rootDSE to update info. getldap_get_rootDSE
434 * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
435 * The calling sequence is
436 * getldap_serverInfo_refresh->
437 * getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
438 * getldap_set_serverInfo->
439 * getldap_get_rootDSE
441 * The original server_info_t has one copy of server info. When libsldap
442 * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
443 * is updating the server info, it would hit a unprotected window in
444 * getldap_rootDSE. The door call will not get server info and libsldap
445 * fails at making ldap connection.
447 * The new server_info_t provides GETLDAPSERVER thread with a current
448 * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
449 * and syncs up 2 copies before thr_exit. This will close the window in
450 * getldap_get_rootDSE.
454 sync_current_with_update_copy(server_info_t
*info
)
456 if (current_admin
.debug_level
>= DBG_ALL
) {
457 logit("sync_current_with_update_copy()...\n");
460 (void) mutex_lock(&info
->mutex
[1]);
461 (void) mutex_lock(&info
->mutex
[0]);
463 if (info
->sinfo
[1].server_status
== INFO_SERVER_UP
&&
464 info
->sinfo
[0].server_status
!= INFO_SERVER_UP
)
465 info
->sinfo
[1].change
= NS_SERVER_UP
;
466 else if (info
->sinfo
[1].server_status
!= INFO_SERVER_UP
&&
467 info
->sinfo
[0].server_status
== INFO_SERVER_UP
)
468 info
->sinfo
[1].change
= NS_SERVER_DOWN
;
470 info
->sinfo
[1].change
= 0;
473 /* free memory in current copy first */
474 if (info
->sinfo
[0].addr
)
475 free(info
->sinfo
[0].addr
);
476 info
->sinfo
[0].addr
= NULL
;
478 if (info
->sinfo
[0].hostname
)
479 free(info
->sinfo
[0].hostname
);
480 info
->sinfo
[0].hostname
= NULL
;
482 if (info
->sinfo
[0].rootDSE_data
)
483 free(info
->sinfo
[0].rootDSE_data
);
484 info
->sinfo
[0].rootDSE_data
= NULL
;
486 if (info
->sinfo
[0].errormsg
)
487 free(info
->sinfo
[0].errormsg
);
488 info
->sinfo
[0].errormsg
= NULL
;
491 * make current and update copy identical
493 info
->sinfo
[0] = info
->sinfo
[1];
496 * getldap_get_server_stat() reads the update copy sinfo[1]
497 * so it can't be freed or nullified yet at this point.
499 * The sinfo[0] and sinfo[1] have identical string pointers.
500 * strdup the strings to avoid the double free problem.
501 * The strings of sinfo[1] are freed in
502 * getldap_get_rootDSE() and the strings of sinfo[0]
503 * are freed earlier in this function. If the pointers are the
504 * same, they will be freed twice.
506 if (info
->sinfo
[1].addr
)
507 info
->sinfo
[0].addr
= strdup(info
->sinfo
[1].addr
);
508 if (info
->sinfo
[1].hostname
)
509 info
->sinfo
[0].hostname
= strdup(info
->sinfo
[1].hostname
);
510 if (info
->sinfo
[1].rootDSE_data
)
511 info
->sinfo
[0].rootDSE_data
=
512 strdup(info
->sinfo
[1].rootDSE_data
);
513 if (info
->sinfo
[1].errormsg
)
514 info
->sinfo
[0].errormsg
= strdup(info
->sinfo
[1].errormsg
);
516 (void) mutex_unlock(&info
->mutex
[0]);
517 (void) mutex_unlock(&info
->mutex
[1]);
522 getldap_get_rootDSE(void *arg
)
524 server_info_t
*serverInfo
= (server_info_t
*)arg
;
526 int exitrc
= NS_LDAP_SUCCESS
;
528 int server_found
= 0;
529 char errmsg
[MAXERROR
];
530 ns_ldap_return_code rc
;
531 ns_ldap_error_t
*error
= NULL
;
533 if (current_admin
.debug_level
>= DBG_ALL
) {
534 logit("getldap_get_rootDSE()....\n");
537 /* initialize the server info element */
538 (void) mutex_lock(&serverInfo
->mutex
[1]);
539 serverInfo
->sinfo
[1].type
= INFO_RW_UNKNOWN
;
540 serverInfo
->sinfo
[1].info_status
=
543 * When the sever list is refreshed over and over,
544 * this function is called each time it is refreshed.
545 * The previous server status of the update copy(sinfo[1])
546 * is the status of the current copy
548 (void) mutex_lock(&serverInfo
->mutex
[0]);
549 serverInfo
->sinfo
[1].prev_server_status
=
550 serverInfo
->sinfo
[0].server_status
;
551 (void) mutex_unlock(&serverInfo
->mutex
[0]);
553 serverInfo
->sinfo
[1].server_status
=
555 if (serverInfo
->sinfo
[1].rootDSE_data
)
556 free(serverInfo
->sinfo
[1].rootDSE_data
);
557 serverInfo
->sinfo
[1].rootDSE_data
= NULL
;
558 if (serverInfo
->sinfo
[1].errormsg
)
559 free(serverInfo
->sinfo
[1].errormsg
);
560 serverInfo
->sinfo
[1].errormsg
= NULL
;
561 (void) mutex_unlock(&serverInfo
->mutex
[1]);
563 (void) mutex_lock(&serverInfo
->mutex
[1]);
564 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_CONNECTING
;
565 (void) mutex_unlock(&serverInfo
->mutex
[1]);
568 * WARNING: anon_fallback == 1 (last argument) means that when
569 * __ns_ldap_getRootDSE is unable to bind using the configured
570 * credentials, it will try to fall back to using anonymous, non-SSL
573 * This is for backward compatibility reasons - we might have machines
574 * in the field with broken configuration (invalid credentials) and we
575 * don't want them to be disturbed.
577 if (rc
= __ns_ldap_getRootDSE(serverInfo
->sinfo
[1].addr
,
580 SA_ALLOW_FALLBACK
) != NS_LDAP_SUCCESS
) {
581 (void) mutex_lock(&serverInfo
->mutex
[1]);
582 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_ERROR
;
583 serverInfo
->sinfo
[1].info_status
= INFO_STATUS_ERROR
;
584 if (error
&& error
->message
) {
585 serverInfo
->sinfo
[1].errormsg
= strdup(error
->message
);
587 (void) snprintf(errmsg
, sizeof (errmsg
), "%s %s "
588 "(rc = %d)", gettext("Can not get the root DSE from"
589 " server"), serverInfo
->sinfo
[1].addr
, rc
);
590 serverInfo
->sinfo
[1].errormsg
= strdup(errmsg
);
594 (void) __ns_ldap_freeError(&error
);
597 if (current_admin
.debug_level
>= DBG_ALL
) {
598 logit("getldap_get_rootDSE: %s.\n",
599 serverInfo
->sinfo
[1].errormsg
);
601 (void) mutex_unlock(&serverInfo
->mutex
[1]);
603 * sync sinfo copies in the serverInfo.
606 sync_current_with_update_copy(serverInfo
);
607 thr_exit((void *) -1);
610 (void) mutex_lock(&serverInfo
->mutex
[1]);
612 /* assume writeable, i.e., can do modify */
613 serverInfo
->sinfo
[1].type
= INFO_RW_WRITEABLE
;
614 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_UP
;
615 serverInfo
->sinfo
[1].info_status
= INFO_STATUS_NEW
;
616 /* remove the last DOORLINESEP */
617 *(rootDSE
+strlen(rootDSE
)-1) = '\0';
618 serverInfo
->sinfo
[1].rootDSE_data
= rootDSE
;
622 (void) mutex_unlock(&serverInfo
->mutex
[1]);
625 * sync sinfo copies in the serverInfo.
628 sync_current_with_update_copy(serverInfo
);
630 * signal that the ldap_cachemgr parent process
631 * should exit now, if it is still waiting
633 (void) mutex_lock(&sig_mutex
);
634 if (signal_done
== FALSE
&& server_found
) {
636 (void) kill(ppid
, SIGUSR1
);
637 if (current_admin
.debug_level
>= DBG_ALL
) {
638 logit("getldap_get_rootDSE(): "
639 "SIGUSR1 signal sent to "
640 "parent process(%ld).\n", ppid
);
644 (void) mutex_unlock(&sig_mutex
);
646 thr_exit((void *) exitrc
);
648 return ((void *) NULL
);
652 getldap_init_serverInfo(server_info_t
**head
)
654 char **servers
= NULL
;
655 int rc
= 0, i
, exitrc
= NS_LDAP_SUCCESS
;
656 ns_ldap_error_t
*errorp
= NULL
;
657 server_info_t
*info
, *tail
= NULL
;
660 if (current_admin
.debug_level
>= DBG_ALL
) {
661 logit("getldap_init_serverInfo()...\n");
663 rc
= __s_api_getServers(&servers
, &errorp
);
665 if (rc
!= NS_LDAP_SUCCESS
) {
666 logit("getldap_init_serverInfo: "
667 "__s_api_getServers failed.\n");
669 __ns_ldap_freeError(&errorp
);
672 for (i
= 0; servers
[i
] != NULL
; i
++) {
673 info
= (server_info_t
*)calloc(1, sizeof (server_info_t
));
675 logit("getldap_init_serverInfo: "
676 "not enough memory.\n");
677 exitrc
= NS_LDAP_MEMORY
;
688 info
->sinfo
[0].addr
= strdup(servers
[i
]);
689 if (info
->sinfo
[0].addr
== NULL
) {
690 logit("getldap_init_serverInfo: "
691 "not enough memory.\n");
692 exitrc
= NS_LDAP_MEMORY
;
695 info
->sinfo
[1].addr
= strdup(servers
[i
]);
696 if (info
->sinfo
[1].addr
== NULL
) {
697 logit("getldap_init_serverInfo: "
698 "not enough memory.\n");
699 exitrc
= NS_LDAP_MEMORY
;
703 info
->sinfo
[0].type
= INFO_RW_UNKNOWN
;
704 info
->sinfo
[1].type
= INFO_RW_UNKNOWN
;
705 info
->sinfo
[0].info_status
= INFO_STATUS_UNKNOWN
;
706 info
->sinfo
[1].info_status
= INFO_STATUS_UNKNOWN
;
707 info
->sinfo
[0].server_status
= INFO_SERVER_UNKNOWN
;
708 info
->sinfo
[1].server_status
= INFO_SERVER_UNKNOWN
;
711 * Assume at startup or after the configuration
712 * profile is refreshed, all servers are good.
714 info
->sinfo
[0].prev_server_status
=
716 info
->sinfo
[1].prev_server_status
=
718 info
->sinfo
[0].hostname
= NULL
;
719 info
->sinfo
[1].hostname
= NULL
;
720 info
->sinfo
[0].rootDSE_data
= NULL
;
721 info
->sinfo
[1].rootDSE_data
= NULL
;
722 info
->sinfo
[0].errormsg
= NULL
;
723 info
->sinfo
[1].errormsg
= NULL
;
726 __s_api_free2dArray(servers
);
727 if (exitrc
!= NS_LDAP_SUCCESS
) {
729 (void) getldap_destroy_serverInfo(*head
);
737 getldap_destroy_serverInfo(server_info_t
*head
)
739 server_info_t
*info
, *next
;
741 if (current_admin
.debug_level
>= DBG_ALL
) {
742 logit("getldap_destroy_serverInfo()...\n");
746 logit("getldap_destroy_serverInfo: "
747 "invalid serverInfo list.\n");
751 for (info
= head
; info
; info
= next
) {
752 if (info
->sinfo
[0].addr
)
753 free(info
->sinfo
[0].addr
);
754 if (info
->sinfo
[1].addr
)
755 free(info
->sinfo
[1].addr
);
756 if (info
->sinfo
[0].hostname
)
757 free(info
->sinfo
[0].hostname
);
758 if (info
->sinfo
[1].hostname
)
759 free(info
->sinfo
[1].hostname
);
760 if (info
->sinfo
[0].rootDSE_data
)
761 free(info
->sinfo
[0].rootDSE_data
);
762 if (info
->sinfo
[1].rootDSE_data
)
763 free(info
->sinfo
[1].rootDSE_data
);
764 if (info
->sinfo
[0].errormsg
)
765 free(info
->sinfo
[0].errormsg
);
766 if (info
->sinfo
[1].errormsg
)
767 free(info
->sinfo
[1].errormsg
);
771 return (NS_LDAP_SUCCESS
);
775 getldap_set_serverInfo(server_info_t
*head
, int reset_bindtime
, info_op_t op
)
780 int num_threads
= 0, i
, j
;
782 void **paramVal
= NULL
;
783 ns_ldap_error_t
*error
= NULL
;
785 if (current_admin
.debug_level
>= DBG_ALL
) {
786 logit("getldap_set_serverInfo()...\n");
790 logit("getldap_set_serverInfo: "
791 "invalid serverInfo list.\n");
795 /* Get the bind timeout value */
796 if (reset_bindtime
== 1) {
797 tcptimeout
= NS_DEFAULT_BIND_TIMEOUT
* 1000;
798 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P
,
800 if (paramVal
!= NULL
&& *paramVal
!= NULL
) {
801 /* convert to milliseconds */
802 tcptimeout
= **((int **)paramVal
);
804 (void) __ns_ldap_freeParam(¶mVal
);
807 (void) __ns_ldap_freeError(&error
);
810 for (info
= head
; info
; info
= info
->next
)
813 if (num_threads
== 0) {
814 logit("getldap_set_serverInfo: "
815 "empty serverInfo list.\n");
819 tid
= (thread_t
*) calloc(1, sizeof (thread_t
) * num_threads
);
821 logit("getldap_set_serverInfo: "
822 "No memory to create thread ID list.\n");
826 for (info
= head
, i
= 0; info
; info
= info
->next
, i
++) {
827 if (thr_create(NULL
, 0,
828 (void *(*)(void*))getldap_get_rootDSE
,
829 (void *)info
, 0, &tid
[i
])) {
830 logit("getldap_set_serverInfo: "
831 "can not create thread %d.\n", i
+ 1);
832 for (j
= 0; j
< i
; j
++)
833 (void) thr_join(tid
[j
], NULL
, NULL
);
839 for (i
= 0; i
< num_threads
; i
++) {
840 if (thr_join(tid
[i
], NULL
, &status
) == 0) {
841 if ((int)status
== NS_LDAP_SUCCESS
)
848 if (op
== INFO_OP_REFRESH
)
849 test_server_change(head
);
851 return (NS_LDAP_SUCCESS
);
857 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
858 * to this function from getldap_serverInfo_op().
860 * a buffer containing an empty string (e.g., input[0]='\0';) or a string
861 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
863 * where addr is the address of a server and
864 * req is one of the following:
865 * NS_CACHE_NEW: send a new server address, addr is ignored.
866 * NS_CACHE_NORESP: send the next one, remove addr from list.
867 * NS_CACHE_NEXT: send the next one, keep addr on list.
868 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same
871 * NS_CACHE_ADDR_IP: return server address as is, this is default.
872 * NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
873 * only self credential case requires such format.
875 * a buffer containing server info in the following format:
876 * serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
877 * [ attr=value [DOORLINESEP attr=value ]...]
878 * For example: ( here | used as DOORLINESEP for visual purposes)
879 * 1) simple bind and sasl/DIGEST-MD5 bind :
880 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
881 * supportedSASLmechanisms=GSSAPI
882 * 2) sasl/GSSAPI bind (self credential):
883 * 1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
884 * supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
885 * NOTE: caller should free this buffer when done using it
888 getldap_get_serverInfo(server_info_t
*head
, char *input
,
889 char **output
, int *svr_removed
)
891 server_info_t
*info
= NULL
;
892 server_info_t
*server
= NULL
;
895 char req_new
[] = NS_CACHE_NEW
;
896 char addr_type
[] = NS_CACHE_ADDR_IP
;
897 int matched
= FALSE
, len
= 0, rc
= 0;
898 char *ret_addr
= NULL
, *ret_addrFQDN
= NULL
;
899 char *new_addr
= NULL
;
902 if (current_admin
.debug_level
>= DBG_ALL
) {
903 logit("getldap_get_serverInfo()...\n");
906 if (input
== NULL
|| output
== NULL
) {
907 logit("getldap_get_serverInfo: "
908 "No input or output buffer.\n");
913 *svr_removed
= FALSE
;
916 logit("getldap_get_serverInfo: "
917 "invalid serverInfo list.\n");
921 * parse the input string to get req and addr,
922 * if input is empty, i.e., input[0] == '\0',
923 * treat it as an NS_CACHE_NEW request
926 if (input
[0] != '\0') {
928 /* Save addr type flag */
929 addr_type
[0] = input
[1];
930 input
[strlen(NS_CACHE_NEW
)] = '\0';
931 /* skip acion type flag, addr type flag and DOORLINESEP */
932 addr
= input
+ strlen(DOORLINESEP
) + strlen(NS_CACHE_NEW
)
933 + strlen(NS_CACHE_ADDR_IP
);
937 * or the server info is new,
939 * beginning of the list
941 if ((strcmp(req
, NS_CACHE_NEW
) == 0) ||
942 (head
->sinfo
[0].info_status
== INFO_STATUS_NEW
))
944 for (info
= head
; info
; info
= info
->next
) {
946 * make sure the server info stays the same
947 * while the data is being processed
951 * This function is called to get server info list
952 * and pass it back to door call clients.
953 * Access the current copy (sinfo[0]) to get such
956 (void) mutex_lock(&info
->mutex
[0]);
958 if (matched
== FALSE
&&
959 strcmp(info
->sinfo
[0].addr
, addr
) == 0) {
961 if (strcmp(req
, NS_CACHE_NORESP
) == 0) {
962 if (chg_is_called_from_nscd_or_peruser_nscd(
963 "REMOVE SERVER", &pid
) == 0) {
964 (void) mutex_unlock(&info
->mutex
[0]);
965 if (current_admin
.debug_level
>=
967 logit("Only nscd can remove "
968 "servers. pid %ld", pid
);
973 * if the information is new,
974 * give this server one more chance
976 if (info
->sinfo
[0].info_status
==
978 info
->sinfo
[0].server_status
==
984 * it is recommended that
985 * before removing the
986 * server from the list,
987 * the server should be
988 * contacted one more time
989 * to make sure that it is
990 * really unavailable.
991 * For now, just trust the client
992 * (i.e., the sldap library)
993 * that it knows what it is
994 * doing and would not try
995 * to mess up the server
999 * Make a copy of addr to contact
1000 * it later. It's not doing it here
1001 * to avoid long wait and possible
1002 * recursion to contact an LDAP server.
1004 new_addr
= strdup(info
->sinfo
[0].addr
);
1006 remove_server(new_addr
);
1007 *svr_removed
= TRUE
;
1008 (void) mutex_unlock(&info
->mutex
[0]);
1013 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
1015 (void) mutex_unlock(&info
->mutex
[0]);
1021 if (strcmp(req
, NS_CACHE_WRITE
) == 0) {
1022 if (info
->sinfo
[0].type
==
1023 INFO_RW_WRITEABLE
&&
1024 info
->sinfo
[0].server_status
==
1029 } else if (info
->sinfo
[0].server_status
==
1036 (void) mutex_unlock(&info
->mutex
[0]);
1040 if (strcmp(addr_type
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
1042 * In SASL/GSSAPI case, a hostname is required for
1043 * Kerberos's service principal.
1045 * ldap/foo.sun.com@SUN.COM
1047 if (server
->sinfo
[0].hostname
== NULL
) {
1048 rc
= __s_api_ip2hostname(server
->sinfo
[0].addr
,
1049 &server
->sinfo
[0].hostname
);
1050 if (rc
!= NS_LDAP_SUCCESS
) {
1051 (void) mutex_unlock(&info
->mutex
[0]);
1054 if (current_admin
.debug_level
>= DBG_ALL
) {
1055 logit("getldap_get_serverInfo: "
1056 "%s is converted to %s\n",
1057 server
->sinfo
[0].addr
,
1058 server
->sinfo
[0].hostname
);
1061 ret_addr
= server
->sinfo
[0].addr
;
1062 ret_addrFQDN
= server
->sinfo
[0].hostname
;
1065 ret_addr
= server
->sinfo
[0].addr
;
1068 len
= strlen(ret_addr
) +
1069 strlen(server
->sinfo
[0].rootDSE_data
) +
1070 strlen(DOORLINESEP
) + 1;
1071 if (ret_addrFQDN
!= NULL
)
1072 len
+= strlen(ret_addrFQDN
) + strlen(DOORLINESEP
);
1073 *output
= (char *)malloc(len
);
1074 if (*output
== NULL
) {
1075 (void) mutex_unlock(&info
->mutex
[0]);
1076 return (NS_LDAP_MEMORY
);
1078 if (ret_addrFQDN
== NULL
)
1079 (void) snprintf(*output
, len
, "%s%s%s",
1080 ret_addr
, DOORLINESEP
,
1081 server
->sinfo
[0].rootDSE_data
);
1083 (void) snprintf(*output
, len
, "%s%s%s%s%s",
1084 ret_addr
, DOORLINESEP
,
1085 ret_addrFQDN
, DOORLINESEP
,
1086 server
->sinfo
[0].rootDSE_data
);
1087 server
->sinfo
[0].info_status
= INFO_STATUS_OLD
;
1088 (void) mutex_unlock(&info
->mutex
[0]);
1089 return (NS_LDAP_SUCCESS
);
1096 * Format previous and next refresh time
1099 getldap_format_refresh_time(char **output
, time_t *prev
, time_t *next
)
1101 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S"
1102 #define TIME_HEADER1 " Previous refresh time: "
1103 #define TIME_HEADER2 " Next refresh time: "
1104 int hdr1_len
= strlen(gettext(TIME_HEADER1
));
1105 int hdr2_len
= strlen(gettext(TIME_HEADER2
));
1111 if (current_admin
.debug_level
>= DBG_ALL
) {
1112 logit("getldap_format_refresh_time()...\n");
1117 /* format the time of previous refresh */
1119 (void) localtime_r(prev
, &tm
);
1120 (void) strftime(pbuf
, sizeof (pbuf
) - 1, TIME_FORMAT
, &tm
);
1122 (void) strcpy(pbuf
, gettext("NOT DONE"));
1125 /* format the time of next refresh */
1127 (void) localtime_r(next
, &tm
);
1128 (void) strftime(nbuf
, sizeof (nbuf
) - 1, TIME_FORMAT
, &tm
);
1130 (void) strcpy(nbuf
, gettext("NOT SET"));
1133 len
= hdr1_len
+ hdr2_len
+ strlen(nbuf
) +
1134 strlen(pbuf
) + 2 * strlen(DOORLINESEP
) + 1;
1136 *output
= malloc(len
);
1137 if (*output
== NULL
)
1140 (void) snprintf(*output
, len
, "%s%s%s%s%s%s",
1141 gettext(TIME_HEADER1
), pbuf
, DOORLINESEP
,
1142 gettext(TIME_HEADER2
), nbuf
, DOORLINESEP
);
1144 return (NS_LDAP_SUCCESS
);
1148 * getldap_get_server_stat processes the GETSTAT request passed
1149 * to this function from getldap_serverInfo_op().
1151 * a buffer containing info for all the servers.
1152 * For each server, the data is in the following format:
1153 * server: server address or name, status: unknown|up|down|removed DOORLINESEP
1154 * for example: ( here | used as DOORLINESEP for visual purposes)
1155 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1156 * NOTE: caller should free this buffer when done using it
1159 getldap_get_server_stat(server_info_t
*head
, char **output
,
1160 time_t *prev
, time_t *next
)
1162 #define S_HEADER "Server information: "
1163 #define S_FORMAT " server: %s, status: %s%s"
1164 #define S_ERROR " error message: %s%s"
1165 server_info_t
*info
= NULL
;
1166 int header_len
= strlen(gettext(S_HEADER
));
1167 int format_len
= strlen(gettext(S_FORMAT
));
1168 int error_len
= strlen(gettext(S_ERROR
));
1169 int len
= header_len
+ strlen(DOORLINESEP
);
1171 char *status
, *output1
= NULL
, *tmpptr
;
1175 if (current_admin
.debug_level
>= DBG_ALL
) {
1176 logit("getldap_get_server_stat()...\n");
1180 logit("getldap_get_server_stat: "
1181 "invalid serverInfo list.\n");
1185 /* format previous and next refresh time */
1186 (void) getldap_format_refresh_time(&output1
, prev
, next
);
1187 if (output1
== NULL
)
1189 len
+= strlen(output1
);
1190 len1
= len
+ strlen(DOORLINESEP
) + 1;
1192 *output
= (char *)calloc(1, len1
);
1193 if (*output
== NULL
) {
1198 /* insert header string and refresh time info */
1199 (void) snprintf(*output
, len1
, "%s%s%s",
1200 gettext(S_HEADER
), DOORLINESEP
, output1
);
1202 for (info
= head
; info
; info
= info
->next
) {
1205 * make sure the server info stays the same
1206 * while the data is being processed
1208 (void) mutex_lock(&info
->mutex
[1]);
1211 * When the updating process is under way(getldap_get_rootDSE)
1212 * the update copy(sinfo[1] is the latest copy.
1213 * When the updating process
1214 * is done, the current copy (sinfo[0]) has the latest status,
1215 * which is still identical to the update copy.
1216 * So update copy has the latest status.
1217 * Use the update copy(sinfo[1]) to show status
1218 * (ldap_cachemgr -g).
1222 switch (info
->sinfo
[1].server_status
) {
1223 case INFO_SERVER_UNKNOWN
:
1224 status
= gettext("UNKNOWN");
1226 case INFO_SERVER_CONNECTING
:
1227 status
= gettext("CONNECTING");
1229 case INFO_SERVER_UP
:
1230 status
= gettext("UP");
1232 case INFO_SERVER_ERROR
:
1233 status
= gettext("ERROR");
1235 case INFO_SERVER_REMOVED
:
1236 status
= gettext("REMOVED");
1240 len
+= format_len
+ strlen(status
) +
1241 strlen(info
->sinfo
[1].addr
) +
1242 strlen(DOORLINESEP
);
1243 if (info
->sinfo
[1].errormsg
!= NULL
)
1245 strlen(info
->sinfo
[1].errormsg
) +
1246 strlen(DOORLINESEP
);
1248 tmpptr
= (char *)realloc(*output
, len
);
1249 if (tmpptr
== NULL
) {
1253 (void) mutex_unlock(&info
->mutex
[1]);
1258 /* insert server IP addr or name and status */
1259 len1
= len
- strlen(*output
);
1260 (void) snprintf(*output
+ strlen(*output
), len1
,
1261 gettext(S_FORMAT
), info
->sinfo
[1].addr
,
1262 status
, DOORLINESEP
);
1263 /* insert error message if any */
1264 len1
= len
- strlen(*output
);
1265 if (info
->sinfo
[1].errormsg
!= NULL
)
1266 (void) snprintf(*output
+ strlen(*output
), len1
,
1268 info
->sinfo
[1].errormsg
,
1271 (void) mutex_unlock(&info
->mutex
[1]);
1276 return (NS_LDAP_SUCCESS
);
1280 * Format and return the refresh time statistics
1283 getldap_get_refresh_stat(char **output
)
1285 #define R_HEADER0 "Configuration refresh information: "
1286 #define R_HEADER1 " Configured to NO REFRESH."
1287 int hdr0_len
= strlen(gettext(R_HEADER0
));
1288 int hdr1_len
= strlen(gettext(R_HEADER1
));
1289 int cache_ttl
= -1, len
= 0;
1291 void **paramVal
= NULL
;
1292 ns_ldap_error_t
*errorp
= NULL
;
1293 char *output1
= NULL
;
1295 if (current_admin
.debug_level
>= DBG_ALL
) {
1296 logit("getldap_get_refresh_stat()...\n");
1301 /* get configured cache TTL */
1302 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P
,
1303 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
1305 (char *)*paramVal
!= NULL
) {
1306 cache_ttl
= atol((char *)*paramVal
);
1309 __ns_ldap_freeError(&errorp
);
1311 (void) __ns_ldap_freeParam(¶mVal
);
1313 /* cound not get cache TTL */
1314 if (cache_ttl
== -1)
1317 if (cache_ttl
== 0) {
1318 len
= hdr0_len
+ hdr1_len
+
1319 2 * strlen(DOORLINESEP
) + 1;
1320 *output
= malloc(len
);
1321 if (*output
== NULL
)
1323 (void) snprintf(*output
, len
, "%s%s%s%s",
1324 gettext(R_HEADER0
), DOORLINESEP
,
1325 gettext(R_HEADER1
), DOORLINESEP
);
1328 /* get configuration expiration time */
1329 if ((__ns_ldap_getParam(NS_LDAP_EXP_P
,
1330 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
1332 (char *)*paramVal
!= NULL
) {
1333 expire
= (time_t)atol((char *)*paramVal
);
1336 __ns_ldap_freeError(&errorp
);
1339 (void) __ns_ldap_freeParam(¶mVal
);
1341 /* cound not get expiration time */
1345 /* format previous and next refresh time */
1346 (void) getldap_format_refresh_time(&output1
,
1347 &prev_refresh_time
, &expire
);
1348 if (output1
== NULL
)
1351 len
= hdr0_len
+ strlen(output1
) +
1352 2 * strlen(DOORLINESEP
) + 1;
1353 *output
= malloc(len
);
1354 if (*output
== NULL
) {
1358 (void) snprintf(*output
, len
, "%s%s%s%s",
1359 gettext(R_HEADER0
), DOORLINESEP
,
1360 output1
, DOORLINESEP
);
1364 return (NS_LDAP_SUCCESS
);
1368 getldap_get_cacheTTL()
1370 void **paramVal
= NULL
;
1371 ns_ldap_error_t
*error
;
1372 int rc
= 0, cachettl
;
1375 if (current_admin
.debug_level
>= DBG_ALL
) {
1376 logit("getldap_get_cacheTTL()....\n");
1379 if ((rc
= __ns_ldap_getParam(NS_LDAP_CACHETTL_P
,
1380 ¶mVal
, &error
)) != NS_LDAP_SUCCESS
) {
1381 if (error
!= NULL
&& error
->message
!= NULL
)
1382 logit("Error: Unable to get configuration "
1383 "refresh TTL: %s\n",
1388 __ns_ldap_err2str(rc
, &tmp
);
1389 logit("Error: Unable to get configuration "
1390 "refresh TTL: %s\n", tmp
);
1392 (void) __ns_ldap_freeParam(¶mVal
);
1393 (void) __ns_ldap_freeError(&error
);
1396 if (paramVal
== NULL
|| (char *)*paramVal
== NULL
)
1398 cachettl
= atol((char *)*paramVal
);
1399 (void) __ns_ldap_freeParam(¶mVal
);
1405 * This function implements the adaptive server list refresh
1406 * algorithm used by ldap_cachemgr. The idea is to have the
1407 * refresh TTL adjust itself between maximum and minimum
1408 * values. If the server list has been walked three times
1409 * in a row without errors, the TTL will be doubled. This will
1410 * be done repeatedly until the maximum value is reached
1411 * or passed. If passed, the maximum value will be used.
1412 * If any time a server is found to be down/bad, either
1413 * after another server list walk or informed by libsldap via
1414 * the GETLDAPSERVER door calls, the TTL will be set to half
1415 * of its value, again repeatedly, but no less than the minimum
1416 * value. Also, at any time, if all the servers on the list
1417 * are found to be down/bad, the TTL will be set to minimum,
1418 * so that a "no-server" refresh loop should be entered to try
1419 * to find a good server as soon as possible. The caller
1420 * could check the no_gd_server flag for this situation.
1421 * The maximum and minimum values are initialized when the input
1422 * refresh_ttl is set to zero, this should occur during
1423 * ldap_cachemgr startup or every time the server list is
1424 * recreated after the configuration profile is refreshed
1425 * from an LDAP server. The maximum is set to the value of
1426 * the NS_LDAP_CACHETTL parameter (configuration profile
1427 * refresh TTL), but if it is zero (never refreshed) or can
1428 * not be retrieved, the maximum is set to the macro
1429 * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1430 * set to REFRESHTTL_MIN, which is the TCP connection timeout
1431 * (tcptimeout) set via the LDAP API ldap_set_option()
1432 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1433 * This accounts for the maximum possible timeout value for an
1434 * LDAP TCP connect call.The first refresh TTL, initial value of
1435 * refresh_ttl, will be set to the smaller of the two,
1436 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1437 * The idea is to have a low starting value and have the value
1438 * stay low if the network/server is unstable, but eventually
1439 * the value will move up to maximum and stay there if the
1440 * network/server is stable.
1443 getldap_set_refresh_ttl(server_info_t
*head
, int *refresh_ttl
,
1446 #define REFRESHTTL_REGULAR 600
1447 #define REFRESHTTL_MAX 43200
1448 /* tcptimeout is in milliseconds */
1449 #define REFRESHTTL_MIN (tcptimeout/1000) + 10
1450 #define UP_REFRESH_TTL_NUM 2
1452 static mutex_t refresh_mutex
;
1453 static int refresh_ttl_max
= 0;
1454 static int refresh_ttl_min
= 0;
1455 static int num_walked_ok
= 0;
1456 int num_servers
= 0;
1457 int num_good_servers
= 0;
1458 int num_prev_good_servers
= 0;
1459 server_info_t
*info
;
1461 /* allow one thread at a time */
1462 (void) mutex_lock(&refresh_mutex
);
1464 if (current_admin
.debug_level
>= DBG_ALL
) {
1465 logit("getldap_set_refresh_ttl()...\n");
1468 if (!head
|| !refresh_ttl
|| !no_gd_server
) {
1469 logit("getldap_set_refresh_ttl: head is "
1470 "NULL or refresh_ttl is NULL or "
1471 "no_gd_server is NULL");
1472 (void) mutex_unlock(&refresh_mutex
);
1475 *no_gd_server
= FALSE
;
1478 * init max. min. TTLs if first time through or a fresh one
1480 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1481 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1482 "seconds\n", *refresh_ttl
);
1484 if (*refresh_ttl
== 0) {
1487 * init cache manager server list TTL:
1489 * init the min. TTL to
1490 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1492 refresh_ttl_min
= REFRESHTTL_MIN
;
1495 * try to set the max. TTL to
1496 * configuration refresh TTL (NS_LDAP_CACHETTL),
1497 * if error (-1), or never refreshed (0),
1498 * set it to REFRESHTTL_MAX (12 hours)
1500 refresh_ttl_max
= getldap_get_cacheTTL();
1501 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1502 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1503 "seconds\n", *refresh_ttl
);
1504 logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1505 "min ttl is %d seconds\n",
1506 refresh_ttl_max
, refresh_ttl_min
);
1508 if (refresh_ttl_max
<= 0)
1509 refresh_ttl_max
= REFRESHTTL_MAX
;
1510 else if (refresh_ttl_max
< refresh_ttl_min
)
1511 refresh_ttl_max
= refresh_ttl_min
;
1514 * init the first TTL to the smaller of the two:
1515 * REFRESHTTL_REGULAR ( 10 minutes),
1516 * (refresh_ttl_max + refresh_ttl_min)/2
1518 *refresh_ttl
= REFRESHTTL_REGULAR
;
1519 if (*refresh_ttl
> (refresh_ttl_max
+ refresh_ttl_min
) / 2)
1520 *refresh_ttl
= (refresh_ttl_max
+ refresh_ttl_min
) / 2;
1521 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1522 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1523 "seconds\n", *refresh_ttl
);
1524 logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1525 "min ttl is %d seconds\n",
1526 refresh_ttl_max
, refresh_ttl_min
);
1531 * get the servers statistics:
1532 * number of servers on list
1533 * number of good servers on list
1534 * number of pevious good servers on list
1536 for (info
= head
; info
; info
= info
->next
) {
1538 (void) mutex_lock(&info
->mutex
[0]);
1539 if (info
->sinfo
[0].server_status
== INFO_SERVER_UP
)
1542 * Server's previous status could be UNKNOWN
1543 * only between the very first and second
1544 * refresh. Treat that UNKNOWN status as up
1546 if (info
->sinfo
[0].prev_server_status
1547 == INFO_SERVER_UP
||
1548 info
->sinfo
[0].prev_server_status
1549 == INFO_SERVER_UNKNOWN
)
1550 num_prev_good_servers
++;
1551 (void) mutex_unlock(&info
->mutex
[0]);
1555 * if the server list is walked three times in a row
1556 * without problems, double the refresh TTL but no more
1557 * than the max. refresh TTL
1559 if (num_good_servers
== num_servers
) {
1561 if (num_walked_ok
> UP_REFRESH_TTL_NUM
) {
1563 *refresh_ttl
= *refresh_ttl
* 2;
1564 if (*refresh_ttl
> refresh_ttl_max
)
1565 *refresh_ttl
= refresh_ttl_max
;
1569 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1570 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1571 "seconds\n", *refresh_ttl
);
1573 } else if (num_good_servers
== 0) {
1575 * if no good server found,
1576 * set refresh TTL to miminum
1578 *refresh_ttl
= refresh_ttl_min
;
1579 *no_gd_server
= TRUE
;
1581 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1582 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1583 "seconds\n", *refresh_ttl
);
1585 } else if (num_prev_good_servers
> num_good_servers
) {
1587 * if more down/bad servers found,
1588 * decrease the refresh TTL by half
1589 * but no less than the min. refresh TTL
1591 *refresh_ttl
= *refresh_ttl
/ 2;
1592 if (*refresh_ttl
< refresh_ttl_min
)
1593 *refresh_ttl
= refresh_ttl_min
;
1595 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1596 "seconds\n", *refresh_ttl
);
1600 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1601 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1604 (void) mutex_unlock(&refresh_mutex
);
1609 getldap_serverInfo_op(info_op_t op
, char *input
, char **output
)
1612 static rwlock_t info_lock
= DEFAULTRWLOCK
;
1613 static rwlock_t info_lock_old
= DEFAULTRWLOCK
;
1614 static mutex_t info_mutex
;
1615 static cond_t info_cond
;
1616 static int creating
= FALSE
;
1617 static int refresh_ttl
= 0;
1618 static int sec_to_refresh
= 0;
1619 static int in_no_server_mode
= FALSE
;
1621 static server_info_t
*serverInfo
= NULL
;
1622 static server_info_t
*serverInfo_old
= NULL
;
1623 server_info_t
*serverInfo_1
;
1625 int err
, no_server_good
= FALSE
;
1626 int server_removed
= FALSE
;
1627 int fall_thru
= FALSE
;
1628 static struct timespec timeout
;
1629 struct timespec new_timeout
;
1631 static time_t prev_refresh
= 0, next_refresh
= 0;
1632 ns_server_status_t changed
= 0;
1634 if (current_admin
.debug_level
>= DBG_ALL
) {
1635 logit("getldap_serverInfo_op()...\n");
1638 case INFO_OP_CREATE
:
1639 if (current_admin
.debug_level
>= DBG_ALL
) {
1640 logit("operation is INFO_OP_CREATE...\n");
1644 * indicate that the server info is being
1645 * (re)created, so that the refresh thread
1646 * will not refresh the info list right
1647 * after the list got (re)created
1649 (void) mutex_lock(&info_mutex
);
1650 is_creating
= creating
;
1652 (void) mutex_unlock(&info_mutex
);
1657 * create an empty info list
1659 (void) getldap_init_serverInfo(&serverInfo_1
);
1661 * exit if list not created
1663 if (serverInfo_1
== NULL
) {
1664 (void) mutex_lock(&info_mutex
);
1666 (void) mutex_unlock(&info_mutex
);
1670 * make the new server info available:
1671 * use writer lock here, so that the switch
1672 * is done after all the reader locks have
1675 (void) rw_wrlock(&info_lock
);
1676 serverInfo
= serverInfo_1
;
1678 * if this is the first time
1679 * the server list is being created,
1680 * (i.e., serverInfo_old is NULL)
1681 * make the old list same as the new
1682 * so the GETSERVER code can do its work
1684 if (serverInfo_old
== NULL
)
1685 serverInfo_old
= serverInfo_1
;
1686 (void) rw_unlock(&info_lock
);
1689 * fill the new info list
1691 (void) rw_rdlock(&info_lock
);
1692 /* reset bind time (tcptimeout) */
1693 (void) getldap_set_serverInfo(serverInfo
, 1, INFO_OP_CREATE
);
1695 (void) mutex_lock(&info_mutex
);
1697 * set cache manager server list TTL,
1698 * set refresh_ttl to zero to indicate a fresh one
1701 (void) getldap_set_refresh_ttl(serverInfo
,
1702 &refresh_ttl
, &no_server_good
);
1703 sec_to_refresh
= refresh_ttl
;
1705 /* statistics: previous refresh time */
1706 if (gettimeofday(&tp
, NULL
) == 0)
1707 prev_refresh
= tp
.tv_sec
;
1712 * if no server found or available,
1713 * tell the server info refresh thread
1714 * to start the "no-server" refresh loop
1715 * otherwise reset the in_no_server_mode flag
1717 if (no_server_good
) {
1719 in_no_server_mode
= TRUE
;
1721 in_no_server_mode
= FALSE
;
1723 * awake the sleeping refresh thread
1725 (void) cond_signal(&info_cond
);
1727 (void) mutex_unlock(&info_mutex
);
1728 (void) rw_unlock(&info_lock
);
1731 * delete the old server info
1733 (void) rw_wrlock(&info_lock_old
);
1734 if (serverInfo_old
!= serverInfo
)
1735 (void) getldap_destroy_serverInfo(serverInfo_old
);
1737 * serverInfo_old needs to be the same as
1739 * it will be used by GETSERVER processing.
1741 serverInfo_old
= serverInfo
;
1742 (void) rw_unlock(&info_lock_old
);
1744 case INFO_OP_DELETE
:
1745 if (current_admin
.debug_level
>= DBG_ALL
) {
1746 logit("operation is INFO_OP_DELETE...\n");
1749 * use writer lock here, so that the delete would
1750 * not start until all the reader locks have
1753 (void) rw_wrlock(&info_lock
);
1755 (void) getldap_destroy_serverInfo(serverInfo
);
1757 (void) rw_unlock(&info_lock
);
1759 case INFO_OP_REFRESH
:
1760 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1761 logit("operation is INFO_OP_REFRESH...\n");
1764 * if server info is currently being
1765 * (re)created, do nothing
1767 (void) mutex_lock(&info_mutex
);
1768 is_creating
= creating
;
1769 (void) mutex_unlock(&info_mutex
);
1773 (void) rw_rdlock(&info_lock
);
1775 /* do not reset bind time (tcptimeout) */
1776 (void) getldap_set_serverInfo(serverInfo
, 0,
1779 (void) mutex_lock(&info_mutex
);
1781 /* statistics: previous refresh time */
1782 if (gettimeofday(&tp
, NULL
) == 0)
1783 prev_refresh
= tp
.tv_sec
;
1785 * set cache manager server list TTL
1787 (void) getldap_set_refresh_ttl(serverInfo
,
1788 &refresh_ttl
, &no_server_good
);
1790 * if no good server found,
1791 * tell the server info refresh thread
1792 * to start the "no-server" refresh loop
1793 * otherwise reset the in_no_server_mode flag
1795 if (no_server_good
) {
1796 in_no_server_mode
= TRUE
;
1799 in_no_server_mode
= FALSE
;
1800 sec_to_refresh
= refresh_ttl
;
1802 if (current_admin
.debug_level
>=
1803 DBG_SERVER_LIST_REFRESH
) {
1804 logit("getldap_serverInfo_op("
1806 " seconds refresh: %d second(s)....\n",
1809 (void) mutex_unlock(&info_mutex
);
1811 (void) rw_unlock(&info_lock
);
1814 case INFO_OP_REFRESH_WAIT
:
1815 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1816 logit("operation is INFO_OP_REFRESH_WAIT...\n");
1818 (void) cond_init(&info_cond
, NULL
, NULL
);
1819 (void) mutex_lock(&info_mutex
);
1821 while (err
!= ETIME
) {
1824 * if need to go into the "no-server" refresh
1825 * loop, set timout value to
1826 * REFRESH_DELAY_WHEN_NO_SERVER
1828 if (sec_to_refresh
== 0) {
1829 sec_to_refresh
= refresh_ttl
;
1830 timeout
.tv_sec
= time(NULL
) +
1831 REFRESH_DELAY_WHEN_NO_SERVER
;
1832 sleeptime
= REFRESH_DELAY_WHEN_NO_SERVER
;
1833 if (current_admin
.debug_level
>=
1834 DBG_SERVER_LIST_REFRESH
) {
1835 logit("getldap_serverInfo_op("
1836 "INFO_OP_REFRESH_WAIT):"
1837 " entering no-server "
1838 "refresh loop...\n");
1841 timeout
.tv_sec
= time(NULL
) + sec_to_refresh
;
1842 sleeptime
= sec_to_refresh
;
1844 timeout
.tv_nsec
= 0;
1846 /* statistics: next refresh time */
1847 next_refresh
= timeout
.tv_sec
;
1849 if (current_admin
.debug_level
>=
1850 DBG_SERVER_LIST_REFRESH
) {
1851 logit("getldap_serverInfo_op("
1852 "INFO_OP_REFRESH_WAIT):"
1853 " about to sleep for %d second(s)...\n",
1856 err
= cond_timedwait(&info_cond
,
1857 &info_mutex
, &timeout
);
1859 (void) cond_destroy(&info_cond
);
1860 (void) mutex_unlock(&info_mutex
);
1862 case INFO_OP_GETSERVER
:
1863 if (current_admin
.debug_level
>= DBG_ALL
) {
1864 logit("operation is INFO_OP_GETSERVER...\n");
1868 * GETSERVER processing always use
1869 * serverInfo_old to retrieve server infomation.
1870 * serverInfo_old is equal to serverInfo
1871 * most of the time, except when a new
1872 * server list is being created.
1873 * This is why the check for is_creating
1876 (void) rw_rdlock(&info_lock_old
);
1878 if (serverInfo_old
== NULL
) {
1879 (void) rw_unlock(&info_lock_old
);
1882 (void) getldap_get_serverInfo(serverInfo_old
,
1883 input
, output
, &server_removed
);
1884 (void) rw_unlock(&info_lock_old
);
1887 * Return here and let remove server thread do its job in
1888 * another thread. It executes INFO_OP_REMOVESERVER code later.
1897 case INFO_OP_REMOVESERVER
:
1899 * INFO_OP_GETSERVER and INFO_OP_REMOVESERVER share the
1900 * following code except (!fall thru) part.
1904 * if server info is currently being
1905 * (re)created, do nothing
1908 (void) mutex_lock(&info_mutex
);
1909 is_creating
= creating
;
1910 (void) mutex_unlock(&info_mutex
);
1915 if (current_admin
.debug_level
>= DBG_ALL
)
1916 logit("operation is INFO_OP_REMOVESERVER...\n");
1917 (void) rw_rdlock(&info_lock_old
);
1918 changed
= set_server_status(input
, serverInfo_old
);
1919 (void) rw_unlock(&info_lock_old
);
1921 create_buf_and_notify(input
, changed
);
1927 * set cache manager server list TTL if necessary
1929 if (*output
== NULL
|| changed
) {
1930 (void) rw_rdlock(&info_lock
);
1931 (void) mutex_lock(&info_mutex
);
1933 (void) getldap_set_refresh_ttl(serverInfo
,
1934 &refresh_ttl
, &no_server_good
);
1937 * if no good server found, need to go into
1938 * the "no-server" refresh loop
1939 * to find a server as soon as possible
1940 * otherwise reset the in_no_server_mode flag
1942 if (no_server_good
) {
1944 * if already in no-server mode,
1947 if (in_no_server_mode
== FALSE
) {
1949 in_no_server_mode
= TRUE
;
1950 (void) cond_signal(&info_cond
);
1952 (void) mutex_unlock(&info_mutex
);
1953 (void) rw_unlock(&info_lock
);
1956 in_no_server_mode
= FALSE
;
1957 sec_to_refresh
= refresh_ttl
;
1960 * if the refresh thread will be timed out
1961 * longer than refresh_ttl seconds,
1962 * wake it up to make it wait on the new
1965 new_timeout
.tv_sec
= time(NULL
) + refresh_ttl
;
1966 if (new_timeout
.tv_sec
< timeout
.tv_sec
)
1967 (void) cond_signal(&info_cond
);
1969 (void) mutex_unlock(&info_mutex
);
1970 (void) rw_unlock(&info_lock
);
1973 case INFO_OP_GETSTAT
:
1974 if (current_admin
.debug_level
>= DBG_ALL
) {
1975 logit("operation is INFO_OP_GETSTAT...\n");
1978 (void) rw_rdlock(&info_lock
);
1980 (void) getldap_get_server_stat(serverInfo
,
1981 output
, &prev_refresh
, &next_refresh
);
1983 (void) rw_unlock(&info_lock
);
1986 logit("getldap_serverInfo_op(): "
1987 "invalid operation code (%d).\n", op
);
1991 return (NS_LDAP_SUCCESS
);
1995 getldap_serverInfo_refresh()
1999 if (current_admin
.debug_level
>= DBG_ALL
) {
2000 logit("getldap_serverInfo_refresh()...\n");
2003 /* create the server info list */
2004 (void) getldap_serverInfo_op(INFO_OP_CREATE
, NULL
, NULL
);
2008 * the operation INFO_OP_REFRESH_WAIT
2009 * causes this thread to wait until
2010 * it is time to do refresh,
2011 * see getldap_serverInfo_op() for details
2013 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT
, NULL
, NULL
);
2014 (void) getldap_serverInfo_op(INFO_OP_REFRESH
, NULL
, NULL
);
2019 getldap_getserver(LineBuf
*config_info
, ldap_call_t
*in
)
2023 if (current_admin
.debug_level
>= DBG_ALL
) {
2024 logit("getldap_getserver()...\n");
2027 config_info
->len
= 0;
2029 /* make sure the request is valid */
2030 req
[0] = (in
->ldap_u
.servername
)[0];
2031 if ((req
[0] != '\0') &&
2032 (strcmp(req
, NS_CACHE_NEW
) != 0) &&
2033 (strcmp(req
, NS_CACHE_NORESP
) != 0) &&
2034 (strcmp(req
, NS_CACHE_NEXT
) != 0) &&
2035 (strcmp(req
, NS_CACHE_WRITE
) != 0)) {
2039 (void) getldap_serverInfo_op(INFO_OP_GETSERVER
,
2040 in
->ldap_u
.domainname
, &config_info
->str
);
2042 if (config_info
->str
== NULL
)
2045 config_info
->len
= strlen(config_info
->str
) + 1;
2047 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2051 ptr
= strstr(config_info
->str
, DOORLINESEP
);
2055 logit("getldap_getserver: got server %s\n",
2059 logit("getldap_getserver: Missing %s."
2060 " Internal error\n", DOORLINESEP
);
2065 getldap_get_cacheData(LineBuf
*config_info
, ldap_call_t
*in
)
2068 int datatype
= CACHE_MAP_UNKNOWN
;
2070 if (current_admin
.debug_level
>= DBG_ALL
) {
2071 logit("getldap_get_cacheData()...\n");
2074 config_info
->len
= 0;
2075 config_info
->str
= NULL
;
2077 /* make sure the request is valid */
2078 if (strncmp(in
->ldap_u
.servername
,
2079 NS_CACHE_DN2DOMAIN
, strlen(NS_CACHE_DN2DOMAIN
)) == 0)
2080 datatype
= CACHE_MAP_DN2DOMAIN
;
2082 if (datatype
== CACHE_MAP_UNKNOWN
)
2085 instr
= strstr(in
->ldap_u
.servername
, DOORLINESEP
);
2088 instr
+= strlen(DOORLINESEP
);
2092 (void) getldap_cache_op(CACHE_OP_FIND
, datatype
,
2093 instr
, &config_info
->str
);
2095 if (config_info
->str
!= NULL
) {
2096 config_info
->len
= strlen(config_info
->str
) + 1;
2101 getldap_set_cacheData(ldap_call_t
*in
)
2103 char *instr1
= NULL
;
2104 char *instr2
= NULL
;
2105 int datatype
= CACHE_MAP_UNKNOWN
;
2108 if (current_admin
.debug_level
>= DBG_ALL
) {
2109 logit("getldap_set_cacheData()...\n");
2112 /* make sure the request is valid */
2113 if (strncmp(in
->ldap_u
.servername
,
2114 NS_CACHE_DN2DOMAIN
, strlen(NS_CACHE_DN2DOMAIN
)) == 0)
2115 datatype
= CACHE_MAP_DN2DOMAIN
;
2117 if (datatype
== CACHE_MAP_UNKNOWN
)
2120 instr1
= strstr(in
->ldap_u
.servername
, DOORLINESEP
);
2124 instr1
+= strlen(DOORLINESEP
);
2125 if (*instr1
== '\0')
2127 instr2
= strstr(instr1
, DOORLINESEP
);
2131 instr2
+= strlen(DOORLINESEP
);
2132 if (*instr2
== '\0')
2135 rc
= getldap_cache_op(CACHE_OP_ADD
, datatype
,
2137 if (rc
!= NS_LDAP_SUCCESS
)
2144 getldap_get_cacheStat(LineBuf
*stat_info
)
2146 char *foutstr
= NULL
;
2147 char *soutstr
= NULL
;
2148 char *coutstr
= NULL
;
2151 if (current_admin
.debug_level
>= DBG_ALL
) {
2152 logit("getldap_get_cacheStat()...\n");
2155 stat_info
->str
= NULL
;
2158 /* get refersh statisitcs */
2159 (void) getldap_get_refresh_stat(&foutstr
);
2160 if (foutstr
== NULL
)
2163 /* get server statisitcs */
2164 (void) getldap_serverInfo_op(INFO_OP_GETSTAT
, NULL
, &soutstr
);
2165 if (soutstr
== NULL
) {
2169 /* get cache data statisitcs */
2170 (void) getldap_cache_op(CACHE_OP_GETSTAT
, NULL
, NULL
, &coutstr
);
2171 if (coutstr
== NULL
) {
2177 infoSize
= strlen(foutstr
) + strlen(soutstr
) + strlen(coutstr
) + 3;
2178 stat_info
->str
= calloc(infoSize
, sizeof (char));
2179 if (stat_info
->str
!= NULL
) {
2180 (void) strncpy(stat_info
->str
,
2182 strlen(foutstr
) + 1);
2183 (void) strncat(stat_info
->str
,
2185 strlen(soutstr
) + 1);
2186 (void) strncat(stat_info
->str
,
2188 strlen(coutstr
) + 1);
2189 stat_info
->len
= infoSize
;
2198 checkupdate(int sighup
)
2202 (void) rw_wrlock(&ldap_lock
);
2204 (void) rw_unlock(&ldap_lock
);
2206 return (value
== TRUE
);
2211 update_from_profile(int *change_status
)
2213 ns_ldap_result_t
*result
= NULL
;
2214 char searchfilter
[BUFSIZ
];
2215 ns_ldap_error_t
*error
;
2217 void **paramVal
= NULL
;
2218 ns_config_t
*ptr
= NULL
;
2219 char *profile
= NULL
;
2220 char errstr
[MAXERROR
];
2222 if (current_admin
.debug_level
>= DBG_ALL
) {
2223 logit("update_from_profile....\n");
2226 (void) rw_wrlock(&ldap_lock
);
2227 sighup_update
= FALSE
;
2228 (void) rw_unlock(&ldap_lock
);
2230 if ((rc
= __ns_ldap_getParam(NS_LDAP_PROFILE_P
,
2231 ¶mVal
, &error
)) != NS_LDAP_SUCCESS
) {
2232 if (error
!= NULL
&& error
->message
!= NULL
)
2233 logit("Error: Unable to profile name: %s\n",
2238 __ns_ldap_err2str(rc
, &tmp
);
2239 logit("Error: Unable to profile name: %s\n",
2242 (void) __ns_ldap_freeParam(¶mVal
);
2243 (void) __ns_ldap_freeError(&error
);
2247 if (paramVal
&& *paramVal
)
2248 profile
= strdup((char *)*paramVal
);
2249 (void) __ns_ldap_freeParam(¶mVal
);
2251 if (profile
== NULL
) {
2255 (void) snprintf(searchfilter
, BUFSIZ
, _PROFILE_FILTER
,
2256 _PROFILE1_OBJECTCLASS
, _PROFILE2_OBJECTCLASS
, profile
);
2258 if ((rc
= __ns_ldap_list(_PROFILE_CONTAINER
,
2259 (const char *)searchfilter
, NULL
,
2261 &result
, &error
, NULL
, NULL
)) != NS_LDAP_SUCCESS
) {
2264 * Is profile name the DEFAULTCONFIGNAME?
2265 * syslog Warning, otherwise syslog error.
2267 if (strcmp(profile
, DEFAULTCONFIGNAME
) == 0) {
2269 "Ignoring attempt to refresh nonexistent "
2270 "default profile: %s.\n",
2272 logit("Ignoring attempt to refresh nonexistent "
2273 "default profile: %s.\n",
2275 } else if ((error
!= NULL
) &&
2276 (error
->message
!= NULL
)) {
2278 "Error: Unable to refresh profile:%s:"
2279 " %s\n", profile
, error
->message
);
2280 logit("Error: Unable to refresh profile:"
2281 "%s:%s\n", profile
, error
->message
);
2283 syslog(LOG_ERR
, "Error: Unable to refresh "
2284 "from profile:%s. (error=%d)\n",
2286 logit("Error: Unable to refresh from profile "
2287 "%s (error=%d)\n", profile
, rc
);
2290 (void) __ns_ldap_freeError(&error
);
2291 (void) __ns_ldap_freeResult(&result
);
2298 } while (checkupdate(sighup_update
) == TRUE
);
2300 (void) rw_wrlock(&ldap_lock
);
2302 ptr
= __ns_ldap_make_config(result
);
2303 (void) __ns_ldap_freeResult(&result
);
2306 logit("Error: __ns_ldap_make_config failed.\n");
2307 (void) rw_unlock(&ldap_lock
);
2312 * cross check the config parameters
2314 if (__s_api_crosscheck(ptr
, errstr
, B_TRUE
) == NS_SUCCESS
) {
2316 * reset the local profile TTL
2318 if (ptr
->paramList
[NS_LDAP_CACHETTL_P
].ns_pc
)
2319 current_admin
.ldap_stat
.ldap_ttl
=
2320 atol(ptr
->paramList
[NS_LDAP_CACHETTL_P
].ns_pc
);
2322 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2323 logit("update_from_profile: reset profile TTL to %d"
2325 current_admin
.ldap_stat
.ldap_ttl
);
2326 logit("update_from_profile: expire time %ld "
2328 ptr
->paramList
[NS_LDAP_EXP_P
].ns_tm
);
2331 /* set ptr as current_config if the config is changed */
2332 chg_test_config_change(ptr
, change_status
);
2335 __s_api_destroy_config(ptr
);
2336 logit("Error: downloaded profile failed to pass "
2337 "crosscheck (%s).\n", errstr
);
2338 syslog(LOG_ERR
, "ldap_cachemgr: %s", errstr
);
2341 (void) rw_unlock(&ldap_lock
);
2349 ns_ldap_error_t
*error
;
2351 ldap_get_chg_cookie_t cookie
;
2353 if (current_admin
.debug_level
>= DBG_ALL
) {
2354 logit("getldap_init()...\n");
2357 (void) __ns_ldap_setServer(TRUE
);
2359 (void) rw_wrlock(&ldap_lock
);
2360 if ((error
= __ns_ldap_LoadConfiguration()) != NULL
) {
2361 logit("Error: Unable to read '%s': %s\n",
2362 NSCONFIGFILE
, error
->message
);
2363 (void) fprintf(stderr
,
2364 gettext("\nError: Unable to read '%s': %s\n"),
2365 NSCONFIGFILE
, error
->message
);
2366 __ns_ldap_freeError(&error
);
2367 (void) rw_unlock(&ldap_lock
);
2370 (void) rw_unlock(&ldap_lock
);
2372 if (gettimeofday(&tp
, NULL
) == 0) {
2373 /* statistics: previous refresh time */
2374 prev_refresh_time
= tp
.tv_sec
;
2377 /* initialize the data cache */
2378 (void) getldap_cache_op(CACHE_OP_CREATE
,
2381 cookie
.mgr_pid
= getpid();
2383 chg_config_cookie_set(&cookie
);
2388 perform_update(void)
2390 ns_ldap_error_t
*error
= NULL
;
2395 void **paramVal
= NULL
;
2396 ns_ldap_self_gssapi_config_t config
;
2398 if (current_admin
.debug_level
>= DBG_ALL
) {
2399 logit("perform_update()...\n");
2402 (void) __ns_ldap_setServer(TRUE
);
2404 if (gettimeofday(&tp
, NULL
) != 0)
2407 rc
= __ns_ldap_getParam(NS_LDAP_CACHETTL_P
, ¶mVal
, &error
);
2409 if (rc
== NS_LDAP_SUCCESS
&& paramVal
!= NULL
) {
2410 current_admin
.ldap_stat
.ldap_ttl
= atol((char *)*paramVal
);
2414 (void) __ns_ldap_freeError(&error
);
2416 if (paramVal
!= NULL
)
2417 (void) __ns_ldap_freeParam(¶mVal
);
2419 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2420 logit("perform_update: current profile TTL is %d seconds\n",
2421 current_admin
.ldap_stat
.ldap_ttl
);
2424 if (current_admin
.ldap_stat
.ldap_ttl
> 0) {
2426 * set the profile TTL parameter, just
2427 * in case that the downloading of
2428 * the profile from server would fail
2432 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2433 * It depends on NS_LDAP_CACHETTL_P to set it's value
2434 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2436 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2437 * downloaded from the server, so is NS_LDAP_EXP_P.
2439 buf
[19] = '\0'; /* null terminated the buffer */
2440 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P
,
2441 lltostr((long long)current_admin
.ldap_stat
.ldap_ttl
,
2443 &error
) != NS_LDAP_SUCCESS
) {
2444 logit("Error: __ns_ldap_setParam failed, status: %d "
2445 "message: %s\n", error
->status
, error
->message
);
2446 (void) __ns_ldap_freeError(&error
);
2450 (void) rw_wrlock(&ldap_lock
);
2451 sighup_update
= FALSE
;
2452 (void) rw_unlock(&ldap_lock
);
2455 rc
= update_from_profile(&changed
);
2457 logit("Error: Unable to update from profile\n");
2459 } while (checkupdate(sighup_update
) == TRUE
);
2465 * recreate the server info list
2468 (void) getldap_serverInfo_op(INFO_OP_CREATE
, NULL
, NULL
);
2470 /* flush the data cache */
2471 (void) getldap_cache_op(CACHE_OP_DELETE
,
2474 /* statistics: previous refresh time */
2475 prev_refresh_time
= tp
.tv_sec
;
2477 rc1
= __ns_ldap_self_gssapi_config(&config
);
2478 if (rc1
== NS_LDAP_SUCCESS
) {
2479 if (config
!= NS_LDAP_SELF_GSSAPI_CONFIG_NONE
) {
2480 rc1
= __ns_ldap_check_all_preq(0, 0, 0, config
, &error
);
2481 (void) __ns_ldap_freeError(&error
);
2482 if (rc1
!= NS_LDAP_SUCCESS
) {
2483 logit("Error: Check on self credential "
2484 "prerquesites failed: %d\n",
2490 logit("Error: Failed to get self credential configuration %d\n",
2498 (void) rw_rdlock(&ldap_lock
);
2499 if (((error
= __ns_ldap_DumpConfiguration(NSCONFIGREFRESH
)) != NULL
) ||
2500 ((error
= __ns_ldap_DumpConfiguration(NSCREDREFRESH
)) != NULL
)) {
2501 logit("Error: __ns_ldap_DumpConfiguration failed, "
2502 "status: %d message: %s\n", error
->status
, error
->message
);
2503 __ns_ldap_freeError(&error
);
2504 (void) rw_unlock(&ldap_lock
);
2507 if (rename(NSCONFIGREFRESH
, NSCONFIGFILE
) != 0) {
2508 logit("Error: unlink failed - errno: %s\n", strerror(errno
));
2509 syslog(LOG_ERR
, "Unable to refresh profile, LDAP configuration"
2510 "files not written");
2511 (void) rw_unlock(&ldap_lock
);
2514 if (rename(NSCREDREFRESH
, NSCREDFILE
) != 0) {
2516 * We probably have inconsistent configuration at this point.
2517 * If we were to create a backup file and rename it here, that
2518 * operation might also fail. Consequently there is no safe way
2521 logit("Error: unlink failed - errno: %s\n", strerror(errno
));
2522 syslog(LOG_ERR
, "Unable to refresh profile consistently, "
2523 "LDAP configuration files inconsistent");
2524 (void) rw_unlock(&ldap_lock
);
2528 (void) rw_unlock(&ldap_lock
);
2534 struct timespec timeout
;
2538 void **paramVal
= NULL
;
2539 ns_ldap_error_t
*errorp
;
2540 int always
= 1, err
;
2545 if (current_admin
.debug_level
>= DBG_ALL
) {
2546 logit("getldap_refresh()...\n");
2550 * wait for an available server
2552 while (sig_done
== 0) {
2553 (void) mutex_lock(&sig_mutex
);
2554 sig_done
= signal_done
;
2555 (void) mutex_unlock(&sig_mutex
);
2558 (void) __ns_ldap_setServer(TRUE
);
2560 dbg_level
= current_admin
.debug_level
;
2561 (void) rw_rdlock(&ldap_lock
);
2562 sleeptime
= current_admin
.ldap_stat
.ldap_ttl
;
2563 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2564 logit("getldap_refresh: current profile TTL is %d "
2565 "seconds\n", current_admin
.ldap_stat
.ldap_ttl
);
2567 if (gettimeofday(&tp
, NULL
) == 0) {
2568 if ((__ns_ldap_getParam(NS_LDAP_EXP_P
,
2569 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
2571 (char *)*paramVal
!= NULL
) {
2573 expire
= atol((char *)*paramVal
);
2574 (void) __ns_ldap_freeParam(¶mVal
);
2578 (void) rw_unlock(&ldap_lock
);
2579 (void) cond_init(&cond
,
2581 (void) mutex_lock(&sighuplock
);
2584 timeout
.tv_nsec
= 0;
2586 DBG_PROFILE_REFRESH
) {
2587 logit("getldap_refresh:"
2589 " for %d seconds\n",
2592 err
= cond_reltimedwait(&cond
,
2593 &sighuplock
, &timeout
);
2594 (void) cond_destroy(&cond
);
2595 (void) mutex_unlock(
2599 * getldap_revalidate(),
2600 * do update right away
2607 * configuration failed
2616 sleeptime
= expire
- tp
.tv_sec
;
2617 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2618 logit("getldap_refresh: expire "
2619 "time = %ld\n", expire
);
2626 (void) rw_unlock(&ldap_lock
);
2629 * if this is the first time downloading
2630 * the profile or expire time already passed,
2631 * do not wait, do update
2633 if (first_time
== 0 && sleeptime
> 0) {
2634 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2635 logit("getldap_refresh: (2)about to sleep "
2636 "for %d seconds\n", sleeptime
);
2638 (void) cond_init(&cond
, NULL
, NULL
);
2639 (void) mutex_lock(&sighuplock
);
2640 timeout
.tv_sec
= sleeptime
;
2641 timeout
.tv_nsec
= 0;
2642 err
= cond_reltimedwait(&cond
,
2643 &sighuplock
, &timeout
);
2644 (void) cond_destroy(&cond
);
2645 (void) mutex_unlock(&sighuplock
);
2648 * if load concfiguration failed
2658 getldap_revalidate()
2660 if (current_admin
.debug_level
>= DBG_ALL
) {
2661 logit("getldap_revalidate()...\n");
2663 /* block signal SIGHUP */
2664 (void) sighold(SIGHUP
);
2666 /* now awake the sleeping refresh thread */
2667 (void) cond_signal(&cond
);
2669 /* release signal SIGHUP */
2670 (void) sigrelse(SIGHUP
);
2675 getldap_admincred(LineBuf
*config_info
, ldap_call_t
*in
)
2677 ns_ldap_error_t
*error
;
2678 ldap_config_out_t
*cout
;
2681 if (current_admin
.debug_level
>= DBG_ALL
) {
2682 logit("getldap_admincred()...\n");
2684 /* check privileges */
2685 if (is_root_or_all_privs("GETADMINCRED", &uc
) == 0) {
2686 logit("admin credential requested by a non-root and no ALL "
2687 "privilege user not allowed");
2688 config_info
->str
= NULL
;
2689 config_info
->len
= 0;
2691 (void) rw_rdlock(&ldap_lock
);
2692 if ((error
= __ns_ldap_LoadDoorInfo(config_info
,
2693 in
->ldap_u
.domainname
, NULL
, 1)) != NULL
) {
2694 if (error
!= NULL
&& error
->message
!= NULL
)
2695 logit("Error: ldap_lookup: %s\n",
2697 (void) __ns_ldap_freeError(&error
);
2699 config_info
->str
= NULL
;
2700 config_info
->len
= 0;
2702 /* set change cookie */
2703 cout
= (ldap_config_out_t
*)config_info
->str
;
2705 cout
->cookie
= chg_config_cookie_get();
2706 (void) rw_unlock(&ldap_lock
);
2711 getldap_lookup(LineBuf
*config_info
, ldap_call_t
*in
)
2713 ns_ldap_error_t
*error
;
2714 ldap_config_out_t
*cout
;
2716 if (current_admin
.debug_level
>= DBG_ALL
) {
2717 logit("getldap_lookup()...\n");
2719 (void) rw_rdlock(&ldap_lock
);
2720 if ((error
= __ns_ldap_LoadDoorInfo(config_info
,
2721 in
->ldap_u
.domainname
, NULL
, 0)) != NULL
) {
2722 if (error
!= NULL
&& error
->message
!= NULL
)
2723 logit("Error: ldap_lookup: %s\n", error
->message
);
2724 (void) __ns_ldap_freeError(&error
);
2726 config_info
->str
= NULL
;
2727 config_info
->len
= 0;
2729 /* set change cookie */
2730 cout
= (ldap_config_out_t
*)config_info
->str
;
2732 cout
->cookie
= chg_config_cookie_get();
2733 (void) rw_unlock(&ldap_lock
);
2736 * It creates the header and data stream to be door returned and notify
2737 * chg_get_statusChange() threads.
2738 * This is called after all getldap_get_rootDSE() threads are joined.
2741 test_server_change(server_info_t
*head
)
2743 server_info_t
*info
;
2744 int len
= 0, num
= 0, ds_len
= 0, new_len
= 0, tlen
= 0;
2745 char *tmp_buf
= NULL
, *ptr
= NULL
, *status
= NULL
;
2746 ldap_get_change_out_t
*cout
;
2748 ds_len
= strlen(DOORLINESEP
);
2750 for (info
= head
; info
; info
= info
->next
) {
2751 (void) mutex_lock(&info
->mutex
[0]);
2752 if (info
->sinfo
[0].change
!= 0) {
2753 /* "9.9.9.9|NS_SERVER_CHANGE_UP|" */
2754 len
+= 2 * ds_len
+ strlen(info
->sinfo
[0].addr
) +
2755 strlen(NS_SERVER_CHANGE_UP
);
2758 (void) mutex_unlock(&info
->mutex
[0]);
2766 tlen
= sizeof (ldap_get_change_out_t
) - sizeof (int) + len
;
2767 if ((tmp_buf
= malloc(tlen
)) == NULL
)
2770 cout
= (ldap_get_change_out_t
*)tmp_buf
;
2771 cout
->type
= NS_STATUS_CHANGE_TYPE_SERVER
;
2772 /* cout->cookie is set by chg_notify_statusChange */
2773 cout
->server_count
= num
;
2774 cout
->data_size
= len
;
2776 /* Create IP|UP or DOWN|IP|UP or DOWN| ... */
2779 for (info
= head
; info
; info
= info
->next
) {
2780 (void) mutex_lock(&info
->mutex
[0]);
2781 if (info
->sinfo
[0].change
== 0) {
2782 (void) mutex_unlock(&info
->mutex
[0]);
2786 if (info
->sinfo
[0].change
== NS_SERVER_UP
)
2787 status
= NS_SERVER_CHANGE_UP
;
2788 else if (info
->sinfo
[0].change
== NS_SERVER_DOWN
)
2789 status
= NS_SERVER_CHANGE_DOWN
;
2791 syslog(LOG_WARNING
, gettext("Bad change value %d"),
2792 info
->sinfo
[0].change
);
2793 (void) mutex_unlock(&info
->mutex
[0]);
2798 if ((snprintf(ptr
, new_len
, "%s%s%s%s",
2799 info
->sinfo
[0].addr
, DOORLINESEP
,
2800 status
, DOORLINESEP
)) >= new_len
) {
2801 (void) mutex_unlock(&info
->mutex
[0]);
2804 new_len
-= strlen(ptr
);
2807 (void) mutex_unlock(&info
->mutex
[0]);
2809 (void) chg_notify_statusChange(tmp_buf
);
2812 * It creates the header and data stream to be door returned and notify
2813 * chg_get_statusChange() threads.
2814 * This is called in removing server case.
2817 create_buf_and_notify(char *input
, ns_server_status_t st
)
2819 rm_svr_t
*rms
= (rm_svr_t
*)input
;
2820 char *tmp_buf
, *ptr
, *status
;
2822 ldap_get_change_out_t
*cout
;
2824 /* IP|UP or DOWN| */
2825 len
= 2 * strlen(DOORLINESEP
) + strlen(rms
->addr
) +
2826 strlen(NS_SERVER_CHANGE_UP
) + 1;
2828 tlen
= sizeof (ldap_get_change_out_t
) - sizeof (int) + len
;
2830 if ((tmp_buf
= malloc(tlen
)) == NULL
)
2833 cout
= (ldap_get_change_out_t
*)tmp_buf
;
2834 cout
->type
= NS_STATUS_CHANGE_TYPE_SERVER
;
2835 /* cout->cookie is set by chg_notify_statusChange */
2836 cout
->server_count
= 1;
2837 cout
->data_size
= len
;
2839 /* Create IP|DOWN| */
2841 if (st
== NS_SERVER_UP
)
2842 status
= NS_SERVER_CHANGE_UP
;
2843 else if (st
== NS_SERVER_DOWN
)
2844 status
= NS_SERVER_CHANGE_DOWN
;
2846 (void) snprintf(ptr
, len
, "%s%s%s%s",
2847 rms
->addr
, DOORLINESEP
, status
, DOORLINESEP
);
2849 (void) chg_notify_statusChange(tmp_buf
);
2854 * Return: 0 server is down, 1 server is up
2857 contact_server(char *addr
)
2859 char *rootDSE
= NULL
;
2860 ns_ldap_error_t
*error
= NULL
;
2863 if (__ns_ldap_getRootDSE(addr
, &rootDSE
, &error
,
2864 SA_ALLOW_FALLBACK
) != NS_LDAP_SUCCESS
) {
2865 if (current_admin
.debug_level
>= DBG_ALL
)
2866 logit("get rootDSE %s failed. %s", addr
,
2867 error
->message
? error
->message
: "");
2875 (void) __ns_ldap_freeError(&error
);
2881 * The thread is spawned to do contact_server() so it won't be blocking
2882 * getldap_serverInfo_op(INFO_OP_GETSERVER, ...) case.
2883 * After contact_server() is done, it calls
2884 * getldap_serverInfo_op(INFO_OP_REMOVESERVER, ...) to return to the remaining
2885 * program flow. It's meant to maintain the original program flow yet be
2886 * non-blocking when it's contacting server.
2889 remove_server_thread(void *arg
)
2891 char *addr
= (char *)arg
, *out
= NULL
;
2895 up
= contact_server(addr
);
2900 (void) getldap_serverInfo_op(INFO_OP_REMOVESERVER
, (char *)&rms
, &out
);
2908 * addr is allocated and is freed by remove_server_thread
2909 * It starts a thread to contact server and remove server to avoid long wait
2913 remove_server(char *addr
)
2915 if (thr_create(NULL
, 0, remove_server_thread
,
2916 (void *)addr
, THR_BOUND
|THR_DETACHED
, NULL
) != 0) {
2918 syslog(LOG_ERR
, "thr_create failed for remove_server_thread");
2922 * Compare the server_status and mark it up or down accordingly.
2923 * This is called in removing server case.
2925 static ns_server_status_t
2926 set_server_status(char *input
, server_info_t
*head
)
2928 rm_svr_t
*rms
= (rm_svr_t
*)input
;
2929 ns_server_status_t changed
= 0;
2930 server_info_t
*info
;
2932 for (info
= head
; info
!= NULL
; info
= info
->next
) {
2933 (void) mutex_lock(&info
->mutex
[0]);
2934 if (strcmp(info
->sinfo
[0].addr
, rms
->addr
) == 0) {
2935 if (info
->sinfo
[0].server_status
== INFO_SERVER_UP
&&
2937 info
->sinfo
[0].prev_server_status
=
2938 info
->sinfo
[0].server_status
;
2939 info
->sinfo
[0].server_status
=
2941 info
->sinfo
[0].change
= NS_SERVER_DOWN
;
2942 changed
= NS_SERVER_DOWN
;
2944 } else if (info
->sinfo
[0].server_status
==
2945 INFO_SERVER_ERROR
&& rms
->up
== TRUE
) {
2947 * It should be INFO_SERVER_UP, but check here
2949 info
->sinfo
[0].prev_server_status
=
2950 info
->sinfo
[0].server_status
;
2951 info
->sinfo
[0].server_status
=
2953 info
->sinfo
[0].change
= NS_SERVER_UP
;
2954 changed
= NS_SERVER_UP
;
2956 (void) mutex_unlock(&info
->mutex
[0]);
2959 (void) mutex_unlock(&info
->mutex
[0]);
2962 /* ldap_cachemgr -g option looks up [1] */
2963 (void) mutex_lock(&info
->mutex
[1]);
2964 info
->sinfo
[1].prev_server_status
=
2965 info
->sinfo
[1].server_status
;
2966 if (changed
== NS_SERVER_DOWN
)
2967 info
->sinfo
[1].server_status
= INFO_SERVER_ERROR
;
2968 else if (changed
== NS_SERVER_UP
)
2969 info
->sinfo
[1].server_status
= INFO_SERVER_UP
;
2970 (void) mutex_unlock(&info
->mutex
[1]);