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;
73 /* nis domain information */
74 #define _NIS_FILTER "objectclass=nisDomainObject"
75 #define _NIS_DOMAIN "nisdomain"
77 #define CACHESLEEPTIME 600
79 * server list refresh delay when in "no server" mode
82 #define REFRESH_DELAY_WHEN_NO_SERVER 1
88 INFO_OP_REFRESH_WAIT
= 3,
89 INFO_OP_GETSERVER
= 4,
91 INFO_OP_REMOVESERVER
= 6
101 INFO_SERVER_JUST_INITED
= -1,
102 INFO_SERVER_UNKNOWN
= 0,
103 INFO_SERVER_CONNECTING
= 1,
105 INFO_SERVER_ERROR
= 3,
106 INFO_SERVER_REMOVED
= 4
110 INFO_STATUS_UNKNOWN
= 0,
111 INFO_STATUS_ERROR
= 1,
125 CACHE_MAP_UNKNOWN
= 0,
126 CACHE_MAP_DN2DOMAIN
= 1
129 typedef struct server_info_ext
{
135 info_server_t server_status
;
136 info_server_t prev_server_status
;
137 info_status_t info_status
;
138 ns_server_status_t change
;
141 typedef struct server_info
{
142 struct server_info
*next
;
143 mutex_t mutex
[2]; /* 0: current copy lock */
144 /* 1: update copy lock */
145 server_info_ext_t sinfo
[2]; /* 0: current, 1: update copy */
148 typedef struct cache_hash
{
152 struct cache_hash
*next
;
156 * The status of a server to be removed. It can be up or down.
158 typedef struct rm_svr
{
160 int up
; /* 1: up, 0: down */
163 static int getldap_destroy_serverInfo(server_info_t
*head
);
164 static void test_server_change(server_info_t
*head
);
165 static void remove_server(char *addr
);
166 static ns_server_status_t
set_server_status(char *input
, server_info_t
*head
);
167 static void create_buf_and_notify(char *input
, ns_server_status_t st
);
171 * The code was in signal handler getldap_revalidate
172 * It's moved out of the handler because it could cause deadlock
178 ns_ldap_error_t
*error
;
181 (void) __ns_ldap_setServer(TRUE
);
183 (void) rw_wrlock(&ldap_lock
);
184 if ((error
= __ns_ldap_LoadConfiguration()) != NULL
) {
185 logit("Error: Unable to read '%s': %s\n",
186 NSCONFIGFILE
, error
->message
);
187 __ns_ldap_freeError(&error
);
190 sighup_update
= TRUE
;
192 (void) rw_unlock(&ldap_lock
);
198 * Calculate a hash for a string
199 * Based on elf_hash algorithm, hash is case insensitive
200 * Uses tolower instead of _tolower because of I18N
204 getldap_hash(const char *str
)
206 unsigned int hval
= 0;
211 hval
= (hval
<< 4) + tolower(*str
++);
212 if ((g
= (hval
& 0xf0000000)) != 0)
216 return ((unsigned long)hval
);
220 * Remove a hash table entry.
221 * This function expects a lock in place when called.
224 static cache_hash_t
*
225 getldap_free_hash(cache_hash_t
*p
)
229 p
->type
= CACHE_MAP_UNKNOWN
;
239 * Scan a hash table hit for a matching hash entry.
240 * This function expects a lock in place when called.
242 static cache_hash_t
*
243 getldap_scan_hash(cache_type_t type
, char *from
,
247 if (idx
->type
== type
&&
248 strcasecmp(from
, idx
->from
) == 0) {
253 return ((cache_hash_t
*)NULL
);
257 * Format and return the cache data statistics
260 getldap_get_cacheData_stat(int max
, int current
, char **output
)
262 #define C_HEADER0 "Cache data information: "
263 #define C_HEADER1 " Maximum cache entries: "
264 #define C_HEADER2 " Number of cache entries: "
265 int hdr0_len
= strlen(gettext(C_HEADER0
));
266 int hdr1_len
= strlen(gettext(C_HEADER1
));
267 int hdr2_len
= strlen(gettext(C_HEADER2
));
270 if (current_admin
.debug_level
>= DBG_ALL
) {
271 logit("getldap_get_cacheData_stat()...\n");
276 len
= hdr0_len
+ hdr1_len
+ hdr2_len
+
277 3 * strlen(DOORLINESEP
) + 21;
278 *output
= malloc(len
);
282 (void) snprintf(*output
, len
, "%s%s%s%10d%s%s%10d%s",
283 gettext(C_HEADER0
), DOORLINESEP
,
284 gettext(C_HEADER1
), max
, DOORLINESEP
,
285 gettext(C_HEADER2
), current
, DOORLINESEP
);
287 return (NS_LDAP_SUCCESS
);
291 getldap_cache_op(cache_op_t op
, cache_type_t type
,
292 char *from
, char **to
)
294 #define CACHE_HASH_MAX 257
295 #define CACHE_HASH_MAX_ENTRY 256
296 static cache_hash_t
*hashTbl
[CACHE_HASH_MAX
];
297 cache_hash_t
*next
, *idx
, *newp
;
299 static rwlock_t cache_lock
= DEFAULTRWLOCK
;
301 static int entry_num
= 0;
303 if (current_admin
.debug_level
>= DBG_ALL
) {
304 logit("getldap_cache_op()...\n");
307 case CACHE_OP_CREATE
:
308 if (current_admin
.debug_level
>= DBG_ALL
) {
309 logit("operation is CACHE_OP_CREATE...\n");
311 (void) rw_wrlock(&cache_lock
);
313 for (i
= 0; i
< CACHE_HASH_MAX
; i
++) {
318 (void) rw_unlock(&cache_lock
);
321 case CACHE_OP_DELETE
:
322 if (current_admin
.debug_level
>= DBG_ALL
) {
323 logit("operation is CACHE_OP_DELETE...\n");
325 (void) rw_wrlock(&cache_lock
);
327 for (i
= 0; i
< CACHE_HASH_MAX
; i
++) {
329 while (next
!= NULL
) {
330 next
= getldap_free_hash(next
);
336 (void) rw_unlock(&cache_lock
);
340 if (current_admin
.debug_level
>= DBG_ALL
) {
341 logit("operation is CACHE_OP_ADD...\n");
343 if (from
== NULL
|| to
== NULL
|| *to
== NULL
)
345 hash
= getldap_hash(from
) % CACHE_HASH_MAX
;
346 (void) rw_wrlock(&cache_lock
);
349 * replace old "to" value with new one
350 * if an entry with same "from"
354 newp
= getldap_scan_hash(type
, from
, idx
);
357 newp
->to
= strdup(*to
);
358 (void) rw_unlock(&cache_lock
);
359 return (NS_LDAP_SUCCESS
);
363 if (entry_num
> CACHE_HASH_MAX_ENTRY
) {
364 (void) rw_unlock(&cache_lock
);
368 newp
= (cache_hash_t
*)malloc(sizeof (cache_hash_t
));
370 (void) rw_unlock(&cache_lock
);
371 return (NS_LDAP_MEMORY
);
374 newp
->from
= strdup(from
);
375 newp
->to
= strdup(*to
);
377 hashTbl
[hash
] = newp
;
379 (void) rw_unlock(&cache_lock
);
383 if (current_admin
.debug_level
>= DBG_ALL
) {
384 logit("operation is CACHE_OP_FIND...\n");
386 if (from
== NULL
|| to
== NULL
)
389 hash
= getldap_hash(from
) % CACHE_HASH_MAX
;
390 (void) rw_rdlock(&cache_lock
);
392 idx
= getldap_scan_hash(type
, from
, idx
);
394 *to
= strdup(idx
->to
);
395 (void) rw_unlock(&cache_lock
);
400 case CACHE_OP_GETSTAT
:
401 if (current_admin
.debug_level
>= DBG_ALL
) {
402 logit("operation is CACHE_OP_GETSTAT...\n");
407 return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY
,
412 logit("getldap_cache_op(): "
413 "invalid operation code (%d).\n", op
);
417 return (NS_LDAP_SUCCESS
);
420 * Function: sync_current_with_update_copy
422 * This function syncs up the 2 sinfo copies in info.
424 * The 2 copies are identical most of time.
425 * The update copy(sinfo[1]) could be different when
426 * getldap_serverInfo_refresh thread is refreshing the server list
427 * and calls getldap_get_rootDSE to update info. getldap_get_rootDSE
428 * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
429 * The calling sequence is
430 * getldap_serverInfo_refresh->
431 * getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
432 * getldap_set_serverInfo->
433 * getldap_get_rootDSE
435 * The original server_info_t has one copy of server info. When libsldap
436 * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
437 * is updating the server info, it would hit a unprotected window in
438 * getldap_rootDSE. The door call will not get server info and libsldap
439 * fails at making ldap connection.
441 * The new server_info_t provides GETLDAPSERVER thread with a current
442 * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
443 * and syncs up 2 copies before thr_exit. This will close the window in
444 * getldap_get_rootDSE.
448 sync_current_with_update_copy(server_info_t
*info
)
450 if (current_admin
.debug_level
>= DBG_ALL
) {
451 logit("sync_current_with_update_copy()...\n");
454 (void) mutex_lock(&info
->mutex
[1]);
455 (void) mutex_lock(&info
->mutex
[0]);
457 if (info
->sinfo
[1].server_status
== INFO_SERVER_UP
&&
458 info
->sinfo
[0].server_status
!= INFO_SERVER_UP
)
459 info
->sinfo
[1].change
= NS_SERVER_UP
;
460 else if (info
->sinfo
[1].server_status
!= INFO_SERVER_UP
&&
461 info
->sinfo
[0].server_status
== INFO_SERVER_UP
)
462 info
->sinfo
[1].change
= NS_SERVER_DOWN
;
464 info
->sinfo
[1].change
= 0;
467 /* free memory in current copy first */
468 free(info
->sinfo
[0].addr
);
469 info
->sinfo
[0].addr
= NULL
;
471 free(info
->sinfo
[0].hostname
);
472 info
->sinfo
[0].hostname
= NULL
;
474 free(info
->sinfo
[0].rootDSE_data
);
475 info
->sinfo
[0].rootDSE_data
= NULL
;
477 free(info
->sinfo
[0].errormsg
);
478 info
->sinfo
[0].errormsg
= NULL
;
481 * make current and update copy identical
483 info
->sinfo
[0] = info
->sinfo
[1];
486 * getldap_get_server_stat() reads the update copy sinfo[1]
487 * so it can't be freed or nullified yet at this point.
489 * The sinfo[0] and sinfo[1] have identical string pointers.
490 * strdup the strings to avoid the double free problem.
491 * The strings of sinfo[1] are freed in
492 * getldap_get_rootDSE() and the strings of sinfo[0]
493 * are freed earlier in this function. If the pointers are the
494 * same, they will be freed twice.
496 if (info
->sinfo
[1].addr
)
497 info
->sinfo
[0].addr
= strdup(info
->sinfo
[1].addr
);
498 if (info
->sinfo
[1].hostname
)
499 info
->sinfo
[0].hostname
= strdup(info
->sinfo
[1].hostname
);
500 if (info
->sinfo
[1].rootDSE_data
)
501 info
->sinfo
[0].rootDSE_data
=
502 strdup(info
->sinfo
[1].rootDSE_data
);
503 if (info
->sinfo
[1].errormsg
)
504 info
->sinfo
[0].errormsg
= strdup(info
->sinfo
[1].errormsg
);
506 (void) mutex_unlock(&info
->mutex
[0]);
507 (void) mutex_unlock(&info
->mutex
[1]);
512 getldap_get_rootDSE(void *arg
)
514 server_info_t
*serverInfo
= (server_info_t
*)arg
;
516 int exitrc
= NS_LDAP_SUCCESS
;
518 int server_found
= 0;
519 char errmsg
[MAXERROR
];
520 ns_ldap_return_code rc
;
521 ns_ldap_error_t
*error
= NULL
;
523 if (current_admin
.debug_level
>= DBG_ALL
) {
524 logit("getldap_get_rootDSE()....\n");
527 /* initialize the server info element */
528 (void) mutex_lock(&serverInfo
->mutex
[1]);
529 serverInfo
->sinfo
[1].type
= INFO_RW_UNKNOWN
;
530 serverInfo
->sinfo
[1].info_status
=
533 * When the sever list is refreshed over and over,
534 * this function is called each time it is refreshed.
535 * The previous server status of the update copy(sinfo[1])
536 * is the status of the current copy
538 (void) mutex_lock(&serverInfo
->mutex
[0]);
539 serverInfo
->sinfo
[1].prev_server_status
=
540 serverInfo
->sinfo
[0].server_status
;
541 (void) mutex_unlock(&serverInfo
->mutex
[0]);
543 serverInfo
->sinfo
[1].server_status
=
545 free(serverInfo
->sinfo
[1].rootDSE_data
);
546 serverInfo
->sinfo
[1].rootDSE_data
= NULL
;
547 free(serverInfo
->sinfo
[1].errormsg
);
548 serverInfo
->sinfo
[1].errormsg
= NULL
;
549 (void) mutex_unlock(&serverInfo
->mutex
[1]);
551 (void) mutex_lock(&serverInfo
->mutex
[1]);
552 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_CONNECTING
;
553 (void) mutex_unlock(&serverInfo
->mutex
[1]);
556 * WARNING: anon_fallback == 1 (last argument) means that when
557 * __ns_ldap_getRootDSE is unable to bind using the configured
558 * credentials, it will try to fall back to using anonymous, non-SSL
561 * This is for backward compatibility reasons - we might have machines
562 * in the field with broken configuration (invalid credentials) and we
563 * don't want them to be disturbed.
565 if (rc
= __ns_ldap_getRootDSE(serverInfo
->sinfo
[1].addr
,
568 SA_ALLOW_FALLBACK
) != NS_LDAP_SUCCESS
) {
569 (void) mutex_lock(&serverInfo
->mutex
[1]);
570 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_ERROR
;
571 serverInfo
->sinfo
[1].info_status
= INFO_STATUS_ERROR
;
572 if (error
&& error
->message
) {
573 serverInfo
->sinfo
[1].errormsg
= strdup(error
->message
);
575 (void) snprintf(errmsg
, sizeof (errmsg
), "%s %s "
576 "(rc = %d)", gettext("Can not get the root DSE from"
577 " server"), serverInfo
->sinfo
[1].addr
, rc
);
578 serverInfo
->sinfo
[1].errormsg
= strdup(errmsg
);
582 (void) __ns_ldap_freeError(&error
);
585 if (current_admin
.debug_level
>= DBG_ALL
) {
586 logit("getldap_get_rootDSE: %s.\n",
587 serverInfo
->sinfo
[1].errormsg
);
589 (void) mutex_unlock(&serverInfo
->mutex
[1]);
591 * sync sinfo copies in the serverInfo.
594 sync_current_with_update_copy(serverInfo
);
595 thr_exit((void *) -1);
598 (void) mutex_lock(&serverInfo
->mutex
[1]);
600 /* assume writeable, i.e., can do modify */
601 serverInfo
->sinfo
[1].type
= INFO_RW_WRITEABLE
;
602 serverInfo
->sinfo
[1].server_status
= INFO_SERVER_UP
;
603 serverInfo
->sinfo
[1].info_status
= INFO_STATUS_NEW
;
604 /* remove the last DOORLINESEP */
605 *(rootDSE
+strlen(rootDSE
)-1) = '\0';
606 serverInfo
->sinfo
[1].rootDSE_data
= rootDSE
;
610 (void) mutex_unlock(&serverInfo
->mutex
[1]);
613 * sync sinfo copies in the serverInfo.
616 sync_current_with_update_copy(serverInfo
);
618 * signal that the ldap_cachemgr parent process
619 * should exit now, if it is still waiting
621 (void) mutex_lock(&sig_mutex
);
622 if (signal_done
== FALSE
&& server_found
) {
624 (void) kill(ppid
, SIGUSR1
);
625 if (current_admin
.debug_level
>= DBG_ALL
) {
626 logit("getldap_get_rootDSE(): "
627 "SIGUSR1 signal sent to "
628 "parent process(%ld).\n", ppid
);
632 (void) mutex_unlock(&sig_mutex
);
634 thr_exit((void *) exitrc
);
640 getldap_init_serverInfo(server_info_t
**head
)
642 char **servers
= NULL
;
643 int rc
= 0, i
, exitrc
= NS_LDAP_SUCCESS
;
644 ns_ldap_error_t
*errorp
= NULL
;
645 server_info_t
*info
, *tail
= NULL
;
648 if (current_admin
.debug_level
>= DBG_ALL
) {
649 logit("getldap_init_serverInfo()...\n");
651 rc
= __s_api_getServers(&servers
, &errorp
);
653 if (rc
!= NS_LDAP_SUCCESS
) {
654 logit("getldap_init_serverInfo: "
655 "__s_api_getServers failed.\n");
657 __ns_ldap_freeError(&errorp
);
660 for (i
= 0; servers
[i
] != NULL
; i
++) {
661 info
= (server_info_t
*)calloc(1, sizeof (server_info_t
));
663 logit("getldap_init_serverInfo: "
664 "not enough memory.\n");
665 exitrc
= NS_LDAP_MEMORY
;
676 info
->sinfo
[0].addr
= strdup(servers
[i
]);
677 if (info
->sinfo
[0].addr
== NULL
) {
678 logit("getldap_init_serverInfo: "
679 "not enough memory.\n");
680 exitrc
= NS_LDAP_MEMORY
;
683 info
->sinfo
[1].addr
= strdup(servers
[i
]);
684 if (info
->sinfo
[1].addr
== NULL
) {
685 logit("getldap_init_serverInfo: "
686 "not enough memory.\n");
687 exitrc
= NS_LDAP_MEMORY
;
691 info
->sinfo
[0].type
= INFO_RW_UNKNOWN
;
692 info
->sinfo
[1].type
= INFO_RW_UNKNOWN
;
693 info
->sinfo
[0].info_status
= INFO_STATUS_UNKNOWN
;
694 info
->sinfo
[1].info_status
= INFO_STATUS_UNKNOWN
;
695 info
->sinfo
[0].server_status
= INFO_SERVER_UNKNOWN
;
696 info
->sinfo
[1].server_status
= INFO_SERVER_UNKNOWN
;
699 * Assume at startup or after the configuration
700 * profile is refreshed, all servers are good.
702 info
->sinfo
[0].prev_server_status
=
704 info
->sinfo
[1].prev_server_status
=
706 info
->sinfo
[0].hostname
= NULL
;
707 info
->sinfo
[1].hostname
= NULL
;
708 info
->sinfo
[0].rootDSE_data
= NULL
;
709 info
->sinfo
[1].rootDSE_data
= NULL
;
710 info
->sinfo
[0].errormsg
= NULL
;
711 info
->sinfo
[1].errormsg
= NULL
;
714 __s_api_free2dArray(servers
);
715 if (exitrc
!= NS_LDAP_SUCCESS
) {
717 (void) getldap_destroy_serverInfo(*head
);
725 getldap_destroy_serverInfo(server_info_t
*head
)
727 server_info_t
*info
, *next
;
729 if (current_admin
.debug_level
>= DBG_ALL
) {
730 logit("getldap_destroy_serverInfo()...\n");
734 logit("getldap_destroy_serverInfo: "
735 "invalid serverInfo list.\n");
739 for (info
= head
; info
; info
= next
) {
740 free(info
->sinfo
[0].addr
);
741 free(info
->sinfo
[1].addr
);
742 free(info
->sinfo
[0].hostname
);
743 free(info
->sinfo
[1].hostname
);
744 free(info
->sinfo
[0].rootDSE_data
);
745 free(info
->sinfo
[1].rootDSE_data
);
746 free(info
->sinfo
[0].errormsg
);
747 free(info
->sinfo
[1].errormsg
);
751 return (NS_LDAP_SUCCESS
);
755 getldap_set_serverInfo(server_info_t
*head
, int reset_bindtime
, info_op_t op
)
760 int num_threads
= 0, i
, j
;
762 void **paramVal
= NULL
;
763 ns_ldap_error_t
*error
= NULL
;
765 if (current_admin
.debug_level
>= DBG_ALL
) {
766 logit("getldap_set_serverInfo()...\n");
770 logit("getldap_set_serverInfo: "
771 "invalid serverInfo list.\n");
775 /* Get the bind timeout value */
776 if (reset_bindtime
== 1) {
777 tcptimeout
= NS_DEFAULT_BIND_TIMEOUT
* 1000;
778 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P
,
780 if (paramVal
!= NULL
&& *paramVal
!= NULL
) {
781 /* convert to milliseconds */
782 tcptimeout
= **((int **)paramVal
);
784 (void) __ns_ldap_freeParam(¶mVal
);
787 (void) __ns_ldap_freeError(&error
);
790 for (info
= head
; info
; info
= info
->next
)
793 if (num_threads
== 0) {
794 logit("getldap_set_serverInfo: "
795 "empty serverInfo list.\n");
799 tid
= (thread_t
*) calloc(1, sizeof (thread_t
) * num_threads
);
801 logit("getldap_set_serverInfo: "
802 "No memory to create thread ID list.\n");
806 for (info
= head
, i
= 0; info
; info
= info
->next
, i
++) {
807 if (thr_create(NULL
, 0,
808 (void *(*)(void*))getldap_get_rootDSE
,
809 (void *)info
, 0, &tid
[i
])) {
810 logit("getldap_set_serverInfo: "
811 "can not create thread %d.\n", i
+ 1);
812 for (j
= 0; j
< i
; j
++)
813 (void) thr_join(tid
[j
], NULL
, NULL
);
819 for (i
= 0; i
< num_threads
; i
++) {
820 if (thr_join(tid
[i
], NULL
, &status
) == 0) {
821 if ((int)status
== NS_LDAP_SUCCESS
)
828 if (op
== INFO_OP_REFRESH
)
829 test_server_change(head
);
831 return (NS_LDAP_SUCCESS
);
837 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
838 * to this function from getldap_serverInfo_op().
840 * a buffer containing an empty string (e.g., input[0]='\0';) or a string
841 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
843 * where addr is the address of a server and
844 * req is one of the following:
845 * NS_CACHE_NEW: send a new server address, addr is ignored.
846 * NS_CACHE_NORESP: send the next one, remove addr from list.
847 * NS_CACHE_NEXT: send the next one, keep addr on list.
848 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same
851 * NS_CACHE_ADDR_IP: return server address as is, this is default.
852 * NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
853 * only self credential case requires such format.
855 * a buffer containing server info in the following format:
856 * serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
857 * [ attr=value [DOORLINESEP attr=value ]...]
858 * For example: ( here | used as DOORLINESEP for visual purposes)
859 * 1) simple bind and sasl/DIGEST-MD5 bind :
860 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
861 * supportedSASLmechanisms=GSSAPI
862 * 2) sasl/GSSAPI bind (self credential):
863 * 1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
864 * supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
865 * NOTE: caller should free this buffer when done using it
868 getldap_get_serverInfo(server_info_t
*head
, char *input
,
869 char **output
, int *svr_removed
)
871 server_info_t
*info
= NULL
;
872 server_info_t
*server
= NULL
;
875 char req_new
[] = NS_CACHE_NEW
;
876 char addr_type
[] = NS_CACHE_ADDR_IP
;
877 int matched
= FALSE
, len
= 0, rc
= 0;
878 char *ret_addr
= NULL
, *ret_addrFQDN
= NULL
;
879 char *new_addr
= NULL
;
882 if (current_admin
.debug_level
>= DBG_ALL
) {
883 logit("getldap_get_serverInfo()...\n");
886 if (input
== NULL
|| output
== NULL
) {
887 logit("getldap_get_serverInfo: "
888 "No input or output buffer.\n");
893 *svr_removed
= FALSE
;
896 logit("getldap_get_serverInfo: "
897 "invalid serverInfo list.\n");
901 * parse the input string to get req and addr,
902 * if input is empty, i.e., input[0] == '\0',
903 * treat it as an NS_CACHE_NEW request
906 if (input
[0] != '\0') {
908 /* Save addr type flag */
909 addr_type
[0] = input
[1];
910 input
[strlen(NS_CACHE_NEW
)] = '\0';
911 /* skip acion type flag, addr type flag and DOORLINESEP */
912 addr
= input
+ strlen(DOORLINESEP
) + strlen(NS_CACHE_NEW
)
913 + strlen(NS_CACHE_ADDR_IP
);
917 * or the server info is new,
919 * beginning of the list
921 if ((strcmp(req
, NS_CACHE_NEW
) == 0) ||
922 (head
->sinfo
[0].info_status
== INFO_STATUS_NEW
))
924 for (info
= head
; info
; info
= info
->next
) {
926 * make sure the server info stays the same
927 * while the data is being processed
931 * This function is called to get server info list
932 * and pass it back to door call clients.
933 * Access the current copy (sinfo[0]) to get such
936 (void) mutex_lock(&info
->mutex
[0]);
938 if (matched
== FALSE
&&
939 strcmp(info
->sinfo
[0].addr
, addr
) == 0) {
941 if (strcmp(req
, NS_CACHE_NORESP
) == 0) {
942 if (chg_is_called_from_nscd_or_peruser_nscd(
943 "REMOVE SERVER", &pid
) == 0) {
944 (void) mutex_unlock(&info
->mutex
[0]);
945 if (current_admin
.debug_level
>=
947 logit("Only nscd can remove "
948 "servers. pid %ld", pid
);
953 * if the information is new,
954 * give this server one more chance
956 if (info
->sinfo
[0].info_status
==
958 info
->sinfo
[0].server_status
==
964 * it is recommended that
965 * before removing the
966 * server from the list,
967 * the server should be
968 * contacted one more time
969 * to make sure that it is
970 * really unavailable.
971 * For now, just trust the client
972 * (i.e., the sldap library)
973 * that it knows what it is
974 * doing and would not try
975 * to mess up the server
979 * Make a copy of addr to contact
980 * it later. It's not doing it here
981 * to avoid long wait and possible
982 * recursion to contact an LDAP server.
984 new_addr
= strdup(info
->sinfo
[0].addr
);
986 remove_server(new_addr
);
988 (void) mutex_unlock(&info
->mutex
[0]);
993 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
995 (void) mutex_unlock(&info
->mutex
[0]);
1001 if (strcmp(req
, NS_CACHE_WRITE
) == 0) {
1002 if (info
->sinfo
[0].type
==
1003 INFO_RW_WRITEABLE
&&
1004 info
->sinfo
[0].server_status
==
1009 } else if (info
->sinfo
[0].server_status
==
1016 (void) mutex_unlock(&info
->mutex
[0]);
1020 if (strcmp(addr_type
, NS_CACHE_ADDR_HOSTNAME
) == 0) {
1022 * In SASL/GSSAPI case, a hostname is required for
1023 * Kerberos's service principal.
1025 * ldap/foo.sun.com@SUN.COM
1027 if (server
->sinfo
[0].hostname
== NULL
) {
1028 rc
= __s_api_ip2hostname(server
->sinfo
[0].addr
,
1029 &server
->sinfo
[0].hostname
);
1030 if (rc
!= NS_LDAP_SUCCESS
) {
1031 (void) mutex_unlock(&info
->mutex
[0]);
1034 if (current_admin
.debug_level
>= DBG_ALL
) {
1035 logit("getldap_get_serverInfo: "
1036 "%s is converted to %s\n",
1037 server
->sinfo
[0].addr
,
1038 server
->sinfo
[0].hostname
);
1041 ret_addr
= server
->sinfo
[0].addr
;
1042 ret_addrFQDN
= server
->sinfo
[0].hostname
;
1045 ret_addr
= server
->sinfo
[0].addr
;
1048 len
= strlen(ret_addr
) +
1049 strlen(server
->sinfo
[0].rootDSE_data
) +
1050 strlen(DOORLINESEP
) + 1;
1051 if (ret_addrFQDN
!= NULL
)
1052 len
+= strlen(ret_addrFQDN
) + strlen(DOORLINESEP
);
1053 *output
= (char *)malloc(len
);
1054 if (*output
== NULL
) {
1055 (void) mutex_unlock(&info
->mutex
[0]);
1056 return (NS_LDAP_MEMORY
);
1058 if (ret_addrFQDN
== NULL
)
1059 (void) snprintf(*output
, len
, "%s%s%s",
1060 ret_addr
, DOORLINESEP
,
1061 server
->sinfo
[0].rootDSE_data
);
1063 (void) snprintf(*output
, len
, "%s%s%s%s%s",
1064 ret_addr
, DOORLINESEP
,
1065 ret_addrFQDN
, DOORLINESEP
,
1066 server
->sinfo
[0].rootDSE_data
);
1067 server
->sinfo
[0].info_status
= INFO_STATUS_OLD
;
1068 (void) mutex_unlock(&info
->mutex
[0]);
1069 return (NS_LDAP_SUCCESS
);
1076 * Format previous and next refresh time
1079 getldap_format_refresh_time(char **output
, time_t *prev
, time_t *next
)
1081 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S"
1082 #define TIME_HEADER1 " Previous refresh time: "
1083 #define TIME_HEADER2 " Next refresh time: "
1084 int hdr1_len
= strlen(gettext(TIME_HEADER1
));
1085 int hdr2_len
= strlen(gettext(TIME_HEADER2
));
1091 if (current_admin
.debug_level
>= DBG_ALL
) {
1092 logit("getldap_format_refresh_time()...\n");
1097 /* format the time of previous refresh */
1099 (void) localtime_r(prev
, &tm
);
1100 (void) strftime(pbuf
, sizeof (pbuf
) - 1, TIME_FORMAT
, &tm
);
1102 (void) strcpy(pbuf
, gettext("NOT DONE"));
1105 /* format the time of next refresh */
1107 (void) localtime_r(next
, &tm
);
1108 (void) strftime(nbuf
, sizeof (nbuf
) - 1, TIME_FORMAT
, &tm
);
1110 (void) strcpy(nbuf
, gettext("NOT SET"));
1113 len
= hdr1_len
+ hdr2_len
+ strlen(nbuf
) +
1114 strlen(pbuf
) + 2 * strlen(DOORLINESEP
) + 1;
1116 *output
= malloc(len
);
1117 if (*output
== NULL
)
1120 (void) snprintf(*output
, len
, "%s%s%s%s%s%s",
1121 gettext(TIME_HEADER1
), pbuf
, DOORLINESEP
,
1122 gettext(TIME_HEADER2
), nbuf
, DOORLINESEP
);
1124 return (NS_LDAP_SUCCESS
);
1128 * getldap_get_server_stat processes the GETSTAT request passed
1129 * to this function from getldap_serverInfo_op().
1131 * a buffer containing info for all the servers.
1132 * For each server, the data is in the following format:
1133 * server: server address or name, status: unknown|up|down|removed DOORLINESEP
1134 * for example: ( here | used as DOORLINESEP for visual purposes)
1135 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1136 * NOTE: caller should free this buffer when done using it
1139 getldap_get_server_stat(server_info_t
*head
, char **output
,
1140 time_t *prev
, time_t *next
)
1142 #define S_HEADER "Server information: "
1143 #define S_FORMAT " server: %s, status: %s%s"
1144 #define S_ERROR " error message: %s%s"
1145 server_info_t
*info
= NULL
;
1146 int header_len
= strlen(gettext(S_HEADER
));
1147 int format_len
= strlen(gettext(S_FORMAT
));
1148 int error_len
= strlen(gettext(S_ERROR
));
1149 int len
= header_len
+ strlen(DOORLINESEP
);
1151 char *status
, *output1
= NULL
, *tmpptr
;
1155 if (current_admin
.debug_level
>= DBG_ALL
) {
1156 logit("getldap_get_server_stat()...\n");
1160 logit("getldap_get_server_stat: "
1161 "invalid serverInfo list.\n");
1165 /* format previous and next refresh time */
1166 (void) getldap_format_refresh_time(&output1
, prev
, next
);
1167 if (output1
== NULL
)
1169 len
+= strlen(output1
);
1170 len1
= len
+ strlen(DOORLINESEP
) + 1;
1172 *output
= (char *)calloc(1, len1
);
1173 if (*output
== NULL
) {
1178 /* insert header string and refresh time info */
1179 (void) snprintf(*output
, len1
, "%s%s%s",
1180 gettext(S_HEADER
), DOORLINESEP
, output1
);
1182 for (info
= head
; info
; info
= info
->next
) {
1185 * make sure the server info stays the same
1186 * while the data is being processed
1188 (void) mutex_lock(&info
->mutex
[1]);
1191 * When the updating process is under way(getldap_get_rootDSE)
1192 * the update copy(sinfo[1] is the latest copy.
1193 * When the updating process
1194 * is done, the current copy (sinfo[0]) has the latest status,
1195 * which is still identical to the update copy.
1196 * So update copy has the latest status.
1197 * Use the update copy(sinfo[1]) to show status
1198 * (ldap_cachemgr -g).
1202 switch (info
->sinfo
[1].server_status
) {
1203 case INFO_SERVER_UNKNOWN
:
1204 status
= gettext("UNKNOWN");
1206 case INFO_SERVER_CONNECTING
:
1207 status
= gettext("CONNECTING");
1209 case INFO_SERVER_UP
:
1210 status
= gettext("UP");
1212 case INFO_SERVER_ERROR
:
1213 status
= gettext("ERROR");
1215 case INFO_SERVER_REMOVED
:
1216 status
= gettext("REMOVED");
1220 len
+= format_len
+ strlen(status
) +
1221 strlen(info
->sinfo
[1].addr
) +
1222 strlen(DOORLINESEP
);
1223 if (info
->sinfo
[1].errormsg
!= NULL
)
1225 strlen(info
->sinfo
[1].errormsg
) +
1226 strlen(DOORLINESEP
);
1228 tmpptr
= (char *)realloc(*output
, len
);
1229 if (tmpptr
== NULL
) {
1233 (void) mutex_unlock(&info
->mutex
[1]);
1238 /* insert server IP addr or name and status */
1239 len1
= len
- strlen(*output
);
1240 (void) snprintf(*output
+ strlen(*output
), len1
,
1241 gettext(S_FORMAT
), info
->sinfo
[1].addr
,
1242 status
, DOORLINESEP
);
1243 /* insert error message if any */
1244 len1
= len
- strlen(*output
);
1245 if (info
->sinfo
[1].errormsg
!= NULL
)
1246 (void) snprintf(*output
+ strlen(*output
), len1
,
1248 info
->sinfo
[1].errormsg
,
1251 (void) mutex_unlock(&info
->mutex
[1]);
1256 return (NS_LDAP_SUCCESS
);
1260 * Format and return the refresh time statistics
1263 getldap_get_refresh_stat(char **output
)
1265 #define R_HEADER0 "Configuration refresh information: "
1266 #define R_HEADER1 " Configured to NO REFRESH."
1267 int hdr0_len
= strlen(gettext(R_HEADER0
));
1268 int hdr1_len
= strlen(gettext(R_HEADER1
));
1269 int cache_ttl
= -1, len
= 0;
1271 void **paramVal
= NULL
;
1272 ns_ldap_error_t
*errorp
= NULL
;
1273 char *output1
= NULL
;
1275 if (current_admin
.debug_level
>= DBG_ALL
) {
1276 logit("getldap_get_refresh_stat()...\n");
1281 /* get configured cache TTL */
1282 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P
,
1283 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
1285 (char *)*paramVal
!= NULL
) {
1286 cache_ttl
= atol((char *)*paramVal
);
1289 __ns_ldap_freeError(&errorp
);
1291 (void) __ns_ldap_freeParam(¶mVal
);
1293 /* cound not get cache TTL */
1294 if (cache_ttl
== -1)
1297 if (cache_ttl
== 0) {
1298 len
= hdr0_len
+ hdr1_len
+
1299 2 * strlen(DOORLINESEP
) + 1;
1300 *output
= malloc(len
);
1301 if (*output
== NULL
)
1303 (void) snprintf(*output
, len
, "%s%s%s%s",
1304 gettext(R_HEADER0
), DOORLINESEP
,
1305 gettext(R_HEADER1
), DOORLINESEP
);
1308 /* get configuration expiration time */
1309 if ((__ns_ldap_getParam(NS_LDAP_EXP_P
,
1310 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
1312 (char *)*paramVal
!= NULL
) {
1313 expire
= (time_t)atol((char *)*paramVal
);
1316 __ns_ldap_freeError(&errorp
);
1319 (void) __ns_ldap_freeParam(¶mVal
);
1321 /* cound not get expiration time */
1325 /* format previous and next refresh time */
1326 (void) getldap_format_refresh_time(&output1
,
1327 &prev_refresh_time
, &expire
);
1328 if (output1
== NULL
)
1331 len
= hdr0_len
+ strlen(output1
) +
1332 2 * strlen(DOORLINESEP
) + 1;
1333 *output
= malloc(len
);
1334 if (*output
== NULL
) {
1338 (void) snprintf(*output
, len
, "%s%s%s%s",
1339 gettext(R_HEADER0
), DOORLINESEP
,
1340 output1
, DOORLINESEP
);
1344 return (NS_LDAP_SUCCESS
);
1348 getldap_get_cacheTTL()
1350 void **paramVal
= NULL
;
1351 ns_ldap_error_t
*error
;
1352 int rc
= 0, cachettl
;
1355 if (current_admin
.debug_level
>= DBG_ALL
) {
1356 logit("getldap_get_cacheTTL()....\n");
1359 if ((rc
= __ns_ldap_getParam(NS_LDAP_CACHETTL_P
,
1360 ¶mVal
, &error
)) != NS_LDAP_SUCCESS
) {
1361 if (error
!= NULL
&& error
->message
!= NULL
)
1362 logit("Error: Unable to get configuration "
1363 "refresh TTL: %s\n",
1368 __ns_ldap_err2str(rc
, &tmp
);
1369 logit("Error: Unable to get configuration "
1370 "refresh TTL: %s\n", tmp
);
1372 (void) __ns_ldap_freeParam(¶mVal
);
1373 (void) __ns_ldap_freeError(&error
);
1376 if (paramVal
== NULL
|| (char *)*paramVal
== NULL
)
1378 cachettl
= atol((char *)*paramVal
);
1379 (void) __ns_ldap_freeParam(¶mVal
);
1385 * This function implements the adaptive server list refresh
1386 * algorithm used by ldap_cachemgr. The idea is to have the
1387 * refresh TTL adjust itself between maximum and minimum
1388 * values. If the server list has been walked three times
1389 * in a row without errors, the TTL will be doubled. This will
1390 * be done repeatedly until the maximum value is reached
1391 * or passed. If passed, the maximum value will be used.
1392 * If any time a server is found to be down/bad, either
1393 * after another server list walk or informed by libsldap via
1394 * the GETLDAPSERVER door calls, the TTL will be set to half
1395 * of its value, again repeatedly, but no less than the minimum
1396 * value. Also, at any time, if all the servers on the list
1397 * are found to be down/bad, the TTL will be set to minimum,
1398 * so that a "no-server" refresh loop should be entered to try
1399 * to find a good server as soon as possible. The caller
1400 * could check the no_gd_server flag for this situation.
1401 * The maximum and minimum values are initialized when the input
1402 * refresh_ttl is set to zero, this should occur during
1403 * ldap_cachemgr startup or every time the server list is
1404 * recreated after the configuration profile is refreshed
1405 * from an LDAP server. The maximum is set to the value of
1406 * the NS_LDAP_CACHETTL parameter (configuration profile
1407 * refresh TTL), but if it is zero (never refreshed) or can
1408 * not be retrieved, the maximum is set to the macro
1409 * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1410 * set to REFRESHTTL_MIN, which is the TCP connection timeout
1411 * (tcptimeout) set via the LDAP API ldap_set_option()
1412 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1413 * This accounts for the maximum possible timeout value for an
1414 * LDAP TCP connect call.The first refresh TTL, initial value of
1415 * refresh_ttl, will be set to the smaller of the two,
1416 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1417 * The idea is to have a low starting value and have the value
1418 * stay low if the network/server is unstable, but eventually
1419 * the value will move up to maximum and stay there if the
1420 * network/server is stable.
1423 getldap_set_refresh_ttl(server_info_t
*head
, int *refresh_ttl
,
1426 #define REFRESHTTL_REGULAR 600
1427 #define REFRESHTTL_MAX 43200
1428 /* tcptimeout is in milliseconds */
1429 #define REFRESHTTL_MIN (tcptimeout/1000) + 10
1430 #define UP_REFRESH_TTL_NUM 2
1432 static mutex_t refresh_mutex
;
1433 static int refresh_ttl_max
= 0;
1434 static int refresh_ttl_min
= 0;
1435 static int num_walked_ok
= 0;
1436 int num_servers
= 0;
1437 int num_good_servers
= 0;
1438 int num_prev_good_servers
= 0;
1439 server_info_t
*info
;
1441 /* allow one thread at a time */
1442 (void) mutex_lock(&refresh_mutex
);
1444 if (current_admin
.debug_level
>= DBG_ALL
) {
1445 logit("getldap_set_refresh_ttl()...\n");
1448 if (!head
|| !refresh_ttl
|| !no_gd_server
) {
1449 logit("getldap_set_refresh_ttl: head is "
1450 "NULL or refresh_ttl is NULL or "
1451 "no_gd_server is NULL");
1452 (void) mutex_unlock(&refresh_mutex
);
1455 *no_gd_server
= FALSE
;
1458 * init max. min. TTLs if first time through or a fresh one
1460 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1461 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1462 "seconds\n", *refresh_ttl
);
1464 if (*refresh_ttl
== 0) {
1467 * init cache manager server list TTL:
1469 * init the min. TTL to
1470 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1472 refresh_ttl_min
= REFRESHTTL_MIN
;
1475 * try to set the max. TTL to
1476 * configuration refresh TTL (NS_LDAP_CACHETTL),
1477 * if error (-1), or never refreshed (0),
1478 * set it to REFRESHTTL_MAX (12 hours)
1480 refresh_ttl_max
= getldap_get_cacheTTL();
1481 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1482 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1483 "seconds\n", *refresh_ttl
);
1484 logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1485 "min ttl is %d seconds\n",
1486 refresh_ttl_max
, refresh_ttl_min
);
1488 if (refresh_ttl_max
<= 0)
1489 refresh_ttl_max
= REFRESHTTL_MAX
;
1490 else if (refresh_ttl_max
< refresh_ttl_min
)
1491 refresh_ttl_max
= refresh_ttl_min
;
1494 * init the first TTL to the smaller of the two:
1495 * REFRESHTTL_REGULAR ( 10 minutes),
1496 * (refresh_ttl_max + refresh_ttl_min)/2
1498 *refresh_ttl
= REFRESHTTL_REGULAR
;
1499 if (*refresh_ttl
> (refresh_ttl_max
+ refresh_ttl_min
) / 2)
1500 *refresh_ttl
= (refresh_ttl_max
+ refresh_ttl_min
) / 2;
1501 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1502 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1503 "seconds\n", *refresh_ttl
);
1504 logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1505 "min ttl is %d seconds\n",
1506 refresh_ttl_max
, refresh_ttl_min
);
1511 * get the servers statistics:
1512 * number of servers on list
1513 * number of good servers on list
1514 * number of pevious good servers on list
1516 for (info
= head
; info
; info
= info
->next
) {
1518 (void) mutex_lock(&info
->mutex
[0]);
1519 if (info
->sinfo
[0].server_status
== INFO_SERVER_UP
)
1522 * Server's previous status could be UNKNOWN
1523 * only between the very first and second
1524 * refresh. Treat that UNKNOWN status as up
1526 if (info
->sinfo
[0].prev_server_status
1527 == INFO_SERVER_UP
||
1528 info
->sinfo
[0].prev_server_status
1529 == INFO_SERVER_UNKNOWN
)
1530 num_prev_good_servers
++;
1531 (void) mutex_unlock(&info
->mutex
[0]);
1535 * if the server list is walked three times in a row
1536 * without problems, double the refresh TTL but no more
1537 * than the max. refresh TTL
1539 if (num_good_servers
== num_servers
) {
1541 if (num_walked_ok
> UP_REFRESH_TTL_NUM
) {
1543 *refresh_ttl
= *refresh_ttl
* 2;
1544 if (*refresh_ttl
> refresh_ttl_max
)
1545 *refresh_ttl
= refresh_ttl_max
;
1549 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1550 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1551 "seconds\n", *refresh_ttl
);
1553 } else if (num_good_servers
== 0) {
1555 * if no good server found,
1556 * set refresh TTL to miminum
1558 *refresh_ttl
= refresh_ttl_min
;
1559 *no_gd_server
= TRUE
;
1561 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1562 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1563 "seconds\n", *refresh_ttl
);
1565 } else if (num_prev_good_servers
> num_good_servers
) {
1567 * if more down/bad servers found,
1568 * decrease the refresh TTL by half
1569 * but no less than the min. refresh TTL
1571 *refresh_ttl
= *refresh_ttl
/ 2;
1572 if (*refresh_ttl
< refresh_ttl_min
)
1573 *refresh_ttl
= refresh_ttl_min
;
1575 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1576 "seconds\n", *refresh_ttl
);
1580 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1581 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1584 (void) mutex_unlock(&refresh_mutex
);
1589 getldap_serverInfo_op(info_op_t op
, char *input
, char **output
)
1592 static rwlock_t info_lock
= DEFAULTRWLOCK
;
1593 static rwlock_t info_lock_old
= DEFAULTRWLOCK
;
1594 static mutex_t info_mutex
;
1595 static cond_t info_cond
;
1596 static int creating
= FALSE
;
1597 static int refresh_ttl
= 0;
1598 static int sec_to_refresh
= 0;
1599 static int in_no_server_mode
= FALSE
;
1601 static server_info_t
*serverInfo
= NULL
;
1602 static server_info_t
*serverInfo_old
= NULL
;
1603 server_info_t
*serverInfo_1
;
1605 int err
, no_server_good
= FALSE
;
1606 int server_removed
= FALSE
;
1607 int fall_thru
= FALSE
;
1608 static struct timespec timeout
;
1609 struct timespec new_timeout
;
1611 static time_t prev_refresh
= 0, next_refresh
= 0;
1612 ns_server_status_t changed
= 0;
1614 if (current_admin
.debug_level
>= DBG_ALL
) {
1615 logit("getldap_serverInfo_op()...\n");
1618 case INFO_OP_CREATE
:
1619 if (current_admin
.debug_level
>= DBG_ALL
) {
1620 logit("operation is INFO_OP_CREATE...\n");
1624 * indicate that the server info is being
1625 * (re)created, so that the refresh thread
1626 * will not refresh the info list right
1627 * after the list got (re)created
1629 (void) mutex_lock(&info_mutex
);
1630 is_creating
= creating
;
1632 (void) mutex_unlock(&info_mutex
);
1637 * create an empty info list
1639 (void) getldap_init_serverInfo(&serverInfo_1
);
1641 * exit if list not created
1643 if (serverInfo_1
== NULL
) {
1644 (void) mutex_lock(&info_mutex
);
1646 (void) mutex_unlock(&info_mutex
);
1650 * make the new server info available:
1651 * use writer lock here, so that the switch
1652 * is done after all the reader locks have
1655 (void) rw_wrlock(&info_lock
);
1656 serverInfo
= serverInfo_1
;
1658 * if this is the first time
1659 * the server list is being created,
1660 * (i.e., serverInfo_old is NULL)
1661 * make the old list same as the new
1662 * so the GETSERVER code can do its work
1664 if (serverInfo_old
== NULL
)
1665 serverInfo_old
= serverInfo_1
;
1666 (void) rw_unlock(&info_lock
);
1669 * fill the new info list
1671 (void) rw_rdlock(&info_lock
);
1672 /* reset bind time (tcptimeout) */
1673 (void) getldap_set_serverInfo(serverInfo
, 1, INFO_OP_CREATE
);
1675 (void) mutex_lock(&info_mutex
);
1677 * set cache manager server list TTL,
1678 * set refresh_ttl to zero to indicate a fresh one
1681 (void) getldap_set_refresh_ttl(serverInfo
,
1682 &refresh_ttl
, &no_server_good
);
1683 sec_to_refresh
= refresh_ttl
;
1685 /* statistics: previous refresh time */
1686 if (gettimeofday(&tp
, NULL
) == 0)
1687 prev_refresh
= tp
.tv_sec
;
1692 * if no server found or available,
1693 * tell the server info refresh thread
1694 * to start the "no-server" refresh loop
1695 * otherwise reset the in_no_server_mode flag
1697 if (no_server_good
) {
1699 in_no_server_mode
= TRUE
;
1701 in_no_server_mode
= FALSE
;
1703 * awake the sleeping refresh thread
1705 (void) cond_signal(&info_cond
);
1707 (void) mutex_unlock(&info_mutex
);
1708 (void) rw_unlock(&info_lock
);
1711 * delete the old server info
1713 (void) rw_wrlock(&info_lock_old
);
1714 if (serverInfo_old
!= serverInfo
)
1715 (void) getldap_destroy_serverInfo(serverInfo_old
);
1717 * serverInfo_old needs to be the same as
1719 * it will be used by GETSERVER processing.
1721 serverInfo_old
= serverInfo
;
1722 (void) rw_unlock(&info_lock_old
);
1724 case INFO_OP_DELETE
:
1725 if (current_admin
.debug_level
>= DBG_ALL
) {
1726 logit("operation is INFO_OP_DELETE...\n");
1729 * use writer lock here, so that the delete would
1730 * not start until all the reader locks have
1733 (void) rw_wrlock(&info_lock
);
1735 (void) getldap_destroy_serverInfo(serverInfo
);
1737 (void) rw_unlock(&info_lock
);
1739 case INFO_OP_REFRESH
:
1740 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1741 logit("operation is INFO_OP_REFRESH...\n");
1744 * if server info is currently being
1745 * (re)created, do nothing
1747 (void) mutex_lock(&info_mutex
);
1748 is_creating
= creating
;
1749 (void) mutex_unlock(&info_mutex
);
1753 (void) rw_rdlock(&info_lock
);
1755 /* do not reset bind time (tcptimeout) */
1756 (void) getldap_set_serverInfo(serverInfo
, 0,
1759 (void) mutex_lock(&info_mutex
);
1761 /* statistics: previous refresh time */
1762 if (gettimeofday(&tp
, NULL
) == 0)
1763 prev_refresh
= tp
.tv_sec
;
1765 * set cache manager server list TTL
1767 (void) getldap_set_refresh_ttl(serverInfo
,
1768 &refresh_ttl
, &no_server_good
);
1770 * if no good server found,
1771 * tell the server info refresh thread
1772 * to start the "no-server" refresh loop
1773 * otherwise reset the in_no_server_mode flag
1775 if (no_server_good
) {
1776 in_no_server_mode
= TRUE
;
1779 in_no_server_mode
= FALSE
;
1780 sec_to_refresh
= refresh_ttl
;
1782 if (current_admin
.debug_level
>=
1783 DBG_SERVER_LIST_REFRESH
) {
1784 logit("getldap_serverInfo_op("
1786 " seconds refresh: %d second(s)....\n",
1789 (void) mutex_unlock(&info_mutex
);
1791 (void) rw_unlock(&info_lock
);
1794 case INFO_OP_REFRESH_WAIT
:
1795 if (current_admin
.debug_level
>= DBG_SERVER_LIST_REFRESH
) {
1796 logit("operation is INFO_OP_REFRESH_WAIT...\n");
1798 (void) cond_init(&info_cond
, 0, NULL
);
1799 (void) mutex_lock(&info_mutex
);
1801 while (err
!= ETIME
) {
1804 * if need to go into the "no-server" refresh
1805 * loop, set timout value to
1806 * REFRESH_DELAY_WHEN_NO_SERVER
1808 if (sec_to_refresh
== 0) {
1809 sec_to_refresh
= refresh_ttl
;
1810 timeout
.tv_sec
= time(NULL
) +
1811 REFRESH_DELAY_WHEN_NO_SERVER
;
1812 sleeptime
= REFRESH_DELAY_WHEN_NO_SERVER
;
1813 if (current_admin
.debug_level
>=
1814 DBG_SERVER_LIST_REFRESH
) {
1815 logit("getldap_serverInfo_op("
1816 "INFO_OP_REFRESH_WAIT):"
1817 " entering no-server "
1818 "refresh loop...\n");
1821 timeout
.tv_sec
= time(NULL
) + sec_to_refresh
;
1822 sleeptime
= sec_to_refresh
;
1824 timeout
.tv_nsec
= 0;
1826 /* statistics: next refresh time */
1827 next_refresh
= timeout
.tv_sec
;
1829 if (current_admin
.debug_level
>=
1830 DBG_SERVER_LIST_REFRESH
) {
1831 logit("getldap_serverInfo_op("
1832 "INFO_OP_REFRESH_WAIT):"
1833 " about to sleep for %d second(s)...\n",
1836 err
= cond_timedwait(&info_cond
,
1837 &info_mutex
, &timeout
);
1839 (void) cond_destroy(&info_cond
);
1840 (void) mutex_unlock(&info_mutex
);
1842 case INFO_OP_GETSERVER
:
1843 if (current_admin
.debug_level
>= DBG_ALL
) {
1844 logit("operation is INFO_OP_GETSERVER...\n");
1848 * GETSERVER processing always use
1849 * serverInfo_old to retrieve server infomation.
1850 * serverInfo_old is equal to serverInfo
1851 * most of the time, except when a new
1852 * server list is being created.
1853 * This is why the check for is_creating
1856 (void) rw_rdlock(&info_lock_old
);
1858 if (serverInfo_old
== NULL
) {
1859 (void) rw_unlock(&info_lock_old
);
1862 (void) getldap_get_serverInfo(serverInfo_old
,
1863 input
, output
, &server_removed
);
1864 (void) rw_unlock(&info_lock_old
);
1867 * Return here and let remove server thread do its job in
1868 * another thread. It executes INFO_OP_REMOVESERVER code later.
1877 case INFO_OP_REMOVESERVER
:
1879 * INFO_OP_GETSERVER and INFO_OP_REMOVESERVER share the
1880 * following code except (!fall thru) part.
1884 * if server info is currently being
1885 * (re)created, do nothing
1888 (void) mutex_lock(&info_mutex
);
1889 is_creating
= creating
;
1890 (void) mutex_unlock(&info_mutex
);
1895 if (current_admin
.debug_level
>= DBG_ALL
)
1896 logit("operation is INFO_OP_REMOVESERVER...\n");
1897 (void) rw_rdlock(&info_lock_old
);
1898 changed
= set_server_status(input
, serverInfo_old
);
1899 (void) rw_unlock(&info_lock_old
);
1901 create_buf_and_notify(input
, changed
);
1907 * set cache manager server list TTL if necessary
1909 if (*output
== NULL
|| changed
) {
1910 (void) rw_rdlock(&info_lock
);
1911 (void) mutex_lock(&info_mutex
);
1913 (void) getldap_set_refresh_ttl(serverInfo
,
1914 &refresh_ttl
, &no_server_good
);
1917 * if no good server found, need to go into
1918 * the "no-server" refresh loop
1919 * to find a server as soon as possible
1920 * otherwise reset the in_no_server_mode flag
1922 if (no_server_good
) {
1924 * if already in no-server mode,
1927 if (in_no_server_mode
== FALSE
) {
1929 in_no_server_mode
= TRUE
;
1930 (void) cond_signal(&info_cond
);
1932 (void) mutex_unlock(&info_mutex
);
1933 (void) rw_unlock(&info_lock
);
1936 in_no_server_mode
= FALSE
;
1937 sec_to_refresh
= refresh_ttl
;
1940 * if the refresh thread will be timed out
1941 * longer than refresh_ttl seconds,
1942 * wake it up to make it wait on the new
1945 new_timeout
.tv_sec
= time(NULL
) + refresh_ttl
;
1946 if (new_timeout
.tv_sec
< timeout
.tv_sec
)
1947 (void) cond_signal(&info_cond
);
1949 (void) mutex_unlock(&info_mutex
);
1950 (void) rw_unlock(&info_lock
);
1953 case INFO_OP_GETSTAT
:
1954 if (current_admin
.debug_level
>= DBG_ALL
) {
1955 logit("operation is INFO_OP_GETSTAT...\n");
1958 (void) rw_rdlock(&info_lock
);
1960 (void) getldap_get_server_stat(serverInfo
,
1961 output
, &prev_refresh
, &next_refresh
);
1963 (void) rw_unlock(&info_lock
);
1966 logit("getldap_serverInfo_op(): "
1967 "invalid operation code (%d).\n", op
);
1971 return (NS_LDAP_SUCCESS
);
1975 getldap_serverInfo_refresh()
1979 if (current_admin
.debug_level
>= DBG_ALL
) {
1980 logit("getldap_serverInfo_refresh()...\n");
1983 /* create the server info list */
1984 (void) getldap_serverInfo_op(INFO_OP_CREATE
, NULL
, NULL
);
1988 * the operation INFO_OP_REFRESH_WAIT
1989 * causes this thread to wait until
1990 * it is time to do refresh,
1991 * see getldap_serverInfo_op() for details
1993 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT
, NULL
, NULL
);
1994 (void) getldap_serverInfo_op(INFO_OP_REFRESH
, NULL
, NULL
);
1999 getldap_getserver(LineBuf
*config_info
, ldap_call_t
*in
)
2003 if (current_admin
.debug_level
>= DBG_ALL
) {
2004 logit("getldap_getserver()...\n");
2007 config_info
->len
= 0;
2009 /* make sure the request is valid */
2010 req
[0] = (in
->ldap_u
.servername
)[0];
2011 if ((req
[0] != '\0') &&
2012 (strcmp(req
, NS_CACHE_NEW
) != 0) &&
2013 (strcmp(req
, NS_CACHE_NORESP
) != 0) &&
2014 (strcmp(req
, NS_CACHE_NEXT
) != 0) &&
2015 (strcmp(req
, NS_CACHE_WRITE
) != 0)) {
2019 (void) getldap_serverInfo_op(INFO_OP_GETSERVER
,
2020 in
->ldap_u
.domainname
, &config_info
->str
);
2022 if (config_info
->str
== NULL
)
2025 config_info
->len
= strlen(config_info
->str
) + 1;
2027 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2031 ptr
= strstr(config_info
->str
, DOORLINESEP
);
2035 logit("getldap_getserver: got server %s\n",
2039 logit("getldap_getserver: Missing %s."
2040 " Internal error\n", DOORLINESEP
);
2045 getldap_get_cacheData(LineBuf
*config_info
, ldap_call_t
*in
)
2048 int datatype
= CACHE_MAP_UNKNOWN
;
2050 if (current_admin
.debug_level
>= DBG_ALL
) {
2051 logit("getldap_get_cacheData()...\n");
2054 config_info
->len
= 0;
2055 config_info
->str
= NULL
;
2057 /* make sure the request is valid */
2058 if (strncmp(in
->ldap_u
.servername
,
2059 NS_CACHE_DN2DOMAIN
, strlen(NS_CACHE_DN2DOMAIN
)) == 0)
2060 datatype
= CACHE_MAP_DN2DOMAIN
;
2062 if (datatype
== CACHE_MAP_UNKNOWN
)
2065 instr
= strstr(in
->ldap_u
.servername
, DOORLINESEP
);
2068 instr
+= strlen(DOORLINESEP
);
2072 (void) getldap_cache_op(CACHE_OP_FIND
, datatype
,
2073 instr
, &config_info
->str
);
2075 if (config_info
->str
!= NULL
) {
2076 config_info
->len
= strlen(config_info
->str
) + 1;
2081 getldap_set_cacheData(ldap_call_t
*in
)
2083 char *instr1
= NULL
;
2084 char *instr2
= NULL
;
2085 int datatype
= CACHE_MAP_UNKNOWN
;
2088 if (current_admin
.debug_level
>= DBG_ALL
) {
2089 logit("getldap_set_cacheData()...\n");
2092 /* make sure the request is valid */
2093 if (strncmp(in
->ldap_u
.servername
,
2094 NS_CACHE_DN2DOMAIN
, strlen(NS_CACHE_DN2DOMAIN
)) == 0)
2095 datatype
= CACHE_MAP_DN2DOMAIN
;
2097 if (datatype
== CACHE_MAP_UNKNOWN
)
2100 instr1
= strstr(in
->ldap_u
.servername
, DOORLINESEP
);
2104 instr1
+= strlen(DOORLINESEP
);
2105 if (*instr1
== '\0')
2107 instr2
= strstr(instr1
, DOORLINESEP
);
2111 instr2
+= strlen(DOORLINESEP
);
2112 if (*instr2
== '\0')
2115 rc
= getldap_cache_op(CACHE_OP_ADD
, datatype
,
2117 if (rc
!= NS_LDAP_SUCCESS
)
2124 getldap_get_cacheStat(LineBuf
*stat_info
)
2126 char *foutstr
= NULL
;
2127 char *soutstr
= NULL
;
2128 char *coutstr
= NULL
;
2131 if (current_admin
.debug_level
>= DBG_ALL
) {
2132 logit("getldap_get_cacheStat()...\n");
2135 stat_info
->str
= NULL
;
2138 /* get refersh statisitcs */
2139 (void) getldap_get_refresh_stat(&foutstr
);
2140 if (foutstr
== NULL
)
2143 /* get server statisitcs */
2144 (void) getldap_serverInfo_op(INFO_OP_GETSTAT
, NULL
, &soutstr
);
2145 if (soutstr
== NULL
) {
2149 /* get cache data statisitcs */
2150 (void) getldap_cache_op(CACHE_OP_GETSTAT
, 0, NULL
, &coutstr
);
2151 if (coutstr
== NULL
) {
2157 infoSize
= strlen(foutstr
) + strlen(soutstr
) + strlen(coutstr
) + 3;
2158 stat_info
->str
= calloc(infoSize
, sizeof (char));
2159 if (stat_info
->str
!= NULL
) {
2160 (void) strncpy(stat_info
->str
,
2162 strlen(foutstr
) + 1);
2163 (void) strncat(stat_info
->str
,
2165 strlen(soutstr
) + 1);
2166 (void) strncat(stat_info
->str
,
2168 strlen(coutstr
) + 1);
2169 stat_info
->len
= infoSize
;
2178 checkupdate(int sighup
)
2182 (void) rw_wrlock(&ldap_lock
);
2184 (void) rw_unlock(&ldap_lock
);
2186 return (value
== TRUE
);
2191 update_from_profile(int *change_status
)
2193 ns_ldap_result_t
*result
= NULL
;
2194 char searchfilter
[BUFSIZ
];
2195 ns_ldap_error_t
*error
;
2197 void **paramVal
= NULL
;
2198 ns_config_t
*ptr
= NULL
;
2199 char *profile
= NULL
;
2200 char errstr
[MAXERROR
];
2202 if (current_admin
.debug_level
>= DBG_ALL
) {
2203 logit("update_from_profile....\n");
2206 (void) rw_wrlock(&ldap_lock
);
2207 sighup_update
= FALSE
;
2208 (void) rw_unlock(&ldap_lock
);
2210 if ((rc
= __ns_ldap_getParam(NS_LDAP_PROFILE_P
,
2211 ¶mVal
, &error
)) != NS_LDAP_SUCCESS
) {
2212 if (error
!= NULL
&& error
->message
!= NULL
)
2213 logit("Error: Unable to profile name: %s\n",
2218 __ns_ldap_err2str(rc
, &tmp
);
2219 logit("Error: Unable to profile name: %s\n",
2222 (void) __ns_ldap_freeParam(¶mVal
);
2223 (void) __ns_ldap_freeError(&error
);
2227 if (paramVal
&& *paramVal
)
2228 profile
= strdup((char *)*paramVal
);
2229 (void) __ns_ldap_freeParam(¶mVal
);
2231 if (profile
== NULL
) {
2235 (void) snprintf(searchfilter
, BUFSIZ
, _PROFILE_FILTER
,
2236 _PROFILE1_OBJECTCLASS
, _PROFILE2_OBJECTCLASS
, profile
);
2238 if ((rc
= __ns_ldap_list(_PROFILE_CONTAINER
,
2239 (const char *)searchfilter
, NULL
,
2241 &result
, &error
, NULL
, NULL
)) != NS_LDAP_SUCCESS
) {
2244 * Is profile name the DEFAULTCONFIGNAME?
2245 * syslog Warning, otherwise syslog error.
2247 if (strcmp(profile
, DEFAULTCONFIGNAME
) == 0) {
2249 "Ignoring attempt to refresh nonexistent "
2250 "default profile: %s.\n",
2252 logit("Ignoring attempt to refresh nonexistent "
2253 "default profile: %s.\n",
2255 } else if ((error
!= NULL
) &&
2256 (error
->message
!= NULL
)) {
2258 "Error: Unable to refresh profile:%s:"
2259 " %s\n", profile
, error
->message
);
2260 logit("Error: Unable to refresh profile:"
2261 "%s:%s\n", profile
, error
->message
);
2263 syslog(LOG_ERR
, "Error: Unable to refresh "
2264 "from profile:%s. (error=%d)\n",
2266 logit("Error: Unable to refresh from profile "
2267 "%s (error=%d)\n", profile
, rc
);
2270 (void) __ns_ldap_freeError(&error
);
2271 (void) __ns_ldap_freeResult(&result
);
2278 } while (checkupdate(sighup_update
) == TRUE
);
2280 (void) rw_wrlock(&ldap_lock
);
2282 ptr
= __ns_ldap_make_config(result
);
2283 (void) __ns_ldap_freeResult(&result
);
2286 logit("Error: __ns_ldap_make_config failed.\n");
2287 (void) rw_unlock(&ldap_lock
);
2292 * cross check the config parameters
2294 if (__s_api_crosscheck(ptr
, errstr
, B_TRUE
) == NS_SUCCESS
) {
2296 * reset the local profile TTL
2298 if (ptr
->paramList
[NS_LDAP_CACHETTL_P
].ns_pc
)
2299 current_admin
.ldap_stat
.ldap_ttl
=
2300 atol(ptr
->paramList
[NS_LDAP_CACHETTL_P
].ns_pc
);
2302 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2303 logit("update_from_profile: reset profile TTL to %d"
2305 current_admin
.ldap_stat
.ldap_ttl
);
2306 logit("update_from_profile: expire time %ld "
2308 ptr
->paramList
[NS_LDAP_EXP_P
].ns_tm
);
2311 /* set ptr as current_config if the config is changed */
2312 chg_test_config_change(ptr
, change_status
);
2315 __s_api_destroy_config(ptr
);
2316 logit("Error: downloaded profile failed to pass "
2317 "crosscheck (%s).\n", errstr
);
2318 syslog(LOG_ERR
, "ldap_cachemgr: %s", errstr
);
2321 (void) rw_unlock(&ldap_lock
);
2329 ns_ldap_error_t
*error
;
2331 ldap_get_chg_cookie_t cookie
;
2333 if (current_admin
.debug_level
>= DBG_ALL
) {
2334 logit("getldap_init()...\n");
2337 (void) __ns_ldap_setServer(TRUE
);
2339 (void) rw_wrlock(&ldap_lock
);
2340 if ((error
= __ns_ldap_LoadConfiguration()) != NULL
) {
2341 logit("Error: Unable to read '%s': %s\n",
2342 NSCONFIGFILE
, error
->message
);
2343 (void) fprintf(stderr
,
2344 gettext("\nError: Unable to read '%s': %s\n"),
2345 NSCONFIGFILE
, error
->message
);
2346 __ns_ldap_freeError(&error
);
2347 (void) rw_unlock(&ldap_lock
);
2350 (void) rw_unlock(&ldap_lock
);
2352 if (gettimeofday(&tp
, NULL
) == 0) {
2353 /* statistics: previous refresh time */
2354 prev_refresh_time
= tp
.tv_sec
;
2357 /* initialize the data cache */
2358 (void) getldap_cache_op(CACHE_OP_CREATE
,
2361 cookie
.mgr_pid
= getpid();
2363 chg_config_cookie_set(&cookie
);
2368 perform_update(void)
2370 ns_ldap_error_t
*error
= NULL
;
2375 void **paramVal
= NULL
;
2376 ns_ldap_self_gssapi_config_t config
;
2378 if (current_admin
.debug_level
>= DBG_ALL
) {
2379 logit("perform_update()...\n");
2382 (void) __ns_ldap_setServer(TRUE
);
2384 if (gettimeofday(&tp
, NULL
) != 0)
2387 rc
= __ns_ldap_getParam(NS_LDAP_CACHETTL_P
, ¶mVal
, &error
);
2389 if (rc
== NS_LDAP_SUCCESS
&& paramVal
!= NULL
) {
2390 current_admin
.ldap_stat
.ldap_ttl
= atol((char *)*paramVal
);
2394 (void) __ns_ldap_freeError(&error
);
2396 if (paramVal
!= NULL
)
2397 (void) __ns_ldap_freeParam(¶mVal
);
2399 if (current_admin
.debug_level
>= DBG_PROFILE_REFRESH
) {
2400 logit("perform_update: current profile TTL is %d seconds\n",
2401 current_admin
.ldap_stat
.ldap_ttl
);
2404 if (current_admin
.ldap_stat
.ldap_ttl
> 0) {
2406 * set the profile TTL parameter, just
2407 * in case that the downloading of
2408 * the profile from server would fail
2412 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2413 * It depends on NS_LDAP_CACHETTL_P to set it's value
2414 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2416 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2417 * downloaded from the server, so is NS_LDAP_EXP_P.
2419 buf
[19] = '\0'; /* null terminated the buffer */
2420 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P
,
2421 lltostr((long long)current_admin
.ldap_stat
.ldap_ttl
,
2423 &error
) != NS_LDAP_SUCCESS
) {
2424 logit("Error: __ns_ldap_setParam failed, status: %d "
2425 "message: %s\n", error
->status
, error
->message
);
2426 (void) __ns_ldap_freeError(&error
);
2430 (void) rw_wrlock(&ldap_lock
);
2431 sighup_update
= FALSE
;
2432 (void) rw_unlock(&ldap_lock
);
2435 rc
= update_from_profile(&changed
);
2437 logit("Error: Unable to update from profile\n");
2439 } while (checkupdate(sighup_update
) == TRUE
);
2445 * recreate the server info list
2448 (void) getldap_serverInfo_op(INFO_OP_CREATE
, NULL
, NULL
);
2450 /* flush the data cache */
2451 (void) getldap_cache_op(CACHE_OP_DELETE
,
2454 /* statistics: previous refresh time */
2455 prev_refresh_time
= tp
.tv_sec
;
2457 rc1
= __ns_ldap_self_gssapi_config(&config
);
2458 if (rc1
== NS_LDAP_SUCCESS
) {
2459 if (config
!= NS_LDAP_SELF_GSSAPI_CONFIG_NONE
) {
2460 rc1
= __ns_ldap_check_all_preq(0, 0, 0, config
, &error
);
2461 (void) __ns_ldap_freeError(&error
);
2462 if (rc1
!= NS_LDAP_SUCCESS
) {
2463 logit("Error: Check on self credential "
2464 "prerquesites failed: %d\n",
2470 logit("Error: Failed to get self credential configuration %d\n",
2478 (void) rw_rdlock(&ldap_lock
);
2479 if (((error
= __ns_ldap_DumpConfiguration(NSCONFIGREFRESH
)) != NULL
) ||
2480 ((error
= __ns_ldap_DumpConfiguration(NSCREDREFRESH
)) != NULL
)) {
2481 logit("Error: __ns_ldap_DumpConfiguration failed, "
2482 "status: %d message: %s\n", error
->status
, error
->message
);
2483 __ns_ldap_freeError(&error
);
2484 (void) rw_unlock(&ldap_lock
);
2487 if (rename(NSCONFIGREFRESH
, NSCONFIGFILE
) != 0) {
2488 logit("Error: unlink failed - errno: %s\n", strerror(errno
));
2489 syslog(LOG_ERR
, "Unable to refresh profile, LDAP configuration"
2490 "files not written");
2491 (void) rw_unlock(&ldap_lock
);
2494 if (rename(NSCREDREFRESH
, NSCREDFILE
) != 0) {
2496 * We probably have inconsistent configuration at this point.
2497 * If we were to create a backup file and rename it here, that
2498 * operation might also fail. Consequently there is no safe way
2501 logit("Error: unlink failed - errno: %s\n", strerror(errno
));
2502 syslog(LOG_ERR
, "Unable to refresh profile consistently, "
2503 "LDAP configuration files inconsistent");
2504 (void) rw_unlock(&ldap_lock
);
2508 (void) rw_unlock(&ldap_lock
);
2514 struct timespec timeout
;
2518 void **paramVal
= NULL
;
2519 ns_ldap_error_t
*errorp
;
2520 int always
= 1, err
;
2525 if (current_admin
.debug_level
>= DBG_ALL
) {
2526 logit("getldap_refresh()...\n");
2530 * wait for an available server
2532 while (sig_done
== 0) {
2533 (void) mutex_lock(&sig_mutex
);
2534 sig_done
= signal_done
;
2535 (void) mutex_unlock(&sig_mutex
);
2538 (void) __ns_ldap_setServer(TRUE
);
2540 dbg_level
= current_admin
.debug_level
;
2541 (void) rw_rdlock(&ldap_lock
);
2542 sleeptime
= current_admin
.ldap_stat
.ldap_ttl
;
2543 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2544 logit("getldap_refresh: current profile TTL is %d "
2545 "seconds\n", current_admin
.ldap_stat
.ldap_ttl
);
2547 if (gettimeofday(&tp
, NULL
) == 0) {
2548 if ((__ns_ldap_getParam(NS_LDAP_EXP_P
,
2549 ¶mVal
, &errorp
) == NS_LDAP_SUCCESS
) &&
2551 (char *)*paramVal
!= NULL
) {
2553 expire
= atol((char *)*paramVal
);
2554 (void) __ns_ldap_freeParam(¶mVal
);
2558 (void) rw_unlock(&ldap_lock
);
2559 (void) cond_init(&cond
,
2561 (void) mutex_lock(&sighuplock
);
2564 timeout
.tv_nsec
= 0;
2566 DBG_PROFILE_REFRESH
) {
2567 logit("getldap_refresh:"
2569 " for %d seconds\n",
2572 err
= cond_reltimedwait(&cond
,
2573 &sighuplock
, &timeout
);
2574 (void) cond_destroy(&cond
);
2575 (void) mutex_unlock(
2579 * getldap_revalidate(),
2580 * do update right away
2587 * configuration failed
2596 sleeptime
= expire
- tp
.tv_sec
;
2597 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2598 logit("getldap_refresh: expire "
2599 "time = %ld\n", expire
);
2606 (void) rw_unlock(&ldap_lock
);
2609 * if this is the first time downloading
2610 * the profile or expire time already passed,
2611 * do not wait, do update
2613 if (first_time
== 0 && sleeptime
> 0) {
2614 if (dbg_level
>= DBG_PROFILE_REFRESH
) {
2615 logit("getldap_refresh: (2)about to sleep "
2616 "for %d seconds\n", sleeptime
);
2618 (void) cond_init(&cond
, 0, NULL
);
2619 (void) mutex_lock(&sighuplock
);
2620 timeout
.tv_sec
= sleeptime
;
2621 timeout
.tv_nsec
= 0;
2622 err
= cond_reltimedwait(&cond
,
2623 &sighuplock
, &timeout
);
2624 (void) cond_destroy(&cond
);
2625 (void) mutex_unlock(&sighuplock
);
2628 * if load concfiguration failed
2638 getldap_revalidate()
2640 if (current_admin
.debug_level
>= DBG_ALL
) {
2641 logit("getldap_revalidate()...\n");
2643 /* block signal SIGHUP */
2644 (void) sighold(SIGHUP
);
2646 /* now awake the sleeping refresh thread */
2647 (void) cond_signal(&cond
);
2649 /* release signal SIGHUP */
2650 (void) sigrelse(SIGHUP
);
2655 getldap_admincred(LineBuf
*config_info
, ldap_call_t
*in
)
2657 ns_ldap_error_t
*error
;
2658 ldap_config_out_t
*cout
;
2661 if (current_admin
.debug_level
>= DBG_ALL
) {
2662 logit("getldap_admincred()...\n");
2664 /* check privileges */
2665 if (is_root_or_all_privs("GETADMINCRED", &uc
) == 0) {
2666 logit("admin credential requested by a non-root and no ALL "
2667 "privilege user not allowed");
2668 config_info
->str
= NULL
;
2669 config_info
->len
= 0;
2671 (void) rw_rdlock(&ldap_lock
);
2672 if ((error
= __ns_ldap_LoadDoorInfo(config_info
,
2673 in
->ldap_u
.domainname
, NULL
, 1)) != NULL
) {
2674 if (error
!= NULL
&& error
->message
!= NULL
)
2675 logit("Error: ldap_lookup: %s\n",
2677 (void) __ns_ldap_freeError(&error
);
2679 config_info
->str
= NULL
;
2680 config_info
->len
= 0;
2682 /* set change cookie */
2683 cout
= (ldap_config_out_t
*)config_info
->str
;
2685 cout
->cookie
= chg_config_cookie_get();
2686 (void) rw_unlock(&ldap_lock
);
2691 getldap_lookup(LineBuf
*config_info
, ldap_call_t
*in
)
2693 ns_ldap_error_t
*error
;
2694 ldap_config_out_t
*cout
;
2696 if (current_admin
.debug_level
>= DBG_ALL
) {
2697 logit("getldap_lookup()...\n");
2699 (void) rw_rdlock(&ldap_lock
);
2700 if ((error
= __ns_ldap_LoadDoorInfo(config_info
,
2701 in
->ldap_u
.domainname
, NULL
, 0)) != NULL
) {
2702 if (error
!= NULL
&& error
->message
!= NULL
)
2703 logit("Error: ldap_lookup: %s\n", error
->message
);
2704 (void) __ns_ldap_freeError(&error
);
2706 config_info
->str
= NULL
;
2707 config_info
->len
= 0;
2709 /* set change cookie */
2710 cout
= (ldap_config_out_t
*)config_info
->str
;
2712 cout
->cookie
= chg_config_cookie_get();
2713 (void) rw_unlock(&ldap_lock
);
2716 * It creates the header and data stream to be door returned and notify
2717 * chg_get_statusChange() threads.
2718 * This is called after all getldap_get_rootDSE() threads are joined.
2721 test_server_change(server_info_t
*head
)
2723 server_info_t
*info
;
2724 int len
= 0, num
= 0, ds_len
= 0, new_len
= 0, tlen
= 0;
2725 char *tmp_buf
= NULL
, *ptr
= NULL
, *status
= NULL
;
2726 ldap_get_change_out_t
*cout
;
2728 ds_len
= strlen(DOORLINESEP
);
2730 for (info
= head
; info
; info
= info
->next
) {
2731 (void) mutex_lock(&info
->mutex
[0]);
2732 if (info
->sinfo
[0].change
!= 0) {
2733 /* "9.9.9.9|NS_SERVER_CHANGE_UP|" */
2734 len
+= 2 * ds_len
+ strlen(info
->sinfo
[0].addr
) +
2735 strlen(NS_SERVER_CHANGE_UP
);
2738 (void) mutex_unlock(&info
->mutex
[0]);
2746 tlen
= sizeof (ldap_get_change_out_t
) - sizeof (int) + len
;
2747 if ((tmp_buf
= malloc(tlen
)) == NULL
)
2750 cout
= (ldap_get_change_out_t
*)tmp_buf
;
2751 cout
->type
= NS_STATUS_CHANGE_TYPE_SERVER
;
2752 /* cout->cookie is set by chg_notify_statusChange */
2753 cout
->server_count
= num
;
2754 cout
->data_size
= len
;
2756 /* Create IP|UP or DOWN|IP|UP or DOWN| ... */
2759 for (info
= head
; info
; info
= info
->next
) {
2760 (void) mutex_lock(&info
->mutex
[0]);
2761 if (info
->sinfo
[0].change
== 0) {
2762 (void) mutex_unlock(&info
->mutex
[0]);
2766 if (info
->sinfo
[0].change
== NS_SERVER_UP
)
2767 status
= NS_SERVER_CHANGE_UP
;
2768 else if (info
->sinfo
[0].change
== NS_SERVER_DOWN
)
2769 status
= NS_SERVER_CHANGE_DOWN
;
2771 syslog(LOG_WARNING
, gettext("Bad change value %d"),
2772 info
->sinfo
[0].change
);
2773 (void) mutex_unlock(&info
->mutex
[0]);
2778 if ((snprintf(ptr
, new_len
, "%s%s%s%s",
2779 info
->sinfo
[0].addr
, DOORLINESEP
,
2780 status
, DOORLINESEP
)) >= new_len
) {
2781 (void) mutex_unlock(&info
->mutex
[0]);
2784 new_len
-= strlen(ptr
);
2787 (void) mutex_unlock(&info
->mutex
[0]);
2789 (void) chg_notify_statusChange(tmp_buf
);
2792 * It creates the header and data stream to be door returned and notify
2793 * chg_get_statusChange() threads.
2794 * This is called in removing server case.
2797 create_buf_and_notify(char *input
, ns_server_status_t st
)
2799 rm_svr_t
*rms
= (rm_svr_t
*)input
;
2800 char *tmp_buf
, *ptr
, *status
;
2802 ldap_get_change_out_t
*cout
;
2804 /* IP|UP or DOWN| */
2805 len
= 2 * strlen(DOORLINESEP
) + strlen(rms
->addr
) +
2806 strlen(NS_SERVER_CHANGE_UP
) + 1;
2808 tlen
= sizeof (ldap_get_change_out_t
) - sizeof (int) + len
;
2810 if ((tmp_buf
= malloc(tlen
)) == NULL
)
2813 cout
= (ldap_get_change_out_t
*)tmp_buf
;
2814 cout
->type
= NS_STATUS_CHANGE_TYPE_SERVER
;
2815 /* cout->cookie is set by chg_notify_statusChange */
2816 cout
->server_count
= 1;
2817 cout
->data_size
= len
;
2819 /* Create IP|DOWN| */
2821 if (st
== NS_SERVER_UP
)
2822 status
= NS_SERVER_CHANGE_UP
;
2823 else if (st
== NS_SERVER_DOWN
)
2824 status
= NS_SERVER_CHANGE_DOWN
;
2826 (void) snprintf(ptr
, len
, "%s%s%s%s",
2827 rms
->addr
, DOORLINESEP
, status
, DOORLINESEP
);
2829 (void) chg_notify_statusChange(tmp_buf
);
2834 * Return: 0 server is down, 1 server is up
2837 contact_server(char *addr
)
2839 char *rootDSE
= NULL
;
2840 ns_ldap_error_t
*error
= NULL
;
2843 if (__ns_ldap_getRootDSE(addr
, &rootDSE
, &error
,
2844 SA_ALLOW_FALLBACK
) != NS_LDAP_SUCCESS
) {
2845 if (current_admin
.debug_level
>= DBG_ALL
)
2846 logit("get rootDSE %s failed. %s", addr
,
2847 error
->message
? error
->message
: "");
2854 (void) __ns_ldap_freeError(&error
);
2860 * The thread is spawned to do contact_server() so it won't be blocking
2861 * getldap_serverInfo_op(INFO_OP_GETSERVER, ...) case.
2862 * After contact_server() is done, it calls
2863 * getldap_serverInfo_op(INFO_OP_REMOVESERVER, ...) to return to the remaining
2864 * program flow. It's meant to maintain the original program flow yet be
2865 * non-blocking when it's contacting server.
2868 remove_server_thread(void *arg
)
2870 char *addr
= (char *)arg
, *out
= NULL
;
2874 up
= contact_server(addr
);
2879 (void) getldap_serverInfo_op(INFO_OP_REMOVESERVER
, (char *)&rms
, &out
);
2887 * addr is allocated and is freed by remove_server_thread
2888 * It starts a thread to contact server and remove server to avoid long wait
2892 remove_server(char *addr
)
2894 if (thr_create(NULL
, 0, remove_server_thread
,
2895 (void *)addr
, THR_BOUND
|THR_DETACHED
, NULL
) != 0) {
2897 syslog(LOG_ERR
, "thr_create failed for remove_server_thread");
2901 * Compare the server_status and mark it up or down accordingly.
2902 * This is called in removing server case.
2904 static ns_server_status_t
2905 set_server_status(char *input
, server_info_t
*head
)
2907 rm_svr_t
*rms
= (rm_svr_t
*)input
;
2908 ns_server_status_t changed
= 0;
2909 server_info_t
*info
;
2911 for (info
= head
; info
!= NULL
; info
= info
->next
) {
2912 (void) mutex_lock(&info
->mutex
[0]);
2913 if (strcmp(info
->sinfo
[0].addr
, rms
->addr
) == 0) {
2914 if (info
->sinfo
[0].server_status
== INFO_SERVER_UP
&&
2916 info
->sinfo
[0].prev_server_status
=
2917 info
->sinfo
[0].server_status
;
2918 info
->sinfo
[0].server_status
=
2920 info
->sinfo
[0].change
= NS_SERVER_DOWN
;
2921 changed
= NS_SERVER_DOWN
;
2923 } else if (info
->sinfo
[0].server_status
==
2924 INFO_SERVER_ERROR
&& rms
->up
== TRUE
) {
2926 * It should be INFO_SERVER_UP, but check here
2928 info
->sinfo
[0].prev_server_status
=
2929 info
->sinfo
[0].server_status
;
2930 info
->sinfo
[0].server_status
=
2932 info
->sinfo
[0].change
= NS_SERVER_UP
;
2933 changed
= NS_SERVER_UP
;
2935 (void) mutex_unlock(&info
->mutex
[0]);
2938 (void) mutex_unlock(&info
->mutex
[0]);
2941 /* ldap_cachemgr -g option looks up [1] */
2942 (void) mutex_lock(&info
->mutex
[1]);
2943 info
->sinfo
[1].prev_server_status
=
2944 info
->sinfo
[1].server_status
;
2945 if (changed
== NS_SERVER_DOWN
)
2946 info
->sinfo
[1].server_status
= INFO_SERVER_ERROR
;
2947 else if (changed
== NS_SERVER_UP
)
2948 info
->sinfo
[1].server_status
= INFO_SERVER_UP
;
2949 (void) mutex_unlock(&info
->mutex
[1]);