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 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 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 * 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 * 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 }