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