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