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