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