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