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