1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 *
24 * Copyright 2018 Joyent, Inc.
25 */
26
27 #include <assert.h>
28 #include <errno.h>
29 #include <memory.h>
30 #include <signal.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <libintl.h>
35 #include <syslog.h>
36 #include <sys/door.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <synch.h>
42 #include <pthread.h>
43 #include <unistd.h>
44 #include <lber.h>
45 #include <ldap.h>
46 #include <ctype.h> /* tolower */
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <ucred.h>
51 #include "cachemgr.h"
52 #include "solaris-priv.h"
53 #include "ns_connmgmt.h"
54
55 static rwlock_t ldap_lock = DEFAULTRWLOCK;
56 static int sighup_update = FALSE;
57 extern admin_t current_admin;
58
59 extern int is_root_or_all_privs(char *dc_str, ucred_t **ucp);
60
61 /* variables used for SIGHUP wakeup on sleep */
62 static mutex_t sighuplock;
63 static cond_t cond;
64
65 /* refresh time statistics */
66 static time_t prev_refresh_time = 0;
67
68 /* variables used for signaling parent process */
69 static mutex_t sig_mutex;
70 static int signal_done = FALSE;
71
72 /* TCP connection timeout (in milliseconds) */
73 static int tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
74
75 #ifdef SLP
76 extern int use_slp;
77 #endif /* SLP */
78
79 /* nis domain information */
80 #define _NIS_FILTER "objectclass=nisDomainObject"
81 #define _NIS_DOMAIN "nisdomain"
82
83 #define CACHESLEEPTIME 600
84 /*
85 * server list refresh delay when in "no server" mode
86 * (1 second)
87 */
88 #define REFRESH_DELAY_WHEN_NO_SERVER 1
89
90 typedef enum {
91 INFO_OP_CREATE = 0,
92 INFO_OP_DELETE = 1,
93 INFO_OP_REFRESH = 2,
94 INFO_OP_REFRESH_WAIT = 3,
95 INFO_OP_GETSERVER = 4,
96 INFO_OP_GETSTAT = 5,
97 INFO_OP_REMOVESERVER = 6
98 } info_op_t;
99
100 typedef enum {
101 INFO_RW_UNKNOWN = 0,
102 INFO_RW_READONLY = 1,
103 INFO_RW_WRITEABLE = 2
104 } info_rw_t;
105
106 typedef enum {
107 INFO_SERVER_JUST_INITED = -1,
108 INFO_SERVER_UNKNOWN = 0,
109 INFO_SERVER_CONNECTING = 1,
110 INFO_SERVER_UP = 2,
111 INFO_SERVER_ERROR = 3,
112 INFO_SERVER_REMOVED = 4
113 } info_server_t;
114
115 typedef enum {
116 INFO_STATUS_UNKNOWN = 0,
117 INFO_STATUS_ERROR = 1,
118 INFO_STATUS_NEW = 2,
119 INFO_STATUS_OLD = 3
120 } info_status_t;
121
122 typedef enum {
123 CACHE_OP_CREATE = 0,
124 CACHE_OP_DELETE = 1,
125 CACHE_OP_FIND = 2,
126 CACHE_OP_ADD = 3,
127 CACHE_OP_GETSTAT = 4
128 } cache_op_t;
129
130 typedef enum {
131 CACHE_MAP_UNKNOWN = 0,
132 CACHE_MAP_DN2DOMAIN = 1
133 } cache_type_t;
134
135 typedef struct server_info_ext {
136 char *addr;
137 char *hostname;
138 char *rootDSE_data;
139 char *errormsg;
140 info_rw_t type;
141 info_server_t server_status;
142 info_server_t prev_server_status;
143 info_status_t info_status;
144 ns_server_status_t change;
145 } server_info_ext_t;
146
147 typedef struct server_info {
148 struct server_info *next;
149 mutex_t mutex[2]; /* 0: current copy lock */
150 /* 1: update copy lock */
151 server_info_ext_t sinfo[2]; /* 0: current, 1: update copy */
152 } server_info_t;
153
154 typedef struct cache_hash {
155 cache_type_t type;
156 char *from;
157 char *to;
158 struct cache_hash *next;
159 } cache_hash_t;
160
161 /*
162 * The status of a server to be removed. It can be up or down.
163 */
164 typedef struct rm_svr {
165 char *addr;
166 int up; /* 1: up, 0: down */
167 } rm_svr_t;
168
169 static int getldap_destroy_serverInfo(server_info_t *head);
170 static void test_server_change(server_info_t *head);
171 static void remove_server(char *addr);
172 static ns_server_status_t set_server_status(char *input, server_info_t *head);
173 static void create_buf_and_notify(char *input, ns_server_status_t st);
174
175 /*
176 * Load configuration
177 * The code was in signal handler getldap_revalidate
178 * It's moved out of the handler because it could cause deadlock
179 * return: 1 SUCCESS
180 * 0 FAIL
181 */
182 static int
load_config(void)183 load_config(void)
184 {
185 ns_ldap_error_t *error;
186 int rc = 1;
187
188 (void) __ns_ldap_setServer(TRUE);
189
190 (void) rw_wrlock(&ldap_lock);
191 if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
192 logit("Error: Unable to read '%s': %s\n",
193 NSCONFIGFILE, error->message);
194 __ns_ldap_freeError(&error);
195 rc = 0; /* FAIL */
196 } else
197 sighup_update = TRUE;
198
199 (void) rw_unlock(&ldap_lock);
200
201 return (rc);
202 }
203
204 /*
205 * Calculate a hash for a string
206 * Based on elf_hash algorithm, hash is case insensitive
207 * Uses tolower instead of _tolower because of I18N
208 */
209
210 static unsigned long
getldap_hash(const char * str)211 getldap_hash(const char *str)
212 {
213 unsigned int hval = 0;
214
215 while (*str) {
216 unsigned int g;
217
218 hval = (hval << 4) + tolower(*str++);
219 if ((g = (hval & 0xf0000000)) != 0)
220 hval ^= g >> 24;
221 hval &= ~g;
222 }
223 return ((unsigned long)hval);
224 }
225
226 /*
227 * Remove a hash table entry.
228 * This function expects a lock in place when called.
229 */
230
231 static cache_hash_t *
getldap_free_hash(cache_hash_t * p)232 getldap_free_hash(cache_hash_t *p)
233 {
234 cache_hash_t *next;
235
236 p->type = CACHE_MAP_UNKNOWN;
237 if (p->from)
238 free(p->from);
239 if (p->to)
240 free(p->to);
241 next = p->next;
242 p->next = NULL;
243 free(p);
244 return (next);
245 }
246
247 /*
248 * Scan a hash table hit for a matching hash entry.
249 * This function expects a lock in place when called.
250 */
251 static cache_hash_t *
getldap_scan_hash(cache_type_t type,char * from,cache_hash_t * idx)252 getldap_scan_hash(cache_type_t type, char *from, cache_hash_t *idx)
253 {
254 while (idx) {
255 if (idx->type == type &&
256 strcasecmp(from, idx->from) == 0) {
257 return (idx);
258 }
259 idx = idx->next;
260 }
261 return ((cache_hash_t *)NULL);
262 }
263
264 /*
265 * Format and return the cache data statistics
266 */
267 static int
getldap_get_cacheData_stat(int max,int current,char ** output)268 getldap_get_cacheData_stat(int max, int current, char **output)
269 {
270 #define C_HEADER0 "Cache data information: "
271 #define C_HEADER1 " Maximum cache entries: "
272 #define C_HEADER2 " Number of cache entries: "
273 int hdr0_len = strlen(gettext(C_HEADER0));
274 int hdr1_len = strlen(gettext(C_HEADER1));
275 int hdr2_len = strlen(gettext(C_HEADER2));
276 int len;
277
278 if (current_admin.debug_level >= DBG_ALL) {
279 logit("getldap_get_cacheData_stat()...\n");
280 }
281
282 *output = NULL;
283
284 len = hdr0_len + hdr1_len + hdr2_len +
285 3 * strlen(DOORLINESEP) + 21;
286 *output = malloc(len);
287 if (*output == NULL)
288 return (-1);
289
290 (void) snprintf(*output, len, "%s%s%s%10d%s%s%10d%s",
291 gettext(C_HEADER0), DOORLINESEP,
292 gettext(C_HEADER1), max, DOORLINESEP,
293 gettext(C_HEADER2), current, DOORLINESEP);
294
295 return (NS_LDAP_SUCCESS);
296 }
297
298 static int
getldap_cache_op(cache_op_t op,cache_type_t type,char * from,char ** to)299 getldap_cache_op(cache_op_t op, cache_type_t type,
300 char *from, char **to)
301 {
302 #define CACHE_HASH_MAX 257
303 #define CACHE_HASH_MAX_ENTRY 256
304 static cache_hash_t *hashTbl[CACHE_HASH_MAX];
305 cache_hash_t *next, *idx, *newp;
306 unsigned long hash;
307 static rwlock_t cache_lock = DEFAULTRWLOCK;
308 int i;
309 static int entry_num = 0;
310
311 if (current_admin.debug_level >= DBG_ALL) {
312 logit("getldap_cache_op()...\n");
313 }
314 switch (op) {
315 case CACHE_OP_CREATE:
316 if (current_admin.debug_level >= DBG_ALL) {
317 logit("operation is CACHE_OP_CREATE...\n");
318 }
319 (void) rw_wrlock(&cache_lock);
320
321 for (i = 0; i < CACHE_HASH_MAX; i++) {
322 hashTbl[i] = NULL;
323 }
324 entry_num = 0;
325
326 (void) rw_unlock(&cache_lock);
327 break;
328
329 case CACHE_OP_DELETE:
330 if (current_admin.debug_level >= DBG_ALL) {
331 logit("operation is CACHE_OP_DELETE...\n");
332 }
333 (void) rw_wrlock(&cache_lock);
334
335 for (i = 0; i < CACHE_HASH_MAX; i++) {
336 next = hashTbl[i];
337 while (next != NULL) {
338 next = getldap_free_hash(next);
339 }
340 hashTbl[i] = NULL;
341 }
342 entry_num = 0;
343
344 (void) rw_unlock(&cache_lock);
345 break;
346
347 case CACHE_OP_ADD:
348 if (current_admin.debug_level >= DBG_ALL) {
349 logit("operation is CACHE_OP_ADD...\n");
350 }
351 if (from == NULL || to == NULL || *to == NULL)
352 return (-1);
353 hash = getldap_hash(from) % CACHE_HASH_MAX;
354 (void) rw_wrlock(&cache_lock);
355 idx = hashTbl[hash];
356 /*
357 * replace old "to" value with new one
358 * if an entry with same "from"
359 * already exists
360 */
361 if (idx) {
362 newp = getldap_scan_hash(type, from, idx);
363 if (newp) {
364 free(newp->to);
365 newp->to = strdup(*to);
366 (void) rw_unlock(&cache_lock);
367 return (NS_LDAP_SUCCESS);
368 }
369 }
370
371 if (entry_num > CACHE_HASH_MAX_ENTRY) {
372 (void) rw_unlock(&cache_lock);
373 return (-1);
374 }
375
376 newp = (cache_hash_t *)malloc(sizeof (cache_hash_t));
377 if (newp == NULL) {
378 (void) rw_unlock(&cache_lock);
379 return (NS_LDAP_MEMORY);
380 }
381 newp->type = type;
382 newp->from = strdup(from);
383 newp->to = strdup(*to);
384 newp->next = idx;
385 hashTbl[hash] = newp;
386 entry_num++;
387 (void) rw_unlock(&cache_lock);
388 break;
389
390 case CACHE_OP_FIND:
391 if (current_admin.debug_level >= DBG_ALL) {
392 logit("operation is CACHE_OP_FIND...\n");
393 }
394 if (from == NULL || to == NULL)
395 return (-1);
396 *to = NULL;
397 hash = getldap_hash(from) % CACHE_HASH_MAX;
398 (void) rw_rdlock(&cache_lock);
399 idx = hashTbl[hash];
400 idx = getldap_scan_hash(type, from, idx);
401 if (idx)
402 *to = strdup(idx->to);
403 (void) rw_unlock(&cache_lock);
404 if (idx == NULL)
405 return (-1);
406 break;
407
408 case CACHE_OP_GETSTAT:
409 if (current_admin.debug_level >= DBG_ALL) {
410 logit("operation is CACHE_OP_GETSTAT...\n");
411 }
412 if (to == NULL)
413 return (-1);
414
415 return (getldap_get_cacheData_stat(CACHE_HASH_MAX_ENTRY,
416 entry_num, to));
417 break;
418
419 default:
420 logit("getldap_cache_op(): "
421 "invalid operation code (%d).\n", op);
422 return (-1);
423 break;
424 }
425 return (NS_LDAP_SUCCESS);
426 }
427 /*
428 * Function: sync_current_with_update_copy
429 *
430 * This function syncs up the 2 sinfo copies in info.
431 *
432 * The 2 copies are identical most of time.
433 * The update copy(sinfo[1]) could be different when
434 * getldap_serverInfo_refresh thread is refreshing the server list
435 * and calls getldap_get_rootDSE to update info. getldap_get_rootDSE
436 * calls sync_current_with_update_copy to sync up 2 copies before thr_exit.
437 * The calling sequence is
438 * getldap_serverInfo_refresh->
439 * getldap_get_serverInfo_op(INFO_OP_CREATE,...)->
440 * getldap_set_serverInfo->
441 * getldap_get_rootDSE
442 *
443 * The original server_info_t has one copy of server info. When libsldap
444 * makes door call GETLDAPSERVER to get the server info and getldap_get_rootDSE
445 * is updating the server info, it would hit a unprotected window in
446 * getldap_rootDSE. The door call will not get server info and libsldap
447 * fails at making ldap connection.
448 *
449 * The new server_info_t provides GETLDAPSERVER thread with a current
450 * copy(sinfo[0]). getldap_get_rootDSE only works on the update copy(sinfo[1])
451 * and syncs up 2 copies before thr_exit. This will close the window in
452 * getldap_get_rootDSE.
453 *
454 */
455 static void
sync_current_with_update_copy(server_info_t * info)456 sync_current_with_update_copy(server_info_t *info)
457 {
458 if (current_admin.debug_level >= DBG_ALL) {
459 logit("sync_current_with_update_copy()...\n");
460 }
461
462 (void) mutex_lock(&info->mutex[1]);
463 (void) mutex_lock(&info->mutex[0]);
464
465 if (info->sinfo[1].server_status == INFO_SERVER_UP &&
466 info->sinfo[0].server_status != INFO_SERVER_UP)
467 info->sinfo[1].change = NS_SERVER_UP;
468 else if (info->sinfo[1].server_status != INFO_SERVER_UP &&
469 info->sinfo[0].server_status == INFO_SERVER_UP)
470 info->sinfo[1].change = NS_SERVER_DOWN;
471 else
472 info->sinfo[1].change = 0;
473
474
475 /* free memory in current copy first */
476 if (info->sinfo[0].addr)
477 free(info->sinfo[0].addr);
478 info->sinfo[0].addr = NULL;
479
480 if (info->sinfo[0].hostname)
481 free(info->sinfo[0].hostname);
482 info->sinfo[0].hostname = NULL;
483
484 if (info->sinfo[0].rootDSE_data)
485 free(info->sinfo[0].rootDSE_data);
486 info->sinfo[0].rootDSE_data = NULL;
487
488 if (info->sinfo[0].errormsg)
489 free(info->sinfo[0].errormsg);
490 info->sinfo[0].errormsg = NULL;
491
492 /*
493 * make current and update copy identical
494 */
495 info->sinfo[0] = info->sinfo[1];
496
497 /*
498 * getldap_get_server_stat() reads the update copy sinfo[1]
499 * so it can't be freed or nullified yet at this point.
500 *
501 * The sinfo[0] and sinfo[1] have identical string pointers.
502 * strdup the strings to avoid the double free problem.
503 * The strings of sinfo[1] are freed in
504 * getldap_get_rootDSE() and the strings of sinfo[0]
505 * are freed earlier in this function. If the pointers are the
506 * same, they will be freed twice.
507 */
508 if (info->sinfo[1].addr)
509 info->sinfo[0].addr = strdup(info->sinfo[1].addr);
510 if (info->sinfo[1].hostname)
511 info->sinfo[0].hostname = strdup(info->sinfo[1].hostname);
512 if (info->sinfo[1].rootDSE_data)
513 info->sinfo[0].rootDSE_data =
514 strdup(info->sinfo[1].rootDSE_data);
515 if (info->sinfo[1].errormsg)
516 info->sinfo[0].errormsg = strdup(info->sinfo[1].errormsg);
517
518 (void) mutex_unlock(&info->mutex[0]);
519 (void) mutex_unlock(&info->mutex[1]);
520
521 }
522
523 static void *
getldap_get_rootDSE(void * arg)524 getldap_get_rootDSE(void *arg)
525 {
526 server_info_t *serverInfo = (server_info_t *)arg;
527 char *rootDSE;
528 int exitrc = NS_LDAP_SUCCESS;
529 pid_t ppid;
530 int server_found = 0;
531 char errmsg[MAXERROR];
532 ns_ldap_return_code rc;
533 ns_ldap_error_t *error = NULL;
534
535 if (current_admin.debug_level >= DBG_ALL) {
536 logit("getldap_get_rootDSE()....\n");
537 }
538
539 /* initialize the server info element */
540 (void) mutex_lock(&serverInfo->mutex[1]);
541 serverInfo->sinfo[1].type = INFO_RW_UNKNOWN;
542 serverInfo->sinfo[1].info_status =
543 INFO_STATUS_UNKNOWN;
544 /*
545 * When the sever list is refreshed over and over,
546 * this function is called each time it is refreshed.
547 * The previous server status of the update copy(sinfo[1])
548 * is the status of the current copy
549 */
550 (void) mutex_lock(&serverInfo->mutex[0]);
551 serverInfo->sinfo[1].prev_server_status =
552 serverInfo->sinfo[0].server_status;
553 (void) mutex_unlock(&serverInfo->mutex[0]);
554
555 serverInfo->sinfo[1].server_status =
556 INFO_SERVER_UNKNOWN;
557 if (serverInfo->sinfo[1].rootDSE_data)
558 free(serverInfo->sinfo[1].rootDSE_data);
559 serverInfo->sinfo[1].rootDSE_data = NULL;
560 if (serverInfo->sinfo[1].errormsg)
561 free(serverInfo->sinfo[1].errormsg);
562 serverInfo->sinfo[1].errormsg = NULL;
563 (void) mutex_unlock(&serverInfo->mutex[1]);
564
565 (void) mutex_lock(&serverInfo->mutex[1]);
566 serverInfo->sinfo[1].server_status = INFO_SERVER_CONNECTING;
567 (void) mutex_unlock(&serverInfo->mutex[1]);
568
569 /*
570 * WARNING: anon_fallback == 1 (last argument) means that when
571 * __ns_ldap_getRootDSE is unable to bind using the configured
572 * credentials, it will try to fall back to using anonymous, non-SSL
573 * mode of operation.
574 *
575 * This is for backward compatibility reasons - we might have machines
576 * in the field with broken configuration (invalid credentials) and we
577 * don't want them to be disturbed.
578 */
579 if (rc = __ns_ldap_getRootDSE(serverInfo->sinfo[1].addr,
580 &rootDSE,
581 &error,
582 SA_ALLOW_FALLBACK) != NS_LDAP_SUCCESS) {
583 (void) mutex_lock(&serverInfo->mutex[1]);
584 serverInfo->sinfo[1].server_status = INFO_SERVER_ERROR;
585 serverInfo->sinfo[1].info_status = INFO_STATUS_ERROR;
586 if (error && error->message) {
587 serverInfo->sinfo[1].errormsg = strdup(error->message);
588 } else {
589 (void) snprintf(errmsg, sizeof (errmsg), "%s %s "
590 "(rc = %d)", gettext("Can not get the root DSE from"
591 " server"), serverInfo->sinfo[1].addr, rc);
592 serverInfo->sinfo[1].errormsg = strdup(errmsg);
593 }
594
595 if (error != NULL) {
596 (void) __ns_ldap_freeError(&error);
597 }
598
599 if (current_admin.debug_level >= DBG_ALL) {
600 logit("getldap_get_rootDSE: %s.\n",
601 serverInfo->sinfo[1].errormsg);
602 }
603 (void) mutex_unlock(&serverInfo->mutex[1]);
604 /*
605 * sync sinfo copies in the serverInfo.
606 * protected by mutex
607 */
608 sync_current_with_update_copy(serverInfo);
609 thr_exit((void *) -1);
610 }
611
612 (void) mutex_lock(&serverInfo->mutex[1]);
613
614 /* assume writeable, i.e., can do modify */
615 serverInfo->sinfo[1].type = INFO_RW_WRITEABLE;
616 serverInfo->sinfo[1].server_status = INFO_SERVER_UP;
617 serverInfo->sinfo[1].info_status = INFO_STATUS_NEW;
618 /* remove the last DOORLINESEP */
619 *(rootDSE+strlen(rootDSE)-1) = '\0';
620 serverInfo->sinfo[1].rootDSE_data = rootDSE;
621
622 server_found = 1;
623
624 (void) mutex_unlock(&serverInfo->mutex[1]);
625
626 /*
627 * sync sinfo copies in the serverInfo.
628 * protected by mutex
629 */
630 sync_current_with_update_copy(serverInfo);
631 /*
632 * signal that the ldap_cachemgr parent process
633 * should exit now, if it is still waiting
634 */
635 (void) mutex_lock(&sig_mutex);
636 if (signal_done == FALSE && server_found) {
637 ppid = getppid();
638 (void) kill(ppid, SIGUSR1);
639 if (current_admin.debug_level >= DBG_ALL) {
640 logit("getldap_get_rootDSE(): "
641 "SIGUSR1 signal sent to "
642 "parent process(%ld).\n", ppid);
643 }
644 signal_done = TRUE;
645 }
646 (void) mutex_unlock(&sig_mutex);
647
648 thr_exit((void *) exitrc);
649
650 return ((void *) NULL);
651 }
652
653 static int
getldap_init_serverInfo(server_info_t ** head)654 getldap_init_serverInfo(server_info_t **head)
655 {
656 char **servers = NULL;
657 int rc = 0, i, exitrc = NS_LDAP_SUCCESS;
658 ns_ldap_error_t *errorp = NULL;
659 server_info_t *info, *tail = NULL;
660
661 *head = NULL;
662 if (current_admin.debug_level >= DBG_ALL) {
663 logit("getldap_init_serverInfo()...\n");
664 }
665 rc = __s_api_getServers(&servers, &errorp);
666
667 if (rc != NS_LDAP_SUCCESS) {
668 logit("getldap_init_serverInfo: "
669 "__s_api_getServers failed.\n");
670 if (errorp)
671 __ns_ldap_freeError(&errorp);
672 return (-1);
673 }
674 for (i = 0; servers[i] != NULL; i++) {
675 info = (server_info_t *)calloc(1, sizeof (server_info_t));
676 if (info == NULL) {
677 logit("getldap_init_serverInfo: "
678 "not enough memory.\n");
679 exitrc = NS_LDAP_MEMORY;
680 break;
681 }
682 if (i == 0) {
683 *head = info;
684 tail = info;
685 } else {
686 tail->next = info;
687 tail = info;
688 }
689
690 info->sinfo[0].addr = strdup(servers[i]);
691 if (info->sinfo[0].addr == NULL) {
692 logit("getldap_init_serverInfo: "
693 "not enough memory.\n");
694 exitrc = NS_LDAP_MEMORY;
695 break;
696 }
697 info->sinfo[1].addr = strdup(servers[i]);
698 if (info->sinfo[1].addr == NULL) {
699 logit("getldap_init_serverInfo: "
700 "not enough memory.\n");
701 exitrc = NS_LDAP_MEMORY;
702 break;
703 }
704
705 info->sinfo[0].type = INFO_RW_UNKNOWN;
706 info->sinfo[1].type = INFO_RW_UNKNOWN;
707 info->sinfo[0].info_status = INFO_STATUS_UNKNOWN;
708 info->sinfo[1].info_status = INFO_STATUS_UNKNOWN;
709 info->sinfo[0].server_status = INFO_SERVER_UNKNOWN;
710 info->sinfo[1].server_status = INFO_SERVER_UNKNOWN;
711
712 /*
713 * Assume at startup or after the configuration
714 * profile is refreshed, all servers are good.
715 */
716 info->sinfo[0].prev_server_status =
717 INFO_SERVER_UP;
718 info->sinfo[1].prev_server_status =
719 INFO_SERVER_UP;
720 info->sinfo[0].hostname = NULL;
721 info->sinfo[1].hostname = NULL;
722 info->sinfo[0].rootDSE_data = NULL;
723 info->sinfo[1].rootDSE_data = NULL;
724 info->sinfo[0].errormsg = NULL;
725 info->sinfo[1].errormsg = NULL;
726 info->next = NULL;
727 }
728 __s_api_free2dArray(servers);
729 if (exitrc != NS_LDAP_SUCCESS) {
730 if (head && *head) {
731 (void) getldap_destroy_serverInfo(*head);
732 *head = NULL;
733 }
734 }
735 return (exitrc);
736 }
737
738 static int
getldap_destroy_serverInfo(server_info_t * head)739 getldap_destroy_serverInfo(server_info_t *head)
740 {
741 server_info_t *info, *next;
742
743 if (current_admin.debug_level >= DBG_ALL) {
744 logit("getldap_destroy_serverInfo()...\n");
745 }
746
747 if (head == NULL) {
748 logit("getldap_destroy_serverInfo: "
749 "invalid serverInfo list.\n");
750 return (-1);
751 }
752
753 for (info = head; info; info = next) {
754 if (info->sinfo[0].addr)
755 free(info->sinfo[0].addr);
756 if (info->sinfo[1].addr)
757 free(info->sinfo[1].addr);
758 if (info->sinfo[0].hostname)
759 free(info->sinfo[0].hostname);
760 if (info->sinfo[1].hostname)
761 free(info->sinfo[1].hostname);
762 if (info->sinfo[0].rootDSE_data)
763 free(info->sinfo[0].rootDSE_data);
764 if (info->sinfo[1].rootDSE_data)
765 free(info->sinfo[1].rootDSE_data);
766 if (info->sinfo[0].errormsg)
767 free(info->sinfo[0].errormsg);
768 if (info->sinfo[1].errormsg)
769 free(info->sinfo[1].errormsg);
770 next = info->next;
771 free(info);
772 }
773 return (NS_LDAP_SUCCESS);
774 }
775
776 static int
getldap_set_serverInfo(server_info_t * head,int reset_bindtime,info_op_t op)777 getldap_set_serverInfo(server_info_t *head, int reset_bindtime, info_op_t op)
778 {
779 server_info_t *info;
780 int atleast1 = 0;
781 thread_t *tid;
782 int num_threads = 0, i, j;
783 void *status;
784 void **paramVal = NULL;
785 ns_ldap_error_t *error = NULL;
786
787 if (current_admin.debug_level >= DBG_ALL) {
788 logit("getldap_set_serverInfo()...\n");
789 }
790
791 if (head == NULL) {
792 logit("getldap_set_serverInfo: "
793 "invalid serverInfo list.\n");
794 return (-1);
795 }
796
797 /* Get the bind timeout value */
798 if (reset_bindtime == 1) {
799 tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000;
800 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P,
801 ¶mVal, &error);
802 if (paramVal != NULL && *paramVal != NULL) {
803 /* convert to milliseconds */
804 tcptimeout = **((int **)paramVal);
805 tcptimeout *= 1000;
806 (void) __ns_ldap_freeParam(¶mVal);
807 }
808 if (error)
809 (void) __ns_ldap_freeError(&error);
810 }
811
812 for (info = head; info; info = info->next)
813 num_threads++;
814
815 if (num_threads == 0) {
816 logit("getldap_set_serverInfo: "
817 "empty serverInfo list.\n");
818 return (-1);
819 }
820
821 tid = (thread_t *) calloc(1, sizeof (thread_t) * num_threads);
822 if (tid == NULL) {
823 logit("getldap_set_serverInfo: "
824 "No memory to create thread ID list.\n");
825 return (-1);
826 }
827
828 for (info = head, i = 0; info; info = info->next, i++) {
829 if (thr_create(NULL, 0,
830 (void *(*)(void*))getldap_get_rootDSE,
831 (void *)info, 0, &tid[i])) {
832 logit("getldap_set_serverInfo: "
833 "can not create thread %d.\n", i + 1);
834 for (j = 0; j < i; j++)
835 (void) thr_join(tid[j], NULL, NULL);
836 free(tid);
837 return (-1);
838 }
839 }
840
841 for (i = 0; i < num_threads; i++) {
842 if (thr_join(tid[i], NULL, &status) == 0) {
843 if ((int)status == NS_LDAP_SUCCESS)
844 atleast1 = 1;
845 }
846 }
847
848 free(tid);
849
850 if (op == INFO_OP_REFRESH)
851 test_server_change(head);
852 if (atleast1) {
853 return (NS_LDAP_SUCCESS);
854 } else
855 return (-1);
856 }
857
858 /*
859 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed
860 * to this function from getldap_serverInfo_op().
861 * input:
862 * a buffer containing an empty string (e.g., input[0]='\0';) or a string
863 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP,
864 * addr);
865 * where addr is the address of a server and
866 * req is one of the following:
867 * NS_CACHE_NEW: send a new server address, addr is ignored.
868 * NS_CACHE_NORESP: send the next one, remove addr from list.
869 * NS_CACHE_NEXT: send the next one, keep addr on list.
870 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same
871 * as NS_CACHE_NEXT.
872 * addrtype:
873 * NS_CACHE_ADDR_IP: return server address as is, this is default.
874 * NS_CACHE_ADDR_HOSTNAME: return both server address and its FQDN format,
875 * only self credential case requires such format.
876 * output:
877 * a buffer containing server info in the following format:
878 * serveraddress DOORLINESEP [ serveraddress FQDN DOORLINESEP ]
879 * [ attr=value [DOORLINESEP attr=value ]...]
880 * For example: ( here | used as DOORLINESEP for visual purposes)
881 * 1) simple bind and sasl/DIGEST-MD5 bind :
882 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL|
883 * supportedSASLmechanisms=GSSAPI
884 * 2) sasl/GSSAPI bind (self credential):
885 * 1.2.3.4|foo.sun.com|supportedControl=1.1.1.1|
886 * supportedSASLmechanisms=EXTERNAL|supportedSASLmechanisms=GSSAPI
887 * NOTE: caller should free this buffer when done using it
888 */
889 static int
getldap_get_serverInfo(server_info_t * head,char * input,char ** output,int * svr_removed)890 getldap_get_serverInfo(server_info_t *head, char *input,
891 char **output, int *svr_removed)
892 {
893 server_info_t *info = NULL;
894 server_info_t *server = NULL;
895 char *addr = NULL;
896 char *req = NULL;
897 char req_new[] = NS_CACHE_NEW;
898 char addr_type[] = NS_CACHE_ADDR_IP;
899 int matched = FALSE, len = 0, rc = 0;
900 char *ret_addr = NULL, *ret_addrFQDN = NULL;
901 char *new_addr = NULL;
902 pid_t pid;
903
904 if (current_admin.debug_level >= DBG_ALL) {
905 logit("getldap_get_serverInfo()...\n");
906 }
907
908 if (input == NULL || output == NULL) {
909 logit("getldap_get_serverInfo: "
910 "No input or output buffer.\n");
911 return (-1);
912 }
913
914 *output = NULL;
915 *svr_removed = FALSE;
916
917 if (head == NULL) {
918 logit("getldap_get_serverInfo: "
919 "invalid serverInfo list.\n");
920 return (-1);
921 }
922 /*
923 * parse the input string to get req and addr,
924 * if input is empty, i.e., input[0] == '\0',
925 * treat it as an NS_CACHE_NEW request
926 */
927 req = req_new;
928 if (input[0] != '\0') {
929 req = input;
930 /* Save addr type flag */
931 addr_type[0] = input[1];
932 input[strlen(NS_CACHE_NEW)] = '\0';
933 /* skip acion type flag, addr type flag and DOORLINESEP */
934 addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW)
935 + strlen(NS_CACHE_ADDR_IP);
936 }
937 /*
938 * if NS_CACHE_NEW,
939 * or the server info is new,
940 * starts from the
941 * beginning of the list
942 */
943 if ((strcmp(req, NS_CACHE_NEW) == 0) ||
944 (head->sinfo[0].info_status == INFO_STATUS_NEW))
945 matched = TRUE;
946 for (info = head; info; info = info->next) {
947 /*
948 * make sure the server info stays the same
949 * while the data is being processed
950 */
951
952 /*
953 * This function is called to get server info list
954 * and pass it back to door call clients.
955 * Access the current copy (sinfo[0]) to get such
956 * information
957 */
958 (void) mutex_lock(&info->mutex[0]);
959
960 if (matched == FALSE &&
961 strcmp(info->sinfo[0].addr, addr) == 0) {
962 matched = TRUE;
963 if (strcmp(req, NS_CACHE_NORESP) == 0) {
964 if (chg_is_called_from_nscd_or_peruser_nscd(
965 "REMOVE SERVER", &pid) == 0) {
966 (void) mutex_unlock(&info->mutex[0]);
967 if (current_admin.debug_level >=
968 DBG_ALL)
969 logit("Only nscd can remove "
970 "servers. pid %ld", pid);
971 continue;
972 }
973
974 /*
975 * if the information is new,
976 * give this server one more chance
977 */
978 if (info->sinfo[0].info_status ==
979 INFO_STATUS_NEW &&
980 info->sinfo[0].server_status ==
981 INFO_SERVER_UP) {
982 server = info;
983 break;
984 } else {
985 /*
986 * it is recommended that
987 * before removing the
988 * server from the list,
989 * the server should be
990 * contacted one more time
991 * to make sure that it is
992 * really unavailable.
993 * For now, just trust the client
994 * (i.e., the sldap library)
995 * that it knows what it is
996 * doing and would not try
997 * to mess up the server
998 * list.
999 */
1000 /*
1001 * Make a copy of addr to contact
1002 * it later. It's not doing it here
1003 * to avoid long wait and possible
1004 * recursion to contact an LDAP server.
1005 */
1006 new_addr = strdup(info->sinfo[0].addr);
1007 if (new_addr)
1008 remove_server(new_addr);
1009 *svr_removed = TRUE;
1010 (void) mutex_unlock(&info->mutex[0]);
1011 break;
1012 }
1013 } else {
1014 /*
1015 * req == NS_CACHE_NEXT or NS_CACHE_WRITE
1016 */
1017 (void) mutex_unlock(&info->mutex[0]);
1018 continue;
1019 }
1020 }
1021
1022 if (matched) {
1023 if (strcmp(req, NS_CACHE_WRITE) == 0) {
1024 if (info->sinfo[0].type ==
1025 INFO_RW_WRITEABLE &&
1026 info->sinfo[0].server_status ==
1027 INFO_SERVER_UP) {
1028 server = info;
1029 break;
1030 }
1031 } else if (info->sinfo[0].server_status ==
1032 INFO_SERVER_UP) {
1033 server = info;
1034 break;
1035 }
1036 }
1037
1038 (void) mutex_unlock(&info->mutex[0]);
1039 }
1040
1041 if (server) {
1042 if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) {
1043 /*
1044 * In SASL/GSSAPI case, a hostname is required for
1045 * Kerberos's service principal.
1046 * e.g.
1047 * ldap/foo.sun.com@SUN.COM
1048 */
1049 if (server->sinfo[0].hostname == NULL) {
1050 rc = __s_api_ip2hostname(server->sinfo[0].addr,
1051 &server->sinfo[0].hostname);
1052 if (rc != NS_LDAP_SUCCESS) {
1053 (void) mutex_unlock(&info->mutex[0]);
1054 return (rc);
1055 }
1056 if (current_admin.debug_level >= DBG_ALL) {
1057 logit("getldap_get_serverInfo: "
1058 "%s is converted to %s\n",
1059 server->sinfo[0].addr,
1060 server->sinfo[0].hostname);
1061 }
1062 }
1063 ret_addr = server->sinfo[0].addr;
1064 ret_addrFQDN = server->sinfo[0].hostname;
1065
1066 } else
1067 ret_addr = server->sinfo[0].addr;
1068
1069
1070 len = strlen(ret_addr) +
1071 strlen(server->sinfo[0].rootDSE_data) +
1072 strlen(DOORLINESEP) + 1;
1073 if (ret_addrFQDN != NULL)
1074 len += strlen(ret_addrFQDN) + strlen(DOORLINESEP);
1075 *output = (char *)malloc(len);
1076 if (*output == NULL) {
1077 (void) mutex_unlock(&info->mutex[0]);
1078 return (NS_LDAP_MEMORY);
1079 }
1080 if (ret_addrFQDN == NULL)
1081 (void) snprintf(*output, len, "%s%s%s",
1082 ret_addr, DOORLINESEP,
1083 server->sinfo[0].rootDSE_data);
1084 else
1085 (void) snprintf(*output, len, "%s%s%s%s%s",
1086 ret_addr, DOORLINESEP,
1087 ret_addrFQDN, DOORLINESEP,
1088 server->sinfo[0].rootDSE_data);
1089 server->sinfo[0].info_status = INFO_STATUS_OLD;
1090 (void) mutex_unlock(&info->mutex[0]);
1091 return (NS_LDAP_SUCCESS);
1092 }
1093 else
1094 return (-99);
1095 }
1096
1097 /*
1098 * Format previous and next refresh time
1099 */
1100 static int
getldap_format_refresh_time(char ** output,time_t * prev,time_t * next)1101 getldap_format_refresh_time(char **output, time_t *prev, time_t *next)
1102 {
1103 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S"
1104 #define TIME_HEADER1 " Previous refresh time: "
1105 #define TIME_HEADER2 " Next refresh time: "
1106 int hdr1_len = strlen(gettext(TIME_HEADER1));
1107 int hdr2_len = strlen(gettext(TIME_HEADER2));
1108 struct tm tm;
1109 char nbuf[256];
1110 char pbuf[256];
1111 int len;
1112
1113 if (current_admin.debug_level >= DBG_ALL) {
1114 logit("getldap_format_refresh_time()...\n");
1115 }
1116
1117 *output = NULL;
1118
1119 /* format the time of previous refresh */
1120 if (*prev != 0) {
1121 (void) localtime_r(prev, &tm);
1122 (void) strftime(pbuf, sizeof (pbuf) - 1, TIME_FORMAT, &tm);
1123 } else {
1124 (void) strcpy(pbuf, gettext("NOT DONE"));
1125 }
1126
1127 /* format the time of next refresh */
1128 if (*next != 0) {
1129 (void) localtime_r(next, &tm);
1130 (void) strftime(nbuf, sizeof (nbuf) - 1, TIME_FORMAT, &tm);
1131 } else {
1132 (void) strcpy(nbuf, gettext("NOT SET"));
1133 }
1134
1135 len = hdr1_len + hdr2_len + strlen(nbuf) +
1136 strlen(pbuf) + 2 * strlen(DOORLINESEP) + 1;
1137
1138 *output = malloc(len);
1139 if (*output == NULL)
1140 return (-1);
1141
1142 (void) snprintf(*output, len, "%s%s%s%s%s%s",
1143 gettext(TIME_HEADER1), pbuf, DOORLINESEP,
1144 gettext(TIME_HEADER2), nbuf, DOORLINESEP);
1145
1146 return (NS_LDAP_SUCCESS);
1147 }
1148
1149 /*
1150 * getldap_get_server_stat processes the GETSTAT request passed
1151 * to this function from getldap_serverInfo_op().
1152 * output:
1153 * a buffer containing info for all the servers.
1154 * For each server, the data is in the following format:
1155 * server: server address or name, status: unknown|up|down|removed DOORLINESEP
1156 * for example: ( here | used as DOORLINESEP for visual purposes)
1157 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up|
1158 * NOTE: caller should free this buffer when done using it
1159 */
1160 static int
getldap_get_server_stat(server_info_t * head,char ** output,time_t * prev,time_t * next)1161 getldap_get_server_stat(server_info_t *head, char **output,
1162 time_t *prev, time_t *next)
1163 {
1164 #define S_HEADER "Server information: "
1165 #define S_FORMAT " server: %s, status: %s%s"
1166 #define S_ERROR " error message: %s%s"
1167 server_info_t *info = NULL;
1168 int header_len = strlen(gettext(S_HEADER));
1169 int format_len = strlen(gettext(S_FORMAT));
1170 int error_len = strlen(gettext(S_ERROR));
1171 int len = header_len + strlen(DOORLINESEP);
1172 int len1 = 0;
1173 char *status, *output1 = NULL, *tmpptr;
1174
1175 *output = NULL;
1176
1177 if (current_admin.debug_level >= DBG_ALL) {
1178 logit("getldap_get_server_stat()...\n");
1179 }
1180
1181 if (head == NULL) {
1182 logit("getldap_get_server_stat: "
1183 "invalid serverInfo list.\n");
1184 return (-1);
1185 }
1186
1187 /* format previous and next refresh time */
1188 (void) getldap_format_refresh_time(&output1, prev, next);
1189 if (output1 == NULL)
1190 return (-1);
1191 len += strlen(output1);
1192 len1 = len + strlen(DOORLINESEP) + 1;
1193
1194 *output = (char *)calloc(1, len1);
1195 if (*output == NULL) {
1196 free(output1);
1197 return (-1);
1198 }
1199
1200 /* insert header string and refresh time info */
1201 (void) snprintf(*output, len1, "%s%s%s",
1202 gettext(S_HEADER), DOORLINESEP, output1);
1203
1204 for (info = head; info; info = info->next) {
1205
1206 /*
1207 * make sure the server info stays the same
1208 * while the data is being processed
1209 */
1210 (void) mutex_lock(&info->mutex[1]);
1211
1212 /*
1213 * When the updating process is under way(getldap_get_rootDSE)
1214 * the update copy(sinfo[1] is the latest copy.
1215 * When the updating process
1216 * is done, the current copy (sinfo[0]) has the latest status,
1217 * which is still identical to the update copy.
1218 * So update copy has the latest status.
1219 * Use the update copy(sinfo[1]) to show status
1220 * (ldap_cachemgr -g).
1221 *
1222 */
1223
1224 switch (info->sinfo[1].server_status) {
1225 case INFO_SERVER_UNKNOWN:
1226 status = gettext("UNKNOWN");
1227 break;
1228 case INFO_SERVER_CONNECTING:
1229 status = gettext("CONNECTING");
1230 break;
1231 case INFO_SERVER_UP:
1232 status = gettext("UP");
1233 break;
1234 case INFO_SERVER_ERROR:
1235 status = gettext("ERROR");
1236 break;
1237 case INFO_SERVER_REMOVED:
1238 status = gettext("REMOVED");
1239 break;
1240 }
1241
1242 len += format_len + strlen(status) +
1243 strlen(info->sinfo[1].addr) +
1244 strlen(DOORLINESEP);
1245 if (info->sinfo[1].errormsg != NULL)
1246 len += error_len +
1247 strlen(info->sinfo[1].errormsg) +
1248 strlen(DOORLINESEP);
1249
1250 tmpptr = (char *)realloc(*output, len);
1251 if (tmpptr == NULL) {
1252 free(output1);
1253 free(*output);
1254 *output = NULL;
1255 (void) mutex_unlock(&info->mutex[1]);
1256 return (-1);
1257 } else
1258 *output = tmpptr;
1259
1260 /* insert server IP addr or name and status */
1261 len1 = len - strlen(*output);
1262 (void) snprintf(*output + strlen(*output), len1,
1263 gettext(S_FORMAT), info->sinfo[1].addr,
1264 status, DOORLINESEP);
1265 /* insert error message if any */
1266 len1 = len - strlen(*output);
1267 if (info->sinfo[1].errormsg != NULL)
1268 (void) snprintf(*output + strlen(*output), len1,
1269 gettext(S_ERROR),
1270 info->sinfo[1].errormsg,
1271 DOORLINESEP);
1272
1273 (void) mutex_unlock(&info->mutex[1]);
1274
1275 }
1276
1277 free(output1);
1278 return (NS_LDAP_SUCCESS);
1279 }
1280
1281 /*
1282 * Format and return the refresh time statistics
1283 */
1284 static int
getldap_get_refresh_stat(char ** output)1285 getldap_get_refresh_stat(char **output)
1286 {
1287 #define R_HEADER0 "Configuration refresh information: "
1288 #define R_HEADER1 " Configured to NO REFRESH."
1289 int hdr0_len = strlen(gettext(R_HEADER0));
1290 int hdr1_len = strlen(gettext(R_HEADER1));
1291 int cache_ttl = -1, len = 0;
1292 time_t expire = 0;
1293 void **paramVal = NULL;
1294 ns_ldap_error_t *errorp = NULL;
1295 char *output1 = NULL;
1296
1297 if (current_admin.debug_level >= DBG_ALL) {
1298 logit("getldap_get_refresh_stat()...\n");
1299 }
1300
1301 *output = NULL;
1302
1303 /* get configured cache TTL */
1304 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1305 ¶mVal, &errorp) == NS_LDAP_SUCCESS) &&
1306 paramVal != NULL &&
1307 (char *)*paramVal != NULL) {
1308 cache_ttl = atol((char *)*paramVal);
1309 } else {
1310 if (errorp)
1311 __ns_ldap_freeError(&errorp);
1312 }
1313 (void) __ns_ldap_freeParam(¶mVal);
1314
1315 /* cound not get cache TTL */
1316 if (cache_ttl == -1)
1317 return (-1);
1318
1319 if (cache_ttl == 0) {
1320 len = hdr0_len + hdr1_len +
1321 2 * strlen(DOORLINESEP) + 1;
1322 *output = malloc(len);
1323 if (*output == NULL)
1324 return (-1);
1325 (void) snprintf(*output, len, "%s%s%s%s",
1326 gettext(R_HEADER0), DOORLINESEP,
1327 gettext(R_HEADER1), DOORLINESEP);
1328 } else {
1329
1330 /* get configuration expiration time */
1331 if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
1332 ¶mVal, &errorp) == NS_LDAP_SUCCESS) &&
1333 paramVal != NULL &&
1334 (char *)*paramVal != NULL) {
1335 expire = (time_t)atol((char *)*paramVal);
1336 } else {
1337 if (errorp)
1338 __ns_ldap_freeError(&errorp);
1339 }
1340
1341 (void) __ns_ldap_freeParam(¶mVal);
1342
1343 /* cound not get expiration time */
1344 if (expire == -1)
1345 return (-1);
1346
1347 /* format previous and next refresh time */
1348 (void) getldap_format_refresh_time(&output1,
1349 &prev_refresh_time, &expire);
1350 if (output1 == NULL)
1351 return (-1);
1352
1353 len = hdr0_len + strlen(output1) +
1354 2 * strlen(DOORLINESEP) + 1;
1355 *output = malloc(len);
1356 if (*output == NULL) {
1357 free(output1);
1358 return (-1);
1359 }
1360 (void) snprintf(*output, len, "%s%s%s%s",
1361 gettext(R_HEADER0), DOORLINESEP,
1362 output1, DOORLINESEP);
1363 free(output1);
1364 }
1365
1366 return (NS_LDAP_SUCCESS);
1367 }
1368
1369 static int
getldap_get_cacheTTL()1370 getldap_get_cacheTTL()
1371 {
1372 void **paramVal = NULL;
1373 ns_ldap_error_t *error;
1374 int rc = 0, cachettl;
1375
1376
1377 if (current_admin.debug_level >= DBG_ALL) {
1378 logit("getldap_get_cacheTTL()....\n");
1379 }
1380
1381 if ((rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P,
1382 ¶mVal, &error)) != NS_LDAP_SUCCESS) {
1383 if (error != NULL && error->message != NULL)
1384 logit("Error: Unable to get configuration "
1385 "refresh TTL: %s\n",
1386 error->message);
1387 else {
1388 char *tmp;
1389
1390 __ns_ldap_err2str(rc, &tmp);
1391 logit("Error: Unable to get configuration "
1392 "refresh TTL: %s\n", tmp);
1393 }
1394 (void) __ns_ldap_freeParam(¶mVal);
1395 (void) __ns_ldap_freeError(&error);
1396 return (-1);
1397 }
1398 if (paramVal == NULL || (char *)*paramVal == NULL)
1399 return (-1);
1400 cachettl = atol((char *)*paramVal);
1401 (void) __ns_ldap_freeParam(¶mVal);
1402 return (cachettl);
1403 }
1404
1405
1406 /*
1407 * This function implements the adaptive server list refresh
1408 * algorithm used by ldap_cachemgr. The idea is to have the
1409 * refresh TTL adjust itself between maximum and minimum
1410 * values. If the server list has been walked three times
1411 * in a row without errors, the TTL will be doubled. This will
1412 * be done repeatedly until the maximum value is reached
1413 * or passed. If passed, the maximum value will be used.
1414 * If any time a server is found to be down/bad, either
1415 * after another server list walk or informed by libsldap via
1416 * the GETLDAPSERVER door calls, the TTL will be set to half
1417 * of its value, again repeatedly, but no less than the minimum
1418 * value. Also, at any time, if all the servers on the list
1419 * are found to be down/bad, the TTL will be set to minimum,
1420 * so that a "no-server" refresh loop should be entered to try
1421 * to find a good server as soon as possible. The caller
1422 * could check the no_gd_server flag for this situation.
1423 * The maximum and minimum values are initialized when the input
1424 * refresh_ttl is set to zero, this should occur during
1425 * ldap_cachemgr startup or every time the server list is
1426 * recreated after the configuration profile is refreshed
1427 * from an LDAP server. The maximum is set to the value of
1428 * the NS_LDAP_CACHETTL parameter (configuration profile
1429 * refresh TTL), but if it is zero (never refreshed) or can
1430 * not be retrieved, the maximum is set to the macro
1431 * REFRESHTTL_MAX (12 hours) defined below. The minimum is
1432 * set to REFRESHTTL_MIN, which is the TCP connection timeout
1433 * (tcptimeout) set via the LDAP API ldap_set_option()
1434 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds.
1435 * This accounts for the maximum possible timeout value for an
1436 * LDAP TCP connect call.The first refresh TTL, initial value of
1437 * refresh_ttl, will be set to the smaller of the two,
1438 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2.
1439 * The idea is to have a low starting value and have the value
1440 * stay low if the network/server is unstable, but eventually
1441 * the value will move up to maximum and stay there if the
1442 * network/server is stable.
1443 */
1444 static int
getldap_set_refresh_ttl(server_info_t * head,int * refresh_ttl,int * no_gd_server)1445 getldap_set_refresh_ttl(server_info_t *head, int *refresh_ttl,
1446 int *no_gd_server)
1447 {
1448 #define REFRESHTTL_REGULAR 600
1449 #define REFRESHTTL_MAX 43200
1450 /* tcptimeout is in milliseconds */
1451 #define REFRESHTTL_MIN (tcptimeout/1000) + 10
1452 #define UP_REFRESH_TTL_NUM 2
1453
1454 static mutex_t refresh_mutex;
1455 static int refresh_ttl_max = 0;
1456 static int refresh_ttl_min = 0;
1457 static int num_walked_ok = 0;
1458 int num_servers = 0;
1459 int num_good_servers = 0;
1460 int num_prev_good_servers = 0;
1461 server_info_t *info;
1462
1463 /* allow one thread at a time */
1464 (void) mutex_lock(&refresh_mutex);
1465
1466 if (current_admin.debug_level >= DBG_ALL) {
1467 logit("getldap_set_refresh_ttl()...\n");
1468 }
1469
1470 if (!head || !refresh_ttl || !no_gd_server) {
1471 logit("getldap_set_refresh_ttl: head is "
1472 "NULL or refresh_ttl is NULL or "
1473 "no_gd_server is NULL");
1474 (void) mutex_unlock(&refresh_mutex);
1475 return (-1);
1476 }
1477 *no_gd_server = FALSE;
1478
1479 /*
1480 * init max. min. TTLs if first time through or a fresh one
1481 */
1482 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1483 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d "
1484 "seconds\n", *refresh_ttl);
1485 }
1486 if (*refresh_ttl == 0) {
1487 num_walked_ok = 0;
1488 /*
1489 * init cache manager server list TTL:
1490 *
1491 * init the min. TTL to
1492 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds)
1493 */
1494 refresh_ttl_min = REFRESHTTL_MIN;
1495
1496 /*
1497 * try to set the max. TTL to
1498 * configuration refresh TTL (NS_LDAP_CACHETTL),
1499 * if error (-1), or never refreshed (0),
1500 * set it to REFRESHTTL_MAX (12 hours)
1501 */
1502 refresh_ttl_max = getldap_get_cacheTTL();
1503 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1504 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d "
1505 "seconds\n", *refresh_ttl);
1506 logit("getldap_set_refresh_ttl:(2) max ttl is %d, "
1507 "min ttl is %d seconds\n",
1508 refresh_ttl_max, refresh_ttl_min);
1509 }
1510 if (refresh_ttl_max <= 0)
1511 refresh_ttl_max = REFRESHTTL_MAX;
1512 else if (refresh_ttl_max < refresh_ttl_min)
1513 refresh_ttl_max = refresh_ttl_min;
1514
1515 /*
1516 * init the first TTL to the smaller of the two:
1517 * REFRESHTTL_REGULAR ( 10 minutes),
1518 * (refresh_ttl_max + refresh_ttl_min)/2
1519 */
1520 *refresh_ttl = REFRESHTTL_REGULAR;
1521 if (*refresh_ttl > (refresh_ttl_max + refresh_ttl_min) / 2)
1522 *refresh_ttl = (refresh_ttl_max + refresh_ttl_min) / 2;
1523 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1524 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d "
1525 "seconds\n", *refresh_ttl);
1526 logit("getldap_set_refresh_ttl:(3) max ttl is %d, "
1527 "min ttl is %d seconds\n",
1528 refresh_ttl_max, refresh_ttl_min);
1529 }
1530 }
1531
1532 /*
1533 * get the servers statistics:
1534 * number of servers on list
1535 * number of good servers on list
1536 * number of pevious good servers on list
1537 */
1538 for (info = head; info; info = info->next) {
1539 num_servers++;
1540 (void) mutex_lock(&info->mutex[0]);
1541 if (info->sinfo[0].server_status == INFO_SERVER_UP)
1542 num_good_servers++;
1543 /*
1544 * Server's previous status could be UNKNOWN
1545 * only between the very first and second
1546 * refresh. Treat that UNKNOWN status as up
1547 */
1548 if (info->sinfo[0].prev_server_status
1549 == INFO_SERVER_UP ||
1550 info->sinfo[0].prev_server_status
1551 == INFO_SERVER_UNKNOWN)
1552 num_prev_good_servers++;
1553 (void) mutex_unlock(&info->mutex[0]);
1554 }
1555
1556 /*
1557 * if the server list is walked three times in a row
1558 * without problems, double the refresh TTL but no more
1559 * than the max. refresh TTL
1560 */
1561 if (num_good_servers == num_servers) {
1562 num_walked_ok++;
1563 if (num_walked_ok > UP_REFRESH_TTL_NUM) {
1564
1565 *refresh_ttl = *refresh_ttl * 2;
1566 if (*refresh_ttl > refresh_ttl_max)
1567 *refresh_ttl = refresh_ttl_max;
1568
1569 num_walked_ok = 0;
1570 }
1571 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1572 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d "
1573 "seconds\n", *refresh_ttl);
1574 }
1575 } else if (num_good_servers == 0) {
1576 /*
1577 * if no good server found,
1578 * set refresh TTL to miminum
1579 */
1580 *refresh_ttl = refresh_ttl_min;
1581 *no_gd_server = TRUE;
1582 num_walked_ok = 0;
1583 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1584 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d "
1585 "seconds\n", *refresh_ttl);
1586 }
1587 } else if (num_prev_good_servers > num_good_servers) {
1588 /*
1589 * if more down/bad servers found,
1590 * decrease the refresh TTL by half
1591 * but no less than the min. refresh TTL
1592 */
1593 *refresh_ttl = *refresh_ttl / 2;
1594 if (*refresh_ttl < refresh_ttl_min)
1595 *refresh_ttl = refresh_ttl_min;
1596 num_walked_ok = 0;
1597 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d "
1598 "seconds\n", *refresh_ttl);
1599
1600 }
1601
1602 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1603 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n",
1604 *refresh_ttl);
1605 }
1606 (void) mutex_unlock(&refresh_mutex);
1607 return (0);
1608 }
1609
1610 static int
getldap_serverInfo_op(info_op_t op,char * input,char ** output)1611 getldap_serverInfo_op(info_op_t op, char *input, char **output)
1612 {
1613
1614 static rwlock_t info_lock = DEFAULTRWLOCK;
1615 static rwlock_t info_lock_old = DEFAULTRWLOCK;
1616 static mutex_t info_mutex;
1617 static cond_t info_cond;
1618 static int creating = FALSE;
1619 static int refresh_ttl = 0;
1620 static int sec_to_refresh = 0;
1621 static int in_no_server_mode = FALSE;
1622
1623 static server_info_t *serverInfo = NULL;
1624 static server_info_t *serverInfo_old = NULL;
1625 server_info_t *serverInfo_1;
1626 int is_creating;
1627 int err, no_server_good = FALSE;
1628 int server_removed = FALSE;
1629 int fall_thru = FALSE;
1630 static struct timespec timeout;
1631 struct timespec new_timeout;
1632 struct timeval tp;
1633 static time_t prev_refresh = 0, next_refresh = 0;
1634 ns_server_status_t changed = 0;
1635
1636 (void) pthread_setname_np(pthread_self(), "getldap_serverinfo");
1637
1638 if (current_admin.debug_level >= DBG_ALL) {
1639 logit("getldap_serverInfo_op()...\n");
1640 }
1641 switch (op) {
1642 case INFO_OP_CREATE:
1643 if (current_admin.debug_level >= DBG_ALL) {
1644 logit("operation is INFO_OP_CREATE...\n");
1645 }
1646
1647 /*
1648 * indicate that the server info is being
1649 * (re)created, so that the refresh thread
1650 * will not refresh the info list right
1651 * after the list got (re)created
1652 */
1653 (void) mutex_lock(&info_mutex);
1654 is_creating = creating;
1655 creating = TRUE;
1656 (void) mutex_unlock(&info_mutex);
1657
1658 if (is_creating)
1659 break;
1660 /*
1661 * create an empty info list
1662 */
1663 (void) getldap_init_serverInfo(&serverInfo_1);
1664 /*
1665 * exit if list not created
1666 */
1667 if (serverInfo_1 == NULL) {
1668 (void) mutex_lock(&info_mutex);
1669 creating = FALSE;
1670 (void) mutex_unlock(&info_mutex);
1671 break;
1672 }
1673 /*
1674 * make the new server info available:
1675 * use writer lock here, so that the switch
1676 * is done after all the reader locks have
1677 * been released.
1678 */
1679 (void) rw_wrlock(&info_lock);
1680 serverInfo = serverInfo_1;
1681 /*
1682 * if this is the first time
1683 * the server list is being created,
1684 * (i.e., serverInfo_old is NULL)
1685 * make the old list same as the new
1686 * so the GETSERVER code can do its work
1687 */
1688 if (serverInfo_old == NULL)
1689 serverInfo_old = serverInfo_1;
1690 (void) rw_unlock(&info_lock);
1691
1692 /*
1693 * fill the new info list
1694 */
1695 (void) rw_rdlock(&info_lock);
1696 /* reset bind time (tcptimeout) */
1697 (void) getldap_set_serverInfo(serverInfo, 1, INFO_OP_CREATE);
1698
1699 (void) mutex_lock(&info_mutex);
1700 /*
1701 * set cache manager server list TTL,
1702 * set refresh_ttl to zero to indicate a fresh one
1703 */
1704 refresh_ttl = 0;
1705 (void) getldap_set_refresh_ttl(serverInfo,
1706 &refresh_ttl, &no_server_good);
1707 sec_to_refresh = refresh_ttl;
1708
1709 /* statistics: previous refresh time */
1710 if (gettimeofday(&tp, NULL) == 0)
1711 prev_refresh = tp.tv_sec;
1712
1713 creating = FALSE;
1714
1715 /*
1716 * if no server found or available,
1717 * tell the server info refresh thread
1718 * to start the "no-server" refresh loop
1719 * otherwise reset the in_no_server_mode flag
1720 */
1721 if (no_server_good) {
1722 sec_to_refresh = 0;
1723 in_no_server_mode = TRUE;
1724 } else
1725 in_no_server_mode = FALSE;
1726 /*
1727 * awake the sleeping refresh thread
1728 */
1729 (void) cond_signal(&info_cond);
1730
1731 (void) mutex_unlock(&info_mutex);
1732 (void) rw_unlock(&info_lock);
1733
1734 /*
1735 * delete the old server info
1736 */
1737 (void) rw_wrlock(&info_lock_old);
1738 if (serverInfo_old != serverInfo)
1739 (void) getldap_destroy_serverInfo(serverInfo_old);
1740 /*
1741 * serverInfo_old needs to be the same as
1742 * serverinfo now.
1743 * it will be used by GETSERVER processing.
1744 */
1745 serverInfo_old = serverInfo;
1746 (void) rw_unlock(&info_lock_old);
1747 break;
1748 case INFO_OP_DELETE:
1749 if (current_admin.debug_level >= DBG_ALL) {
1750 logit("operation is INFO_OP_DELETE...\n");
1751 }
1752 /*
1753 * use writer lock here, so that the delete would
1754 * not start until all the reader locks have
1755 * been released.
1756 */
1757 (void) rw_wrlock(&info_lock);
1758 if (serverInfo)
1759 (void) getldap_destroy_serverInfo(serverInfo);
1760 serverInfo = NULL;
1761 (void) rw_unlock(&info_lock);
1762 break;
1763 case INFO_OP_REFRESH:
1764 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1765 logit("operation is INFO_OP_REFRESH...\n");
1766 }
1767 /*
1768 * if server info is currently being
1769 * (re)created, do nothing
1770 */
1771 (void) mutex_lock(&info_mutex);
1772 is_creating = creating;
1773 (void) mutex_unlock(&info_mutex);
1774 if (is_creating)
1775 break;
1776
1777 (void) rw_rdlock(&info_lock);
1778 if (serverInfo) {
1779 /* do not reset bind time (tcptimeout) */
1780 (void) getldap_set_serverInfo(serverInfo, 0,
1781 INFO_OP_REFRESH);
1782
1783 (void) mutex_lock(&info_mutex);
1784
1785 /* statistics: previous refresh time */
1786 if (gettimeofday(&tp, NULL) == 0)
1787 prev_refresh = tp.tv_sec;
1788 /*
1789 * set cache manager server list TTL
1790 */
1791 (void) getldap_set_refresh_ttl(serverInfo,
1792 &refresh_ttl, &no_server_good);
1793 /*
1794 * if no good server found,
1795 * tell the server info refresh thread
1796 * to start the "no-server" refresh loop
1797 * otherwise reset the in_no_server_mode flag
1798 */
1799 if (no_server_good) {
1800 in_no_server_mode = TRUE;
1801 sec_to_refresh = 0;
1802 } else {
1803 in_no_server_mode = FALSE;
1804 sec_to_refresh = refresh_ttl;
1805 }
1806 if (current_admin.debug_level >=
1807 DBG_SERVER_LIST_REFRESH) {
1808 logit("getldap_serverInfo_op("
1809 "INFO_OP_REFRESH):"
1810 " seconds refresh: %d second(s)....\n",
1811 sec_to_refresh);
1812 }
1813 (void) mutex_unlock(&info_mutex);
1814 }
1815 (void) rw_unlock(&info_lock);
1816
1817 break;
1818 case INFO_OP_REFRESH_WAIT:
1819 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) {
1820 logit("operation is INFO_OP_REFRESH_WAIT...\n");
1821 }
1822 (void) cond_init(&info_cond, USYNC_THREAD, NULL);
1823 (void) mutex_lock(&info_mutex);
1824 err = 0;
1825 while (err != ETIME) {
1826 int sleeptime;
1827 /*
1828 * if need to go into the "no-server" refresh
1829 * loop, set timout value to
1830 * REFRESH_DELAY_WHEN_NO_SERVER
1831 */
1832 if (sec_to_refresh == 0) {
1833 sec_to_refresh = refresh_ttl;
1834 timeout.tv_sec = time(NULL) +
1835 REFRESH_DELAY_WHEN_NO_SERVER;
1836 sleeptime = REFRESH_DELAY_WHEN_NO_SERVER;
1837 if (current_admin.debug_level >=
1838 DBG_SERVER_LIST_REFRESH) {
1839 logit("getldap_serverInfo_op("
1840 "INFO_OP_REFRESH_WAIT):"
1841 " entering no-server "
1842 "refresh loop...\n");
1843 }
1844 } else {
1845 timeout.tv_sec = time(NULL) + sec_to_refresh;
1846 sleeptime = sec_to_refresh;
1847 }
1848 timeout.tv_nsec = 0;
1849
1850 /* statistics: next refresh time */
1851 next_refresh = timeout.tv_sec;
1852
1853 if (current_admin.debug_level >=
1854 DBG_SERVER_LIST_REFRESH) {
1855 logit("getldap_serverInfo_op("
1856 "INFO_OP_REFRESH_WAIT):"
1857 " about to sleep for %d second(s)...\n",
1858 sleeptime);
1859 }
1860 err = cond_timedwait(&info_cond,
1861 &info_mutex, &timeout);
1862 }
1863 (void) cond_destroy(&info_cond);
1864 (void) mutex_unlock(&info_mutex);
1865 break;
1866 case INFO_OP_GETSERVER:
1867 if (current_admin.debug_level >= DBG_ALL) {
1868 logit("operation is INFO_OP_GETSERVER...\n");
1869 }
1870 *output = NULL;
1871 /*
1872 * GETSERVER processing always use
1873 * serverInfo_old to retrieve server infomation.
1874 * serverInfo_old is equal to serverInfo
1875 * most of the time, except when a new
1876 * server list is being created.
1877 * This is why the check for is_creating
1878 * is needed below.
1879 */
1880 (void) rw_rdlock(&info_lock_old);
1881
1882 if (serverInfo_old == NULL) {
1883 (void) rw_unlock(&info_lock_old);
1884 break;
1885 } else
1886 (void) getldap_get_serverInfo(serverInfo_old,
1887 input, output, &server_removed);
1888 (void) rw_unlock(&info_lock_old);
1889
1890 /*
1891 * Return here and let remove server thread do its job in
1892 * another thread. It executes INFO_OP_REMOVESERVER code later.
1893 */
1894 if (server_removed)
1895 break;
1896
1897 fall_thru = TRUE;
1898
1899 /* FALL THROUGH */
1900
1901 case INFO_OP_REMOVESERVER:
1902 /*
1903 * INFO_OP_GETSERVER and INFO_OP_REMOVESERVER share the
1904 * following code except (!fall thru) part.
1905 */
1906
1907 /*
1908 * if server info is currently being
1909 * (re)created, do nothing
1910 */
1911
1912 (void) mutex_lock(&info_mutex);
1913 is_creating = creating;
1914 (void) mutex_unlock(&info_mutex);
1915 if (is_creating)
1916 break;
1917
1918 if (!fall_thru) {
1919 if (current_admin.debug_level >= DBG_ALL)
1920 logit("operation is INFO_OP_REMOVESERVER...\n");
1921 (void) rw_rdlock(&info_lock_old);
1922 changed = set_server_status(input, serverInfo_old);
1923 (void) rw_unlock(&info_lock_old);
1924 if (changed)
1925 create_buf_and_notify(input, changed);
1926 else
1927 break;
1928 }
1929
1930 /*
1931 * set cache manager server list TTL if necessary
1932 */
1933 if (*output == NULL || changed) {
1934 (void) rw_rdlock(&info_lock);
1935 (void) mutex_lock(&info_mutex);
1936
1937 (void) getldap_set_refresh_ttl(serverInfo,
1938 &refresh_ttl, &no_server_good);
1939
1940 /*
1941 * if no good server found, need to go into
1942 * the "no-server" refresh loop
1943 * to find a server as soon as possible
1944 * otherwise reset the in_no_server_mode flag
1945 */
1946 if (no_server_good) {
1947 /*
1948 * if already in no-server mode,
1949 * don't brother
1950 */
1951 if (in_no_server_mode == FALSE) {
1952 sec_to_refresh = 0;
1953 in_no_server_mode = TRUE;
1954 (void) cond_signal(&info_cond);
1955 }
1956 (void) mutex_unlock(&info_mutex);
1957 (void) rw_unlock(&info_lock);
1958 break;
1959 } else {
1960 in_no_server_mode = FALSE;
1961 sec_to_refresh = refresh_ttl;
1962 }
1963 /*
1964 * if the refresh thread will be timed out
1965 * longer than refresh_ttl seconds,
1966 * wake it up to make it wait on the new
1967 * time out value
1968 */
1969 new_timeout.tv_sec = time(NULL) + refresh_ttl;
1970 if (new_timeout.tv_sec < timeout.tv_sec)
1971 (void) cond_signal(&info_cond);
1972
1973 (void) mutex_unlock(&info_mutex);
1974 (void) rw_unlock(&info_lock);
1975 }
1976 break;
1977 case INFO_OP_GETSTAT:
1978 if (current_admin.debug_level >= DBG_ALL) {
1979 logit("operation is INFO_OP_GETSTAT...\n");
1980 }
1981 *output = NULL;
1982 (void) rw_rdlock(&info_lock);
1983 if (serverInfo) {
1984 (void) getldap_get_server_stat(serverInfo,
1985 output, &prev_refresh, &next_refresh);
1986 }
1987 (void) rw_unlock(&info_lock);
1988 break;
1989 default:
1990 logit("getldap_serverInfo_op(): "
1991 "invalid operation code (%d).\n", op);
1992 return (-1);
1993 break;
1994 }
1995 return (NS_LDAP_SUCCESS);
1996 }
1997
1998 void
getldap_serverInfo_refresh()1999 getldap_serverInfo_refresh()
2000 {
2001 int always = 1;
2002
2003 if (current_admin.debug_level >= DBG_ALL) {
2004 logit("getldap_serverInfo_refresh()...\n");
2005 }
2006
2007 /* create the server info list */
2008 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2009
2010 while (always) {
2011 /*
2012 * the operation INFO_OP_REFRESH_WAIT
2013 * causes this thread to wait until
2014 * it is time to do refresh,
2015 * see getldap_serverInfo_op() for details
2016 */
2017 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT, NULL, NULL);
2018 (void) getldap_serverInfo_op(INFO_OP_REFRESH, NULL, NULL);
2019 }
2020 }
2021
2022 void
getldap_getserver(LineBuf * config_info,ldap_call_t * in)2023 getldap_getserver(LineBuf *config_info, ldap_call_t *in)
2024 {
2025 char req[] = "0";
2026
2027 if (current_admin.debug_level >= DBG_ALL) {
2028 logit("getldap_getserver()...\n");
2029 }
2030
2031 config_info->len = 0;
2032
2033 /* make sure the request is valid */
2034 req[0] = (in->ldap_u.servername)[0];
2035 if ((req[0] != '\0') &&
2036 (strcmp(req, NS_CACHE_NEW) != 0) &&
2037 (strcmp(req, NS_CACHE_NORESP) != 0) &&
2038 (strcmp(req, NS_CACHE_NEXT) != 0) &&
2039 (strcmp(req, NS_CACHE_WRITE) != 0)) {
2040 return;
2041 }
2042
2043 (void) getldap_serverInfo_op(INFO_OP_GETSERVER,
2044 in->ldap_u.domainname, &config_info->str);
2045
2046 if (config_info->str == NULL)
2047 return;
2048
2049 config_info->len = strlen(config_info->str) + 1;
2050
2051 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2052 /* Log server IP */
2053 char *ptr,
2054 separator;
2055 ptr = strstr(config_info->str, DOORLINESEP);
2056 if (ptr) {
2057 separator = *ptr;
2058 *ptr = '\0';
2059 logit("getldap_getserver: got server %s\n",
2060 config_info->str);
2061 *ptr = separator;
2062 } else
2063 logit("getldap_getserver: Missing %s."
2064 " Internal error\n", DOORLINESEP);
2065 }
2066 }
2067
2068 void
getldap_get_cacheData(LineBuf * config_info,ldap_call_t * in)2069 getldap_get_cacheData(LineBuf *config_info, ldap_call_t *in)
2070 {
2071 char *instr = NULL;
2072 int datatype = CACHE_MAP_UNKNOWN;
2073
2074 if (current_admin.debug_level >= DBG_ALL) {
2075 logit("getldap_get_cacheData()...\n");
2076 }
2077
2078 config_info->len = 0;
2079 config_info->str = NULL;
2080
2081 /* make sure the request is valid */
2082 if (strncmp(in->ldap_u.servername,
2083 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2084 datatype = CACHE_MAP_DN2DOMAIN;
2085
2086 if (datatype == CACHE_MAP_UNKNOWN)
2087 return;
2088
2089 instr = strstr(in->ldap_u.servername, DOORLINESEP);
2090 if (instr == NULL)
2091 return;
2092 instr += strlen(DOORLINESEP);
2093 if (*instr == '\0')
2094 return;
2095
2096 (void) getldap_cache_op(CACHE_OP_FIND, datatype,
2097 instr, &config_info->str);
2098
2099 if (config_info->str != NULL) {
2100 config_info->len = strlen(config_info->str) + 1;
2101 }
2102 }
2103
2104 int
getldap_set_cacheData(ldap_call_t * in)2105 getldap_set_cacheData(ldap_call_t *in)
2106 {
2107 char *instr1 = NULL;
2108 char *instr2 = NULL;
2109 int datatype = CACHE_MAP_UNKNOWN;
2110 int rc = 0;
2111
2112 if (current_admin.debug_level >= DBG_ALL) {
2113 logit("getldap_set_cacheData()...\n");
2114 }
2115
2116 /* make sure the request is valid */
2117 if (strncmp(in->ldap_u.servername,
2118 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0)
2119 datatype = CACHE_MAP_DN2DOMAIN;
2120
2121 if (datatype == CACHE_MAP_UNKNOWN)
2122 return (-1);
2123
2124 instr1 = strstr(in->ldap_u.servername, DOORLINESEP);
2125 if (instr1 == NULL)
2126 return (-1);
2127 *instr1 = '\0';
2128 instr1 += strlen(DOORLINESEP);
2129 if (*instr1 == '\0')
2130 return (-1);
2131 instr2 = strstr(instr1, DOORLINESEP);
2132 if (instr2 == NULL)
2133 return (-1);
2134 *instr2 = '\0';
2135 instr2 += strlen(DOORLINESEP);
2136 if (*instr2 == '\0')
2137 return (-1);
2138
2139 rc = getldap_cache_op(CACHE_OP_ADD, datatype,
2140 instr1, &instr2);
2141 if (rc != NS_LDAP_SUCCESS)
2142 return (-1);
2143
2144 return (0);
2145 }
2146
2147 void
getldap_get_cacheStat(LineBuf * stat_info)2148 getldap_get_cacheStat(LineBuf *stat_info)
2149 {
2150 char *foutstr = NULL;
2151 char *soutstr = NULL;
2152 char *coutstr = NULL;
2153 int infoSize;
2154
2155 if (current_admin.debug_level >= DBG_ALL) {
2156 logit("getldap_get_cacheStat()...\n");
2157 }
2158
2159 stat_info->str = NULL;
2160 stat_info->len = 0;
2161
2162 /* get refersh statisitcs */
2163 (void) getldap_get_refresh_stat(&foutstr);
2164 if (foutstr == NULL)
2165 return;
2166
2167 /* get server statisitcs */
2168 (void) getldap_serverInfo_op(INFO_OP_GETSTAT, NULL, &soutstr);
2169 if (soutstr == NULL) {
2170 free(foutstr);
2171 return;
2172 }
2173 /* get cache data statisitcs */
2174 (void) getldap_cache_op(CACHE_OP_GETSTAT, 0, NULL, &coutstr);
2175 if (coutstr == NULL) {
2176 free(foutstr);
2177 free(soutstr);
2178 return;
2179 }
2180
2181 infoSize = strlen(foutstr) + strlen(soutstr) + strlen(coutstr) + 3;
2182 stat_info->str = calloc(infoSize, sizeof (char));
2183 if (stat_info->str != NULL) {
2184 (void) strncpy(stat_info->str,
2185 foutstr,
2186 strlen(foutstr) + 1);
2187 (void) strncat(stat_info->str,
2188 soutstr,
2189 strlen(soutstr) + 1);
2190 (void) strncat(stat_info->str,
2191 coutstr,
2192 strlen(coutstr) + 1);
2193 stat_info->len = infoSize;
2194 }
2195
2196 free(foutstr);
2197 free(soutstr);
2198 free(coutstr);
2199 }
2200
2201 static int
checkupdate(int sighup)2202 checkupdate(int sighup)
2203 {
2204 int value;
2205
2206 (void) rw_wrlock(&ldap_lock);
2207 value = sighup;
2208 (void) rw_unlock(&ldap_lock);
2209
2210 return (value == TRUE);
2211 }
2212
2213
2214 static int
update_from_profile(int * change_status)2215 update_from_profile(int *change_status)
2216 {
2217 ns_ldap_result_t *result = NULL;
2218 char searchfilter[BUFSIZ];
2219 ns_ldap_error_t *error;
2220 int rc;
2221 void **paramVal = NULL;
2222 ns_config_t *ptr = NULL;
2223 char *profile = NULL;
2224 char errstr[MAXERROR];
2225
2226 if (current_admin.debug_level >= DBG_ALL) {
2227 logit("update_from_profile....\n");
2228 }
2229 do {
2230 (void) rw_wrlock(&ldap_lock);
2231 sighup_update = FALSE;
2232 (void) rw_unlock(&ldap_lock);
2233
2234 if ((rc = __ns_ldap_getParam(NS_LDAP_PROFILE_P,
2235 ¶mVal, &error)) != NS_LDAP_SUCCESS) {
2236 if (error != NULL && error->message != NULL)
2237 logit("Error: Unable to profile name: %s\n",
2238 error->message);
2239 else {
2240 char *tmp;
2241
2242 __ns_ldap_err2str(rc, &tmp);
2243 logit("Error: Unable to profile name: %s\n",
2244 tmp);
2245 }
2246 (void) __ns_ldap_freeParam(¶mVal);
2247 (void) __ns_ldap_freeError(&error);
2248 return (-1);
2249 }
2250
2251 if (paramVal && *paramVal)
2252 profile = strdup((char *)*paramVal);
2253 (void) __ns_ldap_freeParam(¶mVal);
2254
2255 if (profile == NULL) {
2256 return (-1);
2257 }
2258
2259 (void) snprintf(searchfilter, BUFSIZ, _PROFILE_FILTER,
2260 _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile);
2261
2262 if ((rc = __ns_ldap_list(_PROFILE_CONTAINER,
2263 (const char *)searchfilter, NULL,
2264 NULL, NULL, 0,
2265 &result, &error, NULL, NULL)) != NS_LDAP_SUCCESS) {
2266
2267 /*
2268 * Is profile name the DEFAULTCONFIGNAME?
2269 * syslog Warning, otherwise syslog error.
2270 */
2271 if (strcmp(profile, DEFAULTCONFIGNAME) == 0) {
2272 syslog(LOG_WARNING,
2273 "Ignoring attempt to refresh nonexistent "
2274 "default profile: %s.\n",
2275 profile);
2276 logit("Ignoring attempt to refresh nonexistent "
2277 "default profile: %s.\n",
2278 profile);
2279 } else if ((error != NULL) &&
2280 (error->message != NULL)) {
2281 syslog(LOG_ERR,
2282 "Error: Unable to refresh profile:%s:"
2283 " %s\n", profile, error->message);
2284 logit("Error: Unable to refresh profile:"
2285 "%s:%s\n", profile, error->message);
2286 } else {
2287 syslog(LOG_ERR, "Error: Unable to refresh "
2288 "from profile:%s. (error=%d)\n",
2289 profile, rc);
2290 logit("Error: Unable to refresh from profile "
2291 "%s (error=%d)\n", profile, rc);
2292 }
2293
2294 (void) __ns_ldap_freeError(&error);
2295 (void) __ns_ldap_freeResult(&result);
2296 free(profile);
2297 return (-1);
2298 }
2299 free(profile);
2300
2301
2302 } while (checkupdate(sighup_update) == TRUE);
2303
2304 (void) rw_wrlock(&ldap_lock);
2305
2306 ptr = __ns_ldap_make_config(result);
2307 (void) __ns_ldap_freeResult(&result);
2308
2309 if (ptr == NULL) {
2310 logit("Error: __ns_ldap_make_config failed.\n");
2311 (void) rw_unlock(&ldap_lock);
2312 return (-1);
2313 }
2314
2315 /*
2316 * cross check the config parameters
2317 */
2318 if (__s_api_crosscheck(ptr, errstr, B_TRUE) == NS_SUCCESS) {
2319 /*
2320 * reset the local profile TTL
2321 */
2322 if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc)
2323 current_admin.ldap_stat.ldap_ttl =
2324 atol(ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc);
2325
2326 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2327 logit("update_from_profile: reset profile TTL to %d"
2328 " seconds\n",
2329 current_admin.ldap_stat.ldap_ttl);
2330 logit("update_from_profile: expire time %ld "
2331 "seconds\n",
2332 ptr->paramList[NS_LDAP_EXP_P].ns_tm);
2333 }
2334
2335 /* set ptr as current_config if the config is changed */
2336 chg_test_config_change(ptr, change_status);
2337 rc = 0;
2338 } else {
2339 __s_api_destroy_config(ptr);
2340 logit("Error: downloaded profile failed to pass "
2341 "crosscheck (%s).\n", errstr);
2342 syslog(LOG_ERR, "ldap_cachemgr: %s", errstr);
2343 rc = -1;
2344 }
2345 (void) rw_unlock(&ldap_lock);
2346
2347 return (rc);
2348 }
2349
2350 int
getldap_init()2351 getldap_init()
2352 {
2353 ns_ldap_error_t *error;
2354 struct timeval tp;
2355 ldap_get_chg_cookie_t cookie;
2356
2357 if (current_admin.debug_level >= DBG_ALL) {
2358 logit("getldap_init()...\n");
2359 }
2360
2361 (void) __ns_ldap_setServer(TRUE);
2362
2363 (void) rw_wrlock(&ldap_lock);
2364 if ((error = __ns_ldap_LoadConfiguration()) != NULL) {
2365 logit("Error: Unable to read '%s': %s\n",
2366 NSCONFIGFILE, error->message);
2367 (void) fprintf(stderr,
2368 gettext("\nError: Unable to read '%s': %s\n"),
2369 NSCONFIGFILE, error->message);
2370 __ns_ldap_freeError(&error);
2371 (void) rw_unlock(&ldap_lock);
2372 return (-1);
2373 }
2374 (void) rw_unlock(&ldap_lock);
2375
2376 if (gettimeofday(&tp, NULL) == 0) {
2377 /* statistics: previous refresh time */
2378 prev_refresh_time = tp.tv_sec;
2379 }
2380
2381 /* initialize the data cache */
2382 (void) getldap_cache_op(CACHE_OP_CREATE,
2383 0, NULL, NULL);
2384
2385 cookie.mgr_pid = getpid();
2386 cookie.seq_num = 0;
2387 chg_config_cookie_set(&cookie);
2388 return (0);
2389 }
2390
2391 static void
perform_update(void)2392 perform_update(void)
2393 {
2394 ns_ldap_error_t *error = NULL;
2395 struct timeval tp;
2396 char buf[20];
2397 int rc, rc1;
2398 int changed = 0;
2399 void **paramVal = NULL;
2400 ns_ldap_self_gssapi_config_t config;
2401
2402 if (current_admin.debug_level >= DBG_ALL) {
2403 logit("perform_update()...\n");
2404 }
2405
2406 (void) __ns_ldap_setServer(TRUE);
2407
2408 if (gettimeofday(&tp, NULL) != 0)
2409 return;
2410
2411 rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, ¶mVal, &error);
2412
2413 if (rc == NS_LDAP_SUCCESS && paramVal != NULL) {
2414 current_admin.ldap_stat.ldap_ttl = atol((char *)*paramVal);
2415 }
2416
2417 if (error != NULL)
2418 (void) __ns_ldap_freeError(&error);
2419
2420 if (paramVal != NULL)
2421 (void) __ns_ldap_freeParam(¶mVal);
2422
2423 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
2424 logit("perform_update: current profile TTL is %d seconds\n",
2425 current_admin.ldap_stat.ldap_ttl);
2426 }
2427
2428 if (current_admin.ldap_stat.ldap_ttl > 0) {
2429 /*
2430 * set the profile TTL parameter, just
2431 * in case that the downloading of
2432 * the profile from server would fail
2433 */
2434
2435 /*
2436 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam
2437 * It depends on NS_LDAP_CACHETTL_P to set it's value
2438 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value
2439 * can be set.
2440 * NS_LDAP_CACHETTL_P value can be reset after the profile is
2441 * downloaded from the server, so is NS_LDAP_EXP_P.
2442 */
2443 buf[19] = '\0'; /* null terminated the buffer */
2444 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P,
2445 lltostr((long long)current_admin.ldap_stat.ldap_ttl,
2446 &buf[19]),
2447 &error) != NS_LDAP_SUCCESS) {
2448 logit("Error: __ns_ldap_setParam failed, status: %d "
2449 "message: %s\n", error->status, error->message);
2450 (void) __ns_ldap_freeError(&error);
2451 return;
2452 }
2453
2454 (void) rw_wrlock(&ldap_lock);
2455 sighup_update = FALSE;
2456 (void) rw_unlock(&ldap_lock);
2457
2458 do {
2459 rc = update_from_profile(&changed);
2460 if (rc != 0) {
2461 logit("Error: Unable to update from profile\n");
2462 }
2463 } while (checkupdate(sighup_update) == TRUE);
2464 } else {
2465 rc = 0;
2466 }
2467
2468 /*
2469 * recreate the server info list
2470 */
2471 if (rc == 0) {
2472 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL);
2473
2474 /* flush the data cache */
2475 (void) getldap_cache_op(CACHE_OP_DELETE,
2476 0, NULL, NULL);
2477
2478 /* statistics: previous refresh time */
2479 prev_refresh_time = tp.tv_sec;
2480 }
2481 rc1 = __ns_ldap_self_gssapi_config(&config);
2482 if (rc1 == NS_LDAP_SUCCESS) {
2483 if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) {
2484 rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error);
2485 (void) __ns_ldap_freeError(&error);
2486 if (rc1 != NS_LDAP_SUCCESS) {
2487 logit("Error: Check on self credential "
2488 "prerquesites failed: %d\n",
2489 rc1);
2490 exit(rc1);
2491 }
2492 }
2493 } else {
2494 logit("Error: Failed to get self credential configuration %d\n",
2495 rc1);
2496 exit(rc1);
2497 }
2498
2499 if (!changed)
2500 return;
2501
2502 (void) rw_rdlock(&ldap_lock);
2503 if (((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) ||
2504 ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL)) {
2505 logit("Error: __ns_ldap_DumpConfiguration failed, "
2506 "status: %d message: %s\n", error->status, error->message);
2507 __ns_ldap_freeError(&error);
2508 (void) rw_unlock(&ldap_lock);
2509 return;
2510 }
2511 if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0) {
2512 logit("Error: unlink failed - errno: %s\n", strerror(errno));
2513 syslog(LOG_ERR, "Unable to refresh profile, LDAP configuration"
2514 "files not written");
2515 (void) rw_unlock(&ldap_lock);
2516 return;
2517 }
2518 if (rename(NSCREDREFRESH, NSCREDFILE) != 0) {
2519 /*
2520 * We probably have inconsistent configuration at this point.
2521 * If we were to create a backup file and rename it here, that
2522 * operation might also fail. Consequently there is no safe way
2523 * to roll back.
2524 */
2525 logit("Error: unlink failed - errno: %s\n", strerror(errno));
2526 syslog(LOG_ERR, "Unable to refresh profile consistently, "
2527 "LDAP configuration files inconsistent");
2528 (void) rw_unlock(&ldap_lock);
2529 return;
2530 }
2531
2532 (void) rw_unlock(&ldap_lock);
2533 }
2534
2535 void
getldap_refresh()2536 getldap_refresh()
2537 {
2538 struct timespec timeout;
2539 int sleeptime;
2540 struct timeval tp;
2541 long expire = 0;
2542 void **paramVal = NULL;
2543 ns_ldap_error_t *errorp;
2544 int always = 1, err;
2545 int first_time = 1;
2546 int sig_done = 0;
2547 int dbg_level;
2548
2549 (void) pthread_setname_np(pthread_self(), "getldap_refresh");
2550
2551 if (current_admin.debug_level >= DBG_ALL) {
2552 logit("getldap_refresh()...\n");
2553 }
2554
2555 /*
2556 * wait for an available server
2557 */
2558 while (sig_done == 0) {
2559 (void) mutex_lock(&sig_mutex);
2560 sig_done = signal_done;
2561 (void) mutex_unlock(&sig_mutex);
2562 }
2563
2564 (void) __ns_ldap_setServer(TRUE);
2565 while (always) {
2566 dbg_level = current_admin.debug_level;
2567 (void) rw_rdlock(&ldap_lock);
2568 sleeptime = current_admin.ldap_stat.ldap_ttl;
2569 if (dbg_level >= DBG_PROFILE_REFRESH) {
2570 logit("getldap_refresh: current profile TTL is %d "
2571 "seconds\n", current_admin.ldap_stat.ldap_ttl);
2572 }
2573 if (gettimeofday(&tp, NULL) == 0) {
2574 if ((__ns_ldap_getParam(NS_LDAP_EXP_P,
2575 ¶mVal, &errorp) == NS_LDAP_SUCCESS) &&
2576 paramVal != NULL &&
2577 (char *)*paramVal != NULL) {
2578 errno = 0;
2579 expire = atol((char *)*paramVal);
2580 (void) __ns_ldap_freeParam(¶mVal);
2581 if (errno == 0) {
2582 if (expire == 0) {
2583 first_time = 0;
2584 (void) rw_unlock(&ldap_lock);
2585 (void) cond_init(&cond,
2586 USYNC_THREAD, NULL);
2587 (void) mutex_lock(&sighuplock);
2588 timeout.tv_sec =
2589 CACHESLEEPTIME;
2590 timeout.tv_nsec = 0;
2591 if (dbg_level >=
2592 DBG_PROFILE_REFRESH) {
2593 logit("getldap_refresh:"
2594 "(1)about to sleep"
2595 " for %d seconds\n",
2596 CACHESLEEPTIME);
2597 }
2598 err = cond_reltimedwait(&cond,
2599 &sighuplock, &timeout);
2600 (void) cond_destroy(&cond);
2601 (void) mutex_unlock(
2602 &sighuplock);
2603 /*
2604 * if woke up by
2605 * getldap_revalidate(),
2606 * do update right away
2607 */
2608 if (err == ETIME)
2609 continue;
2610 else {
2611 /*
2612 * if load
2613 * configuration failed
2614 * don't do update
2615 */
2616 if (load_config())
2617 perform_update
2618 ();
2619 continue;
2620 }
2621 }
2622 sleeptime = expire - tp.tv_sec;
2623 if (dbg_level >= DBG_PROFILE_REFRESH) {
2624 logit("getldap_refresh: expire "
2625 "time = %ld\n", expire);
2626 }
2627
2628 }
2629 }
2630 }
2631
2632 (void) rw_unlock(&ldap_lock);
2633
2634 /*
2635 * if this is the first time downloading
2636 * the profile or expire time already passed,
2637 * do not wait, do update
2638 */
2639 if (first_time == 0 && sleeptime > 0) {
2640 if (dbg_level >= DBG_PROFILE_REFRESH) {
2641 logit("getldap_refresh: (2)about to sleep "
2642 "for %d seconds\n", sleeptime);
2643 }
2644 (void) cond_init(&cond, USYNC_THREAD, NULL);
2645 (void) mutex_lock(&sighuplock);
2646 timeout.tv_sec = sleeptime;
2647 timeout.tv_nsec = 0;
2648 err = cond_reltimedwait(&cond,
2649 &sighuplock, &timeout);
2650 (void) cond_destroy(&cond);
2651 (void) mutex_unlock(&sighuplock);
2652 }
2653 /*
2654 * if load concfiguration failed
2655 * don't do update
2656 */
2657 if (load_config())
2658 perform_update();
2659 first_time = 0;
2660 }
2661 }
2662
2663 void
getldap_revalidate(int signal __unused)2664 getldap_revalidate(int signal __unused)
2665 {
2666 if (current_admin.debug_level >= DBG_ALL) {
2667 logit("getldap_revalidate()...\n");
2668 }
2669 /* block signal SIGHUP */
2670 (void) sighold(SIGHUP);
2671
2672 /* now awake the sleeping refresh thread */
2673 (void) cond_signal(&cond);
2674
2675 /* release signal SIGHUP */
2676 (void) sigrelse(SIGHUP);
2677
2678 }
2679
2680 void
getldap_admincred(LineBuf * config_info,ldap_call_t * in)2681 getldap_admincred(LineBuf *config_info, ldap_call_t *in)
2682 {
2683 ns_ldap_error_t *error;
2684 ldap_config_out_t *cout;
2685 ucred_t *uc = NULL;
2686
2687 if (current_admin.debug_level >= DBG_ALL) {
2688 logit("getldap_admincred()...\n");
2689 }
2690 /* check privileges */
2691 if (is_root_or_all_privs("GETADMINCRED", &uc) == 0) {
2692 logit("admin credential requested by a non-root and no ALL "
2693 "privilege user not allowed");
2694 config_info->str = NULL;
2695 config_info->len = 0;
2696 } else {
2697 (void) rw_rdlock(&ldap_lock);
2698 if ((error = __ns_ldap_LoadDoorInfo(config_info,
2699 in->ldap_u.domainname, NULL, 1)) != NULL) {
2700 if (error != NULL && error->message != NULL)
2701 logit("Error: ldap_lookup: %s\n",
2702 error->message);
2703 (void) __ns_ldap_freeError(&error);
2704
2705 config_info->str = NULL;
2706 config_info->len = 0;
2707 }
2708 /* set change cookie */
2709 cout = (ldap_config_out_t *)config_info->str;
2710 if (cout)
2711 cout->cookie = chg_config_cookie_get();
2712 (void) rw_unlock(&ldap_lock);
2713 }
2714 }
2715
2716 void
getldap_lookup(LineBuf * config_info,ldap_call_t * in)2717 getldap_lookup(LineBuf *config_info, ldap_call_t *in)
2718 {
2719 ns_ldap_error_t *error;
2720 ldap_config_out_t *cout;
2721
2722 if (current_admin.debug_level >= DBG_ALL) {
2723 logit("getldap_lookup()...\n");
2724 }
2725 (void) rw_rdlock(&ldap_lock);
2726 if ((error = __ns_ldap_LoadDoorInfo(config_info,
2727 in->ldap_u.domainname, NULL, 0)) != NULL) {
2728 if (error != NULL && error->message != NULL)
2729 logit("Error: ldap_lookup: %s\n", error->message);
2730 (void) __ns_ldap_freeError(&error);
2731
2732 config_info->str = NULL;
2733 config_info->len = 0;
2734 }
2735 /* set change cookie */
2736 cout = (ldap_config_out_t *)config_info->str;
2737 if (cout)
2738 cout->cookie = chg_config_cookie_get();
2739 (void) rw_unlock(&ldap_lock);
2740 }
2741 /*
2742 * It creates the header and data stream to be door returned and notify
2743 * chg_get_statusChange() threads.
2744 * This is called after all getldap_get_rootDSE() threads are joined.
2745 */
2746 void
test_server_change(server_info_t * head)2747 test_server_change(server_info_t *head)
2748 {
2749 server_info_t *info;
2750 int len = 0, num = 0, ds_len = 0, new_len = 0, tlen = 0;
2751 char *tmp_buf = NULL, *ptr = NULL, *status = NULL;
2752 ldap_get_change_out_t *cout;
2753
2754 ds_len = strlen(DOORLINESEP);
2755
2756 for (info = head; info; info = info->next) {
2757 (void) mutex_lock(&info->mutex[0]);
2758 if (info->sinfo[0].change != 0) {
2759 /* "9.9.9.9|NS_SERVER_CHANGE_UP|" */
2760 len += 2 * ds_len + strlen(info->sinfo[0].addr) +
2761 strlen(NS_SERVER_CHANGE_UP);
2762 num++;
2763 }
2764 (void) mutex_unlock(&info->mutex[0]);
2765 }
2766
2767 if (len == 0)
2768 return;
2769
2770 len++; /* '\0' */
2771
2772 tlen = sizeof (ldap_get_change_out_t) - sizeof (int) + len;
2773 if ((tmp_buf = malloc(tlen)) == NULL)
2774 return;
2775
2776 cout = (ldap_get_change_out_t *)tmp_buf;
2777 cout->type = NS_STATUS_CHANGE_TYPE_SERVER;
2778 /* cout->cookie is set by chg_notify_statusChange */
2779 cout->server_count = num;
2780 cout->data_size = len;
2781
2782 /* Create IP|UP or DOWN|IP|UP or DOWN| ... */
2783 ptr = cout->data;
2784 new_len = len;
2785 for (info = head; info; info = info->next) {
2786 (void) mutex_lock(&info->mutex[0]);
2787 if (info->sinfo[0].change == 0) {
2788 (void) mutex_unlock(&info->mutex[0]);
2789 continue;
2790 }
2791
2792 if (info->sinfo[0].change == NS_SERVER_UP)
2793 status = NS_SERVER_CHANGE_UP;
2794 else if (info->sinfo[0].change == NS_SERVER_DOWN)
2795 status = NS_SERVER_CHANGE_DOWN;
2796 else {
2797 syslog(LOG_WARNING, gettext("Bad change value %d"),
2798 info->sinfo[0].change);
2799 (void) mutex_unlock(&info->mutex[0]);
2800 free(tmp_buf);
2801 return;
2802 }
2803
2804 if ((snprintf(ptr, new_len, "%s%s%s%s",
2805 info->sinfo[0].addr, DOORLINESEP,
2806 status, DOORLINESEP)) >= new_len) {
2807 (void) mutex_unlock(&info->mutex[0]);
2808 break;
2809 }
2810 new_len -= strlen(ptr);
2811 ptr += strlen(ptr);
2812
2813 (void) mutex_unlock(&info->mutex[0]);
2814 }
2815 (void) chg_notify_statusChange(tmp_buf);
2816 }
2817 /*
2818 * It creates the header and data stream to be door returned and notify
2819 * chg_get_statusChange() threads.
2820 * This is called in removing server case.
2821 */
2822 static void
create_buf_and_notify(char * input,ns_server_status_t st)2823 create_buf_and_notify(char *input, ns_server_status_t st)
2824 {
2825 rm_svr_t *rms = (rm_svr_t *)input;
2826 char *tmp_buf, *ptr, *status;
2827 int len, tlen;
2828 ldap_get_change_out_t *cout;
2829
2830 /* IP|UP or DOWN| */
2831 len = 2 * strlen(DOORLINESEP) + strlen(rms->addr) +
2832 strlen(NS_SERVER_CHANGE_UP) + 1;
2833
2834 tlen = sizeof (ldap_get_change_out_t) - sizeof (int) + len;
2835
2836 if ((tmp_buf = malloc(tlen)) == NULL)
2837 return;
2838
2839 cout = (ldap_get_change_out_t *)tmp_buf;
2840 cout->type = NS_STATUS_CHANGE_TYPE_SERVER;
2841 /* cout->cookie is set by chg_notify_statusChange */
2842 cout->server_count = 1;
2843 cout->data_size = len;
2844
2845 /* Create IP|DOWN| */
2846 ptr = cout->data;
2847 if (st == NS_SERVER_UP)
2848 status = NS_SERVER_CHANGE_UP;
2849 else if (st == NS_SERVER_DOWN)
2850 status = NS_SERVER_CHANGE_DOWN;
2851
2852 (void) snprintf(ptr, len, "%s%s%s%s",
2853 rms->addr, DOORLINESEP, status, DOORLINESEP);
2854
2855 (void) chg_notify_statusChange(tmp_buf);
2856
2857 }
2858
2859 /*
2860 * Return: 0 server is down, 1 server is up
2861 */
2862 static int
contact_server(char * addr)2863 contact_server(char *addr)
2864 {
2865 char *rootDSE = NULL;
2866 ns_ldap_error_t *error = NULL;
2867 int rc;
2868
2869 if (__ns_ldap_getRootDSE(addr, &rootDSE, &error,
2870 SA_ALLOW_FALLBACK) != NS_LDAP_SUCCESS) {
2871 if (current_admin.debug_level >= DBG_ALL)
2872 logit("get rootDSE %s failed. %s", addr,
2873 error->message ? error->message : "");
2874 rc = 0;
2875 } else
2876 rc = 1;
2877
2878 if (rootDSE)
2879 free(rootDSE);
2880 if (error)
2881 (void) __ns_ldap_freeError(&error);
2882
2883 return (rc);
2884 }
2885
2886 /*
2887 * The thread is spawned to do contact_server() so it won't be blocking
2888 * getldap_serverInfo_op(INFO_OP_GETSERVER, ...) case.
2889 * After contact_server() is done, it calls
2890 * getldap_serverInfo_op(INFO_OP_REMOVESERVER, ...) to return to the remaining
2891 * program flow. It's meant to maintain the original program flow yet be
2892 * non-blocking when it's contacting server.
2893 */
2894 static void *
remove_server_thread(void * arg)2895 remove_server_thread(void *arg)
2896 {
2897 char *addr = (char *)arg, *out = NULL;
2898 int up;
2899 rm_svr_t rms;
2900
2901 (void) pthread_setname_np(pthread_self(), "remove_server");
2902
2903 up = contact_server(addr);
2904
2905 rms.addr = addr;
2906 rms.up = up;
2907
2908 (void) getldap_serverInfo_op(INFO_OP_REMOVESERVER, (char *)&rms, &out);
2909
2910 free(addr);
2911
2912 thr_exit(NULL);
2913 return (NULL);
2914 }
2915 /*
2916 * addr is allocated and is freed by remove_server_thread
2917 * It starts a thread to contact server and remove server to avoid long wait
2918 * or recursion.
2919 */
2920 static void
remove_server(char * addr)2921 remove_server(char *addr)
2922 {
2923 if (thr_create(NULL, 0, remove_server_thread,
2924 (void *)addr, THR_BOUND|THR_DETACHED, NULL) != 0) {
2925 free(addr);
2926 syslog(LOG_ERR, "thr_create failed for remove_server_thread");
2927 }
2928 }
2929 /*
2930 * Compare the server_status and mark it up or down accordingly.
2931 * This is called in removing server case.
2932 */
2933 static ns_server_status_t
set_server_status(char * input,server_info_t * head)2934 set_server_status(char *input, server_info_t *head)
2935 {
2936 rm_svr_t *rms = (rm_svr_t *)input;
2937 ns_server_status_t changed = 0;
2938 server_info_t *info;
2939
2940 for (info = head; info != NULL; info = info->next) {
2941 (void) mutex_lock(&info->mutex[0]);
2942 if (strcmp(info->sinfo[0].addr, rms->addr) == 0) {
2943 if (info->sinfo[0].server_status == INFO_SERVER_UP &&
2944 rms->up == FALSE) {
2945 info->sinfo[0].prev_server_status =
2946 info->sinfo[0].server_status;
2947 info->sinfo[0].server_status =
2948 INFO_SERVER_ERROR;
2949 info->sinfo[0].change = NS_SERVER_DOWN;
2950 changed = NS_SERVER_DOWN;
2951
2952 } else if (info->sinfo[0].server_status ==
2953 INFO_SERVER_ERROR && rms->up == TRUE) {
2954 /*
2955 * It should be INFO_SERVER_UP, but check here
2956 */
2957 info->sinfo[0].prev_server_status =
2958 info->sinfo[0].server_status;
2959 info->sinfo[0].server_status =
2960 INFO_SERVER_UP;
2961 info->sinfo[0].change = NS_SERVER_UP;
2962 changed = NS_SERVER_UP;
2963 }
2964 (void) mutex_unlock(&info->mutex[0]);
2965 break;
2966 }
2967 (void) mutex_unlock(&info->mutex[0]);
2968 }
2969 if (changed) {
2970 /* ldap_cachemgr -g option looks up [1] */
2971 (void) mutex_lock(&info->mutex[1]);
2972 info->sinfo[1].prev_server_status =
2973 info->sinfo[1].server_status;
2974 if (changed == NS_SERVER_DOWN)
2975 info->sinfo[1].server_status = INFO_SERVER_ERROR;
2976 else if (changed == NS_SERVER_UP)
2977 info->sinfo[1].server_status = INFO_SERVER_UP;
2978 (void) mutex_unlock(&info->mutex[1]);
2979 }
2980 return (changed);
2981 }
2982