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