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 2006 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) + 2; 674 (void) snprintf( 675 rootDSE + 676 strlen(rootDSE), 677 len, "%s=%s%s", 678 a, vals[i], 679 DOORLINESEP); 680 } 681 ldap_value_free(vals); 682 } 683 ldap_memfree(a); 684 } 685 if (ber != NULL) 686 ber_free(ber, 0); 687 } else 688 len = 0; 689 } 690 } 691 692 /* error, if no root DSE data */ 693 (void) mutex_lock(&serverInfo->mutex[1]); 694 if (len == 0) { 695 serverInfo->sinfo[1].errormsg = 696 strdup(gettext("No root DSE data returned.")); 697 if (current_admin.debug_level >= DBG_ALL) { 698 logit("getldap_get_rootDSE: %s.\n", 699 serverInfo->sinfo[1].errormsg); 700 } 701 serverInfo->sinfo[1].type 702 = INFO_RW_UNKNOWN; 703 serverInfo->sinfo[1].info_status 704 = INFO_STATUS_ERROR; 705 serverInfo->sinfo[1].server_status = INFO_SERVER_ERROR; 706 exitrc = -1; 707 } else { 708 /* assume writeable, i.e., can do modify */ 709 serverInfo->sinfo[1].type = INFO_RW_WRITEABLE; 710 serverInfo->sinfo[1].server_status 711 = INFO_SERVER_UP; 712 serverInfo->sinfo[1].info_status = INFO_STATUS_NEW; 713 /* remove the last DOORLINESEP */ 714 *(rootDSE+strlen(rootDSE)-1) = '\0'; 715 serverInfo->sinfo[1].rootDSE_data = rootDSE; 716 717 server_found = 1; 718 719 exitrc = NS_LDAP_SUCCESS; 720 } 721 (void) mutex_unlock(&serverInfo->mutex[1]); 722 723 if (resultMsg) 724 ldap_msgfree(resultMsg); 725 ldap_unbind(ld); 726 727 /* 728 * sync sinfo copies in the serverInfo. 729 * protected by mutex 730 */ 731 sync_current_with_update_copy(serverInfo); 732 /* 733 * signal that the ldap_cachemgr parent process 734 * should exit now, if it is still waiting 735 */ 736 (void) mutex_lock(&sig_mutex); 737 if (signal_done == FALSE && server_found) { 738 ppid = getppid(); 739 (void) kill(ppid, SIGUSR1); 740 if (current_admin.debug_level >= DBG_ALL) { 741 logit("getldap_get_rootDSE(): " 742 "SIGUSR1 signal sent to " 743 "parent process(%ld).\n", ppid); 744 } 745 signal_done = TRUE; 746 } 747 (void) mutex_unlock(&sig_mutex); 748 749 thr_exit((void *) exitrc); 750 751 return ((void *) NULL); 752 } 753 754 static int 755 getldap_init_serverInfo(server_info_t **head) 756 { 757 char **servers = NULL; 758 int rc = 0, i, exitrc = NS_LDAP_SUCCESS; 759 ns_ldap_error_t *errorp = NULL; 760 server_info_t *info, *tail = NULL; 761 762 *head = NULL; 763 if (current_admin.debug_level >= DBG_ALL) { 764 logit("getldap_init_serverInfo()...\n"); 765 } 766 rc = __s_api_getServers(&servers, &errorp); 767 768 if (rc != NS_LDAP_SUCCESS) { 769 logit("getldap_init_serverInfo: " 770 "__s_api_getServers failed.\n"); 771 if (errorp) 772 __ns_ldap_freeError(&errorp); 773 return (-1); 774 } 775 for (i = 0; servers[i] != NULL; i++) { 776 info = (server_info_t *)calloc(1, sizeof (server_info_t)); 777 if (info == NULL) { 778 logit("getldap_init_serverInfo: " 779 "not enough memory.\n"); 780 exitrc = NS_LDAP_MEMORY; 781 break; 782 } 783 if (i == 0) { 784 *head = info; 785 tail = info; 786 } else { 787 tail->next = info; 788 tail = info; 789 } 790 791 info->sinfo[0].addr = strdup(servers[i]); 792 if (info->sinfo[0].addr == NULL) { 793 logit("getldap_init_serverInfo: " 794 "not enough memory.\n"); 795 exitrc = NS_LDAP_MEMORY; 796 break; 797 } 798 info->sinfo[1].addr = strdup(servers[i]); 799 if (info->sinfo[1].addr == NULL) { 800 logit("getldap_init_serverInfo: " 801 "not enough memory.\n"); 802 exitrc = NS_LDAP_MEMORY; 803 break; 804 } 805 806 info->sinfo[0].type = INFO_RW_UNKNOWN; 807 info->sinfo[1].type = INFO_RW_UNKNOWN; 808 info->sinfo[0].info_status = INFO_STATUS_UNKNOWN; 809 info->sinfo[1].info_status = INFO_STATUS_UNKNOWN; 810 info->sinfo[0].server_status = INFO_SERVER_UNKNOWN; 811 info->sinfo[1].server_status = INFO_SERVER_UNKNOWN; 812 813 /* 814 * Assume at startup or after the configuration 815 * profile is refreshed, all servers are good. 816 */ 817 info->sinfo[0].prev_server_status = 818 INFO_SERVER_UP; 819 info->sinfo[1].prev_server_status = 820 INFO_SERVER_UP; 821 info->sinfo[0].hostname = NULL; 822 info->sinfo[1].hostname = NULL; 823 info->sinfo[0].rootDSE_data = NULL; 824 info->sinfo[1].rootDSE_data = NULL; 825 info->sinfo[0].errormsg = NULL; 826 info->sinfo[1].errormsg = NULL; 827 info->next = NULL; 828 } 829 __s_api_free2dArray(servers); 830 if (exitrc != NS_LDAP_SUCCESS) { 831 if (head && *head) { 832 (void) getldap_destroy_serverInfo(*head); 833 *head = NULL; 834 } 835 } 836 return (exitrc); 837 } 838 839 static int 840 getldap_destroy_serverInfo(server_info_t *head) 841 { 842 server_info_t *info, *next; 843 844 if (current_admin.debug_level >= DBG_ALL) { 845 logit("getldap_destroy_serverInfo()...\n"); 846 } 847 848 if (head == NULL) { 849 logit("getldap_destroy_serverInfo: " 850 "invalid serverInfo list.\n"); 851 return (-1); 852 } 853 854 for (info = head; info; info = next) { 855 if (info->sinfo[0].addr) 856 free(info->sinfo[0].addr); 857 if (info->sinfo[1].addr) 858 free(info->sinfo[1].addr); 859 if (info->sinfo[0].hostname) 860 free(info->sinfo[0].hostname); 861 if (info->sinfo[1].hostname) 862 free(info->sinfo[1].hostname); 863 if (info->sinfo[0].rootDSE_data) 864 free(info->sinfo[0].rootDSE_data); 865 if (info->sinfo[1].rootDSE_data) 866 free(info->sinfo[1].rootDSE_data); 867 if (info->sinfo[0].errormsg) 868 free(info->sinfo[0].errormsg); 869 if (info->sinfo[1].errormsg) 870 free(info->sinfo[1].errormsg); 871 next = info->next; 872 free(info); 873 } 874 return (NS_LDAP_SUCCESS); 875 } 876 877 static int 878 getldap_set_serverInfo(server_info_t *head, 879 int reset_bindtime) 880 { 881 server_info_t *info; 882 int atleast1 = 0; 883 thread_t *tid; 884 int num_threads = 0, i, j; 885 void *status; 886 void **paramVal = NULL; 887 ns_ldap_error_t *error = NULL; 888 889 if (current_admin.debug_level >= DBG_ALL) { 890 logit("getldap_set_serverInfo()...\n"); 891 } 892 893 if (head == NULL) { 894 logit("getldap_set_serverInfo: " 895 "invalid serverInfo list.\n"); 896 return (-1); 897 } 898 899 /* Get the bind timeout value */ 900 if (reset_bindtime == 1) { 901 tcptimeout = NS_DEFAULT_BIND_TIMEOUT * 1000; 902 (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, 903 ¶mVal, &error); 904 if (paramVal != NULL && *paramVal != NULL) { 905 /* convert to milliseconds */ 906 tcptimeout = **((int **)paramVal); 907 tcptimeout *= 1000; 908 (void) __ns_ldap_freeParam(¶mVal); 909 } 910 if (error) 911 (void) __ns_ldap_freeError(&error); 912 913 /* get search timeout value */ 914 search_timeout = NS_DEFAULT_SEARCH_TIMEOUT; 915 (void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, 916 ¶mVal, &error); 917 if (paramVal != NULL && *paramVal != NULL) { 918 search_timeout = **((int **)paramVal); 919 (void) __ns_ldap_freeParam(¶mVal); 920 } 921 if (error) 922 (void) __ns_ldap_freeError(&error); 923 924 } 925 926 for (info = head; info; info = info->next) 927 num_threads++; 928 929 if (num_threads == 0) { 930 logit("getldap_set_serverInfo: " 931 "empty serverInfo list.\n"); 932 return (-1); 933 } 934 935 tid = (thread_t *) calloc(1, sizeof (thread_t) * num_threads); 936 if (tid == NULL) { 937 logit("getldap_set_serverInfo: " 938 "No memory to create thread ID list.\n"); 939 return (-1); 940 } 941 942 for (info = head, i = 0; info; info = info->next, i++) { 943 if (thr_create(NULL, 0, 944 (void *(*)(void*))getldap_get_rootDSE, 945 (void *)info, 0, &tid[i])) { 946 logit("getldap_set_serverInfo: " 947 "can not create thread %d.\n", i + 1); 948 for (j = 0; j < i; j++) 949 (void) thr_join(tid[j], NULL, NULL); 950 free(tid); 951 return (-1); 952 } 953 } 954 955 for (i = 0; i < num_threads; i++) { 956 if (thr_join(tid[i], NULL, &status) == 0) { 957 if ((int)status == NS_LDAP_SUCCESS) 958 atleast1 = 1; 959 } 960 } 961 962 free(tid); 963 964 if (atleast1) 965 return (NS_LDAP_SUCCESS); 966 else 967 return (-1); 968 } 969 970 /* 971 * Convert an IP to a host name 972 */ 973 static int 974 getldap_ip2hostname(char *ipaddr, char **hostname) { 975 struct in_addr in; 976 struct in6_addr in6; 977 struct hostent *hp = NULL; 978 char *start = NULL, *end = NULL, delim = '\0'; 979 char *port = NULL, *addr = NULL; 980 int error_num = 0, len = 0; 981 982 if (ipaddr == NULL || hostname == NULL) 983 return (NS_LDAP_INVALID_PARAM); 984 *hostname = NULL; 985 if ((addr = strdup(ipaddr)) == NULL) 986 return (NS_LDAP_MEMORY); 987 988 if (addr[0] == '[') { 989 /* 990 * Assume it's [ipv6]:port 991 * Extract ipv6 IP 992 */ 993 start = &addr[1]; 994 if ((end = strchr(addr, ']')) != NULL) { 995 *end = '\0'; 996 delim = ']'; 997 if (*(end + 1) == ':') 998 /* extract port */ 999 port = end + 2; 1000 } else { 1001 return (NS_LDAP_INVALID_PARAM); 1002 } 1003 } else if ((end = strchr(addr, ':')) != NULL) { 1004 /* assume it's ipv4:port */ 1005 *end = '\0'; 1006 delim = ':'; 1007 start = addr; 1008 port = end + 1; 1009 } else 1010 /* No port */ 1011 start = addr; 1012 1013 1014 if (inet_pton(AF_INET, start, &in) == 1) { 1015 /* IPv4 */ 1016 hp = getipnodebyaddr((char *)&in, 1017 sizeof (struct in_addr), AF_INET, &error_num); 1018 if (hp && hp->h_name) { 1019 /* hostname + '\0' */ 1020 len = strlen(hp->h_name) + 1; 1021 if (port) 1022 /* ':' + port */ 1023 len += strlen(port) + 1; 1024 if ((*hostname = malloc(len)) == NULL) { 1025 free(addr); 1026 freehostent(hp); 1027 return (NS_LDAP_MEMORY); 1028 } 1029 1030 if (port) 1031 (void) snprintf(*hostname, len, "%s:%s", 1032 hp->h_name, port); 1033 else 1034 (void) strlcpy(*hostname, hp->h_name, len); 1035 1036 free(addr); 1037 freehostent(hp); 1038 return (NS_LDAP_SUCCESS); 1039 } else { 1040 return (NS_LDAP_NOTFOUND); 1041 } 1042 } else if (inet_pton(AF_INET6, start, &in6) == 1) { 1043 /* IPv6 */ 1044 hp = getipnodebyaddr((char *)&in6, 1045 sizeof (struct in6_addr), AF_INET6, &error_num); 1046 if (hp && hp->h_name) { 1047 /* hostname + '\0' */ 1048 len = strlen(hp->h_name) + 1; 1049 if (port) 1050 /* ':' + port */ 1051 len += strlen(port) + 1; 1052 if ((*hostname = malloc(len)) == NULL) { 1053 free(addr); 1054 freehostent(hp); 1055 return (NS_LDAP_MEMORY); 1056 } 1057 1058 if (port) 1059 (void) snprintf(*hostname, len, "%s:%s", 1060 hp->h_name, port); 1061 else 1062 (void) strlcpy(*hostname, hp->h_name, len); 1063 1064 free(addr); 1065 freehostent(hp); 1066 return (NS_LDAP_SUCCESS); 1067 } else { 1068 return (NS_LDAP_NOTFOUND); 1069 } 1070 } else { 1071 /* 1072 * A hostname 1073 * Return it as is 1074 */ 1075 if (end) 1076 *end = delim; 1077 *hostname = addr; 1078 return (NS_LDAP_SUCCESS); 1079 } 1080 } 1081 /* 1082 * getldap_get_serverInfo processes the GETLDAPSERVER door request passed 1083 * to this function from getldap_serverInfo_op(). 1084 * input: 1085 * a buffer containing an empty string (e.g., input[0]='\0';) or a string 1086 * as the "input" in printf(input, "%s%s%s%s", req, addrtype, DOORLINESEP, 1087 * addr); 1088 * where addr is the address of a server and 1089 * req is one of the following: 1090 * NS_CACHE_NEW: send a new server address, addr is ignored. 1091 * NS_CACHE_NORESP: send the next one, remove addr from list. 1092 * NS_CACHE_NEXT: send the next one, keep addr on list. 1093 * NS_CACHE_WRITE: send a non-replica server, if possible, if not, same 1094 * as NS_CACHE_NEXT. 1095 * addrtype: 1096 * NS_CACHE_ADDR_IP: return server address as is, this is default. 1097 * NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only 1098 * self credential case requires such format. 1099 * output: 1100 * a buffer containing server info in the following format: 1101 * serveraddress DOORLINESEP [ attr=value [DOORLINESEP attr=value ]...] 1102 * for example: ( here | used as DOORLINESEP for visual purposes) 1103 * 1.2.3.4|supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL 1104 * NOTE: caller should free this buffer when done using it 1105 */ 1106 static int 1107 getldap_get_serverInfo(server_info_t *head, char *input, 1108 char **output, int *svr_removed) 1109 { 1110 server_info_t *info = NULL; 1111 server_info_t *server = NULL; 1112 char *addr = NULL; 1113 char *req = NULL; 1114 char req_new[] = NS_CACHE_NEW; 1115 char addr_type[] = NS_CACHE_ADDR_IP; 1116 int matched = FALSE, len, rc = 0; 1117 char *ret_addr = NULL; 1118 1119 if (current_admin.debug_level >= DBG_ALL) { 1120 logit("getldap_get_serverInfo()...\n"); 1121 } 1122 1123 if (input == NULL || output == NULL) { 1124 logit("getldap_get_serverInfo: " 1125 "No input or output buffer.\n"); 1126 return (-1); 1127 } 1128 1129 *output = NULL; 1130 *svr_removed = FALSE; 1131 1132 if (head == NULL) { 1133 logit("getldap_get_serverInfo: " 1134 "invalid serverInfo list.\n"); 1135 return (-1); 1136 } 1137 /* 1138 * parse the input string to get req and addr, 1139 * if input is empty, i.e., input[0] == '\0', 1140 * treat it as an NS_CACHE_NEW request 1141 */ 1142 req = req_new; 1143 if (input[0] != '\0') { 1144 req = input; 1145 /* Save addr type flag */ 1146 addr_type[0] = input[1]; 1147 input[strlen(NS_CACHE_NEW)] = '\0'; 1148 /* skip acion type flag, addr type flag and DOORLINESEP */ 1149 addr = input + strlen(DOORLINESEP) + strlen(NS_CACHE_NEW) 1150 + strlen(NS_CACHE_ADDR_IP); 1151 } 1152 /* 1153 * if NS_CACHE_NEW, 1154 * or the server info is new, 1155 * starts from the 1156 * beginning of the list 1157 */ 1158 if ((strcmp(req, NS_CACHE_NEW) == 0) || 1159 (head->sinfo[0].info_status == INFO_STATUS_NEW)) 1160 matched = TRUE; 1161 for (info = head; info; info = info->next) { 1162 /* 1163 * make sure the server info stays the same 1164 * while the data is being processed 1165 */ 1166 1167 /* 1168 * This function is called to get server info list 1169 * and pass it back to door call clients. 1170 * Access the current copy (sinfo[0]) to get such 1171 * information 1172 */ 1173 (void) mutex_lock(&info->mutex[0]); 1174 1175 if (matched == FALSE && 1176 strcmp(info->sinfo[0].addr, addr) == 0) { 1177 matched = TRUE; 1178 if (strcmp(req, NS_CACHE_NORESP) == 0) { 1179 1180 /* 1181 * if the server has already been removed, 1182 * don't bother 1183 */ 1184 if (info->sinfo[0].server_status == 1185 INFO_SERVER_REMOVED) { 1186 (void) mutex_unlock(&info->mutex[0]); 1187 continue; 1188 } 1189 1190 /* 1191 * if the information is new, 1192 * give this server one more chance 1193 */ 1194 if (info->sinfo[0].info_status == 1195 INFO_STATUS_NEW && 1196 info->sinfo[0].server_status == 1197 INFO_SERVER_UP) { 1198 server = info; 1199 break; 1200 } else { 1201 /* 1202 * it is recommended that 1203 * before removing the 1204 * server from the list, 1205 * the server should be 1206 * contacted one more time 1207 * to make sure that it is 1208 * really unavailable. 1209 * For now, just trust the client 1210 * (i.e., the sldap library) 1211 * that it knows what it is 1212 * doing and would not try 1213 * to mess up the server 1214 * list. 1215 */ 1216 info->sinfo[0].prev_server_status = 1217 info->sinfo[0].server_status; 1218 info->sinfo[0].server_status = 1219 INFO_SERVER_REMOVED; 1220 /* 1221 * make sure this will be seen 1222 * if a user query the server 1223 * status via the ldap_cachemgr's 1224 * -g option 1225 */ 1226 info->sinfo[1].server_status = 1227 INFO_SERVER_REMOVED; 1228 *svr_removed = TRUE; 1229 (void) mutex_unlock(&info->mutex[0]); 1230 continue; 1231 } 1232 } else { 1233 /* 1234 * req == NS_CACHE_NEXT or NS_CACHE_WRITE 1235 */ 1236 (void) mutex_unlock(&info->mutex[0]); 1237 continue; 1238 } 1239 } 1240 1241 if (matched) { 1242 if (strcmp(req, NS_CACHE_WRITE) == 0) { 1243 if (info->sinfo[0].type == 1244 INFO_RW_WRITEABLE && 1245 info->sinfo[0].server_status == 1246 INFO_SERVER_UP) { 1247 server = info; 1248 break; 1249 } 1250 } else if (info->sinfo[0].server_status == 1251 INFO_SERVER_UP) { 1252 server = info; 1253 break; 1254 } 1255 } 1256 1257 (void) mutex_unlock(&info->mutex[0]); 1258 } 1259 1260 if (server) { 1261 if (strcmp(addr_type, NS_CACHE_ADDR_HOSTNAME) == 0) { 1262 /* 1263 * In SASL/GSSAPI case, a hostname is required for 1264 * Kerberos's service principal. 1265 * e.g. 1266 * ldap/foo.sun.com@SUN.COM 1267 */ 1268 if (server->sinfo[0].hostname == NULL) { 1269 rc = getldap_ip2hostname(server->sinfo[0].addr, 1270 &server->sinfo[0].hostname); 1271 if (rc != NS_LDAP_SUCCESS) { 1272 (void) mutex_unlock(&info->mutex[0]); 1273 return (rc); 1274 } 1275 if (current_admin.debug_level >= DBG_ALL) { 1276 logit("getldap_get_serverInfo: " 1277 "%s is converted to %s\n", 1278 server->sinfo[0].addr, 1279 server->sinfo[0].hostname); 1280 } 1281 } 1282 ret_addr = server->sinfo[0].hostname; 1283 1284 } else 1285 ret_addr = server->sinfo[0].addr; 1286 1287 1288 len = strlen(ret_addr) + 1289 strlen(server->sinfo[0].rootDSE_data) + 1290 strlen(DOORLINESEP) + 1; 1291 *output = (char *)malloc(len); 1292 if (*output == NULL) { 1293 (void) mutex_unlock(&info->mutex[0]); 1294 return (NS_LDAP_MEMORY); 1295 } 1296 (void) snprintf(*output, len, "%s%s%s", 1297 ret_addr, DOORLINESEP, 1298 server->sinfo[0].rootDSE_data); 1299 server->sinfo[0].info_status = INFO_STATUS_OLD; 1300 (void) mutex_unlock(&info->mutex[0]); 1301 return (NS_LDAP_SUCCESS); 1302 } 1303 else 1304 return (-99); 1305 } 1306 1307 /* 1308 * Format previous and next refresh time 1309 */ 1310 static int 1311 getldap_format_refresh_time(char **output, time_t *prev, time_t *next) 1312 { 1313 #define TIME_FORMAT "%Y/%m/%d %H:%M:%S" 1314 #define TIME_HEADER1 " Previous refresh time: " 1315 #define TIME_HEADER2 " Next refresh time: " 1316 int hdr1_len = strlen(gettext(TIME_HEADER1)); 1317 int hdr2_len = strlen(gettext(TIME_HEADER2)); 1318 struct tm tm; 1319 char nbuf[256]; 1320 char pbuf[256]; 1321 int len; 1322 1323 if (current_admin.debug_level >= DBG_ALL) { 1324 logit("getldap_format_refresh_time()...\n"); 1325 } 1326 1327 *output = NULL; 1328 1329 /* format the time of previous refresh */ 1330 if (*prev != 0) { 1331 (void) localtime_r(prev, &tm); 1332 (void) strftime(pbuf, sizeof (pbuf) - 1, TIME_FORMAT, &tm); 1333 } else { 1334 (void) strcpy(pbuf, gettext("NOT DONE")); 1335 } 1336 1337 /* format the time of next refresh */ 1338 if (*next != 0) { 1339 (void) localtime_r(next, &tm); 1340 (void) strftime(nbuf, sizeof (nbuf) - 1, TIME_FORMAT, &tm); 1341 } else { 1342 (void) strcpy(nbuf, gettext("NOT SET")); 1343 } 1344 1345 len = hdr1_len + hdr2_len + strlen(nbuf) + 1346 strlen(pbuf) + 2 * strlen(DOORLINESEP) + 1; 1347 1348 *output = malloc(len); 1349 if (*output == NULL) 1350 return (-1); 1351 1352 (void) snprintf(*output, len, "%s%s%s%s%s%s", 1353 gettext(TIME_HEADER1), pbuf, DOORLINESEP, 1354 gettext(TIME_HEADER2), nbuf, DOORLINESEP); 1355 1356 return (NS_LDAP_SUCCESS); 1357 } 1358 1359 /* 1360 * getldap_get_server_stat processes the GETSTAT request passed 1361 * to this function from getldap_serverInfo_op(). 1362 * output: 1363 * a buffer containing info for all the servers. 1364 * For each server, the data is in the following format: 1365 * server: server address or name, status: unknown|up|down|removed DOORLINESEP 1366 * for example: ( here | used as DOORLINESEP for visual purposes) 1367 * server: 1.2.3.4, status: down|server: 2.2.2.2, status: up| 1368 * NOTE: caller should free this buffer when done using it 1369 */ 1370 static int 1371 getldap_get_server_stat(server_info_t *head, char **output, 1372 time_t *prev, time_t *next) 1373 { 1374 #define S_HEADER "Server information: " 1375 #define S_FORMAT " server: %s, status: %s%s" 1376 #define S_ERROR " error message: %s%s" 1377 server_info_t *info = NULL; 1378 int header_len = strlen(gettext(S_HEADER)); 1379 int format_len = strlen(gettext(S_FORMAT)); 1380 int error_len = strlen(gettext(S_ERROR)); 1381 int len = header_len + strlen(DOORLINESEP); 1382 int len1 = 0; 1383 char *status, *output1 = NULL, *tmpptr; 1384 1385 *output = NULL; 1386 1387 if (current_admin.debug_level >= DBG_ALL) { 1388 logit("getldap_get_server_stat()...\n"); 1389 } 1390 1391 if (head == NULL) { 1392 logit("getldap_get_server_stat: " 1393 "invalid serverInfo list.\n"); 1394 return (-1); 1395 } 1396 1397 /* format previous and next refresh time */ 1398 (void) getldap_format_refresh_time(&output1, prev, next); 1399 if (output1 == NULL) 1400 return (-1); 1401 len += strlen(output1); 1402 len1 = len + strlen(DOORLINESEP) + 1; 1403 1404 *output = (char *)calloc(1, len1); 1405 if (*output == NULL) { 1406 free(output1); 1407 return (-1); 1408 } 1409 1410 /* insert header string and refresh time info */ 1411 (void) snprintf(*output, len1, "%s%s%s", 1412 gettext(S_HEADER), DOORLINESEP, output1); 1413 1414 for (info = head; info; info = info->next) { 1415 1416 /* 1417 * make sure the server info stays the same 1418 * while the data is being processed 1419 */ 1420 (void) mutex_lock(&info->mutex[1]); 1421 1422 /* 1423 * When the updating process is under way(getldap_get_rootDSE) 1424 * the update copy(sinfo[1] is the latest copy. 1425 * When the updating process 1426 * is done, the current copy (sinfo[0]) has the latest status, 1427 * which is still identical to the update copy. 1428 * So update copy has the latest status. 1429 * Use the update copy(sinfo[1]) to show status 1430 * (ldap_cachemgr -g). 1431 * 1432 */ 1433 1434 switch (info->sinfo[1].server_status) { 1435 case INFO_SERVER_UNKNOWN: 1436 status = gettext("UNKNOWN"); 1437 break; 1438 case INFO_SERVER_CONNECTING: 1439 status = gettext("CONNECTING"); 1440 break; 1441 case INFO_SERVER_UP: 1442 status = gettext("UP"); 1443 break; 1444 case INFO_SERVER_ERROR: 1445 status = gettext("ERROR"); 1446 break; 1447 case INFO_SERVER_REMOVED: 1448 status = gettext("REMOVED"); 1449 break; 1450 } 1451 1452 len += format_len + strlen(status) + 1453 strlen(info->sinfo[1].addr) + 1454 strlen(DOORLINESEP); 1455 if (info->sinfo[1].errormsg != NULL) 1456 len += error_len + 1457 strlen(info->sinfo[1].errormsg) + 1458 strlen(DOORLINESEP); 1459 1460 tmpptr = (char *)realloc(*output, len); 1461 if (tmpptr == NULL) { 1462 free(output1); 1463 free(*output); 1464 *output = NULL; 1465 (void) mutex_unlock(&info->mutex[1]); 1466 return (-1); 1467 } else 1468 *output = tmpptr; 1469 1470 /* insert server IP addr or name and status */ 1471 len1 = len - strlen(*output); 1472 (void) snprintf(*output + strlen(*output), len1, 1473 gettext(S_FORMAT), info->sinfo[1].addr, 1474 status, DOORLINESEP); 1475 /* insert error message if any */ 1476 len1 = len - strlen(*output); 1477 if (info->sinfo[1].errormsg != NULL) 1478 (void) snprintf(*output + strlen(*output), len1, 1479 gettext(S_ERROR), 1480 info->sinfo[1].errormsg, 1481 DOORLINESEP); 1482 1483 (void) mutex_unlock(&info->mutex[1]); 1484 1485 } 1486 1487 free(output1); 1488 return (NS_LDAP_SUCCESS); 1489 } 1490 1491 /* 1492 * Format and return the refresh time statistics 1493 */ 1494 static int 1495 getldap_get_refresh_stat(char **output) 1496 { 1497 #define R_HEADER0 "Configuration refresh information: " 1498 #define R_HEADER1 " Configured to NO REFRESH." 1499 int hdr0_len = strlen(gettext(R_HEADER0)); 1500 int hdr1_len = strlen(gettext(R_HEADER1)); 1501 int cache_ttl = -1, len = 0; 1502 time_t expire = 0; 1503 void **paramVal = NULL; 1504 ns_ldap_error_t *errorp = NULL; 1505 char *output1 = NULL; 1506 1507 if (current_admin.debug_level >= DBG_ALL) { 1508 logit("getldap_get_refresh_stat()...\n"); 1509 } 1510 1511 *output = NULL; 1512 1513 /* get configured cache TTL */ 1514 if ((__ns_ldap_getParam(NS_LDAP_CACHETTL_P, 1515 ¶mVal, &errorp) == NS_LDAP_SUCCESS) && 1516 paramVal != NULL && 1517 (char *)*paramVal != NULL) { 1518 cache_ttl = atol((char *)*paramVal); 1519 } else { 1520 if (errorp) 1521 __ns_ldap_freeError(&errorp); 1522 } 1523 (void) __ns_ldap_freeParam(¶mVal); 1524 1525 /* cound not get cache TTL */ 1526 if (cache_ttl == -1) 1527 return (-1); 1528 1529 if (cache_ttl == 0) { 1530 len = hdr0_len + hdr1_len + 1531 2 * strlen(DOORLINESEP) + 1; 1532 *output = malloc(len); 1533 if (*output == NULL) 1534 return (-1); 1535 (void) snprintf(*output, len, "%s%s%s%s", 1536 gettext(R_HEADER0), DOORLINESEP, 1537 gettext(R_HEADER1), DOORLINESEP); 1538 } else { 1539 1540 /* get configuration expiration time */ 1541 if ((__ns_ldap_getParam(NS_LDAP_EXP_P, 1542 ¶mVal, &errorp) == NS_LDAP_SUCCESS) && 1543 paramVal != NULL && 1544 (char *)*paramVal != NULL) { 1545 expire = (time_t)atol((char *)*paramVal); 1546 } else { 1547 if (errorp) 1548 __ns_ldap_freeError(&errorp); 1549 } 1550 1551 (void) __ns_ldap_freeParam(¶mVal); 1552 1553 /* cound not get expiration time */ 1554 if (expire == -1) 1555 return (-1); 1556 1557 /* format previous and next refresh time */ 1558 (void) getldap_format_refresh_time(&output1, 1559 &prev_refresh_time, &expire); 1560 if (output1 == NULL) 1561 return (-1); 1562 1563 len = hdr0_len + strlen(output1) + 1564 2 * strlen(DOORLINESEP) + 1; 1565 *output = malloc(len); 1566 if (*output == NULL) { 1567 free(output1); 1568 return (-1); 1569 } 1570 (void) snprintf(*output, len, "%s%s%s%s", 1571 gettext(R_HEADER0), DOORLINESEP, 1572 output1, DOORLINESEP); 1573 free(output1); 1574 } 1575 1576 return (NS_LDAP_SUCCESS); 1577 } 1578 1579 static int 1580 getldap_get_cacheTTL() 1581 { 1582 void **paramVal = NULL; 1583 ns_ldap_error_t *error; 1584 int rc = 0, cachettl; 1585 1586 1587 if (current_admin.debug_level >= DBG_ALL) { 1588 logit("getldap_get_cacheTTL()....\n"); 1589 } 1590 1591 if ((rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, 1592 ¶mVal, &error)) != NS_LDAP_SUCCESS) { 1593 if (error != NULL && error->message != NULL) 1594 logit("Error: Unable to get configuration " 1595 "refresh TTL: %s\n", 1596 error->message); 1597 else { 1598 char *tmp; 1599 1600 __ns_ldap_err2str(rc, &tmp); 1601 logit("Error: Unable to get configuration " 1602 "refresh TTL: %s\n", tmp); 1603 } 1604 (void) __ns_ldap_freeParam(¶mVal); 1605 (void) __ns_ldap_freeError(&error); 1606 return (-1); 1607 } 1608 if (paramVal == NULL || (char *)*paramVal == NULL) 1609 return (-1); 1610 cachettl = atol((char *)*paramVal); 1611 (void) __ns_ldap_freeParam(¶mVal); 1612 return (cachettl); 1613 } 1614 1615 1616 /* 1617 * This function implements the adaptive server list refresh 1618 * algorithm used by ldap_cachemgr. The idea is to have the 1619 * refresh TTL adjust itself between maximum and minimum 1620 * values. If the server list has been walked three times 1621 * in a row without errors, the TTL will be doubled. This will 1622 * be done repeatedly until the maximum value is reached 1623 * or passed. If passed, the maximum value will be used. 1624 * If any time a server is found to be down/bad, either 1625 * after another server list walk or informed by libsldap via 1626 * the GETLDAPSERVER door calls, the TTL will be set to half 1627 * of its value, again repeatedly, but no less than the minimum 1628 * value. Also, at any time, if all the servers on the list 1629 * are found to be down/bad, the TTL will be set to minimum, 1630 * so that a "no-server" refresh loop should be entered to try 1631 * to find a good server as soon as possible. The caller 1632 * could check the no_gd_server flag for this situation. 1633 * The maximum and minimum values are initialized when the input 1634 * refresh_ttl is set to zero, this should occur during 1635 * ldap_cachemgr startup or every time the server list is 1636 * recreated after the configuration profile is refreshed 1637 * from an LDAP server. The maximum is set to the value of 1638 * the NS_LDAP_CACHETTL parameter (configuration profile 1639 * refresh TTL), but if it is zero (never refreshed) or can 1640 * not be retrieved, the maximum is set to the macro 1641 * REFRESHTTL_MAX (12 hours) defined below. The minimum is 1642 * set to REFRESHTTL_MIN, which is the TCP connection timeout 1643 * (tcptimeout) set via the LDAP API ldap_set_option() 1644 * with the new LDAP_X_OPT_CONNECT_TIMEOUT option plus 10 seconds. 1645 * This accounts for the maximum possible timeout value for an 1646 * LDAP TCP connect call.The first refresh TTL, initial value of 1647 * refresh_ttl, will be set to the smaller of the two, 1648 * REFRESHTTL_REGULAR (10 minutes) or (REFRESHTTL_MAX + REFRESHTTL_MIN)/2. 1649 * The idea is to have a low starting value and have the value 1650 * stay low if the network/server is unstable, but eventually 1651 * the value will move up to maximum and stay there if the 1652 * network/server is stable. 1653 */ 1654 static int 1655 getldap_set_refresh_ttl(server_info_t *head, int *refresh_ttl, 1656 int *no_gd_server) 1657 { 1658 #define REFRESHTTL_REGULAR 600 1659 #define REFRESHTTL_MAX 43200 1660 /* tcptimeout is in milliseconds */ 1661 #define REFRESHTTL_MIN (tcptimeout/1000) + 10 1662 #define UP_REFRESH_TTL_NUM 2 1663 1664 static mutex_t refresh_mutex; 1665 static int refresh_ttl_max = 0; 1666 static int refresh_ttl_min = 0; 1667 static int num_walked_ok = 0; 1668 int num_servers = 0; 1669 int num_good_servers = 0; 1670 int num_prev_good_servers = 0; 1671 server_info_t *info; 1672 1673 /* allow one thread at a time */ 1674 (void) mutex_lock(&refresh_mutex); 1675 1676 if (current_admin.debug_level >= DBG_ALL) { 1677 logit("getldap_set_refresh_ttl()...\n"); 1678 } 1679 1680 if (!head || !refresh_ttl || !no_gd_server) { 1681 logit("getldap_set_refresh_ttl: head is " 1682 "NULL or refresh_ttl is NULL or " 1683 "no_gd_server is NULL"); 1684 (void) mutex_unlock(&refresh_mutex); 1685 return (-1); 1686 } 1687 *no_gd_server = FALSE; 1688 1689 /* 1690 * init max. min. TTLs if first time through or a fresh one 1691 */ 1692 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1693 logit("getldap_set_refresh_ttl:(1) refresh ttl is %d " 1694 "seconds\n", *refresh_ttl); 1695 } 1696 if (*refresh_ttl == 0) { 1697 num_walked_ok = 0; 1698 /* 1699 * init cache manager server list TTL: 1700 * 1701 * init the min. TTL to 1702 * REFRESHTTL_MIN ( 2*(TCP MSL) + 10 seconds) 1703 */ 1704 refresh_ttl_min = REFRESHTTL_MIN; 1705 1706 /* 1707 * try to set the max. TTL to 1708 * configuration refresh TTL (NS_LDAP_CACHETTL), 1709 * if error (-1), or never refreshed (0), 1710 * set it to REFRESHTTL_MAX (12 hours) 1711 */ 1712 refresh_ttl_max = getldap_get_cacheTTL(); 1713 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1714 logit("getldap_set_refresh_ttl:(2) refresh ttl is %d " 1715 "seconds\n", *refresh_ttl); 1716 logit("getldap_set_refresh_ttl:(2) max ttl is %d, " 1717 "min ttl is %d seconds\n", 1718 refresh_ttl_max, refresh_ttl_min); 1719 } 1720 if (refresh_ttl_max <= 0) 1721 refresh_ttl_max = REFRESHTTL_MAX; 1722 else if (refresh_ttl_max < refresh_ttl_min) 1723 refresh_ttl_max = refresh_ttl_min; 1724 1725 /* 1726 * init the first TTL to the smaller of the two: 1727 * REFRESHTTL_REGULAR ( 10 minutes), 1728 * (refresh_ttl_max + refresh_ttl_min)/2 1729 */ 1730 *refresh_ttl = REFRESHTTL_REGULAR; 1731 if (*refresh_ttl > (refresh_ttl_max + refresh_ttl_min) / 2) 1732 *refresh_ttl = (refresh_ttl_max + refresh_ttl_min) / 2; 1733 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1734 logit("getldap_set_refresh_ttl:(3) refresh ttl is %d " 1735 "seconds\n", *refresh_ttl); 1736 logit("getldap_set_refresh_ttl:(3) max ttl is %d, " 1737 "min ttl is %d seconds\n", 1738 refresh_ttl_max, refresh_ttl_min); 1739 } 1740 } 1741 1742 /* 1743 * get the servers statistics: 1744 * number of servers on list 1745 * number of good servers on list 1746 * number of pevious good servers on list 1747 */ 1748 for (info = head; info; info = info->next) { 1749 num_servers++; 1750 (void) mutex_lock(&info->mutex[0]); 1751 if (info->sinfo[0].server_status == INFO_SERVER_UP) 1752 num_good_servers++; 1753 /* 1754 * Server's previous status could be UNKNOWN 1755 * only between the very first and second 1756 * refresh. Treat that UNKNOWN status as up 1757 */ 1758 if (info->sinfo[0].prev_server_status 1759 == INFO_SERVER_UP || 1760 info->sinfo[0].prev_server_status 1761 == INFO_SERVER_UNKNOWN) 1762 num_prev_good_servers++; 1763 (void) mutex_unlock(&info->mutex[0]); 1764 } 1765 1766 /* 1767 * if the server list is walked three times in a row 1768 * without problems, double the refresh TTL but no more 1769 * than the max. refresh TTL 1770 */ 1771 if (num_good_servers == num_servers) { 1772 num_walked_ok++; 1773 if (num_walked_ok > UP_REFRESH_TTL_NUM) { 1774 1775 *refresh_ttl = *refresh_ttl * 2; 1776 if (*refresh_ttl > refresh_ttl_max) 1777 *refresh_ttl = refresh_ttl_max; 1778 1779 num_walked_ok = 0; 1780 } 1781 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1782 logit("getldap_set_refresh_ttl:(4) refresh ttl is %d " 1783 "seconds\n", *refresh_ttl); 1784 } 1785 } else if (num_good_servers == 0) { 1786 /* 1787 * if no good server found, 1788 * set refresh TTL to miminum 1789 */ 1790 *refresh_ttl = refresh_ttl_min; 1791 *no_gd_server = TRUE; 1792 num_walked_ok = 0; 1793 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1794 logit("getldap_set_refresh_ttl:(5) refresh ttl is %d " 1795 "seconds\n", *refresh_ttl); 1796 } 1797 } else if (num_prev_good_servers > num_good_servers) { 1798 /* 1799 * if more down/bad servers found, 1800 * decrease the refresh TTL by half 1801 * but no less than the min. refresh TTL 1802 */ 1803 *refresh_ttl = *refresh_ttl / 2; 1804 if (*refresh_ttl < refresh_ttl_min) 1805 *refresh_ttl = refresh_ttl_min; 1806 num_walked_ok = 0; 1807 logit("getldap_set_refresh_ttl:(6) refresh ttl is %d " 1808 "seconds\n", *refresh_ttl); 1809 1810 } 1811 1812 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1813 logit("getldap_set_refresh_ttl:(7) refresh ttl is %d seconds\n", 1814 *refresh_ttl); 1815 } 1816 (void) mutex_unlock(&refresh_mutex); 1817 return (0); 1818 } 1819 1820 static int 1821 getldap_serverInfo_op(info_op_t op, char *input, char **output) 1822 { 1823 1824 static rwlock_t info_lock = DEFAULTRWLOCK; 1825 static rwlock_t info_lock_old = DEFAULTRWLOCK; 1826 static mutex_t info_mutex; 1827 static cond_t info_cond; 1828 static int creating = FALSE; 1829 static int refresh_ttl = 0; 1830 static int sec_to_refresh = 0; 1831 static int in_no_server_mode = FALSE; 1832 1833 static server_info_t *serverInfo = NULL; 1834 static server_info_t *serverInfo_old = NULL; 1835 server_info_t *serverInfo_1; 1836 int is_creating; 1837 int err, no_server_good = FALSE; 1838 int server_removed = FALSE; 1839 static struct timespec timeout; 1840 struct timespec new_timeout; 1841 struct timeval tp; 1842 static time_t prev_refresh = 0, next_refresh = 0; 1843 1844 if (current_admin.debug_level >= DBG_ALL) { 1845 logit("getldap_serverInfo_op()...\n"); 1846 } 1847 switch (op) { 1848 case INFO_OP_CREATE: 1849 if (current_admin.debug_level >= DBG_ALL) { 1850 logit("operation is INFO_OP_CREATE...\n"); 1851 } 1852 1853 /* 1854 * indicate that the server info is being 1855 * (re)created, so that the refresh thread 1856 * will not refresh the info list right 1857 * after the list got (re)created 1858 */ 1859 (void) mutex_lock(&info_mutex); 1860 is_creating = creating; 1861 creating = TRUE; 1862 (void) mutex_unlock(&info_mutex); 1863 1864 if (is_creating) 1865 break; 1866 /* 1867 * create an empty info list 1868 */ 1869 (void) getldap_init_serverInfo(&serverInfo_1); 1870 /* 1871 * exit if list not created 1872 */ 1873 if (serverInfo_1 == NULL) { 1874 (void) mutex_lock(&info_mutex); 1875 creating = FALSE; 1876 (void) mutex_unlock(&info_mutex); 1877 break; 1878 } 1879 /* 1880 * make the new server info available: 1881 * use writer lock here, so that the switch 1882 * is done after all the reader locks have 1883 * been released. 1884 */ 1885 (void) rw_wrlock(&info_lock); 1886 serverInfo = serverInfo_1; 1887 /* 1888 * if this is the first time 1889 * the server list is being created, 1890 * (i.e., serverInfo_old is NULL) 1891 * make the old list same as the new 1892 * so the GETSERVER code can do its work 1893 */ 1894 if (serverInfo_old == NULL) 1895 serverInfo_old = serverInfo_1; 1896 (void) rw_unlock(&info_lock); 1897 1898 /* 1899 * fill the new info list 1900 */ 1901 (void) rw_rdlock(&info_lock); 1902 /* reset bind time (tcptimeout) */ 1903 (void) getldap_set_serverInfo(serverInfo, 1); 1904 1905 (void) mutex_lock(&info_mutex); 1906 /* 1907 * set cache manager server list TTL, 1908 * set refresh_ttl to zero to indicate a fresh one 1909 */ 1910 refresh_ttl = 0; 1911 (void) getldap_set_refresh_ttl(serverInfo, 1912 &refresh_ttl, &no_server_good); 1913 sec_to_refresh = refresh_ttl; 1914 1915 /* statistics: previous refresh time */ 1916 if (gettimeofday(&tp, NULL) == 0) 1917 prev_refresh = tp.tv_sec; 1918 1919 creating = FALSE; 1920 1921 /* 1922 * if no server found or available, 1923 * tell the server info refresh thread 1924 * to start the "no-server" refresh loop 1925 * otherwise reset the in_no_server_mode flag 1926 */ 1927 if (no_server_good) { 1928 sec_to_refresh = 0; 1929 in_no_server_mode = TRUE; 1930 } else 1931 in_no_server_mode = FALSE; 1932 /* 1933 * awake the sleeping refresh thread 1934 */ 1935 (void) cond_signal(&info_cond); 1936 1937 (void) mutex_unlock(&info_mutex); 1938 (void) rw_unlock(&info_lock); 1939 1940 /* 1941 * delete the old server info 1942 */ 1943 (void) rw_wrlock(&info_lock_old); 1944 if (serverInfo_old != serverInfo) 1945 (void) getldap_destroy_serverInfo(serverInfo_old); 1946 /* 1947 * serverInfo_old needs to be the same as 1948 * serverinfo now. 1949 * it will be used by GETSERVER processing. 1950 */ 1951 serverInfo_old = serverInfo; 1952 (void) rw_unlock(&info_lock_old); 1953 break; 1954 case INFO_OP_DELETE: 1955 if (current_admin.debug_level >= DBG_ALL) { 1956 logit("operation is INFO_OP_DELETE...\n"); 1957 } 1958 /* 1959 * use writer lock here, so that the delete would 1960 * not start until all the reader locks have 1961 * been released. 1962 */ 1963 (void) rw_wrlock(&info_lock); 1964 if (serverInfo) 1965 (void) getldap_destroy_serverInfo(serverInfo); 1966 serverInfo = NULL; 1967 (void) rw_unlock(&info_lock); 1968 break; 1969 case INFO_OP_REFRESH: 1970 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 1971 logit("operation is INFO_OP_REFRESH...\n"); 1972 } 1973 /* 1974 * if server info is currently being 1975 * (re)created, do nothing 1976 */ 1977 (void) mutex_lock(&info_mutex); 1978 is_creating = creating; 1979 (void) mutex_unlock(&info_mutex); 1980 if (is_creating) 1981 break; 1982 1983 (void) rw_rdlock(&info_lock); 1984 if (serverInfo) { 1985 /* do not reset bind time (tcptimeout) */ 1986 (void) getldap_set_serverInfo(serverInfo, 0); 1987 1988 (void) mutex_lock(&info_mutex); 1989 1990 /* statistics: previous refresh time */ 1991 if (gettimeofday(&tp, NULL) == 0) 1992 prev_refresh = tp.tv_sec; 1993 /* 1994 * set cache manager server list TTL 1995 */ 1996 (void) getldap_set_refresh_ttl(serverInfo, 1997 &refresh_ttl, &no_server_good); 1998 /* 1999 * if no good server found, 2000 * tell the server info refresh thread 2001 * to start the "no-server" refresh loop 2002 * otherwise reset the in_no_server_mode flag 2003 */ 2004 if (no_server_good) { 2005 in_no_server_mode = TRUE; 2006 sec_to_refresh = 0; 2007 } else { 2008 in_no_server_mode = FALSE; 2009 sec_to_refresh = refresh_ttl; 2010 } 2011 if (current_admin.debug_level >= 2012 DBG_SERVER_LIST_REFRESH) { 2013 logit("getldap_serverInfo_op(" 2014 "INFO_OP_REFRESH):" 2015 " seconds refresh: %d second(s)....\n", 2016 sec_to_refresh); 2017 } 2018 (void) mutex_unlock(&info_mutex); 2019 } 2020 (void) rw_unlock(&info_lock); 2021 2022 break; 2023 case INFO_OP_REFRESH_WAIT: 2024 if (current_admin.debug_level >= DBG_SERVER_LIST_REFRESH) { 2025 logit("operation is INFO_OP_REFRESH_WAIT...\n"); 2026 } 2027 (void) cond_init(&info_cond, NULL, NULL); 2028 (void) mutex_lock(&info_mutex); 2029 err = 0; 2030 while (err != ETIME) { 2031 int sleeptime; 2032 /* 2033 * if need to go into the "no-server" refresh 2034 * loop, set timout value to 2035 * REFRESH_DELAY_WHEN_NO_SERVER 2036 */ 2037 if (sec_to_refresh == 0) { 2038 sec_to_refresh = refresh_ttl; 2039 timeout.tv_sec = time(NULL) + 2040 REFRESH_DELAY_WHEN_NO_SERVER; 2041 sleeptime = REFRESH_DELAY_WHEN_NO_SERVER; 2042 if (current_admin.debug_level >= 2043 DBG_SERVER_LIST_REFRESH) { 2044 logit("getldap_serverInfo_op(" 2045 "INFO_OP_REFRESH_WAIT):" 2046 " entering no-server " 2047 "refresh loop...\n"); 2048 } 2049 } else { 2050 timeout.tv_sec = time(NULL) + sec_to_refresh; 2051 sleeptime = sec_to_refresh; 2052 } 2053 timeout.tv_nsec = 0; 2054 2055 /* statistics: next refresh time */ 2056 next_refresh = timeout.tv_sec; 2057 2058 if (current_admin.debug_level >= 2059 DBG_SERVER_LIST_REFRESH) { 2060 logit("getldap_serverInfo_op(" 2061 "INFO_OP_REFRESH_WAIT):" 2062 " about to sleep for %d second(s)...\n", 2063 sleeptime); 2064 } 2065 err = cond_timedwait(&info_cond, 2066 &info_mutex, &timeout); 2067 } 2068 (void) cond_destroy(&info_cond); 2069 (void) mutex_unlock(&info_mutex); 2070 break; 2071 case INFO_OP_GETSERVER: 2072 if (current_admin.debug_level >= DBG_ALL) { 2073 logit("operation is INFO_OP_GETSERVER...\n"); 2074 } 2075 *output = NULL; 2076 /* 2077 * GETSERVER processing always use 2078 * serverInfo_old to retrieve server infomation. 2079 * serverInfo_old is equal to serverInfo 2080 * most of the time, except when a new 2081 * server list is being created. 2082 * This is why the check for is_creating 2083 * is needed below. 2084 */ 2085 (void) rw_rdlock(&info_lock_old); 2086 2087 if (serverInfo_old == NULL) { 2088 (void) rw_unlock(&info_lock_old); 2089 break; 2090 } else 2091 (void) getldap_get_serverInfo(serverInfo_old, 2092 input, output, &server_removed); 2093 (void) rw_unlock(&info_lock_old); 2094 2095 /* 2096 * if server info is currently being 2097 * (re)created, do nothing 2098 */ 2099 2100 (void) mutex_lock(&info_mutex); 2101 is_creating = creating; 2102 (void) mutex_unlock(&info_mutex); 2103 if (is_creating) 2104 break; 2105 2106 /* 2107 * set cache manager server list TTL if necessary 2108 */ 2109 if (*output == NULL || server_removed) { 2110 (void) rw_rdlock(&info_lock); 2111 (void) mutex_lock(&info_mutex); 2112 2113 (void) getldap_set_refresh_ttl(serverInfo, 2114 &refresh_ttl, &no_server_good); 2115 2116 /* 2117 * if no good server found, need to go into 2118 * the "no-server" refresh loop 2119 * to find a server as soon as possible 2120 * otherwise reset the in_no_server_mode flag 2121 */ 2122 if (no_server_good) { 2123 /* 2124 * if already in no-server mode, 2125 * don't brother 2126 */ 2127 if (in_no_server_mode == FALSE) { 2128 sec_to_refresh = 0; 2129 in_no_server_mode = TRUE; 2130 (void) cond_signal(&info_cond); 2131 } 2132 (void) mutex_unlock(&info_mutex); 2133 (void) rw_unlock(&info_lock); 2134 break; 2135 } else { 2136 in_no_server_mode = FALSE; 2137 sec_to_refresh = refresh_ttl; 2138 } 2139 /* 2140 * if the refresh thread will be timed out 2141 * longer than refresh_ttl seconds, 2142 * wake it up to make it wait on the new 2143 * time out value 2144 */ 2145 new_timeout.tv_sec = time(NULL) + refresh_ttl; 2146 if (new_timeout.tv_sec < timeout.tv_sec) 2147 (void) cond_signal(&info_cond); 2148 2149 (void) mutex_unlock(&info_mutex); 2150 (void) rw_unlock(&info_lock); 2151 } 2152 break; 2153 case INFO_OP_GETSTAT: 2154 if (current_admin.debug_level >= DBG_ALL) { 2155 logit("operation is INFO_OP_GETSTAT...\n"); 2156 } 2157 *output = NULL; 2158 (void) rw_rdlock(&info_lock); 2159 if (serverInfo) { 2160 (void) getldap_get_server_stat(serverInfo, 2161 output, &prev_refresh, &next_refresh); 2162 } 2163 (void) rw_unlock(&info_lock); 2164 break; 2165 default: 2166 logit("getldap_serverInfo_op(): " 2167 "invalid operation code (%d).\n", op); 2168 return (-1); 2169 break; 2170 } 2171 return (NS_LDAP_SUCCESS); 2172 } 2173 2174 void 2175 getldap_serverInfo_refresh() 2176 { 2177 int always = 1; 2178 2179 if (current_admin.debug_level >= DBG_ALL) { 2180 logit("getldap_serverInfo_refresh()...\n"); 2181 } 2182 2183 /* create the server info list */ 2184 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL); 2185 2186 while (always) { 2187 /* 2188 * the operation INFO_OP_REFRESH_WAIT 2189 * causes this thread to wait until 2190 * it is time to do refresh, 2191 * see getldap_serverInfo_op() for details 2192 */ 2193 (void) getldap_serverInfo_op(INFO_OP_REFRESH_WAIT, NULL, NULL); 2194 (void) getldap_serverInfo_op(INFO_OP_REFRESH, NULL, NULL); 2195 } 2196 } 2197 2198 void 2199 getldap_getserver(ldap_return_t *out, ldap_call_t *in) 2200 { 2201 char *outstr = NULL; 2202 char req[] = "0"; 2203 2204 if (current_admin.debug_level >= DBG_ALL) { 2205 logit("getldap_getserver()...\n"); 2206 } 2207 2208 /* assume no server found */ 2209 out->ldap_errno = -1; 2210 out->ldap_return_code = NOTFOUND; 2211 out->ldap_bufferbytesused = sizeof (*out); 2212 2213 /* make sure the request is valid */ 2214 req[0] = (in->ldap_u.servername)[0]; 2215 if ((req[0] != '\0') && 2216 (strcmp(req, NS_CACHE_NEW) != 0) && 2217 (strcmp(req, NS_CACHE_NORESP) != 0) && 2218 (strcmp(req, NS_CACHE_NEXT) != 0) && 2219 (strcmp(req, NS_CACHE_WRITE) != 0)) { 2220 return; 2221 } 2222 2223 (void) getldap_serverInfo_op(INFO_OP_GETSERVER, 2224 in->ldap_u.domainname, &outstr); 2225 2226 if (outstr == NULL) 2227 return; 2228 2229 out->ldap_bufferbytesused = sizeof (ldap_return_t); 2230 (void) strncpy(out->ldap_u.config, outstr, strlen(outstr)+1); 2231 2232 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) { 2233 /* Log server IP */ 2234 char *ptr; 2235 ptr = strstr(outstr, DOORLINESEP); 2236 if (ptr) { 2237 *ptr = '\0'; 2238 logit("getldap_getserver: got server %s\n", outstr); 2239 } else 2240 logit("getldap_getserver: Missing %s." 2241 " Internal error\n", DOORLINESEP); 2242 } 2243 free(outstr); 2244 out->ldap_return_code = SUCCESS; 2245 out->ldap_errno = 0; 2246 2247 } 2248 2249 void 2250 getldap_get_cacheData(ldap_return_t *out, ldap_call_t *in) 2251 { 2252 char *outstr = NULL, *instr = NULL; 2253 int datatype = CACHE_MAP_UNKNOWN; 2254 2255 if (current_admin.debug_level >= DBG_ALL) { 2256 logit("getldap_get_cacheData()...\n"); 2257 } 2258 2259 /* assume no cache data found */ 2260 out->ldap_errno = -1; 2261 out->ldap_return_code = NOTFOUND; 2262 out->ldap_bufferbytesused = sizeof (*out); 2263 2264 /* make sure the request is valid */ 2265 if (strncmp(in->ldap_u.servername, 2266 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0) 2267 datatype = CACHE_MAP_DN2DOMAIN; 2268 2269 if (datatype == CACHE_MAP_UNKNOWN) 2270 return; 2271 2272 instr = strstr(in->ldap_u.servername, DOORLINESEP); 2273 if (instr == NULL) 2274 return; 2275 instr += strlen(DOORLINESEP); 2276 if (*instr == '\0') 2277 return; 2278 2279 (void) getldap_cache_op(CACHE_OP_FIND, datatype, 2280 instr, &outstr); 2281 2282 if (outstr == NULL) 2283 return; 2284 2285 out->ldap_bufferbytesused = sizeof (ldap_return_t); 2286 (void) strncpy(out->ldap_u.config, outstr, strlen(outstr)+1); 2287 free(outstr); 2288 out->ldap_return_code = SUCCESS; 2289 out->ldap_errno = 0; 2290 } 2291 2292 void 2293 getldap_set_cacheData(ldap_return_t *out, ldap_call_t *in) 2294 { 2295 char *instr1 = NULL; 2296 char *instr2 = NULL; 2297 int datatype = CACHE_MAP_UNKNOWN; 2298 int rc = 0; 2299 2300 if (current_admin.debug_level >= DBG_ALL) { 2301 logit("getldap_set_cacheData()...\n"); 2302 } 2303 2304 /* assume error */ 2305 out->ldap_errno = -1; 2306 out->ldap_return_code = NOTFOUND; 2307 out->ldap_bufferbytesused = sizeof (*out); 2308 2309 /* make sure the request is valid */ 2310 if (strncmp(in->ldap_u.servername, 2311 NS_CACHE_DN2DOMAIN, strlen(NS_CACHE_DN2DOMAIN)) == 0) 2312 datatype = CACHE_MAP_DN2DOMAIN; 2313 2314 if (datatype == CACHE_MAP_UNKNOWN) 2315 return; 2316 2317 instr1 = strstr(in->ldap_u.servername, DOORLINESEP); 2318 if (instr1 == NULL) 2319 return; 2320 *instr1 = '\0'; 2321 instr1 += strlen(DOORLINESEP); 2322 if (*instr1 == '\0') 2323 return; 2324 instr2 = strstr(instr1, DOORLINESEP); 2325 if (instr2 == NULL) 2326 return; 2327 *instr2 = '\0'; 2328 instr2 += strlen(DOORLINESEP); 2329 if (*instr2 == '\0') 2330 return; 2331 2332 rc = getldap_cache_op(CACHE_OP_ADD, datatype, 2333 instr1, &instr2); 2334 if (rc != NS_LDAP_SUCCESS) 2335 return; 2336 2337 out->ldap_bufferbytesused = sizeof (ldap_return_t); 2338 out->ldap_return_code = SUCCESS; 2339 out->ldap_errno = 0; 2340 } 2341 2342 void 2343 getldap_get_cacheStat(ldap_return_t *out) 2344 { 2345 char *foutstr = NULL; 2346 char *soutstr = NULL; 2347 char *coutstr = NULL; 2348 2349 if (current_admin.debug_level >= DBG_ALL) { 2350 logit("getldap_get_cacheStat()...\n"); 2351 } 2352 2353 /* setup for error return */ 2354 out->ldap_errno = -1; 2355 out->ldap_return_code = NOTFOUND; 2356 out->ldap_bufferbytesused = sizeof (*out); 2357 2358 /* get refersh statisitcs */ 2359 (void) getldap_get_refresh_stat(&foutstr); 2360 if (foutstr == NULL) 2361 return; 2362 2363 /* get server statisitcs */ 2364 (void) getldap_serverInfo_op(INFO_OP_GETSTAT, NULL, &soutstr); 2365 if (soutstr == NULL) { 2366 free(foutstr); 2367 return; 2368 } 2369 /* get cache data statisitcs */ 2370 (void) getldap_cache_op(CACHE_OP_GETSTAT, NULL, NULL, &coutstr); 2371 if (coutstr == NULL) { 2372 free(foutstr); 2373 free(soutstr); 2374 return; 2375 } 2376 2377 out->ldap_bufferbytesused = sizeof (ldap_return_t); 2378 (void) strncpy(out->ldap_u.config, foutstr, strlen(foutstr) + 1); 2379 (void) strncat(out->ldap_u.config, soutstr, strlen(soutstr) + 1); 2380 (void) strncat(out->ldap_u.config, coutstr, strlen(coutstr) + 1); 2381 2382 free(foutstr); 2383 free(soutstr); 2384 free(coutstr); 2385 2386 out->ldap_return_code = SUCCESS; 2387 out->ldap_errno = 0; 2388 } 2389 2390 static int 2391 checkupdate(int sighup) 2392 { 2393 int value; 2394 2395 (void) rw_wrlock(&ldap_lock); 2396 value = sighup; 2397 (void) rw_unlock(&ldap_lock); 2398 2399 return (value == TRUE); 2400 } 2401 2402 2403 static int 2404 update_from_profile() 2405 { 2406 ns_ldap_result_t *result = NULL; 2407 char searchfilter[BUFSIZ]; 2408 ns_ldap_error_t *error; 2409 int rc; 2410 void **paramVal = NULL; 2411 ns_config_t *ptr = NULL; 2412 char *profile = NULL; 2413 char errstr[MAXERROR]; 2414 2415 if (current_admin.debug_level >= DBG_ALL) { 2416 logit("update_from_profile....\n"); 2417 } 2418 do { 2419 (void) rw_wrlock(&ldap_lock); 2420 sighup_update = FALSE; 2421 (void) rw_unlock(&ldap_lock); 2422 2423 if ((rc = __ns_ldap_getParam(NS_LDAP_PROFILE_P, 2424 ¶mVal, &error)) != NS_LDAP_SUCCESS) { 2425 if (error != NULL && error->message != NULL) 2426 logit("Error: Unable to profile name: %s\n", 2427 error->message); 2428 else { 2429 char *tmp; 2430 2431 __ns_ldap_err2str(rc, &tmp); 2432 logit("Error: Unable to profile name: %s\n", 2433 tmp); 2434 } 2435 (void) __ns_ldap_freeParam(¶mVal); 2436 (void) __ns_ldap_freeError(&error); 2437 return (-1); 2438 } 2439 2440 if (paramVal && *paramVal) 2441 profile = strdup((char *)*paramVal); 2442 (void) __ns_ldap_freeParam(¶mVal); 2443 2444 if (profile == NULL) { 2445 return (-1); 2446 } 2447 2448 (void) snprintf(searchfilter, BUFSIZ, _PROFILE_FILTER, 2449 _PROFILE1_OBJECTCLASS, _PROFILE2_OBJECTCLASS, profile); 2450 2451 if ((rc = __ns_ldap_list(_PROFILE_CONTAINER, 2452 (const char *)searchfilter, NULL, 2453 NULL, NULL, 0, 2454 &result, &error, NULL, NULL)) != NS_LDAP_SUCCESS) { 2455 2456 /* 2457 * Is profile name the DEFAULTCONFIGNAME? 2458 * syslog Warning, otherwise syslog error. 2459 */ 2460 if (strcmp(profile, DEFAULTCONFIGNAME) == 0) { 2461 syslog(LOG_WARNING, 2462 "Ignoring attempt to refresh nonexistent " 2463 "default profile: %s.\n", 2464 profile); 2465 logit("Ignoring attempt to refresh nonexistent " 2466 "default profile: %s.\n", 2467 profile); 2468 } else if ((error != NULL) && 2469 (error->message != NULL)) { 2470 syslog(LOG_ERR, 2471 "Error: Unable to refresh profile:%s:" 2472 " %s\n", profile, error->message); 2473 logit("Error: Unable to refresh profile:" 2474 "%s:%s\n", profile, error->message); 2475 } else { 2476 syslog(LOG_ERR, "Error: Unable to refresh " 2477 "from profile:%s. (error=%d)\n", 2478 profile, rc); 2479 logit("Error: Unable to refresh from profile " 2480 "%s (error=%d)\n", profile, rc); 2481 } 2482 2483 (void) __ns_ldap_freeError(&error); 2484 (void) __ns_ldap_freeResult(&result); 2485 free(profile); 2486 return (-1); 2487 } 2488 free(profile); 2489 2490 2491 } while (checkupdate(sighup_update) == TRUE); 2492 2493 (void) rw_wrlock(&ldap_lock); 2494 2495 ptr = __ns_ldap_make_config(result); 2496 (void) __ns_ldap_freeResult(&result); 2497 2498 if (ptr == NULL) { 2499 logit("Error: __ns_ldap_make_config failed.\n"); 2500 (void) rw_unlock(&ldap_lock); 2501 return (-1); 2502 } 2503 2504 /* 2505 * cross check the config parameters 2506 */ 2507 if (__s_api_crosscheck(ptr, errstr, B_TRUE) == NS_SUCCESS) { 2508 /* 2509 * reset the local profile TTL 2510 */ 2511 if (ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc) 2512 current_admin.ldap_stat.ldap_ttl = 2513 atol(ptr->paramList[NS_LDAP_CACHETTL_P].ns_pc); 2514 2515 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) { 2516 logit("update_from_profile: reset profile TTL to %d" 2517 " seconds\n", 2518 current_admin.ldap_stat.ldap_ttl); 2519 logit("update_from_profile: expire time %ld " 2520 "seconds\n", 2521 ptr->paramList[NS_LDAP_EXP_P].ns_tm); 2522 } 2523 2524 /* set ptr as current_config */ 2525 __s_api_init_config(ptr); 2526 rc = 0; 2527 } else { 2528 __s_api_destroy_config(ptr); 2529 logit("Error: downloaded profile failed to pass " 2530 "crosscheck (%s).\n", errstr); 2531 syslog(LOG_ERR, "ldap_cachemgr: %s", errstr); 2532 rc = -1; 2533 } 2534 (void) rw_unlock(&ldap_lock); 2535 2536 return (rc); 2537 } 2538 2539 int 2540 getldap_init() 2541 { 2542 ns_ldap_error_t *error; 2543 struct timeval tp; 2544 2545 if (current_admin.debug_level >= DBG_ALL) { 2546 logit("getldap_init()...\n"); 2547 } 2548 2549 (void) __ns_ldap_setServer(TRUE); 2550 2551 (void) rw_wrlock(&ldap_lock); 2552 if ((error = __ns_ldap_LoadConfiguration()) != NULL) { 2553 logit("Error: Unable to read '%s': %s\n", 2554 NSCONFIGFILE, error->message); 2555 (void) fprintf(stderr, 2556 gettext("\nError: Unable to read '%s': %s\n"), 2557 NSCONFIGFILE, error->message); 2558 __ns_ldap_freeError(&error); 2559 (void) rw_unlock(&ldap_lock); 2560 return (-1); 2561 } 2562 (void) rw_unlock(&ldap_lock); 2563 2564 if (gettimeofday(&tp, NULL) == 0) { 2565 /* statistics: previous refresh time */ 2566 prev_refresh_time = tp.tv_sec; 2567 } 2568 2569 /* initialize the data cache */ 2570 (void) getldap_cache_op(CACHE_OP_CREATE, 2571 0, NULL, NULL); 2572 2573 return (0); 2574 } 2575 2576 static void 2577 perform_update(void) 2578 { 2579 ns_ldap_error_t *error = NULL; 2580 struct timeval tp; 2581 char buf[20]; 2582 int rc, rc1; 2583 void **paramVal = NULL; 2584 ns_ldap_self_gssapi_config_t config; 2585 2586 if (current_admin.debug_level >= DBG_ALL) { 2587 logit("perform_update()...\n"); 2588 } 2589 2590 (void) __ns_ldap_setServer(TRUE); 2591 2592 if (gettimeofday(&tp, NULL) != 0) 2593 return; 2594 2595 rc = __ns_ldap_getParam(NS_LDAP_CACHETTL_P, ¶mVal, &error); 2596 2597 if (rc == NS_LDAP_SUCCESS && paramVal != NULL) { 2598 current_admin.ldap_stat.ldap_ttl = atol((char *)*paramVal); 2599 } 2600 2601 if (error != NULL) 2602 (void) __ns_ldap_freeError(&error); 2603 2604 if (paramVal != NULL) 2605 (void) __ns_ldap_freeParam(¶mVal); 2606 2607 if (current_admin.debug_level >= DBG_PROFILE_REFRESH) { 2608 logit("perform_update: current profile TTL is %d seconds\n", 2609 current_admin.ldap_stat.ldap_ttl); 2610 } 2611 2612 if (current_admin.ldap_stat.ldap_ttl > 0) { 2613 /* 2614 * set the profile TTL parameter, just 2615 * in case that the downloading of 2616 * the profile from server would fail 2617 */ 2618 2619 /* 2620 * NS_LDAP_EXP_P is a no op for __ns_ldap_setParam 2621 * It depends on NS_LDAP_CACHETTL_P to set it's value 2622 * Set NS_LDAP_CACHETTL_P here so NS_LDAP_EXP_P value 2623 * can be set. 2624 * NS_LDAP_CACHETTL_P value can be reset after the profile is 2625 * downloaded from the server, so is NS_LDAP_EXP_P. 2626 */ 2627 buf[19] = '\0'; /* null terminated the buffer */ 2628 if (__ns_ldap_setParam(NS_LDAP_CACHETTL_P, 2629 lltostr((long long)current_admin.ldap_stat.ldap_ttl, 2630 &buf[19]), 2631 &error) != NS_LDAP_SUCCESS) { 2632 logit("Error: __ns_ldap_setParam failed, status: %d " 2633 "message: %s\n", error->status, error->message); 2634 (void) __ns_ldap_freeError(&error); 2635 return; 2636 } 2637 2638 (void) rw_wrlock(&ldap_lock); 2639 sighup_update = FALSE; 2640 (void) rw_unlock(&ldap_lock); 2641 2642 do { 2643 rc = update_from_profile(); 2644 if (rc != 0) { 2645 logit("Error: Unable to update from profile\n"); 2646 } 2647 } while (checkupdate(sighup_update) == TRUE); 2648 } else { 2649 rc = 0; 2650 } 2651 2652 /* 2653 * recreate the server info list 2654 */ 2655 if (rc == 0) { 2656 (void) getldap_serverInfo_op(INFO_OP_CREATE, NULL, NULL); 2657 2658 /* flush the data cache */ 2659 (void) getldap_cache_op(CACHE_OP_DELETE, 2660 0, NULL, NULL); 2661 2662 /* statistics: previous refresh time */ 2663 prev_refresh_time = tp.tv_sec; 2664 } 2665 rc1 = __ns_ldap_self_gssapi_config(&config); 2666 if (rc1 == NS_LDAP_SUCCESS) { 2667 if (config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) { 2668 rc1 = __ns_ldap_check_all_preq(0, 0, 0, config, &error); 2669 (void) __ns_ldap_freeError(&error); 2670 if (rc1 != NS_LDAP_SUCCESS) { 2671 logit("Error: Check on self credential " 2672 "prerquesites failed: %d\n", 2673 rc1); 2674 exit(rc1); 2675 } 2676 } 2677 } else { 2678 logit("Error: Failed to get self credential configuration %d\n", 2679 rc1); 2680 exit(rc1); 2681 } 2682 2683 (void) rw_rdlock(&ldap_lock); 2684 if ((error = __ns_ldap_DumpConfiguration(NSCONFIGREFRESH)) != NULL) { 2685 logit("Error: __ns_ldap_DumpConfiguration(\"%s\") failed, " 2686 "status: %d " 2687 "message: %s\n", NSCONFIGREFRESH, 2688 error->status, error->message); 2689 __ns_ldap_freeError(&error); 2690 } 2691 if ((error = __ns_ldap_DumpConfiguration(NSCREDREFRESH)) != NULL) { 2692 logit("Error: __ns_ldap_DumpConfiguration(\"%s\") failed, " 2693 "status: %d " 2694 "message: %s\n", NSCREDREFRESH, 2695 error->status, error->message); 2696 __ns_ldap_freeError(&error); 2697 } 2698 if (rename(NSCONFIGREFRESH, NSCONFIGFILE) != 0) 2699 logit("Error: unlink failed - errno: %d\n", errno); 2700 if (rename(NSCREDREFRESH, NSCREDFILE) != 0) 2701 logit("Error: unlink failed - errno: %d\n", errno); 2702 2703 (void) rw_unlock(&ldap_lock); 2704 2705 } 2706 2707 void 2708 getldap_refresh() 2709 { 2710 struct timespec timeout; 2711 int sleeptime; 2712 struct timeval tp; 2713 long expire = 0; 2714 void **paramVal = NULL; 2715 ns_ldap_error_t *errorp; 2716 int always = 1, err; 2717 int first_time = 1; 2718 int sig_done = 0; 2719 int dbg_level; 2720 2721 if (current_admin.debug_level >= DBG_ALL) { 2722 logit("getldap_refresh()...\n"); 2723 } 2724 2725 /* 2726 * wait for an available server 2727 */ 2728 while (sig_done == 0) { 2729 (void) mutex_lock(&sig_mutex); 2730 sig_done = signal_done; 2731 (void) mutex_unlock(&sig_mutex); 2732 } 2733 2734 (void) __ns_ldap_setServer(TRUE); 2735 while (always) { 2736 dbg_level = current_admin.debug_level; 2737 (void) rw_rdlock(&ldap_lock); 2738 sleeptime = current_admin.ldap_stat.ldap_ttl; 2739 if (dbg_level >= DBG_PROFILE_REFRESH) { 2740 logit("getldap_refresh: current profile TTL is %d " 2741 "seconds\n", current_admin.ldap_stat.ldap_ttl); 2742 } 2743 if (gettimeofday(&tp, NULL) == 0) { 2744 if ((__ns_ldap_getParam(NS_LDAP_EXP_P, 2745 ¶mVal, &errorp) == NS_LDAP_SUCCESS) && 2746 paramVal != NULL && 2747 (char *)*paramVal != NULL) { 2748 errno = 0; 2749 expire = atol((char *)*paramVal); 2750 (void) __ns_ldap_freeParam(¶mVal); 2751 if (errno == 0) { 2752 if (expire == 0) { 2753 first_time = 0; 2754 (void) rw_unlock(&ldap_lock); 2755 (void) cond_init(&cond, 2756 NULL, NULL); 2757 (void) mutex_lock(&sighuplock); 2758 timeout.tv_sec = 2759 CACHESLEEPTIME; 2760 timeout.tv_nsec = 0; 2761 if (dbg_level >= 2762 DBG_PROFILE_REFRESH) { 2763 logit("getldap_refresh: " 2764 "(1)about to sleep for %d " 2765 "seconds\n", 2766 CACHESLEEPTIME); 2767 } 2768 err = cond_reltimedwait(&cond, 2769 &sighuplock, &timeout); 2770 (void) cond_destroy(&cond); 2771 (void) mutex_unlock( 2772 &sighuplock); 2773 /* 2774 * if woke up by 2775 * getldap_revalidate(), 2776 * do update right away 2777 */ 2778 if (err == ETIME) 2779 continue; 2780 else { 2781 /* 2782 * if load 2783 * configuration failed 2784 * don't do update 2785 */ 2786 if (load_config()) 2787 perform_update(); 2788 continue; 2789 } 2790 } 2791 sleeptime = expire - tp.tv_sec; 2792 if (dbg_level >= DBG_PROFILE_REFRESH) { 2793 logit("getldap_refresh: expire time" 2794 " = %ld\n", expire); 2795 } 2796 2797 } 2798 } 2799 } 2800 2801 (void) rw_unlock(&ldap_lock); 2802 2803 /* 2804 * if this is the first time downloading 2805 * the profile or expire time already passed, 2806 * do not wait, do update 2807 */ 2808 if (first_time == 0 && sleeptime > 0) { 2809 if (dbg_level >= DBG_PROFILE_REFRESH) { 2810 logit("getldap_refresh: (2)about to sleep " 2811 "for %d seconds\n", sleeptime); 2812 } 2813 (void) cond_init(&cond, NULL, NULL); 2814 (void) mutex_lock(&sighuplock); 2815 timeout.tv_sec = sleeptime; 2816 timeout.tv_nsec = 0; 2817 err = cond_reltimedwait(&cond, 2818 &sighuplock, &timeout); 2819 (void) cond_destroy(&cond); 2820 (void) mutex_unlock(&sighuplock); 2821 } 2822 /* 2823 * if load concfiguration failed 2824 * don't do update 2825 */ 2826 if (load_config()) 2827 perform_update(); 2828 first_time = 0; 2829 } 2830 } 2831 2832 void 2833 getldap_revalidate() 2834 { 2835 if (current_admin.debug_level >= DBG_ALL) { 2836 logit("getldap_revalidate()...\n"); 2837 } 2838 /* block signal SIGHUP */ 2839 (void) sighold(SIGHUP); 2840 2841 /* now awake the sleeping refresh thread */ 2842 (void) cond_signal(&cond); 2843 2844 /* release signal SIGHUP */ 2845 (void) sigrelse(SIGHUP); 2846 2847 } 2848 2849 void 2850 getldap_lookup(ldap_return_t *out, ldap_call_t *in) 2851 { 2852 LineBuf configinfo; 2853 ns_ldap_error_t *error; 2854 2855 if (current_admin.debug_level >= DBG_ALL) { 2856 logit("getldap_lookup()...\n"); 2857 } 2858 2859 (void) rw_rdlock(&ldap_lock); 2860 if ((error = __ns_ldap_LoadDoorInfo(&configinfo, in->ldap_u.domainname)) 2861 != NULL) { 2862 if (error != NULL && error->message != NULL) 2863 logit("Error: ldap_lookup: %s\n", error->message); 2864 (void) __ns_ldap_freeError(&error); 2865 out->ldap_errno = -1; 2866 out->ldap_return_code = NOTFOUND; 2867 out->ldap_bufferbytesused = sizeof (*out); 2868 2869 } else { 2870 out->ldap_bufferbytesused = sizeof (ldap_return_t); 2871 (void) strncpy(out->ldap_u.config, 2872 configinfo.str, configinfo.len); 2873 out->ldap_return_code = SUCCESS; 2874 out->ldap_errno = 0; 2875 } 2876 2877 if (configinfo.str != NULL) { 2878 free(configinfo.str); 2879 configinfo.str = NULL; 2880 configinfo.alloc = 0; 2881 configinfo.len = 0; 2882 } 2883 2884 (void) rw_unlock(&ldap_lock); 2885 } 2886