Print this page
    
3285 memory leaks in libsldap
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libsldap/common/ns_standalone.c
          +++ new/usr/src/lib/libsldap/common/ns_standalone.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | ↓ open down ↓ | 14 lines elided | ↑ open up ↑ | 
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   * Copyright 2012 Milan Jurik. All rights reserved.
       25 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  25   26   */
  26   27  
  27   28  #define __STANDALONE_MODULE__
  28   29  
  29   30  #include <stdio.h>
  30   31  #include <sys/types.h>
  31   32  #include <stdlib.h>
  32   33  #include <libintl.h>
  33   34  #include <string.h>
  34   35  #include <ctype.h>
  35   36  
  36   37  #include <sys/stat.h>
  37   38  #include <fcntl.h>
  38   39  #include <unistd.h>
  39   40  #include <syslog.h>
  40   41  #include <locale.h>
  41   42  #include <errno.h>
  42   43  #include <sys/time.h>
  43   44  
  44   45  #include <arpa/inet.h>
  45   46  #include <netdb.h>
  46   47  #include <strings.h>
  47   48  
  48   49  #include <thread.h>
  49   50  
  50   51  #include <nsswitch.h>
  51   52  #include <nss_dbdefs.h>
  52   53  #include <nss.h>
  53   54  
  54   55  #include "ns_cache_door.h"
  55   56  #include "ns_internal.h"
  56   57  #include "ns_connmgmt.h"
  57   58  
  58   59  typedef enum {
  59   60          INFO_SERVER_JUST_INITED = -1,
  60   61          INFO_SERVER_UNKNOWN     = 0,
  61   62          INFO_SERVER_CONNECTING  = 1,
  62   63          INFO_SERVER_UP          = 2,
  63   64          INFO_SERVER_ERROR       = 3,
  64   65          INFO_SERVER_REMOVED     = 4
  65   66  } dir_server_status_t;
  66   67  
  67   68  typedef enum {
  68   69          INFO_STATUS_NEW         = 2,
  69   70          INFO_STATUS_OLD         = 3
  70   71  } dir_server_info_t;
  71   72  
  72   73  typedef struct dir_server {
  73   74          char                    *ip;
  74   75          char                    **controls;
  75   76          char                    **saslMech;
  76   77          dir_server_status_t     status;
  77   78          mutex_t                 updateStatus;
  78   79          dir_server_info_t       info;
  79   80  } dir_server_t;
  80   81  
  81   82  typedef struct dir_server_list {
  82   83          dir_server_t    **nsServers;
  83   84  
  84   85          rwlock_t        listDestroyLock;
  85   86  } dir_server_list_t;
  86   87  
  87   88  struct {
  88   89          /* The local list of the directory servers' root DSEs. */
  89   90          dir_server_list_t       *list;
  90   91          /* The flag indicating if libsldap is in the 'Standalone' mode. */
  91   92          int                     standalone;
  92   93          /*
  93   94           * The mutex ensuring that only one thread performs
  94   95           * the initialization of the list.
  95   96           */
  96   97          mutex_t                 listReplaceLock;
  97   98          /*
  98   99           * A flag indicating that a particular thread is
  99  100           * in the 'ldap_cachemgr' mode. It is stored by thread as
 100  101           * a thread specific data.
 101  102           */
 102  103          const int               initFlag;
 103  104          /*
 104  105           * A thread specific key storing
 105  106           * the the 'ldap_cachemgr' mode indicator.
 106  107           */
 107  108          thread_key_t            standaloneInitKey;
 108  109  } dir_servers = {NULL, 0, DEFAULTMUTEX, '1'};
 109  110  
 110  111  typedef struct switchDatabase {
 111  112          char *conf;
 112  113          uint32_t alloced;
 113  114  } switch_database_t;
 114  115  
 115  116  static thread_key_t switchConfigKey;
 116  117  
 117  118  #pragma init(createStandaloneKey)
 118  119  
 119  120  #define DONT_INCLUDE_ATTR_NAMES 0
 120  121  #define INCLUDE_ATTR_NAMES      1
 121  122  #define IS_PROFILE              1
 122  123  #define NOT_PROFILE             0
 123  124  /* INET6_ADDRSTRLEN + ":" + <5-digit port> + some round-up */
 124  125  #define MAX_HOSTADDR_LEN (INET6_ADDRSTRLEN + 6 + 12)
 125  126  
 126  127  static
 127  128  void
 128  129  switch_conf_disposer(void *data)
 129  130  {
 130  131          switch_database_t *localData = (switch_database_t *)data;
 131  132  
 132  133          free(localData->conf);
 133  134          free(localData);
 134  135  }
 135  136  
 136  137  /*
 137  138   * This function initializes an indication that a thread obtaining a root DSE
 138  139   * will be switched to the 'ldap_cachemgr' mode. Within the thread libsldap
 139  140   * will not invoke the __s_api_requestServer function. Instead, the library
 140  141   * will establish a connection to the server specified by
 141  142   * the __ns_ldap_getRootDSE function.
 142  143   * Since  ldap_cachmgr can obtain a DUAProfile and root DSEs at the same time
 143  144   * and we do not want to affect a thread obtaining a DUAProfile,
 144  145   * the 'ldap_cachemgr' mode is thread private.
 145  146   * In addition, this function creates a key holding temporary configuration
 146  147   * for the "hosts" and "ipnodes" databases which is used by the "SKIPDB"
 147  148   * mechanism (__s_api_ip2hostname() & _s_api_hostname2ip()).
 148  149   */
 149  150  static
 150  151  void
 151  152  createStandaloneKey()
 152  153  {
 153  154          if (thr_keycreate(&dir_servers.standaloneInitKey, NULL) != 0) {
 154  155                  syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
 155  156                  "key needed for sharing ldap connections"));
 156  157          }
 157  158          if (thr_keycreate(&switchConfigKey, switch_conf_disposer) != 0) {
 158  159                  syslog(LOG_ERR, gettext("libsldap: unable to create a thread "
 159  160                      "key containing current nsswitch configuration"));
 160  161          }
 161  162  }
 162  163  
 163  164  /*
 164  165   * This function sets the 'ldap_cachemgr' mode indication.
 165  166   */
 166  167  void
 167  168  __s_api_setInitMode()
 168  169  {
 169  170          (void) thr_setspecific(dir_servers.standaloneInitKey,
 170  171              (void *) &dir_servers.initFlag);
 171  172  }
 172  173  
 173  174  /*
 174  175   * This function unset the 'ldap_cachemgr' mode indication.
 175  176   */
 176  177  void
 177  178  __s_api_unsetInitMode()
 178  179  {
 179  180          (void) thr_setspecific(dir_servers.standaloneInitKey, NULL);
 180  181  }
 181  182  
 182  183  /*
 183  184   * This function checks if the 'ldap_cachemgr' mode indication is set.
 184  185   */
 185  186  int
 186  187  __s_api_isInitializing() {
 187  188          int *flag = NULL;
 188  189  
 189  190          (void) thr_getspecific(dir_servers.standaloneInitKey, (void **) &flag);
 190  191  
 191  192          return (flag != NULL && *flag == dir_servers.initFlag);
 192  193  }
 193  194  
 194  195  /*
 195  196   * This function checks if the process runs in the 'Standalone' mode.
 196  197   * In this mode libsldap will check the local, process private list of root DSEs
 197  198   * instead of requesting them via a door call to ldap_cachemgr.
 198  199   */
 199  200  int
 200  201  __s_api_isStandalone()
 201  202  {
 202  203          int     mode;
 203  204  
 204  205          (void) mutex_lock(&dir_servers.listReplaceLock);
 205  206          mode = dir_servers.standalone;
 206  207          (void) mutex_unlock(&dir_servers.listReplaceLock);
 207  208  
 208  209          return (mode);
 209  210  }
 210  211  
 211  212  
 212  213  static
 213  214  int
 214  215  remove_ldap(char *dst, char *src, int dst_buf_len)
 215  216  {
 216  217          int i = 0;
 217  218  
 218  219          if (strlen(src) >= dst_buf_len)
 219  220                  return (0);
 220  221  
 221  222          while (*src != '\0') {
 222  223                  /* Copy up to one space from source. */
 223  224                  if (isspace(*src)) {
 224  225                          dst[i++] = *src;
 225  226                          while (isspace(*src))
 226  227                                  src++;
 227  228                  }
 228  229  
 229  230                  /* If not "ldap", just copy. */
 230  231                  if (strncmp(src, "ldap", 4) != 0) {
 231  232                          while (!isspace(*src)) {
 232  233                                  dst[i++] = *src++;
 233  234                                  /* At the end of string? */
 234  235                                  if (dst[i-1] == '\0')
 235  236                                          return (1);
 236  237                          }
 237  238                          /* Copy up to one space from source. */
 238  239                          if (isspace(*src)) {
 239  240                                  dst[i++] = *src;
 240  241                                  while (isspace(*src))
 241  242                                          src++;
 242  243                          }
 243  244                          /* Copy also the criteria section */
 244  245                          if (*src == '[')
 245  246                                  while (*src != ']') {
 246  247                                          dst[i++] = *src++;
 247  248                                          /* Shouln't happen if format is right */
 248  249                                          if (dst[i-1] == '\0')
 249  250                                                  return (1);
 250  251                                  }
 251  252                  }
 252  253  
 253  254                  /* If next part is ldap, skip over it ... */
 254  255                  if (strncmp(src, "ldap", 4) == 0) {
 255  256                          if (isspace(*(src+4)) || *(src+4) == '\0') {
 256  257                                  src += 4;
 257  258                                  while (isspace(*src))
 258  259                                          src++;
 259  260                                  if (*src == '[') {
 260  261                                          while (*src++ != ']') {
 261  262                                                  /*
 262  263                                                   * See comment above about
 263  264                                                   * correct format.
 264  265                                                   */
 265  266                                                  if (*src == '\0') {
 266  267                                                          dst[i++] = '\0';
 267  268                                                          return (1);
 268  269                                                  }
 269  270                                          }
 270  271                                  }
 271  272                                  while (isspace(*src))
 272  273                                          src++;
 273  274                          }
 274  275                  }
 275  276                  if (*src == '\0')
 276  277                          dst[i++] = '\0';
 277  278          }
 278  279  
 279  280          return (1);
 280  281  }
 281  282  
 282  283  static
 283  284  char *
 284  285  get_db(const char *db_name)
 285  286  {
 286  287          char                    *ptr;
 287  288          switch_database_t       *hostService = NULL;
 288  289          FILE                    *fp = fopen(__NSW_CONFIG_FILE, "rF");
 289  290          char                    *linep, line[NSS_BUFSIZ];
 290  291  
 291  292          if (fp == NULL) {
 292  293                  syslog(LOG_WARNING, gettext("libsldap: can not read %s"),
 293  294                      __NSW_CONFIG_FILE);
 294  295                  return (NULL);
 295  296          }
 296  297  
 297  298          while ((linep = fgets(line, NSS_BUFSIZ, fp)) != NULL) {
 298  299                  while (isspace(*linep)) {
 299  300                          ++linep;
 300  301                  }
 301  302                  if (*linep == '#') {
 302  303                          continue;
 303  304                  }
 304  305                  if (strncmp(linep, db_name, strlen(db_name)) != 0) {
 305  306                          continue;
 306  307                  }
 307  308                  if ((linep = strchr(linep, ':')) != NULL) {
 308  309                          if (linep[strlen(linep) - 1] == '\n') {
 309  310                                  linep[strlen(linep) - 1] = '\0';
 310  311                          }
 311  312  
 312  313                          while (isspace(*++linep))
 313  314                                  ;
 314  315  
 315  316                          if ((ptr = strchr(linep, '#')) != NULL) {
 316  317                                  while (--ptr >= linep && isspace(*ptr))
 317  318                                          ;
 318  319                                  *(ptr + 1) = '\0';
 319  320                          }
 320  321  
 321  322                          if (strlen(linep) == 0) {
 322  323                                  continue;
 323  324                          }
 324  325                          break;
 325  326                  }
 326  327          }
 327  328  
 328  329          (void) fclose(fp);
 329  330  
 330  331          if (linep == NULL) {
 331  332                  syslog(LOG_WARNING,
 332  333                      gettext("libsldap: the %s database "
 333  334                      "is missing from %s"),
 334  335                      db_name,
 335  336                      __NSW_CONFIG_FILE);
 336  337                  return (NULL);
 337  338          }
 338  339  
 339  340          (void) thr_getspecific(switchConfigKey, (void **) &hostService);
 340  341          if (hostService == NULL) {
 341  342                  hostService = calloc(1, sizeof (switch_database_t));
 342  343                  if (hostService == NULL) {
 343  344                          return (NULL);
 344  345                  }
 345  346                  (void) thr_setspecific(switchConfigKey, hostService);
 346  347          }
 347  348  
 348  349          /*
 349  350           * In a long-living process threads can perform several
 350  351           * getXbyY requests. And the windows between those requests
 351  352           * can be long. The nsswitch configuration can change from time
 352  353           * to time. So instead of allocating/freeing memory every time
 353  354           * the API is called, reallocate memory only when the current
 354  355           * configuration for the database being used is longer than
 355  356           * the previous one.
 356  357           */
 357  358          if (strlen(linep) >= hostService->alloced) {
 358  359                  ptr = (char *)realloc((void *)hostService->conf,
 359  360                      strlen(linep) + 1);
 360  361                  if (ptr == NULL) {
 361  362                          free((void *)hostService->conf);
 362  363                          hostService->conf = NULL;
 363  364                          hostService->alloced = 0;
 364  365                          return (NULL);
 365  366                  }
 366  367                  bzero(ptr, strlen(linep) + 1);
 367  368                  hostService->conf = ptr;
 368  369                  hostService->alloced = strlen(linep) + 1;
 369  370          }
 370  371  
 371  372          if (remove_ldap(hostService->conf, linep, hostService->alloced))
 372  373                  return (hostService->conf);
 373  374          else
 374  375                  return (NULL);
 375  376  }
 376  377  
 377  378  static
 378  379  void
 379  380  _initf_ipnodes(nss_db_params_t *p)
 380  381  {
 381  382          char *services = get_db("ipnodes");
 382  383  
 383  384          p->name = NSS_DBNAM_IPNODES;
 384  385          p->flags |= NSS_USE_DEFAULT_CONFIG;
 385  386          p->default_config = services == NULL ? "" : services;
 386  387  }
 387  388  
 388  389  static
 389  390  void
 390  391  _initf_hosts(nss_db_params_t *p)
 391  392  {
 392  393          char *services = get_db("hosts");
 393  394  
 394  395          p->name = NSS_DBNAM_HOSTS;
 395  396          p->flags |= NSS_USE_DEFAULT_CONFIG;
 396  397          p->default_config = services == NULL ? "" : services;
 397  398  }
 398  399  
 399  400  /*
 400  401   * This function is an analog of the standard gethostbyaddr_r()
 401  402   * function with an exception that it removes the 'ldap' back-end
 402  403   * (if any) from the host/ipnodes nsswitch's databases and then
 403  404   * looks up using remaining back-ends.
 404  405   */
 405  406  static
 406  407  struct hostent *
 407  408  _filter_gethostbyaddr_r(const char *addr, int len, int type,
 408  409          struct hostent *result, char *buffer, int buflen,
 409  410          int *h_errnop)
 410  411  {
 411  412          DEFINE_NSS_DB_ROOT(db_root_hosts);
 412  413          DEFINE_NSS_DB_ROOT(db_root_ipnodes);
 413  414          nss_XbyY_args_t arg;
 414  415          nss_status_t    res;
 415  416          int             (*str2ent)();
 416  417          void            (*nss_initf)();
 417  418          nss_db_root_t   *nss_db_root;
 418  419          int             dbop;
 419  420  
 420  421          switch (type) {
 421  422          case AF_INET:
 422  423                  str2ent         = str2hostent;
 423  424                  nss_initf       = _initf_hosts;
 424  425                  nss_db_root     = &db_root_hosts;
 425  426                  dbop            = NSS_DBOP_HOSTS_BYADDR;
 426  427                  break;
 427  428          case AF_INET6:
 428  429                  str2ent         = str2hostent6;
 429  430                  nss_initf       = _initf_ipnodes;
 430  431                  nss_db_root     = &db_root_ipnodes;
 431  432                  dbop            = NSS_DBOP_IPNODES_BYADDR;
 432  433          default:
 433  434                  return (NULL);
 434  435          }
 435  436  
 436  437          NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent);
 437  438  
 438  439          arg.key.hostaddr.addr   = addr;
 439  440          arg.key.hostaddr.len    = len;
 440  441          arg.key.hostaddr.type   = type;
 441  442          arg.stayopen            = 0;
 442  443          arg.h_errno             = NETDB_SUCCESS;
 443  444  
 444  445          res = nss_search(nss_db_root, nss_initf, dbop, &arg);
 445  446          arg.status = res;
 446  447          *h_errnop = arg.h_errno;
 447  448          return (struct hostent *)NSS_XbyY_FINI(&arg);
 448  449  }
 449  450  
 450  451  /*
 451  452   * This routine is an analog of gethostbyaddr_r().
 452  453   * But in addition __s_api_hostname2ip() performs the "LDAP SKIPDB" activity
 453  454   * prior to querying the name services.
 454  455   * If the buffer is not big enough to accommodate a returning data,
 455  456   * NULL is returned and h_errnop is set to TRY_AGAIN.
 456  457   */
 457  458  struct hostent *
 458  459  __s_api_hostname2ip(const char *name,
 459  460          struct hostent *result, char *buffer, int buflen,
 460  461          int *h_errnop)
 461  462  {
 462  463          DEFINE_NSS_DB_ROOT(db_root_ipnodes);
 463  464          DEFINE_NSS_DB_ROOT(db_root_hosts);
 464  465          nss_XbyY_args_t arg;
 465  466          nss_status_t    res;
 466  467          struct in_addr  addr;
 467  468          struct in6_addr addr6;
 468  469  
 469  470          if (inet_pton(AF_INET, name, &addr) > 0) {
 470  471                  if (buflen < strlen(name) + 1 +
 471  472                      sizeof (char *) * 2 + /* The h_aliases member */
 472  473                      sizeof (struct in_addr) +
 473  474                      sizeof (struct in_addr *) * 2) {
 474  475                          *h_errnop = TRY_AGAIN;
 475  476                          return (NULL);
 476  477                  }
 477  478  
 478  479                  result->h_addrtype = AF_INET;
 479  480                  result->h_length = sizeof (struct in_addr);
 480  481                  (void) strncpy(buffer, name, buflen);
 481  482  
 482  483                  result->h_addr_list = (char **)ROUND_UP(
 483  484                      buffer + strlen(name) + 1,
 484  485                      sizeof (char *));
 485  486                  result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
 486  487                      sizeof (char *));
 487  488                  result->h_aliases[0] = buffer;
 488  489                  result->h_aliases[1] = NULL;
 489  490                  bcopy(&addr,
 490  491                      buffer + buflen - sizeof (struct in_addr),
 491  492                      sizeof (struct in_addr));
 492  493                  result->h_addr_list[0] = buffer + buflen -
 493  494                      sizeof (struct in_addr);
 494  495                  result->h_addr_list[1] = NULL;
 495  496                  result->h_aliases = result->h_addr_list;
 496  497                  result->h_name = buffer;
 497  498  
 498  499                  *h_errnop = NETDB_SUCCESS;
 499  500                  return (result);
 500  501          }
 501  502          if (inet_pton(AF_INET6, name, &addr6) > 0) {
 502  503                  if (buflen < strlen(name) + 1 +
 503  504                      sizeof (char *) * 2 + /* The h_aliases member */
 504  505                      sizeof (struct in6_addr) +
 505  506                      sizeof (struct in6_addr *) * 2) {
 506  507                          *h_errnop = TRY_AGAIN;
 507  508                          return (NULL);
 508  509                  }
 509  510  
 510  511                  result->h_addrtype = AF_INET6;
 511  512                  result->h_length = sizeof (struct in6_addr);
 512  513                  (void) strncpy(buffer, name, buflen);
 513  514  
 514  515                  result->h_addr_list = (char **)ROUND_UP(
 515  516                      buffer + strlen(name) + 1,
 516  517                      sizeof (char *));
 517  518                  result->h_aliases = (char **)ROUND_UP(result->h_addr_list,
 518  519                      sizeof (char *));
 519  520                  result->h_aliases[0] = buffer;
 520  521                  result->h_aliases[1] = NULL;
 521  522                  bcopy(&addr6,
 522  523                      buffer + buflen - sizeof (struct in6_addr),
 523  524                      sizeof (struct in6_addr));
 524  525                  result->h_addr_list[0] = buffer + buflen -
 525  526                      sizeof (struct in6_addr);
 526  527                  result->h_addr_list[1] = NULL;
 527  528                  result->h_aliases = result->h_addr_list;
 528  529                  result->h_name = buffer;
 529  530  
 530  531                  *h_errnop = NETDB_SUCCESS;
 531  532                  return (result);
 532  533          }
 533  534  
 534  535          NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent);
 535  536  
 536  537          arg.key.name = name;
 537  538          arg.stayopen = 0;
 538  539          arg.h_errno = NETDB_SUCCESS;
 539  540  
 540  541          res = nss_search(&db_root_ipnodes, _initf_ipnodes,
 541  542              NSS_DBOP_IPNODES_BYNAME, &arg);
 542  543          if (res == NSS_NOTFOUND || res == NSS_UNAVAIL) {
 543  544                  arg.h_errno = NETDB_SUCCESS;
 544  545                  res = nss_search(&db_root_hosts, _initf_hosts,
 545  546                      NSS_DBOP_HOSTS_BYNAME, &arg);
 546  547          }
 547  548          arg.status = res;
 548  549          *h_errnop = arg.h_errno;
 549  550          return ((struct hostent *)NSS_XbyY_FINI(&arg));
 550  551  }
 551  552  
 552  553  /*
 553  554   * Convert an IP to a host name.
 554  555   */
 555  556  ns_ldap_return_code
 556  557  __s_api_ip2hostname(char *ipaddr, char **hostname) {
 557  558          struct in_addr  in;
 558  559          struct in6_addr in6;
 559  560          struct hostent  *hp = NULL, hostEnt;
 560  561          char            buffer[NSS_BUFLEN_HOSTS];
 561  562          int             buflen = NSS_BUFLEN_HOSTS;
 562  563          char            *start = NULL,
 563  564                          *end = NULL,
 564  565                          delim = '\0';
 565  566          char            *port = NULL,
 566  567                          *addr = NULL;
 567  568          int             errorNum = 0,
 568  569                          len = 0;
 569  570  
 570  571          if (ipaddr == NULL || hostname == NULL)
 571  572                  return (NS_LDAP_INVALID_PARAM);
 572  573          *hostname = NULL;
 573  574          if ((addr = strdup(ipaddr)) == NULL)
 574  575                  return (NS_LDAP_MEMORY);
 575  576  
 576  577          if (addr[0] == '[') {
 577  578                  /*
 578  579                   * Assume it's [ipv6]:port
 579  580                   * Extract ipv6 IP
 580  581                   */
 581  582                  start = &addr[1];
 582  583                  if ((end = strchr(addr, ']')) != NULL) {
 583  584                          *end = '\0';
 584  585                          delim = ']';
 585  586                          if (*(end + 1) == ':')
 586  587                                  /* extract port */
 587  588                                  port = end + 2;
 588  589                  } else {
 589  590                          free(addr);
 590  591                          return (NS_LDAP_INVALID_PARAM);
 591  592                  }
 592  593          } else if ((end = strchr(addr, ':')) != NULL) {
 593  594                  /* assume it's ipv4:port */
 594  595                  *end = '\0';
 595  596                  delim = ':';
 596  597                  start = addr;
 597  598                  port = end + 1;
 598  599          } else
 599  600                  /* No port */
 600  601                  start = addr;
 601  602  
 602  603  
 603  604          if (inet_pton(AF_INET, start, &in) == 1) {
 604  605                  /* IPv4 */
 605  606                  hp = _filter_gethostbyaddr_r((char *)&in,
 606  607                      sizeof (in.s_addr),
 607  608                      AF_INET,
 608  609                      &hostEnt,
 609  610                      buffer,
 610  611                      buflen,
 611  612                      &errorNum);
 612  613                  if (hp && hp->h_name) {
 613  614                          /* hostname + '\0' */
 614  615                          len = strlen(hp->h_name) + 1;
 615  616                          if (port)
 616  617                                  /* ':' + port */
 617  618                                  len += strlen(port) + 1;
 618  619                          if ((*hostname = malloc(len)) == NULL) {
 619  620                                  free(addr);
 620  621                                  return (NS_LDAP_MEMORY);
 621  622                          }
 622  623  
 623  624                          if (port)
 624  625                                  (void) snprintf(*hostname, len, "%s:%s",
 625  626                                                  hp->h_name, port);
 626  627                          else
 627  628                                  (void) strlcpy(*hostname, hp->h_name, len);
 628  629  
 629  630                          free(addr);
 630  631                          return (NS_LDAP_SUCCESS);
 631  632                  } else {
 632  633                          free(addr);
 633  634                          return (NS_LDAP_NOTFOUND);
 634  635                  }
 635  636          } else if (inet_pton(AF_INET6, start, &in6) == 1) {
 636  637                  /* IPv6 */
 637  638                  hp = _filter_gethostbyaddr_r((char *)&in6,
 638  639                      sizeof (in6.s6_addr),
 639  640                      AF_INET6,
 640  641                      &hostEnt,
 641  642                      buffer,
 642  643                      buflen,
 643  644                      &errorNum);
 644  645                  if (hp && hp->h_name) {
 645  646                          /* hostname + '\0' */
 646  647                          len = strlen(hp->h_name) + 1;
 647  648                          if (port)
 648  649                                  /* ':' + port */
 649  650                                  len += strlen(port) + 1;
 650  651                          if ((*hostname = malloc(len)) == NULL) {
 651  652                                  free(addr);
 652  653                                  return (NS_LDAP_MEMORY);
 653  654                          }
 654  655  
 655  656                          if (port)
 656  657                                  (void) snprintf(*hostname, len, "%s:%s",
 657  658                                                  hp->h_name, port);
 658  659                          else
 659  660                                  (void) strlcpy(*hostname, hp->h_name, len);
 660  661  
 661  662                          free(addr);
 662  663                          return (NS_LDAP_SUCCESS);
 663  664                  } else {
 664  665                          free(addr);
 665  666                          return (NS_LDAP_NOTFOUND);
 666  667                  }
 667  668          } else {
 668  669                  /*
 669  670                   * A hostname
 670  671                   * Return it as is
 671  672                   */
 672  673                  if (end)
 673  674                          *end = delim;
 674  675                  *hostname = addr;
 675  676                  return (NS_LDAP_SUCCESS);
 676  677          }
 677  678  }
 678  679  
 679  680  /*
 680  681   * This function obtains data returned by an LDAP search request and puts it
 681  682   * in a string in the ldap_cachmgr(1) door call format.
 682  683   *
 683  684   * INPUT:
 684  685   *     ld - a pointer to an LDAP structure used for a search operation,
 685  686   *     result_msg - a pointer to an LDAPMessage returned by the search,
 686  687   *     include_names - if set to INCLUDE_ATTR_NAMES, the output buffer will
 687  688   *                     contain attribute names.
 688  689   *                     Otherwise, only values will be return.
 689  690   *
 690  691   * OUTPUT:
 691  692   *      a buffer containing server info in the following format:
 692  693   *         [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
 693  694   *      Should be free'ed by the caller.
 694  695   */
 695  696  static
 696  697  ns_ldap_return_code
 697  698  convert_to_door_line(LDAP* ld,
 698  699                  LDAPMessage *result_msg,
 699  700                  int include_names,
 700  701                  int is_profile,
 701  702                  char **door_line)
 702  703  {
 703  704          uint32_t        total_length = 0, attr_len = 0, i;
 704  705          LDAPMessage     *e;
 705  706          char            *a, **vals;
 706  707          BerElement      *ber;
 707  708          int             seen_objectclass = 0, rewind = 0;
 708  709  
 709  710          if (!door_line) {
 710  711                  return (NS_LDAP_INVALID_PARAM);
 711  712          }
 712  713          *door_line = NULL;
 713  714  
 714  715          if ((e = ldap_first_entry(ld, result_msg)) == NULL) {
 715  716                  return (NS_LDAP_NOTFOUND);
 716  717          }
 717  718  
 718  719          /* calculate length of received data */
 719  720          for (a = ldap_first_attribute(ld, e, &ber);
 720  721              a != NULL;
 721  722              a = ldap_next_attribute(ld, e, ber)) {
 722  723  
 723  724                  if ((vals = ldap_get_values(ld, e, a)) != NULL) {
 724  725                          for (i = 0; vals[i] != NULL; i++) {
 725  726                                  total_length += (include_names ?
 726  727                                      strlen(a) : 0) +
 727  728                                      strlen(vals[i]) +
 728  729                                      strlen(DOORLINESEP) +1;
 729  730                          }
 730  731                          ldap_value_free(vals);
 731  732                  }
 732  733                  ldap_memfree(a);
 733  734          }
 734  735          if (ber != NULL) {
 735  736                  ber_free(ber, 0);
 736  737          }
 737  738  
 738  739          if (total_length == 0) {
 739  740                  return (NS_LDAP_NOTFOUND);
 740  741          }
 741  742  
 742  743          /* copy the data */
 743  744          /* add 1 for the last '\0' */
 744  745          *door_line  = (char *)malloc(total_length + 1);
 745  746          if (*door_line == NULL) {
 746  747                  return (NS_LDAP_MEMORY);
 747  748          }
 748  749  
 749  750          /* make it an empty string first */
 750  751          **door_line = '\0';
 751  752          a = ldap_first_attribute(ld, e, &ber);
 752  753          while (a != NULL) {
 753  754                  if (is_profile) {
 754  755                          /*
 755  756                           * If we're processing DUAConfigProfile, we need to make
 756  757                           * sure we put objectclass attribute first.
 757  758                           * __s_api_create_config_door_str depends on that.
 758  759                           */
 759  760                          if (seen_objectclass) {
 760  761                                  if (strcasecmp(a, "objectclass") == 0) {
 761  762                                          /* Skip objectclass now. */
 762  763                                          a = ldap_next_attribute(ld, e, ber);
 763  764                                          continue;
 764  765                                  }
 765  766                          } else {
 766  767                                  if (strcasecmp(a, "objectclass") == 0) {
 767  768                                          seen_objectclass = 1;
 768  769                                          rewind = 1;
 769  770                                  } else {
 770  771                                          /* Skip all but objectclass first. */
 771  772                                          a = ldap_next_attribute(ld, e, ber);
 772  773                                          continue;
 773  774                                  }
 774  775                          }
 775  776                  }
 776  777  
 777  778                  if ((vals = ldap_get_values(ld, e, a)) != NULL) {
 778  779                          for (i = 0; vals[i] != NULL; i++) {
 779  780                                  if (include_names) {
 780  781                                          attr_len += strlen(a);
 781  782                                  }
 782  783                                  attr_len += strlen(vals[i]) +
 783  784                                      strlen(DOORLINESEP) + 2;
 784  785                                  if (include_names) {
 785  786                                          (void) snprintf(*door_line +
 786  787                                              strlen(*door_line),
 787  788                                              attr_len,
 788  789                                              "%s=%s%s",
 789  790                                              a, vals[i],
 790  791                                              DOORLINESEP);
 791  792                                  } else {
 792  793                                          (void) snprintf(*door_line +
 793  794                                              strlen(*door_line),
 794  795                                              attr_len,
 795  796                                              "%s%s",
 796  797                                              vals[i],
 797  798                                              DOORLINESEP);
 798  799                                  }
 799  800                          }
 800  801                          ldap_value_free(vals);
 801  802                  }
 802  803                  ldap_memfree(a);
 803  804  
 804  805                  /* Rewind */
 805  806                  if (rewind) {
 806  807                          if (ber != NULL) {
 807  808                                  ber_free(ber, 0);
 808  809                          }
 809  810                          a = ldap_first_attribute(ld, e, &ber);
 810  811                          rewind = 0;
 811  812                  } else {
 812  813                          a = ldap_next_attribute(ld, e, ber);
 813  814                  }
 814  815          }
 815  816          if (ber != NULL) {
 816  817                  ber_free(ber, 0);
 817  818          }
 818  819  
 819  820          if (e != result_msg) {
 820  821                  (void) ldap_msgfree(e);
 821  822          }
 822  823  
 823  824          return (NS_LDAP_SUCCESS);
 824  825  }
 825  826  
 826  827  /*
 827  828   * This function looks up the base DN of a directory serving
 828  829   * a specified domain name.
 829  830   *
 830  831   * INPUT:
 831  832   *     ld - a pointer to an LDAP structure used for the search operation,
 832  833   *     domain_name - the name of a domain.
 833  834   *
 834  835   * OUTPUT:
 835  836   *     a buffer containing a directory's base DN found.
 836  837   *     Should be free'ed by the caller.
 837  838   */
 838  839  static
 839  840  ns_ldap_return_code
 840  841  getDirBaseDN(LDAP *ld, const char *domain_name, char **dir_base_dn)
 841  842  {
 842  843          struct timeval          tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
 843  844          char                    *attrs[2], *DNlist, *rest, *ptr;
 844  845          char                    filter[BUFSIZ], *a = NULL;
 845  846          int                     ldap_rc;
 846  847          LDAPMessage             *resultMsg = NULL;
 847  848          ns_ldap_return_code     ret_code;
 848  849  
 849  850          /* Get the whole list of naming contexts residing on the server */
 850  851          attrs[0] = "namingcontexts";
 851  852          attrs[1] = NULL;
 852  853          ldap_rc = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
 853  854              attrs, 0, NULL, NULL, &tv, 0, &resultMsg);
 854  855          switch (ldap_rc) {
 855  856                  /* If successful, the root DSE was found. */
 856  857                  case LDAP_SUCCESS:
 857  858                          break;
 858  859                  /*
 859  860                   * If the root DSE was not found, the server does
 860  861                   * not comply with the LDAP v3 protocol.
 861  862                   */
 862  863                  default:
 863  864                          if (resultMsg) {
 864  865                                  (void) ldap_msgfree(resultMsg);
 865  866                                  resultMsg = NULL;
 866  867                          }
 867  868  
 868  869                          return (NS_LDAP_OP_FAILED);
 869  870          }
 870  871  
 871  872          if ((ret_code = convert_to_door_line(ld,
 872  873              resultMsg,
 873  874              DONT_INCLUDE_ATTR_NAMES,
 874  875              NOT_PROFILE,
 875  876              &DNlist)) != NS_LDAP_SUCCESS) {
 876  877                  if (resultMsg) {
 877  878                          (void) ldap_msgfree(resultMsg);
 878  879                          resultMsg = NULL;
 879  880                  }
 880  881                  return (ret_code);
 881  882          }
 882  883  
 883  884          if (resultMsg) {
 884  885                  (void) ldap_msgfree(resultMsg);
 885  886                  resultMsg = NULL;
 886  887          }
 887  888  
 888  889          if (DNlist == NULL ||
 889  890              (ptr = strtok_r(DNlist, DOORLINESEP, &rest)) == NULL) {
 890  891                  return (NS_LDAP_NOTFOUND);
 891  892          }
 892  893          attrs[0] = "dn";
 893  894          do {
 894  895                  /*
 895  896                   * For each context try to find a NIS domain object
 896  897                   * which 'nisdomain' attribute's value matches the domain name
 897  898                   */
 898  899                  (void) snprintf(filter,
 899  900                      BUFSIZ,
 900  901                      "(&(objectclass=nisDomainObject)"
 901  902                      "(nisdomain=%s))",
 902  903                      domain_name);
 903  904                  ldap_rc = ldap_search_ext_s(ld,
 904  905                      ptr,
 905  906                      LDAP_SCOPE_SUBTREE,
 906  907                      filter,
 907  908                      attrs,
 908  909                      0,
 909  910                      NULL,
 910  911                      NULL,
 911  912                      &tv,
 912  913                      0,
 913  914                      &resultMsg);
 914  915                  if (ldap_rc != LDAP_SUCCESS) {
 915  916                          if (resultMsg) {
 916  917                                  (void) ldap_msgfree(resultMsg);
 917  918                                  resultMsg = NULL;
 918  919                          }
 919  920                          continue;
 920  921                  }
 921  922                  if ((a = ldap_get_dn(ld, resultMsg)) != NULL) {
 922  923                          *dir_base_dn = strdup(a);
 923  924                          ldap_memfree(a);
 924  925  
 925  926                          if (resultMsg) {
 926  927                                  (void) ldap_msgfree(resultMsg);
 927  928                                  resultMsg = NULL;
 928  929                          }
 929  930  
 930  931                          if (!*dir_base_dn) {
 931  932                                  free(DNlist);
 932  933                                  return (NS_LDAP_MEMORY);
 933  934                          }
 934  935                          break;
 935  936                  }
 936  937  
 937  938                  if (resultMsg) {
 938  939                          (void) ldap_msgfree(resultMsg);
 939  940                          resultMsg = NULL;
 940  941                  }
 941  942          } while (ptr = strtok_r(NULL, DOORLINESEP, &rest));
 942  943  
 943  944          free(DNlist);
 944  945  
 945  946          if (!*dir_base_dn) {
 946  947                  return (NS_LDAP_NOTFOUND);
 947  948          }
 948  949  
 949  950          return (NS_LDAP_SUCCESS);
 950  951  }
 951  952  
 952  953  /*
 953  954   * This function parses the results of a search operation
 954  955   * requesting a DUAProfile.
 955  956   *
 956  957   * INPUT:
 957  958   *     ld - a pointer to an LDAP structure used for the search operation,
 958  959   *     dir_base_dn - the name of a directory's base DN,
 959  960   *     profile_name - the name of a DUAProfile to be obtained.
 960  961   *
 961  962   * OUTPUT:
 962  963   *      a buffer containing the DUAProfile in the following format:
 963  964   *        [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
 964  965   *      Should be free'ed by the caller.
 965  966   */
 966  967  static
 967  968  ns_ldap_return_code
 968  969  getDUAProfile(LDAP *ld,
 969  970                  const char *dir_base_dn,
 970  971                  const char *profile_name,
 971  972                  char **profile)
 972  973  {
 973  974          char                    searchBaseDN[BUFSIZ], filter[BUFSIZ];
 974  975          LDAPMessage             *resultMsg = NULL;
 975  976          struct timeval          tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
 976  977          int                     ldap_rc;
 977  978          ns_ldap_return_code     ret_code;
 978  979  
 979  980          (void) snprintf(searchBaseDN, BUFSIZ, "ou=profile,%s", dir_base_dn);
 980  981          (void) snprintf(filter,
 981  982              BUFSIZ,
 982  983              _PROFILE_FILTER,
 983  984              _PROFILE1_OBJECTCLASS,
 984  985              _PROFILE2_OBJECTCLASS,
 985  986              profile_name);
 986  987          ldap_rc = ldap_search_ext_s(ld,
 987  988              searchBaseDN,
 988  989              LDAP_SCOPE_SUBTREE,
 989  990              filter,
 990  991              NULL,
 991  992              0,
 992  993              NULL,
 993  994              NULL,
 994  995              &tv,
 995  996              0,
 996  997              &resultMsg);
 997  998  
 998  999          switch (ldap_rc) {
 999 1000                  /* If successful, the DUA profile was found. */
1000 1001                  case LDAP_SUCCESS:
1001 1002                          break;
1002 1003                  /*
1003 1004                   * If the root DSE was not found, the server does
1004 1005                   * not comply with the LDAP v3 protocol.
1005 1006                   */
1006 1007                  default:
1007 1008                          if (resultMsg) {
1008 1009                                  (void) ldap_msgfree(resultMsg);
1009 1010                                  resultMsg = NULL;
1010 1011                          }
1011 1012  
1012 1013                          return (NS_LDAP_OP_FAILED);
1013 1014          }
1014 1015  
1015 1016          ret_code = convert_to_door_line(ld,
1016 1017              resultMsg,
1017 1018              INCLUDE_ATTR_NAMES,
1018 1019              IS_PROFILE,
1019 1020              profile);
1020 1021          if (resultMsg) {
1021 1022                  (void) ldap_msgfree(resultMsg);
1022 1023                  resultMsg = NULL;
1023 1024          }
1024 1025          return (ret_code);
1025 1026  }
1026 1027  
1027 1028  /*
1028 1029   * This function derives the directory's base DN from a provided domain name.
1029 1030   *
1030 1031   * INPUT:
1031 1032   *     domain_name - the name of a domain to be converted into a base DN,
1032 1033   *     buffer - contains the derived base DN,
1033 1034   *     buf_len - the length of the buffer.
1034 1035   *
1035 1036   * OUTPUT:
1036 1037   *     The function returns the address of the buffer or NULL.
1037 1038   */
1038 1039  static
1039 1040  char *
1040 1041  domainname2baseDN(char *domain_name, char *buffer, uint16_t buf_len)
1041 1042  {
1042 1043          char            *nextDC, *chr;
1043 1044          uint16_t        i, length;
1044 1045  
1045 1046          if (!domain_name || !buffer || buf_len == 0) {
1046 1047                  return (NULL);
1047 1048          }
1048 1049  
1049 1050          buffer[0] = '\0';
1050 1051          nextDC = chr = domain_name;
1051 1052          length = strlen(domain_name);
1052 1053          for (i = 0; i < length + 1; ++i, ++chr) {
1053 1054                  /* Simply replace dots with "dc=" */
1054 1055                  if (*chr != '.' && *chr != '\0') {
1055 1056                          continue;
1056 1057                  }
1057 1058                  *chr = '\0';
1058 1059                  if (strlcat(buffer, "dc=", buf_len) >= buf_len)
1059 1060                          return (NULL);
1060 1061                  if (strlcat(buffer, nextDC, buf_len) >= buf_len)
1061 1062                          return (NULL);
1062 1063                  if (i < length) {
1063 1064                          /*
1064 1065                           * The end of the domain name
1065 1066                           * has not been reached yet
1066 1067                           */
1067 1068                          if (strlcat(buffer, ",", buf_len) >= buf_len)
1068 1069                                  return (NULL);
1069 1070                          nextDC = chr + 1;
1070 1071                          *chr = '.';
1071 1072                  }
1072 1073          }
1073 1074  
1074 1075          return (buffer);
1075 1076  }
1076 1077  
1077 1078  /*
1078 1079   * This function obtains the directory's base DN and a DUAProfile
1079 1080   * from a specified server.
1080 1081   *
1081 1082   * INPUT:
1082 1083   *     server - a structure describing a server to connect to and
1083 1084   *              a DUAProfile to be obtained from the server,
1084 1085   *     cred - credentials to be used during establishing connections to
1085 1086   *            the server.
1086 1087   *
1087 1088   * OUTPUT:
1088 1089   *     dua_profile - a buffer containing the DUAProfile in the following format:
1089 1090   *        [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1090 1091   *     dir_base_dn - a buffer containing the base DN,
1091 1092   *     errorp - an error object describing an error, if any.
1092 1093   *
1093 1094   *     All the output data structures should be free'ed by the caller.
1094 1095   */
1095 1096  ns_ldap_return_code
1096 1097  __ns_ldap_getConnectionInfoFromDUA(const ns_dir_server_t *server,
1097 1098          const ns_cred_t *cred,
1098 1099          char **dua_profile,
1099 1100          char **dir_base_dn,
1100 1101          ns_ldap_error_t **errorp)
1101 1102  {
1102 1103          char                    serverAddr[MAX_HOSTADDR_LEN];
1103 1104          char                    *dirBaseDN = NULL, *duaProfile = NULL;
1104 1105          ns_cred_t               default_cred;
1105 1106          ns_ldap_return_code     ret_code;
1106 1107  
1107 1108          ns_config_t             *config_struct = __s_api_create_config();
1108 1109          ConnectionID            sessionId = 0;
1109 1110          Connection              *session = NULL;
1110 1111          char                    errmsg[MAXERROR];
1111 1112          char                    buffer[NSS_BUFLEN_HOSTS];
1112 1113          ns_conn_user_t          *cu = NULL;
1113 1114  
1114 1115          if (errorp == NULL) {
1115 1116                  __s_api_destroy_config(config_struct);
1116 1117                  return (NS_LDAP_INVALID_PARAM);
1117 1118          }
1118 1119  
1119 1120          *errorp = NULL;
1120 1121  
1121 1122          if (server == NULL) {
1122 1123                  __s_api_destroy_config(config_struct);
1123 1124                  return (NS_LDAP_INVALID_PARAM);
1124 1125          }
1125 1126  
1126 1127          if (config_struct == NULL) {
1127 1128                  return (NS_LDAP_MEMORY);
1128 1129          }
1129 1130  
1130 1131          /*
1131 1132           * If no credentials are specified, try to establish a connection
1132 1133           * as anonymous.
1133 1134           */
1134 1135          if (!cred) {
1135 1136                  default_cred.cred.unix_cred.passwd = NULL;
1136 1137                  default_cred.cred.unix_cred.userID = NULL;
1137 1138                  default_cred.auth.type = NS_LDAP_AUTH_NONE;
1138 1139          }
1139 1140  
1140 1141          /* Now create a default LDAP configuration */
1141 1142  
1142 1143          (void) strncpy(buffer, server->server, sizeof (buffer));
1143 1144          if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SERVERS_P, buffer,
1144 1145              errorp) != NS_LDAP_SUCCESS) {
1145 1146                  __s_api_destroy_config(config_struct);
1146 1147                  return (NS_LDAP_CONFIG);
1147 1148          }
1148 1149  
1149 1150          /* Put together the address and the port specified by the user app. */
1150 1151          if (server->port > 0) {
1151 1152                  (void) snprintf(serverAddr,
1152 1153                      sizeof (serverAddr),
1153 1154                      "%s:%hu",
1154 1155                      buffer,
1155 1156                      server->port);
1156 1157          } else {
1157 1158                  (void) strncpy(serverAddr, buffer, sizeof (serverAddr));
1158 1159          }
1159 1160  
1160 1161          /*
1161 1162           * There is no default value for the 'Default Search Base DN' attribute.
1162 1163           * Derive one from the domain name to make __s_api_crosscheck() happy.
1163 1164           */
1164 1165          if (domainname2baseDN(server->domainName ?
1165 1166              server->domainName : config_struct->domainName,
1166 1167              buffer, NSS_BUFLEN_HOSTS) == NULL) {
1167 1168                  (void) snprintf(errmsg,
1168 1169                      sizeof (errmsg),
1169 1170                      gettext("Can not convert %s into a base DN name"),
1170 1171                      server->domainName ?
1171 1172                      server->domainName : config_struct->domainName);
1172 1173                  MKERROR(LOG_ERR,
1173 1174                      *errorp,
1174 1175                      NS_LDAP_INTERNAL,
1175 1176                      strdup(errmsg),
1176 1177                      NS_LDAP_MEMORY);
1177 1178                  __s_api_destroy_config(config_struct);
1178 1179                  return (NS_LDAP_INTERNAL);
1179 1180          }
1180 1181          if (__ns_ldap_setParamValue(config_struct, NS_LDAP_SEARCH_BASEDN_P,
1181 1182              buffer, errorp) != NS_LDAP_SUCCESS) {
1182 1183                  __s_api_destroy_config(config_struct);
1183 1184                  return (NS_LDAP_CONFIG);
1184 1185          }
1185 1186  
1186 1187          if (__s_api_crosscheck(config_struct, errmsg, B_FALSE) != NS_SUCCESS) {
1187 1188                  __s_api_destroy_config(config_struct);
1188 1189                  return (NS_LDAP_CONFIG);
1189 1190          }
1190 1191  
1191 1192          __s_api_init_config(config_struct);
1192 1193  
1193 1194          __s_api_setInitMode();
1194 1195  
1195 1196          cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
1196 1197          if (cu == NULL) {
1197 1198                  return (NS_LDAP_INTERNAL);
1198 1199          }
1199 1200  
1200 1201          if ((ret_code = __s_api_getConnection(serverAddr,
1201 1202              NS_LDAP_NEW_CONN,
1202 1203              cred ? cred : &default_cred,
1203 1204              &sessionId,
1204 1205              &session,
1205 1206              errorp,
1206 1207              0,
1207 1208              0,
1208 1209              cu)) != NS_LDAP_SUCCESS) {
1209 1210                  __s_api_conn_user_free(cu);
1210 1211                  __s_api_unsetInitMode();
1211 1212                  return (ret_code);
1212 1213          }
1213 1214  
1214 1215          __s_api_unsetInitMode();
1215 1216  
1216 1217          if ((ret_code = getDirBaseDN(session->ld,
1217 1218              server->domainName ?
1218 1219              server->domainName :
1219 1220              config_struct->domainName,
1220 1221              &dirBaseDN)) != NS_LDAP_SUCCESS) {
1221 1222                  (void) snprintf(errmsg,
1222 1223                      sizeof (errmsg),
1223 1224                      gettext("Can not find the "
1224 1225                      "nisDomainObject for domain %s\n"),
1225 1226                      server->domainName ?
1226 1227                      server->domainName : config_struct->domainName);
1227 1228                  MKERROR(LOG_ERR,
1228 1229                      *errorp,
1229 1230                      ret_code,
1230 1231                      strdup(errmsg),
1231 1232                      NS_LDAP_MEMORY);
1232 1233                  __s_api_conn_user_free(cu);
1233 1234                  DropConnection(sessionId, NS_LDAP_NEW_CONN);
1234 1235                  return (ret_code);
1235 1236          }
1236 1237  
1237 1238          /*
1238 1239           * And here obtain a DUAProfile which will be used
1239 1240           * as a real configuration.
1240 1241           */
1241 1242          if ((ret_code = getDUAProfile(session->ld,
1242 1243              dirBaseDN,
1243 1244              server->profileName ?
1244 1245              server->profileName : "default",
1245 1246              &duaProfile)) != NS_LDAP_SUCCESS) {
1246 1247                  (void) snprintf(errmsg,
1247 1248                      sizeof (errmsg),
1248 1249                      gettext("Can not find the "
1249 1250                      "%s DUAProfile\n"),
1250 1251                      server->profileName ?
1251 1252                      server->profileName : "default");
1252 1253                  MKERROR(LOG_ERR,
1253 1254                      *errorp,
1254 1255                      ret_code,
1255 1256                      strdup(errmsg),
1256 1257                      NS_LDAP_MEMORY);
1257 1258                  __s_api_conn_user_free(cu);
1258 1259                  DropConnection(sessionId, NS_LDAP_NEW_CONN);
1259 1260                  return (ret_code);
1260 1261          }
1261 1262  
1262 1263          if (dir_base_dn) {
1263 1264                  *dir_base_dn = dirBaseDN;
1264 1265          } else {
1265 1266                  free(dirBaseDN);
1266 1267          }
1267 1268  
1268 1269          if (dua_profile) {
1269 1270                  *dua_profile = duaProfile;
1270 1271          } else {
1271 1272                  free(duaProfile);
1272 1273          }
1273 1274  
1274 1275          __s_api_conn_user_free(cu);
1275 1276          DropConnection(sessionId, NS_LDAP_NEW_CONN);
1276 1277  
1277 1278          return (NS_LDAP_SUCCESS);
1278 1279  }
1279 1280  
1280 1281  /*
1281 1282   * This function obtains the root DSE from a specified server.
1282 1283   *
1283 1284   * INPUT:
1284 1285   *     server_addr - an adress of a server to be connected to.
1285 1286   *
1286 1287   * OUTPUT:
1287 1288   *     root_dse - a buffer containing the root DSE in the following format:
1288 1289   *          [<attribute name>=]value [DOORLINESEP [<attribute name>=]value ]...]
1289 1290   *        For example: ( here | used as DOORLINESEP for visual purposes)
1290 1291   *          supportedControl=1.1.1.1|supportedSASLmechanisms=EXTERNAL
1291 1292   *        Should be free'ed by the caller.
1292 1293   */
1293 1294  ns_ldap_return_code
1294 1295  __ns_ldap_getRootDSE(const char *server_addr,
1295 1296                  char **root_dse,
1296 1297                  ns_ldap_error_t **errorp,
1297 1298                  int anon_fallback)
1298 1299  {
1299 1300          char                    errmsg[MAXERROR];
1300 1301          ns_ldap_return_code     ret_code;
1301 1302  
1302 1303          ConnectionID            sessionId = 0;
1303 1304          Connection              *session = NULL;
1304 1305  
1305 1306          struct timeval          tv = {NS_DEFAULT_SEARCH_TIMEOUT, 0};
1306 1307          char                    *attrs[3];
1307 1308          int                     ldap_rc, ldaperrno = 0;
1308 1309          LDAPMessage             *resultMsg = NULL;
1309 1310          void                    **paramVal = NULL;
1310 1311  
1311 1312          ns_cred_t               anon;
1312 1313          ns_conn_user_t          *cu = NULL;
1313 1314  
1314 1315          if (errorp == NULL) {
1315 1316                  return (NS_LDAP_INVALID_PARAM);
1316 1317          }
1317 1318  
1318 1319          *errorp = NULL;
1319 1320  
1320 1321          if (!root_dse) {
1321 1322                  return (NS_LDAP_INVALID_PARAM);
1322 1323          }
1323 1324  
1324 1325          if (!server_addr) {
1325 1326                  return (NS_LDAP_INVALID_PARAM);
1326 1327          }
1327 1328  
1328 1329          __s_api_setInitMode();
1329 1330  
1330 1331          cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, B_FALSE);
1331 1332          if (cu == NULL) {
1332 1333                  return (NS_LDAP_INTERNAL);
1333 1334          }
1334 1335  
1335 1336          /*
1336 1337           * All the credentials will be taken from the current
1337 1338           * libsldap configuration.
1338 1339           */
1339 1340          if ((ret_code = __s_api_getConnection(server_addr,
1340 1341              NS_LDAP_NEW_CONN,
1341 1342              NULL,
1342 1343              &sessionId,
1343 1344              &session,
1344 1345              errorp,
1345 1346              0,
1346 1347              0,
1347 1348              cu)) != NS_LDAP_SUCCESS) {
1348 1349                  /* Fallback to anonymous mode is disabled. Stop. */
1349 1350                  if (anon_fallback == 0) {
1350 1351                          syslog(LOG_WARNING,
1351 1352                              gettext("libsldap: can not get the root DSE from "
1352 1353                              " the %s server: %s. "
1353 1354                              "Falling back to anonymous disabled.\n"),
1354 1355                              server_addr,
1355 1356                              errorp && *errorp && (*errorp)->message ?
1356 1357                              (*errorp)->message : "");
1357 1358                          if (errorp != NULL && *errorp != NULL) {
1358 1359                                  (void) __ns_ldap_freeError(errorp);
1359 1360                          }
1360 1361                          __s_api_unsetInitMode();
1361 1362                          return (ret_code);
1362 1363                  }
1363 1364  
1364 1365                  /*
1365 1366                   * Fallback to anonymous, non-SSL mode for backward
1366 1367                   * compatibility reasons. This mode should only be used when
1367 1368                   * this function (__ns_ldap_getRootDSE) is called from
1368 1369                   * ldap_cachemgr(1M).
1369 1370                   */
1370 1371                  syslog(LOG_WARNING,
1371 1372                      gettext("libsldap: Falling back to anonymous, non-SSL"
1372 1373                      " mode for __ns_ldap_getRootDSE. %s\n"),
1373 1374                      errorp && *errorp && (*errorp)->message ?
1374 1375                      (*errorp)->message : "");
1375 1376  
1376 1377                  /* Setup the anon credential for anonymous connection. */
1377 1378                  (void) memset(&anon, 0, sizeof (ns_cred_t));
1378 1379                  anon.auth.type = NS_LDAP_AUTH_NONE;
1379 1380  
1380 1381                  if (*errorp != NULL) {
1381 1382                          (void) __ns_ldap_freeError(errorp);
1382 1383                  }
1383 1384                  *errorp = NULL;
1384 1385  
1385 1386                  ret_code = __s_api_getConnection(server_addr,
1386 1387                      NS_LDAP_NEW_CONN,
1387 1388                      &anon,
1388 1389                      &sessionId,
1389 1390                      &session,
1390 1391                      errorp,
1391 1392                      0,
1392 1393                      0,
1393 1394                      cu);
1394 1395  
1395 1396                  if (ret_code != NS_LDAP_SUCCESS) {
1396 1397                          __s_api_conn_user_free(cu);
1397 1398                          __s_api_unsetInitMode();
1398 1399                          return (ret_code);
1399 1400                  }
1400 1401          }
1401 1402  
1402 1403          __s_api_unsetInitMode();
1403 1404  
1404 1405          /* get search timeout value */
1405 1406          (void) __ns_ldap_getParam(NS_LDAP_SEARCH_TIME_P, ¶mVal, errorp);
1406 1407          if (paramVal != NULL && *paramVal != NULL) {
1407 1408                  tv.tv_sec = **((int **)paramVal);
1408 1409                  (void) __ns_ldap_freeParam(¶mVal);
1409 1410          }
1410 1411          if (*errorp != NULL) {
1411 1412                  (void) __ns_ldap_freeError(errorp);
1412 1413          }
1413 1414  
1414 1415          /* Get root DSE from the server specified by the caller. */
1415 1416          attrs[0] = "supportedControl";
1416 1417          attrs[1] = "supportedsaslmechanisms";
1417 1418          attrs[2] = NULL;
1418 1419          ldap_rc = ldap_search_ext_s(session->ld,
1419 1420              "",
1420 1421              LDAP_SCOPE_BASE,
1421 1422              "(objectclass=*)",
1422 1423              attrs,
1423 1424              0,
1424 1425              NULL,
1425 1426              NULL,
1426 1427              &tv,
1427 1428              0,
1428 1429              &resultMsg);
1429 1430  
1430 1431          if (ldap_rc != LDAP_SUCCESS) {
1431 1432                  /*
1432 1433                   * If the root DSE was not found, the server does
1433 1434                   * not comply with the LDAP v3 protocol.
1434 1435                   */
1435 1436                  (void) ldap_get_option(session->ld,
1436 1437                      LDAP_OPT_ERROR_NUMBER,
1437 1438                      &ldaperrno);
1438 1439                  (void) snprintf(errmsg,
1439 1440                      sizeof (errmsg),
1440 1441                      gettext(ldap_err2string(ldaperrno)));
1441 1442                  MKERROR(LOG_ERR,
1442 1443                      *errorp,
  
    | ↓ open down ↓ | 1408 lines elided | ↑ open up ↑ | 
1443 1444                      NS_LDAP_OP_FAILED,
1444 1445                      strdup(errmsg),
1445 1446                      NS_LDAP_MEMORY);
1446 1447  
1447 1448                  if (resultMsg) {
1448 1449                          (void) ldap_msgfree(resultMsg);
1449 1450                          resultMsg = NULL;
1450 1451                  }
1451 1452  
1452 1453                  __s_api_conn_user_free(cu);
     1454 +                DropConnection(sessionId, NS_LDAP_NEW_CONN);
1453 1455                  return (NS_LDAP_OP_FAILED);
1454 1456          }
1455 1457          __s_api_conn_user_free(cu);
1456 1458  
1457 1459          ret_code = convert_to_door_line(session->ld,
1458 1460              resultMsg,
1459 1461              INCLUDE_ATTR_NAMES,
1460 1462              NOT_PROFILE,
1461 1463              root_dse);
1462 1464          if (ret_code == NS_LDAP_NOTFOUND) {
1463 1465                  (void) snprintf(errmsg,
1464 1466                      sizeof (errmsg),
1465 1467                      gettext("No root DSE data "
1466 1468                      "for server %s returned."),
1467 1469                      server_addr);
1468 1470                  MKERROR(LOG_ERR,
1469 1471                      *errorp,
1470 1472                      NS_LDAP_NOTFOUND,
1471 1473                      strdup(errmsg),
1472 1474                      NS_LDAP_MEMORY);
1473 1475          }
1474 1476  
1475 1477          if (resultMsg) {
1476 1478                  (void) ldap_msgfree(resultMsg);
1477 1479                  resultMsg = NULL;
1478 1480          }
1479 1481  
1480 1482          DropConnection(sessionId, NS_LDAP_NEW_CONN);
1481 1483  
1482 1484          return (ret_code);
1483 1485  }
1484 1486  
1485 1487  /*
1486 1488   * This function destroys the local list of root DSEs. The input parameter is
1487 1489   * a pointer to the list to be erased.
1488 1490   * The type of the pointer passed to this function should be
1489 1491   * (dir_server_list_t *).
1490 1492   */
1491 1493  static
1492 1494  void *
1493 1495  disposeOfOldList(void *param)
1494 1496  {
1495 1497          dir_server_list_t       *old_list = (dir_server_list_t *)param;
1496 1498          long                    i = 0, j;
1497 1499  
1498 1500          (void) rw_wrlock(&old_list->listDestroyLock);
1499 1501          /* Destroy the old list */
1500 1502          while (old_list->nsServers[i]) {
1501 1503                  free(old_list->nsServers[i]->ip);
1502 1504                  j = 0;
1503 1505                  while (old_list->nsServers[i]->controls &&
1504 1506                      old_list->nsServers[i]->controls[j]) {
1505 1507                          free(old_list->nsServers[i]->controls[j]);
1506 1508                          ++j;
1507 1509                  }
1508 1510                  free(old_list->nsServers[i]->controls);
1509 1511                  j = 0;
1510 1512                  while (old_list->nsServers[i]->saslMech &&
1511 1513                      old_list->nsServers[i]->saslMech[j]) {
1512 1514                          free(old_list->nsServers[i]->saslMech[j]);
1513 1515                          ++j;
1514 1516                  }
1515 1517                  free(old_list->nsServers[i]->saslMech);
1516 1518                  ++i;
1517 1519          }
1518 1520          /*
1519 1521           * All the structures pointed by old_list->nsServers were allocated
1520 1522           * in one chunck. The nsServers[0] pointer points to the beginning
1521 1523           * of that chunck.
1522 1524           */
1523 1525          free(old_list->nsServers[0]);
1524 1526          free(old_list->nsServers);
1525 1527          (void) rw_unlock(&old_list->listDestroyLock);
1526 1528          (void) rwlock_destroy(&old_list->listDestroyLock);
1527 1529          free(old_list);
1528 1530  
1529 1531          return (NULL);
1530 1532  }
1531 1533  
1532 1534  /*
1533 1535   * This function cancels the Standalone mode and destroys the list of root DSEs.
1534 1536   */
1535 1537  void
1536 1538  __ns_ldap_cancelStandalone(void)
1537 1539  {
1538 1540          dir_server_list_t       *old_list;
1539 1541  
1540 1542          (void) mutex_lock(&dir_servers.listReplaceLock);
1541 1543          dir_servers.standalone = 0;
1542 1544          if (!dir_servers.list) {
1543 1545                  (void) mutex_unlock(&dir_servers.listReplaceLock);
1544 1546                  return;
1545 1547          }
1546 1548          old_list = dir_servers.list;
1547 1549          dir_servers.list = NULL;
1548 1550          (void) mutex_unlock(&dir_servers.listReplaceLock);
1549 1551  
1550 1552          (void) disposeOfOldList(old_list);
1551 1553  }
1552 1554  
1553 1555  
1554 1556  static
1555 1557  void*
1556 1558  create_ns_servers_entry(void *param)
1557 1559  {
1558 1560  #define CHUNK_SIZE 16
1559 1561  
1560 1562          dir_server_t            *server = (dir_server_t *)param;
1561 1563          ns_ldap_return_code     *retCode = calloc(1,
1562 1564              sizeof (ns_ldap_return_code));
1563 1565          uint32_t                sc_counter = 0, sm_counter = 0;
1564 1566          uint32_t                sc_mem_blocks = 1, sm_mem_blocks = 1;
1565 1567          char                    *rootDSE = NULL, *attr, *val, *rest, **ptr;
1566 1568          ns_ldap_error_t         *error = NULL;
1567 1569  
1568 1570          if (retCode == NULL) {
1569 1571                  return (NULL);
1570 1572          }
1571 1573  
1572 1574          /*
1573 1575           * We call this function in non anon-fallback mode because we
1574 1576           * want the whole procedure to fail as soon as possible to
1575 1577           * indicate there are problems with connecting to the server.
1576 1578           */
1577 1579          *retCode = __ns_ldap_getRootDSE(server->ip,
1578 1580              &rootDSE,
1579 1581              &error,
1580 1582              SA_ALLOW_FALLBACK);
1581 1583  
1582 1584          if (*retCode == NS_LDAP_MEMORY) {
1583 1585                  free(retCode);
1584 1586                  return (NULL);
1585 1587          }
1586 1588  
1587 1589          /*
1588 1590           * If the root DSE can not be obtained, log an error and keep the
1589 1591           * server.
1590 1592           */
1591 1593          if (*retCode != NS_LDAP_SUCCESS) {
1592 1594                  server->status = INFO_SERVER_ERROR;
1593 1595                  syslog(LOG_WARNING,
1594 1596                      gettext("libsldap (\"standalone\" mode): "
1595 1597                      "can not obtain the root DSE from %s. %s"),
1596 1598                      server->ip,
1597 1599                      error && error->message ? error->message : "");
1598 1600                  if (error) {
1599 1601                          (void) __ns_ldap_freeError(&error);
1600 1602                  }
1601 1603                  return (retCode);
1602 1604          }
1603 1605  
1604 1606          /* Get the first attribute of the root DSE. */
1605 1607          attr = strtok_r(rootDSE, DOORLINESEP, &rest);
1606 1608          if (attr == NULL) {
1607 1609                  free(rootDSE);
1608 1610                  server->status = INFO_SERVER_ERROR;
1609 1611                  syslog(LOG_WARNING,
1610 1612                      gettext("libsldap (\"standalone\" mode): "
1611 1613                      "the root DSE from %s is empty or corrupted."),
1612 1614                      server->ip);
1613 1615                  *retCode = NS_LDAP_INTERNAL;
1614 1616                  return (retCode);
1615 1617          }
1616 1618  
1617 1619          server->controls = (char **)calloc(CHUNK_SIZE, sizeof (char *));
1618 1620          server->saslMech = (char **)calloc(CHUNK_SIZE, sizeof (char *));
1619 1621          if (server->controls == NULL || server->saslMech == NULL) {
1620 1622                  free(rootDSE);
1621 1623                  free(retCode);
1622 1624                  return (NULL);
1623 1625          }
1624 1626  
1625 1627          do {
1626 1628                  if ((val = strchr(attr, '=')) == NULL) {
1627 1629                          continue;
1628 1630                  }
1629 1631                  ++val;
1630 1632  
1631 1633                  if (strncasecmp(attr,
1632 1634                      _SASLMECHANISM,
1633 1635                      _SASLMECHANISM_LEN) == 0) {
1634 1636                          if (sm_counter == CHUNK_SIZE * sm_mem_blocks - 1) {
1635 1637                                  ptr = (char **)realloc(server->saslMech,
1636 1638                                      CHUNK_SIZE *
1637 1639                                      ++sm_mem_blocks *
1638 1640                                      sizeof (char *));
1639 1641                                  if (ptr == NULL) {
1640 1642                                          *retCode = NS_LDAP_MEMORY;
1641 1643                                          break;
1642 1644                                  }
1643 1645                                  bzero((char *)ptr +
1644 1646                                      (sm_counter + 1) *
1645 1647                                      sizeof (char *),
1646 1648                                      CHUNK_SIZE *
1647 1649                                      sm_mem_blocks *
1648 1650                                      sizeof (char *) -
1649 1651                                      (sm_counter + 1) *
1650 1652                                      sizeof (char *));
1651 1653                                  server->saslMech = ptr;
1652 1654                          }
1653 1655                          server->saslMech[sm_counter] = strdup(val);
1654 1656                          if (server->saslMech[sm_counter] == NULL) {
1655 1657                                  *retCode = NS_LDAP_MEMORY;
1656 1658                                  break;
1657 1659                          }
1658 1660                          ++sm_counter;
1659 1661                          continue;
1660 1662                  }
1661 1663                  if (strncasecmp(attr,
1662 1664                      _SUPPORTEDCONTROL,
1663 1665                      _SUPPORTEDCONTROL_LEN) == 0) {
1664 1666                          if (sc_counter == CHUNK_SIZE * sc_mem_blocks - 1) {
1665 1667                                  ptr = (char **)realloc(server->controls,
1666 1668                                      CHUNK_SIZE *
1667 1669                                      ++sc_mem_blocks *
1668 1670                                      sizeof (char *));
1669 1671                                  if (ptr == NULL) {
1670 1672                                          *retCode = NS_LDAP_MEMORY;
1671 1673                                          break;
1672 1674                                  }
1673 1675                                  bzero((char *)ptr +
1674 1676                                      (sc_counter + 1) *
1675 1677                                      sizeof (char *),
1676 1678                                      CHUNK_SIZE *
1677 1679                                      sc_mem_blocks *
1678 1680                                      sizeof (char *) -
1679 1681                                      (sc_counter + 1) *
1680 1682                                      sizeof (char *));
1681 1683                                  server->controls = ptr;
1682 1684                          }
1683 1685  
1684 1686                          server->controls[sc_counter] = strdup(val);
1685 1687                          if (server->controls[sc_counter] == NULL) {
1686 1688                                  *retCode = NS_LDAP_MEMORY;
1687 1689                                  break;
1688 1690                          }
1689 1691                          ++sc_counter;
1690 1692                          continue;
1691 1693                  }
1692 1694  
1693 1695          } while (attr = strtok_r(NULL, DOORLINESEP, &rest));
1694 1696  
1695 1697          free(rootDSE);
1696 1698  
1697 1699          if (*retCode == NS_LDAP_MEMORY) {
1698 1700                  free(retCode);
1699 1701                  return (NULL);
1700 1702          }
1701 1703  
1702 1704          server->controls[sc_counter] = NULL;
1703 1705          server->saslMech[sm_counter] = NULL;
1704 1706  
1705 1707          server->status = INFO_SERVER_UP;
1706 1708  
1707 1709          return (retCode);
1708 1710  #undef CHUNK_SIZE
1709 1711  }
1710 1712  
1711 1713  
1712 1714  /*
1713 1715   * This function creates a new local list of root DSEs from all the servers
1714 1716   * mentioned in the DUAProfile (or local NS BEC) and returns
1715 1717   * a pointer to the list.
1716 1718   */
1717 1719  static
1718 1720  ns_ldap_return_code
1719 1721  createDirServerList(dir_server_list_t **new_list,
1720 1722                  ns_ldap_error_t **errorp)
1721 1723  {
1722 1724          char                    **serverList;
1723 1725          ns_ldap_return_code     retCode = NS_LDAP_SUCCESS;
1724 1726          dir_server_t            *tmpSrvArray;
1725 1727          long                    srvListLength, i;
1726 1728          thread_t                *thrPool, thrID;
1727 1729          void                    *status = NULL;
1728 1730  
1729 1731          if (errorp == NULL) {
1730 1732                  return (NS_LDAP_INVALID_PARAM);
1731 1733          }
1732 1734  
1733 1735          *errorp = NULL;
1734 1736  
1735 1737          if (new_list == NULL) {
1736 1738                  return (NS_LDAP_INVALID_PARAM);
1737 1739          }
1738 1740  
1739 1741          retCode = __s_api_getServers(&serverList, errorp);
1740 1742          if (retCode != NS_LDAP_SUCCESS || serverList == NULL) {
1741 1743                  return (retCode);
1742 1744          }
1743 1745  
1744 1746          for (i = 0; serverList[i]; ++i) {
1745 1747                  ;
1746 1748          }
1747 1749          srvListLength = i;
1748 1750  
1749 1751          thrPool = calloc(srvListLength, sizeof (thread_t));
1750 1752          if (thrPool == NULL) {
1751 1753                  __s_api_free2dArray(serverList);
1752 1754                  return (NS_LDAP_MEMORY);
1753 1755          }
1754 1756  
1755 1757          *new_list = (dir_server_list_t *)calloc(1,
1756 1758              sizeof (dir_server_list_t));
1757 1759          if (*new_list == NULL) {
1758 1760                  __s_api_free2dArray(serverList);
1759 1761                  free(thrPool);
1760 1762                  return (NS_LDAP_MEMORY);
1761 1763          }
1762 1764          (void) rwlock_init(&(*new_list)->listDestroyLock, USYNC_THREAD, NULL);
1763 1765  
1764 1766          (*new_list)->nsServers = (dir_server_t **)calloc(srvListLength + 1,
1765 1767              sizeof (dir_server_t *));
1766 1768          if ((*new_list)->nsServers == NULL) {
1767 1769                  free(*new_list);
1768 1770                  *new_list = NULL;
1769 1771                  __s_api_free2dArray(serverList);
1770 1772                  free(thrPool);
1771 1773                  return (NS_LDAP_MEMORY);
1772 1774          }
1773 1775  
1774 1776          /*
1775 1777           * Allocate a set of dir_server_t structures as an array,
1776 1778           * with one alloc call and then initialize the nsServers pointers
1777 1779           * with the addresses of the array's members.
1778 1780           */
1779 1781          tmpSrvArray = (dir_server_t *)calloc(srvListLength,
1780 1782              sizeof (dir_server_t));
1781 1783          for (i = 0; i < srvListLength; ++i) {
1782 1784                  (*new_list)->nsServers[i] = &tmpSrvArray[i];
1783 1785  
1784 1786                  (*new_list)->nsServers[i]->info = INFO_STATUS_NEW;
1785 1787                  (void) mutex_init(&(*new_list)->nsServers[i]->updateStatus,
1786 1788                      USYNC_THREAD,
1787 1789                      NULL);
1788 1790  
1789 1791                  (*new_list)->nsServers[i]->ip = strdup(serverList[i]);
1790 1792                  if ((*new_list)->nsServers[i]->ip == NULL) {
1791 1793                          retCode = NS_LDAP_MEMORY;
1792 1794                          break;
1793 1795                  }
1794 1796  
1795 1797                  (*new_list)->nsServers[i]->status = INFO_SERVER_CONNECTING;
1796 1798  
1797 1799                  switch (thr_create(NULL,
1798 1800                      0,
1799 1801                      create_ns_servers_entry,
1800 1802                      (*new_list)->nsServers[i],
1801 1803                      0,
1802 1804                      &thrID)) {
1803 1805                  case EAGAIN:
1804 1806                          (*new_list)->nsServers[i]->status =
1805 1807                              INFO_SERVER_ERROR;
1806 1808                          continue;
1807 1809                  case ENOMEM:
1808 1810                          (*new_list)->nsServers[i]->status =
1809 1811                              INFO_SERVER_ERROR;
1810 1812                          continue;
1811 1813                  default:
1812 1814                          thrPool[i] = thrID;
1813 1815                          continue;
1814 1816                  }
1815 1817          }
1816 1818  
1817 1819          for (i = 0; i < srvListLength; ++i) {
1818 1820                  if (thrPool[i] != 0 &&
1819 1821                      thr_join(thrPool[i], NULL, &status) == 0) {
1820 1822                          if (status == NULL) {
1821 1823                                  /*
1822 1824                                   * Some memory allocation problems occured. Just
1823 1825                                   * ignore the server and hope there will be some
1824 1826                                   * other good ones.
1825 1827                                   */
1826 1828                                  (*new_list)->nsServers[i]->status =
1827 1829                                      INFO_SERVER_ERROR;
1828 1830                          }
1829 1831                          free(status);
1830 1832                  }
1831 1833          }
1832 1834  
1833 1835          __s_api_free2dArray(serverList);
1834 1836          free(thrPool);
1835 1837  
1836 1838          if (retCode == NS_LDAP_MEMORY) {
1837 1839                  (void) disposeOfOldList(*new_list);
1838 1840                  return (NS_LDAP_MEMORY);
1839 1841          }
1840 1842  
1841 1843          return (NS_LDAP_SUCCESS);
1842 1844  }
1843 1845  
1844 1846  /*
1845 1847   * This functions replaces the local list of root DSEs with a new one and starts
1846 1848   * a thread destroying the old list. There is no need for other threads to wait
1847 1849   * until the old list will be destroyed.
1848 1850   * Since it is possible that more than one thread can start creating the list,
1849 1851   * this function should be protected by mutexes to be sure that only one thread
1850 1852   * performs the initialization.
1851 1853   */
1852 1854  static
1853 1855  ns_ldap_return_code
1854 1856  initGlobalList(ns_ldap_error_t **error)
1855 1857  {
1856 1858          dir_server_list_t       *new_list, *old_list;
1857 1859          ns_ldap_return_code     ret_code;
1858 1860          thread_t                tid;
1859 1861  
1860 1862          ret_code = createDirServerList(&new_list, error);
1861 1863          if (ret_code != NS_LDAP_SUCCESS) {
1862 1864                  return (ret_code);
1863 1865          }
1864 1866  
1865 1867          old_list = dir_servers.list;
1866 1868          dir_servers.list = new_list;
1867 1869  
1868 1870          if (old_list) {
1869 1871                  (void) thr_create(NULL,
1870 1872                      0,
1871 1873                      disposeOfOldList,
1872 1874                      old_list,
1873 1875                      THR_DETACHED,
1874 1876                      &tid);
1875 1877          }
1876 1878  
1877 1879          return (NS_LDAP_SUCCESS);
1878 1880  }
1879 1881  
1880 1882  static
1881 1883  struct {
1882 1884          char *authMech;
1883 1885          ns_auth_t auth;
1884 1886  } authArray[] = {{"none", {NS_LDAP_AUTH_NONE,
1885 1887                          NS_LDAP_TLS_NONE,
1886 1888                          NS_LDAP_SASL_NONE,
1887 1889                          NS_LDAP_SASLOPT_NONE}},
1888 1890                  {"simple", {NS_LDAP_AUTH_SIMPLE,
1889 1891                          NS_LDAP_TLS_NONE,
1890 1892                          NS_LDAP_SASL_NONE,
1891 1893                          NS_LDAP_SASLOPT_NONE}},
1892 1894                  {"tls:simple", {NS_LDAP_AUTH_TLS,
1893 1895                          NS_LDAP_TLS_SIMPLE,
1894 1896                          NS_LDAP_SASL_NONE,
1895 1897                          NS_LDAP_SASLOPT_NONE}},
1896 1898                  {"tls:sasl/CRAM-MD5", {NS_LDAP_AUTH_TLS,
1897 1899                          NS_LDAP_TLS_SASL,
1898 1900                          NS_LDAP_SASL_CRAM_MD5,
1899 1901                          NS_LDAP_SASLOPT_NONE}},
1900 1902                  {"tls:sasl/DIGEST-MD5", {NS_LDAP_AUTH_TLS,
1901 1903                          NS_LDAP_TLS_SASL,
1902 1904                          NS_LDAP_SASL_DIGEST_MD5,
1903 1905                          NS_LDAP_SASLOPT_NONE}},
1904 1906                  {"sasl/CRAM-MD5", {NS_LDAP_AUTH_SASL,
1905 1907                          NS_LDAP_TLS_SASL,
1906 1908                          NS_LDAP_SASL_CRAM_MD5,
1907 1909                          NS_LDAP_SASLOPT_NONE}},
1908 1910                  {"sasl/DIGEST-MD5", {NS_LDAP_AUTH_SASL,
1909 1911                          NS_LDAP_TLS_SASL,
1910 1912                          NS_LDAP_SASL_DIGEST_MD5,
1911 1913                          NS_LDAP_SASLOPT_NONE}},
1912 1914                  {"sasl/GSSAPI", {NS_LDAP_AUTH_SASL,
1913 1915                          NS_LDAP_TLS_SASL,
1914 1916                          NS_LDAP_SASL_GSSAPI,
1915 1917                          NS_LDAP_SASLOPT_PRIV | NS_LDAP_SASLOPT_INT}},
1916 1918                  {NULL, {NS_LDAP_AUTH_NONE,
1917 1919                          NS_LDAP_TLS_NONE,
1918 1920                          NS_LDAP_SASL_NONE,
1919 1921                          NS_LDAP_SASLOPT_NONE}}};
1920 1922  
1921 1923  ns_ldap_return_code
1922 1924  __ns_ldap_initAuth(const char *auth_mech,
1923 1925                  ns_auth_t *auth,
1924 1926                  ns_ldap_error_t **errorp)
1925 1927  {
1926 1928          uint32_t        i;
1927 1929          char            errmsg[MAXERROR];
1928 1930  
1929 1931          if (auth_mech == NULL) {
1930 1932                  (void) snprintf(errmsg,
1931 1933                      sizeof (errmsg),
1932 1934                      gettext("Invalid authentication method specified\n"));
1933 1935                  MKERROR(LOG_WARNING,
1934 1936                      *errorp,
1935 1937                      NS_LDAP_INTERNAL,
1936 1938                      strdup(errmsg),
1937 1939                      NS_LDAP_MEMORY);
1938 1940                  return (NS_LDAP_INTERNAL);
1939 1941          }
1940 1942  
1941 1943          for (i = 0; authArray[i].authMech != NULL; ++i) {
1942 1944                  if (strcasecmp(auth_mech, authArray[i].authMech) == 0) {
1943 1945                          *auth = authArray[i].auth;
1944 1946                          return (NS_LDAP_SUCCESS);
1945 1947                  }
1946 1948          }
1947 1949  
1948 1950          (void) snprintf(errmsg,
1949 1951              sizeof (errmsg),
1950 1952              gettext("Invalid authentication method specified\n"));
1951 1953          MKERROR(LOG_WARNING,
1952 1954              *errorp,
1953 1955              NS_LDAP_INTERNAL,
1954 1956              strdup(errmsg),
1955 1957              NS_LDAP_MEMORY);
1956 1958          return (NS_LDAP_INTERNAL);
1957 1959  }
1958 1960  
1959 1961  /*
1960 1962   * This function "informs" libsldap that a client application has specified
1961 1963   * a directory to use. The function obtains a DUAProfile, credentials,
1962 1964   * and naming context. During all further operations on behalf
1963 1965   * of the application requested a standalone schema libsldap will use
1964 1966   * the information obtained by __ns_ldap_initStandalone() instead of
1965 1967   * door_call(3C)ing ldap_cachemgr(1M).
1966 1968   *
1967 1969   * INPUT:
1968 1970   *     sa_conf - a structure describing where and in which way to obtain all
1969 1971   *               the configuration describing how to communicate to
1970 1972   *               a choosen LDAP directory,
1971 1973   *     errorp - an error object describing an error occured.
1972 1974   */
1973 1975  ns_ldap_return_code
1974 1976  __ns_ldap_initStandalone(const ns_standalone_conf_t *sa_conf,
1975 1977                          ns_ldap_error_t **errorp) {
1976 1978  
1977 1979          ns_cred_t       user_cred = {{NS_LDAP_AUTH_NONE,
1978 1980                                          NS_LDAP_TLS_NONE,
1979 1981                                          NS_LDAP_SASL_NONE,
1980 1982                                          NS_LDAP_SASLOPT_NONE},
1981 1983                                          NULL,
1982 1984                                          {NULL, NULL}};
1983 1985          char            *dua_profile = NULL;
1984 1986          char            errmsg[MAXERROR];
1985 1987          ns_config_t     *cfg;
1986 1988          int             ret_code;
1987 1989  
1988 1990          if (sa_conf->SA_BIND_DN == NULL && sa_conf->SA_BIND_PWD != NULL ||
1989 1991              sa_conf->SA_BIND_DN != NULL && sa_conf->SA_BIND_PWD == NULL) {
1990 1992                  (void) snprintf(errmsg,
1991 1993                      sizeof (errmsg),
1992 1994                      gettext("Bind DN and bind password"
1993 1995                      " must both be provided\n"));
1994 1996                  MKERROR(LOG_ERR,
1995 1997                      *errorp,
1996 1998                      NS_CONFIG_NOTLOADED,
1997 1999                      strdup(errmsg),
1998 2000                      NS_LDAP_MEMORY);
1999 2001                  return (NS_LDAP_INTERNAL);
2000 2002          }
2001 2003  
2002 2004          switch (sa_conf->type) {
2003 2005          case NS_LDAP_SERVER:
2004 2006                  if (sa_conf->SA_BIND_DN != NULL) {
2005 2007                          user_cred.cred.unix_cred.userID = sa_conf->SA_BIND_DN;
2006 2008                          user_cred.auth.type = NS_LDAP_AUTH_SIMPLE;
2007 2009                  }
2008 2010  
2009 2011                  if (sa_conf->SA_BIND_PWD != NULL) {
2010 2012                          user_cred.cred.unix_cred.passwd = sa_conf->SA_BIND_PWD;
2011 2013                  }
2012 2014  
2013 2015                  if (sa_conf->SA_AUTH != NULL) {
2014 2016                          user_cred.auth.type = sa_conf->SA_AUTH->type;
2015 2017                          user_cred.auth.tlstype = sa_conf->SA_AUTH->tlstype;
2016 2018                          user_cred.auth.saslmech = sa_conf->SA_AUTH->saslmech;
2017 2019                          user_cred.auth.saslopt = sa_conf->SA_AUTH->saslopt;
2018 2020                  }
2019 2021  
2020 2022                  if (sa_conf->SA_CERT_PATH != NULL) {
2021 2023                          user_cred.hostcertpath = sa_conf->SA_CERT_PATH;
2022 2024                  }
2023 2025  
2024 2026                  ret_code = __ns_ldap_getConnectionInfoFromDUA(
2025 2027                      &sa_conf->ds_profile.server,
2026 2028                      &user_cred,
2027 2029                      &dua_profile,
2028 2030                      NULL,
2029 2031                      errorp);
2030 2032                  if (ret_code != NS_LDAP_SUCCESS) {
2031 2033                          return (ret_code);
2032 2034                  }
2033 2035  
2034 2036                  cfg = __s_api_create_config_door_str(dua_profile, errorp);
2035 2037                  if (cfg == NULL) {
2036 2038                          free(dua_profile);
2037 2039                          return (NS_LDAP_CONFIG);
2038 2040                  }
2039 2041  
2040 2042                  if (sa_conf->SA_CERT_PATH != NULL) {
2041 2043                          char            *certPathAttr;
2042 2044                          ParamIndexType  type;
2043 2045  
2044 2046                          switch (cfg->version) {
2045 2047                          case NS_LDAP_V1:
2046 2048                                  certPathAttr = "NS_LDAP_CERT_PATH";
2047 2049                                  break;
2048 2050                          default:        /* Version 2 */
2049 2051                                  certPathAttr = "NS_LDAP_HOST_CERTPATH";
2050 2052                                  break;
2051 2053                          }
2052 2054  
2053 2055                          if (__s_api_get_versiontype(cfg,
2054 2056                                                  certPathAttr,
2055 2057                                                  &type) == 0 &&
2056 2058                              (ret_code = __ns_ldap_setParamValue(cfg,
2057 2059                                                  type,
2058 2060                                                  sa_conf->SA_CERT_PATH,
2059 2061                                                  errorp)) != NS_LDAP_SUCCESS) {
2060 2062                                  __s_api_destroy_config(cfg);
2061 2063                                  return (ret_code);
2062 2064                          }
2063 2065                  }
2064 2066  
2065 2067                  if (sa_conf->SA_BIND_DN != NULL &&
2066 2068                      sa_conf->SA_BIND_PWD != NULL) {
2067 2069                          char *authMethods;
2068 2070  
2069 2071                          authMethods = __s_api_strValue(cfg, NS_LDAP_AUTH_P,
2070 2072                              NS_FILE_FMT);
2071 2073                          if (authMethods != NULL &&
2072 2074                              strstr(authMethods, "sasl/GSSAPI") != NULL) {
2073 2075                                  /*
2074 2076                                   * The received DUAProfile specifies
2075 2077                                   * sasl/GSSAPI as an auth. mechanism.
2076 2078                                   * The bind DN and password will be
2077 2079                                   * ignored.
2078 2080                                   */
2079 2081                                  syslog(LOG_INFO, gettext("sasl/GSSAPI will be "
2080 2082                                      "used as an authentication method. "
2081 2083                                      "The bind DN and password will "
2082 2084                                      "be ignored.\n"));
2083 2085                                  free(authMethods);
2084 2086                                  break;
2085 2087                          }
2086 2088  
2087 2089                          if (authMethods != NULL)
2088 2090                                  free(authMethods);
2089 2091  
2090 2092                          if (__ns_ldap_setParamValue(cfg,
2091 2093                                                  NS_LDAP_BINDDN_P,
2092 2094                                                  sa_conf->SA_BIND_DN,
2093 2095                                                  errorp) != NS_LDAP_SUCCESS) {
2094 2096                                  __s_api_destroy_config(cfg);
2095 2097                                  return (NS_LDAP_CONFIG);
2096 2098                          }
2097 2099  
2098 2100                          if (__ns_ldap_setParamValue(cfg,
2099 2101                              NS_LDAP_BINDPASSWD_P,
2100 2102                              sa_conf->SA_BIND_PWD,
2101 2103                              errorp) != NS_LDAP_SUCCESS) {
2102 2104                                  __s_api_destroy_config(cfg);
2103 2105                                  return (NS_LDAP_CONFIG);
2104 2106                          }
2105 2107                  }
2106 2108  
2107 2109                  break;
2108 2110          default:        /* NS_CACHEMGR */
2109 2111                  return (NS_LDAP_SUCCESS);
2110 2112          }
2111 2113  
2112 2114          __s_api_init_config(cfg);
2113 2115          /* Connection management should use the new config now. */
2114 2116          __s_api_reinit_conn_mgmt_new_config(cfg);
2115 2117          __ns_ldap_setServer(TRUE);
2116 2118  
2117 2119          (void) mutex_lock(&dir_servers.listReplaceLock);
2118 2120          if ((ret_code = initGlobalList(errorp)) != NS_SUCCESS) {
2119 2121                  (void) mutex_unlock(&dir_servers.listReplaceLock);
2120 2122                  return (ret_code);
2121 2123          }
2122 2124          dir_servers.standalone = 1;
2123 2125          (void) mutex_unlock(&dir_servers.listReplaceLock);
2124 2126  
2125 2127          return (NS_LDAP_SUCCESS);
2126 2128  }
2127 2129  
2128 2130  /*
2129 2131   * INPUT:
2130 2132   *     serverAddr is the address of a server and
2131 2133   *     request is one of the following:
2132 2134   *     NS_CACHE_NEW:    get a new server address, addr is ignored.
2133 2135   *     NS_CACHE_NORESP: get the next one, remove addr from list.
2134 2136   *     NS_CACHE_NEXT:   get the next one, keep addr on list.
2135 2137   *     NS_CACHE_WRITE:  get a non-replica server, if possible, if not, same
2136 2138   *                      as NS_CACHE_NEXT.
2137 2139   *     addrType:
2138 2140   *     NS_CACHE_ADDR_IP: return server address as is, this is default.
2139 2141   *     NS_CACHE_ADDR_HOSTNAME: return server addess as FQDN format, only
2140 2142   *                             self credential case requires such format.
2141 2143   * OUTPUT:
2142 2144   *     ret
2143 2145   *
2144 2146   *     a structure of type ns_server_info_t containing the server address
2145 2147   *     or name, server controls and supported SASL mechanisms.
2146 2148   *     NOTE: Caller should allocate space for the structure and free
2147 2149   *     all the space allocated by the function for the information contained
2148 2150   *     in the structure.
2149 2151   *
2150 2152   *     error - an error object describing an error, if any.
2151 2153   */
2152 2154  ns_ldap_return_code
2153 2155  __s_api_findRootDSE(const char *request,
2154 2156                  const char *serverAddr,
2155 2157                  const char *addrType,
2156 2158                  ns_server_info_t *ret,
2157 2159                  ns_ldap_error_t **error)
2158 2160  {
2159 2161          dir_server_list_t       *current_list = NULL;
2160 2162          ns_ldap_return_code     ret_code;
2161 2163          long                    i = 0;
2162 2164          int                     matched = FALSE;
2163 2165          dir_server_t            *server = NULL;
2164 2166          char                    errmsg[MAXERROR];
2165 2167  
2166 2168          (void) mutex_lock(&dir_servers.listReplaceLock);
2167 2169          if (dir_servers.list == NULL) {
2168 2170                  (void) mutex_unlock(&dir_servers.listReplaceLock);
2169 2171                  (void) snprintf(errmsg,
2170 2172                      sizeof (errmsg),
2171 2173                      gettext("The list of root DSEs is empty: "
2172 2174                      "the Standalone mode was not properly initialized"));
2173 2175                  MKERROR(LOG_ERR,
2174 2176                      *error,
2175 2177                      NS_CONFIG_NOTLOADED,
2176 2178                      strdup(errmsg),
2177 2179                      NS_LDAP_MEMORY);
2178 2180                  return (NS_LDAP_INTERNAL);
2179 2181          }
2180 2182  
2181 2183          current_list = dir_servers.list;
2182 2184          (void) rw_rdlock(¤t_list->listDestroyLock);
2183 2185          (void) mutex_unlock(&dir_servers.listReplaceLock);
2184 2186  
2185 2187          /*
2186 2188           * The code below is mostly the clone of the
2187 2189           * ldap_cachemgr::cachemgr_getldap.c::getldap_get_serverInfo() function.
2188 2190           * Currently we have two different server lists: one is maintained
2189 2191           * by libsldap ('standalone' mode), the other is in ldap_cachemgr
2190 2192           * (a part of its standard functionality).
2191 2193           */
2192 2194  
2193 2195          /*
2194 2196           * If NS_CACHE_NEW, or the server info is new,
2195 2197           * starts from the beginning of the list.
2196 2198           */
2197 2199          (void) mutex_lock(¤t_list->nsServers[0]->updateStatus);
2198 2200          if (strcmp(request, NS_CACHE_NEW) == 0 ||
2199 2201              current_list->nsServers[0]->info == INFO_STATUS_NEW) {
2200 2202                  matched = TRUE;
2201 2203          }
2202 2204          (void) mutex_unlock(¤t_list->nsServers[i]->updateStatus);
2203 2205  
2204 2206          for (i = 0; current_list->nsServers[i]; ++i) {
2205 2207                  /*
2206 2208                   * Lock the updateStatus mutex to
2207 2209                   * make sure the server status stays the same
2208 2210                   * while the data is being processed.
2209 2211                   */
2210 2212                  if (matched == FALSE &&
2211 2213                      strcmp(current_list->nsServers[i]->ip,
2212 2214                      serverAddr) == 0) {
2213 2215                          matched = TRUE;
2214 2216                          if (strcmp(request, NS_CACHE_NORESP) == 0) {
2215 2217  
2216 2218                                  /*
2217 2219                                   * if the server has already been removed,
2218 2220                                   * don't bother.
2219 2221                                   */
2220 2222                                  (void) mutex_lock(¤t_list->
2221 2223                                      nsServers[i]->updateStatus);
2222 2224                                  if (current_list->nsServers[i]->status ==
2223 2225                                      INFO_SERVER_REMOVED) {
2224 2226                                          (void) mutex_unlock(¤t_list->
2225 2227                                              nsServers[i]->
2226 2228                                              updateStatus);
2227 2229                                          continue;
2228 2230                                  }
2229 2231                                  (void) mutex_unlock(¤t_list->
2230 2232                                      nsServers[i]->
2231 2233                                      updateStatus);
2232 2234  
2233 2235                                  /*
2234 2236                                   * if the information is new,
2235 2237                                   * give this server one more chance.
2236 2238                                   */
2237 2239                                  (void) mutex_lock(¤t_list->
2238 2240                                      nsServers[i]->
2239 2241                                      updateStatus);
2240 2242                                  if (current_list->nsServers[i]->info ==
2241 2243                                      INFO_STATUS_NEW &&
2242 2244                                      current_list->nsServers[i]->status  ==
2243 2245                                      INFO_SERVER_UP) {
2244 2246                                          server = current_list->nsServers[i];
2245 2247                                          (void) mutex_unlock(¤t_list->
2246 2248                                              nsServers[i]->
2247 2249                                              updateStatus);
2248 2250                                          break;
2249 2251                                  } else {
2250 2252                                          /*
2251 2253                                           * it is recommended that
2252 2254                                           * before removing the
2253 2255                                           * server from the list,
2254 2256                                           * the server should be
2255 2257                                           * contacted one more time
2256 2258                                           * to make sure that it is
2257 2259                                           * really unavailable.
2258 2260                                           * For now, just trust the client
2259 2261                                           * (i.e., the sldap library)
2260 2262                                           * that it knows what it is
2261 2263                                           * doing and would not try
2262 2264                                           * to mess up the server
2263 2265                                           * list.
2264 2266                                           */
2265 2267                                          current_list->nsServers[i]->status =
2266 2268                                              INFO_SERVER_REMOVED;
2267 2269                                          (void) mutex_unlock(¤t_list->
2268 2270                                              nsServers[i]->
2269 2271                                              updateStatus);
2270 2272                                          continue;
2271 2273                                  }
2272 2274                          } else {
2273 2275                                  /*
2274 2276                                   * req == NS_CACHE_NEXT or NS_CACHE_WRITE
2275 2277                                   */
2276 2278                                  continue;
2277 2279                          }
2278 2280                  }
2279 2281  
2280 2282                  if (matched) {
2281 2283                          if (strcmp(request, NS_CACHE_WRITE) == 0) {
2282 2284                                  /*
2283 2285                                   * ldap_cachemgr checks here if the server
2284 2286                                   * is not a non-replica server (a server
2285 2287                                   * of type INFO_RW_WRITEABLE). But currently
2286 2288                                   * it considers all the servers in its list
2287 2289                                   * as those.
2288 2290                                   */
2289 2291                                  (void) mutex_lock(¤t_list->
2290 2292                                      nsServers[i]->
2291 2293                                      updateStatus);
2292 2294                                  if (current_list->nsServers[i]->status  ==
2293 2295                                      INFO_SERVER_UP) {
2294 2296                                          (void) mutex_unlock(¤t_list->
2295 2297                                              nsServers[i]->
2296 2298                                              updateStatus);
2297 2299                                          server = current_list->nsServers[i];
2298 2300                                          break;
2299 2301                                  }
2300 2302                          } else {
2301 2303                                  (void) mutex_lock(¤t_list->
2302 2304                                      nsServers[i]->
2303 2305                                      updateStatus);
2304 2306                                  if (current_list->nsServers[i]->status ==
2305 2307                                      INFO_SERVER_UP) {
2306 2308                                          (void) mutex_unlock(¤t_list->
2307 2309                                              nsServers[i]->
2308 2310                                              updateStatus);
2309 2311                                          server = current_list->nsServers[i];
2310 2312                                          break;
2311 2313                                  }
2312 2314                          }
2313 2315  
2314 2316                          (void) mutex_unlock(¤t_list->
2315 2317                              nsServers[i]->
2316 2318                              updateStatus);
2317 2319                  }
2318 2320          }
2319 2321  
2320 2322          if (server == NULL) {
2321 2323                  (void) rw_unlock(¤t_list->listDestroyLock);
2322 2324                  (void) snprintf(errmsg,
2323 2325                      sizeof (errmsg),
2324 2326                      gettext("No servers are available"));
2325 2327                  MKERROR(LOG_ERR,
2326 2328                      *error,
2327 2329                      NS_CONFIG_NOTLOADED,
2328 2330                      strdup(errmsg),
2329 2331                      NS_LDAP_MEMORY);
2330 2332                  return (NS_LDAP_NOTFOUND);
2331 2333          }
2332 2334  
2333 2335          (void) mutex_lock(&server->updateStatus);
2334 2336          server->info = INFO_STATUS_OLD;
2335 2337          (void) mutex_unlock(&server->updateStatus);
2336 2338  
2337 2339          if (ret == NULL) {
2338 2340                  (void) rw_unlock(¤t_list->listDestroyLock);
2339 2341                  return (NS_LDAP_SUCCESS);
2340 2342          }
2341 2343  
2342 2344          if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
2343 2345                  ret_code = __s_api_ip2hostname(server->ip, &ret->serverFQDN);
2344 2346                  if (ret_code != NS_LDAP_SUCCESS) {
2345 2347                          (void) snprintf(errmsg,
2346 2348                              sizeof (errmsg),
2347 2349                              gettext("The %s address "
2348 2350                              "can not be resolved into "
2349 2351                              "a host name. Returning "
2350 2352                              "the address as it is."),
2351 2353                              server->ip);
2352 2354                          MKERROR(LOG_ERR,
2353 2355                              *error,
2354 2356                              NS_CONFIG_NOTLOADED,
2355 2357                              strdup(errmsg),
2356 2358                              NS_LDAP_MEMORY);
2357 2359                          return (NS_LDAP_INTERNAL);
2358 2360                  }
2359 2361          }
2360 2362  
2361 2363          ret->server = strdup(server->ip);
2362 2364  
2363 2365          ret->controls = __s_api_cp2dArray(server->controls);
2364 2366          ret->saslMechanisms = __s_api_cp2dArray(server->saslMech);
2365 2367  
2366 2368          (void) rw_unlock(¤t_list->listDestroyLock);
2367 2369  
2368 2370          return (NS_LDAP_SUCCESS);
2369 2371  }
2370 2372  
2371 2373  /*
2372 2374   * This function iterates through the list of the configured LDAP servers
2373 2375   * and "pings" those which are marked as removed or if any error occurred
2374 2376   * during the previous receiving of the server's root DSE. If the
2375 2377   * function is able to reach such a server and get its root DSE, it
2376 2378   * marks the server as on-line. Otherwise, the server's status is set
2377 2379   * to "Error".
2378 2380   * For each server the function tries to connect to, it fires up
2379 2381   * a separate thread and then waits until all the treads finish.
2380 2382   * The function returns NS_LDAP_INTERNAL if the Standalone mode was not
2381 2383   * initialized or was canceled prior to an invocation of
2382 2384   * __ns_ldap_pingOfflineServers().
2383 2385   */
2384 2386  ns_ldap_return_code
2385 2387  __ns_ldap_pingOfflineServers(void)
2386 2388  {
2387 2389          dir_server_list_t       *current_list = NULL;
2388 2390          ns_ldap_return_code     retCode = NS_LDAP_SUCCESS;
2389 2391          long                    srvListLength, i = 0;
2390 2392          thread_t                *thrPool, thrID;
2391 2393          void                    *status = NULL;
2392 2394  
2393 2395          (void) mutex_lock(&dir_servers.listReplaceLock);
2394 2396          if (dir_servers.list == NULL) {
2395 2397                  (void) mutex_unlock(&dir_servers.listReplaceLock);
2396 2398                  return (NS_LDAP_INTERNAL);
2397 2399          }
2398 2400  
2399 2401          current_list = dir_servers.list;
2400 2402          (void) rw_wrlock(¤t_list->listDestroyLock);
2401 2403          (void) mutex_unlock(&dir_servers.listReplaceLock);
2402 2404  
2403 2405          while (current_list->nsServers[i] != NULL) {
2404 2406                  ++i;
2405 2407          }
2406 2408          srvListLength = i;
2407 2409  
2408 2410          thrPool = calloc(srvListLength, sizeof (thread_t));
2409 2411          if (thrPool == NULL) {
2410 2412                  (void) rw_unlock(¤t_list->listDestroyLock);
2411 2413                  return (NS_LDAP_MEMORY);
2412 2414          }
2413 2415  
2414 2416          for (i = 0; i < srvListLength; ++i) {
2415 2417                  if (current_list->nsServers[i]->status != INFO_SERVER_REMOVED &&
2416 2418                      current_list->nsServers[i]->status != INFO_SERVER_ERROR) {
2417 2419                          continue;
2418 2420                  }
2419 2421                  current_list->nsServers[i]->status = INFO_SERVER_CONNECTING;
2420 2422                  current_list->nsServers[i]->info = INFO_STATUS_NEW;
2421 2423  
2422 2424                  __s_api_free2dArray(current_list->nsServers[i]->controls);
2423 2425                  current_list->nsServers[i]->controls = NULL;
2424 2426                  __s_api_free2dArray(current_list->nsServers[i]->saslMech);
2425 2427                  current_list->nsServers[i]->saslMech = NULL;
2426 2428  
2427 2429                  switch (thr_create(NULL,
2428 2430                      0,
2429 2431                      create_ns_servers_entry,
2430 2432                      current_list->nsServers[i],
2431 2433                      0,
2432 2434                      &thrID)) {
2433 2435                  case EAGAIN:
2434 2436                          current_list->nsServers[i]->status = INFO_SERVER_ERROR;
2435 2437                          continue;
2436 2438                  case ENOMEM:
2437 2439                          current_list->nsServers[i]->status = INFO_SERVER_ERROR;
2438 2440                          retCode = NS_LDAP_MEMORY;
2439 2441                          break;
2440 2442                  default:
2441 2443                          thrPool[i] = thrID;
2442 2444                          continue;
2443 2445                  }
2444 2446                  /* A memory allocation error has occured */
2445 2447                  break;
2446 2448  
2447 2449          }
2448 2450  
2449 2451          for (i = 0; i < srvListLength; ++i) {
2450 2452                  if (thrPool[i] != 0 &&
2451 2453                      thr_join(thrPool[i], NULL, &status) == 0) {
2452 2454                          if (status == NULL) {
2453 2455                                  current_list->nsServers[i]->status =
2454 2456                                      INFO_SERVER_ERROR;
2455 2457                                  retCode = NS_LDAP_MEMORY;
2456 2458                          }
2457 2459                          free(status);
2458 2460                  }
2459 2461          }
2460 2462  
2461 2463          (void) rw_unlock(¤t_list->listDestroyLock);
2462 2464  
2463 2465          free(thrPool);
2464 2466  
2465 2467          return (retCode);
2466 2468  }
  
    | ↓ open down ↓ | 1004 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX