Print this page
    
3285 memory leaks in libsldap
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libsldap/common/ns_connect.c
          +++ new/usr/src/lib/libsldap/common/ns_connect.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
  
    | ↓ open down ↓ | 13 lines elided | ↑ open up ↑ | 
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  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  /*
  23   23   * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  #include <stdlib.h>
  27   28  #include <stdio.h>
  28   29  #include <errno.h>
  29   30  #include <string.h>
  30   31  #include <synch.h>
  31   32  #include <time.h>
  32   33  #include <libintl.h>
  33   34  #include <thread.h>
  34   35  #include <syslog.h>
  35   36  #include <sys/mman.h>
  36   37  #include <nsswitch.h>
  37   38  #include <nss_dbdefs.h>
  38   39  #include "solaris-priv.h"
  39   40  #include "solaris-int.h"
  40   41  #include "ns_sldap.h"
  41   42  #include "ns_internal.h"
  42   43  #include "ns_cache_door.h"
  43   44  #include "ns_connmgmt.h"
  44   45  #include "ldappr.h"
  45   46  #include <sys/stat.h>
  46   47  #include <fcntl.h>
  47   48  #include <procfs.h>
  48   49  #include <unistd.h>
  49   50  
  50   51  #define USE_DEFAULT_PORT 0
  51   52  
  52   53  static ns_ldap_return_code performBind(const ns_cred_t *,
  53   54                                          LDAP *,
  54   55                                          int,
  55   56                                          ns_ldap_error_t **,
  56   57                                          int,
  57   58                                          int);
  58   59  static ns_ldap_return_code createSession(const ns_cred_t *,
  59   60                                          const char *,
  60   61                                          uint16_t,
  61   62                                          int,
  62   63                                          LDAP **,
  63   64                                          ns_ldap_error_t **);
  64   65  
  65   66  extern int ldap_sasl_cram_md5_bind_s(LDAP *, char *, struct berval *,
  66   67                  LDAPControl **, LDAPControl **);
  67   68  extern int ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip);
  68   69  
  69   70  extern int __door_getconf(char **buffer, int *buflen,
  70   71                  ns_ldap_error_t **error, int callnumber);
  71   72  extern int __ns_ldap_freeUnixCred(UnixCred_t **credp);
  72   73  extern int SetDoorInfoToUnixCred(char *buffer,
  73   74                  ns_ldap_error_t **errorp,
  74   75                  UnixCred_t **cred);
  75   76  
  76   77  static int openConnection(LDAP **, const char *, const ns_cred_t *,
  77   78                  int, ns_ldap_error_t **, int, int, ns_conn_user_t *, int);
  78   79  static void
  79   80  _DropConnection(ConnectionID cID, int flag, int fini);
  80   81  
  81   82  static mutex_t sessionPoolLock = DEFAULTMUTEX;
  82   83  
  83   84  static Connection **sessionPool = NULL;
  84   85  static int sessionPoolSize = 0;
  85   86  
  86   87  /*
  87   88   * SSF values are for SASL integrity & privacy.
  88   89   * JES DS5.2 does not support this feature but DS6 does.
  89   90   * The values between 0 and 65535 can work with both server versions.
  90   91   */
  91   92  #define MAX_SASL_SSF    65535
  92   93  #define MIN_SASL_SSF    0
  93   94  
  94   95  /* Number of hostnames to allocate memory for */
  95   96  #define NUMTOMALLOC     32
  96   97  
  97   98  /*
  98   99   * This function get the servers from the lists and returns
  99  100   * the first server with the empty lists of server controls and
 100  101   * SASL mechanisms. It is invoked if it is not possible to obtain a server
 101  102   * from ldap_cachemgr or the local list.
 102  103   */
 103  104  static
 104  105  ns_ldap_return_code
 105  106  getFirstFromConfig(ns_server_info_t *ret, ns_ldap_error_t **error)
 106  107  {
 107  108          char                    **servers = NULL;
 108  109          ns_ldap_return_code     ret_code;
 109  110          char                    errstr[MAXERROR];
 110  111  
 111  112          /* get first server from config list unavailable otherwise */
 112  113          ret_code = __s_api_getServers(&servers, error);
 113  114          if (ret_code != NS_LDAP_SUCCESS) {
 114  115                  if (servers != NULL) {
 115  116                          __s_api_free2dArray(servers);
 116  117                  }
 117  118                  return (ret_code);
 118  119          }
 119  120  
 120  121          if (servers == NULL || servers[0] == NULL) {
 121  122                  __s_api_free2dArray(servers);
 122  123                  (void) sprintf(errstr,
 123  124                      gettext("No server found in configuration"));
 124  125                  MKERROR(LOG_ERR, *error, NS_CONFIG_NODEFAULT,
 125  126                      strdup(errstr), NS_LDAP_MEMORY);
 126  127                  return (NS_LDAP_CONFIG);
 127  128          }
 128  129  
 129  130          ret->server = strdup(servers[0]);
 130  131          if (ret->server == NULL) {
 131  132                  __s_api_free2dArray(servers);
 132  133                  return (NS_LDAP_MEMORY);
 133  134          }
 134  135  
 135  136          ret->saslMechanisms = NULL;
 136  137          ret->controls = NULL;
 137  138  
 138  139          __s_api_free2dArray(servers);
 139  140  
 140  141          return (NS_LDAP_SUCCESS);
 141  142  }
 142  143  
 143  144  /* very similar to __door_getldapconfig() in ns_config.c */
 144  145  static int
 145  146  __door_getadmincred(char **buffer, int *buflen, ns_ldap_error_t **error)
 146  147  {
 147  148          return (__door_getconf(buffer, buflen, error, GETADMINCRED));
 148  149  }
 149  150  
 150  151  /*
 151  152   * This function requests Admin credentials from the cache manager through
 152  153   * the door functionality
 153  154   */
 154  155  
 155  156  static int
 156  157  requestAdminCred(UnixCred_t **cred, ns_ldap_error_t **error)
 157  158  {
 158  159          char    *buffer = NULL;
 159  160          int     buflen = 0;
 160  161          int     ret;
 161  162  
 162  163          *error = NULL;
 163  164          ret = __door_getadmincred(&buffer, &buflen, error);
 164  165  
 165  166          if (ret != NS_LDAP_SUCCESS) {
 166  167                  if (*error != NULL && (*error)->message != NULL)
 167  168                          syslog(LOG_WARNING, "libsldap: %s", (*error)->message);
 168  169                  return (ret);
 169  170          }
 170  171  
 171  172          /* now convert from door format */
 172  173          ret = SetDoorInfoToUnixCred(buffer, error, cred);
 173  174          free(buffer);
 174  175  
 175  176          return (ret);
 176  177  }
 177  178  
 178  179  /*
 179  180   * This function requests a server from the cache manager through
 180  181   * the door functionality
 181  182   */
 182  183  
 183  184  int
 184  185  __s_api_requestServer(const char *request, const char *server,
 185  186          ns_server_info_t *ret, ns_ldap_error_t **error,  const char *addrType)
 186  187  {
 187  188          union {
 188  189                  ldap_data_t     s_d;
 189  190                  char            s_b[DOORBUFFERSIZE];
 190  191          } space;
 191  192          ldap_data_t             *sptr;
 192  193          int                     ndata;
 193  194          int                     adata;
 194  195          char                    errstr[MAXERROR];
 195  196          const char              *ireq;
 196  197          char                    *rbuf, *ptr, *rest;
 197  198          char                    *dptr;
 198  199          char                    **mptr, **mptr1, **cptr, **cptr1;
 199  200          int                     mcnt, ccnt;
 200  201          int                     len;
 201  202          ns_ldap_return_code     ret_code;
 202  203  
 203  204          if (ret == NULL || error == NULL) {
 204  205                  return (NS_LDAP_OP_FAILED);
 205  206          }
 206  207          (void) memset(ret, 0, sizeof (ns_server_info_t));
 207  208          *error = NULL;
 208  209  
 209  210          if (request == NULL)
 210  211                  ireq = NS_CACHE_NEW;
 211  212          else
 212  213                  ireq = request;
 213  214  
 214  215          /*
 215  216           * In the 'Standalone' mode a server will be obtained
 216  217           * from the local libsldap's list
 217  218           */
 218  219          if (__s_api_isStandalone()) {
 219  220                  if ((ret_code = __s_api_findRootDSE(ireq,
 220  221                      server,
 221  222                      addrType,
 222  223                      ret,
 223  224                      error)) != NS_LDAP_SUCCESS) {
 224  225                          /*
 225  226                           * get first server from local list only once
 226  227                           * to prevent looping
 227  228                           */
 228  229                          if (strcmp(ireq, NS_CACHE_NEW) != 0)
 229  230                                  return (ret_code);
 230  231  
 231  232                          syslog(LOG_WARNING,
 232  233                              "libsldap (\"standalone\" mode): "
 233  234                              "can not find any available server. "
 234  235                              "Return the first one from the lists");
 235  236                          if (*error != NULL) {
 236  237                                  (void) __ns_ldap_freeError(error);
 237  238                          }
 238  239  
 239  240                          ret_code = getFirstFromConfig(ret, error);
 240  241                          if (ret_code != NS_LDAP_SUCCESS) {
 241  242                                  return (ret_code);
 242  243                          }
 243  244  
 244  245                          if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
 245  246                                  ret_code = __s_api_ip2hostname(ret->server,
 246  247                                      &ret->serverFQDN);
 247  248                                  if (ret_code != NS_LDAP_SUCCESS) {
 248  249                                          (void) snprintf(errstr,
 249  250                                              sizeof (errstr),
 250  251                                              gettext("The %s address "
 251  252                                              "can not be resolved into "
 252  253                                              "a host name. Returning "
 253  254                                              "the address as it is."),
 254  255                                              ret->server);
 255  256                                          MKERROR(LOG_ERR,
 256  257                                              *error,
 257  258                                              NS_CONFIG_NOTLOADED,
 258  259                                              strdup(errstr),
 259  260                                              NS_LDAP_MEMORY);
 260  261                                          free(ret->server);
 261  262                                          ret->server = NULL;
 262  263                                          return (NS_LDAP_INTERNAL);
 263  264                                  }
 264  265                          }
 265  266                  }
 266  267  
 267  268                  return (NS_LDAP_SUCCESS);
 268  269          }
 269  270  
 270  271          (void) memset(space.s_b, 0, DOORBUFFERSIZE);
 271  272  
 272  273          adata = (sizeof (ldap_call_t) + strlen(ireq) + strlen(addrType) + 1);
 273  274          if (server != NULL) {
 274  275                  adata += strlen(DOORLINESEP) + 1;
 275  276                  adata += strlen(server) + 1;
 276  277          }
 277  278          ndata = sizeof (space);
 278  279          len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
 279  280          space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
 280  281          if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
 281  282                  return (NS_LDAP_MEMORY);
 282  283          if (strlcat(space.s_d.ldap_call.ldap_u.domainname, addrType, len) >=
 283  284              len)
 284  285                  return (NS_LDAP_MEMORY);
 285  286          if (server != NULL) {
 286  287                  if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
 287  288                      DOORLINESEP, len) >= len)
 288  289                          return (NS_LDAP_MEMORY);
 289  290                  if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server,
 290  291                      len) >= len)
 291  292                          return (NS_LDAP_MEMORY);
 292  293          }
 293  294          sptr = &space.s_d;
 294  295  
 295  296          switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
 296  297          case NS_CACHE_SUCCESS:
 297  298                  break;
 298  299          /* this case is for when the $mgr is not running, but ldapclient */
 299  300          /* is trying to initialize things */
 300  301          case NS_CACHE_NOSERVER:
 301  302                  ret_code = getFirstFromConfig(ret, error);
 302  303                  if (ret_code != NS_LDAP_SUCCESS) {
 303  304                          return (ret_code);
 304  305                  }
 305  306  
 306  307                  if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
 307  308                          ret_code = __s_api_ip2hostname(ret->server,
 308  309                              &ret->serverFQDN);
 309  310                          if (ret_code != NS_LDAP_SUCCESS) {
 310  311                                  (void) snprintf(errstr,
 311  312                                      sizeof (errstr),
 312  313                                      gettext("The %s address "
 313  314                                      "can not be resolved into "
 314  315                                      "a host name. Returning "
 315  316                                      "the address as it is."),
 316  317                                      ret->server);
 317  318                                  MKERROR(LOG_ERR,
 318  319                                      *error,
 319  320                                      NS_CONFIG_NOTLOADED,
 320  321                                      strdup(errstr),
 321  322                                      NS_LDAP_MEMORY);
 322  323                                  free(ret->server);
 323  324                                  ret->server = NULL;
 324  325                                  return (NS_LDAP_INTERNAL);
 325  326                          }
 326  327                  }
 327  328                  return (NS_LDAP_SUCCESS);
 328  329          case NS_CACHE_NOTFOUND:
 329  330          default:
 330  331                  return (NS_LDAP_OP_FAILED);
 331  332          }
 332  333  
 333  334          /* copy info from door call return structure here */
 334  335          rbuf =  space.s_d.ldap_ret.ldap_u.config;
 335  336  
 336  337          /* Get the host */
 337  338          ptr = strtok_r(rbuf, DOORLINESEP, &rest);
 338  339          if (ptr == NULL) {
 339  340                  (void) sprintf(errstr, gettext("No server returned from "
 340  341                      "ldap_cachemgr"));
 341  342                  MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
 342  343                      strdup(errstr), NS_LDAP_MEMORY);
 343  344                  return (NS_LDAP_OP_FAILED);
 344  345          }
 345  346          ret->server = strdup(ptr);
 346  347          if (ret->server == NULL) {
 347  348                  return (NS_LDAP_MEMORY);
 348  349          }
 349  350          /* Get the host FQDN format */
 350  351          if (strcmp(addrType, NS_CACHE_ADDR_HOSTNAME) == 0) {
 351  352                  ptr = strtok_r(NULL, DOORLINESEP, &rest);
 352  353                  if (ptr == NULL) {
 353  354                          (void) sprintf(errstr, gettext("No server FQDN format "
 354  355                              "returned from ldap_cachemgr"));
 355  356                          MKERROR(LOG_WARNING, *error, NS_CONFIG_CACHEMGR,
 356  357                              strdup(errstr), NULL);
 357  358                          free(ret->server);
 358  359                          ret->server = NULL;
 359  360                          return (NS_LDAP_OP_FAILED);
 360  361                  }
 361  362                  ret->serverFQDN = strdup(ptr);
 362  363                  if (ret->serverFQDN == NULL) {
 363  364                          free(ret->server);
 364  365                          ret->server = NULL;
 365  366                          return (NS_LDAP_MEMORY);
 366  367                  }
 367  368          }
 368  369  
 369  370          /* get the Supported Controls/SASL mechs */
 370  371          mptr = NULL;
 371  372          mcnt = 0;
 372  373          cptr = NULL;
 373  374          ccnt = 0;
 374  375          for (;;) {
 375  376                  ptr = strtok_r(NULL, DOORLINESEP, &rest);
 376  377                  if (ptr == NULL)
 377  378                          break;
 378  379                  if (strncasecmp(ptr, _SASLMECHANISM,
 379  380                      _SASLMECHANISM_LEN) == 0) {
 380  381                          dptr = strchr(ptr, '=');
 381  382                          if (dptr == NULL)
 382  383                                  continue;
 383  384                          dptr++;
 384  385                          mptr1 = (char **)realloc((void *)mptr,
 385  386                              sizeof (char *) * (mcnt+2));
 386  387                          if (mptr1 == NULL) {
 387  388                                  __s_api_free2dArray(mptr);
 388  389                                  if (sptr != &space.s_d) {
 389  390                                          (void) munmap((char *)sptr, ndata);
 390  391                                  }
 391  392                                  __s_api_free2dArray(cptr);
 392  393                                  __s_api_free_server_info(ret);
 393  394                                  return (NS_LDAP_MEMORY);
 394  395                          }
 395  396                          mptr = mptr1;
 396  397                          mptr[mcnt] = strdup(dptr);
 397  398                          if (mptr[mcnt] == NULL) {
 398  399                                  if (sptr != &space.s_d) {
 399  400                                          (void) munmap((char *)sptr, ndata);
 400  401                                  }
 401  402                                  __s_api_free2dArray(cptr);
 402  403                                  cptr = NULL;
 403  404                                  __s_api_free2dArray(mptr);
 404  405                                  mptr = NULL;
 405  406                                  __s_api_free_server_info(ret);
 406  407                                  return (NS_LDAP_MEMORY);
 407  408                          }
 408  409                          mcnt++;
 409  410                          mptr[mcnt] = NULL;
 410  411                  }
 411  412                  if (strncasecmp(ptr, _SUPPORTEDCONTROL,
 412  413                      _SUPPORTEDCONTROL_LEN) == 0) {
 413  414                          dptr = strchr(ptr, '=');
 414  415                          if (dptr == NULL)
 415  416                                  continue;
 416  417                          dptr++;
 417  418                          cptr1 = (char **)realloc((void *)cptr,
 418  419                              sizeof (char *) * (ccnt+2));
 419  420                          if (cptr1 == NULL) {
 420  421                                  if (sptr != &space.s_d) {
 421  422                                          (void) munmap((char *)sptr, ndata);
 422  423                                  }
 423  424                                  __s_api_free2dArray(cptr);
 424  425                                  __s_api_free2dArray(mptr);
 425  426                                  mptr = NULL;
 426  427                                  __s_api_free_server_info(ret);
 427  428                                  return (NS_LDAP_MEMORY);
 428  429                          }
 429  430                          cptr = cptr1;
 430  431                          cptr[ccnt] = strdup(dptr);
 431  432                          if (cptr[ccnt] == NULL) {
 432  433                                  if (sptr != &space.s_d) {
 433  434                                          (void) munmap((char *)sptr, ndata);
 434  435                                  }
 435  436                                  __s_api_free2dArray(cptr);
 436  437                                  cptr = NULL;
 437  438                                  __s_api_free2dArray(mptr);
 438  439                                  mptr = NULL;
 439  440                                  __s_api_free_server_info(ret);
 440  441                                  return (NS_LDAP_MEMORY);
 441  442                          }
 442  443                          ccnt++;
 443  444                          cptr[ccnt] = NULL;
 444  445                  }
 445  446          }
 446  447          if (mptr != NULL) {
 447  448                  ret->saslMechanisms = mptr;
 448  449          }
 449  450          if (cptr != NULL) {
 450  451                  ret->controls = cptr;
 451  452          }
 452  453  
 453  454  
 454  455          /* clean up door call */
 455  456          if (sptr != &space.s_d) {
 456  457                  (void) munmap((char *)sptr, ndata);
 457  458          }
 458  459          *error = NULL;
 459  460  
 460  461          return (NS_LDAP_SUCCESS);
 461  462  }
 462  463  
 463  464  
 464  465  #ifdef DEBUG
 465  466  /*
 466  467   * printCred(): prints the credential structure
 467  468   */
  
    | ↓ open down ↓ | 434 lines elided | ↑ open up ↑ | 
 468  469  static void
 469  470  printCred(FILE *fp, const ns_cred_t *cred)
 470  471  {
 471  472          thread_t        t = thr_self();
 472  473  
 473  474          if (cred == NULL) {
 474  475                  (void) fprintf(fp, "tid= %d: printCred: cred is NULL\n", t);
 475  476                  return;
 476  477          }
 477  478  
 478      -        (void) fprintf(fp, "tid= %d: AuthType=%d", t, cred->auth.type);
 479      -        (void) fprintf(fp, "tid= %d: TlsType=%d", t, cred->auth.tlstype);
 480      -        (void) fprintf(fp, "tid= %d: SaslMech=%d", t, cred->auth.saslmech);
 481      -        (void) fprintf(fp, "tid= %d: SaslOpt=%d", t, cred->auth.saslopt);
      479 +        (void) fprintf(fp, "tid= %d: AuthType=%d\n", t, cred->auth.type);
      480 +        (void) fprintf(fp, "tid= %d: TlsType=%d\n", t, cred->auth.tlstype);
      481 +        (void) fprintf(fp, "tid= %d: SaslMech=%d\n", t, cred->auth.saslmech);
      482 +        (void) fprintf(fp, "tid= %d: SaslOpt=%d\n", t, cred->auth.saslopt);
 482  483          if (cred->hostcertpath)
 483  484                  (void) fprintf(fp, "tid= %d: hostCertPath=%s\n",
 484  485                      t, cred->hostcertpath);
 485  486          if (cred->cred.unix_cred.userID)
 486  487                  (void) fprintf(fp, "tid= %d: userID=%s\n",
 487  488                      t, cred->cred.unix_cred.userID);
 488  489          if (cred->cred.unix_cred.passwd)
 489  490                  (void) fprintf(fp, "tid= %d: passwd=%s\n",
 490  491                      t, cred->cred.unix_cred.passwd);
 491  492  }
 492  493  
 493  494  /*
 494  495   * printConnection(): prints the connection structure
 495  496   */
 496  497  static void
 497  498  printConnection(FILE *fp, Connection *con)
 498  499  {
 499  500          thread_t        t = thr_self();
 500  501  
 501  502          if (con == NULL)
 502  503                  return;
 503  504  
 504  505          (void) fprintf(fp, "tid= %d: connectionID=%d\n", t, con->connectionId);
 505  506          (void) fprintf(fp, "tid= %d: usedBit=%d\n", t, con->usedBit);
 506  507          (void) fprintf(fp, "tid= %d: threadID=%d\n", t, con->threadID);
 507  508          if (con->serverAddr) {
 508  509                  (void) fprintf(fp, "tid= %d: serverAddr=%s\n",
 509  510                      t, con->serverAddr);
 510  511          }
 511  512          printCred(fp, con->auth);
 512  513  }
 513  514  #endif
 514  515  
 515  516  /*
 516  517   * addConnection(): inserts a connection in the connection list.
 517  518   * It will also sets use bit and the thread Id for the thread
 518  519   * using the connection for the first time.
 519  520   * Returns: -1 = failure, new Connection ID = success
 520  521   */
 521  522  static int
 522  523  addConnection(Connection *con)
 523  524  {
 524  525          int i;
 525  526  
 526  527          if (!con)
 527  528                  return (-1);
 528  529  #ifdef DEBUG
 529  530          (void) fprintf(stderr, "Adding connection thrid=%d\n", con->threadID);
 530  531  #endif /* DEBUG */
 531  532          (void) mutex_lock(&sessionPoolLock);
 532  533          if (sessionPool == NULL) {
 533  534                  sessionPoolSize = SESSION_CACHE_INC;
 534  535                  sessionPool = calloc(sessionPoolSize,
 535  536                      sizeof (Connection *));
 536  537                  if (!sessionPool) {
 537  538                          (void) mutex_unlock(&sessionPoolLock);
 538  539                          return (-1);
 539  540                  }
 540  541  #ifdef DEBUG
 541  542                  (void) fprintf(stderr, "Initialized sessionPool\n");
 542  543  #endif /* DEBUG */
 543  544          }
 544  545          for (i = 0; (i < sessionPoolSize) && (sessionPool[i] != NULL); ++i)
 545  546                  ;
 546  547          if (i == sessionPoolSize) {
 547  548                  /* run out of array, need to increase sessionPool */
 548  549                  Connection **cl;
 549  550                  cl = (Connection **) realloc(sessionPool,
 550  551                      (sessionPoolSize + SESSION_CACHE_INC) *
 551  552                      sizeof (Connection *));
 552  553                  if (!cl) {
 553  554                          (void) mutex_unlock(&sessionPoolLock);
 554  555                          return (-1);
 555  556                  }
 556  557                  (void) memset(cl + sessionPoolSize, 0,
 557  558                      SESSION_CACHE_INC * sizeof (Connection *));
 558  559                  sessionPool = cl;
 559  560                  sessionPoolSize += SESSION_CACHE_INC;
 560  561  #ifdef DEBUG
 561  562                  (void) fprintf(stderr, "Increased sessionPoolSize to: %d\n",
 562  563                      sessionPoolSize);
 563  564  #endif /* DEBUG */
 564  565          }
 565  566          sessionPool[i] = con;
 566  567          con->usedBit = B_TRUE;
 567  568          (void) mutex_unlock(&sessionPoolLock);
 568  569          con->connectionId = i + CONID_OFFSET;
 569  570  #ifdef DEBUG
 570  571          (void) fprintf(stderr, "Connection added [%d]\n", i);
 571  572          printConnection(stderr, con);
 572  573  #endif /* DEBUG */
 573  574          return (i + CONID_OFFSET);
 574  575  }
 575  576  
 576  577  /*
 577  578   * findConnection(): find an available connection from the list
 578  579   * that matches the criteria specified in Connection structure.
 579  580   * If serverAddr is NULL, then find a connection to any server
 580  581   * as long as it matches the rest of the parameters.
 581  582   * Returns: -1 = failure, the Connection ID found = success.
 582  583   */
 583  584  static int
 584  585  findConnection(int flags, const char *serverAddr,
 585  586          const ns_cred_t *auth, Connection **conp)
 586  587  {
 587  588          Connection *cp;
 588  589          int i;
 589  590  #ifdef DEBUG
 590  591          thread_t t;
 591  592  #endif /* DEBUG */
 592  593  
 593  594          if (auth == NULL || conp == NULL)
 594  595                  return (-1);
 595  596          *conp = NULL;
 596  597  
 597  598          /*
 598  599           * If a new connection is requested, no need to continue.
 599  600           * If the process is not nscd and is not requesting keep
 600  601           * connections alive, no need to continue.
 601  602           */
 602  603          if ((flags & NS_LDAP_NEW_CONN) || (!__s_api_nscd_proc() &&
 603  604              !__s_api_peruser_proc() && !(flags & NS_LDAP_KEEP_CONN)))
 604  605                  return (-1);
 605  606  
 606  607  #ifdef DEBUG
 607  608          t = thr_self();
 608  609          (void) fprintf(stderr, "tid= %d: Find connection\n", t);
 609  610          (void) fprintf(stderr, "tid= %d: Looking for ....\n", t);
 610  611          if (serverAddr && *serverAddr)
 611  612                  (void) fprintf(stderr, "tid= %d: serverAddr=%s\n",
 612  613                      t, serverAddr);
 613  614          else
 614  615                  (void) fprintf(stderr, "tid= %d: serverAddr=NULL\n", t);
 615  616          printCred(stderr, auth);
 616  617          fflush(stderr);
 617  618  #endif /* DEBUG */
 618  619          if (sessionPool == NULL)
 619  620                  return (-1);
 620  621          (void) mutex_lock(&sessionPoolLock);
 621  622          for (i = 0; i < sessionPoolSize; ++i) {
 622  623                  if (sessionPool[i] == NULL)
 623  624                          continue;
 624  625                  cp = sessionPool[i];
 625  626  #ifdef DEBUG
 626  627                  (void) fprintf(stderr,
 627  628                      "tid: %d: checking connection [%d] ....\n", t, i);
 628  629                  printConnection(stderr, cp);
 629  630  #endif /* DEBUG */
 630  631                  if ((cp->usedBit) || (serverAddr && *serverAddr &&
 631  632                      (strcasecmp(serverAddr, cp->serverAddr) != 0)))
 632  633                          continue;
 633  634  
 634  635                  if (__s_api_is_auth_matched(cp->auth, auth) == B_FALSE)
 635  636                          continue;
 636  637  
 637  638                  /* found an available connection */
 638  639                  cp->usedBit = B_TRUE;
 639  640                  (void) mutex_unlock(&sessionPoolLock);
 640  641                  cp->threadID = thr_self();
 641  642                  *conp = cp;
 642  643  #ifdef DEBUG
 643  644                  (void) fprintf(stderr,
 644  645                      "tid %d: Connection found cID=%d\n", t, i);
 645  646                  fflush(stderr);
 646  647  #endif /* DEBUG */
 647  648                  return (i + CONID_OFFSET);
 648  649          }
 649  650          (void) mutex_unlock(&sessionPoolLock);
 650  651          return (-1);
 651  652  }
 652  653  
 653  654  /*
 654  655   * Free a Connection structure
 655  656   */
 656  657  void
 657  658  __s_api_freeConnection(Connection *con)
 658  659  {
 659  660          if (con == NULL)
 660  661                  return;
 661  662          if (con->serverAddr)
 662  663                  free(con->serverAddr);
 663  664          if (con->auth)
 664  665                  (void) __ns_ldap_freeCred(&(con->auth));
 665  666          if (con->saslMechanisms) {
 666  667                  __s_api_free2dArray(con->saslMechanisms);
 667  668          }
 668  669          if (con->controls) {
 669  670                  __s_api_free2dArray(con->controls);
 670  671          }
 671  672          free(con);
 672  673  }
 673  674  
 674  675  /*
 675  676   * Find a connection matching the passed in criteria.  If an open
 676  677   * connection with that criteria exists use it, otherwise open a
 677  678   * new connection.
 678  679   * Success: returns the pointer to the Connection structure
 679  680   * Failure: returns NULL, error code and message should be in errorp
 680  681   */
 681  682  
 682  683  static int
 683  684  makeConnection(Connection **conp, const char *serverAddr,
 684  685          const ns_cred_t *auth, ConnectionID *cID, int timeoutSec,
 685  686          ns_ldap_error_t **errorp, int fail_if_new_pwd_reqd,
 686  687          int nopasswd_acct_mgmt, int flags, char ***badsrvrs,
 687  688          ns_conn_user_t *conn_user)
 688  689  {
 689  690          Connection *con = NULL;
 690  691          ConnectionID id;
 691  692          char errmsg[MAXERROR];
 692  693          int rc, exit_rc = NS_LDAP_SUCCESS;
 693  694          ns_server_info_t sinfo;
  
    | ↓ open down ↓ | 202 lines elided | ↑ open up ↑ | 
 694  695          char *hReq, *host = NULL;
 695  696          LDAP *ld = NULL;
 696  697          int passwd_mgmt = 0;
 697  698          int totalbad = 0; /* Number of servers contacted unsuccessfully */
 698  699          short   memerr = 0; /* Variable for tracking memory allocation */
 699  700          char *serverAddrType = NULL, **bindHost = NULL;
 700  701  
 701  702  
 702  703          if (conp == NULL || errorp == NULL || auth == NULL)
 703  704                  return (NS_LDAP_INVALID_PARAM);
 704      -        *errorp = NULL;
      705 +        if (*errorp)
      706 +                __ns_ldap_freeError(errorp);
 705  707          *conp = NULL;
 706  708          (void) memset(&sinfo, 0, sizeof (sinfo));
 707  709  
 708  710          if ((id = findConnection(flags, serverAddr, auth, &con)) != -1) {
 709  711                  /* connection found in cache */
 710  712  #ifdef DEBUG
 711  713                  (void) fprintf(stderr, "tid= %d: connection found in "
 712  714                      "cache %d\n", thr_self(), id);
 713  715                  fflush(stderr);
 714  716  #endif /* DEBUG */
 715  717                  *cID = id;
 716  718                  *conp = con;
 717  719                  return (NS_LDAP_SUCCESS);
 718  720          }
 719  721  
 720  722          if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
 721  723                  serverAddrType = NS_CACHE_ADDR_HOSTNAME;
 722  724                  bindHost = &sinfo.serverFQDN;
 723  725          } else {
 724  726                  serverAddrType = NS_CACHE_ADDR_IP;
 725  727                  bindHost = &sinfo.server;
 726  728          }
 727  729  
 728  730          if (serverAddr) {
 729  731                  if (__s_api_isInitializing()) {
 730  732                          /*
 731  733                           * When obtaining the root DSE, connect to the server
 732  734                           * passed here through the serverAddr parameter
 733  735                           */
 734  736                          sinfo.server = strdup(serverAddr);
 735  737                          if (sinfo.server == NULL)
 736  738                                  return (NS_LDAP_MEMORY);
 737  739                          if (strcmp(serverAddrType,
 738  740                              NS_CACHE_ADDR_HOSTNAME) == 0) {
 739  741                                  rc = __s_api_ip2hostname(sinfo.server,
 740  742                                      &sinfo.serverFQDN);
 741  743                                  if (rc != NS_LDAP_SUCCESS) {
 742  744                                          (void) snprintf(errmsg,
 743  745                                              sizeof (errmsg),
 744  746                                              gettext("The %s address "
 745  747                                              "can not be resolved into "
 746  748                                              "a host name. Returning "
 747  749                                              "the address as it is."),
 748  750                                              serverAddr);
 749  751                                          MKERROR(LOG_ERR,
 750  752                                              *errorp,
 751  753                                              NS_CONFIG_NOTLOADED,
 752  754                                              strdup(errmsg),
 753  755                                              NS_LDAP_MEMORY);
 754  756                                          __s_api_free_server_info(&sinfo);
 755  757                                          return (NS_LDAP_INTERNAL);
 756  758                                  }
 757  759                          }
 758  760                  } else {
 759  761                          /*
 760  762                           * We're given the server address, just use it.
 761  763                           * In case of sasl/GSSAPI, serverAddr would need
 762  764                           * to be a FQDN.  We assume this is the case for now.
 763  765                           *
 764  766                           * Only the server address fields of sinfo structure
 765  767                           * are filled in since these are the only relevant
 766  768                           * data that we have. Other fields of this structure
 767  769                           * (controls, saslMechanisms) are kept to NULL.
 768  770                           */
 769  771                          sinfo.server = strdup(serverAddr);
 770  772                          if (sinfo.server == NULL)  {
 771  773                                  return (NS_LDAP_MEMORY);
 772  774                          }
 773  775                          if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
 774  776                                  sinfo.serverFQDN = strdup(serverAddr);
 775  777                                  if (sinfo.serverFQDN == NULL) {
 776  778                                          free(sinfo.server);
 777  779                                          return (NS_LDAP_MEMORY);
 778  780                                  }
 779  781                          }
 780  782                  }
 781  783                  rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
 782  784                      fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
 783  785                  if (rc == NS_LDAP_SUCCESS || rc ==
 784  786                      NS_LDAP_SUCCESS_WITH_INFO) {
 785  787                          exit_rc = rc;
 786  788                          goto create_con;
 787  789                  } else {
 788  790                          if (auth->auth.saslmech == NS_LDAP_SASL_GSSAPI) {
 789  791                                  (void) snprintf(errmsg, sizeof (errmsg),
 790  792                                      "%s %s", gettext("makeConnection: "
 791  793                                      "failed to open connection using "
 792  794                                      "sasl/GSSAPI to"), *bindHost);
 793  795                          } else {
 794  796                                  (void) snprintf(errmsg, sizeof (errmsg),
 795  797                                      "%s %s", gettext("makeConnection: "
 796  798                                      "failed to open connection to"),
 797  799                                      *bindHost);
 798  800                          }
 799  801                          syslog(LOG_ERR, "libsldap: %s", errmsg);
 800  802                          __s_api_free_server_info(&sinfo);
 801  803                          return (rc);
 802  804                  }
 803  805          }
 804  806  
 805  807          /* No cached connection, create one */
 806  808          for (; ; ) {
 807  809                  if (host == NULL)
 808  810                          hReq = NS_CACHE_NEW;
 809  811                  else
 810  812                          hReq = NS_CACHE_NEXT;
 811  813                  rc = __s_api_requestServer(hReq, host, &sinfo, errorp,
 812  814                      serverAddrType);
 813  815                  if ((rc != NS_LDAP_SUCCESS) || (sinfo.server == NULL) ||
 814  816                      (host && (strcasecmp(host, sinfo.server) == 0))) {
 815  817                          /* Log the error */
 816  818                          if (*errorp) {
 817  819                                  (void) snprintf(errmsg, sizeof (errmsg),
 818  820                                  "%s: (%s)", gettext("makeConnection: "
 819  821                                  "unable to make LDAP connection, "
 820  822                                  "request for a server failed"),
 821  823                                      (*errorp)->message);
 822  824                                  syslog(LOG_ERR, "libsldap: %s", errmsg);
 823  825                          }
 824  826  
 825  827                          __s_api_free_server_info(&sinfo);
 826  828                          if (host)
 827  829                                  free(host);
 828  830                          return (NS_LDAP_OP_FAILED);
 829  831                  }
 830  832                  if (host)
 831  833                          free(host);
 832  834                  host = strdup(sinfo.server);
 833  835                  if (host == NULL) {
 834  836                          __s_api_free_server_info(&sinfo);
 835  837                          return (NS_LDAP_MEMORY);
 836  838                  }
 837  839  
 838  840                  /* check if server supports password management */
 839  841                  passwd_mgmt = __s_api_contain_passwd_control_oid(
 840  842                      sinfo.controls);
 841  843                  /* check if server supports password less account mgmt */
 842  844                  if (nopasswd_acct_mgmt &&
 843  845                      !__s_api_contain_account_usable_control_oid(
 844  846                      sinfo.controls)) {
 845  847                          syslog(LOG_WARNING, "libsldap: server %s does not "
 846  848                              "provide account information without password",
 847  849                              host);
 848  850                          free(host);
 849  851                          __s_api_free_server_info(&sinfo);
 850  852                          return (NS_LDAP_OP_FAILED);
 851  853                  }
 852  854                  /* make the connection */
 853  855                  rc = openConnection(&ld, *bindHost, auth, timeoutSec, errorp,
 854  856                      fail_if_new_pwd_reqd, passwd_mgmt, conn_user, flags);
 855  857                  /* if success, go to create connection structure */
 856  858                  if (rc == NS_LDAP_SUCCESS ||
 857  859                      rc == NS_LDAP_SUCCESS_WITH_INFO) {
 858  860                          exit_rc = rc;
 859  861                          break;
 860  862                  }
 861  863  
 862  864                  /*
 863  865                   * If not able to reach the server, inform the ldap
 864  866                   * cache manager that the server should be removed
 865  867                   * from its server list. Thus, the manager will not
 866  868                   * return this server on the next get-server request
 867  869                   * and will also reduce the server list refresh TTL,
 868  870                   * so that it will find out sooner when the server
 869  871                   * is up again.
 870  872                   */
 871  873                  if (rc == NS_LDAP_INTERNAL && *errorp != NULL) {
 872  874                          if ((*errorp)->status == LDAP_CONNECT_ERROR ||
 873  875                              (*errorp)->status == LDAP_SERVER_DOWN) {
 874  876                                  /* Reset memory allocation error */
 875  877                                  memerr = 0;
 876  878                                  /*
 877  879                                   * We contacted a server that we could
 878  880                                   * not either authenticate to or contact.
 879  881                                   * If it is due to authentication, then
 880  882                                   * we need to try the server again. So,
 881  883                                   * do not remove the server yet, but
 882  884                                   * add it to the bad server list.
 883  885                                   * The caller routine will remove
 884  886                                   * the servers if:
 885  887                                   *      a). A good server is found or
 886  888                                   *      b). All the possible methods
 887  889                                   *          are tried without finding
 888  890                                   *          a good server
 889  891                                   */
 890  892                                  if (*badsrvrs == NULL) {
 891  893                                          if (!(*badsrvrs = (char **)malloc
 892  894                                              (sizeof (char *) * NUMTOMALLOC))) {
 893  895                                                  memerr = 1;
 894  896                                          }
 895  897                                  /* Allocate memory in chunks of NUMTOMALLOC */
 896  898                                  } else if ((totalbad % NUMTOMALLOC) ==
 897  899                                      NUMTOMALLOC - 1) {
 898  900                                          char **tmpptr;
 899  901                                          if (!(tmpptr = (char **)realloc(
 900  902                                              *badsrvrs,
 901  903                                              (sizeof (char *) * NUMTOMALLOC *
 902  904                                              ((totalbad/NUMTOMALLOC) + 2))))) {
 903  905                                                  memerr = 1;
 904  906                                          } else {
 905  907                                                  *badsrvrs = tmpptr;
 906  908                                          }
 907  909                                  }
 908  910                                  /*
 909  911                                   * Store host only if there were no unsuccessful
 910  912                                   * memory allocations above
 911  913                                   */
 912  914                                  if (!memerr &&
 913  915                                      !((*badsrvrs)[totalbad++] = strdup(host))) {
 914  916                                          memerr = 1;
 915  917                                          totalbad--;
 916  918                                  }
 917  919                                  (*badsrvrs)[totalbad] = NULL;
 918  920                          }
 919  921                  }
 920  922  
 921  923                  /* else, cleanup and go for the next server */
 922  924                  __s_api_free_server_info(&sinfo);
 923  925  
 924  926                  /* Return if we had memory allocation errors */
 925  927                  if (memerr)
 926  928                          return (NS_LDAP_MEMORY);
 927  929                  if (*errorp) {
 928  930                          /*
 929  931                           * If openConnection() failed due to
 930  932                           * password policy, or invalid credential,
 931  933                           * keep *errorp and exit
 932  934                           */
 933  935                          if ((*errorp)->pwd_mgmt.status != NS_PASSWD_GOOD ||
 934  936                              (*errorp)->status == LDAP_INVALID_CREDENTIALS) {
 935  937                                  free(host);
 936  938                                  return (rc);
 937  939                          } else {
 938  940                                  (void) __ns_ldap_freeError(errorp);
 939  941                                  *errorp = NULL;
 940  942                          }
 941  943                  }
 942  944          }
 943  945  
 944  946  create_con:
 945  947          /* we have created ld, setup con structure */
 946  948          if (host)
 947  949                  free(host);
 948  950          if ((con = calloc(1, sizeof (Connection))) == NULL) {
 949  951                  __s_api_free_server_info(&sinfo);
 950  952                  /*
 951  953                   * If password control attached in **errorp,
 952  954                   * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
 953  955                   * free the error structure
 954  956                   */
 955  957                  if (*errorp) {
 956  958                          (void) __ns_ldap_freeError(errorp);
 957  959                          *errorp = NULL;
 958  960                  }
 959  961                  (void) ldap_unbind(ld);
 960  962                  return (NS_LDAP_MEMORY);
 961  963          }
 962  964  
 963  965          con->serverAddr = sinfo.server; /* Store original format */
 964  966          if (sinfo.serverFQDN != NULL) {
 965  967                  free(sinfo.serverFQDN);
 966  968                  sinfo.serverFQDN = NULL;
 967  969          }
 968  970          con->saslMechanisms = sinfo.saslMechanisms;
 969  971          con->controls = sinfo.controls;
 970  972  
 971  973          con->auth = __ns_ldap_dupAuth(auth);
 972  974          if (con->auth == NULL) {
 973  975                  (void) ldap_unbind(ld);
 974  976                  __s_api_freeConnection(con);
 975  977                  /*
 976  978                   * If password control attached in **errorp,
 977  979                   * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
 978  980                   * free the error structure
 979  981                   */
 980  982                  if (*errorp) {
 981  983                          (void) __ns_ldap_freeError(errorp);
 982  984                          *errorp = NULL;
 983  985                  }
 984  986                  return (NS_LDAP_MEMORY);
 985  987          }
 986  988  
 987  989          con->threadID = thr_self();
 988  990          con->pid = getpid();
 989  991  
 990  992          con->ld = ld;
 991  993          /* add MT connection to the MT connection pool */
 992  994          if (conn_user != NULL && conn_user->conn_mt != NULL) {
 993  995                  if (__s_api_conn_mt_add(con, conn_user, errorp) ==
 994  996                      NS_LDAP_SUCCESS) {
 995  997                          *conp = con;
 996  998                          return (exit_rc);
 997  999                  } else {
 998 1000                          (void) ldap_unbind(ld);
 999 1001                          __s_api_freeConnection(con);
1000 1002                          return ((*errorp)->status);
1001 1003                  }
1002 1004          }
1003 1005  
1004 1006          /* MT connection not supported or not required case */
1005 1007          if ((id = addConnection(con)) == -1) {
1006 1008                  (void) ldap_unbind(ld);
1007 1009                  __s_api_freeConnection(con);
1008 1010                  /*
1009 1011                   * If password control attached in **errorp,
1010 1012                   * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1011 1013                   * free the error structure
1012 1014                   */
1013 1015                  if (*errorp) {
1014 1016                          (void) __ns_ldap_freeError(errorp);
1015 1017                          *errorp = NULL;
1016 1018                  }
1017 1019                  return (NS_LDAP_MEMORY);
1018 1020          }
1019 1021  #ifdef DEBUG
1020 1022          (void) fprintf(stderr, "tid= %d: connection added into "
1021 1023              "cache %d\n", thr_self(), id);
1022 1024          fflush(stderr);
1023 1025  #endif /* DEBUG */
1024 1026          *cID = id;
1025 1027          *conp = con;
1026 1028          return (exit_rc);
1027 1029  }
1028 1030  
1029 1031  /*
1030 1032   * Return the specified connection to the pool.  If necessary
1031 1033   * delete the connection.
1032 1034   */
1033 1035  
1034 1036  static void
1035 1037  _DropConnection(ConnectionID cID, int flag, int fini)
1036 1038  {
1037 1039          Connection *cp;
1038 1040          int id;
1039 1041          int use_mutex = !fini;
1040 1042          struct timeval  zerotime;
1041 1043          LDAPMessage     *res;
1042 1044  
1043 1045          zerotime.tv_sec = zerotime.tv_usec = 0L;
1044 1046  
1045 1047          id = cID - CONID_OFFSET;
1046 1048          if (id < 0 || id >= sessionPoolSize)
1047 1049                  return;
1048 1050  #ifdef DEBUG
1049 1051          (void) fprintf(stderr,
1050 1052              "tid %d: Dropping connection cID=%d flag=0x%x\n",
1051 1053              thr_self(), cID, flag);
1052 1054          fflush(stderr);
1053 1055  #endif /* DEBUG */
1054 1056          if (use_mutex)
1055 1057                  (void) mutex_lock(&sessionPoolLock);
1056 1058  
1057 1059          cp = sessionPool[id];
1058 1060          /* sanity check before removing */
1059 1061          if (!cp || (!fini && (!cp->usedBit || cp->threadID != thr_self()))) {
1060 1062                  if (use_mutex)
1061 1063                          (void) mutex_unlock(&sessionPoolLock);
1062 1064                  return;
1063 1065          }
1064 1066  
1065 1067          if (!fini &&
1066 1068              ((flag & NS_LDAP_NEW_CONN) == 0) &&
1067 1069              ((flag & NS_LDAP_KEEP_CONN) || __s_api_nscd_proc() ||
1068 1070              __s_api_peruser_proc())) {
1069 1071                  /* release Connection (keep alive) */
1070 1072                  cp->usedBit = B_FALSE;
1071 1073                  cp->threadID = 0;       /* unmark the threadID */
1072 1074                  /*
1073 1075                   * Do sanity cleanup of remaining results.
1074 1076                   */
1075 1077                  while (ldap_result(cp->ld, LDAP_RES_ANY, LDAP_MSG_ALL,
1076 1078                      &zerotime, &res) > 0) {
1077 1079                          if (res != NULL)
1078 1080                                  (void) ldap_msgfree(res);
1079 1081                  }
1080 1082                  if (use_mutex)
1081 1083                          (void) mutex_unlock(&sessionPoolLock);
1082 1084          } else {
1083 1085                  /* delete Connection (disconnect) */
1084 1086                  sessionPool[id] = NULL;
1085 1087                  if (use_mutex)
1086 1088                          (void) mutex_unlock(&sessionPoolLock);
1087 1089                  (void) ldap_unbind(cp->ld);
1088 1090                  __s_api_freeConnection(cp);
1089 1091          }
1090 1092  }
1091 1093  
1092 1094  void
1093 1095  DropConnection(ConnectionID cID, int flag)
1094 1096  {
1095 1097          _DropConnection(cID, flag, 0);
1096 1098  }
1097 1099  
1098 1100  /*
1099 1101   * This routine is called after a bind operation is
1100 1102   * done in openConnection() to process the password
1101 1103   * management information, if any.
1102 1104   *
1103 1105   * Input:
1104 1106   *   bind_type: "simple" or "sasl/DIGEST-MD5"
1105 1107   *   ldaprc   : ldap rc from the ldap bind operation
1106 1108   *   controls : controls returned by the server
1107 1109   *   errmsg   : error message from the server
1108 1110   *   fail_if_new_pwd_reqd:
1109 1111   *              flag indicating if connection should be open
1110 1112   *              when password needs to change immediately
1111 1113   *   passwd_mgmt:
1112 1114   *              flag indicating if server supports password
1113 1115   *              policy/management
1114 1116   *
1115 1117   * Output     : ns_ldap_error structure, which may contain
1116 1118   *              password status and number of seconds until
1117 1119   *              expired
1118 1120   *
1119 1121   * return rc:
1120 1122   * NS_LDAP_EXTERNAL: error, connection should not open
1121 1123   * NS_LDAP_SUCCESS_WITH_INFO: OK to open but password info attached
1122 1124   * NS_LDAP_SUCCESS: OK to open connection
1123 1125   *
1124 1126   */
1125 1127  
1126 1128  static int
1127 1129  process_pwd_mgmt(char *bind_type, int ldaprc,
1128 1130                  LDAPControl **controls,
1129 1131                  char *errmsg, ns_ldap_error_t **errorp,
1130 1132                  int fail_if_new_pwd_reqd,
1131 1133                  int passwd_mgmt)
1132 1134  {
1133 1135          char            errstr[MAXERROR];
1134 1136          LDAPControl     **ctrl = NULL;
1135 1137          int             exit_rc;
1136 1138          ns_ldap_passwd_status_t pwd_status = NS_PASSWD_GOOD;
1137 1139          int             sec_until_exp = 0;
1138 1140  
1139 1141          /*
1140 1142           * errmsg may be an empty string,
1141 1143           * even if ldaprc is LDAP_SUCCESS,
1142 1144           * free the empty string if that's the case
1143 1145           */
1144 1146          if (errmsg &&
1145 1147              (*errmsg == '\0' || ldaprc == LDAP_SUCCESS)) {
1146 1148                  ldap_memfree(errmsg);
1147 1149                  errmsg = NULL;
1148 1150          }
1149 1151  
1150 1152          if (ldaprc != LDAP_SUCCESS) {
1151 1153                  /*
1152 1154                   * try to map ldap rc and error message to
1153 1155                   * a password status
1154 1156                   */
1155 1157                  if (errmsg) {
1156 1158                          if (passwd_mgmt)
1157 1159                                  pwd_status =
1158 1160                                      __s_api_set_passwd_status(
1159 1161                                      ldaprc, errmsg);
1160 1162                          ldap_memfree(errmsg);
1161 1163                  }
1162 1164  
1163 1165                  (void) snprintf(errstr, sizeof (errstr),
1164 1166                      gettext("openConnection: "
1165 1167                      "%s bind failed "
1166 1168                      "- %s"), bind_type, ldap_err2string(ldaprc));
1167 1169  
1168 1170                  if (pwd_status != NS_PASSWD_GOOD) {
1169 1171                          MKERROR_PWD_MGMT(*errorp,
1170 1172                              ldaprc, strdup(errstr),
1171 1173                              pwd_status, 0, NULL);
1172 1174                  } else {
1173 1175                          MKERROR(LOG_ERR, *errorp, ldaprc, strdup(errstr),
1174 1176                              NS_LDAP_MEMORY);
1175 1177                  }
1176 1178                  if (controls)
1177 1179                          ldap_controls_free(controls);
1178 1180  
1179 1181                  return (NS_LDAP_INTERNAL);
1180 1182          }
1181 1183  
1182 1184          /*
1183 1185           * ldaprc is LDAP_SUCCESS,
1184 1186           * process the password management controls, if any
1185 1187           */
1186 1188          exit_rc = NS_LDAP_SUCCESS;
1187 1189          if (controls && passwd_mgmt) {
1188 1190                  /*
1189 1191                   * The control with the OID
1190 1192                   * 2.16.840.1.113730.3.4.4 (or
1191 1193                   * LDAP_CONTROL_PWEXPIRED, as defined
1192 1194                   * in the ldap.h header file) is the
1193 1195                   * expired password control.
1194 1196                   *
1195 1197                   * This control is used if the server
1196 1198                   * is configured to require users to
1197 1199                   * change their passwords when first
1198 1200                   * logging in and whenever the
1199 1201                   * passwords are reset.
1200 1202                   *
1201 1203                   * If the user is logging in for the
1202 1204                   * first time or if the user's
1203 1205                   * password has been reset, the
1204 1206                   * server sends this control to
1205 1207                   * indicate that the client needs to
1206 1208                   * change the password immediately.
1207 1209                   *
1208 1210                   * At this point, the only operation
1209 1211                   * that the client can perform is to
1210 1212                   * change the user's password. If the
1211 1213                   * client requests any other LDAP
1212 1214                   * operation, the server sends back
1213 1215                   * an LDAP_UNWILLING_TO_PERFORM
1214 1216                   * result code with an expired
1215 1217                   * password control.
1216 1218                   *
1217 1219                   * The control with the OID
1218 1220                   * 2.16.840.1.113730.3.4.5 (or
1219 1221                   * LDAP_CONTROL_PWEXPIRING, as
1220 1222                   * defined in the ldap.h header file)
1221 1223                   * is the password expiration warning
1222 1224                   * control.
1223 1225                   *
1224 1226                   * This control is used if the server
1225 1227                   * is configured to expire user
1226 1228                   * passwords after a certain amount
1227 1229                   * of time.
1228 1230                   *
1229 1231                   * The server sends this control back
1230 1232                   * to the client if the client binds
1231 1233                   * using a password that will soon
1232 1234                   * expire.  The ldctl_value field of
1233 1235                   * the LDAPControl structure
1234 1236                   * specifies the number of seconds
1235 1237                   * before the password will expire.
1236 1238                   */
1237 1239                  for (ctrl = controls; *ctrl; ctrl++) {
1238 1240  
1239 1241                          if (strcmp((*ctrl)->ldctl_oid,
1240 1242                              LDAP_CONTROL_PWEXPIRED) == 0) {
1241 1243                                  /*
1242 1244                                   * if the caller wants this bind
1243 1245                                   * to fail, set up the error info.
1244 1246                                   * If call to this function is
1245 1247                                   * for searching the LDAP directory,
1246 1248                                   * e.g., __ns_ldap_list(),
1247 1249                                   * there's really no sense to
1248 1250                                   * let a connection open and
1249 1251                                   * then fail immediately afterward
1250 1252                                   * on the LDAP search operation with
1251 1253                                   * the LDAP_UNWILLING_TO_PERFORM rc
1252 1254                                   */
1253 1255                                  pwd_status =
1254 1256                                      NS_PASSWD_CHANGE_NEEDED;
1255 1257                                  if (fail_if_new_pwd_reqd) {
1256 1258                                          (void) snprintf(errstr,
1257 1259                                              sizeof (errstr),
1258 1260                                              gettext(
1259 1261                                              "openConnection: "
1260 1262                                              "%s bind "
1261 1263                                              "failed "
1262 1264                                              "- password "
1263 1265                                              "expired. It "
1264 1266                                              " needs to change "
1265 1267                                              "immediately!"),
1266 1268                                              bind_type);
1267 1269                                          MKERROR_PWD_MGMT(*errorp,
1268 1270                                              LDAP_SUCCESS,
1269 1271                                              strdup(errstr),
1270 1272                                              pwd_status,
1271 1273                                              0,
1272 1274                                              NULL);
1273 1275                                          exit_rc = NS_LDAP_INTERNAL;
1274 1276                                  } else {
1275 1277                                          MKERROR_PWD_MGMT(*errorp,
1276 1278                                              LDAP_SUCCESS,
1277 1279                                              NULL,
1278 1280                                              pwd_status,
1279 1281                                              0,
1280 1282                                              NULL);
1281 1283                                          exit_rc =
1282 1284                                              NS_LDAP_SUCCESS_WITH_INFO;
1283 1285                                  }
1284 1286                                  break;
1285 1287                          } else if (strcmp((*ctrl)->ldctl_oid,
1286 1288                              LDAP_CONTROL_PWEXPIRING) == 0) {
1287 1289                                  pwd_status =
1288 1290                                      NS_PASSWD_ABOUT_TO_EXPIRE;
1289 1291                                  if ((*ctrl)->
1290 1292                                      ldctl_value.bv_len > 0 &&
1291 1293                                      (*ctrl)->
1292 1294                                      ldctl_value.bv_val)
1293 1295                                          sec_until_exp =
1294 1296                                              atoi((*ctrl)->
1295 1297                                              ldctl_value.bv_val);
1296 1298                                  MKERROR_PWD_MGMT(*errorp,
1297 1299                                      LDAP_SUCCESS,
1298 1300                                      NULL,
1299 1301                                      pwd_status,
1300 1302                                      sec_until_exp,
1301 1303                                      NULL);
1302 1304                                  exit_rc =
1303 1305                                      NS_LDAP_SUCCESS_WITH_INFO;
1304 1306                                  break;
1305 1307                          }
1306 1308                  }
1307 1309          }
1308 1310  
1309 1311          if (controls)
1310 1312                  ldap_controls_free(controls);
1311 1313  
1312 1314          return (exit_rc);
1313 1315  }
1314 1316  
1315 1317  static int
1316 1318  ldap_in_nss_switch(char *db)
1317 1319  {
1318 1320          enum __nsw_parse_err            pserr;
1319 1321          struct __nsw_switchconfig       *conf;
1320 1322          struct __nsw_lookup             *lkp;
1321 1323          const char                      *name;
1322 1324          int                             found = 0;
1323 1325  
1324 1326          conf = __nsw_getconfig(db, &pserr);
1325 1327          if (conf == NULL) {
1326 1328                  return (-1);
1327 1329          }
1328 1330  
1329 1331          /* check for skip and count other backends */
1330 1332          for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) {
1331 1333                  name = lkp->service_name;
1332 1334                  if (strcmp(name, "ldap") == 0) {
1333 1335                          found = 1;
1334 1336                          break;
1335 1337                  }
1336 1338          }
1337 1339          (void) __nsw_freeconfig(conf);
1338 1340          return (found);
1339 1341  }
1340 1342  
1341 1343  static int
1342 1344  openConnection(LDAP **ldp, const char *serverAddr, const ns_cred_t *auth,
1343 1345          int timeoutSec, ns_ldap_error_t **errorp,
1344 1346          int fail_if_new_pwd_reqd, int passwd_mgmt,
1345 1347          ns_conn_user_t *conn_user, int flags)
1346 1348  {
1347 1349          LDAP                    *ld = NULL;
1348 1350          int                     ldapVersion = LDAP_VERSION3;
1349 1351          int                     derefOption = LDAP_DEREF_ALWAYS;
1350 1352          int                     zero = 0;
1351 1353          int                     timeoutMilliSec = timeoutSec * 1000;
1352 1354          uint16_t                port = USE_DEFAULT_PORT;
1353 1355          char                    *s;
1354 1356          char                    errstr[MAXERROR];
1355 1357          int                     followRef;
1356 1358  
1357 1359          ns_ldap_return_code     ret_code = NS_LDAP_SUCCESS;
1358 1360  
1359 1361          *errorp = NULL;
1360 1362          *ldp = NULL;
1361 1363  
1362 1364          /* determine if the host name contains a port number */
1363 1365          s = strchr(serverAddr, ']');    /* skip over ipv6 addr */
1364 1366          s = strchr(s != NULL ? s : serverAddr, ':');
1365 1367          if (s != NULL) {
1366 1368                  if (sscanf(s + 1, "%hu", &port) != 1) {
1367 1369                          (void) snprintf(errstr,
1368 1370                              sizeof (errstr),
1369 1371                              gettext("openConnection: cannot "
1370 1372                              "convert %s into a valid "
1371 1373                              "port number for the "
1372 1374                              "%s server. A default value "
1373 1375                              "will be used."),
1374 1376                              s,
1375 1377                              serverAddr);
1376 1378                          syslog(LOG_ERR, "libsldap: %s", errstr);
1377 1379                  } else {
1378 1380                          *s = '\0';
1379 1381                  }
1380 1382          }
1381 1383  
1382 1384          ret_code = createSession(auth,
1383 1385              serverAddr,
1384 1386              port,
1385 1387              timeoutMilliSec,
1386 1388              &ld,
1387 1389              errorp);
1388 1390          if (s != NULL) {
1389 1391                  *s = ':';
1390 1392          }
1391 1393          if (ret_code != NS_LDAP_SUCCESS) {
1392 1394                  return (ret_code);
1393 1395          }
1394 1396  
1395 1397          /* check to see if the underlying libsldap supports MT connection */
1396 1398          if (conn_user != NULL) {
1397 1399                  int rc;
1398 1400  
1399 1401                  rc = __s_api_check_libldap_MT_conn_support(conn_user, ld,
1400 1402                      errorp);
1401 1403                  if (rc != NS_LDAP_SUCCESS) {
1402 1404                          (void) ldap_unbind(ld);
1403 1405                          return (rc);
1404 1406                  }
1405 1407          }
1406 1408  
1407 1409          (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
1408 1410          (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
1409 1411          /*
1410 1412           * This library will handle the referral itself based on API flags or
1411 1413           * configuration file specification. The LDAP bind operation is an
1412 1414           * exception where we rely on the LDAP library to follow the referal.
1413 1415           *
1414 1416           * The LDAP follow referral option must be set to OFF for the libldap5
1415 1417           * to pass the referral info up to this library. This option MUST be
1416 1418           * set to OFF after we have performed a sucessful bind. If we are not
1417 1419           * to follow referrals we MUST also set the LDAP follow referral option
1418 1420           * to OFF before we perform an LDAP bind.
1419 1421           */
1420 1422          ret_code = __s_api_toFollowReferrals(flags, &followRef, errorp);
1421 1423          if (ret_code != NS_LDAP_SUCCESS) {
1422 1424                  (void) ldap_unbind(ld);
1423 1425                  return (ret_code);
1424 1426          }
1425 1427  
1426 1428          if (followRef)
1427 1429                  (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
1428 1430          else
1429 1431                  (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1430 1432  
1431 1433          (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
1432 1434          (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
1433 1435          /* setup TCP/IP connect timeout */
1434 1436          (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
1435 1437              &timeoutMilliSec);
1436 1438          /* retry if LDAP I/O was interrupted */
1437 1439          (void) ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
1438 1440  
1439 1441          ret_code = performBind(auth,
1440 1442              ld,
1441 1443              timeoutSec,
1442 1444              errorp,
1443 1445              fail_if_new_pwd_reqd,
1444 1446              passwd_mgmt);
1445 1447  
1446 1448          if (ret_code == NS_LDAP_SUCCESS ||
1447 1449              ret_code == NS_LDAP_SUCCESS_WITH_INFO) {
1448 1450                  /*
1449 1451                   * Turn off LDAP referral following so that this library can
1450 1452                   * process referrals.
1451 1453                   */
1452 1454                  (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1453 1455                  *ldp = ld;
1454 1456          }
1455 1457  
1456 1458          return (ret_code);
1457 1459  }
1458 1460  
1459 1461  /*
1460 1462   * FUNCTION:    __s_api_getDefaultAuth
1461 1463   *
1462 1464   *      Constructs a credential for authentication using the config module.
1463 1465   *
1464 1466   * RETURN VALUES:
1465 1467   *
1466 1468   * NS_LDAP_SUCCESS      If successful
1467 1469   * NS_LDAP_CONFIG       If there are any config errors.
1468 1470   * NS_LDAP_MEMORY       Memory errors.
1469 1471   * NS_LDAP_OP_FAILED    If there are no more authentication methods so can
1470 1472   *                      not build a new authp.
1471 1473   * NS_LDAP_INVALID_PARAM This overloaded return value means that some of the
1472 1474   *                      necessary fields of a cred for a given auth method
1473 1475   *                      are not provided.
1474 1476   * INPUT:
1475 1477   *
1476 1478   * cLevel       Currently requested credential level to be tried
1477 1479   *
1478 1480   * aMethod      Currently requested authentication method to be tried
1479 1481   *
1480 1482   * getAdmin     If non 0,  get Admin -i.e., not proxyAgent- DN and password
1481 1483   *
1482 1484   * OUTPUT:
1483 1485   *
1484 1486   * authp                authentication method to use.
1485 1487   */
1486 1488  static int
1487 1489  __s_api_getDefaultAuth(
1488 1490          int     *cLevel,
1489 1491          ns_auth_t *aMethod,
1490 1492          ns_cred_t **authp,
1491 1493          int     getAdmin)
1492 1494  {
1493 1495          void            **paramVal = NULL;
1494 1496          char            *modparamVal = NULL;
1495 1497          int             getUid = 0;
1496 1498          int             getPasswd = 0;
1497 1499          int             getCertpath = 0;
1498 1500          int             rc = 0;
1499 1501          ns_ldap_error_t *errorp = NULL;
1500 1502          UnixCred_t      *AdminCred = NULL;
1501 1503  
1502 1504  #ifdef DEBUG
1503 1505          (void) fprintf(stderr, "__s_api_getDefaultAuth START\n");
1504 1506  #endif
1505 1507  
1506 1508          if (aMethod == NULL) {
1507 1509                  /* Require an Auth */
1508 1510                  return (NS_LDAP_INVALID_PARAM);
1509 1511  
1510 1512          }
1511 1513          /*
1512 1514           * credential level "self" can work with auth method sasl/GSSAPI only
1513 1515           */
1514 1516          if (cLevel && *cLevel == NS_LDAP_CRED_SELF &&
1515 1517              aMethod->saslmech != NS_LDAP_SASL_GSSAPI)
1516 1518                  return (NS_LDAP_INVALID_PARAM);
1517 1519  
1518 1520          *authp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
1519 1521          if ((*authp) == NULL)
1520 1522                  return (NS_LDAP_MEMORY);
1521 1523  
1522 1524          (*authp)->auth = *aMethod;
1523 1525  
1524 1526          switch (aMethod->type) {
1525 1527                  case NS_LDAP_AUTH_NONE:
1526 1528                          return (NS_LDAP_SUCCESS);
1527 1529                  case NS_LDAP_AUTH_SIMPLE:
1528 1530                          getUid++;
1529 1531                          getPasswd++;
1530 1532                          break;
1531 1533                  case NS_LDAP_AUTH_SASL:
1532 1534                          if ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
1533 1535                              (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)) {
1534 1536                                  getUid++;
1535 1537                                  getPasswd++;
1536 1538                          } else if (aMethod->saslmech != NS_LDAP_SASL_GSSAPI) {
1537 1539                                  (void) __ns_ldap_freeCred(authp);
1538 1540                                  return (NS_LDAP_INVALID_PARAM);
1539 1541                          }
1540 1542                          break;
1541 1543                  case NS_LDAP_AUTH_TLS:
1542 1544                          if ((aMethod->tlstype == NS_LDAP_TLS_SIMPLE) ||
1543 1545                              ((aMethod->tlstype == NS_LDAP_TLS_SASL) &&
1544 1546                              ((aMethod->saslmech == NS_LDAP_SASL_DIGEST_MD5) ||
1545 1547                              (aMethod->saslmech == NS_LDAP_SASL_CRAM_MD5)))) {
1546 1548                                  getUid++;
1547 1549                                  getPasswd++;
1548 1550                                  getCertpath++;
1549 1551                          } else if (aMethod->tlstype == NS_LDAP_TLS_NONE) {
1550 1552                                  getCertpath++;
1551 1553                          } else {
1552 1554                                  (void) __ns_ldap_freeCred(authp);
1553 1555                                  return (NS_LDAP_INVALID_PARAM);
1554 1556                          }
1555 1557                          break;
1556 1558          }
1557 1559  
1558 1560          if (getUid) {
1559 1561                  paramVal = NULL;
1560 1562                  if (getAdmin) {
1561 1563                          /*
1562 1564                           * Assume AdminCred has been retrieved from
1563 1565                           * ldap_cachemgr already. It will not work
1564 1566                           * without userID or password. Flags getUid
1565 1567                           * and getPasswd should always be set
1566 1568                           * together.
1567 1569                           */
1568 1570                          AdminCred = calloc(1, sizeof (UnixCred_t));
1569 1571                          if (AdminCred == NULL) {
1570 1572                                  (void) __ns_ldap_freeCred(authp);
1571 1573                                  return (NS_LDAP_MEMORY);
1572 1574                          }
1573 1575  
1574 1576                          rc = requestAdminCred(&AdminCred, &errorp);
1575 1577                          if (rc != NS_LDAP_SUCCESS) {
1576 1578                                  (void) __ns_ldap_freeCred(authp);
1577 1579                                  (void) __ns_ldap_freeUnixCred(&AdminCred);
1578 1580                                  (void) __ns_ldap_freeError(&errorp);
1579 1581                                  return (rc);
1580 1582                          }
1581 1583  
1582 1584                          if (AdminCred->userID == NULL) {
1583 1585                                  (void) __ns_ldap_freeCred(authp);
1584 1586                                  (void) __ns_ldap_freeUnixCred(&AdminCred);
1585 1587                                  return (NS_LDAP_INVALID_PARAM);
1586 1588                          }
1587 1589                          (*authp)->cred.unix_cred.userID = AdminCred->userID;
1588 1590                          AdminCred->userID = NULL;
1589 1591                  } else {
1590 1592                          rc = __ns_ldap_getParam(NS_LDAP_BINDDN_P,
1591 1593                              ¶mVal, &errorp);
1592 1594                          if (rc != NS_LDAP_SUCCESS) {
1593 1595                                  (void) __ns_ldap_freeCred(authp);
1594 1596                                  (void) __ns_ldap_freeError(&errorp);
1595 1597                                  return (rc);
1596 1598                          }
1597 1599  
1598 1600                          if (paramVal == NULL || *paramVal == NULL) {
1599 1601                                  (void) __ns_ldap_freeCred(authp);
1600 1602                                  return (NS_LDAP_INVALID_PARAM);
1601 1603                          }
1602 1604  
1603 1605                          (*authp)->cred.unix_cred.userID =
1604 1606                              strdup((char *)*paramVal);
1605 1607                          (void) __ns_ldap_freeParam(¶mVal);
1606 1608                  }
1607 1609                  if ((*authp)->cred.unix_cred.userID == NULL) {
1608 1610                          (void) __ns_ldap_freeCred(authp);
1609 1611                          (void) __ns_ldap_freeUnixCred(&AdminCred);
1610 1612                          return (NS_LDAP_MEMORY);
1611 1613                  }
1612 1614          }
1613 1615          if (getPasswd) {
1614 1616                  paramVal = NULL;
1615 1617                  if (getAdmin) {
1616 1618                          /*
1617 1619                           * Assume AdminCred has been retrieved from
1618 1620                           * ldap_cachemgr already. It will not work
1619 1621                           * without the userID anyway because for
1620 1622                           * getting admin credential, flags getUid
1621 1623                           * and getPasswd should always be set
1622 1624                           * together.
1623 1625                           */
1624 1626                          if (AdminCred == NULL || AdminCred->passwd == NULL) {
1625 1627                                  (void) __ns_ldap_freeCred(authp);
1626 1628                                  (void) __ns_ldap_freeUnixCred(&AdminCred);
1627 1629                                  return (NS_LDAP_INVALID_PARAM);
1628 1630                          }
1629 1631                          modparamVal = dvalue(AdminCred->passwd);
1630 1632                  } else {
1631 1633                          rc = __ns_ldap_getParam(NS_LDAP_BINDPASSWD_P,
1632 1634                              ¶mVal, &errorp);
1633 1635                          if (rc != NS_LDAP_SUCCESS) {
1634 1636                                  (void) __ns_ldap_freeCred(authp);
1635 1637                                  (void) __ns_ldap_freeError(&errorp);
1636 1638                                  return (rc);
1637 1639                          }
1638 1640  
1639 1641                          if (paramVal == NULL || *paramVal == NULL) {
1640 1642                                  (void) __ns_ldap_freeCred(authp);
1641 1643                                  return (NS_LDAP_INVALID_PARAM);
1642 1644                          }
1643 1645  
1644 1646                          modparamVal = dvalue((char *)*paramVal);
1645 1647                          (void) __ns_ldap_freeParam(¶mVal);
1646 1648                  }
1647 1649  
1648 1650                  if (modparamVal == NULL || (strlen((char *)modparamVal) == 0)) {
1649 1651                          (void) __ns_ldap_freeCred(authp);
1650 1652                          (void) __ns_ldap_freeUnixCred(&AdminCred);
1651 1653                          if (modparamVal != NULL)
1652 1654                                  free(modparamVal);
1653 1655                          return (NS_LDAP_INVALID_PARAM);
1654 1656                  }
1655 1657  
1656 1658                  (*authp)->cred.unix_cred.passwd = modparamVal;
1657 1659          }
1658 1660          if (getCertpath) {
1659 1661                  paramVal = NULL;
1660 1662                  if ((rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
1661 1663                      ¶mVal, &errorp)) != NS_LDAP_SUCCESS) {
1662 1664                          (void) __ns_ldap_freeCred(authp);
1663 1665                          (void) __ns_ldap_freeUnixCred(&AdminCred);
1664 1666                          (void) __ns_ldap_freeError(&errorp);
1665 1667                          *authp = NULL;
1666 1668                          return (rc);
1667 1669                  }
1668 1670  
1669 1671                  if (paramVal == NULL || *paramVal == NULL) {
1670 1672                          (void) __ns_ldap_freeCred(authp);
1671 1673                          (void) __ns_ldap_freeUnixCred(&AdminCred);
1672 1674                          *authp = NULL;
1673 1675                          return (NS_LDAP_INVALID_PARAM);
1674 1676                  }
1675 1677  
1676 1678                  (*authp)->hostcertpath = strdup((char *)*paramVal);
1677 1679                  (void) __ns_ldap_freeParam(¶mVal);
1678 1680                  if ((*authp)->hostcertpath == NULL) {
1679 1681                          (void) __ns_ldap_freeCred(authp);
1680 1682                          (void) __ns_ldap_freeUnixCred(&AdminCred);
1681 1683                          *authp = NULL;
1682 1684                          return (NS_LDAP_MEMORY);
1683 1685                  }
1684 1686          }
1685 1687          (void) __ns_ldap_freeUnixCred(&AdminCred);
1686 1688          return (NS_LDAP_SUCCESS);
1687 1689  }
1688 1690  
1689 1691  /*
1690 1692   * FUNCTION:    getConnection
1691 1693   *
1692 1694   *      internal version of __s_api_getConnection()
1693 1695   */
1694 1696  static int
1695 1697  getConnection(
1696 1698          const char *server,
1697 1699          const int flags,
1698 1700          const ns_cred_t *cred,          /* credentials for bind */
1699 1701          ConnectionID *sessionId,
1700 1702          Connection **session,
1701 1703          ns_ldap_error_t **errorp,
1702 1704          int fail_if_new_pwd_reqd,
1703 1705          int nopasswd_acct_mgmt,
1704 1706          ns_conn_user_t *conn_user)
1705 1707  {
1706 1708          char            errmsg[MAXERROR];
1707 1709          ns_auth_t       **aMethod = NULL;
1708 1710          ns_auth_t       **aNext = NULL;
1709 1711          int             **cLevel = NULL;
1710 1712          int             **cNext = NULL;
1711 1713          int             timeoutSec = NS_DEFAULT_BIND_TIMEOUT;
1712 1714          int             rc;
1713 1715          Connection      *con = NULL;
1714 1716          int             sec = 1;
1715 1717          ns_cred_t       *authp = NULL;
1716 1718          ns_cred_t       anon;
1717 1719          int             version = NS_LDAP_V2, self_gssapi_only = 0;
1718 1720          void            **paramVal = NULL;
1719 1721          char            **badSrvrs = NULL; /* List of problem hostnames */
1720 1722  
1721 1723          if ((session == NULL) || (sessionId == NULL)) {
1722 1724                  return (NS_LDAP_INVALID_PARAM);
1723 1725          }
1724 1726          *session = NULL;
1725 1727  
1726 1728          /* reuse MT connection if needed and if available */
1727 1729          if (conn_user != NULL) {
1728 1730                  rc = __s_api_conn_mt_get(server, flags, cred, session, errorp,
1729 1731                      conn_user);
1730 1732                  if (rc != NS_LDAP_NOTFOUND)
1731 1733                          return (rc);
1732 1734          }
1733 1735  
1734 1736          /* get profile version number */
1735 1737          if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
1736 1738              ¶mVal, errorp)) != NS_LDAP_SUCCESS)
1737 1739                  return (rc);
1738 1740          if (paramVal == NULL) {
1739 1741                  (void) sprintf(errmsg, gettext("getConnection: no file "
1740 1742                      "version"));
1741 1743                  MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE, strdup(errmsg),
1742 1744                      NS_LDAP_CONFIG);
1743 1745                  return (NS_LDAP_CONFIG);
1744 1746          }
1745 1747          if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
1746 1748                  version = NS_LDAP_V1;
1747 1749          (void) __ns_ldap_freeParam((void ***)¶mVal);
1748 1750  
1749 1751          /* Get the bind timeout value */
1750 1752          (void) __ns_ldap_getParam(NS_LDAP_BIND_TIME_P, ¶mVal, errorp);
1751 1753          if (paramVal != NULL && *paramVal != NULL) {
1752 1754                  timeoutSec = **((int **)paramVal);
1753 1755                  (void) __ns_ldap_freeParam(¶mVal);
1754 1756          }
1755 1757          if (*errorp)
1756 1758                  (void) __ns_ldap_freeError(errorp);
1757 1759  
1758 1760          if (cred == NULL) {
1759 1761                  /* Get the authentication method list */
1760 1762                  if ((rc = __ns_ldap_getParam(NS_LDAP_AUTH_P,
1761 1763                      (void ***)&aMethod, errorp)) != NS_LDAP_SUCCESS)
1762 1764                          return (rc);
1763 1765                  if (aMethod == NULL) {
1764 1766                          aMethod = (ns_auth_t **)calloc(2, sizeof (ns_auth_t *));
1765 1767                          if (aMethod == NULL)
1766 1768                                  return (NS_LDAP_MEMORY);
1767 1769                          aMethod[0] = (ns_auth_t *)calloc(1, sizeof (ns_auth_t));
1768 1770                          if (aMethod[0] == NULL) {
1769 1771                                  free(aMethod);
1770 1772                                  return (NS_LDAP_MEMORY);
1771 1773                          }
1772 1774                          if (version == NS_LDAP_V1)
1773 1775                                  (aMethod[0])->type = NS_LDAP_AUTH_SIMPLE;
1774 1776                          else {
1775 1777                                  (aMethod[0])->type = NS_LDAP_AUTH_SASL;
1776 1778                                  (aMethod[0])->saslmech =
1777 1779                                      NS_LDAP_SASL_DIGEST_MD5;
1778 1780                                  (aMethod[0])->saslopt = NS_LDAP_SASLOPT_NONE;
1779 1781                          }
1780 1782                  }
1781 1783  
1782 1784                  /* Get the credential level list */
1783 1785                  if ((rc = __ns_ldap_getParam(NS_LDAP_CREDENTIAL_LEVEL_P,
1784 1786                      (void ***)&cLevel, errorp)) != NS_LDAP_SUCCESS) {
1785 1787                          (void) __ns_ldap_freeParam((void ***)&aMethod);
1786 1788                          return (rc);
1787 1789                  }
1788 1790                  if (cLevel == NULL) {
1789 1791                          cLevel = (int **)calloc(2, sizeof (int *));
1790 1792                          if (cLevel == NULL)
1791 1793                                  return (NS_LDAP_MEMORY);
1792 1794                          cLevel[0] = (int *)calloc(1, sizeof (int));
1793 1795                          if (cLevel[0] == NULL)
1794 1796                                  return (NS_LDAP_MEMORY);
1795 1797                          if (version == NS_LDAP_V1)
1796 1798                                  *(cLevel[0]) = NS_LDAP_CRED_PROXY;
1797 1799                          else
1798 1800                                  *(cLevel[0]) = NS_LDAP_CRED_ANON;
1799 1801                  }
1800 1802          }
1801 1803  
1802 1804          /* setup the anon credential for anonymous connection */
1803 1805          (void) memset(&anon, 0, sizeof (ns_cred_t));
1804 1806          anon.auth.type = NS_LDAP_AUTH_NONE;
1805 1807  
1806 1808          for (;;) {
1807 1809                  if (cred != NULL) {
1808 1810                          /* using specified auth method */
1809 1811                          rc = makeConnection(&con, server, cred,
1810 1812                              sessionId, timeoutSec, errorp,
1811 1813                              fail_if_new_pwd_reqd,
1812 1814                              nopasswd_acct_mgmt, flags, &badSrvrs, conn_user);
1813 1815                          /* not using bad server if credentials were supplied */
1814 1816                          if (badSrvrs && *badSrvrs) {
1815 1817                                  __s_api_free2dArray(badSrvrs);
1816 1818                                  badSrvrs = NULL;
1817 1819                          }
1818 1820                          if (rc == NS_LDAP_SUCCESS ||
1819 1821                              rc == NS_LDAP_SUCCESS_WITH_INFO) {
1820 1822                                  *session = con;
1821 1823                                  break;
1822 1824                          }
1823 1825                  } else {
1824 1826                          self_gssapi_only = __s_api_self_gssapi_only_get();
1825 1827                          /* for every cred level */
1826 1828                          for (cNext = cLevel; *cNext != NULL; cNext++) {
1827 1829                                  if (self_gssapi_only &&
1828 1830                                      **cNext != NS_LDAP_CRED_SELF)
1829 1831                                          continue;
1830 1832                                  if (**cNext == NS_LDAP_CRED_ANON) {
1831 1833                                          /*
1832 1834                                           * make connection anonymously
1833 1835                                           * Free the down server list before
1834 1836                                           * looping through
1835 1837                                           */
1836 1838                                          if (badSrvrs && *badSrvrs) {
1837 1839                                                  __s_api_free2dArray(badSrvrs);
1838 1840                                                  badSrvrs = NULL;
1839 1841                                          }
1840 1842                                          rc = makeConnection(&con, server, &anon,
1841 1843                                              sessionId, timeoutSec, errorp,
1842 1844                                              fail_if_new_pwd_reqd,
1843 1845                                              nopasswd_acct_mgmt, flags,
1844 1846                                              &badSrvrs, conn_user);
1845 1847                                          if (rc == NS_LDAP_SUCCESS ||
1846 1848                                              rc ==
1847 1849                                              NS_LDAP_SUCCESS_WITH_INFO) {
1848 1850                                                  *session = con;
1849 1851                                                  goto done;
1850 1852                                          }
1851 1853                                          continue;
1852 1854                                  }
1853 1855                                  /* for each cred level */
1854 1856                                  for (aNext = aMethod; *aNext != NULL; aNext++) {
1855 1857                                          if (self_gssapi_only &&
1856 1858                                              (*aNext)->saslmech !=
1857 1859                                              NS_LDAP_SASL_GSSAPI)
1858 1860                                                  continue;
1859 1861                                          /*
1860 1862                                           * self coexists with sasl/GSSAPI only
1861 1863                                           * and non-self coexists with non-gssapi
1862 1864                                           * only
1863 1865                                           */
1864 1866                                          if ((**cNext == NS_LDAP_CRED_SELF &&
1865 1867                                              (*aNext)->saslmech !=
1866 1868                                              NS_LDAP_SASL_GSSAPI) ||
1867 1869                                              (**cNext != NS_LDAP_CRED_SELF &&
1868 1870                                              (*aNext)->saslmech ==
1869 1871                                              NS_LDAP_SASL_GSSAPI))
1870 1872                                                  continue;
1871 1873                                          /* make connection and authenticate */
1872 1874                                          /* with default credentials */
1873 1875                                          authp = NULL;
1874 1876                                          rc = __s_api_getDefaultAuth(*cNext,
1875 1877                                              *aNext, &authp,
1876 1878                                              flags & NS_LDAP_READ_SHADOW);
1877 1879                                          if (rc != NS_LDAP_SUCCESS) {
1878 1880                                                  continue;
1879 1881                                          }
1880 1882                                          /*
1881 1883                                           * Free the down server list before
1882 1884                                           * looping through
1883 1885                                           */
1884 1886                                          if (badSrvrs && *badSrvrs) {
1885 1887                                                  __s_api_free2dArray(badSrvrs);
1886 1888                                                  badSrvrs = NULL;
1887 1889                                          }
1888 1890                                          rc = makeConnection(&con, server, authp,
1889 1891                                              sessionId, timeoutSec, errorp,
1890 1892                                              fail_if_new_pwd_reqd,
1891 1893                                              nopasswd_acct_mgmt, flags,
1892 1894                                              &badSrvrs, conn_user);
1893 1895                                          (void) __ns_ldap_freeCred(&authp);
1894 1896                                          if (rc == NS_LDAP_SUCCESS ||
1895 1897                                              rc ==
1896 1898                                              NS_LDAP_SUCCESS_WITH_INFO) {
1897 1899                                                  *session = con;
1898 1900                                                  goto done;
1899 1901                                          }
1900 1902                                  }
1901 1903                          }
1902 1904                  }
1903 1905                  if (flags & NS_LDAP_HARD) {
1904 1906                          if (sec < LDAPMAXHARDLOOKUPTIME)
1905 1907                                  sec *= 2;
1906 1908                          (void) sleep(sec);
1907 1909                  } else {
1908 1910                          break;
1909 1911                  }
1910 1912          }
1911 1913  
1912 1914  done:
1913 1915          if (self_gssapi_only && rc == NS_LDAP_SUCCESS && *session == NULL) {
1914 1916                  /*
1915 1917                   * self_gssapi_only is true but no self/sasl/gssapi is
1916 1918                   * configured
1917 1919                   */
1918 1920                  rc = NS_LDAP_CONFIG;
1919 1921          }
1920 1922  
1921 1923          (void) __ns_ldap_freeParam((void ***)&aMethod);
1922 1924          (void) __ns_ldap_freeParam((void ***)&cLevel);
1923 1925  
1924 1926          if (badSrvrs && *badSrvrs) {
1925 1927                  /*
1926 1928                   * At this point, either we have a successful
1927 1929                   * connection or exhausted all the possible auths.
1928 1930                   * and creds. Mark the problem servers as down
1929 1931                   * so that the problem servers are not contacted
1930 1932                   * again until the refresh_ttl expires.
1931 1933                   */
1932 1934                  (void) __s_api_removeBadServers(badSrvrs);
1933 1935                  __s_api_free2dArray(badSrvrs);
1934 1936          }
1935 1937          return (rc);
1936 1938  }
1937 1939  
1938 1940  /*
1939 1941   * FUNCTION:    __s_api_getConnection
1940 1942   *
1941 1943   *      Bind to the specified server or one from the server
1942 1944   *      list and return the pointer.
1943 1945   *
1944 1946   *      This function can rebind or not (NS_LDAP_HARD), it can require a
1945 1947   *      credential or bind anonymously
1946 1948   *
1947 1949   *      This function follows the DUA configuration schema algorithm
1948 1950   *
1949 1951   * RETURN VALUES:
1950 1952   *
1951 1953   * NS_LDAP_SUCCESS      A connection was made successfully.
1952 1954   * NS_LDAP_SUCCESS_WITH_INFO
1953 1955   *                      A connection was made successfully, but with
1954 1956   *                      password management info in *errorp
1955 1957   * NS_LDAP_INVALID_PARAM If any invalid arguments were passed to the function.
1956 1958   * NS_LDAP_CONFIG       If there are any config errors.
1957 1959   * NS_LDAP_MEMORY       Memory errors.
1958 1960   * NS_LDAP_INTERNAL     If there was a ldap error.
1959 1961   *
1960 1962   * INPUT:
1961 1963   *
1962 1964   * server       Bind to this LDAP server only
1963 1965   * flags        If NS_LDAP_HARD is set function will not return until it has
1964 1966   *              a connection unless there is a authentication problem.
1965 1967   *              If NS_LDAP_NEW_CONN is set the function must force a new
1966 1968   *              connection to be created
1967 1969   *              If NS_LDAP_KEEP_CONN is set the connection is to be kept open
1968 1970   * auth         Credentials for bind. This could be NULL in which case
1969 1971   *              a default cred built from the config module is used.
1970 1972   * sessionId    cookie that points to a previous session
1971 1973   * fail_if_new_pwd_reqd
1972 1974   *              a flag indicating this function should fail if the passwd
1973 1975   *              in auth needs to change immediately
1974 1976   * nopasswd_acct_mgmt
1975 1977   *              a flag indicating that makeConnection should check before
1976 1978   *              binding if server supports LDAP V3 password less
1977 1979   *              account management
1978 1980   *
1979 1981   * OUTPUT:
1980 1982   *
1981 1983   * session      pointer to a session with connection information
1982 1984   * errorp       Set if there are any INTERNAL, or CONFIG error.
1983 1985   */
1984 1986  int
1985 1987  __s_api_getConnection(
1986 1988          const char *server,
1987 1989          const int flags,
1988 1990          const ns_cred_t *cred,          /* credentials for bind */
1989 1991          ConnectionID *sessionId,
1990 1992          Connection **session,
1991 1993          ns_ldap_error_t **errorp,
1992 1994          int fail_if_new_pwd_reqd,
1993 1995          int nopasswd_acct_mgmt,
1994 1996          ns_conn_user_t *conn_user)
1995 1997  {
1996 1998          int rc;
1997 1999  
1998 2000          rc = getConnection(server, flags, cred, sessionId, session,
1999 2001              errorp, fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
2000 2002              conn_user);
2001 2003  
2002 2004          if (rc != NS_LDAP_SUCCESS && rc != NS_LDAP_SUCCESS_WITH_INFO) {
2003 2005                  if (conn_user != NULL && conn_user->conn_mt != NULL)
2004 2006                          __s_api_conn_mt_remove(conn_user, rc, errorp);
2005 2007          }
2006 2008  
2007 2009          return (rc);
2008 2010  }
2009 2011  
2010 2012  void
2011 2013  __s_api_free_sessionPool()
2012 2014  {
2013 2015          int id;
2014 2016  
2015 2017          (void) mutex_lock(&sessionPoolLock);
2016 2018  
2017 2019          if (sessionPool != NULL) {
2018 2020                  for (id = 0; id < sessionPoolSize; id++)
2019 2021                          _DropConnection(id + CONID_OFFSET, 0, 1);
2020 2022                  free(sessionPool);
2021 2023                  sessionPool = NULL;
2022 2024                  sessionPoolSize = 0;
2023 2025          }
2024 2026          (void) mutex_unlock(&sessionPoolLock);
2025 2027  }
2026 2028  
2027 2029  /*
2028 2030   * This function initializes a TLS LDAP session. On success LDAP* is returned
2029 2031   * (pointed by *ldp). Otherwise, the function returns an NS error code and
2030 2032   * provide an additional info pointed by *errorp.
2031 2033   */
2032 2034  static
2033 2035  ns_ldap_return_code
2034 2036  createTLSSession(const ns_cred_t *auth, const char *serverAddr,
2035 2037                      uint16_t port, int timeoutMilliSec,
2036 2038                      LDAP **ldp, ns_ldap_error_t **errorp)
2037 2039  {
2038 2040          const char      *hostcertpath;
2039 2041          char            *alloc_hcp = NULL, errstr[MAXERROR];
2040 2042          int             ldap_rc;
2041 2043  
2042 2044  #ifdef DEBUG
2043 2045          (void) fprintf(stderr, "tid= %d: +++TLS transport\n",
2044 2046              thr_self());
2045 2047  #endif /* DEBUG */
2046 2048  
2047 2049          if (prldap_set_session_option(NULL, NULL,
2048 2050              PRLDAP_OPT_IO_MAX_TIMEOUT,
2049 2051              timeoutMilliSec) != LDAP_SUCCESS) {
2050 2052                  (void) snprintf(errstr, sizeof (errstr),
2051 2053                      gettext("createTLSSession: failed to initialize "
2052 2054                      "TLS security"));
2053 2055                  MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2054 2056                      strdup(errstr), NS_LDAP_MEMORY);
2055 2057                  return (NS_LDAP_INTERNAL);
2056 2058          }
2057 2059  
2058 2060          hostcertpath = auth->hostcertpath;
2059 2061          if (hostcertpath == NULL) {
2060 2062                  alloc_hcp = __s_get_hostcertpath();
2061 2063                  hostcertpath = alloc_hcp;
2062 2064          }
2063 2065  
2064 2066          if (hostcertpath == NULL)
2065 2067                  return (NS_LDAP_MEMORY);
2066 2068  
2067 2069          if ((ldap_rc = ldapssl_client_init(hostcertpath, NULL)) < 0) {
2068 2070                  if (alloc_hcp != NULL) {
2069 2071                          free(alloc_hcp);
2070 2072                  }
2071 2073                  (void) snprintf(errstr, sizeof (errstr),
2072 2074                      gettext("createTLSSession: failed to initialize "
2073 2075                      "TLS security (%s)"),
2074 2076                      ldapssl_err2string(ldap_rc));
2075 2077                  MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2076 2078                      strdup(errstr), NS_LDAP_MEMORY);
2077 2079                  return (NS_LDAP_INTERNAL);
2078 2080          }
2079 2081          if (alloc_hcp)
2080 2082                  free(alloc_hcp);
2081 2083  
2082 2084          *ldp = ldapssl_init(serverAddr, port, 1);
2083 2085  
2084 2086          if (*ldp == NULL ||
2085 2087              ldapssl_install_gethostbyaddr(*ldp, "ldap") != 0) {
2086 2088                  (void) snprintf(errstr, sizeof (errstr),
2087 2089                      gettext("createTLSSession: failed to connect "
2088 2090                      "using TLS (%s)"), strerror(errno));
2089 2091                  MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2090 2092                      strdup(errstr), NS_LDAP_MEMORY);
2091 2093                  return (NS_LDAP_INTERNAL);
2092 2094          }
2093 2095  
2094 2096          return (NS_LDAP_SUCCESS);
2095 2097  }
2096 2098  
2097 2099  /*
2098 2100   * Convert (resolve) hostname to IP address.
2099 2101   *
2100 2102   * INPUT:
2101 2103   *
2102 2104   *      server  - \[IPv6_address\][:port]
2103 2105   *              - IPv4_address[:port]
2104 2106   *              - hostname[:port]
2105 2107   *
2106 2108   *      newaddr - Buffer to which this function writes resulting address,
2107 2109   *              including the port number, if specified in server argument.
2108 2110   *
2109 2111   *      newaddr_size - Size of the newaddr buffer.
2110 2112   *
2111 2113   *      errstr  - Buffer to which error string is written if error occurs.
2112 2114   *
2113 2115   *      errstr_size - Size of the errstr buffer.
2114 2116   *
2115 2117   * OUTPUT:
2116 2118   *
2117 2119   *      Returns 1 for success, 0 in case of error.
2118 2120   *
2119 2121   *      newaddr - See above (INPUT section).
2120 2122   *
2121 2123   *      errstr  - See above (INPUT section).
2122 2124   */
2123 2125  static int
2124 2126  cvt_hostname2ip(char *server, char *newaddr, int newaddr_size,
2125 2127      char *errstr, int errstr_size)
2126 2128  {
2127 2129          char    *s;
2128 2130          unsigned short port = 0;
2129 2131          int     err;
2130 2132          char    buffer[NSS_BUFLEN_HOSTS];
2131 2133          struct hostent  result;
2132 2134  
2133 2135          /* Determine if the host name contains a port number. */
2134 2136  
2135 2137          /* Skip over IPv6 address. */
2136 2138          s = strchr(server, ']');
2137 2139          s = strchr(s != NULL ? s : server, ':');
2138 2140          if (s != NULL) {
2139 2141                  if (sscanf(s + 1, "%hu", &port) != 1) {
2140 2142                          /* Address misformatted. No port number after : */
2141 2143                          (void) snprintf(errstr, errstr_size, "%s",
2142 2144                              gettext("Invalid host:port format"));
2143 2145                          return (0);
2144 2146                  } else
2145 2147                          /* Cut off the :<port> part. */
2146 2148                          *s = '\0';
2147 2149          }
2148 2150  
2149 2151          buffer[0] = '\0';
2150 2152          /*
2151 2153           * Resolve hostname and fill in hostent structure.
2152 2154           */
2153 2155          if (!__s_api_hostname2ip(server, &result, buffer, NSS_BUFLEN_HOSTS,
2154 2156              &err)) {
2155 2157                  /*
2156 2158                   * The only possible error here could be TRY_AGAIN if buffer was
2157 2159                   * not big enough. NSS_BUFLEN_HOSTS should have been enough
2158 2160                   * though.
2159 2161                   */
2160 2162                  (void) snprintf(errstr, errstr_size, "%s",
2161 2163                      gettext("Unable to resolve address."));
2162 2164                  return (0);
2163 2165          }
2164 2166  
2165 2167  
2166 2168          buffer[0] = '\0';
2167 2169          /*
2168 2170           * Convert the address to string.
2169 2171           */
2170 2172          if (!inet_ntop(result.h_addrtype, result.h_addr_list[0], buffer,
2171 2173              NSS_BUFLEN_HOSTS)) {
2172 2174                  /* There's not much we can do. */
2173 2175                  (void) snprintf(errstr, errstr_size, "%s",
2174 2176                      gettext("Unable to convert address to string."));
2175 2177                  return (0);
2176 2178          }
2177 2179  
2178 2180          /* Put together the address and the port */
2179 2181          if (port > 0) {
2180 2182                  switch (result.h_addrtype) {
2181 2183                          case AF_INET6:
2182 2184                                  (void) snprintf(newaddr,
2183 2185                                      /* [IP]:<port>\0 */
2184 2186                                      1 + strlen(buffer) + 1 + 1 + 5 + 1,
2185 2187                                      "[%s]:%hu",
2186 2188                                      buffer,
2187 2189                                      port);
2188 2190                                  break;
2189 2191                          /* AF_INET */
2190 2192                          default :
2191 2193                                  (void) snprintf(newaddr,
2192 2194                                      /* IP:<port>\0 */
2193 2195                                      strlen(buffer) + 1 + 5 + 1,
2194 2196                                      "%s:%hu",
2195 2197                                      buffer,
2196 2198                                      port);
2197 2199                                  break;
2198 2200                  }
2199 2201          } else {
2200 2202                  (void) strncpy(newaddr, buffer, newaddr_size);
2201 2203          }
2202 2204  
2203 2205          return (1);
2204 2206  }
2205 2207  
2206 2208  
2207 2209  /*
2208 2210   * This finction initializes a none-TLS LDAP session.  On success LDAP*
2209 2211   * is returned (pointed by *ldp). Otherwise, the function returns
2210 2212   * an NS error code and provides an additional info pointed by *errorp.
2211 2213   */
2212 2214  static
2213 2215  ns_ldap_return_code
2214 2216  createNonTLSSession(const char *serverAddr,
2215 2217                  uint16_t port, int gssapi,
2216 2218                  LDAP **ldp, ns_ldap_error_t **errorp)
2217 2219  {
2218 2220          char            errstr[MAXERROR];
2219 2221          char            *addr;
2220 2222          int             is_ip = 0;
2221 2223                          /* [INET6_ADDRSTRLEN]:<port>\0 */
2222 2224          char            svraddr[1+INET6_ADDRSTRLEN+1+1+5+1];
2223 2225  #ifdef DEBUG
2224 2226          (void) fprintf(stderr, "tid= %d: +++Unsecure transport\n",
2225 2227              thr_self());
2226 2228  #endif /* DEBUG */
2227 2229  
2228 2230          if (gssapi == 0) {
2229 2231                  is_ip = (__s_api_isipv4((char *)serverAddr) ||
2230 2232                      __s_api_isipv6((char *)serverAddr));
2231 2233          }
2232 2234  
2233 2235          /*
2234 2236           * Let's try to resolve IP address of server.
2235 2237           */
2236 2238          if (is_ip == 0 && !gssapi && (ldap_in_nss_switch((char *)"hosts") > 0 ||
2237 2239              ldap_in_nss_switch((char *)"ipnodes") > 0)) {
2238 2240                  addr = strdup(serverAddr);
2239 2241                  if (addr == NULL)
2240 2242                          return (NS_LDAP_MEMORY);
2241 2243                  svraddr[0] = '\0';
2242 2244                  if (cvt_hostname2ip(addr, svraddr, sizeof (svraddr),
2243 2245                      errstr, MAXERROR) == 1) {
2244 2246                          serverAddr = svraddr;
2245 2247                          free(addr);
2246 2248                  } else {
2247 2249                          free(addr);
2248 2250                          MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2249 2251                              strdup(errstr), NS_LDAP_MEMORY);
2250 2252                          return (NS_LDAP_INTERNAL);
2251 2253                  }
2252 2254          }
2253 2255  
2254 2256          /* Warning message IF cannot connect to host(s) */
2255 2257          if ((*ldp = ldap_init((char *)serverAddr, port)) == NULL) {
2256 2258                  char *p = strerror(errno);
2257 2259                  MKERROR(LOG_WARNING, *errorp, LDAP_CONNECT_ERROR,
2258 2260                      strdup(p), NS_LDAP_MEMORY);
2259 2261                  return (NS_LDAP_INTERNAL);
2260 2262          }
2261 2263  
2262 2264          return (NS_LDAP_SUCCESS);
2263 2265  }
2264 2266  
2265 2267  /*
2266 2268   * This finction initializes an LDAP session.
2267 2269   *
2268 2270   * INPUT:
2269 2271   *     auth - a structure specified an authenticastion method and credentials,
2270 2272   *     serverAddr - the address of a server to which a connection
2271 2273   *                  will be established,
2272 2274   *     port - a port being listened by the server,
2273 2275   *     timeoutMilliSec - a timeout in milliseconds for the Bind operation.
2274 2276   *
2275 2277   * OUTPUT:
2276 2278   *     ldp - a pointer to an LDAP structure which will be used
2277 2279   *           for all the subsequent operations against the server.
2278 2280   *     If an error occurs, the function returns an NS error code
2279 2281   *     and provides an additional info pointed by *errorp.
2280 2282   */
2281 2283  static
2282 2284  ns_ldap_return_code
2283 2285  createSession(const ns_cred_t *auth, const char *serverAddr,
2284 2286                      uint16_t port, int timeoutMilliSec,
2285 2287                      LDAP **ldp, ns_ldap_error_t **errorp)
2286 2288  {
2287 2289          int     useSSL = 0, gssapi = 0;
2288 2290          char    errstr[MAXERROR];
2289 2291  
2290 2292          switch (auth->auth.type) {
2291 2293                  case NS_LDAP_AUTH_NONE:
2292 2294                  case NS_LDAP_AUTH_SIMPLE:
2293 2295                  case NS_LDAP_AUTH_SASL:
2294 2296                          break;
2295 2297                  case NS_LDAP_AUTH_TLS:
2296 2298                          useSSL = 1;
2297 2299                          break;
2298 2300                  default:
2299 2301                          (void) sprintf(errstr,
2300 2302                              gettext("openConnection: unsupported "
2301 2303                              "authentication method (%d)"), auth->auth.type);
2302 2304                          MKERROR(LOG_WARNING, *errorp,
2303 2305                              LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
2304 2306                              NS_LDAP_MEMORY);
2305 2307                          return (NS_LDAP_INTERNAL);
2306 2308          }
2307 2309  
2308 2310          if (port == USE_DEFAULT_PORT) {
2309 2311                  port = useSSL ? LDAPS_PORT : LDAP_PORT;
2310 2312          }
2311 2313  
2312 2314          if (auth->auth.type == NS_LDAP_AUTH_SASL &&
2313 2315              auth->auth.saslmech == NS_LDAP_SASL_GSSAPI)
2314 2316                  gssapi = 1;
2315 2317  
2316 2318          if (useSSL)
2317 2319                  return (createTLSSession(auth, serverAddr, port,
2318 2320                      timeoutMilliSec, ldp, errorp));
2319 2321          else
2320 2322                  return (createNonTLSSession(serverAddr, port, gssapi,
2321 2323                      ldp, errorp));
2322 2324  }
2323 2325  
2324 2326  /*
2325 2327   * This finction performs a non-SASL bind operation.  If an error accures,
2326 2328   * the function returns an NS error code and provides an additional info
2327 2329   * pointed by *errorp.
2328 2330   */
2329 2331  static
2330 2332  ns_ldap_return_code
2331 2333  doSimpleBind(const ns_cred_t *auth,
2332 2334                  LDAP *ld,
2333 2335                  int timeoutSec,
2334 2336                  ns_ldap_error_t **errorp,
2335 2337                  int fail_if_new_pwd_reqd,
2336 2338                  int passwd_mgmt)
2337 2339  {
2338 2340          char                    *binddn, *passwd, errstr[MAXERROR], *errmsg;
2339 2341          int                     msgId, errnum = 0, ldap_rc;
2340 2342          ns_ldap_return_code     ret_code;
2341 2343          LDAPMessage             *resultMsg = NULL;
2342 2344          LDAPControl             **controls;
2343 2345          struct timeval          tv;
2344 2346  
2345 2347          binddn = auth->cred.unix_cred.userID;
2346 2348          passwd = auth->cred.unix_cred.passwd;
2347 2349          if (passwd == NULL || *passwd == '\0' ||
2348 2350              binddn == NULL || *binddn == '\0') {
2349 2351                  (void) sprintf(errstr, gettext("openConnection: "
2350 2352                      "missing credentials for Simple bind"));
2351 2353                  MKERROR(LOG_WARNING, *errorp, LDAP_INVALID_CREDENTIALS,
2352 2354                      strdup(errstr), NS_LDAP_MEMORY);
2353 2355                  (void) ldap_unbind(ld);
2354 2356                  return (NS_LDAP_INTERNAL);
2355 2357          }
2356 2358  
2357 2359  #ifdef DEBUG
2358 2360          (void) fprintf(stderr, "tid= %d: +++Simple bind\n",
2359 2361              thr_self());
2360 2362  #endif /* DEBUG */
2361 2363          msgId = ldap_simple_bind(ld, binddn, passwd);
2362 2364  
2363 2365          if (msgId == -1) {
2364 2366                  (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2365 2367                      (void *)&errnum);
2366 2368                  (void) snprintf(errstr, sizeof (errstr),
2367 2369                      gettext("openConnection: simple bind failed "
2368 2370                      "- %s"), ldap_err2string(errnum));
2369 2371                  (void) ldap_unbind(ld);
2370 2372                  MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
2371 2373                      NS_LDAP_MEMORY);
2372 2374                  return (NS_LDAP_INTERNAL);
2373 2375          }
2374 2376  
2375 2377          tv.tv_sec = timeoutSec;
2376 2378          tv.tv_usec = 0;
2377 2379          ldap_rc = ldap_result(ld, msgId, 0, &tv, &resultMsg);
2378 2380  
2379 2381          if ((ldap_rc == -1) || (ldap_rc == 0)) {
2380 2382                  (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
2381 2383                      (void *)&errnum);
2382 2384                  (void) snprintf(errstr, sizeof (errstr),
2383 2385                      gettext("openConnection: simple bind failed "
2384 2386                      "- %s"), ldap_err2string(errnum));
2385 2387                  (void) ldap_msgfree(resultMsg);
2386 2388                  (void) ldap_unbind(ld);
2387 2389                  MKERROR(LOG_WARNING, *errorp, errnum, strdup(errstr),
2388 2390                      NS_LDAP_MEMORY);
2389 2391                  return (NS_LDAP_INTERNAL);
2390 2392          }
2391 2393  
2392 2394          /*
2393 2395           * get ldaprc, controls, and error msg
2394 2396           */
2395 2397          ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
2396 2398              &errmsg, NULL, &controls, 1);
2397 2399  
2398 2400          if (ldap_rc != LDAP_SUCCESS) {
2399 2401                  (void) snprintf(errstr, sizeof (errstr),
2400 2402                      gettext("openConnection: simple bind failed "
2401 2403                      "- unable to parse result"));
2402 2404                  (void) ldap_unbind(ld);
2403 2405                  MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2404 2406                      strdup(errstr), NS_LDAP_MEMORY);
2405 2407                  return (NS_LDAP_INTERNAL);
2406 2408          }
2407 2409  
2408 2410          /* process the password management info, if any */
2409 2411          ret_code = process_pwd_mgmt("simple",
2410 2412              errnum, controls, errmsg,
2411 2413              errorp,
2412 2414              fail_if_new_pwd_reqd,
2413 2415              passwd_mgmt);
2414 2416  
2415 2417          if (ret_code == NS_LDAP_INTERNAL) {
2416 2418                  (void) ldap_unbind(ld);
2417 2419          }
2418 2420  
2419 2421          return (ret_code);
2420 2422  }
2421 2423  
2422 2424  /*
2423 2425   * This finction performs a SASL bind operation.  If an error accures,
2424 2426   * the function returns an NS error code and provides an additional info
2425 2427   * pointed by *errorp.
2426 2428   */
2427 2429  static
2428 2430  ns_ldap_return_code
2429 2431  doSASLBind(const ns_cred_t *auth,
2430 2432                  LDAP *ld,
2431 2433                  int timeoutSec,
2432 2434                  ns_ldap_error_t **errorp,
2433 2435                  int fail_if_new_pwd_reqd,
2434 2436                  int passwd_mgmt)
2435 2437  {
2436 2438          char                    *binddn, *passwd, *digest_md5_name,
2437 2439              errstr[MAXERROR], *errmsg;
2438 2440          struct berval           cred;
2439 2441          int                     ldap_rc, errnum = 0;
2440 2442          ns_ldap_return_code     ret_code;
2441 2443          struct timeval          tv;
2442 2444          LDAPMessage             *resultMsg;
2443 2445          LDAPControl             **controls;
2444 2446          int                     min_ssf = MIN_SASL_SSF, max_ssf = MAX_SASL_SSF;
2445 2447          ns_sasl_cb_param_t      sasl_param;
2446 2448  
2447 2449          if (auth->auth.saslopt != NS_LDAP_SASLOPT_NONE &&
2448 2450              auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
2449 2451                  (void) sprintf(errstr,
2450 2452                      gettext("openConnection: SASL options are "
2451 2453                      "not supported (%d) for non-GSSAPI sasl bind"),
2452 2454                      auth->auth.saslopt);
2453 2455                  MKERROR(LOG_WARNING, *errorp,
2454 2456                      LDAP_AUTH_METHOD_NOT_SUPPORTED,
2455 2457                      strdup(errstr), NS_LDAP_MEMORY);
2456 2458                  (void) ldap_unbind(ld);
2457 2459                  return (NS_LDAP_INTERNAL);
2458 2460          }
2459 2461          if (auth->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
2460 2462                  binddn = auth->cred.unix_cred.userID;
2461 2463                  passwd = auth->cred.unix_cred.passwd;
2462 2464                  if (passwd == NULL || *passwd == '\0' ||
2463 2465                      binddn == NULL || *binddn == '\0') {
2464 2466                          (void) sprintf(errstr,
2465 2467                          gettext("openConnection: missing credentials "
2466 2468                              "for SASL bind"));
2467 2469                          MKERROR(LOG_WARNING, *errorp,
2468 2470                              LDAP_INVALID_CREDENTIALS,
2469 2471                              strdup(errstr), NS_LDAP_MEMORY);
2470 2472                          (void) ldap_unbind(ld);
2471 2473                          return (NS_LDAP_INTERNAL);
2472 2474                  }
2473 2475                  cred.bv_val = passwd;
2474 2476                  cred.bv_len = strlen(passwd);
2475 2477          }
2476 2478  
2477 2479          ret_code = NS_LDAP_SUCCESS;
2478 2480  
2479 2481          switch (auth->auth.saslmech) {
2480 2482          case NS_LDAP_SASL_CRAM_MD5:
2481 2483                  /*
2482 2484                   * NOTE: if iDS changes to support cram_md5,
2483 2485                   * please add password management code here.
2484 2486                   * Since ldap_sasl_cram_md5_bind_s does not
2485 2487                   * return anything that could be used to
2486 2488                   * extract the ldap rc/errmsg/control to
2487 2489                   * determine if bind failed due to password
2488 2490                   * policy, a new cram_md5_bind API will need
2489 2491                   * to be introduced. See
2490 2492                   * ldap_x_sasl_digest_md5_bind() and case
2491 2493                   * NS_LDAP_SASL_DIGEST_MD5 below for details.
2492 2494                   */
2493 2495                  if ((ldap_rc = ldap_sasl_cram_md5_bind_s(ld, binddn,
2494 2496                      &cred, NULL, NULL)) != LDAP_SUCCESS) {
2495 2497                          (void) ldap_get_option(ld,
2496 2498                              LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
2497 2499                          (void) snprintf(errstr, sizeof (errstr),
2498 2500                              gettext("openConnection: "
2499 2501                              "sasl/CRAM-MD5 bind failed - %s"),
2500 2502                              ldap_err2string(errnum));
2501 2503                          MKERROR(LOG_WARNING, *errorp, errnum,
2502 2504                              strdup(errstr), NS_LDAP_MEMORY);
2503 2505                          (void) ldap_unbind(ld);
2504 2506                          return (NS_LDAP_INTERNAL);
2505 2507                  }
2506 2508                  break;
2507 2509          case NS_LDAP_SASL_DIGEST_MD5:
2508 2510                  digest_md5_name = malloc(strlen(binddn) + 5);
2509 2511                  /* 5 = strlen("dn: ") + 1 */
2510 2512                  if (digest_md5_name == NULL) {
2511 2513                          (void) ldap_unbind(ld);
2512 2514                          return (NS_LDAP_MEMORY);
2513 2515                  }
2514 2516                  (void) strcpy(digest_md5_name, "dn: ");
2515 2517                  (void) strcat(digest_md5_name, binddn);
2516 2518  
2517 2519                  tv.tv_sec = timeoutSec;
2518 2520                  tv.tv_usec = 0;
2519 2521                  ldap_rc = ldap_x_sasl_digest_md5_bind(ld,
2520 2522                      digest_md5_name, &cred, NULL, NULL,
2521 2523                      &tv, &resultMsg);
2522 2524  
2523 2525                  if (resultMsg == NULL) {
2524 2526                          free(digest_md5_name);
2525 2527                          (void) ldap_get_option(ld,
2526 2528                              LDAP_OPT_ERROR_NUMBER, (void *)&errnum);
2527 2529                          (void) snprintf(errstr, sizeof (errstr),
2528 2530                              gettext("openConnection: "
2529 2531                              "DIGEST-MD5 bind failed - %s"),
2530 2532                              ldap_err2string(errnum));
2531 2533                          (void) ldap_unbind(ld);
2532 2534                          MKERROR(LOG_WARNING, *errorp, errnum,
2533 2535                              strdup(errstr), NS_LDAP_MEMORY);
2534 2536                          return (NS_LDAP_INTERNAL);
2535 2537                  }
2536 2538  
2537 2539                  /*
2538 2540                   * get ldaprc, controls, and error msg
2539 2541                   */
2540 2542                  ldap_rc = ldap_parse_result(ld, resultMsg, &errnum, NULL,
2541 2543                      &errmsg, NULL, &controls, 1);
2542 2544  
2543 2545                  if (ldap_rc != LDAP_SUCCESS) {
2544 2546                          free(digest_md5_name);
2545 2547                          (void) snprintf(errstr, sizeof (errstr),
2546 2548                              gettext("openConnection: "
2547 2549                              "DIGEST-MD5 bind failed "
2548 2550                              "- unable to parse result"));
2549 2551                          (void) ldap_unbind(ld);
2550 2552                          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2551 2553                              strdup(errstr), NS_LDAP_MEMORY);
2552 2554                          return (NS_LDAP_INTERNAL);
2553 2555                  }
2554 2556  
2555 2557                  /* process the password management info, if any */
2556 2558                  ret_code = process_pwd_mgmt("sasl/DIGEST-MD5",
2557 2559                      errnum, controls, errmsg,
2558 2560                      errorp,
2559 2561                      fail_if_new_pwd_reqd,
2560 2562                      passwd_mgmt);
2561 2563  
2562 2564                  if (ret_code == NS_LDAP_INTERNAL) {
2563 2565                          (void) ldap_unbind(ld);
2564 2566                  }
2565 2567  
2566 2568                  free(digest_md5_name);
2567 2569                  break;
2568 2570          case NS_LDAP_SASL_GSSAPI:
2569 2571                  (void) memset(&sasl_param, 0,
2570 2572                      sizeof (ns_sasl_cb_param_t));
2571 2573                  sasl_param.authid = NULL;
2572 2574                  sasl_param.authzid = "";
2573 2575                  (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MIN,
2574 2576                      (void *)&min_ssf);
2575 2577                  (void) ldap_set_option(ld, LDAP_OPT_X_SASL_SSF_MAX,
2576 2578                      (void *)&max_ssf);
2577 2579  
2578 2580                  ldap_rc = ldap_sasl_interactive_bind_s(
2579 2581                      ld, NULL, "GSSAPI",
2580 2582                      NULL, NULL, LDAP_SASL_INTERACTIVE,
2581 2583                      __s_api_sasl_bind_callback,
2582 2584                      &sasl_param);
2583 2585  
2584 2586                  if (ldap_rc != LDAP_SUCCESS) {
2585 2587                          (void) snprintf(errstr, sizeof (errstr),
2586 2588                              gettext("openConnection: "
2587 2589                              "GSSAPI bind failed "
2588 2590                              "- %d %s"),
2589 2591                              ldap_rc,
2590 2592                              ldap_err2string(ldap_rc));
2591 2593                          (void) ldap_unbind(ld);
2592 2594                          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2593 2595                              strdup(errstr), NS_LDAP_MEMORY);
2594 2596                          return (NS_LDAP_INTERNAL);
2595 2597                  }
2596 2598  
2597 2599                  break;
2598 2600          default:
2599 2601                  (void) ldap_unbind(ld);
2600 2602                  (void) sprintf(errstr,
2601 2603                      gettext("openConnection: unsupported SASL "
2602 2604                      "mechanism (%d)"), auth->auth.saslmech);
2603 2605                  MKERROR(LOG_WARNING, *errorp,
2604 2606                      LDAP_AUTH_METHOD_NOT_SUPPORTED, strdup(errstr),
2605 2607                      NS_LDAP_MEMORY);
2606 2608                  return (NS_LDAP_INTERNAL);
2607 2609          }
2608 2610  
2609 2611          return (ret_code);
2610 2612  }
2611 2613  
2612 2614  /*
2613 2615   * This function performs an LDAP Bind operation proceeding
2614 2616   * from a type of the connection specified by auth->auth.type.
2615 2617   *
2616 2618   * INPUT:
2617 2619   *     auth - a structure specified an authenticastion method and credentials,
2618 2620   *     ld - a pointer returned by the createSession() function,
2619 2621   *     timeoutSec - a timeout in seconds for the Bind operation,
2620 2622   *     fail_if_new_pwd_reqd - a flag indicating that the call should fail
2621 2623   *                            if a new password is required,
2622 2624   *     passwd_mgmt - a flag indicating that the server supports
2623 2625   *                   password management.
2624 2626   *
2625 2627   * OUTPUT:
2626 2628   *     If an error accures, the function returns an NS error code
2627 2629   *     and provides an additional info pointed by *errorp.
2628 2630   */
2629 2631  static
2630 2632  ns_ldap_return_code
2631 2633  performBind(const ns_cred_t *auth,
2632 2634                  LDAP *ld,
2633 2635                  int timeoutSec,
2634 2636                  ns_ldap_error_t **errorp,
2635 2637                  int fail_if_new_pwd_reqd,
2636 2638                  int passwd_mgmt)
2637 2639  {
2638 2640          int     bindType;
2639 2641          char    errstr[MAXERROR];
2640 2642  
2641 2643          ns_ldap_return_code (*binder)(const ns_cred_t *auth,
2642 2644              LDAP *ld,
2643 2645              int timeoutSec,
2644 2646              ns_ldap_error_t **errorp,
2645 2647              int fail_if_new_pwd_reqd,
2646 2648              int passwd_mgmt) = NULL;
2647 2649  
2648 2650          if (!ld) {
2649 2651                  (void) sprintf(errstr,
2650 2652                      "performBind: LDAP session "
2651 2653                      "is not initialized.");
2652 2654                  MKERROR(LOG_WARNING, *errorp,
2653 2655                      LDAP_AUTH_METHOD_NOT_SUPPORTED,
2654 2656                      strdup(errstr), NS_LDAP_MEMORY);
2655 2657                  return (NS_LDAP_INTERNAL);
2656 2658          }
2657 2659  
2658 2660          bindType = auth->auth.type == NS_LDAP_AUTH_TLS ?
2659 2661              auth->auth.tlstype : auth->auth.type;
2660 2662  
2661 2663          switch (bindType) {
2662 2664                  case NS_LDAP_AUTH_NONE:
2663 2665  #ifdef DEBUG
2664 2666                  (void) fprintf(stderr, "tid= %d: +++Anonymous bind\n",
2665 2667                      thr_self());
2666 2668  #endif /* DEBUG */
2667 2669                          break;
2668 2670                  case NS_LDAP_AUTH_SIMPLE:
2669 2671                          binder = doSimpleBind;
2670 2672                          break;
2671 2673                  case NS_LDAP_AUTH_SASL:
2672 2674                          binder = doSASLBind;
2673 2675                          break;
2674 2676                  default:
2675 2677                          (void) sprintf(errstr,
2676 2678                              gettext("openConnection: unsupported "
2677 2679                              "authentication method "
2678 2680                              "(%d)"), bindType);
2679 2681                          MKERROR(LOG_WARNING, *errorp,
2680 2682                              LDAP_AUTH_METHOD_NOT_SUPPORTED,
2681 2683                              strdup(errstr), NS_LDAP_MEMORY);
2682 2684                          (void) ldap_unbind(ld);
2683 2685                          return (NS_LDAP_INTERNAL);
2684 2686          }
2685 2687  
2686 2688          if (binder != NULL) {
2687 2689                  return (*binder)(auth,
2688 2690                      ld,
2689 2691                      timeoutSec,
2690 2692                      errorp,
2691 2693                      fail_if_new_pwd_reqd,
2692 2694                      passwd_mgmt);
2693 2695          }
2694 2696  
2695 2697          return (NS_LDAP_SUCCESS);
2696 2698  }
  
    | ↓ open down ↓ | 1982 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX