Print this page
    
12236 getmembers_DN doesn't properly handle errors from __ns_ldap_dn2uid
12240 nss_ldap does not properly look up group members by distinguished name
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libsldap/common/ns_reads.c
          +++ new/usr/src/lib/libsldap/common/ns_reads.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   * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2020 Joyent, Inc.
  24   25   */
  25   26  
  26   27  #include <stdio.h>
  27   28  #include <sys/types.h>
  28   29  #include <stdlib.h>
  29   30  #include <libintl.h>
  30   31  #include <ctype.h>
  31   32  #include <syslog.h>
  32   33  #include <sys/stat.h>
  33   34  #include <fcntl.h>
  34   35  #include <unistd.h>
  35   36  #include <string.h>
  36   37  #include <strings.h>
  37   38  #include <priv.h>
  38   39  
  39   40  #include "ns_sldap.h"
  40   41  #include "ns_internal.h"
  41   42  #include "ns_cache_door.h"
  42   43  #include "ns_connmgmt.h"
  43   44  
  44   45  #define _NIS_FILTER     "nisdomain=*"
  45   46  #define _NIS_DOMAIN     "nisdomain"
  46   47  static const char *nis_domain_attrs[] = {
  47   48          _NIS_DOMAIN,
  48   49          (char *)NULL
  49   50  };
  50   51  
  51   52  static int validate_filter(ns_ldap_cookie_t *cookie);
  52   53  
  53   54  void
  54   55  __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
  55   56  {
  56   57          int             j, k = 0;
  57   58  
  58   59          if (ep == NULL)
  59   60                  return;
  60   61  
  61   62          if (ep->attr_pair == NULL) {
  62   63                  free(ep);
  63   64                  return;
  64   65          }
  65   66          for (j = 0; j < ep->attr_count; j++) {
  66   67                  if (ep->attr_pair[j] == NULL)
  67   68                          continue;
  68   69                  if (ep->attr_pair[j]->attrname)
  69   70                          free(ep->attr_pair[j]->attrname);
  70   71                  if (ep->attr_pair[j]->attrvalue) {
  71   72                          for (k = 0; (k < ep->attr_pair[j]->value_count) &&
  72   73                              (ep->attr_pair[j]->attrvalue[k]); k++) {
  73   74                                  free(ep->attr_pair[j]->attrvalue[k]);
  74   75                          }
  75   76                          free(ep->attr_pair[j]->attrvalue);
  76   77                  }
  77   78                  free(ep->attr_pair[j]);
  78   79          }
  79   80          free(ep->attr_pair);
  80   81          free(ep);
  81   82  }
  82   83  
  83   84  static void
  84   85  _freeControlList(LDAPControl ***ctrls)
  85   86  {
  86   87          LDAPControl     **ctrl;
  87   88  
  88   89          if (ctrls == NULL || *ctrls == NULL)
  89   90                  return;
  90   91  
  91   92          for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
  92   93                  ldap_control_free(*ctrl);
  93   94          free(*ctrls);
  94   95          *ctrls = NULL;
  95   96  }
  96   97  /*
  97   98   * Convert attribute type in a RDN that has an attribute mapping to the
  98   99   * original mappped type.
  99  100   * e.g.
 100  101   * cn<->cn-st and iphostnumber<->iphostnumber-st
 101  102   * cn-st=aaa+iphostnumber-st=10.10.01.01
 102  103   * is mapped to
 103  104   * cn=aaa+iphostnumber=10.10.01.01
 104  105   *
 105  106   * Input - service: e.g. hosts, passwd etc.
 106  107   *         rdn: RDN
 107  108   * Return: NULL - No attribute mapping in the RDN
 108  109   *         Non-NULL - The attribute type(s) in the RDN are mapped and
 109  110   *                    the memory is allocated for the new rdn.
 110  111   *
 111  112   */
 112  113  static char *
 113  114  _cvtRDN(const char *service, const char *rdn)
 114  115  {
 115  116          char    **attrs, **mapped_attrs, **mapp, *type, *value, *attr;
 116  117          char    *new_rdn = NULL;
 117  118          int     nAttr = 0, i, attr_mapped, len = 0;
 118  119  
 119  120          /* Break down "type=value\0" pairs. Assume RDN is normalized */
 120  121          if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
 121  122                  return (NULL);
 122  123  
 123  124          for (nAttr = 0; attrs[nAttr] != NULL; nAttr++)
 124  125                  ;
 125  126  
 126  127          if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
 127  128                  ldap_value_free(attrs);
 128  129                  return (NULL);
 129  130          }
 130  131  
 131  132          attr_mapped = 0;
 132  133          for (i = 0; i < nAttr; i++) {
 133  134                  /* Parse type=value pair */
 134  135                  if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
 135  136                      value == NULL)
 136  137                          goto cleanup;
 137  138                  /* Reverse map: e.g. cn-sm -> cn */
 138  139                  mapp = __ns_ldap_getOrigAttribute(service, type);
 139  140                  if (mapp != NULL && mapp[0] != NULL) {
 140  141                          /* The attribute mapping is found */
 141  142                          type = mapp[0];
 142  143                          attr_mapped = 1;
 143  144  
 144  145                          /* "type=value\0" */
 145  146                          len = strlen(type) + strlen(value) + 2;
 146  147  
 147  148                          /* Reconstruct type=value pair. A string is allocated */
 148  149                          if ((attr = (char *)calloc(1, len)) == NULL) {
 149  150                                  __s_api_free2dArray(mapp);
 150  151                                  goto cleanup;
 151  152                          }
 152  153                          (void) snprintf(attr, len, "%s=%s", type, value);
 153  154                          mapped_attrs[i] = attr;
 154  155                  } else {
 155  156                          /*
 156  157                           * No attribute mapping. attrs[i] is going to be copied
 157  158                           * later. Restore "type\0value\0" back to
 158  159                           * "type=value\0".
 159  160                           */
 160  161                          type[strlen(type)] = '=';
 161  162                  }
 162  163                  __s_api_free2dArray(mapp);
 163  164          }
 164  165          if (attr_mapped == 0)
 165  166                  /* No attribute mapping. Don't bother to reconstruct RDN */
 166  167                  goto cleanup;
 167  168  
 168  169          len = 0;
 169  170          /* Reconstruct RDN from type=value pairs */
 170  171          for (i = 0; i < nAttr; i++) {
 171  172                  if (mapped_attrs[i])
 172  173                          len += strlen(mapped_attrs[i]);
 173  174                  else
 174  175                          len += strlen(attrs[i]);
 175  176                  /* Add 1 for "+" */
 176  177                  len++;
 177  178          }
 178  179          if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
 179  180                  goto cleanup;
 180  181          for (i = 0; i < nAttr; i++) {
 181  182                  if (i > 0)
 182  183                          /* Add seperator */
 183  184                          (void) strlcat(new_rdn, "+", len);
 184  185  
 185  186                  if (mapped_attrs[i])
 186  187                          (void) strlcat(new_rdn, mapped_attrs[i], len);
 187  188                  else
 188  189                          (void) strlcat(new_rdn, attrs[i], len);
 189  190  
 190  191          }
 191  192  cleanup:
 192  193          ldap_value_free(attrs);
 193  194          if (mapped_attrs) {
 194  195                  if (attr_mapped) {
 195  196                          for (i = 0; i < nAttr; i++) {
 196  197                                  if (mapped_attrs[i])
 197  198                                          free(mapped_attrs[i]);
 198  199                          }
 199  200                  }
 200  201                  free(mapped_attrs);
 201  202          }
 202  203  
 203  204          return (new_rdn);
 204  205  }
 205  206  /*
 206  207   * Convert attribute type in a DN that has an attribute mapping to the
 207  208   * original mappped type.
 208  209   * e.g
 209  210   * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
 210  211   *
 211  212   * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
 212  213   * is converted to
 213  214   * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
 214  215   *
 215  216   * Input - service: e.g. hosts, passwd etc.
 216  217   *         dn: the value of a distinguished name
 217  218   * Return - NULL: error
 218  219   *          non-NULL: A converted DN and the memory is allocated
 219  220   */
 220  221  static char *
 221  222  _cvtDN(const char *service, const char *dn)
 222  223  {
 223  224          char    **mapped_rdns;
 224  225          char    **rdns, *new_rdn, *new_dn = NULL;
 225  226          int     nRdn = 0, i, len = 0, rdn_mapped;
 226  227  
 227  228          if (service == NULL || dn == NULL)
 228  229                  return (NULL);
 229  230  
 230  231          if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
 231  232                  return (NULL);
 232  233  
 233  234          for (nRdn = 0; rdns[nRdn] != NULL; nRdn++)
 234  235                  ;
 235  236  
 236  237          if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
 237  238                  ldap_value_free(rdns);
 238  239                  return (NULL);
 239  240          }
 240  241  
 241  242          rdn_mapped = 0;
 242  243          /* Break down RDNs in a DN */
 243  244          for (i = 0; i < nRdn; i++) {
 244  245                  if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
 245  246                          mapped_rdns[i] = new_rdn;
 246  247                          rdn_mapped = 1;
 247  248                  }
 248  249          }
 249  250          if (rdn_mapped == 0) {
 250  251                  /*
 251  252                   * No RDN contains any attribute mapping.
 252  253                   * Don't bother to reconstruct DN from RDN. Copy DN directly.
 253  254                   */
 254  255                  new_dn = strdup(dn);
 255  256                  goto cleanup;
 256  257          }
 257  258          /*
 258  259           * Reconstruct dn from RDNs.
 259  260           * Calculate the length first.
 260  261           */
 261  262          for (i = 0; i < nRdn; i++) {
 262  263                  if (mapped_rdns[i])
 263  264                          len += strlen(mapped_rdns[i]);
 264  265                  else
 265  266                          len += strlen(rdns[i]);
 266  267  
 267  268                  /* add 1 for ',' */
 268  269                  len ++;
 269  270          }
 270  271          if ((new_dn = (char *)calloc(1, ++len)) == NULL)
 271  272                  goto cleanup;
 272  273          for (i = 0; i < nRdn; i++) {
 273  274                  if (i > 0)
 274  275                          /* Add seperator */
 275  276                          (void) strlcat(new_dn, ",", len);
 276  277  
 277  278                  if (mapped_rdns[i])
 278  279                          (void) strlcat(new_dn, mapped_rdns[i], len);
 279  280                  else
 280  281                          (void) strlcat(new_dn, rdns[i], len);
 281  282  
 282  283          }
 283  284  
 284  285  cleanup:
 285  286          ldap_value_free(rdns);
 286  287          if (mapped_rdns) {
 287  288                  if (rdn_mapped) {
 288  289                          for (i = 0; i < nRdn; i++) {
 289  290                                  if (mapped_rdns[i])
 290  291                                          free(mapped_rdns[i]);
 291  292                          }
 292  293                  }
 293  294                  free(mapped_rdns);
 294  295          }
 295  296  
 296  297          return (new_dn);
 297  298  }
 298  299  /*
 299  300   * Convert a single ldap entry from a LDAPMessage
 300  301   * into an ns_ldap_entry structure.
 301  302   * Schema map the entry if specified in flags
 302  303   */
 303  304  
 304  305  static int
 305  306  __s_api_cvtEntry(LDAP *ld, const char *service, LDAPMessage *e, int flags,
 306  307      ns_ldap_entry_t **ret, ns_ldap_error_t **error)
 307  308  {
 308  309  
 309  310          ns_ldap_entry_t *ep = NULL;
 310  311          ns_ldap_attr_t  **ap = NULL;
 311  312          BerElement      *ber;
 312  313          char            *attr = NULL;
 313  314          char            **vals = NULL;
 314  315          char            **mapping;
 315  316          char            *dn;
 316  317          int             nAttrs = 0;
 317  318          int             i, j, k = 0;
 318  319          char            **gecos_mapping = NULL;
 319  320          int             gecos_val_index[3] = { -1, -1, -1};
 320  321          char            errstr[MAXERROR];
 321  322          int             schema_mapping_existed = FALSE;
 322  323          int             gecos_mapping_existed = FALSE;
 323  324          int             gecos_attr_matched;
 324  325          int             auto_service = FALSE;
 325  326          int             rc = NS_LDAP_SUCCESS;
 326  327  
 327  328          if (e == NULL || ret == NULL || error == NULL)
 328  329                  return (NS_LDAP_INVALID_PARAM);
 329  330  
 330  331          *error = NULL;
 331  332  
 332  333          ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
 333  334          if (ep == NULL)
 334  335                  return (NS_LDAP_MEMORY);
 335  336  
 336  337          if (service != NULL &&
 337  338              (strncasecmp(service, "auto_", 5) == 0 ||
 338  339              strcasecmp(service, "automount") == 0))
 339  340                  auto_service = TRUE;
 340  341          /*
 341  342           * see if schema mapping existed for the given service
 342  343           */
 343  344          mapping = __ns_ldap_getOrigAttribute(service,
 344  345              NS_HASH_SCHEMA_MAPPING_EXISTED);
 345  346          if (mapping) {
 346  347                  schema_mapping_existed = TRUE;
 347  348                  __s_api_free2dArray(mapping);
 348  349                  mapping = NULL;
 349  350          } else if (auto_service) {
 350  351                  /*
 351  352                   * If service == auto_* and no
 352  353                   * schema mapping found
 353  354                   * then try automount
 354  355                   * There is certain case that schema mapping exist
 355  356                   * but __ns_ldap_getOrigAttribute(service,
 356  357                   *      NS_HASH_SCHEMA_MAPPING_EXISTED);
 357  358                   * returns NULL.
 358  359                   * e.g.
 359  360                   * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
 360  361                   * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
 361  362                   * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
 362  363                   *
 363  364                   * Make a check for schema_mapping_existed here
 364  365                   * so later on __s_api_convert_automountmapname won't be called
 365  366                   * unnecessarily. It is also used for attribute mapping
 366  367                   * and objectclass mapping.
 367  368                   */
 368  369                  mapping = __ns_ldap_getOrigAttribute("automount",
 369  370                      NS_HASH_SCHEMA_MAPPING_EXISTED);
 370  371                  if (mapping) {
 371  372                          schema_mapping_existed = TRUE;
 372  373                          __s_api_free2dArray(mapping);
 373  374                          mapping = NULL;
 374  375                  }
 375  376          }
 376  377  
 377  378          nAttrs = 1;  /* start with 1 for the DN attr */
 378  379          for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
 379  380              attr = ldap_next_attribute(ld, e, ber)) {
 380  381                  nAttrs++;
 381  382                  ldap_memfree(attr);
 382  383                  attr = NULL;
 383  384          }
 384  385          ber_free(ber, 0);
 385  386          ber = NULL;
 386  387  
 387  388          ep->attr_count = nAttrs;
 388  389  
 389  390          /*
 390  391           * add 1 for "gecos" 1 to N attribute mapping,
 391  392           * just in case it is needed.
 392  393           * ep->attr_count will be updated later if that is true.
 393  394           */
 394  395          ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
 395  396              sizeof (ns_ldap_attr_t *));
 396  397          if (ap == NULL) {
 397  398                  __ns_ldap_freeEntry(ep);
 398  399                  ep = NULL;
 399  400                  return (NS_LDAP_MEMORY);
 400  401          }
 401  402          ep->attr_pair = ap;
 402  403  
 403  404          /* DN attribute */
 404  405          dn = ldap_get_dn(ld, e);
 405  406          ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
 406  407          if (ap[0] == NULL) {
 407  408                  ldap_memfree(dn);
 408  409                  dn = NULL;
 409  410                  __ns_ldap_freeEntry(ep);
 410  411                  ep = NULL;
 411  412                  return (NS_LDAP_MEMORY);
 412  413          }
 413  414  
 414  415          if ((ap[0]->attrname = strdup("dn")) == NULL) {
 415  416                  ldap_memfree(dn);
 416  417                  dn = NULL;
 417  418                  __ns_ldap_freeEntry(ep);
 418  419                  ep = NULL;
 419  420                  return (NS_LDAP_INVALID_PARAM);
 420  421          }
 421  422          ap[0]->value_count = 1;
 422  423          if ((ap[0]->attrvalue = (char **)
 423  424              calloc(2, sizeof (char *))) == NULL) {
 424  425                  ldap_memfree(dn);
 425  426                  dn = NULL;
 426  427                  __ns_ldap_freeEntry(ep);
 427  428                  ep = NULL;
 428  429                  return (NS_LDAP_MEMORY);
 429  430          }
 430  431  
 431  432          if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
 432  433                  ap[0]->attrvalue[0] = _cvtDN(service, dn);
 433  434          else
 434  435                  ap[0]->attrvalue[0] = strdup(dn);
 435  436  
 436  437          if (ap[0]->attrvalue[0] == NULL) {
 437  438                  ldap_memfree(dn);
 438  439                  dn = NULL;
 439  440                  __ns_ldap_freeEntry(ep);
 440  441                  ep = NULL;
 441  442                  return (NS_LDAP_MEMORY);
 442  443          }
 443  444          ldap_memfree(dn);
 444  445          dn = NULL;
 445  446  
 446  447          if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
 447  448              schema_mapping_existed) {
 448  449                  rc = __s_api_convert_automountmapname(service,
 449  450                      &ap[0]->attrvalue[0],
 450  451                      error);
 451  452                  if (rc != NS_LDAP_SUCCESS) {
 452  453                          __ns_ldap_freeEntry(ep);
 453  454                          ep = NULL;
 454  455                          return (rc);
 455  456                  }
 456  457          }
 457  458  
 458  459          /* other attributes */
 459  460          for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
 460  461              attr != NULL && j != nAttrs;
 461  462              attr = ldap_next_attribute(ld, e, ber), j++) {
 462  463                  /* allocate new attr name */
 463  464  
 464  465                  if ((ap[j] = (ns_ldap_attr_t *)
 465  466                      calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
 466  467                          ber_free(ber, 0);
 467  468                          ber = NULL;
 468  469                          __ns_ldap_freeEntry(ep);
 469  470                          ep = NULL;
 470  471                          if (gecos_mapping)
 471  472                                  __s_api_free2dArray(gecos_mapping);
 472  473                          gecos_mapping = NULL;
 473  474                          return (NS_LDAP_MEMORY);
 474  475                  }
 475  476  
 476  477                  if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
 477  478                          mapping = NULL;
 478  479                  else
 479  480                          mapping = __ns_ldap_getOrigAttribute(service, attr);
 480  481  
 481  482                  if (mapping == NULL && auto_service &&
 482  483                      schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
 483  484                          /*
 484  485                           * if service == auto_* and no schema mapping found
 485  486                           * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
 486  487                           * is not set then try automount e.g.
 487  488                           * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
 488  489                           */
 489  490                          mapping = __ns_ldap_getOrigAttribute("automount",
 490  491                              attr);
 491  492  
 492  493                  if (mapping == NULL) {
 493  494                          if ((ap[j]->attrname = strdup(attr)) == NULL) {
 494  495                                  ber_free(ber, 0);
 495  496                                  ber = NULL;
 496  497                                  __ns_ldap_freeEntry(ep);
 497  498                                  ep = NULL;
 498  499                                  if (gecos_mapping)
 499  500                                          __s_api_free2dArray(gecos_mapping);
 500  501                                  gecos_mapping = NULL;
 501  502                                  return (NS_LDAP_MEMORY);
 502  503                          }
 503  504                  } else {
 504  505                          /*
 505  506                           * for "gecos" 1 to N mapping,
 506  507                           * do not remove the mapped attribute,
 507  508                           * just create a new gecos attribute
 508  509                           * and append it to the end of the attribute list
 509  510                           */
 510  511                          if (strcasecmp(mapping[0], "gecos") == 0) {
 511  512                                  ap[j]->attrname = strdup(attr);
 512  513                                  gecos_mapping_existed = TRUE;
 513  514                          } else {
 514  515                                  ap[j]->attrname = strdup(mapping[0]);
 515  516                          }
 516  517  
 517  518                          if (ap[j]->attrname == NULL) {
 518  519                                  ber_free(ber, 0);
 519  520                                  ber = NULL;
 520  521                                  __ns_ldap_freeEntry(ep);
 521  522                                  ep = NULL;
 522  523                                  if (gecos_mapping)
 523  524                                          __s_api_free2dArray(gecos_mapping);
 524  525                                  gecos_mapping = NULL;
 525  526                                  return (NS_LDAP_MEMORY);
 526  527                          }
 527  528                          /*
 528  529                           * 1 to N attribute mapping processing
 529  530                           * is only done for "gecos"
 530  531                           */
 531  532  
 532  533                          if (strcasecmp(mapping[0], "gecos") == 0) {
 533  534                                  /*
 534  535                                   * get attribute mapping for "gecos",
 535  536                                   * need to know the number and order of the
 536  537                                   * mapped attributes
 537  538                                   */
 538  539                                  if (gecos_mapping == NULL) {
 539  540                                          gecos_mapping =
 540  541                                              __ns_ldap_getMappedAttributes(
 541  542                                              service, mapping[0]);
 542  543                                          if (gecos_mapping == NULL ||
 543  544                                              gecos_mapping[0] == NULL) {
 544  545                                                  /*
 545  546                                                   * this should never happens,
 546  547                                                   * syslog the error
 547  548                                                   */
 548  549                                                  (void) sprintf(errstr,
 549  550                                                      gettext(
 550  551                                                      "Attribute mapping "
 551  552                                                      "inconsistency "
 552  553                                                      "found for attributes "
 553  554                                                      "'%s' and '%s'."),
 554  555                                                      mapping[0], attr);
 555  556                                                  syslog(LOG_ERR, "libsldap: %s",
 556  557                                                      errstr);
 557  558  
 558  559                                                  ber_free(ber, 0);
 559  560                                                  ber = NULL;
 560  561                                                  __ns_ldap_freeEntry(ep);
 561  562                                                  ep = NULL;
 562  563                                                  __s_api_free2dArray(mapping);
 563  564                                                  mapping = NULL;
 564  565                                                  if (gecos_mapping)
 565  566                                                          __s_api_free2dArray(
 566  567                                                              gecos_mapping);
 567  568                                                  gecos_mapping = NULL;
 568  569                                                  return (NS_LDAP_INTERNAL);
 569  570                                          }
 570  571                                  }
 571  572  
 572  573                                  /*
 573  574                                   * is this attribute the 1st, 2nd, or
 574  575                                   * 3rd attr in the mapping list?
 575  576                                   */
 576  577                                  gecos_attr_matched = FALSE;
 577  578                                  for (i = 0; i < 3 && gecos_mapping[i]; i++) {
 578  579                                          if (gecos_mapping[i] &&
 579  580                                              strcasecmp(gecos_mapping[i],
 580  581                                              attr) == 0) {
 581  582                                                  gecos_val_index[i] = j;
 582  583                                                  gecos_attr_matched = TRUE;
 583  584                                                  break;
 584  585                                          }
 585  586                                  }
 586  587                                  if (gecos_attr_matched == FALSE) {
 587  588                                          /*
 588  589                                           * Not match found.
 589  590                                           * This should never happens,
 590  591                                           * syslog the error
 591  592                                           */
 592  593                                          (void) sprintf(errstr,
 593  594                                              gettext(
 594  595                                              "Attribute mapping "
 595  596                                              "inconsistency "
 596  597                                              "found for attributes "
 597  598                                              "'%s' and '%s'."),
 598  599                                              mapping[0], attr);
 599  600                                          syslog(LOG_ERR, "libsldap: %s", errstr);
 600  601  
 601  602                                          ber_free(ber, 0);
 602  603                                          ber = NULL;
 603  604                                          __ns_ldap_freeEntry(ep);
 604  605                                          ep = NULL;
 605  606                                          __s_api_free2dArray(mapping);
 606  607                                          mapping = NULL;
 607  608                                          __s_api_free2dArray(gecos_mapping);
 608  609                                          gecos_mapping = NULL;
 609  610                                          return (NS_LDAP_INTERNAL);
 610  611                                  }
 611  612                          }
 612  613                          __s_api_free2dArray(mapping);
 613  614                          mapping = NULL;
 614  615                  }
 615  616  
 616  617                  if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
 617  618  
 618  619                          if ((ap[j]->value_count =
 619  620                              ldap_count_values(vals)) == 0) {
 620  621                                  ldap_value_free(vals);
 621  622                                  vals = NULL;
 622  623                                  continue;
 623  624                          } else {
 624  625                                  ap[j]->attrvalue = (char **)
 625  626                                      calloc(ap[j]->value_count+1,
 626  627                                      sizeof (char *));
 627  628                                  if (ap[j]->attrvalue == NULL) {
 628  629                                          ber_free(ber, 0);
 629  630                                          ber = NULL;
 630  631                                          __ns_ldap_freeEntry(ep);
 631  632                                          ep = NULL;
 632  633                                          if (gecos_mapping)
 633  634                                                  __s_api_free2dArray(
 634  635                                                      gecos_mapping);
 635  636                                          gecos_mapping = NULL;
 636  637                                          return (NS_LDAP_MEMORY);
 637  638                                  }
 638  639                          }
 639  640  
 640  641                          /* map object classes if necessary */
 641  642                          if ((flags & NS_LDAP_NOMAP) == 0 &&
 642  643                              schema_mapping_existed && ap[j]->attrname &&
 643  644                              strcasecmp(ap[j]->attrname, "objectclass") == 0) {
 644  645                                  for (k = 0; k < ap[j]->value_count; k++) {
 645  646                                          mapping =
 646  647                                              __ns_ldap_getOrigObjectClass(
 647  648                                              service, vals[k]);
 648  649  
 649  650                                          if (mapping == NULL && auto_service)
 650  651                                                  /*
 651  652                                                   * if service == auto_* and no
 652  653                                                   * schema mapping found
 653  654                                                   * then try automount
 654  655                                                   */
 655  656                                          mapping =
 656  657                                              __ns_ldap_getOrigObjectClass(
 657  658                                              "automount", vals[k]);
 658  659  
 659  660                                          if (mapping == NULL) {
 660  661                                                  ap[j]->attrvalue[k] =
 661  662                                                      strdup(vals[k]);
 662  663                                          } else {
 663  664                                                  ap[j]->attrvalue[k] =
 664  665                                                      strdup(mapping[0]);
 665  666                                                  __s_api_free2dArray(mapping);
 666  667                                                  mapping = NULL;
 667  668                                          }
 668  669                                          if (ap[j]->attrvalue[k] == NULL) {
 669  670                                                  ber_free(ber, 0);
 670  671                                                  ber = NULL;
 671  672                                                  __ns_ldap_freeEntry(ep);
 672  673                                                  ep = NULL;
 673  674                                                  if (gecos_mapping)
 674  675                                                          __s_api_free2dArray(
 675  676                                                              gecos_mapping);
 676  677                                                  gecos_mapping = NULL;
 677  678                                                  return (NS_LDAP_MEMORY);
 678  679                                          }
 679  680                                  }
 680  681                          } else {
 681  682                                  for (k = 0; k < ap[j]->value_count; k++) {
 682  683                                          if ((ap[j]->attrvalue[k] =
 683  684                                              strdup(vals[k])) == NULL) {
 684  685                                                  ber_free(ber, 0);
 685  686                                                  ber = NULL;
 686  687                                                  __ns_ldap_freeEntry(ep);
 687  688                                                  ep = NULL;
 688  689                                                  if (gecos_mapping)
 689  690                                                          __s_api_free2dArray(
 690  691                                                              gecos_mapping);
 691  692                                                  gecos_mapping = NULL;
 692  693                                                  return (NS_LDAP_MEMORY);
 693  694                                          }
 694  695                                  }
 695  696                          }
 696  697  
 697  698                          ap[j]->attrvalue[k] = NULL;
 698  699                          ldap_value_free(vals);
 699  700                          vals = NULL;
 700  701                  }
 701  702  
 702  703                  ldap_memfree(attr);
 703  704                  attr = NULL;
 704  705          }
 705  706  
 706  707          ber_free(ber, 0);
 707  708          ber = NULL;
 708  709  
 709  710          if (gecos_mapping) {
 710  711                  __s_api_free2dArray(gecos_mapping);
 711  712                  gecos_mapping = NULL;
 712  713          }
 713  714  
 714  715          /* special processing for gecos 1 to up to 3 attribute mapping */
 715  716          if (schema_mapping_existed && gecos_mapping_existed) {
 716  717  
 717  718                  int     f = -1;
 718  719  
 719  720                  for (i = 0; i < 3; i++) {
 720  721                          k = gecos_val_index[i];
 721  722  
 722  723                          /*
 723  724                           * f is the index of the first returned
 724  725                           * attribute which "gecos" attribute mapped to
 725  726                           */
 726  727                          if (k != -1 && f == -1)
 727  728                                  f = k;
 728  729  
 729  730                          if (k != -1 && ap[k]->value_count > 0 &&
 730  731                              ap[k]->attrvalue[0] &&
 731  732                              strlen(ap[k]->attrvalue[0]) > 0) {
 732  733  
 733  734                                  if (k == f) {
 734  735                                          /*
 735  736                                           * Create and fill in the last reserved
 736  737                                           * ap with the data from the "gecos"
 737  738                                           * mapping attributes
 738  739                                           */
 739  740                                          ap[nAttrs] = (ns_ldap_attr_t *)
 740  741                                              calloc(1,
 741  742                                              sizeof (ns_ldap_attr_t));
 742  743                                          if (ap[nAttrs] == NULL) {
 743  744                                                  __ns_ldap_freeEntry(ep);
 744  745                                                  ep = NULL;
 745  746                                                  return (NS_LDAP_MEMORY);
 746  747                                          }
 747  748                                          ap[nAttrs]->attrvalue = (char **)calloc(
 748  749                                              2, sizeof (char *));
 749  750                                          if (ap[nAttrs]->attrvalue == NULL) {
 750  751                                                  __ns_ldap_freeEntry(ep);
 751  752                                                  ep = NULL;
 752  753                                                  return (NS_LDAP_MEMORY);
 753  754                                          }
 754  755                                          /* add 1 more for a possible "," */
 755  756                                          ap[nAttrs]->attrvalue[0] =
 756  757                                              (char *)calloc(
 757  758                                              strlen(ap[f]->attrvalue[0]) +
 758  759                                              2, 1);
 759  760                                          if (ap[nAttrs]->attrvalue[0] == NULL) {
 760  761                                                  __ns_ldap_freeEntry(ep);
 761  762                                                  ep = NULL;
 762  763                                                  return (NS_LDAP_MEMORY);
 763  764                                          }
 764  765                                          (void) strcpy(ap[nAttrs]->attrvalue[0],
 765  766                                              ap[f]->attrvalue[0]);
 766  767  
 767  768                                          ap[nAttrs]->attrname = strdup("gecos");
 768  769                                          if (ap[nAttrs]->attrname == NULL) {
 769  770                                                  __ns_ldap_freeEntry(ep);
 770  771                                                  ep = NULL;
 771  772                                                  return (NS_LDAP_MEMORY);
 772  773                                          }
 773  774  
 774  775                                          ap[nAttrs]->value_count = 1;
 775  776                                          ep->attr_count = nAttrs + 1;
 776  777  
 777  778                                  } else {
 778  779                                          char    *tmp = NULL;
 779  780  
 780  781                                          /*
 781  782                                           * realloc to add "," and
 782  783                                           * ap[k]->attrvalue[0]
 783  784                                           */
 784  785                                          tmp = (char *)realloc(
 785  786                                              ap[nAttrs]->attrvalue[0],
 786  787                                              strlen(ap[nAttrs]->
 787  788                                              attrvalue[0]) +
 788  789                                              strlen(ap[k]->
 789  790                                              attrvalue[0]) + 2);
 790  791                                          if (tmp == NULL) {
 791  792                                                  __ns_ldap_freeEntry(ep);
 792  793                                                  ep = NULL;
 793  794                                                  return (NS_LDAP_MEMORY);
 794  795                                          }
 795  796                                          ap[nAttrs]->attrvalue[0] = tmp;
 796  797                                          (void) strcat(ap[nAttrs]->attrvalue[0],
 797  798                                              ",");
 798  799                                          (void) strcat(ap[nAttrs]->attrvalue[0],
 799  800                                              ap[k]->attrvalue[0]);
 800  801                                  }
 801  802                          }
 802  803                  }
 803  804          }
 804  805  
 805  806          *ret = ep;
 806  807          return (NS_LDAP_SUCCESS);
 807  808  }
 808  809  
 809  810  static int
 810  811  __s_api_getEntry(ns_ldap_cookie_t *cookie)
 811  812  {
 812  813          ns_ldap_entry_t *curEntry = NULL;
 813  814          int             ret;
 814  815  
 815  816  #ifdef DEBUG
 816  817          (void) fprintf(stderr, "__s_api_getEntry START\n");
 817  818  #endif
 818  819  
 819  820          if (cookie->resultMsg == NULL) {
 820  821                  return (NS_LDAP_INVALID_PARAM);
 821  822          }
 822  823          ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
 823  824              cookie->resultMsg, cookie->i_flags,
 824  825              &curEntry, &cookie->errorp);
 825  826          if (ret != NS_LDAP_SUCCESS) {
 826  827                  return (ret);
 827  828          }
 828  829  
 829  830          if (cookie->result == NULL) {
 830  831                  cookie->result = (ns_ldap_result_t *)
 831  832                      calloc(1, sizeof (ns_ldap_result_t));
 832  833                  if (cookie->result == NULL) {
 833  834                          __ns_ldap_freeEntry(curEntry);
 834  835                          curEntry = NULL;
 835  836                          return (NS_LDAP_MEMORY);
 836  837                  }
 837  838                  cookie->result->entry = curEntry;
 838  839                  cookie->nextEntry = curEntry;
 839  840          } else {
 840  841                  cookie->nextEntry->next = curEntry;
 841  842                  cookie->nextEntry = curEntry;
 842  843          }
 843  844          cookie->result->entries_count++;
 844  845  
 845  846          return (NS_LDAP_SUCCESS);
 846  847  }
 847  848  
 848  849  static int
 849  850  __s_api_get_cachemgr_data(const char *type, const char *from, char **to)
 850  851  {
 851  852          union {
 852  853                  ldap_data_t     s_d;
 853  854                  char            s_b[DOORBUFFERSIZE];
 854  855          } space;
 855  856          ldap_data_t     *sptr;
 856  857          int             ndata;
 857  858          int             adata;
 858  859          int             rc;
 859  860  
 860  861  #ifdef DEBUG
 861  862          (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
 862  863  #endif
 863  864          /*
 864  865           * We are not going to perform DN to domain mapping
 865  866           * in the Standalone mode
 866  867           */
 867  868          if (__s_api_isStandalone()) {
 868  869                  return (-1);
 869  870          }
 870  871  
 871  872          if (from == NULL || from[0] == '\0' || to == NULL)
 872  873                  return (-1);
 873  874  
 874  875          *to = NULL;
 875  876          (void) memset(space.s_b, 0, DOORBUFFERSIZE);
 876  877  
 877  878          space.s_d.ldap_call.ldap_callnumber = GETCACHE;
 878  879          (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
 879  880              DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
 880  881              "%s%s%s",
 881  882              type,
 882  883              DOORLINESEP,
 883  884              from);
 884  885          ndata = sizeof (space);
 885  886          adata = sizeof (ldap_call_t) +
 886  887              strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
 887  888          sptr = &space.s_d;
 888  889  
 889  890          rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
 890  891          if (rc != NS_CACHE_SUCCESS)
 891  892                  return (-1);
 892  893          else
 893  894                  *to = strdup(sptr->ldap_ret.ldap_u.buff);
 894  895          return (NS_LDAP_SUCCESS);
 895  896  }
 896  897  
 897  898  static int
 898  899  __s_api_set_cachemgr_data(const char *type, const char *from, const char *to)
 899  900  {
 900  901          union {
 901  902                  ldap_data_t     s_d;
 902  903                  char            s_b[DOORBUFFERSIZE];
 903  904          } space;
 904  905          ldap_data_t     *sptr;
 905  906          int             ndata;
 906  907          int             adata;
 907  908          int             rc;
 908  909  
 909  910  #ifdef DEBUG
 910  911          (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
 911  912  #endif
 912  913          /*
 913  914           * We are not going to perform DN to domain mapping
 914  915           * in the Standalone mode
 915  916           */
 916  917          if (__s_api_isStandalone()) {
 917  918                  return (-1);
 918  919          }
 919  920  
 920  921          if ((from == NULL) || (from[0] == '\0') ||
 921  922              (to == NULL) || (to[0] == '\0'))
 922  923                  return (-1);
 923  924  
 924  925          (void) memset(space.s_b, 0, DOORBUFFERSIZE);
 925  926  
 926  927          space.s_d.ldap_call.ldap_callnumber = SETCACHE;
 927  928          (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
 928  929              DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
 929  930              "%s%s%s%s%s",
 930  931              type,
 931  932              DOORLINESEP,
 932  933              from,
 933  934              DOORLINESEP,
 934  935              to);
 935  936  
 936  937          ndata = sizeof (space);
 937  938          adata = sizeof (ldap_call_t) +
 938  939              strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
 939  940          sptr = &space.s_d;
 940  941  
 941  942          rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
 942  943          if (rc != NS_CACHE_SUCCESS)
 943  944                  return (-1);
 944  945  
 945  946          return (NS_LDAP_SUCCESS);
 946  947  }
 947  948  
 948  949  
 949  950  static char *
 950  951  __s_api_remove_rdn_space(char *rdn)
 951  952  {
 952  953          char    *tf, *tl, *vf, *vl, *eqsign;
 953  954  
 954  955          /* if no space(s) to remove, return */
 955  956          if (strchr(rdn, SPACETOK) == NULL)
 956  957                  return (rdn);
 957  958  
 958  959          /* if no '=' separator, return */
 959  960          eqsign = strchr(rdn, '=');
 960  961          if (eqsign == NULL)
 961  962                  return (rdn);
 962  963  
 963  964          tf = rdn;
 964  965          tl = eqsign - 1;
 965  966          vf = eqsign + 1;
 966  967          vl = rdn + strlen(rdn) - 1;
 967  968  
 968  969          /* now two strings, type and value */
 969  970          *eqsign = '\0';
 970  971  
 971  972          /* remove type's leading spaces */
 972  973          while (tf < tl && *tf == SPACETOK)
 973  974                  tf++;
 974  975          /* remove type's trailing spaces */
 975  976          while (tf < tl && *tl == SPACETOK)
 976  977                  tl--;
 977  978          /* add '=' separator back */
 978  979          *(++tl) = '=';
 979  980          /* remove value's leading spaces */
 980  981          while (vf < vl && *vf == SPACETOK)
 981  982                  vf++;
 982  983          /* remove value's trailing spaces */
 983  984          while (vf < vl && *vl == SPACETOK)
 984  985                  *vl-- = '\0';
 985  986  
 986  987          /* move value up if necessary */
 987  988          if (vf != tl + 1)
 988  989                  (void) strcpy(tl + 1, vf);
 989  990  
 990  991          return (tf);
 991  992  }
 992  993  
 993  994  static
 994  995  ns_ldap_cookie_t *
 995  996  init_search_state_machine()
 996  997  {
 997  998          ns_ldap_cookie_t        *cookie;
 998  999          ns_config_t             *cfg;
 999 1000  
1000 1001          cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
1001 1002          if (cookie == NULL)
1002 1003                  return (NULL);
1003 1004          cookie->state = INIT;
1004 1005          /* assign other state variables */
1005 1006          cfg = __s_api_loadrefresh_config();
1006 1007          cookie->connectionId = -1;
1007 1008          if (cfg == NULL ||
1008 1009              cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
1009 1010                  cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
1010 1011          } else {
1011 1012                  cookie->search_timeout.tv_sec =
1012 1013                      cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
1013 1014          }
1014 1015          if (cfg != NULL)
1015 1016                  __s_api_release_config(cfg);
1016 1017          cookie->search_timeout.tv_usec = 0;
1017 1018  
1018 1019          return (cookie);
1019 1020  }
1020 1021  
1021 1022  static void
1022 1023  delete_search_cookie(ns_ldap_cookie_t *cookie)
1023 1024  {
1024 1025          if (cookie == NULL)
1025 1026                  return;
1026 1027          if (cookie->connectionId > -1)
1027 1028                  DropConnection(cookie->connectionId, cookie->i_flags);
1028 1029          if (cookie->filter)
1029 1030                  free(cookie->filter);
1030 1031          if (cookie->i_filter)
1031 1032                  free(cookie->i_filter);
1032 1033          if (cookie->service)
1033 1034                  free(cookie->service);
1034 1035          if (cookie->sdlist)
1035 1036                  (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
1036 1037          if (cookie->result)
1037 1038                  (void) __ns_ldap_freeResult(&cookie->result);
1038 1039          if (cookie->attribute)
1039 1040                  __s_api_free2dArray(cookie->attribute);
1040 1041          if (cookie->errorp)
1041 1042                  (void) __ns_ldap_freeError(&cookie->errorp);
1042 1043          if (cookie->reflist)
1043 1044                  __s_api_deleteRefInfo(cookie->reflist);
1044 1045          if (cookie->basedn)
1045 1046                  free(cookie->basedn);
1046 1047          if (cookie->ctrlCookie)
1047 1048                  ber_bvfree(cookie->ctrlCookie);
1048 1049          _freeControlList(&cookie->p_serverctrls);
1049 1050          if (cookie->resultctrl)
1050 1051                  ldap_controls_free(cookie->resultctrl);
1051 1052          free(cookie);
1052 1053  }
1053 1054  
1054 1055  static int
1055 1056  get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
1056 1057  {
1057 1058  
1058 1059          typedef struct  filter_mapping_info {
1059 1060                  char    oc_or_attr;
1060 1061                  char    *name_start;
1061 1062                  char    *name_end;
1062 1063                  char    *veq_pos;
1063 1064                  char    *from_name;
1064 1065                  char    *to_name;
1065 1066                  char    **mapping;
1066 1067          } filter_mapping_info_t;
1067 1068  
1068 1069          char                    *c, *last_copied;
1069 1070          char                    *filter_c, *filter_c_next;
1070 1071          char                    *key, *tail, *head;
1071 1072          char                    errstr[MAXERROR];
1072 1073          int                     num_eq = 0, num_veq = 0;
1073 1074          boolean_t               in_quote = B_FALSE;
1074 1075          boolean_t               is_value = B_FALSE;
1075 1076          int                     i, j, oc_len, len;
1076 1077          boolean_t               at_least_one = B_FALSE;
1077 1078          filter_mapping_info_t   **info, *info1;
1078 1079          char                    **mapping;
1079 1080          char                    *service, *filter, *err;
1080 1081          boolean_t               auto_service = B_FALSE;
1081 1082  
1082 1083          if (cookie == NULL || new_filter == NULL)
1083 1084                  return (NS_LDAP_INVALID_PARAM);
1084 1085  
1085 1086          *new_filter = NULL;
1086 1087          service = cookie->service;
1087 1088          filter = cookie->filter;
1088 1089  
1089 1090          /*
1090 1091           * count the number of '=' char
1091 1092           */
1092 1093          for (c = filter; *c; c++) {
1093 1094                  if (*c == TOKENSEPARATOR)
1094 1095                          num_eq++;
1095 1096          }
1096 1097  
1097 1098          if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
1098 1099                  auto_service = TRUE;
1099 1100  
1100 1101          /*
1101 1102           * See if schema mapping existed for the given service.
1102 1103           * If not, just return success.
1103 1104           */
1104 1105          mapping = __ns_ldap_getOrigAttribute(service,
1105 1106              NS_HASH_SCHEMA_MAPPING_EXISTED);
1106 1107  
1107 1108          if (mapping == NULL && auto_service)
1108 1109                  /*
1109 1110                   * if service == auto_* and no
1110 1111                   * schema mapping found
1111 1112                   * then try automount
1112 1113                   */
1113 1114                  mapping = __ns_ldap_getOrigAttribute(
1114 1115                      "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
1115 1116  
1116 1117          if (mapping)
1117 1118                  __s_api_free2dArray(mapping);
1118 1119          else
1119 1120                  return (NS_LDAP_SUCCESS);
1120 1121  
1121 1122          /*
1122 1123           * no '=' sign, just say OK and return nothing
1123 1124           */
1124 1125          if (num_eq == 0)
1125 1126                  return (NS_LDAP_SUCCESS);
1126 1127  
1127 1128          /*
1128 1129           * Make a copy of the filter string
1129 1130           * for saving the name of the objectclasses or
1130 1131           * attributes that need to be passed to the
1131 1132           * objectclass or attribute mapping functions.
1132 1133           * pointer "info->from_name" points to the locations
1133 1134           * within this string.
1134 1135           *
1135 1136           * The input filter string, filter, will be used
1136 1137           * to indicate where these names start and end.
1137 1138           * pointers "info->name_start" and "info->name_end"
1138 1139           * point to locations within the input filter string,
1139 1140           * and are used at the end of this function to
1140 1141           * merge the original filter data with the
1141 1142           * mapped objectclass or attribute names.
1142 1143           */
1143 1144          filter_c = strdup(filter);
1144 1145          if (filter_c == NULL)
1145 1146                  return (NS_LDAP_MEMORY);
1146 1147          filter_c_next = filter_c;
1147 1148  
1148 1149          /*
1149 1150           * get memory for info arrays
1150 1151           */
1151 1152          info = (filter_mapping_info_t **)calloc(num_eq + 1,
1152 1153              sizeof (filter_mapping_info_t *));
1153 1154  
1154 1155          if (info == NULL) {
1155 1156                  free(filter_c);
1156 1157                  return (NS_LDAP_MEMORY);
1157 1158          }
1158 1159  
1159 1160          /*
1160 1161           * find valid '=' for further processing,
1161 1162           * ignore the "escaped =" (.i.e. "\="), or
1162 1163           * "=" in quoted string
1163 1164           */
1164 1165          for (c = filter_c; *c; c++) {
1165 1166  
1166 1167                  switch (*c) {
1167 1168                  case TOKENSEPARATOR:
1168 1169                          if (!in_quote && !is_value) {
1169 1170                                  info1 = (filter_mapping_info_t *)calloc(1,
1170 1171                                      sizeof (filter_mapping_info_t));
1171 1172                                  if (info1 == NULL) {
1172 1173                                          free(filter_c);
1173 1174                                          for (i = 0; i < num_veq; i++)
1174 1175                                                  free(info[i]);
1175 1176                                          free(info);
1176 1177                                          return (NS_LDAP_MEMORY);
1177 1178                                  }
1178 1179                                  info[num_veq] = info1;
1179 1180  
1180 1181                                  /*
1181 1182                                   * remember the location of this "="
1182 1183                                   */
1183 1184                                  info[num_veq++]->veq_pos = c;
1184 1185  
1185 1186                                  /*
1186 1187                                   * skip until the end of the attribute value
1187 1188                                   */
1188 1189                                  is_value = B_TRUE;
1189 1190                          }
1190 1191                          break;
1191 1192                  case CPARATOK:
1192 1193                          /*
1193 1194                           * mark the end of the attribute value
1194 1195                           */
1195 1196                          if (!in_quote)
1196 1197                                  is_value = B_FALSE;
1197 1198                          break;
1198 1199                  case QUOTETOK:
1199 1200                          /*
1200 1201                           * switch on/off the in_quote mode
1201 1202                           */
1202 1203                          in_quote = (in_quote == B_FALSE);
1203 1204                          break;
1204 1205                  case '\\':
1205 1206                          /*
1206 1207                           * ignore escape characters
1207 1208                           * don't skip if next char is '\0'
1208 1209                           */
1209 1210                          if (!in_quote)
1210 1211                                  if (*(++c) == '\0')
1211 1212                                          c--;
1212 1213                          break;
1213 1214                  }
1214 1215  
1215 1216          }
1216 1217  
1217 1218          /*
1218 1219           * for each valid "=" found, get the name to
1219 1220           * be mapped
1220 1221           */
1221 1222          oc_len = strlen("objectclass");
1222 1223          for (i = 0; i < num_veq; i++) {
1223 1224  
1224 1225                  /*
1225 1226                   * look at the left side of "=" to see
1226 1227                   * if assertion is "objectclass=<ocname>"
1227 1228                   * or "<attribute name>=<attribute value>"
1228 1229                   *
1229 1230                   * first skip spaces before "=".
1230 1231                   * Note that filter_c_next may not point to the
1231 1232                   * start of the filter string. For i > 0,
1232 1233                   * it points to the end of the last name processed + 2
1233 1234                   */
1234 1235                  for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1235 1236                      (*(tail - 1) == SPACETOK); tail--)
1236 1237                          ;
1237 1238  
1238 1239                  /*
1239 1240                   * mark the end of the left side string (the key)
1240 1241                   */
1241 1242                  *tail = '\0';
1242 1243                  info[i]->name_end = tail - filter_c - 1 + filter;
1243 1244  
1244 1245                  /*
1245 1246                   * find the start of the key
1246 1247                   */
1247 1248                  key = filter_c_next;
1248 1249                  for (c = tail; filter_c_next <= c; c--) {
1249 1250                          /* OPARATOK is '(' */
1250 1251                          if (*c == OPARATOK ||
1251 1252                              *c == SPACETOK) {
1252 1253                                  key = c + 1;
1253 1254                                  break;
1254 1255                          }
1255 1256                  }
1256 1257                  info[i]->name_start = key - filter_c + filter;
1257 1258  
1258 1259                  if ((key + oc_len) <= tail) {
1259 1260                          if (strncasecmp(key, "objectclass",
1260 1261                              oc_len) == 0) {
1261 1262                                  /*
1262 1263                                   * assertion is "objectclass=ocname",
1263 1264                                   * ocname is the one needs to be mapped
1264 1265                                   *
1265 1266                                   * skip spaces after "=" to find start
1266 1267                                   * of the ocname
1267 1268                                   */
1268 1269                                  head = info[i]->veq_pos;
1269 1270                                  for (head = info[i]->veq_pos + 1;
1270 1271                                      *head && *head == SPACETOK; head++)
1271 1272                                          ;
1272 1273  
1273 1274                                  /* ignore empty ocname */
1274 1275                                  if (!(*head))
1275 1276                                          continue;
1276 1277  
1277 1278                                  info[i]->name_start = head - filter_c +
1278 1279                                      filter;
1279 1280  
1280 1281                                  /*
1281 1282                                   * now find the end of the ocname
1282 1283                                   */
1283 1284                                  for (c = head; ; c++) {
1284 1285                                          /* CPARATOK is ')' */
1285 1286                                          if (*c == CPARATOK ||
1286 1287                                              *c == '\0' ||
1287 1288                                              *c == SPACETOK) {
1288 1289                                                  *c = '\0';
1289 1290                                                  info[i]->name_end =
1290 1291                                                      c - filter_c - 1 +
1291 1292                                                      filter;
1292 1293                                                  filter_c_next = c + 1;
1293 1294                                                  info[i]->oc_or_attr = 'o';
1294 1295                                                  info[i]->from_name = head;
1295 1296                                                  break;
1296 1297                                          }
1297 1298                                  }
1298 1299                          }
1299 1300                  }
1300 1301  
1301 1302                  /*
1302 1303                   * assertion is not "objectclass=ocname",
1303 1304                   * assume assertion is "<key> = <value>",
1304 1305                   * <key> is the one needs to be mapped
1305 1306                   */
1306 1307                  if (info[i]->from_name == NULL && strlen(key) > 0) {
1307 1308                          info[i]->oc_or_attr = 'a';
1308 1309                          info[i]->from_name = key;
1309 1310                  }
1310 1311          }
1311 1312  
1312 1313          /* perform schema mapping */
1313 1314          for (i = 0; i < num_veq; i++) {
1314 1315                  if (info[i]->from_name == NULL)
1315 1316                          continue;
1316 1317  
1317 1318                  if (info[i]->oc_or_attr == 'a')
1318 1319                          info[i]->mapping =
1319 1320                              __ns_ldap_getMappedAttributes(service,
1320 1321                              info[i]->from_name);
1321 1322                  else
1322 1323                          info[i]->mapping =
1323 1324                              __ns_ldap_getMappedObjectClass(service,
1324 1325                              info[i]->from_name);
1325 1326  
1326 1327                  if (info[i]->mapping == NULL && auto_service)  {
1327 1328                          /*
1328 1329                           * If no mapped attribute/objectclass is found
1329 1330                           * and service == auto*
1330 1331                           * try to find automount's
1331 1332                           * mapped attribute/objectclass
1332 1333                           */
1333 1334                          if (info[i]->oc_or_attr == 'a')
1334 1335                                  info[i]->mapping =
1335 1336                                      __ns_ldap_getMappedAttributes("automount",
1336 1337                                      info[i]->from_name);
1337 1338                          else
1338 1339                                  info[i]->mapping =
1339 1340                                      __ns_ldap_getMappedObjectClass("automount",
1340 1341                                      info[i]->from_name);
1341 1342                  }
1342 1343  
1343 1344                  if (info[i]->mapping == NULL ||
1344 1345                      info[i]->mapping[0] == NULL) {
1345 1346                          info[i]->to_name = NULL;
1346 1347                  } else if (info[i]->mapping[1] == NULL) {
1347 1348                          info[i]->to_name = info[i]->mapping[0];
1348 1349                          at_least_one = TRUE;
1349 1350                  } else {
1350 1351                          __s_api_free2dArray(info[i]->mapping);
1351 1352                          /*
1352 1353                           * multiple mapping
1353 1354                           * not allowed
1354 1355                           */
1355 1356                          (void) sprintf(errstr,
1356 1357                              gettext(
1357 1358                              "Multiple attribute or objectclass "
1358 1359                              "mapping for '%s' in filter "
1359 1360                              "'%s' not allowed."),
1360 1361                              info[i]->from_name, filter);
1361 1362                          err = strdup(errstr);
1362 1363                          if (err) {
1363 1364                                  MKERROR(LOG_WARNING, cookie->errorp,
1364 1365                                      NS_CONFIG_SYNTAX,
1365 1366                                      err, NS_LDAP_MEMORY);
1366 1367                          }
1367 1368  
1368 1369                          free(filter_c);
1369 1370                          for (j = 0; j < num_veq; j++) {
1370 1371                                  if (info[j]->mapping)
1371 1372                                          __s_api_free2dArray(
1372 1373                                              info[j]->mapping);
1373 1374                                  free(info[j]);
1374 1375                          }
1375 1376                          free(info);
1376 1377                          return (NS_LDAP_CONFIG);
1377 1378                  }
1378 1379          }
1379 1380  
1380 1381  
1381 1382          if (at_least_one) {
1382 1383  
1383 1384                  len = strlen(filter);
1384 1385                  last_copied = filter - 1;
1385 1386  
1386 1387                  for (i = 0; i < num_veq; i++) {
1387 1388                          if (info[i]->to_name)
1388 1389                                  len += strlen(info[i]->to_name);
1389 1390                  }
1390 1391  
1391 1392                  *new_filter = (char *)calloc(1, len);
1392 1393                  if (*new_filter == NULL) {
1393 1394                          free(filter_c);
1394 1395                          for (j = 0; j < num_veq; j++) {
1395 1396                                  if (info[j]->mapping)
1396 1397                                          __s_api_free2dArray(
1397 1398                                              info[j]->mapping);
1398 1399                                  free(info[j]);
1399 1400                          }
1400 1401                          free(info);
1401 1402                          return (NS_LDAP_MEMORY);
1402 1403                  }
1403 1404  
1404 1405                  for (i = 0; i < num_veq; i++) {
1405 1406                          if (info[i]->to_name != NULL &&
1406 1407                              info[i]->to_name != NULL) {
1407 1408  
1408 1409                                  /*
1409 1410                                   * copy the original filter data
1410 1411                                   * between the last name and current
1411 1412                                   * name
1412 1413                                   */
1413 1414                                  if ((last_copied + 1) != info[i]->name_start)
1414 1415                                          (void) strncat(*new_filter,
1415 1416                                              last_copied + 1,
1416 1417                                              info[i]->name_start -
1417 1418                                              last_copied - 1);
1418 1419  
1419 1420                                  /* the data is copied */
1420 1421                                  last_copied = info[i]->name_end;
1421 1422  
1422 1423                                  /*
1423 1424                                   * replace the name with
1424 1425                                   * the mapped name
1425 1426                                   */
1426 1427                                  (void) strcat(*new_filter, info[i]->to_name);
1427 1428                          }
1428 1429  
1429 1430                          /* copy the filter data after the last name */
1430 1431                          if (i == (num_veq -1) &&
1431 1432                              info[i]->name_end <
1432 1433                              (filter + strlen(filter)))
1433 1434                                  (void) strncat(*new_filter, last_copied + 1,
1434 1435                                      filter + strlen(filter) -
1435 1436                                      last_copied - 1);
1436 1437                  }
1437 1438  
1438 1439          }
1439 1440  
1440 1441          /* free memory */
1441 1442          free(filter_c);
1442 1443          for (j = 0; j < num_veq; j++) {
1443 1444                  if (info[j]->mapping)
1444 1445                          __s_api_free2dArray(info[j]->mapping);
1445 1446                  free(info[j]);
1446 1447          }
1447 1448          free(info);
1448 1449  
1449 1450          return (NS_LDAP_SUCCESS);
1450 1451  }
1451 1452  
1452 1453  static int
1453 1454  setup_next_search(ns_ldap_cookie_t *cookie)
1454 1455  {
1455 1456          ns_ldap_search_desc_t   *dptr;
1456 1457          int                     scope;
1457 1458          char                    *filter, *str;
1458 1459          int                     baselen;
1459 1460          int                     rc;
1460 1461          void                    **param;
1461 1462  
1462 1463          dptr = *cookie->sdpos;
1463 1464          scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1464 1465              NS_LDAP_SCOPE_ONELEVEL |
1465 1466              NS_LDAP_SCOPE_SUBTREE);
1466 1467          if (scope)
1467 1468                  cookie->scope = scope;
1468 1469          else
1469 1470                  cookie->scope = dptr->scope;
1470 1471          switch (cookie->scope) {
1471 1472          case NS_LDAP_SCOPE_BASE:
1472 1473                  cookie->scope = LDAP_SCOPE_BASE;
1473 1474                  break;
1474 1475          case NS_LDAP_SCOPE_ONELEVEL:
1475 1476                  cookie->scope = LDAP_SCOPE_ONELEVEL;
1476 1477                  break;
1477 1478          case NS_LDAP_SCOPE_SUBTREE:
1478 1479                  cookie->scope = LDAP_SCOPE_SUBTREE;
1479 1480                  break;
1480 1481          }
1481 1482  
1482 1483          filter = NULL;
1483 1484          if (cookie->use_filtercb && cookie->init_filter_cb &&
1484 1485              dptr->filter && strlen(dptr->filter) > 0) {
1485 1486                  (*cookie->init_filter_cb)(dptr, &filter,
1486 1487                      cookie->userdata);
1487 1488          }
1488 1489          if (filter == NULL) {
1489 1490                  if (cookie->i_filter == NULL) {
1490 1491                          cookie->err_rc = NS_LDAP_INVALID_PARAM;
1491 1492                          return (-1);
1492 1493                  } else {
1493 1494                          if (cookie->filter)
1494 1495                                  free(cookie->filter);
1495 1496                          cookie->filter = strdup(cookie->i_filter);
1496 1497                          if (cookie->filter == NULL) {
1497 1498                                  cookie->err_rc = NS_LDAP_MEMORY;
1498 1499                                  return (-1);
1499 1500                          }
1500 1501                  }
1501 1502          } else {
1502 1503                  if (cookie->filter)
1503 1504                          free(cookie->filter);
1504 1505                  cookie->filter = strdup(filter);
1505 1506                  free(filter);
1506 1507                  if (cookie->filter == NULL) {
1507 1508                          cookie->err_rc = NS_LDAP_MEMORY;
1508 1509                          return (-1);
1509 1510                  }
1510 1511          }
1511 1512  
1512 1513          /*
1513 1514           * perform attribute/objectclass mapping on filter
1514 1515           */
1515 1516          filter = NULL;
1516 1517  
1517 1518          if (cookie->service) {
1518 1519                  rc = get_mapped_filter(cookie, &filter);
1519 1520                  if (rc != NS_LDAP_SUCCESS) {
1520 1521                          cookie->err_rc = rc;
1521 1522                          return (-1);
1522 1523                  } else {
1523 1524                          /*
1524 1525                           * get_mapped_filter returns
1525 1526                           * NULL filter pointer, if
1526 1527                           * no mapping was done
1527 1528                           */
1528 1529                          if (filter) {
1529 1530                                  free(cookie->filter);
1530 1531                                  cookie->filter = filter;
1531 1532                          }
1532 1533                  }
1533 1534          }
1534 1535  
1535 1536          /*
1536 1537           * validate filter to make sure it's legal
1537 1538           * [remove redundant ()'s]
1538 1539           */
1539 1540          rc = validate_filter(cookie);
1540 1541          if (rc != NS_LDAP_SUCCESS) {
1541 1542                  cookie->err_rc = rc;
1542 1543                  return (-1);
1543 1544          }
1544 1545  
1545 1546          baselen = strlen(dptr->basedn);
1546 1547          if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
1547 1548                  rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1548 1549                      (void ***)¶m, &cookie->errorp);
1549 1550                  if (rc != NS_LDAP_SUCCESS) {
1550 1551                          cookie->err_rc = rc;
1551 1552                          return (-1);
1552 1553                  }
1553 1554                  str = ((char **)param)[0];
1554 1555                  baselen += strlen(str)+1;
1555 1556                  if (cookie->basedn)
1556 1557                          free(cookie->basedn);
1557 1558                  cookie->basedn = (char *)malloc(baselen);
1558 1559                  if (cookie->basedn == NULL) {
1559 1560                          cookie->err_rc = NS_LDAP_MEMORY;
1560 1561                          return (-1);
1561 1562                  }
1562 1563                  (void) strcpy(cookie->basedn, dptr->basedn);
1563 1564                  (void) strcat(cookie->basedn, str);
1564 1565                  (void) __ns_ldap_freeParam(¶m);
1565 1566          } else {
1566 1567                  if (cookie->basedn)
1567 1568                          free(cookie->basedn);
1568 1569                  cookie->basedn = strdup(dptr->basedn);
1569 1570          }
1570 1571          return (0);
1571 1572  }
1572 1573  
1573 1574  static int
1574 1575  setup_referral_search(ns_ldap_cookie_t *cookie)
1575 1576  {
1576 1577          ns_referral_info_t      *ref;
1577 1578  
1578 1579          ref = cookie->refpos;
1579 1580          cookie->scope = ref->refScope;
1580 1581          if (cookie->filter) {
1581 1582                  free(cookie->filter);
1582 1583          }
1583 1584          cookie->filter = strdup(ref->refFilter);
1584 1585          if (cookie->basedn) {
1585 1586                  free(cookie->basedn);
1586 1587          }
1587 1588          cookie->basedn = strdup(ref->refDN);
1588 1589          if (cookie->filter == NULL || cookie->basedn == NULL) {
1589 1590                  cookie->err_rc = NS_LDAP_MEMORY;
1590 1591                  return (-1);
1591 1592          }
1592 1593          return (0);
1593 1594  }
1594 1595  
1595 1596  static int
1596 1597  get_current_session(ns_ldap_cookie_t *cookie)
1597 1598  {
1598 1599          ConnectionID    connectionId = -1;
1599 1600          Connection      *conp = NULL;
1600 1601          int             rc;
1601 1602          int             fail_if_new_pwd_reqd = 1;
1602 1603  
1603 1604          rc = __s_api_getConnection(NULL, cookie->i_flags,
1604 1605              cookie->i_auth, &connectionId, &conp,
1605 1606              &cookie->errorp, fail_if_new_pwd_reqd,
1606 1607              cookie->nopasswd_acct_mgmt, cookie->conn_user);
1607 1608  
1608 1609          /*
1609 1610           * If password control attached in *cookie->errorp,
1610 1611           * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1611 1612           * free the error structure (we do not need
1612 1613           * the sec_to_expired info).
1613 1614           * Reset rc to NS_LDAP_SUCCESS.
1614 1615           */
1615 1616          if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1616 1617                  (void) __ns_ldap_freeError(
1617 1618                      &cookie->errorp);
1618 1619                  cookie->errorp = NULL;
1619 1620                  rc = NS_LDAP_SUCCESS;
1620 1621          }
1621 1622  
1622 1623          if (rc != NS_LDAP_SUCCESS) {
1623 1624                  cookie->err_rc = rc;
1624 1625                  return (-1);
1625 1626          }
1626 1627          cookie->conn = conp;
1627 1628          cookie->connectionId = connectionId;
1628 1629  
1629 1630          return (0);
1630 1631  }
1631 1632  
1632 1633  static int
1633 1634  get_next_session(ns_ldap_cookie_t *cookie)
1634 1635  {
1635 1636          ConnectionID    connectionId = -1;
1636 1637          Connection      *conp = NULL;
1637 1638          int             rc;
1638 1639          int             fail_if_new_pwd_reqd = 1;
1639 1640  
1640 1641          if (cookie->connectionId > -1) {
1641 1642                  DropConnection(cookie->connectionId, cookie->i_flags);
1642 1643                  cookie->connectionId = -1;
1643 1644          }
1644 1645  
1645 1646          /* If using a MT connection, return it. */
1646 1647          if (cookie->conn_user != NULL &&
1647 1648              cookie->conn_user->conn_mt != NULL)
1648 1649                  __s_api_conn_mt_return(cookie->conn_user);
1649 1650  
1650 1651          rc = __s_api_getConnection(NULL, cookie->i_flags,
1651 1652              cookie->i_auth, &connectionId, &conp,
1652 1653              &cookie->errorp, fail_if_new_pwd_reqd,
1653 1654              cookie->nopasswd_acct_mgmt, cookie->conn_user);
1654 1655  
1655 1656          /*
1656 1657           * If password control attached in *cookie->errorp,
1657 1658           * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1658 1659           * free the error structure (we do not need
1659 1660           * the sec_to_expired info).
1660 1661           * Reset rc to NS_LDAP_SUCCESS.
1661 1662           */
1662 1663          if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1663 1664                  (void) __ns_ldap_freeError(
1664 1665                      &cookie->errorp);
1665 1666                  cookie->errorp = NULL;
1666 1667                  rc = NS_LDAP_SUCCESS;
1667 1668          }
1668 1669  
1669 1670          if (rc != NS_LDAP_SUCCESS) {
1670 1671                  cookie->err_rc = rc;
1671 1672                  return (-1);
1672 1673          }
1673 1674          cookie->conn = conp;
1674 1675          cookie->connectionId = connectionId;
1675 1676          return (0);
1676 1677  }
1677 1678  
1678 1679  static int
1679 1680  get_referral_session(ns_ldap_cookie_t *cookie)
1680 1681  {
1681 1682          ConnectionID    connectionId = -1;
1682 1683          Connection      *conp = NULL;
1683 1684          int             rc;
1684 1685          int             fail_if_new_pwd_reqd = 1;
1685 1686  
1686 1687          if (cookie->connectionId > -1) {
1687 1688                  DropConnection(cookie->connectionId, cookie->i_flags);
1688 1689                  cookie->connectionId = -1;
1689 1690          }
1690 1691  
1691 1692          /* set it up to use a connection opened for referral */
1692 1693          if (cookie->conn_user != NULL) {
1693 1694                  /* If using a MT connection, return it. */
1694 1695                  if (cookie->conn_user->conn_mt != NULL)
1695 1696                          __s_api_conn_mt_return(cookie->conn_user);
1696 1697                  cookie->conn_user->referral = B_TRUE;
1697 1698          }
1698 1699  
1699 1700          rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1700 1701              cookie->i_auth, &connectionId, &conp,
1701 1702              &cookie->errorp, fail_if_new_pwd_reqd,
1702 1703              cookie->nopasswd_acct_mgmt, cookie->conn_user);
1703 1704  
1704 1705          /*
1705 1706           * If password control attached in *cookie->errorp,
1706 1707           * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1707 1708           * free the error structure (we do not need
1708 1709           * the sec_to_expired info).
1709 1710           * Reset rc to NS_LDAP_SUCCESS.
1710 1711           */
1711 1712          if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1712 1713                  (void) __ns_ldap_freeError(
1713 1714                      &cookie->errorp);
1714 1715                  cookie->errorp = NULL;
1715 1716                  rc = NS_LDAP_SUCCESS;
1716 1717          }
1717 1718  
1718 1719          if (rc != NS_LDAP_SUCCESS) {
1719 1720                  cookie->err_rc = rc;
1720 1721                  return (-1);
1721 1722          }
1722 1723          cookie->conn = conp;
1723 1724          cookie->connectionId = connectionId;
1724 1725          return (0);
1725 1726  }
1726 1727  
1727 1728  static int
1728 1729  paging_supported(ns_ldap_cookie_t *cookie)
1729 1730  {
1730 1731          int             rc;
1731 1732  
1732 1733          cookie->listType = 0;
1733 1734          rc = __s_api_isCtrlSupported(cookie->conn,
1734 1735              LDAP_CONTROL_VLVREQUEST);
1735 1736          if (rc == NS_LDAP_SUCCESS) {
1736 1737                  cookie->listType = VLVCTRLFLAG;
1737 1738                  return (1);
1738 1739          }
1739 1740          rc = __s_api_isCtrlSupported(cookie->conn,
1740 1741              LDAP_CONTROL_SIMPLE_PAGE);
1741 1742          if (rc == NS_LDAP_SUCCESS) {
1742 1743                  cookie->listType = SIMPLEPAGECTRLFLAG;
1743 1744                  return (1);
1744 1745          }
1745 1746          return (0);
1746 1747  }
1747 1748  
1748 1749  typedef struct servicesorttype {
1749 1750          char *service;
1750 1751          ns_srvsidesort_t type;
1751 1752  } servicesorttype_t;
1752 1753  
1753 1754  static servicesorttype_t *sort_type = NULL;
1754 1755  static int sort_type_size = 0;
1755 1756  static int sort_type_hwm = 0;
1756 1757  static mutex_t sort_type_mutex = DEFAULTMUTEX;
1757 1758  
1758 1759  
1759 1760  static ns_srvsidesort_t
1760 1761  get_srvsidesort_type(char *service)
1761 1762  {
1762 1763          int i;
1763 1764          ns_srvsidesort_t type = SSS_UNKNOWN;
1764 1765  
1765 1766          if (service == NULL)
1766 1767                  return (type);
1767 1768  
1768 1769          (void) mutex_lock(&sort_type_mutex);
1769 1770          if (sort_type != NULL) {
1770 1771                  for (i = 0; i < sort_type_hwm; i++) {
1771 1772                          if (strcmp(sort_type[i].service, service) == 0) {
1772 1773                                  type = sort_type[i].type;
1773 1774                                  break;
1774 1775                          }
1775 1776                  }
1776 1777          }
1777 1778          (void) mutex_unlock(&sort_type_mutex);
1778 1779          return (type);
1779 1780  }
1780 1781  
1781 1782  static void
1782 1783  update_srvsidesort_type(char *service, ns_srvsidesort_t type)
1783 1784  {
1784 1785          int i, size;
1785 1786          servicesorttype_t *tmp;
1786 1787  
1787 1788          if (service == NULL)
1788 1789                  return;
1789 1790  
1790 1791          (void) mutex_lock(&sort_type_mutex);
1791 1792  
1792 1793          for (i = 0; i < sort_type_hwm; i++) {
1793 1794                  if (strcmp(sort_type[i].service, service) == 0) {
1794 1795                          sort_type[i].type = type;
1795 1796                          (void) mutex_unlock(&sort_type_mutex);
1796 1797                          return;
1797 1798                  }
1798 1799          }
1799 1800          if (sort_type == NULL) {
1800 1801                  size = 10;
1801 1802                  tmp = malloc(size * sizeof (servicesorttype_t));
1802 1803                  if (tmp == NULL) {
1803 1804                          (void) mutex_unlock(&sort_type_mutex);
1804 1805                          return;
1805 1806                  }
1806 1807                  sort_type = tmp;
1807 1808                  sort_type_size = size;
1808 1809          } else if (sort_type_hwm >= sort_type_size) {
1809 1810                  size = sort_type_size + 10;
1810 1811                  tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
1811 1812                  if (tmp == NULL) {
1812 1813                          (void) mutex_unlock(&sort_type_mutex);
1813 1814                          return;
1814 1815                  }
1815 1816                  sort_type = tmp;
1816 1817                  sort_type_size = size;
1817 1818          }
1818 1819          sort_type[sort_type_hwm].service = strdup(service);
1819 1820          if (sort_type[sort_type_hwm].service == NULL) {
1820 1821                  (void) mutex_unlock(&sort_type_mutex);
1821 1822                  return;
1822 1823          }
1823 1824          sort_type[sort_type_hwm].type = type;
1824 1825          sort_type_hwm++;
1825 1826  
1826 1827          (void) mutex_unlock(&sort_type_mutex);
1827 1828  }
1828 1829  
1829 1830  static int
1830 1831  setup_vlv_params(ns_ldap_cookie_t *cookie)
1831 1832  {
1832 1833          LDAPControl     **ctrls;
1833 1834          LDAPsortkey     **sortkeylist;
1834 1835          LDAPControl     *sortctrl = NULL;
1835 1836          LDAPControl     *vlvctrl = NULL;
1836 1837          LDAPVirtualList vlist;
1837 1838          char            *sortattr;
1838 1839          int             rc;
1839 1840          int             free_sort = FALSE;
1840 1841  
1841 1842          _freeControlList(&cookie->p_serverctrls);
1842 1843  
1843 1844          if (cookie->sortTypeTry == SSS_UNKNOWN)
1844 1845                  cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
1845 1846          if (cookie->sortTypeTry == SSS_UNKNOWN)
1846 1847                  cookie->sortTypeTry = SSS_SINGLE_ATTR;
1847 1848  
1848 1849          if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
1849 1850                  if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
1850 1851                      cookie->i_sortattr) {
1851 1852                          sortattr =  __ns_ldap_mapAttribute(cookie->service,
1852 1853                              cookie->i_sortattr);
1853 1854                          free_sort = TRUE;
1854 1855                  } else if (cookie->i_sortattr) {
1855 1856                          sortattr = (char *)cookie->i_sortattr;
1856 1857                  } else {
1857 1858                          sortattr = "cn";
1858 1859                  }
1859 1860          } else {
1860 1861                  sortattr = "cn uid";
1861 1862          }
1862 1863  
1863 1864          rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
1864 1865          if (free_sort)
1865 1866                  free(sortattr);
1866 1867          if (rc != LDAP_SUCCESS) {
1867 1868                  (void) ldap_get_option(cookie->conn->ld,
1868 1869                      LDAP_OPT_ERROR_NUMBER, &rc);
1869 1870                  return (rc);
1870 1871          }
1871 1872          rc = ldap_create_sort_control(cookie->conn->ld,
1872 1873              sortkeylist, 1, &sortctrl);
1873 1874          ldap_free_sort_keylist(sortkeylist);
1874 1875          if (rc != LDAP_SUCCESS) {
1875 1876                  (void) ldap_get_option(cookie->conn->ld,
1876 1877                      LDAP_OPT_ERROR_NUMBER, &rc);
1877 1878                  return (rc);
1878 1879          }
1879 1880  
1880 1881          vlist.ldvlist_index = cookie->index;
1881 1882          vlist.ldvlist_size = 0;
1882 1883  
1883 1884          vlist.ldvlist_before_count = 0;
1884 1885          vlist.ldvlist_after_count = LISTPAGESIZE-1;
1885 1886          vlist.ldvlist_attrvalue = NULL;
1886 1887          vlist.ldvlist_extradata = NULL;
1887 1888  
1888 1889          rc = ldap_create_virtuallist_control(cookie->conn->ld,
1889 1890              &vlist, &vlvctrl);
1890 1891          if (rc != LDAP_SUCCESS) {
1891 1892                  ldap_control_free(sortctrl);
1892 1893                  (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1893 1894                      &rc);
1894 1895                  return (rc);
1895 1896          }
1896 1897  
1897 1898          ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
1898 1899          if (ctrls == NULL) {
1899 1900                  ldap_control_free(sortctrl);
1900 1901                  ldap_control_free(vlvctrl);
1901 1902                  return (LDAP_NO_MEMORY);
1902 1903          }
1903 1904  
1904 1905          ctrls[0] = sortctrl;
1905 1906          ctrls[1] = vlvctrl;
1906 1907  
1907 1908          cookie->p_serverctrls = ctrls;
1908 1909          return (LDAP_SUCCESS);
1909 1910  }
1910 1911  
1911 1912  static int
1912 1913  setup_simplepg_params(ns_ldap_cookie_t *cookie)
1913 1914  {
1914 1915          LDAPControl     **ctrls;
1915 1916          LDAPControl     *pgctrl = NULL;
1916 1917          int             rc;
1917 1918  
1918 1919          _freeControlList(&cookie->p_serverctrls);
1919 1920  
1920 1921          rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1921 1922              cookie->ctrlCookie, (char)0, &pgctrl);
1922 1923          if (rc != LDAP_SUCCESS) {
1923 1924                  (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1924 1925                      &rc);
1925 1926                  return (rc);
1926 1927          }
1927 1928  
1928 1929          ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
1929 1930          if (ctrls == NULL) {
1930 1931                  ldap_control_free(pgctrl);
1931 1932                  return (LDAP_NO_MEMORY);
1932 1933          }
1933 1934          ctrls[0] = pgctrl;
1934 1935          cookie->p_serverctrls = ctrls;
1935 1936          return (LDAP_SUCCESS);
1936 1937  }
1937 1938  
1938 1939  static void
1939 1940  proc_result_referrals(ns_ldap_cookie_t *cookie)
1940 1941  {
1941 1942          int             errCode, i, rc;
1942 1943          char            **referrals = NULL;
1943 1944  
1944 1945          /*
1945 1946           * Only follow one level of referrals, i.e.
1946 1947           * if already in referral mode, do nothing
1947 1948           */
1948 1949          if (cookie->refpos == NULL) {
1949 1950                  cookie->new_state = END_RESULT;
1950 1951                  rc = ldap_parse_result(cookie->conn->ld,
1951 1952                      cookie->resultMsg,
1952 1953                      &errCode, NULL,
1953 1954                      NULL, &referrals,
1954 1955                      NULL, 0);
1955 1956                  if (rc != NS_LDAP_SUCCESS) {
1956 1957                          (void) ldap_get_option(cookie->conn->ld,
1957 1958                              LDAP_OPT_ERROR_NUMBER,
1958 1959                              &cookie->err_rc);
1959 1960                          cookie->new_state = LDAP_ERROR;
1960 1961                          return;
1961 1962                  }
1962 1963                  if (errCode == LDAP_REFERRAL) {
1963 1964                          for (i = 0; referrals[i] != NULL;
1964 1965                              i++) {
1965 1966                                  /* add to referral list */
1966 1967                                  rc = __s_api_addRefInfo(
1967 1968                                      &cookie->reflist,
1968 1969                                      referrals[i],
1969 1970                                      cookie->basedn,
1970 1971                                      &cookie->scope,
1971 1972                                      cookie->filter,
1972 1973                                      cookie->conn->ld);
1973 1974                                  if (rc != NS_LDAP_SUCCESS) {
1974 1975                                          cookie->new_state =
1975 1976                                              ERROR;
1976 1977                                          break;
1977 1978                                  }
1978 1979                          }
1979 1980                          ldap_value_free(referrals);
1980 1981                  }
1981 1982          }
1982 1983  }
1983 1984  
1984 1985  static void
1985 1986  proc_search_references(ns_ldap_cookie_t *cookie)
1986 1987  {
1987 1988          char            **refurls = NULL;
1988 1989          int             i, rc;
1989 1990  
1990 1991          /*
1991 1992           * Only follow one level of referrals, i.e.
1992 1993           * if already in referral mode, do nothing
1993 1994           */
1994 1995          if (cookie->refpos == NULL) {
1995 1996                  refurls = ldap_get_reference_urls(
1996 1997                      cookie->conn->ld,
1997 1998                      cookie->resultMsg);
1998 1999                  if (refurls == NULL) {
1999 2000                          (void) ldap_get_option(cookie->conn->ld,
2000 2001                              LDAP_OPT_ERROR_NUMBER,
2001 2002                              &cookie->err_rc);
2002 2003                          cookie->new_state = LDAP_ERROR;
2003 2004                          return;
2004 2005                  }
2005 2006                  for (i = 0; refurls[i] != NULL; i++) {
2006 2007                          /* add to referral list */
2007 2008                          rc = __s_api_addRefInfo(
2008 2009                              &cookie->reflist,
2009 2010                              refurls[i],
2010 2011                              cookie->basedn,
2011 2012                              &cookie->scope,
2012 2013                              cookie->filter,
2013 2014                              cookie->conn->ld);
2014 2015                          if (rc != NS_LDAP_SUCCESS) {
2015 2016                                  cookie->new_state =
2016 2017                                      ERROR;
2017 2018                                  break;
2018 2019                          }
2019 2020                  }
2020 2021                  /* free allocated storage */
2021 2022                  for (i = 0; refurls[i] != NULL; i++)
2022 2023                          free(refurls[i]);
2023 2024          }
2024 2025  }
2025 2026  
2026 2027  static ns_state_t
2027 2028  multi_result(ns_ldap_cookie_t *cookie)
2028 2029  {
2029 2030          char            errstr[MAXERROR];
2030 2031          char            *err;
2031 2032          ns_ldap_error_t **errorp = NULL;
2032 2033          LDAPControl     **retCtrls = NULL;
2033 2034          int             i, rc;
2034 2035          int             errCode;
2035 2036          boolean_t       finished = B_FALSE;
2036 2037          unsigned long   target_posp = 0;
2037 2038          unsigned long   list_size = 0;
2038 2039          unsigned int    count = 0;
2039 2040          char            **referrals = NULL;
2040 2041  
2041 2042          if (cookie->listType == VLVCTRLFLAG) {
2042 2043                  rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2043 2044                      &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2044 2045                  if (rc != LDAP_SUCCESS) {
2045 2046                          (void) ldap_get_option(cookie->conn->ld,
2046 2047                              LDAP_OPT_ERROR_NUMBER,
2047 2048                              &cookie->err_rc);
2048 2049                          (void) sprintf(errstr,
2049 2050                              gettext("LDAP ERROR (%d): %s.\n"),
2050 2051                              cookie->err_rc,
2051 2052                              gettext(ldap_err2string(cookie->err_rc)));
2052 2053                          err = strdup(errstr);
2053 2054                          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2054 2055                              NS_LDAP_MEMORY);
2055 2056                          cookie->err_rc = NS_LDAP_INTERNAL;
2056 2057                          cookie->errorp = *errorp;
2057 2058                          return (LDAP_ERROR);
2058 2059                  }
2059 2060                  if (errCode == LDAP_REFERRAL) {
2060 2061                          for (i = 0; referrals[i] != NULL;
2061 2062                              i++) {
2062 2063                                  /* add to referral list */
2063 2064                                  rc = __s_api_addRefInfo(
2064 2065                                      &cookie->reflist,
2065 2066                                      referrals[i],
2066 2067                                      cookie->basedn,
2067 2068                                      &cookie->scope,
2068 2069                                      cookie->filter,
2069 2070                                      cookie->conn->ld);
2070 2071                                  if (rc != NS_LDAP_SUCCESS) {
2071 2072                                          ldap_value_free(
2072 2073                                              referrals);
2073 2074                                          if (retCtrls)
2074 2075                                                  ldap_controls_free(
2075 2076                                                      retCtrls);
2076 2077                                          return (ERROR);
2077 2078                                  }
2078 2079                          }
2079 2080                          ldap_value_free(referrals);
2080 2081                          if (retCtrls)
2081 2082                                  ldap_controls_free(retCtrls);
2082 2083                          return (END_RESULT);
2083 2084                  }
2084 2085                  if (retCtrls) {
2085 2086                          rc = ldap_parse_virtuallist_control(
2086 2087                              cookie->conn->ld, retCtrls,
2087 2088                              &target_posp, &list_size, &errCode);
2088 2089                          if (rc == LDAP_SUCCESS) {
2089 2090                                  /*
2090 2091                                   * AD does not return valid target_posp
2091 2092                                   * and list_size
2092 2093                                   */
2093 2094                                  if (target_posp != 0 && list_size != 0) {
2094 2095                                          cookie->index =
2095 2096                                              target_posp + LISTPAGESIZE;
2096 2097                                          if (cookie->index > list_size)
2097 2098                                                  finished = B_TRUE;
2098 2099                                  } else {
2099 2100                                          if (cookie->entryCount < LISTPAGESIZE)
2100 2101                                                  finished = B_TRUE;
2101 2102                                          else
2102 2103                                                  cookie->index +=
2103 2104                                                      cookie->entryCount;
2104 2105                                  }
2105 2106                          }
2106 2107                          ldap_controls_free(retCtrls);
2107 2108                          retCtrls = NULL;
2108 2109                  } else {
2109 2110                          finished = B_TRUE;
2110 2111                  }
2111 2112          } else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
2112 2113                  rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2113 2114                      &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2114 2115                  if (rc != LDAP_SUCCESS) {
2115 2116                          (void) ldap_get_option(cookie->conn->ld,
2116 2117                              LDAP_OPT_ERROR_NUMBER,
2117 2118                              &cookie->err_rc);
2118 2119                          (void) sprintf(errstr,
2119 2120                              gettext("LDAP ERROR (%d): %s.\n"),
2120 2121                              cookie->err_rc,
2121 2122                              gettext(ldap_err2string(cookie->err_rc)));
2122 2123                          err = strdup(errstr);
2123 2124                          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2124 2125                              NS_LDAP_MEMORY);
2125 2126                          cookie->err_rc = NS_LDAP_INTERNAL;
2126 2127                          cookie->errorp = *errorp;
2127 2128                          return (LDAP_ERROR);
2128 2129                  }
2129 2130                  if (errCode == LDAP_REFERRAL) {
2130 2131                          for (i = 0; referrals[i] != NULL;
2131 2132                              i++) {
2132 2133                                  /* add to referral list */
2133 2134                                  rc = __s_api_addRefInfo(
2134 2135                                      &cookie->reflist,
2135 2136                                      referrals[i],
2136 2137                                      cookie->basedn,
2137 2138                                      &cookie->scope,
2138 2139                                      cookie->filter,
2139 2140                                      cookie->conn->ld);
2140 2141                                  if (rc != NS_LDAP_SUCCESS) {
2141 2142                                          ldap_value_free(
2142 2143                                              referrals);
2143 2144                                          if (retCtrls)
2144 2145                                                  ldap_controls_free(
2145 2146                                                      retCtrls);
2146 2147                                          return (ERROR);
2147 2148                                  }
2148 2149                          }
2149 2150                          ldap_value_free(referrals);
2150 2151                          if (retCtrls)
2151 2152                                  ldap_controls_free(retCtrls);
2152 2153                          return (END_RESULT);
2153 2154                  }
2154 2155                  if (retCtrls) {
2155 2156                          if (cookie->ctrlCookie)
2156 2157                                  ber_bvfree(cookie->ctrlCookie);
2157 2158                          cookie->ctrlCookie = NULL;
2158 2159                          rc = ldap_parse_page_control(
2159 2160                              cookie->conn->ld, retCtrls,
2160 2161                              &count, &cookie->ctrlCookie);
2161 2162                          if (rc == LDAP_SUCCESS) {
2162 2163                                  if ((cookie->ctrlCookie == NULL) ||
2163 2164                                      (cookie->ctrlCookie->bv_val == NULL) ||
2164 2165                                      (cookie->ctrlCookie->bv_len == 0))
2165 2166                                          finished = B_TRUE;
2166 2167                          }
2167 2168                          ldap_controls_free(retCtrls);
2168 2169                          retCtrls = NULL;
2169 2170                  } else {
2170 2171                          finished = B_TRUE;
2171 2172                  }
2172 2173          }
2173 2174          if (!finished && cookie->listType == VLVCTRLFLAG)
2174 2175                  return (NEXT_VLV);
2175 2176          if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
2176 2177                  return (NEXT_PAGE);
2177 2178          if (finished)
2178 2179                  return (END_RESULT);
2179 2180          return (ERROR);
2180 2181  }
2181 2182  
2182 2183  /*
2183 2184   * clear_results(ns_ldap_cookie_t):
2184 2185   *
2185 2186   * Attempt to obtain remnants of ldap responses and free them.  If remnants are
2186 2187   * not obtained within a certain time period tell the server we wish to abandon
2187 2188   * the request.
2188 2189   *
2189 2190   * Note that we do not initially tell the server to abandon the request as that
2190 2191   * can be an expensive operation for the server, while it is cheap for us to
2191 2192   * just flush the input.
2192 2193   *
2193 2194   * If something was to remain in libldap queue as a result of some error then
2194 2195   * it would be freed later during drop connection call or when no other
2195 2196   * requests share the connection.
2196 2197   */
2197 2198  static void
2198 2199  clear_results(ns_ldap_cookie_t *cookie)
2199 2200  {
2200 2201          int rc;
2201 2202          if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2202 2203              (cookie->connectionId != -1 ||
2203 2204              (cookie->conn_user != NULL &&
2204 2205              cookie->conn_user->conn_mt != NULL)) &&
2205 2206              cookie->msgId != 0) {
2206 2207                  /*
2207 2208                   * We need to cleanup the rest of response (if there is such)
2208 2209                   * and LDAP abandon is too heavy for LDAP servers, so we will
2209 2210                   * wait for the rest of response till timeout and "process" it.
2210 2211                   */
2211 2212                  rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
2212 2213                      (struct timeval *)&cookie->search_timeout,
2213 2214                      &cookie->resultMsg);
2214 2215                  if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2215 2216                          (void) ldap_msgfree(cookie->resultMsg);
2216 2217                          cookie->resultMsg = NULL;
2217 2218                  }
2218 2219  
2219 2220                  /*
2220 2221                   * If there was timeout then we will send  ABANDON request to
2221 2222                   * LDAP server to decrease load.
2222 2223                   */
2223 2224                  if (rc == 0)
2224 2225                          (void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2225 2226                              NULL, NULL);
2226 2227                  /* Disassociate cookie with msgId */
2227 2228                  cookie->msgId = 0;
2228 2229          }
2229 2230  }
2230 2231  
2231 2232  /*
2232 2233   * This state machine performs one or more LDAP searches to a given
2233 2234   * directory server using service search descriptors and schema
2234 2235   * mapping as appropriate.  The approximate pseudocode for
2235 2236   * this routine is the following:
2236 2237   *    Given the current configuration [set/reset connection etc.]
2237 2238   *    and the current service search descriptor list
2238 2239   *        or default search filter parameters
2239 2240   *    foreach (service search filter) {
2240 2241   *        initialize the filter [via filter_init if appropriate]
2241 2242   *                get a valid session/connection (preferably the current one)
2242 2243   *                                      Recover if the connection is lost
2243 2244   *        perform the search
2244 2245   *        foreach (result entry) {
2245 2246   *            process result [via callback if appropriate]
2246 2247   *                save result for caller if accepted.
2247 2248   *                exit and return all collected if allResults found;
2248 2249   *        }
2249 2250   *    }
2250 2251   *    return collected results and exit
2251 2252   */
2252 2253  
2253 2254  static
2254 2255  ns_state_t
2255 2256  search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2256 2257  {
2257 2258          char            errstr[MAXERROR];
2258 2259          char            *err;
2259 2260          int             rc, ret;
2260 2261          int             rc_save;
2261 2262          ns_ldap_entry_t *nextEntry;
2262 2263          ns_ldap_error_t *error = NULL;
2263 2264          ns_ldap_error_t **errorp;
2264 2265          struct timeval  tv;
2265 2266  
2266 2267          errorp = &error;
2267 2268          cookie->state = state;
2268 2269          errstr[0] = '\0';
2269 2270  
2270 2271          for (;;) {
2271 2272                  switch (cookie->state) {
2272 2273                  case CLEAR_RESULTS:
2273 2274                          clear_results(cookie);
2274 2275                          cookie->new_state = EXIT;
2275 2276                          break;
2276 2277                  case GET_ACCT_MGMT_INFO:
2277 2278                          /*
2278 2279                           * Set the flag to get ldap account management controls.
2279 2280                           */
2280 2281                          cookie->nopasswd_acct_mgmt = 1;
2281 2282                          cookie->new_state = INIT;
2282 2283                          break;
2283 2284                  case EXIT:
2284 2285                          /* state engine/connection cleaned up in delete */
2285 2286                          if (cookie->attribute) {
2286 2287                                  __s_api_free2dArray(cookie->attribute);
2287 2288                                  cookie->attribute = NULL;
2288 2289                          }
2289 2290                          if (cookie->reflist) {
2290 2291                                  __s_api_deleteRefInfo(cookie->reflist);
2291 2292                                  cookie->reflist = NULL;
2292 2293                          }
2293 2294                          return (EXIT);
2294 2295                  case INIT:
2295 2296                          cookie->sdpos = NULL;
2296 2297                          cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2297 2298                          if (cookie->attribute) {
2298 2299                                  __s_api_free2dArray(cookie->attribute);
2299 2300                                  cookie->attribute = NULL;
2300 2301                          }
2301 2302                          if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2302 2303                              cookie->i_attr) {
2303 2304                                  cookie->attribute =
2304 2305                                      __ns_ldap_mapAttributeList(
2305 2306                                      cookie->service,
2306 2307                                      cookie->i_attr);
2307 2308                          }
2308 2309                          break;
2309 2310                  case REINIT:
2310 2311                          /* Check if we've reached MAX retries. */
2311 2312                          cookie->retries++;
2312 2313                          if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2313 2314                                  cookie->new_state = LDAP_ERROR;
2314 2315                                  break;
2315 2316                          }
2316 2317  
2317 2318                          /*
2318 2319                           * Even if we still have retries left, check
2319 2320                           * if retry is possible.
2320 2321                           */
2321 2322                          if (cookie->conn_user != NULL) {
2322 2323                                  int             retry;
2323 2324                                  ns_conn_mgmt_t  *cmg;
2324 2325                                  cmg = cookie->conn_user->conn_mgmt;
2325 2326                                  retry = cookie->conn_user->retry;
2326 2327                                  if (cmg != NULL && cmg->cfg_reloaded == 1)
2327 2328                                          retry = 1;
2328 2329                                  if (retry == 0) {
2329 2330                                          cookie->new_state = LDAP_ERROR;
2330 2331                                          break;
2331 2332                                  }
2332 2333                          }
2333 2334                          /*
2334 2335                           * Free results if any, reset to the first
2335 2336                           * search descriptor and start a new session.
2336 2337                           */
2337 2338                          if (cookie->resultMsg != NULL) {
2338 2339                                  (void) ldap_msgfree(cookie->resultMsg);
2339 2340                                  cookie->resultMsg = NULL;
2340 2341                          }
2341 2342                          (void) __ns_ldap_freeError(&cookie->errorp);
2342 2343                          (void) __ns_ldap_freeResult(&cookie->result);
2343 2344                          cookie->sdpos = cookie->sdlist;
2344 2345                          cookie->err_from_result = 0;
2345 2346                          cookie->err_rc = 0;
2346 2347                          cookie->new_state = NEXT_SESSION;
2347 2348                          break;
2348 2349                  case NEXT_SEARCH_DESCRIPTOR:
2349 2350                          /* get next search descriptor */
2350 2351                          if (cookie->sdpos == NULL) {
2351 2352                                  cookie->sdpos = cookie->sdlist;
2352 2353                                  cookie->new_state = GET_SESSION;
2353 2354                          } else {
2354 2355                                  cookie->sdpos++;
2355 2356                                  cookie->new_state = NEXT_SEARCH;
2356 2357                          }
2357 2358                          if (*cookie->sdpos == NULL)
2358 2359                                  cookie->new_state = EXIT;
2359 2360                          break;
2360 2361                  case GET_SESSION:
2361 2362                          if (get_current_session(cookie) < 0)
2362 2363                                  cookie->new_state = NEXT_SESSION;
2363 2364                          else
2364 2365                                  cookie->new_state = NEXT_SEARCH;
2365 2366                          break;
2366 2367                  case NEXT_SESSION:
2367 2368                          if (get_next_session(cookie) < 0)
2368 2369                                  cookie->new_state = RESTART_SESSION;
2369 2370                          else
2370 2371                                  cookie->new_state = NEXT_SEARCH;
2371 2372                          break;
2372 2373                  case RESTART_SESSION:
2373 2374                          if (cookie->i_flags & NS_LDAP_HARD) {
2374 2375                                  cookie->new_state = NEXT_SESSION;
2375 2376                                  break;
2376 2377                          }
2377 2378                          (void) sprintf(errstr,
2378 2379                              gettext("Session error no available conn.\n"),
2379 2380                              state);
2380 2381                          err = strdup(errstr);
2381 2382                          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2382 2383                              NS_LDAP_MEMORY);
2383 2384                          cookie->err_rc = NS_LDAP_INTERNAL;
2384 2385                          cookie->errorp = *errorp;
2385 2386                          cookie->new_state = EXIT;
2386 2387                          break;
2387 2388                  case NEXT_SEARCH:
2388 2389                          /* setup referrals search if necessary */
2389 2390                          if (cookie->refpos) {
2390 2391                                  if (setup_referral_search(cookie) < 0) {
2391 2392                                          cookie->new_state = EXIT;
2392 2393                                          break;
2393 2394                                  }
2394 2395                          } else if (setup_next_search(cookie) < 0) {
2395 2396                                  cookie->new_state = EXIT;
2396 2397                                  break;
2397 2398                          }
2398 2399                          /* only do VLV/PAGE on scopes onelevel/subtree */
2399 2400                          if (paging_supported(cookie)) {
2400 2401                                  if (cookie->use_paging &&
2401 2402                                      (cookie->scope != LDAP_SCOPE_BASE)) {
2402 2403                                          cookie->index = 1;
2403 2404                                          if (cookie->listType == VLVCTRLFLAG)
2404 2405                                                  cookie->new_state = NEXT_VLV;
2405 2406                                          else
2406 2407                                                  cookie->new_state = NEXT_PAGE;
2407 2408                                          break;
2408 2409                                  }
2409 2410                          }
2410 2411                          cookie->new_state = ONE_SEARCH;
2411 2412                          break;
2412 2413                  case NEXT_VLV:
2413 2414                          rc = setup_vlv_params(cookie);
2414 2415                          if (rc != LDAP_SUCCESS) {
2415 2416                                  cookie->err_rc = rc;
2416 2417                                  cookie->new_state = LDAP_ERROR;
2417 2418                                  break;
2418 2419                          }
2419 2420                          cookie->next_state = MULTI_RESULT;
2420 2421                          cookie->new_state = DO_SEARCH;
2421 2422                          break;
2422 2423                  case NEXT_PAGE:
2423 2424                          rc = setup_simplepg_params(cookie);
2424 2425                          if (rc != LDAP_SUCCESS) {
2425 2426                                  cookie->err_rc = rc;
2426 2427                                  cookie->new_state = LDAP_ERROR;
2427 2428                                  break;
2428 2429                          }
2429 2430                          cookie->next_state = MULTI_RESULT;
2430 2431                          cookie->new_state = DO_SEARCH;
2431 2432                          break;
2432 2433                  case ONE_SEARCH:
2433 2434                          cookie->next_state = NEXT_RESULT;
2434 2435                          cookie->new_state = DO_SEARCH;
2435 2436                          break;
2436 2437                  case DO_SEARCH:
2437 2438                          cookie->entryCount = 0;
2438 2439                          rc = ldap_search_ext(cookie->conn->ld,
2439 2440                              cookie->basedn,
2440 2441                              cookie->scope,
2441 2442                              cookie->filter,
2442 2443                              cookie->attribute,
2443 2444                              0,
2444 2445                              cookie->p_serverctrls,
2445 2446                              NULL,
2446 2447                              &cookie->search_timeout, 0,
2447 2448                              &cookie->msgId);
2448 2449                          if (rc != LDAP_SUCCESS) {
2449 2450                                  if (rc == LDAP_BUSY ||
2450 2451                                      rc == LDAP_UNAVAILABLE ||
2451 2452                                      rc == LDAP_UNWILLING_TO_PERFORM ||
2452 2453                                      rc == LDAP_CONNECT_ERROR ||
2453 2454                                      rc == LDAP_SERVER_DOWN) {
2454 2455  
2455 2456                                          if (cookie->reinit_on_retriable_err) {
2456 2457                                                  cookie->err_rc = rc;
2457 2458                                                  cookie->new_state = REINIT;
2458 2459                                          } else {
2459 2460                                                  cookie->new_state =
2460 2461                                                      NEXT_SESSION;
2461 2462                                          }
2462 2463  
2463 2464                                          /*
2464 2465                                           * If not able to reach the
2465 2466                                           * server, inform the ldap
2466 2467                                           * cache manager that the
2467 2468                                           * server should be removed
2468 2469                                           * from it's server list.
2469 2470                                           * Thus, the manager will not
2470 2471                                           * return this server on the next
2471 2472                                           * get-server request and will
2472 2473                                           * also reduce the server list
2473 2474                                           * refresh TTL, so that it will
2474 2475                                           * find out sooner when the server
2475 2476                                           * is up again.
2476 2477                                           */
2477 2478                                          if ((rc == LDAP_CONNECT_ERROR ||
2478 2479                                              rc == LDAP_SERVER_DOWN) &&
2479 2480                                              (cookie->conn_user == NULL ||
2480 2481                                              cookie->conn_user->conn_mt ==
2481 2482                                              NULL)) {
2482 2483                                                  ret = __s_api_removeServer(
2483 2484                                                      cookie->conn->serverAddr);
2484 2485                                                  if (ret == NS_CACHE_NOSERVER &&
2485 2486                                                      cookie->conn_auth_type
2486 2487                                                      == NS_LDAP_AUTH_NONE) {
2487 2488                                                          /*
2488 2489                                                           * Couldn't remove
2489 2490                                                           * server from server
2490 2491                                                           * list.
2491 2492                                                           * Exit to avoid
2492 2493                                                           * potential infinite
2493 2494                                                           * loop.
2494 2495                                                           */
2495 2496                                                          cookie->err_rc = rc;
2496 2497                                                          cookie->new_state =
2497 2498                                                              LDAP_ERROR;
2498 2499                                                  }
2499 2500                                                  if (cookie->connectionId > -1) {
2500 2501                                                          /*
2501 2502                                                           * NS_LDAP_NEW_CONN
2502 2503                                                           * indicates that the
2503 2504                                                           * connection should
2504 2505                                                           * be deleted, not
2505 2506                                                           * kept alive
2506 2507                                                           */
2507 2508                                                          DropConnection(
2508 2509                                                              cookie->
2509 2510                                                              connectionId,
2510 2511                                                              NS_LDAP_NEW_CONN);
2511 2512                                                          cookie->connectionId =
2512 2513                                                              -1;
2513 2514                                                  }
2514 2515                                          } else if ((rc == LDAP_CONNECT_ERROR ||
2515 2516                                              rc == LDAP_SERVER_DOWN) &&
2516 2517                                              cookie->conn_user != NULL) {
2517 2518                                                  if (cookie->
2518 2519                                                      reinit_on_retriable_err) {
2519 2520                                                          /*
2520 2521                                                           * MT connection not
2521 2522                                                           * usable, close it
2522 2523                                                           * before REINIT.
2523 2524                                                           * rc has already
2524 2525                                                           * been saved in
2525 2526                                                           * cookie->err_rc above.
2526 2527                                                           */
2527 2528                                                          __s_api_conn_mt_close(
2528 2529                                                              cookie->conn_user,
2529 2530                                                              rc,
2530 2531                                                              &cookie->errorp);
2531 2532                                                  } else {
2532 2533                                                          /*
2533 2534                                                           * MT connection not
2534 2535                                                           * usable, close it in
2535 2536                                                           * the LDAP_ERROR state.
2536 2537                                                           * A retry will be done
2537 2538                                                           * next if allowed.
2538 2539                                                           */
2539 2540                                                          cookie->err_rc = rc;
2540 2541                                                          cookie->new_state =
2541 2542                                                              LDAP_ERROR;
2542 2543                                                  }
2543 2544                                          }
2544 2545                                          break;
2545 2546                                  }
2546 2547                                  cookie->err_rc = rc;
2547 2548                                  cookie->new_state = LDAP_ERROR;
2548 2549                                  break;
2549 2550                          }
2550 2551                          cookie->new_state = cookie->next_state;
2551 2552                          break;
2552 2553                  case NEXT_RESULT:
2553 2554                          /*
2554 2555                           * Caller (e.g. __ns_ldap_list_batch_add)
2555 2556                           * does not want to block on ldap_result().
2556 2557                           * Therefore we execute ldap_result() with
2557 2558                           * a zeroed timeval.
2558 2559                           */
2559 2560                          if (cookie->no_wait == B_TRUE)
2560 2561                                  (void) memset(&tv, 0, sizeof (tv));
2561 2562                          else
2562 2563                                  tv = cookie->search_timeout;
2563 2564                          rc = ldap_result(cookie->conn->ld, cookie->msgId,
2564 2565                              LDAP_MSG_ONE,
2565 2566                              &tv,
2566 2567                              &cookie->resultMsg);
2567 2568                          if (rc == LDAP_RES_SEARCH_RESULT) {
2568 2569                                  cookie->new_state = END_RESULT;
2569 2570                                  /* check and process referrals info */
2570 2571                                  if (cookie->followRef)
2571 2572                                          proc_result_referrals(
2572 2573                                              cookie);
2573 2574                                  (void) ldap_msgfree(cookie->resultMsg);
2574 2575                                  cookie->resultMsg = NULL;
2575 2576                                  break;
2576 2577                          }
2577 2578                          /* handle referrals if necessary */
2578 2579                          if (rc == LDAP_RES_SEARCH_REFERENCE) {
2579 2580                                  if (cookie->followRef)
2580 2581                                          proc_search_references(cookie);
2581 2582                                  (void) ldap_msgfree(cookie->resultMsg);
2582 2583                                  cookie->resultMsg = NULL;
2583 2584                                  break;
2584 2585                          }
2585 2586                          if (rc != LDAP_RES_SEARCH_ENTRY) {
2586 2587                                  switch (rc) {
2587 2588                                  case 0:
2588 2589                                          if (cookie->no_wait == B_TRUE) {
2589 2590                                                  (void) ldap_msgfree(
2590 2591                                                      cookie->resultMsg);
2591 2592                                                  cookie->resultMsg = NULL;
2592 2593                                                  return (cookie->new_state);
2593 2594                                          }
2594 2595                                          rc = LDAP_TIMEOUT;
2595 2596                                          break;
2596 2597                                  case -1:
2597 2598                                          rc = ldap_get_lderrno(cookie->conn->ld,
2598 2599                                              NULL, NULL);
2599 2600                                          break;
2600 2601                                  default:
2601 2602                                          rc = ldap_result2error(cookie->conn->ld,
2602 2603                                              cookie->resultMsg, 1);
2603 2604                                          break;
2604 2605                                  }
2605 2606                                  if ((rc == LDAP_TIMEOUT ||
2606 2607                                      rc == LDAP_SERVER_DOWN) &&
2607 2608                                      (cookie->conn_user == NULL ||
2608 2609                                      cookie->conn_user->conn_mt == NULL)) {
2609 2610                                          if (rc == LDAP_TIMEOUT)
2610 2611                                                  (void) __s_api_removeServer(
2611 2612                                                      cookie->conn->serverAddr);
2612 2613                                          if (cookie->connectionId > -1) {
2613 2614                                                  DropConnection(
2614 2615                                                      cookie->connectionId,
2615 2616                                                      NS_LDAP_NEW_CONN);
2616 2617                                                  cookie->connectionId = -1;
2617 2618                                          }
2618 2619                                          cookie->err_from_result = 1;
2619 2620                                  }
2620 2621                                  (void) ldap_msgfree(cookie->resultMsg);
2621 2622                                  cookie->resultMsg = NULL;
2622 2623                                  if (rc == LDAP_BUSY ||
2623 2624                                      rc == LDAP_UNAVAILABLE ||
2624 2625                                      rc == LDAP_UNWILLING_TO_PERFORM) {
2625 2626                                          if (cookie->reinit_on_retriable_err) {
2626 2627                                                  cookie->err_rc = rc;
2627 2628                                                  cookie->err_from_result = 1;
2628 2629                                                  cookie->new_state = REINIT;
2629 2630                                          } else {
2630 2631                                                  cookie->new_state =
2631 2632                                                      NEXT_SESSION;
2632 2633                                          }
2633 2634                                          break;
2634 2635                                  }
2635 2636                                  if ((rc == LDAP_CONNECT_ERROR ||
2636 2637                                      rc == LDAP_SERVER_DOWN) &&
2637 2638                                      cookie->reinit_on_retriable_err) {
2638 2639                                          ns_ldap_error_t *errorp = NULL;
2639 2640                                          cookie->err_rc = rc;
2640 2641                                          cookie->err_from_result = 1;
2641 2642                                          cookie->new_state = REINIT;
2642 2643                                          if (cookie->conn_user != NULL)
2643 2644                                                  __s_api_conn_mt_close(
2644 2645                                                      cookie->conn_user,
2645 2646                                                      rc, &errorp);
2646 2647                                          if (errorp != NULL) {
2647 2648                                                  (void) __ns_ldap_freeError(
2648 2649                                                      &cookie->errorp);
2649 2650                                                  cookie->errorp = errorp;
2650 2651                                          }
2651 2652                                          break;
2652 2653                                  }
2653 2654                                  cookie->err_rc = rc;
2654 2655                                  cookie->new_state = LDAP_ERROR;
2655 2656                                  break;
2656 2657                          }
2657 2658                          /* else LDAP_RES_SEARCH_ENTRY */
2658 2659                          /* get account management response control */
2659 2660                          if (cookie->nopasswd_acct_mgmt == 1) {
2660 2661                                  rc = ldap_get_entry_controls(cookie->conn->ld,
2661 2662                                      cookie->resultMsg,
2662 2663                                      &(cookie->resultctrl));
2663 2664                                  if (rc != LDAP_SUCCESS) {
2664 2665                                          cookie->new_state = LDAP_ERROR;
2665 2666                                          cookie->err_rc = rc;
2666 2667                                          break;
2667 2668                                  }
2668 2669                          }
2669 2670                          rc = __s_api_getEntry(cookie);
2670 2671                          (void) ldap_msgfree(cookie->resultMsg);
2671 2672                          cookie->resultMsg = NULL;
2672 2673                          if (rc != NS_LDAP_SUCCESS) {
2673 2674                                  cookie->new_state = LDAP_ERROR;
2674 2675                                  break;
2675 2676                          }
2676 2677                          cookie->new_state = PROCESS_RESULT;
2677 2678                          cookie->next_state = NEXT_RESULT;
2678 2679                          break;
2679 2680                  case MULTI_RESULT:
2680 2681                          if (cookie->no_wait == B_TRUE)
2681 2682                                  (void) memset(&tv, 0, sizeof (tv));
2682 2683                          else
2683 2684                                  tv = cookie->search_timeout;
2684 2685                          rc = ldap_result(cookie->conn->ld, cookie->msgId,
2685 2686                              LDAP_MSG_ONE,
2686 2687                              &tv,
2687 2688                              &cookie->resultMsg);
2688 2689                          if (rc == LDAP_RES_SEARCH_RESULT) {
2689 2690                                  rc = ldap_result2error(cookie->conn->ld,
2690 2691                                      cookie->resultMsg, 0);
2691 2692                                  if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2692 2693                                      cookie->listType == VLVCTRLFLAG &&
2693 2694                                      cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2694 2695                                          /* Try old "cn uid" server side sort */
2695 2696                                          cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2696 2697                                          cookie->new_state = NEXT_VLV;
2697 2698                                          (void) ldap_msgfree(cookie->resultMsg);
2698 2699                                          cookie->resultMsg = NULL;
2699 2700                                          break;
2700 2701                                  }
2701 2702                                  if (rc != LDAP_SUCCESS) {
2702 2703                                          cookie->err_rc = rc;
2703 2704                                          cookie->new_state = LDAP_ERROR;
2704 2705                                          (void) ldap_msgfree(cookie->resultMsg);
2705 2706                                          cookie->resultMsg = NULL;
2706 2707                                          break;
2707 2708                                  }
2708 2709                                  cookie->new_state = multi_result(cookie);
2709 2710                                  (void) ldap_msgfree(cookie->resultMsg);
2710 2711                                  cookie->resultMsg = NULL;
2711 2712                                  break;
2712 2713                          }
2713 2714                          /* handle referrals if necessary */
2714 2715                          if (rc == LDAP_RES_SEARCH_REFERENCE &&
2715 2716                              cookie->followRef) {
2716 2717                                  proc_search_references(cookie);
2717 2718                                  (void) ldap_msgfree(cookie->resultMsg);
2718 2719                                  cookie->resultMsg = NULL;
2719 2720                                  break;
2720 2721                          }
2721 2722                          if (rc != LDAP_RES_SEARCH_ENTRY) {
2722 2723                                  switch (rc) {
2723 2724                                  case 0:
2724 2725                                          if (cookie->no_wait == B_TRUE) {
2725 2726                                                  (void) ldap_msgfree(
2726 2727                                                      cookie->resultMsg);
2727 2728                                                  cookie->resultMsg = NULL;
2728 2729                                                  return (cookie->new_state);
2729 2730                                          }
2730 2731                                          rc = LDAP_TIMEOUT;
2731 2732                                          break;
2732 2733                                  case -1:
2733 2734                                          rc = ldap_get_lderrno(cookie->conn->ld,
2734 2735                                              NULL, NULL);
2735 2736                                          break;
2736 2737                                  default:
2737 2738                                          rc = ldap_result2error(cookie->conn->ld,
2738 2739                                              cookie->resultMsg, 1);
2739 2740                                          break;
2740 2741                                  }
2741 2742                                  if ((rc == LDAP_TIMEOUT ||
2742 2743                                      rc == LDAP_SERVER_DOWN) &&
2743 2744                                      (cookie->conn_user == NULL ||
2744 2745                                      cookie->conn_user->conn_mt == NULL)) {
2745 2746                                          if (rc == LDAP_TIMEOUT)
2746 2747                                                  (void) __s_api_removeServer(
2747 2748                                                      cookie->conn->serverAddr);
2748 2749                                          if (cookie->connectionId > -1) {
2749 2750                                                  DropConnection(
2750 2751                                                      cookie->connectionId,
2751 2752                                                      NS_LDAP_NEW_CONN);
2752 2753                                                  cookie->connectionId = -1;
2753 2754                                          }
2754 2755                                          cookie->err_from_result = 1;
2755 2756                                  }
2756 2757                                  (void) ldap_msgfree(cookie->resultMsg);
2757 2758                                  cookie->resultMsg = NULL;
2758 2759                                  if (rc == LDAP_BUSY ||
2759 2760                                      rc == LDAP_UNAVAILABLE ||
2760 2761                                      rc == LDAP_UNWILLING_TO_PERFORM) {
2761 2762                                          if (cookie->reinit_on_retriable_err) {
2762 2763                                                  cookie->err_rc = rc;
2763 2764                                                  cookie->err_from_result = 1;
2764 2765                                                  cookie->new_state = REINIT;
2765 2766                                          } else {
2766 2767                                                  cookie->new_state =
2767 2768                                                      NEXT_SESSION;
2768 2769                                          }
2769 2770                                          break;
2770 2771                                  }
2771 2772  
2772 2773                                  if ((rc == LDAP_CONNECT_ERROR ||
2773 2774                                      rc == LDAP_SERVER_DOWN) &&
2774 2775                                      cookie->reinit_on_retriable_err) {
2775 2776                                          ns_ldap_error_t *errorp = NULL;
2776 2777                                          cookie->err_rc = rc;
2777 2778                                          cookie->err_from_result = 1;
2778 2779                                          cookie->new_state = REINIT;
2779 2780                                          if (cookie->conn_user != NULL)
2780 2781                                                  __s_api_conn_mt_close(
2781 2782                                                      cookie->conn_user,
2782 2783                                                      rc, &errorp);
2783 2784                                          if (errorp != NULL) {
2784 2785                                                  (void) __ns_ldap_freeError(
2785 2786                                                      &cookie->errorp);
2786 2787                                                  cookie->errorp = errorp;
2787 2788                                          }
2788 2789                                          break;
2789 2790                                  }
2790 2791                                  cookie->err_rc = rc;
2791 2792                                  cookie->new_state = LDAP_ERROR;
2792 2793                                  break;
2793 2794                          }
2794 2795                          /* else LDAP_RES_SEARCH_ENTRY */
2795 2796                          cookie->entryCount++;
2796 2797                          rc = __s_api_getEntry(cookie);
2797 2798                          (void) ldap_msgfree(cookie->resultMsg);
2798 2799                          cookie->resultMsg = NULL;
2799 2800                          if (rc != NS_LDAP_SUCCESS) {
2800 2801                                  cookie->new_state = LDAP_ERROR;
2801 2802                                  break;
2802 2803                          }
2803 2804                          /*
2804 2805                           * If VLV search was successfull save the server
2805 2806                           * side sort type tried.
2806 2807                           */
2807 2808                          if (cookie->listType == VLVCTRLFLAG)
2808 2809                                  update_srvsidesort_type(cookie->service,
2809 2810                                      cookie->sortTypeTry);
2810 2811  
2811 2812                          cookie->new_state = PROCESS_RESULT;
2812 2813                          cookie->next_state = MULTI_RESULT;
2813 2814                          break;
2814 2815                  case PROCESS_RESULT:
2815 2816                          /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2816 2817                          if (cookie->use_usercb && cookie->callback) {
2817 2818                                  rc = 0;
2818 2819                                  for (nextEntry = cookie->result->entry;
2819 2820                                      nextEntry != NULL;
2820 2821                                      nextEntry = nextEntry->next) {
2821 2822                                          rc = (*cookie->callback)(nextEntry,
2822 2823                                              cookie->userdata);
2823 2824  
2824 2825                                          if (rc == NS_LDAP_CB_DONE) {
2825 2826                                          /* cb doesn't want any more data */
2826 2827                                                  rc = NS_LDAP_PARTIAL;
2827 2828                                                  cookie->err_rc = rc;
2828 2829                                                  break;
2829 2830                                          } else if (rc != NS_LDAP_CB_NEXT) {
2830 2831                                          /* invalid return code */
2831 2832                                                  rc = NS_LDAP_OP_FAILED;
2832 2833                                                  cookie->err_rc = rc;
2833 2834                                                  break;
2834 2835                                          }
2835 2836                                  }
2836 2837                                  (void) __ns_ldap_freeResult(&cookie->result);
2837 2838                                  cookie->result = NULL;
2838 2839                          }
2839 2840                          if (rc != 0) {
2840 2841                                  cookie->new_state = EXIT;
2841 2842                                  break;
2842 2843                          }
2843 2844                          /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2844 2845                          cookie->new_state = cookie->next_state;
2845 2846                          break;
2846 2847                  case END_PROCESS_RESULT:
2847 2848                          cookie->new_state = cookie->next_state;
2848 2849                          break;
2849 2850                  case END_RESULT:
2850 2851                          /*
2851 2852                           * XXX DO WE NEED THIS CASE?
2852 2853                           * if (search is complete) {
2853 2854                           *      cookie->new_state = EXIT;
2854 2855                           * } else
2855 2856                           */
2856 2857                                  /*
2857 2858                                   * entering referral mode if necessary
2858 2859                                   */
2859 2860                                  if (cookie->followRef && cookie->reflist)
2860 2861                                          cookie->new_state =
2861 2862                                              NEXT_REFERRAL;
2862 2863                                  else
2863 2864                                          cookie->new_state =
2864 2865                                              NEXT_SEARCH_DESCRIPTOR;
2865 2866                          break;
2866 2867                  case NEXT_REFERRAL:
2867 2868                          /* get next referral info */
2868 2869                          if (cookie->refpos == NULL)
2869 2870                                  cookie->refpos =
2870 2871                                      cookie->reflist;
2871 2872                          else
2872 2873                                  cookie->refpos =
2873 2874                                      cookie->refpos->next;
2874 2875                          /* check see if done with all referrals */
2875 2876                          if (cookie->refpos != NULL) {
2876 2877                                  cookie->new_state =
2877 2878                                      GET_REFERRAL_SESSION;
2878 2879                          } else {
2879 2880                                  __s_api_deleteRefInfo(cookie->reflist);
2880 2881                                  cookie->reflist = NULL;
2881 2882                                  cookie->new_state =
2882 2883                                      NEXT_SEARCH_DESCRIPTOR;
2883 2884                                  if (cookie->conn_user != NULL)
2884 2885                                          cookie->conn_user->referral = B_FALSE;
2885 2886                          }
2886 2887                          break;
2887 2888                  case GET_REFERRAL_SESSION:
2888 2889                          if (get_referral_session(cookie) < 0) {
2889 2890                                  cookie->new_state = EXIT;
2890 2891                          } else {
2891 2892                                  cookie->new_state = NEXT_SEARCH;
2892 2893                          }
2893 2894                          break;
2894 2895                  case LDAP_ERROR:
2895 2896                          rc_save = cookie->err_rc;
2896 2897                          if (cookie->err_from_result) {
2897 2898                                  if (cookie->err_rc == LDAP_SERVER_DOWN) {
2898 2899                                          (void) sprintf(errstr,
2899 2900                                              gettext("LDAP ERROR (%d): "
2900 2901                                              "Error occurred during"
2901 2902                                              " receiving results. "
2902 2903                                              "Connection to server lost."),
2903 2904                                              cookie->err_rc);
2904 2905                                  } else if (cookie->err_rc == LDAP_TIMEOUT) {
2905 2906                                          (void) sprintf(errstr,
2906 2907                                              gettext("LDAP ERROR (%d): "
2907 2908                                              "Error occurred during"
2908 2909                                              " receiving results. %s"
2909 2910                                              "."), cookie->err_rc,
2910 2911                                              ldap_err2string(
2911 2912                                              cookie->err_rc));
2912 2913                                  }
2913 2914                          } else {
2914 2915                                  (void) sprintf(errstr,
2915 2916                                      gettext("LDAP ERROR (%d): %s."),
2916 2917                                      cookie->err_rc,
2917 2918                                      ldap_err2string(cookie->err_rc));
2918 2919                          }
2919 2920                          err = strdup(errstr);
2920 2921                          if (cookie->err_from_result) {
2921 2922                                  if (cookie->err_rc == LDAP_SERVER_DOWN) {
2922 2923                                          MKERROR(LOG_INFO, *errorp,
2923 2924                                              cookie->err_rc, err,
2924 2925                                              NS_LDAP_MEMORY);
2925 2926                                  } else {
2926 2927                                          MKERROR(LOG_WARNING, *errorp,
2927 2928                                              cookie->err_rc, err,
2928 2929                                              NS_LDAP_MEMORY);
2929 2930                                  }
2930 2931                          } else {
2931 2932                                  MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2932 2933                                      err, NS_LDAP_MEMORY);
2933 2934                          }
2934 2935                          cookie->err_rc = NS_LDAP_INTERNAL;
2935 2936                          cookie->errorp = *errorp;
2936 2937                          if (cookie->conn_user != NULL)  {
2937 2938                                  if (rc_save == LDAP_SERVER_DOWN ||
2938 2939                                      rc_save == LDAP_CONNECT_ERROR) {
2939 2940                                          /*
2940 2941                                           * MT connection is not usable,
2941 2942                                           * close it.
2942 2943                                           */
2943 2944                                          __s_api_conn_mt_close(cookie->conn_user,
2944 2945                                              rc_save, &cookie->errorp);
2945 2946                                          return (ERROR);
2946 2947                                  }
2947 2948                          }
2948 2949                          return (ERROR);
2949 2950                  default:
2950 2951                  case ERROR:
2951 2952                          (void) sprintf(errstr,
2952 2953                              gettext("Internal State machine exit (%d).\n"),
2953 2954                              cookie->state);
2954 2955                          err = strdup(errstr);
2955 2956                          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2956 2957                              NS_LDAP_MEMORY);
2957 2958                          cookie->err_rc = NS_LDAP_INTERNAL;
2958 2959                          cookie->errorp = *errorp;
2959 2960                          return (ERROR);
2960 2961                  }
2961 2962  
2962 2963                  if (cookie->conn_user != NULL &&
2963 2964                      cookie->conn_user->bad_mt_conn ==  B_TRUE) {
2964 2965                          __s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2965 2966                          cookie->err_rc = cookie->conn_user->ns_rc;
2966 2967                          cookie->errorp = cookie->conn_user->ns_error;
2967 2968                          cookie->conn_user->ns_error = NULL;
2968 2969                          return (ERROR);
2969 2970                  }
2970 2971  
2971 2972                  if (cycle == ONE_STEP) {
2972 2973                          return (cookie->new_state);
2973 2974                  }
2974 2975                  cookie->state = cookie->new_state;
2975 2976          }
2976 2977          /*NOTREACHED*/
2977 2978  #if 0
2978 2979          (void) sprintf(errstr,
2979 2980              gettext("Unexpected State machine error.\n"));
2980 2981          err = strdup(errstr);
2981 2982          MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NS_LDAP_MEMORY);
2982 2983          cookie->err_rc = NS_LDAP_INTERNAL;
2983 2984          cookie->errorp = *errorp;
2984 2985          return (ERROR);
2985 2986  #endif
2986 2987  }
2987 2988  
2988 2989  /*
2989 2990   * For a lookup of shadow data, if shadow update is enabled,
2990 2991   * check the calling process' privilege to ensure it's
2991 2992   * allowed to perform such operation.
2992 2993   */
2993 2994  static int
2994 2995  check_shadow(ns_ldap_cookie_t *cookie, const char *service)
2995 2996  {
2996 2997          char errstr[MAXERROR];
2997 2998          char *err;
2998 2999          boolean_t priv;
2999 3000          /* caller */
3000 3001          priv_set_t *ps;
3001 3002          /* zone */
3002 3003          priv_set_t *zs;
3003 3004  
3004 3005          /*
3005 3006           * If service is "shadow", we may need
3006 3007           * to use privilege credentials.
3007 3008           */
3008 3009          if ((strcmp(service, "shadow") == 0) &&
3009 3010              __ns_ldap_is_shadow_update_enabled()) {
3010 3011                  /*
3011 3012                   * Since we release admin credentials after
3012 3013                   * connection is closed and we do not cache
3013 3014                   * them, we allow any root or all zone
3014 3015                   * privilege process to read shadow data.
3015 3016                   */
3016 3017                  priv = (geteuid() == 0);
3017 3018                  if (!priv) {
3018 3019                          /* caller */
3019 3020                          ps = priv_allocset();
3020 3021  
3021 3022                          (void) getppriv(PRIV_EFFECTIVE, ps);
3022 3023                          zs = priv_str_to_set("zone", ",", NULL);
3023 3024                          priv = priv_isequalset(ps, zs);
3024 3025                          priv_freeset(ps);
3025 3026                          priv_freeset(zs);
3026 3027                  }
3027 3028                  if (!priv) {
3028 3029                          (void) sprintf(errstr,
3029 3030                              gettext("Permission denied"));
3030 3031                          err = strdup(errstr);
3031 3032                          if (err == NULL)
3032 3033                                  return (NS_LDAP_MEMORY);
3033 3034                          MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
3034 3035                              NS_LDAP_MEMORY);
3035 3036                          return (NS_LDAP_INTERNAL);
3036 3037                  }
3037 3038                  cookie->i_flags |= NS_LDAP_READ_SHADOW;
3038 3039                  /*
3039 3040                   * We do not want to reuse connection (hence
3040 3041                   * keep it open) with admin credentials.
3041 3042                   * If NS_LDAP_KEEP_CONN is set, reject the
3042 3043                   * request.
3043 3044                   */
3044 3045                  if (cookie->i_flags & NS_LDAP_KEEP_CONN)
3045 3046                          return (NS_LDAP_INVALID_PARAM);
3046 3047                  cookie->i_flags |= NS_LDAP_NEW_CONN;
3047 3048          }
3048 3049  
3049 3050          return (NS_LDAP_SUCCESS);
3050 3051  }
3051 3052  
3052 3053  /*
3053 3054   * internal function for __ns_ldap_list
3054 3055   */
3055 3056  static int
3056 3057  ldap_list(
3057 3058          ns_ldap_list_batch_t *batch,
3058 3059          const char *service,
3059 3060          const char *filter,
3060 3061          const char *sortattr,
3061 3062          int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3062 3063          char **realfilter, const void *userdata),
3063 3064          const char * const *attribute,
3064 3065          const ns_cred_t *auth,
3065 3066          const int flags,
3066 3067          ns_ldap_result_t **rResult, /* return result entries */
3067 3068          ns_ldap_error_t **errorp,
3068 3069          int *rcp,
3069 3070          int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3070 3071          const void *userdata, ns_conn_user_t *conn_user)
3071 3072  {
3072 3073          ns_ldap_cookie_t        *cookie;
3073 3074          ns_ldap_search_desc_t   **sdlist = NULL;
3074 3075          ns_ldap_search_desc_t   *dptr;
3075 3076          ns_ldap_error_t         *error = NULL;
3076 3077          char                    **dns = NULL;
3077 3078          int                     scope;
3078 3079          int                     rc;
3079 3080          int                     from_result;
3080 3081  
3081 3082          *errorp = NULL;
3082 3083          *rResult = NULL;
3083 3084          *rcp = NS_LDAP_SUCCESS;
3084 3085  
3085 3086          /*
3086 3087           * Sanity check - NS_LDAP_READ_SHADOW is for our
3087 3088           * own internal use.
3088 3089           */
3089 3090          if (flags & NS_LDAP_READ_SHADOW)
3090 3091                  return (NS_LDAP_INVALID_PARAM);
3091 3092  
3092 3093          /* Initialize State machine cookie */
3093 3094          cookie = init_search_state_machine();
3094 3095          if (cookie == NULL) {
3095 3096                  *rcp = NS_LDAP_MEMORY;
3096 3097                  return (NS_LDAP_MEMORY);
3097 3098          }
3098 3099          cookie->conn_user = conn_user;
3099 3100  
3100 3101          /* see if need to follow referrals */
3101 3102          rc = __s_api_toFollowReferrals(flags,
3102 3103              &cookie->followRef, errorp);
3103 3104          if (rc != NS_LDAP_SUCCESS) {
3104 3105                  delete_search_cookie(cookie);
3105 3106                  *rcp = rc;
3106 3107                  return (rc);
3107 3108          }
3108 3109  
3109 3110          /* get the service descriptor - or create a default one */
3110 3111          rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3111 3112              &sdlist, &error);
3112 3113          if (rc != NS_LDAP_SUCCESS) {
3113 3114                  delete_search_cookie(cookie);
3114 3115                  *errorp = error;
3115 3116                  *rcp = rc;
3116 3117                  return (rc);
3117 3118          }
3118 3119  
3119 3120          if (sdlist == NULL) {
3120 3121                  /* Create default service Desc */
3121 3122                  sdlist = (ns_ldap_search_desc_t **)calloc(2,
3122 3123                      sizeof (ns_ldap_search_desc_t *));
3123 3124                  if (sdlist == NULL) {
3124 3125                          delete_search_cookie(cookie);
3125 3126                          cookie = NULL;
3126 3127                          *rcp = NS_LDAP_MEMORY;
3127 3128                          return (NS_LDAP_MEMORY);
3128 3129                  }
3129 3130                  dptr = (ns_ldap_search_desc_t *)
3130 3131                      calloc(1, sizeof (ns_ldap_search_desc_t));
3131 3132                  if (dptr == NULL) {
3132 3133                          free(sdlist);
3133 3134                          delete_search_cookie(cookie);
3134 3135                          cookie = NULL;
3135 3136                          *rcp = NS_LDAP_MEMORY;
3136 3137                          return (NS_LDAP_MEMORY);
3137 3138                  }
3138 3139                  sdlist[0] = dptr;
3139 3140  
3140 3141                  /* default base */
3141 3142                  rc = __s_api_getDNs(&dns, service, &cookie->errorp);
3142 3143                  if (rc != NS_LDAP_SUCCESS) {
3143 3144                          if (dns) {
3144 3145                                  __s_api_free2dArray(dns);
3145 3146                                  dns = NULL;
3146 3147                          }
3147 3148                          *errorp = cookie->errorp;
3148 3149                          cookie->errorp = NULL;
3149 3150                          delete_search_cookie(cookie);
3150 3151                          cookie = NULL;
3151 3152                          *rcp = rc;
3152 3153                          return (rc);
3153 3154                  }
3154 3155                  dptr->basedn = strdup(dns[0]);
3155 3156                  __s_api_free2dArray(dns);
3156 3157                  dns = NULL;
3157 3158  
3158 3159                  /* default scope */
3159 3160                  scope = 0;
3160 3161                  rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3161 3162                  dptr->scope = scope;
3162 3163          }
3163 3164  
3164 3165          cookie->sdlist = sdlist;
3165 3166  
3166 3167          /*
3167 3168           * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3168 3169           */
3169 3170          if (flags & NS_LDAP_PAGE_CTRL)
3170 3171                  cookie->use_paging = TRUE;
3171 3172          else
3172 3173                  cookie->use_paging = FALSE;
3173 3174  
3174 3175          /* Set up other arguments */
3175 3176          cookie->userdata = userdata;
3176 3177          if (init_filter_cb != NULL) {
3177 3178                  cookie->init_filter_cb = init_filter_cb;
3178 3179                  cookie->use_filtercb = 1;
3179 3180          }
3180 3181          if (callback != NULL) {
3181 3182                  cookie->callback = callback;
3182 3183                  cookie->use_usercb = 1;
3183 3184          }
3184 3185  
3185 3186          /* check_shadow() may add extra value to cookie->i_flags */
3186 3187          cookie->i_flags = flags;
3187 3188          if (service) {
3188 3189                  cookie->service = strdup(service);
3189 3190                  if (cookie->service == NULL) {
3190 3191                          delete_search_cookie(cookie);
3191 3192                          cookie = NULL;
3192 3193                          *rcp = NS_LDAP_MEMORY;
3193 3194                          return (NS_LDAP_MEMORY);
3194 3195                  }
3195 3196  
3196 3197                  /*
3197 3198                   * If given, use the credential given by the caller, and
3198 3199                   * skip the credential check required for shadow update.
3199 3200                   */
3200 3201                  if (auth == NULL) {
3201 3202                          rc = check_shadow(cookie, service);
3202 3203                          if (rc != NS_LDAP_SUCCESS) {
3203 3204                                  *errorp = cookie->errorp;
3204 3205                                  cookie->errorp = NULL;
3205 3206                                  delete_search_cookie(cookie);
3206 3207                                  cookie = NULL;
3207 3208                                  *rcp = rc;
3208 3209                                  return (rc);
3209 3210                          }
3210 3211                  }
3211 3212          }
3212 3213  
3213 3214          cookie->i_filter = strdup(filter);
3214 3215          cookie->i_attr = attribute;
3215 3216          cookie->i_auth = auth;
3216 3217          cookie->i_sortattr = sortattr;
3217 3218  
3218 3219          if (batch != NULL) {
3219 3220                  cookie->batch = batch;
3220 3221                  cookie->reinit_on_retriable_err = B_TRUE;
3221 3222                  cookie->no_wait = B_TRUE;
3222 3223                  (void) search_state_machine(cookie, INIT, 0);
3223 3224                  cookie->no_wait = B_FALSE;
3224 3225                  rc = cookie->err_rc;
3225 3226  
3226 3227                  if (rc == NS_LDAP_SUCCESS) {
3227 3228                          /*
3228 3229                           * Here rc == NS_LDAP_SUCCESS means that the state
3229 3230                           * machine init'ed successfully. The actual status
3230 3231                           * of the search will be determined by
3231 3232                           * __ns_ldap_list_batch_end(). Add the cookie to our
3232 3233                           * batch.
3233 3234                           */
3234 3235                          cookie->caller_result = rResult;
3235 3236                          cookie->caller_errorp = errorp;
3236 3237                          cookie->caller_rc = rcp;
3237 3238                          cookie->next_cookie_in_batch = batch->cookie_list;
3238 3239                          batch->cookie_list = cookie;
3239 3240                          batch->nactive++;
3240 3241                          return (rc);
3241 3242                  }
3242 3243                  /*
3243 3244                   * If state machine init failed then copy error to the caller
3244 3245                   * and delete the cookie.
3245 3246                   */
3246 3247          } else {
3247 3248                  (void) search_state_machine(cookie, INIT, 0);
3248 3249          }
3249 3250  
3250 3251          /* Copy results back to user */
3251 3252          rc = cookie->err_rc;
3252 3253          if (rc != NS_LDAP_SUCCESS) {
3253 3254                  if (conn_user != NULL && conn_user->ns_error != NULL) {
3254 3255                          *errorp = conn_user->ns_error;
3255 3256                          conn_user->ns_error = NULL;
3256 3257                  } else {
3257 3258                          *errorp = cookie->errorp;
3258 3259                  }
3259 3260          }
3260 3261          *rResult = cookie->result;
3261 3262          from_result = cookie->err_from_result;
3262 3263  
3263 3264          cookie->errorp = NULL;
3264 3265          cookie->result = NULL;
3265 3266          delete_search_cookie(cookie);
3266 3267          cookie = NULL;
3267 3268  
3268 3269          if (from_result == 0 && *rResult == NULL)
3269 3270                  rc = NS_LDAP_NOTFOUND;
3270 3271          *rcp = rc;
3271 3272          return (rc);
3272 3273  }
3273 3274  
3274 3275  
3275 3276  /*
3276 3277   * __ns_ldap_list performs one or more LDAP searches to a given
3277 3278   * directory server using service search descriptors and schema
3278 3279   * mapping as appropriate. The operation may be retried a
3279 3280   * couple of times in error situations.
3280 3281   */
3281 3282  int
3282 3283  __ns_ldap_list(
3283 3284          const char *service,
3284 3285          const char *filter,
3285 3286          int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3286 3287          char **realfilter, const void *userdata),
3287 3288          const char * const *attribute,
3288 3289          const ns_cred_t *auth,
3289 3290          const int flags,
3290 3291          ns_ldap_result_t **rResult, /* return result entries */
3291 3292          ns_ldap_error_t **errorp,
3292 3293          int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3293 3294          const void *userdata)
3294 3295  {
3295 3296          int mod_flags;
3296 3297          /*
3297 3298           * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3298 3299           * support this. If you want to use this option call the API
3299 3300           * __ns_ldap_list_sort() with has the sort attribute.
3300 3301           */
3301 3302          mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3302 3303  
3303 3304          return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
3304 3305              attribute, auth, mod_flags, rResult, errorp,
3305 3306              callback, userdata));
3306 3307  }
3307 3308  
3308 3309  /*
3309 3310   * __ns_ldap_list_sort performs one or more LDAP searches to a given
3310 3311   * directory server using service search descriptors and schema
3311 3312   * mapping as appropriate. The operation may be retried a
3312 3313   * couple of times in error situations.
3313 3314   */
3314 3315  int
3315 3316  __ns_ldap_list_sort(
3316 3317          const char *service,
3317 3318          const char *filter,
3318 3319          const char *sortattr,
3319 3320          int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3320 3321          char **realfilter, const void *userdata),
3321 3322          const char * const *attribute,
3322 3323          const ns_cred_t *auth,
3323 3324          const int flags,
3324 3325          ns_ldap_result_t **rResult, /* return result entries */
3325 3326          ns_ldap_error_t **errorp,
3326 3327          int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3327 3328          const void *userdata)
3328 3329  {
3329 3330          ns_conn_user_t  *cu = NULL;
3330 3331          int             try_cnt = 0;
3331 3332          int             rc = NS_LDAP_SUCCESS, trc;
3332 3333  
3333 3334          for (;;) {
3334 3335                  if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3335 3336                      &try_cnt, &rc, errorp) == 0)
3336 3337                          break;
3337 3338                  rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
3338 3339                      attribute, auth, flags, rResult, errorp, &trc, callback,
3339 3340                      userdata, cu);
3340 3341          }
3341 3342  
3342 3343          return (rc);
3343 3344  }
3344 3345  
3345 3346  /*
3346 3347   * Create and initialize batch for native LDAP lookups
3347 3348   */
3348 3349  int
3349 3350  __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
3350 3351  {
3351 3352          *batch = calloc(1, sizeof (ns_ldap_list_batch_t));
3352 3353          if (*batch == NULL)
3353 3354                  return (NS_LDAP_MEMORY);
3354 3355          return (NS_LDAP_SUCCESS);
3355 3356  }
3356 3357  
3357 3358  
3358 3359  /*
3359 3360   * Add a LDAP search request to the batch.
3360 3361   */
3361 3362  int
3362 3363  __ns_ldap_list_batch_add(
3363 3364          ns_ldap_list_batch_t *batch,
3364 3365          const char *service,
3365 3366          const char *filter,
3366 3367          int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3367 3368          char **realfilter, const void *userdata),
3368 3369          const char * const *attribute,
3369 3370          const ns_cred_t *auth,
3370 3371          const int flags,
3371 3372          ns_ldap_result_t **rResult, /* return result entries */
3372 3373          ns_ldap_error_t **errorp,
3373 3374          int *rcp,
3374 3375          int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3375 3376          const void *userdata)
3376 3377  {
3377 3378          ns_conn_user_t  *cu;
3378 3379          int             rc;
3379 3380          int             mod_flags;
3380 3381  
3381 3382          cu =  __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
3382 3383          if (cu == NULL) {
3383 3384                  if (rcp != NULL)
3384 3385                          *rcp = NS_LDAP_MEMORY;
3385 3386                  return (NS_LDAP_MEMORY);
3386 3387          }
3387 3388  
3388 3389          /*
3389 3390           * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3390 3391           * support this.
3391 3392           */
3392 3393          mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3393 3394  
3394 3395          rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
3395 3396              auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
3396 3397  
3397 3398          /*
3398 3399           * Free the conn_user if the cookie was not batched. If the cookie
3399 3400           * was batched then __ns_ldap_list_batch_end or release will free the
3400 3401           * conn_user. The batch API instructs the search_state_machine
3401 3402           * to reinit and retry (max 3 times) on retriable LDAP errors.
3402 3403           */
3403 3404          if (rc != NS_LDAP_SUCCESS && cu != NULL) {
3404 3405                  if (cu->conn_mt != NULL)
3405 3406                          __s_api_conn_mt_return(cu);
3406 3407                  __s_api_conn_user_free(cu);
3407 3408          }
3408 3409          return (rc);
3409 3410  }
3410 3411  
3411 3412  
3412 3413  /*
3413 3414   * Free batch.
3414 3415   */
3415 3416  void
3416 3417  __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
3417 3418  {
3418 3419          ns_ldap_cookie_t        *c, *next;
3419 3420  
3420 3421          for (c = batch->cookie_list; c != NULL; c = next) {
3421 3422                  next = c->next_cookie_in_batch;
3422 3423                  if (c->conn_user != NULL) {
3423 3424                          if (c->conn_user->conn_mt != NULL)
3424 3425                                  __s_api_conn_mt_return(c->conn_user);
3425 3426                          __s_api_conn_user_free(c->conn_user);
3426 3427                          c->conn_user = NULL;
3427 3428                  }
3428 3429                  delete_search_cookie(c);
3429 3430          }
3430 3431          free(batch);
3431 3432  }
3432 3433  
3433 3434  #define LD_USING_STATE(st) \
3434 3435          ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3435 3436  
3436 3437  /*
3437 3438   * Process batch. Everytime this function is called it selects an
3438 3439   * active cookie from the batch and single steps through the
3439 3440   * search_state_machine for the selected cookie. If lookup associated
3440 3441   * with the cookie is complete (success or error) then the cookie is
3441 3442   * removed from the batch and its memory freed.
3442 3443   *
3443 3444   * Returns 1 (if batch still has active cookies)
3444 3445   *         0 (if batch has no more active cookies)
3445 3446   *        -1 (on errors, *rcp will contain the error code)
3446 3447   *
3447 3448   * The caller should call this function in a loop as long as it returns 1
3448 3449   * to process all the requests added to the batch. The results (and errors)
3449 3450   * will be available in the locations provided by the caller at the time of
3450 3451   * __ns_ldap_list_batch_add().
3451 3452   */
3452 3453  static
3453 3454  int
3454 3455  __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
3455 3456  {
3456 3457          ns_ldap_cookie_t        *c, *ptr, **prev;
3457 3458          ns_state_t              state;
3458 3459          ns_ldap_error_t         *errorp = NULL;
3459 3460          int                     rc;
3460 3461  
3461 3462          /* Check if are already done */
3462 3463          if (batch->nactive == 0)
3463 3464                  return (0);
3464 3465  
3465 3466          /* Get the next cookie from the batch */
3466 3467          c = (batch->next_cookie == NULL) ?
3467 3468              batch->cookie_list : batch->next_cookie;
3468 3469  
3469 3470          batch->next_cookie = c->next_cookie_in_batch;
3470 3471  
3471 3472          /*
3472 3473           * Checks the status of the cookie's connection if it needs
3473 3474           * to use that connection for ldap_search_ext or ldap_result.
3474 3475           * If the connection is no longer good but worth retrying
3475 3476           * then reinit the search_state_machine for this cookie
3476 3477           * starting from the first search descriptor. REINIT will
3477 3478           * clear any leftover results if max retries have not been
3478 3479           * reached and redo the search (which may also involve
3479 3480           * following referrals again).
3480 3481           *
3481 3482           * Note that each cookie in the batch will make this
3482 3483           * determination when it reaches one of the LD_USING_STATES.
3483 3484           */
3484 3485          if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
3485 3486                  rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
3486 3487                  if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
3487 3488                      rc == LDAP_UNWILLING_TO_PERFORM) {
3488 3489                          if (errorp != NULL) {
3489 3490                                  (void) __ns_ldap_freeError(&c->errorp);
3490 3491                                  c->errorp = errorp;
3491 3492                          }
3492 3493                          c->new_state = REINIT;
3493 3494                  } else if (rc == LDAP_CONNECT_ERROR ||
3494 3495                      rc == LDAP_SERVER_DOWN) {
3495 3496                          if (errorp != NULL) {
3496 3497                                  (void) __ns_ldap_freeError(&c->errorp);
3497 3498                                  c->errorp = errorp;
3498 3499                          }
3499 3500                          c->new_state = REINIT;
3500 3501                          /*
3501 3502                           * MT connection is not usable,
3502 3503                           * close it before REINIT.
3503 3504                           */
3504 3505                          __s_api_conn_mt_close(
3505 3506                              c->conn_user, rc, NULL);
3506 3507                  } else if (rc != NS_LDAP_SUCCESS) {
3507 3508                          if (rcp != NULL)
3508 3509                                  *rcp = rc;
3509 3510                          *c->caller_result = NULL;
3510 3511                          *c->caller_errorp = errorp;
3511 3512                          *c->caller_rc = rc;
3512 3513                          return (-1);
3513 3514                  }
3514 3515          }
3515 3516  
3516 3517          for (;;) {
3517 3518                  /* Single step through the search_state_machine */
3518 3519                  state = search_state_machine(c, c->new_state, ONE_STEP);
3519 3520                  switch (state) {
3520 3521                  case LDAP_ERROR:
3521 3522                          (void) search_state_machine(c, state, ONE_STEP);
3522 3523                          (void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
3523 3524                          /* FALLTHROUGH */
3524 3525                  case ERROR:
3525 3526                  case EXIT:
3526 3527                          *c->caller_result = c->result;
3527 3528                          *c->caller_errorp = c->errorp;
3528 3529                          *c->caller_rc =
3529 3530                              (c->result == NULL && c->err_from_result == 0)
3530 3531                              ? NS_LDAP_NOTFOUND : c->err_rc;
3531 3532                          c->result = NULL;
3532 3533                          c->errorp = NULL;
3533 3534                          /* Remove the cookie from the batch */
3534 3535                          ptr = batch->cookie_list;
3535 3536                          prev = &batch->cookie_list;
3536 3537                          while (ptr != NULL) {
3537 3538                                  if (ptr == c) {
3538 3539                                          *prev = ptr->next_cookie_in_batch;
3539 3540                                          break;
3540 3541                                  }
3541 3542                                  prev = &ptr->next_cookie_in_batch;
3542 3543                                  ptr = ptr->next_cookie_in_batch;
3543 3544                          }
3544 3545                          /* Delete cookie and decrement active cookie count */
3545 3546                          if (c->conn_user != NULL) {
3546 3547                                  if (c->conn_user->conn_mt != NULL)
3547 3548                                          __s_api_conn_mt_return(c->conn_user);
3548 3549                                  __s_api_conn_user_free(c->conn_user);
3549 3550                                  c->conn_user = NULL;
3550 3551                          }
3551 3552                          delete_search_cookie(c);
3552 3553                          batch->nactive--;
3553 3554                          break;
3554 3555                  case NEXT_RESULT:
3555 3556                  case MULTI_RESULT:
3556 3557                          /*
3557 3558                           * This means that search_state_machine needs to do
3558 3559                           * another ldap_result() for the cookie in question.
3559 3560                           * We only do at most one ldap_result() per call in
3560 3561                           * this function and therefore we return. This allows
3561 3562                           * the caller to process results from other cookies
3562 3563                           * in the batch without getting tied up on just one
3563 3564                           * cookie.
3564 3565                           */
3565 3566                          break;
3566 3567                  default:
3567 3568                          /*
3568 3569                           * This includes states that follow NEXT_RESULT or
3569 3570                           * MULTI_RESULT such as PROCESS_RESULT and
3570 3571                           * END_PROCESS_RESULT. We continue processing
3571 3572                           * this cookie till we reach either the error, exit
3572 3573                           * or the result states.
3573 3574                           */
3574 3575                          continue;
3575 3576                  }
3576 3577                  break;
3577 3578          }
3578 3579  
3579 3580          /* Return 0 if no more cookies left otherwise 1 */
3580 3581          return ((batch->nactive > 0) ? 1 : 0);
3581 3582  }
3582 3583  
3583 3584  
3584 3585  /*
3585 3586   * Process all the active cookies in the batch and when none
3586 3587   * remains finalize the batch.
3587 3588   */
  
    | 
      ↓ open down ↓ | 
    3554 lines elided | 
    
      ↑ open up ↑ | 
  
3588 3589  int
3589 3590  __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3590 3591  {
3591 3592          int rc = NS_LDAP_SUCCESS;
3592 3593          while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3593 3594                  ;
3594 3595          __ns_ldap_list_batch_release(batch);
3595 3596          return (rc);
3596 3597  }
3597 3598  
     3599 +typedef struct lookup_data {
     3600 +        const char *lkd_dn;
     3601 +        const char *lkd_service;
     3602 +        const char *lkd_filter;
     3603 +        const ns_cred_t *lkd_cred;
     3604 +        ns_conn_user_t *lkd_user;
     3605 +} lookup_data_t;
     3606 +
3598 3607  /*
3599      - * find_domainname performs one or more LDAP searches to
3600      - * find the value of the nisdomain attribute associated with
3601      - * the input DN (with no retry).
     3608 + * This creates a service search descriptor that can be used to
     3609 + * retrieve a specific DN by using the DN as the basedn with a search
     3610 + * scope of 'base'. We don't use any service SSDs in this instance since
     3611 + * they are intended to search specific locations/subtrees and filter the
     3612 + * results, while here we are wanting to retrieve a specific entry.
3602 3613   */
3603      -
3604 3614  static int
3605      -find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3606      -    ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
     3615 +lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp)
3607 3616  {
     3617 +        ns_ldap_search_desc_t *dptr;
3608 3618  
     3619 +        *descpp = NULL;
     3620 +
     3621 +        dptr = calloc(1, sizeof (ns_ldap_search_desc_t));
     3622 +        if (dptr == NULL)
     3623 +                return (NS_LDAP_MEMORY);
     3624 +
     3625 +        dptr->basedn = strdup(dn_data->lkd_dn);
     3626 +        dptr->scope = NS_LDAP_SCOPE_BASE;
     3627 +        dptr->filter = strdup(UIDFILTER);
     3628 +
     3629 +        if (dptr->basedn == NULL || dptr->filter == NULL) {
     3630 +                __ns_ldap_freeASearchDesc(dptr);
     3631 +                return (NS_LDAP_MEMORY);
     3632 +        }
     3633 +
     3634 +        *descpp = dptr;
     3635 +        return (NS_LDAP_SUCCESS);
     3636 +}
     3637 +
     3638 +static int
     3639 +lookup_dn(lookup_data_t *dn_data, const char **attrs,
     3640 +    ns_ldap_result_t **resultp, ns_ldap_error_t **errorp)
     3641 +{
3609 3642          ns_ldap_cookie_t        *cookie;
3610      -        ns_ldap_search_desc_t   **sdlist;
3611      -        ns_ldap_search_desc_t   *dptr;
3612      -        int                     rc;
3613      -        char                    **value;
     3643 +        int                     rc = 0;
3614 3644          int                     flags = 0;
3615 3645  
3616      -        *domainname = NULL;
3617 3646          *errorp = NULL;
     3647 +        *resultp = NULL;
3618 3648  
3619      -        /* Initialize State machine cookie */
     3649 +        if (dn_data == NULL || dn_data->lkd_dn == NULL ||
     3650 +            dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL)
     3651 +                return (NS_LDAP_INVALID_PARAM);
     3652 +
3620 3653          cookie = init_search_state_machine();
3621      -        if (cookie == NULL) {
     3654 +        if (cookie == NULL)
3622 3655                  return (NS_LDAP_MEMORY);
3623      -        }
3624      -        cookie->conn_user = conn_user;
3625 3656  
3626      -        /* see if need to follow referrals */
3627      -        rc = __s_api_toFollowReferrals(flags,
3628      -            &cookie->followRef, errorp);
3629      -        if (rc != NS_LDAP_SUCCESS) {
3630      -                delete_search_cookie(cookie);
3631      -                return (rc);
3632      -        }
     3657 +        rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp);
     3658 +        if (rc != NS_LDAP_SUCCESS)
     3659 +                goto out;
3633 3660  
3634      -        /* Create default service Desc */
3635      -        sdlist = (ns_ldap_search_desc_t **)calloc(2,
3636      -            sizeof (ns_ldap_search_desc_t *));
3637      -        if (sdlist == NULL) {
3638      -                delete_search_cookie(cookie);
3639      -                cookie = NULL;
3640      -                return (NS_LDAP_MEMORY);
     3661 +        /* 1 for SSD, 1 for terminating NULL */
     3662 +        cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *));
     3663 +        if (cookie->sdlist == NULL) {
     3664 +                rc = NS_LDAP_MEMORY;
     3665 +                goto out;
3641 3666          }
3642      -        dptr = (ns_ldap_search_desc_t *)
3643      -            calloc(1, sizeof (ns_ldap_search_desc_t));
3644      -        if (dptr == NULL) {
3645      -                free(sdlist);
3646      -                delete_search_cookie(cookie);
3647      -                cookie = NULL;
3648      -                return (NS_LDAP_MEMORY);
3649      -        }
3650      -        sdlist[0] = dptr;
3651 3667  
3652      -        /* search base is dn */
3653      -        dptr->basedn = strdup(dn);
     3668 +        rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]);
     3669 +        if (rc != NS_LDAP_SUCCESS)
     3670 +                goto out;
3654 3671  
3655      -        /* search scope is base */
3656      -        dptr->scope = NS_LDAP_SCOPE_BASE;
     3672 +        if (dn_data->lkd_service != NULL) {
     3673 +                /*
     3674 +                 * If a service was specified, set that on the cookie so
     3675 +                 * that search_state_machine() will properly map
     3676 +                 * attributes and objectclasses.
     3677 +                 */
     3678 +                cookie->service = strdup(dn_data->lkd_service);
     3679 +                if (cookie->service == NULL) {
     3680 +                        rc = NS_LDAP_MEMORY;
     3681 +                        goto out;
     3682 +                }
     3683 +        }
3657 3684  
3658      -        /* search filter is "nisdomain=*" */
3659      -        dptr->filter = strdup(_NIS_FILTER);
3660      -
3661      -        cookie->sdlist = sdlist;
3662      -        cookie->i_filter = strdup(dptr->filter);
3663      -        cookie->i_attr = nis_domain_attrs;
3664      -        cookie->i_auth = cred;
     3685 +        cookie->i_attr = attrs;
     3686 +        cookie->i_auth = dn_data->lkd_cred;
3665 3687          cookie->i_flags = 0;
     3688 +        cookie->i_filter = strdup(dn_data->lkd_filter);
     3689 +        if (cookie->i_filter == NULL) {
     3690 +                rc = NS_LDAP_MEMORY;
     3691 +                goto out;
     3692 +        }
3666 3693  
3667      -        /* Process search */
3668      -        rc = search_state_machine(cookie, INIT, 0);
3669      -
3670      -        /* Copy domain name if found */
     3694 +        /*
     3695 +         * Actually perform the search. The return value is only used when
     3696 +         * iterating through multiple results. Since we are searching with
     3697 +         * a scope of base, we will always get at most one result entry,
     3698 +         * we ignore the return value and look at err_rc to determine if
     3699 +         * there were any errors.
     3700 +         */
     3701 +        (void) search_state_machine(cookie, INIT, 0);
3671 3702          rc = cookie->err_rc;
     3703 +
3672 3704          if (rc != NS_LDAP_SUCCESS) {
3673      -                if (conn_user != NULL && conn_user->ns_error != NULL) {
3674      -                        *errorp = conn_user->ns_error;
3675      -                        conn_user->ns_error = NULL;
     3705 +                ns_conn_user_t *user = dn_data->lkd_user;
     3706 +
     3707 +                if (user != NULL && user->ns_error != NULL) {
     3708 +                        *errorp = user->ns_error;
     3709 +                        user->ns_error = NULL;
3676 3710                  } else {
3677 3711                          *errorp = cookie->errorp;
     3712 +                        cookie->errorp = NULL;
3678 3713                  }
3679      -        }
3680      -        if (cookie->result == NULL)
     3714 +        } else if (cookie->result != NULL) {
     3715 +                *resultp = cookie->result;
     3716 +                cookie->result = NULL;
     3717 +        } else {
3681 3718                  rc = NS_LDAP_NOTFOUND;
3682      -        if (rc == NS_LDAP_SUCCESS) {
3683      -                value = __ns_ldap_getAttr(cookie->result->entry,
3684      -                    _NIS_DOMAIN);
3685      -                if (value[0])
3686      -                        *domainname = strdup(value[0]);
3687      -                else
3688      -                        rc = NS_LDAP_NOTFOUND;
3689 3719          }
3690      -        if (cookie->result != NULL)
3691      -                (void) __ns_ldap_freeResult(&cookie->result);
3692      -        cookie->errorp = NULL;
     3720 +
     3721 +out:
3693 3722          delete_search_cookie(cookie);
3694      -        cookie = NULL;
3695 3723          return (rc);
3696 3724  }
3697 3725  
3698 3726  /*
     3727 + * find_domainname performs one or more LDAP searches to
     3728 + * find the value of the nisdomain attribute associated with
     3729 + * the input DN (with no retry).
     3730 + */
     3731 +
     3732 +static int
     3733 +find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
     3734 +    ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
     3735 +{
     3736 +        lookup_data_t           ldata;
     3737 +        ns_ldap_result_t        *result;
     3738 +        char                    **value;
     3739 +        int                     rc;
     3740 +
     3741 +        *domainname = NULL;
     3742 +        *errorp = NULL;
     3743 +
     3744 +        ldata.lkd_dn = dn;
     3745 +        ldata.lkd_service = NULL;
     3746 +        ldata.lkd_filter = _NIS_FILTER;
     3747 +        ldata.lkd_cred = cred;
     3748 +        ldata.lkd_user = conn_user;
     3749 +
     3750 +        rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp);
     3751 +        if (rc != NS_LDAP_SUCCESS)
     3752 +                return (rc);
     3753 +
     3754 +        value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN);
     3755 +
     3756 +        if (value != NULL && value[0] != NULL) {
     3757 +                *domainname = strdup(value[0]);
     3758 +                if (*domainname == NULL)
     3759 +                        rc = NS_LDAP_MEMORY;
     3760 +        } else {
     3761 +                rc = NS_LDAP_NOTFOUND;
     3762 +        }
     3763 +
     3764 +        (void) __ns_ldap_freeResult(&result);
     3765 +        return (rc);
     3766 +}
     3767 +
     3768 +/*
3699 3769   * __s_api_find_domainname performs one or more LDAP searches to
3700 3770   * find the value of the nisdomain attribute associated with
3701 3771   * the input DN (with retry).
3702 3772   */
3703 3773  
3704 3774  static int
3705 3775  __s_api_find_domainname(const char *dn, char **domainname,
3706 3776      const ns_cred_t *cred, ns_ldap_error_t **errorp)
3707 3777  {
3708 3778          ns_conn_user_t  *cu = NULL;
3709 3779          int             try_cnt = 0;
3710 3780          int             rc = NS_LDAP_SUCCESS;
3711 3781  
3712 3782          for (;;) {
3713 3783                  if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3714 3784                      &try_cnt, &rc, errorp) == 0)
3715 3785                          break;
3716 3786                  rc = find_domainname(dn, domainname, cred, errorp, cu);
3717 3787          }
3718 3788  
3719 3789          return (rc);
3720 3790  }
3721 3791  
3722 3792  static int
3723 3793  firstEntry(
3724 3794      const char *service,
3725 3795      const char *filter,
3726 3796      const char *sortattr,
3727 3797      int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3728 3798      char **realfilter, const void *userdata),
3729 3799      const char * const *attribute,
3730 3800      const ns_cred_t *auth,
3731 3801      const int flags,
3732 3802      void **vcookie,
3733 3803      ns_ldap_result_t **result,
3734 3804      ns_ldap_error_t ** errorp,
3735 3805      const void *userdata,
3736 3806      ns_conn_user_t *conn_user)
3737 3807  {
3738 3808          ns_ldap_cookie_t        *cookie = NULL;
3739 3809          ns_ldap_error_t         *error = NULL;
3740 3810          ns_state_t              state;
3741 3811          ns_ldap_search_desc_t   **sdlist;
3742 3812          ns_ldap_search_desc_t   *dptr;
3743 3813          char                    **dns = NULL;
3744 3814          int                     scope;
3745 3815          int                     rc;
3746 3816  
3747 3817          *errorp = NULL;
3748 3818          *result = NULL;
3749 3819  
3750 3820          /*
3751 3821           * Sanity check - NS_LDAP_READ_SHADOW is for our
3752 3822           * own internal use.
3753 3823           */
3754 3824          if (flags & NS_LDAP_READ_SHADOW)
3755 3825                  return (NS_LDAP_INVALID_PARAM);
3756 3826  
3757 3827          /* get the service descriptor - or create a default one */
3758 3828          rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3759 3829              &sdlist, &error);
3760 3830          if (rc != NS_LDAP_SUCCESS) {
3761 3831                  *errorp = error;
3762 3832                  return (rc);
3763 3833          }
3764 3834          if (sdlist == NULL) {
3765 3835                  /* Create default service Desc */
3766 3836                  sdlist = (ns_ldap_search_desc_t **)calloc(2,
3767 3837                      sizeof (ns_ldap_search_desc_t *));
3768 3838                  if (sdlist == NULL) {
3769 3839                          return (NS_LDAP_MEMORY);
3770 3840                  }
3771 3841                  dptr = (ns_ldap_search_desc_t *)
3772 3842                      calloc(1, sizeof (ns_ldap_search_desc_t));
3773 3843                  if (dptr == NULL) {
3774 3844                          free(sdlist);
3775 3845                          return (NS_LDAP_MEMORY);
3776 3846                  }
3777 3847                  sdlist[0] = dptr;
3778 3848  
3779 3849                  /* default base */
3780 3850                  rc = __s_api_getDNs(&dns, service, &error);
3781 3851                  if (rc != NS_LDAP_SUCCESS) {
3782 3852                          if (dns) {
3783 3853                                  __s_api_free2dArray(dns);
3784 3854                                  dns = NULL;
3785 3855                          }
3786 3856                          if (sdlist) {
3787 3857                                  (void) __ns_ldap_freeSearchDescriptors(
3788 3858                                      &sdlist);
3789 3859  
3790 3860                                  sdlist = NULL;
3791 3861                          }
3792 3862                          *errorp = error;
3793 3863                          return (rc);
3794 3864                  }
3795 3865                  dptr->basedn = strdup(dns[0]);
3796 3866                  __s_api_free2dArray(dns);
3797 3867                  dns = NULL;
3798 3868  
3799 3869                  /* default scope */
3800 3870                  scope = 0;
3801 3871                  cookie = init_search_state_machine();
3802 3872                  if (cookie == NULL) {
3803 3873                          if (sdlist) {
3804 3874                                  (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3805 3875                                  sdlist = NULL;
3806 3876                          }
3807 3877                          return (NS_LDAP_MEMORY);
3808 3878                  }
3809 3879                  rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3810 3880                  dptr->scope = scope;
3811 3881          }
3812 3882  
3813 3883          /* Initialize State machine cookie */
3814 3884          if (cookie == NULL)
3815 3885                  cookie = init_search_state_machine();
3816 3886          if (cookie == NULL) {
3817 3887                  if (sdlist) {
3818 3888                          (void) __ns_ldap_freeSearchDescriptors(&sdlist);
3819 3889                          sdlist = NULL;
3820 3890                  }
3821 3891                  return (NS_LDAP_MEMORY);
3822 3892          }
3823 3893  
3824 3894          /* identify self as a getent user */
3825 3895          cookie->conn_user = conn_user;
3826 3896  
3827 3897          cookie->sdlist = sdlist;
3828 3898  
3829 3899          /* see if need to follow referrals */
3830 3900          rc = __s_api_toFollowReferrals(flags,
3831 3901              &cookie->followRef, errorp);
3832 3902          if (rc != NS_LDAP_SUCCESS) {
3833 3903                  delete_search_cookie(cookie);
3834 3904                  return (rc);
3835 3905          }
3836 3906  
3837 3907          /*
3838 3908           * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
3839 3909           */
3840 3910          if (flags & NS_LDAP_NO_PAGE_CTRL)
3841 3911                  cookie->use_paging = FALSE;
3842 3912          else
3843 3913                  cookie->use_paging = TRUE;
3844 3914  
3845 3915          /* Set up other arguments */
3846 3916          cookie->userdata = userdata;
3847 3917          if (init_filter_cb != NULL) {
3848 3918                  cookie->init_filter_cb = init_filter_cb;
3849 3919                  cookie->use_filtercb = 1;
3850 3920          }
3851 3921          cookie->use_usercb = 0;
3852 3922          /* check_shadow() may add extra value to cookie->i_flags */
3853 3923          cookie->i_flags = flags;
3854 3924          if (service) {
3855 3925                  cookie->service = strdup(service);
3856 3926                  if (cookie->service == NULL) {
3857 3927                          delete_search_cookie(cookie);
3858 3928                          return (NS_LDAP_MEMORY);
3859 3929                  }
3860 3930  
3861 3931                  /*
3862 3932                   * If given, use the credential given by the caller, and
3863 3933                   * skip the credential check required for shadow update.
3864 3934                   */
3865 3935                  if (auth == NULL) {
3866 3936                          rc = check_shadow(cookie, service);
3867 3937                          if (rc != NS_LDAP_SUCCESS) {
3868 3938                                  *errorp = cookie->errorp;
3869 3939                                  cookie->errorp = NULL;
3870 3940                                  delete_search_cookie(cookie);
3871 3941                                  cookie = NULL;
3872 3942                                  return (rc);
3873 3943                          }
3874 3944                  }
3875 3945          }
3876 3946  
3877 3947          cookie->i_filter = strdup(filter);
3878 3948          cookie->i_attr = attribute;
3879 3949          cookie->i_sortattr = sortattr;
3880 3950          cookie->i_auth = auth;
3881 3951  
3882 3952          state = INIT;
3883 3953          for (;;) {
3884 3954                  state = search_state_machine(cookie, state, ONE_STEP);
3885 3955                  switch (state) {
3886 3956                  case PROCESS_RESULT:
3887 3957                          *result = cookie->result;
3888 3958                          cookie->result = NULL;
3889 3959                          *vcookie = (void *)cookie;
3890 3960                          return (NS_LDAP_SUCCESS);
3891 3961                  case LDAP_ERROR:
3892 3962                          state = search_state_machine(cookie, state, ONE_STEP);
3893 3963                          state = search_state_machine(cookie, CLEAR_RESULTS,
3894 3964                              ONE_STEP);
3895 3965                          /* FALLTHROUGH */
3896 3966                  case ERROR:
3897 3967                          rc = cookie->err_rc;
3898 3968                          if (conn_user != NULL && conn_user->ns_error != NULL) {
3899 3969                                  *errorp = conn_user->ns_error;
3900 3970                                  conn_user->ns_error = NULL;
3901 3971                          } else {
3902 3972                                  *errorp = cookie->errorp;
3903 3973                                  cookie->errorp = NULL;
3904 3974                          }
3905 3975                          delete_search_cookie(cookie);
3906 3976                          return (rc);
3907 3977                  case EXIT:
3908 3978                          rc = cookie->err_rc;
3909 3979                          if (rc != NS_LDAP_SUCCESS) {
3910 3980                                  *errorp = cookie->errorp;
3911 3981                                  cookie->errorp = NULL;
3912 3982                          } else {
3913 3983                                  rc = NS_LDAP_NOTFOUND;
3914 3984                          }
3915 3985  
3916 3986                          delete_search_cookie(cookie);
3917 3987                          return (rc);
3918 3988  
3919 3989                  default:
3920 3990                          break;
3921 3991                  }
3922 3992          }
3923 3993  }
3924 3994  
3925 3995  int
3926 3996  __ns_ldap_firstEntry(
3927 3997      const char *service,
3928 3998      const char *filter,
3929 3999      const char *vlv_sort,
3930 4000      int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3931 4001      char **realfilter, const void *userdata),
3932 4002      const char * const *attribute,
3933 4003      const ns_cred_t *auth,
3934 4004      const int flags,
3935 4005      void **vcookie,
3936 4006      ns_ldap_result_t **result,
3937 4007      ns_ldap_error_t ** errorp,
3938 4008      const void *userdata)
3939 4009  {
3940 4010          ns_conn_user_t  *cu = NULL;
3941 4011          int             try_cnt = 0;
3942 4012          int             rc = NS_LDAP_SUCCESS;
3943 4013  
3944 4014          for (;;) {
3945 4015                  if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
3946 4016                      &try_cnt, &rc, errorp) == 0)
3947 4017                          break;
3948 4018                  rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
3949 4019                      attribute, auth, flags, vcookie, result, errorp, userdata,
3950 4020                      cu);
3951 4021          }
3952 4022          return (rc);
3953 4023  }
3954 4024  
3955 4025  /*ARGSUSED2*/
3956 4026  int
3957 4027  __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
3958 4028      ns_ldap_error_t ** errorp)
3959 4029  {
3960 4030          ns_ldap_cookie_t        *cookie;
3961 4031          ns_state_t              state;
3962 4032          int                     rc;
3963 4033  
3964 4034          cookie = (ns_ldap_cookie_t *)vcookie;
3965 4035          cookie->result = NULL;
3966 4036          *result = NULL;
3967 4037  
3968 4038          if (cookie->conn_user != NULL) {
3969 4039                  rc = __s_api_setup_getnext(cookie->conn_user,
3970 4040                      &cookie->err_rc, errorp);
3971 4041                  if (rc != NS_LDAP_SUCCESS)
3972 4042                          return (rc);
3973 4043          }
3974 4044  
3975 4045          state = END_PROCESS_RESULT;
3976 4046          for (;;) {
3977 4047                  state = search_state_machine(cookie, state, ONE_STEP);
3978 4048                  switch (state) {
3979 4049                  case PROCESS_RESULT:
3980 4050                          *result = cookie->result;
3981 4051                          cookie->result = NULL;
3982 4052                          return (NS_LDAP_SUCCESS);
3983 4053                  case LDAP_ERROR:
3984 4054                          state = search_state_machine(cookie, state, ONE_STEP);
3985 4055                          state = search_state_machine(cookie, CLEAR_RESULTS,
3986 4056                              ONE_STEP);
3987 4057                          /* FALLTHROUGH */
3988 4058                  case ERROR:
3989 4059                          rc = cookie->err_rc;
3990 4060                          *errorp = cookie->errorp;
3991 4061                          cookie->errorp = NULL;
3992 4062                          return (rc);
3993 4063                  case EXIT:
3994 4064                          return (NS_LDAP_SUCCESS);
3995 4065                  }
3996 4066          }
3997 4067  }
3998 4068  
3999 4069  int
4000 4070  __ns_ldap_endEntry(
4001 4071          void **vcookie,
4002 4072          ns_ldap_error_t ** errorp)
4003 4073  {
4004 4074          ns_ldap_cookie_t        *cookie;
4005 4075          int                     rc;
4006 4076  
4007 4077          if (*vcookie == NULL)
4008 4078                  return (NS_LDAP_INVALID_PARAM);
4009 4079  
4010 4080          cookie = (ns_ldap_cookie_t *)(*vcookie);
4011 4081          cookie->result = NULL;
4012 4082  
4013 4083          /* Complete search */
4014 4084          rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
4015 4085  
4016 4086          /* Copy results back to user */
4017 4087          rc = cookie->err_rc;
4018 4088          if (rc != NS_LDAP_SUCCESS)
4019 4089                  *errorp = cookie->errorp;
4020 4090  
4021 4091          cookie->errorp = NULL;
4022 4092          if (cookie->conn_user != NULL) {
4023 4093                  if (cookie->conn_user->conn_mt != NULL)
4024 4094                          __s_api_conn_mt_return(cookie->conn_user);
4025 4095                  __s_api_conn_user_free(cookie->conn_user);
4026 4096          }
4027 4097          delete_search_cookie(cookie);
4028 4098          cookie = NULL;
4029 4099          *vcookie = NULL;
4030 4100  
4031 4101          return (rc);
4032 4102  }
4033 4103  
4034 4104  
4035 4105  int
4036 4106  __ns_ldap_freeResult(ns_ldap_result_t **result)
4037 4107  {
4038 4108  
4039 4109          ns_ldap_entry_t *curEntry = NULL;
4040 4110          ns_ldap_entry_t *delEntry = NULL;
4041 4111          int             i;
4042 4112          ns_ldap_result_t        *res = *result;
4043 4113  
4044 4114  #ifdef DEBUG
4045 4115          (void) fprintf(stderr, "__ns_ldap_freeResult START\n");
4046 4116  #endif
4047 4117          if (res == NULL)
4048 4118                  return (NS_LDAP_INVALID_PARAM);
4049 4119  
4050 4120          if (res->entry != NULL)
4051 4121                  curEntry = res->entry;
4052 4122  
4053 4123          for (i = 0; i < res->entries_count; i++) {
4054 4124                  if (curEntry != NULL) {
4055 4125                          delEntry = curEntry;
4056 4126                          curEntry = curEntry->next;
4057 4127                          __ns_ldap_freeEntry(delEntry);
4058 4128                  }
4059 4129          }
4060 4130  
4061 4131          free(res);
4062 4132          *result = NULL;
4063 4133          return (NS_LDAP_SUCCESS);
4064 4134  }
4065 4135  
4066 4136  int
4067 4137  __ns_ldap_auth(const ns_cred_t *auth, const int flags, ns_ldap_error_t **errorp,
4068 4138      LDAPControl **serverctrls __unused, LDAPControl **clientctrls __unused)
4069 4139  {
4070 4140  
4071 4141          ConnectionID    connectionId = -1;
4072 4142          Connection      *conp;
4073 4143          int             rc = 0;
4074 4144          int             do_not_fail_if_new_pwd_reqd = 0;
4075 4145          int             nopasswd_acct_mgmt = 0;
4076 4146          ns_conn_user_t  *conn_user;
4077 4147  
4078 4148  
4079 4149  #ifdef DEBUG
4080 4150          (void) fprintf(stderr, "__ns_ldap_auth START\n");
4081 4151  #endif
4082 4152  
4083 4153          *errorp = NULL;
4084 4154          if (auth == NULL)
4085 4155                  return (NS_LDAP_INVALID_PARAM);
4086 4156  
4087 4157          conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
4088 4158              NULL, B_FALSE);
4089 4159  
4090 4160          rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
4091 4161              auth, &connectionId, &conp, errorp,
4092 4162              do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
4093 4163              conn_user);
4094 4164  
4095 4165          if (conn_user != NULL)
4096 4166                  __s_api_conn_user_free(conn_user);
4097 4167  
4098 4168          if (rc == NS_LDAP_OP_FAILED && *errorp)
4099 4169                  (void) __ns_ldap_freeError(errorp);
4100 4170  
4101 4171          if (connectionId > -1)
4102 4172                  DropConnection(connectionId, flags);
4103 4173          return (rc);
4104 4174  }
4105 4175  
4106 4176  char **
4107 4177  __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
4108 4178  {
4109 4179          int     i;
4110 4180  
4111 4181          if (entry == NULL)
4112 4182                  return (NULL);
4113 4183          for (i = 0; i < entry->attr_count; i++) {
4114 4184                  if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4115 4185                          return (entry->attr_pair[i]->attrvalue);
4116 4186          }
4117 4187          return (NULL);
4118 4188  }
4119 4189  
4120 4190  ns_ldap_attr_t *
4121 4191  __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
4122 4192  {
4123 4193          int     i;
4124 4194  
4125 4195          if (entry == NULL)
4126 4196                  return (NULL);
4127 4197          for (i = 0; i < entry->attr_count; i++) {
4128 4198                  if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4129 4199                          return (entry->attr_pair[i]);
4130 4200          }
4131 4201          return (NULL);
4132 4202  }
4133 4203  
4134 4204  
4135 4205  int
4136 4206  __ns_ldap_uid2dn(const char *uid, char **userDN, const ns_cred_t *cred,
4137 4207      ns_ldap_error_t **errorp)
4138 4208  {
4139 4209          ns_ldap_result_t        *result = NULL;
4140 4210          char            *filter, *userdata;
4141 4211          char            errstr[MAXERROR];
4142 4212          char            **value;
4143 4213          int             rc = 0;
4144 4214          int             i;
4145 4215          size_t          len;
4146 4216  
4147 4217          *errorp = NULL;
4148 4218          *userDN = NULL;
4149 4219          if ((uid == NULL) || (uid[0] == '\0'))
4150 4220                  return (NS_LDAP_INVALID_PARAM);
4151 4221  
4152 4222          for (i = 0; uid[i] != '\0'; i++) {
4153 4223                  if (uid[i] == '=') {
4154 4224                          *userDN = strdup(uid);
4155 4225                          return (NS_LDAP_SUCCESS);
4156 4226                  }
4157 4227          }
4158 4228          for (i = 0; (uid[i] != '\0') && isdigit(uid[i]); i++)
4159 4229                  ;
4160 4230          if (uid[i] == '\0') {
4161 4231                  len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
4162 4232                  filter = malloc(len);
4163 4233                  if (filter == NULL) {
4164 4234                          *userDN = NULL;
4165 4235                          return (NS_LDAP_MEMORY);
4166 4236                  }
4167 4237                  (void) snprintf(filter, len, UIDNUMFILTER, uid);
4168 4238  
4169 4239                  len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
4170 4240                  userdata = malloc(len);
4171 4241                  if (userdata == NULL) {
4172 4242                          *userDN = NULL;
4173 4243                          free(filter);
4174 4244                          return (NS_LDAP_MEMORY);
4175 4245                  }
4176 4246                  (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
4177 4247          } else {
4178 4248                  len = strlen(UIDFILTER) + strlen(uid) + 1;
4179 4249                  filter = malloc(len);
4180 4250                  if (filter == NULL) {
4181 4251                          *userDN = NULL;
4182 4252                          return (NS_LDAP_MEMORY);
4183 4253                  }
4184 4254                  (void) snprintf(filter, len, UIDFILTER, uid);
4185 4255  
4186 4256                  len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
4187 4257                  userdata = malloc(len);
4188 4258                  if (userdata == NULL) {
4189 4259                          *userDN = NULL;
4190 4260                          free(filter);
4191 4261                          return (NS_LDAP_MEMORY);
4192 4262                  }
4193 4263                  (void) snprintf(userdata, len, UIDFILTER_SSD, uid);
4194 4264          }
4195 4265  
4196 4266          /*
4197 4267           * we want to retrieve the DN as it appears in LDAP
4198 4268           * hence the use of NS_LDAP_NOT_CVT_DN in flags
4199 4269           */
4200 4270          rc = __ns_ldap_list("passwd", filter,
4201 4271              __s_api_merge_SSD_filter,
4202 4272              NULL, cred, NS_LDAP_NOT_CVT_DN,
4203 4273              &result, errorp, NULL,
4204 4274              userdata);
4205 4275          free(filter);
4206 4276          filter = NULL;
4207 4277          free(userdata);
4208 4278          userdata = NULL;
4209 4279          if (rc != NS_LDAP_SUCCESS) {
4210 4280                  if (result) {
4211 4281                          (void) __ns_ldap_freeResult(&result);
4212 4282                          result = NULL;
4213 4283                  }
4214 4284                  return (rc);
4215 4285          }
4216 4286          if (result->entries_count > 1) {
4217 4287                  (void) __ns_ldap_freeResult(&result);
4218 4288                  result = NULL;
4219 4289                  *userDN = NULL;
4220 4290                  (void) sprintf(errstr,
4221 4291                      gettext("Too many entries are returned for %s"), uid);
4222 4292                  MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4223 4293                      NS_LDAP_MEMORY);
4224 4294                  return (NS_LDAP_INTERNAL);
4225 4295          }
4226 4296  
4227 4297          value = __ns_ldap_getAttr(result->entry, "dn");
4228 4298          *userDN = strdup(value[0]);
4229 4299          (void) __ns_ldap_freeResult(&result);
4230 4300          result = NULL;
4231 4301          return (NS_LDAP_SUCCESS);
  
    | 
      ↓ open down ↓ | 
    523 lines elided | 
    
      ↑ open up ↑ | 
  
4232 4302  }
4233 4303  
4234 4304  #define _P_UID  "uid"
4235 4305  static const char *dn2uid_attrs[] = {
4236 4306          _P_CN,
4237 4307          _P_UID,
4238 4308          (char *)NULL
4239 4309  };
4240 4310  
4241 4311  int
4242      -__ns_ldap_dn2uid(const char *dn, char **userID, const ns_cred_t *cred,
     4312 +__ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred,
4243 4313      ns_ldap_error_t **errorp)
4244 4314  {
4245      -        ns_ldap_result_t        *result = NULL;
4246      -        char            *filter, *userdata;
4247      -        char            errstr[MAXERROR];
4248      -        char            **value;
4249      -        int             rc = 0;
4250      -        size_t          len;
     4315 +        lookup_data_t           ldata;
     4316 +        ns_ldap_result_t        *result;
     4317 +        char                    **value;
     4318 +        int                     rc;
4251 4319  
4252 4320          *errorp = NULL;
4253      -        *userID = NULL;
     4321 +        *userIDp = NULL;
4254 4322          if ((dn == NULL) || (dn[0] == '\0'))
4255 4323                  return (NS_LDAP_INVALID_PARAM);
4256 4324  
4257      -        len = strlen(UIDDNFILTER) + strlen(dn) + 1;
4258      -        filter = malloc(len);
4259      -        if (filter == NULL) {
4260      -                return (NS_LDAP_MEMORY);
4261      -        }
4262      -        (void) snprintf(filter, len, UIDDNFILTER, dn);
     4325 +        /*
     4326 +         * Many LDAP servers do not support using the dn in a search
     4327 +         * filter. As a result, we unfortunately cannot  use __ns_ldap_list()
     4328 +         * to lookup the DN. Instead we perform a search with the baseDN
     4329 +         * being the DN we are looking for with a scope of 'base' to
     4330 +         * return the entry, as this should be supported by all LDAP servers.
     4331 +         */
     4332 +        ldata.lkd_dn = dn;
4263 4333  
4264      -        len = strlen(UIDDNFILTER_SSD) + strlen(dn) + 1;
4265      -        userdata = malloc(len);
4266      -        if (userdata == NULL) {
4267      -                free(filter);
4268      -                return (NS_LDAP_MEMORY);
4269      -        }
4270      -        (void) snprintf(userdata, len, UIDDNFILTER_SSD, dn);
4271      -
4272 4334          /*
4273      -         * Unlike uid2dn, we DO want attribute mapping, so that
4274      -         * "uid" is mapped to/from samAccountName, for example.
     4335 +         * Since we are looking up a user account by its DN, use the attribute
     4336 +         * and objectclass mappings (if present) for the passwd service.
4275 4337           */
4276      -        rc = __ns_ldap_list("passwd", filter,
4277      -            __s_api_merge_SSD_filter,
4278      -            dn2uid_attrs, cred, 0,
4279      -            &result, errorp, NULL,
4280      -            userdata);
4281      -        free(filter);
4282      -        filter = NULL;
4283      -        free(userdata);
4284      -        userdata = NULL;
     4338 +        ldata.lkd_service = "passwd";
     4339 +        ldata.lkd_filter = UIDDNFILTER;
     4340 +        ldata.lkd_cred = cred;
     4341 +        ldata.lkd_user = NULL;
     4342 +
     4343 +        rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp);
4285 4344          if (rc != NS_LDAP_SUCCESS)
4286      -                goto out;
     4345 +                return (rc);
4287 4346  
4288      -        if (result->entries_count > 1) {
4289      -                (void) sprintf(errstr,
4290      -                    gettext("Too many entries are returned for %s"), dn);
4291      -                MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4292      -                    NS_LDAP_MEMORY);
4293      -                rc = NS_LDAP_INTERNAL;
4294      -                goto out;
4295      -        }
4296      -
4297 4347          value = __ns_ldap_getAttr(result->entry, _P_UID);
4298      -        if (value == NULL || value[0] == NULL) {
     4348 +        if (value != NULL && value[0] != NULL) {
     4349 +                *userIDp = strdup(value[0]);
     4350 +                if (*userIDp == NULL)
     4351 +                        rc = NS_LDAP_MEMORY;
     4352 +        } else {
4299 4353                  rc = NS_LDAP_NOTFOUND;
4300      -                goto out;
4301 4354          }
4302 4355  
4303      -        *userID = strdup(value[0]);
4304      -        rc = NS_LDAP_SUCCESS;
4305      -
4306      -out:
4307 4356          (void) __ns_ldap_freeResult(&result);
4308      -        result = NULL;
4309 4357          return (rc);
4310 4358  }
4311 4359  
4312 4360  int
4313 4361  __ns_ldap_host2dn(const char *host, const char *domain, char **hostDN,
4314 4362      const ns_cred_t *cred, ns_ldap_error_t **errorp)
4315 4363  {
4316 4364          ns_ldap_result_t        *result = NULL;
4317 4365          char            *filter, *userdata;
4318 4366          char            errstr[MAXERROR];
4319 4367          char            **value;
4320 4368          int             rc;
4321 4369          size_t          len;
4322 4370  
4323 4371          /*
4324 4372           * XXX
4325 4373           * the domain parameter needs to be used in case domain is not local,
4326 4374           * if this routine is to support multi domain setups, it needs lots
4327 4375           * of work...
4328 4376           */
4329 4377          *errorp = NULL;
4330 4378          *hostDN = NULL;
4331 4379          if ((host == NULL) || (host[0] == '\0'))
4332 4380                  return (NS_LDAP_INVALID_PARAM);
4333 4381  
4334 4382          len = strlen(HOSTFILTER) + strlen(host) + 1;
4335 4383          filter = malloc(len);
4336 4384          if (filter == NULL) {
4337 4385                  return (NS_LDAP_MEMORY);
4338 4386          }
4339 4387          (void) snprintf(filter, len, HOSTFILTER, host);
4340 4388  
4341 4389          len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
4342 4390          userdata = malloc(len);
4343 4391          if (userdata == NULL) {
4344 4392                  free(filter);
4345 4393                  return (NS_LDAP_MEMORY);
4346 4394          }
4347 4395          (void) snprintf(userdata, len, HOSTFILTER_SSD, host);
4348 4396  
4349 4397          /*
4350 4398           * we want to retrieve the DN as it appears in LDAP
4351 4399           * hence the use of NS_LDAP_NOT_CVT_DN in flags
4352 4400           */
4353 4401          rc = __ns_ldap_list("hosts", filter,
4354 4402              __s_api_merge_SSD_filter,
4355 4403              NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
4356 4404              errorp, NULL,
4357 4405              userdata);
4358 4406          free(filter);
4359 4407          filter = NULL;
4360 4408          free(userdata);
4361 4409          userdata = NULL;
4362 4410          if (rc != NS_LDAP_SUCCESS) {
4363 4411                  if (result) {
4364 4412                          (void) __ns_ldap_freeResult(&result);
4365 4413                          result = NULL;
4366 4414                  }
4367 4415                  return (rc);
4368 4416          }
4369 4417  
4370 4418          if (result->entries_count > 1) {
4371 4419                  (void) __ns_ldap_freeResult(&result);
4372 4420                  result = NULL;
4373 4421                  *hostDN = NULL;
4374 4422                  (void) sprintf(errstr,
4375 4423                      gettext("Too many entries are returned for %s"), host);
4376 4424                  MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
4377 4425                      NS_LDAP_MEMORY);
4378 4426                  return (NS_LDAP_INTERNAL);
4379 4427          }
4380 4428  
4381 4429          value = __ns_ldap_getAttr(result->entry, "dn");
4382 4430          *hostDN = strdup(value[0]);
4383 4431          (void) __ns_ldap_freeResult(&result);
4384 4432          result = NULL;
4385 4433          return (NS_LDAP_SUCCESS);
4386 4434  }
4387 4435  
4388 4436  int
4389 4437  __ns_ldap_dn2domain(const char *dn, char **domain, const ns_cred_t *cred,
4390 4438      ns_ldap_error_t **errorp)
4391 4439  {
4392 4440          int             rc, pnum, i, j, len = 0;
4393 4441          char            *newdn, **rdns = NULL;
4394 4442          char            **dns, *dn1;
4395 4443  
4396 4444          *errorp = NULL;
4397 4445  
4398 4446          if (domain == NULL)
4399 4447                  return (NS_LDAP_INVALID_PARAM);
4400 4448          else
4401 4449                  *domain = NULL;
4402 4450  
4403 4451          if ((dn == NULL) || (dn[0] == '\0'))
4404 4452                  return (NS_LDAP_INVALID_PARAM);
4405 4453  
4406 4454          /*
4407 4455           * break dn into rdns
4408 4456           */
4409 4457          dn1 = strdup(dn);
4410 4458          if (dn1 == NULL)
4411 4459                  return (NS_LDAP_MEMORY);
4412 4460          rdns = ldap_explode_dn(dn1, 0);
4413 4461          free(dn1);
4414 4462          if (rdns == NULL || *rdns == NULL)
4415 4463                  return (NS_LDAP_INVALID_PARAM);
4416 4464  
4417 4465          for (i = 0; rdns[i]; i++)
4418 4466                  len += strlen(rdns[i]) + 1;
4419 4467          pnum = i;
4420 4468  
4421 4469          newdn = (char *)malloc(len + 1);
4422 4470          dns = (char **)calloc(pnum, sizeof (char *));
4423 4471          if (newdn == NULL || dns == NULL) {
4424 4472                  if (newdn)
4425 4473                          free(newdn);
4426 4474                  ldap_value_free(rdns);
4427 4475                  return (NS_LDAP_MEMORY);
4428 4476          }
4429 4477  
4430 4478          /* construct a semi-normalized dn, newdn */
4431 4479          *newdn = '\0';
4432 4480          for (i = 0; rdns[i]; i++) {
4433 4481                  dns[i] = newdn + strlen(newdn);
4434 4482                  (void) strcat(newdn,
4435 4483                      __s_api_remove_rdn_space(rdns[i]));
4436 4484                  (void) strcat(newdn, ",");
4437 4485          }
4438 4486          /* remove the last ',' */
4439 4487          newdn[strlen(newdn) - 1] = '\0';
4440 4488          ldap_value_free(rdns);
4441 4489  
4442 4490          /*
4443 4491           * loop and find the domain name associated with newdn,
4444 4492           * removing rdn one by one from left to right
4445 4493           */
4446 4494          for (i = 0; i < pnum; i++) {
4447 4495  
4448 4496                  if (*errorp)
4449 4497                          (void) __ns_ldap_freeError(errorp);
4450 4498  
4451 4499                  /*
4452 4500                   *  try cache manager first
4453 4501                   */
4454 4502                  rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
4455 4503                      dns[i], domain);
4456 4504                  if (rc != NS_LDAP_SUCCESS) {
4457 4505                          /*
4458 4506                           *  try ldap server second
4459 4507                           */
4460 4508                          rc = __s_api_find_domainname(dns[i], domain,
4461 4509                              cred, errorp);
4462 4510                  } else {
4463 4511                          /*
4464 4512                           * skip the last one,
4465 4513                           * since it is already cached by ldap_cachemgr
4466 4514                           */
4467 4515                          i--;
4468 4516                  }
4469 4517                  if (rc == NS_LDAP_SUCCESS) {
4470 4518                          if (__s_api_nscd_proc()) {
4471 4519                                  /*
4472 4520                                   * If it's nscd, ask cache manager to save the
4473 4521                                   * dn to domain mapping(s)
4474 4522                                   */
4475 4523                                  for (j = 0; j <= i; j++) {
4476 4524                                          (void) __s_api_set_cachemgr_data(
4477 4525                                              NS_CACHE_DN2DOMAIN,
4478 4526                                              dns[j],
4479 4527                                              *domain);
4480 4528                                  }
4481 4529                          }
4482 4530                          break;
4483 4531                  }
4484 4532          }
4485 4533  
4486 4534          free(dns);
4487 4535          free(newdn);
4488 4536          if (rc != NS_LDAP_SUCCESS)
4489 4537                  rc = NS_LDAP_NOTFOUND;
4490 4538          return (rc);
4491 4539  }
4492 4540  
4493 4541  int
4494 4542  __ns_ldap_getServiceAuthMethods(const char *service, ns_auth_t ***auth,
4495 4543      ns_ldap_error_t **errorp)
4496 4544  {
4497 4545          char            errstr[MAXERROR];
4498 4546          int             rc, i;
4499 4547          boolean_t       done = B_FALSE;
4500 4548          int             slen;
4501 4549          void            **param;
4502 4550          char            **sam, *srv, *send;
4503 4551          ns_auth_t       **authpp = NULL, *ap;
4504 4552          int             cnt, max;
4505 4553          ns_config_t     *cfg;
4506 4554          ns_ldap_error_t *error = NULL;
4507 4555  
4508 4556          if (errorp == NULL)
4509 4557                  return (NS_LDAP_INVALID_PARAM);
4510 4558          *errorp = NULL;
4511 4559  
4512 4560          if ((service == NULL) || (service[0] == '\0') ||
4513 4561              (auth == NULL))
4514 4562                  return (NS_LDAP_INVALID_PARAM);
4515 4563  
4516 4564          *auth = NULL;
4517 4565          rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, ¶m, &error);
4518 4566          if (rc != NS_LDAP_SUCCESS || param == NULL) {
4519 4567                  *errorp = error;
4520 4568                  return (rc);
4521 4569          }
4522 4570          sam = (char **)param;
4523 4571  
4524 4572          cfg = __s_api_get_default_config();
4525 4573          cnt = 0;
4526 4574  
4527 4575          slen = strlen(service);
4528 4576  
4529 4577          for (; *sam; sam++) {
4530 4578                  srv = *sam;
4531 4579                  if (strncasecmp(service, srv, slen) != 0)
4532 4580                          continue;
4533 4581                  srv += slen;
4534 4582                  if (*srv != COLONTOK)
4535 4583                          continue;
4536 4584                  send = srv;
4537 4585                  srv++;
4538 4586                  for (max = 1; (send = strchr(++send, SEMITOK)) != NULL; max++)
4539 4587                          ;
4540 4588                  authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
4541 4589                  if (authpp == NULL) {
4542 4590                          (void) __ns_ldap_freeParam(¶m);
4543 4591                          __s_api_release_config(cfg);
4544 4592                          return (NS_LDAP_MEMORY);
4545 4593                  }
4546 4594                  while (!done) {
4547 4595                          send = strchr(srv, SEMITOK);
4548 4596                          if (send != NULL) {
4549 4597                                  *send = '\0';
4550 4598                                  send++;
4551 4599                          }
4552 4600                          i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
4553 4601                          if (i == -1) {
4554 4602                                  (void) __ns_ldap_freeParam(¶m);
4555 4603                                  (void) sprintf(errstr,
4556 4604                                  gettext("Unsupported "
4557 4605                                      "serviceAuthenticationMethod: %s.\n"), srv);
4558 4606                                  MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
4559 4607                                      strdup(errstr), NS_LDAP_MEMORY);
4560 4608                                  __s_api_release_config(cfg);
4561 4609                                  return (NS_LDAP_CONFIG);
4562 4610                          }
4563 4611                          ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
4564 4612                          if (ap == NULL) {
4565 4613                                  (void) __ns_ldap_freeParam(¶m);
4566 4614                                  __s_api_release_config(cfg);
4567 4615                                  return (NS_LDAP_MEMORY);
4568 4616                          }
4569 4617                          authpp[cnt++] = ap;
4570 4618                          if (send == NULL)
4571 4619                                  done = B_TRUE;
4572 4620                          else
4573 4621                                  srv = send;
4574 4622                  }
4575 4623          }
4576 4624  
4577 4625          *auth = authpp;
4578 4626          (void) __ns_ldap_freeParam(¶m);
4579 4627          __s_api_release_config(cfg);
4580 4628          return (NS_LDAP_SUCCESS);
4581 4629  }
4582 4630  
4583 4631  /*
4584 4632   * This routine is called when certain scenario occurs
4585 4633   * e.g.
4586 4634   * service == auto_home
4587 4635   * SSD = automount: ou = mytest,
4588 4636   * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
4589 4637   * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
4590 4638   * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
4591 4639   *
4592 4640   * The automountMapName is prepended implicitely but is mapped
4593 4641   * to AAA. So dn could appers as
4594 4642   * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
4595 4643   * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
4596 4644   * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
4597 4645   * in the directory.
4598 4646   * This function is called to covert the mapped attr back to
4599 4647   * orig attr when the entries are searched and returned
4600 4648   */
4601 4649  
4602 4650  int
4603 4651  __s_api_convert_automountmapname(const char *service, char **dn,
4604 4652      ns_ldap_error_t **errp)
4605 4653  {
4606 4654  
4607 4655          char    **mapping = NULL;
4608 4656          char    *mapped_attr = NULL;
4609 4657          char    *automountmapname = "automountMapName";
4610 4658          char    *buffer = NULL;
4611 4659          int     rc = NS_LDAP_SUCCESS;
4612 4660          char    errstr[MAXERROR];
4613 4661  
4614 4662          /*
4615 4663           * dn is an input/out parameter, check it first
4616 4664           */
4617 4665  
4618 4666          if (service == NULL || dn == NULL || *dn == NULL)
4619 4667                  return (NS_LDAP_INVALID_PARAM);
4620 4668  
4621 4669          /*
4622 4670           * Check to see if there is a mapped attribute for auto_xxx
4623 4671           */
4624 4672  
4625 4673          mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
4626 4674  
4627 4675          /*
4628 4676           * if no mapped attribute for auto_xxx, try automount
4629 4677           */
4630 4678  
4631 4679          if (mapping == NULL) {
4632 4680                  mapping = __ns_ldap_getMappedAttributes(
4633 4681                      "automount", automountmapname);
4634 4682          }
4635 4683  
4636 4684          /*
4637 4685           * if no mapped attribute is found, return SUCCESS (no op)
4638 4686           */
4639 4687  
4640 4688          if (mapping == NULL)
4641 4689                  return (NS_LDAP_SUCCESS);
4642 4690  
4643 4691          /*
4644 4692           * if the mapped attribute is found and attr is not empty,
4645 4693           * copy it
4646 4694           */
4647 4695  
4648 4696          if (mapping[0] != NULL) {
4649 4697                  mapped_attr = strdup(mapping[0]);
4650 4698                  __s_api_free2dArray(mapping);
4651 4699                  if (mapped_attr == NULL) {
4652 4700                          return (NS_LDAP_MEMORY);
4653 4701                  }
4654 4702          } else {
4655 4703                  __s_api_free2dArray(mapping);
4656 4704  
4657 4705                  (void) snprintf(errstr, (2 * MAXERROR),
4658 4706                      gettext("Attribute nisMapName is mapped to an "
4659 4707                      "empty string.\n"));
4660 4708  
4661 4709                  MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
4662 4710                      strdup(errstr), NS_LDAP_MEMORY);
4663 4711  
4664 4712                  return (NS_LDAP_CONFIG);
4665 4713          }
4666 4714  
4667 4715          /*
4668 4716           * Locate the mapped attribute in the dn
4669 4717           * and replace it if it exists
4670 4718           */
4671 4719  
4672 4720          rc = __s_api_replace_mapped_attr_in_dn(
4673 4721              (const char *) automountmapname, (const char *) mapped_attr,
4674 4722              (const char *) *dn, &buffer);
4675 4723  
4676 4724          /* clean up */
4677 4725  
4678 4726          free(mapped_attr);
4679 4727  
4680 4728          /*
4681 4729           * If mapped attr is found(buffer != NULL)
4682 4730           *      a new dn is returned
4683 4731           * If no mapped attribute is in dn,
4684 4732           *      return NS_LDAP_SUCCESS (no op)
4685 4733           * If no memory,
4686 4734           *      return NS_LDAP_MEMORY (no op)
4687 4735           */
4688 4736  
4689 4737          if (buffer != NULL) {
4690 4738                  free(*dn);
4691 4739                  *dn = buffer;
4692 4740          }
4693 4741  
4694 4742          return (rc);
4695 4743  }
4696 4744  
4697 4745  /*
4698 4746   * If the mapped attr is found in the dn,
4699 4747   *      return NS_LDAP_SUCCESS and a new_dn.
4700 4748   * If no mapped attr is found,
4701 4749   *      return NS_LDAP_SUCCESS and *new_dn == NULL
4702 4750   * If there is not enough memory,
4703 4751   *      return NS_LDAP_MEMORY and *new_dn == NULL
4704 4752   */
4705 4753  
4706 4754  int
4707 4755  __s_api_replace_mapped_attr_in_dn(const char *orig_attr,
4708 4756      const char *mapped_attr, const char *dn, char **new_dn)
4709 4757  {
4710 4758  
4711 4759          char    **dnArray = NULL;
4712 4760          char    *cur = NULL, *start = NULL;
4713 4761          int     i = 0;
4714 4762          boolean_t found = B_FALSE;
4715 4763          int     len = 0, orig_len = 0, mapped_len = 0;
4716 4764          int     dn_len = 0, tmp_len = 0;
4717 4765  
4718 4766          *new_dn = NULL;
4719 4767  
4720 4768          /*
4721 4769           * seperate dn into individual componets
4722 4770           * e.g.
4723 4771           * "automountKey=user_01" , "automountMapName_test=auto_home", ...
4724 4772           */
4725 4773          dnArray = ldap_explode_dn(dn, 0);
4726 4774  
4727 4775          /*
4728 4776           * This will find "mapped attr=value" in dn.
4729 4777           * It won't find match if mapped attr appears
4730 4778           * in the value.
4731 4779           */
4732 4780          for (i = 0; dnArray[i] != NULL; i++) {
4733 4781                  /*
4734 4782                   * This function is called when reading from
4735 4783                   * the directory so assume each component has "=".
4736 4784                   * Any ill formatted dn should be rejected
4737 4785                   * before adding to the directory
4738 4786                   */
4739 4787                  cur = strchr(dnArray[i], '=');
4740 4788                  *cur = '\0';
4741 4789                  if (strcasecmp(mapped_attr, dnArray[i]) == 0)
4742 4790                          found = B_TRUE;
4743 4791                  *cur = '=';
4744 4792                  if (found)
4745 4793                          break;
4746 4794          }
4747 4795  
4748 4796          if (!found) {
4749 4797                  __s_api_free2dArray(dnArray);
4750 4798                  *new_dn = NULL;
4751 4799                  return (NS_LDAP_SUCCESS);
4752 4800          }
4753 4801          /*
4754 4802           * The new length is *dn length + (difference between
4755 4803           * orig attr and mapped attr) + 1 ;
4756 4804           * e.g.
4757 4805           * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
4758 4806           * ==>
4759 4807           * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
4760 4808           */
4761 4809          mapped_len = strlen(mapped_attr);
4762 4810          orig_len = strlen(orig_attr);
4763 4811          dn_len = strlen(dn);
4764 4812          len = dn_len + orig_len - mapped_len + 1;
4765 4813          *new_dn = (char *)calloc(1, len);
4766 4814          if (*new_dn == NULL) {
4767 4815                  __s_api_free2dArray(dnArray);
4768 4816                  return (NS_LDAP_MEMORY);
4769 4817          }
4770 4818  
4771 4819          /*
4772 4820           * Locate the mapped attr in the dn.
4773 4821           * Use dnArray[i] instead of mapped_attr
4774 4822           * because mapped_attr could appear in
4775 4823           * the value
4776 4824           */
4777 4825  
4778 4826          cur = strstr(dn, dnArray[i]);
4779 4827          __s_api_free2dArray(dnArray);
4780 4828          /* copy the portion before mapped attr in dn  */
4781 4829          start = *new_dn;
4782 4830          tmp_len = cur - dn;
4783 4831          (void) memcpy(start, dn, tmp_len);
4784 4832  
4785 4833          /*
4786 4834           * Copy the orig_attr. e.g. automountMapName
4787 4835           * This replaces mapped attr with orig attr
4788 4836           */
4789 4837          start = start + (cur - dn); /* move cursor in buffer */
4790 4838          (void) memcpy(start, orig_attr, orig_len);
4791 4839  
4792 4840          /*
4793 4841           * Copy the portion after mapped attr in dn
4794 4842           */
4795 4843          cur = cur + mapped_len; /* move cursor in  dn  */
4796 4844          start = start + orig_len; /* move cursor in buffer */
4797 4845          (void) strcpy(start, cur);
4798 4846  
4799 4847          return (NS_LDAP_SUCCESS);
4800 4848  }
4801 4849  
4802 4850  /*
4803 4851   * Validate Filter functions
4804 4852   */
4805 4853  
4806 4854  /* ***** Start of modified libldap.so.5 filter parser ***** */
4807 4855  
4808 4856  /* filter parsing routine forward references */
4809 4857  static int adj_filter_list(char *str);
4810 4858  static int adj_simple_filter(char *str);
4811 4859  static int unescape_filterval(char *val);
4812 4860  static int hexchar2int(char c);
4813 4861  static int adj_substring_filter(char *val);
4814 4862  
4815 4863  
4816 4864  /*
4817 4865   * assumes string manipulation is in-line
4818 4866   * and all strings are sufficient in size
4819 4867   * return value is the position after 'c'
4820 4868   */
4821 4869  
4822 4870  static char *
4823 4871  resync_str(char *str, char *next, char c)
4824 4872  {
4825 4873          char    *ret;
4826 4874  
4827 4875          ret = str + strlen(str);
4828 4876          *next = c;
4829 4877          if (ret == next)
4830 4878                  return (ret);
4831 4879          (void) strcat(str, next);
4832 4880          return (ret);
4833 4881  }
4834 4882  
4835 4883  static char *
4836 4884  find_right_paren(char *s)
4837 4885  {
4838 4886          int balance;
4839 4887          boolean_t escape;
4840 4888  
4841 4889          balance = 1;
4842 4890          escape = B_FALSE;
4843 4891          while (*s && balance) {
4844 4892                  if (escape == B_FALSE) {
4845 4893                          if (*s == '(')
4846 4894                                  balance++;
4847 4895                          else if (*s == ')')
4848 4896                                  balance--;
4849 4897                  }
4850 4898                  if (*s == '\\' && !escape)
4851 4899                          escape = B_TRUE;
4852 4900                  else
4853 4901                          escape = B_FALSE;
4854 4902                  if (balance)
4855 4903                          s++;
4856 4904          }
4857 4905  
4858 4906          return (*s ? s : NULL);
4859 4907  }
4860 4908  
4861 4909  static char *
4862 4910  adj_complex_filter(char *str)
4863 4911  {
4864 4912          char    *next;
4865 4913  
4866 4914          /*
4867 4915           * We have (x(filter)...) with str sitting on
4868 4916           * the x.  We have to find the paren matching
4869 4917           * the one before the x and put the intervening
4870 4918           * filters by calling adj_filter_list().
4871 4919           */
4872 4920  
4873 4921          str++;
4874 4922          if ((next = find_right_paren(str)) == NULL)
4875 4923                  return (NULL);
4876 4924  
4877 4925          *next = '\0';
4878 4926          if (adj_filter_list(str) == -1)
4879 4927                  return (NULL);
4880 4928          next = resync_str(str, next, ')');
4881 4929          next++;
4882 4930  
4883 4931          return (next);
4884 4932  }
4885 4933  
4886 4934  static int
4887 4935  adj_filter(char *str)
4888 4936  {
4889 4937          char *next;
4890 4938          int parens, balance;
4891 4939          boolean_t escape;
4892 4940          char *np, *cp,  *dp;
4893 4941  
4894 4942          parens = 0;
4895 4943          while (*str) {
4896 4944                  switch (*str) {
4897 4945                  case '(':
4898 4946                          str++;
4899 4947                          parens++;
4900 4948                          switch (*str) {
4901 4949                          case '&':
4902 4950                                  if ((str = adj_complex_filter(str)) == NULL)
4903 4951                                          return (-1);
4904 4952  
4905 4953                                  parens--;
4906 4954                                  break;
4907 4955  
4908 4956                          case '|':
4909 4957                                  if ((str = adj_complex_filter(str)) == NULL)
4910 4958                                          return (-1);
4911 4959  
4912 4960                                  parens--;
4913 4961                                  break;
4914 4962  
4915 4963                          case '!':
4916 4964                                  if ((str = adj_complex_filter(str)) == NULL)
4917 4965                                          return (-1);
4918 4966  
4919 4967                                  parens--;
4920 4968                                  break;
4921 4969  
4922 4970                          case '(':
4923 4971                                  /* illegal ((case - generated by conversion */
4924 4972  
4925 4973                                  /* find missing close) */
4926 4974                                  np = find_right_paren(str+1);
4927 4975  
4928 4976                                  /* error if not found */
4929 4977                                  if (np == NULL)
4930 4978                                          return (-1);
4931 4979  
4932 4980                                  /* remove redundant (and) */
4933 4981                                  for (dp = str, cp = str+1; cp < np; ) {
4934 4982                                          *dp++ = *cp++;
4935 4983                                  }
4936 4984                                  cp++;
4937 4985                                  while (*cp)
4938 4986                                          *dp++ = *cp++;
4939 4987                                  *dp = '\0';
4940 4988  
4941 4989                                  /* re-start test at original ( */
4942 4990                                  parens--;
4943 4991                                  str--;
4944 4992                                  break;
4945 4993  
4946 4994                          default:
4947 4995                                  balance = 1;
4948 4996                                  escape = B_FALSE;
4949 4997                                  next = str;
4950 4998                                  while (*next && balance) {
4951 4999                                          if (escape == B_FALSE) {
4952 5000                                                  if (*next == '(')
4953 5001                                                          balance++;
4954 5002                                                  else if (*next == ')')
4955 5003                                                          balance--;
4956 5004                                          }
4957 5005                                          if (*next == '\\' && !escape)
4958 5006                                                  escape = B_TRUE;
4959 5007                                          else
4960 5008                                                  escape = B_FALSE;
4961 5009                                          if (balance)
4962 5010                                                  next++;
4963 5011                                  }
4964 5012                                  if (balance != 0)
4965 5013                                          return (-1);
4966 5014  
4967 5015                                  *next = '\0';
4968 5016                                  if (adj_simple_filter(str) == -1) {
4969 5017                                          return (-1);
4970 5018                                  }
4971 5019                                  next = resync_str(str, next, ')');
4972 5020                                  next++;
4973 5021                                  str = next;
4974 5022                                  parens--;
4975 5023                                  break;
4976 5024                          }
4977 5025                          break;
4978 5026  
4979 5027                  case ')':
4980 5028                          str++;
4981 5029                          parens--;
4982 5030                          break;
4983 5031  
4984 5032                  case ' ':
4985 5033                          str++;
4986 5034                          break;
4987 5035  
4988 5036                  default:        /* assume it's a simple type=value filter */
4989 5037                          next = strchr(str, '\0');
4990 5038                          if (adj_simple_filter(str) == -1) {
4991 5039                                  return (-1);
4992 5040                          }
4993 5041                          str = next;
4994 5042                          break;
4995 5043                  }
4996 5044          }
4997 5045  
4998 5046          return (parens ? -1 : 0);
4999 5047  }
5000 5048  
5001 5049  
5002 5050  /*
5003 5051   * Put a list of filters like this "(filter1)(filter2)..."
5004 5052   */
5005 5053  
5006 5054  static int
5007 5055  adj_filter_list(char *str)
5008 5056  {
5009 5057          char    *next;
5010 5058          char    save;
5011 5059  
5012 5060          while (*str) {
5013 5061                  while (*str && isspace(*str))
5014 5062                          str++;
5015 5063                  if (*str == '\0')
5016 5064                          break;
5017 5065  
5018 5066                  if ((next = find_right_paren(str + 1)) == NULL)
5019 5067                          return (-1);
5020 5068                  save = *++next;
5021 5069  
5022 5070                  /* now we have "(filter)" with str pointing to it */
5023 5071                  *next = '\0';
5024 5072                  if (adj_filter(str) == -1)
5025 5073                          return (-1);
5026 5074                  next = resync_str(str, next, save);
5027 5075  
5028 5076                  str = next;
5029 5077          }
5030 5078  
5031 5079          return (0);
5032 5080  }
5033 5081  
5034 5082  
5035 5083  /*
5036 5084   * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
5037 5085   * of a filter expression, 0 otherwise.  A valid string may contain only
5038 5086   * letters, numbers, hyphens, semi-colons, colons and periods. examples:
5039 5087   *      cn
5040 5088   *      cn;lang-fr
5041 5089   *      1.2.3.4;binary;dynamic
5042 5090   *      mail;dynamic
5043 5091   *      cn:dn:1.2.3.4
5044 5092   *
5045 5093   * For compatibility with older servers, we also allow underscores in
5046 5094   * attribute types, even through they are not allowed by the LDAPv3 RFCs.
5047 5095   */
5048 5096  static int
5049 5097  is_valid_attr(char *a)
5050 5098  {
5051 5099          for (; *a; a++) {
5052 5100                  if (!isascii(*a)) {
5053 5101                          return (0);
5054 5102                  } else if (!isalnum(*a)) {
5055 5103                          switch (*a) {
5056 5104                          case '-':
5057 5105                          case '.':
5058 5106                          case ';':
5059 5107                          case ':':
5060 5108                          case '_':
5061 5109                                  break; /* valid */
5062 5110                          default:
5063 5111                                  return (0);
5064 5112                          }
5065 5113                  }
5066 5114          }
5067 5115          return (1);
5068 5116  }
5069 5117  
5070 5118  static char *
5071 5119  find_star(char *s)
5072 5120  {
5073 5121          for (; *s; ++s) {
5074 5122                  switch (*s) {
5075 5123                  case '*':
5076 5124                          return (s);
5077 5125                  case '\\':
5078 5126                          ++s;
5079 5127                          if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
5080 5128                                  ++s;
5081 5129                  default:
5082 5130                          break;
5083 5131                  }
5084 5132          }
5085 5133          return (NULL);
5086 5134  }
5087 5135  
5088 5136  static int
5089 5137  adj_simple_filter(char *str)
5090 5138  {
5091 5139          char            *s, *s2, *s3, filterop;
5092 5140          char            *value;
5093 5141          int             ftype = 0;
5094 5142          int             rc;
5095 5143  
5096 5144          rc = -1;        /* pessimistic */
5097 5145  
5098 5146          if ((str = strdup(str)) == NULL) {
5099 5147                  return (rc);
5100 5148          }
5101 5149  
5102 5150          if ((s = strchr(str, '=')) == NULL) {
5103 5151                  goto free_and_return;
5104 5152          }
5105 5153          value = s + 1;
5106 5154          *s-- = '\0';
5107 5155          filterop = *s;
5108 5156          if (filterop == '<' || filterop == '>' || filterop == '~' ||
5109 5157              filterop == ':') {
5110 5158                  *s = '\0';
5111 5159          }
5112 5160  
5113 5161          if (!is_valid_attr(str)) {
5114 5162                  goto free_and_return;
5115 5163          }
5116 5164  
5117 5165          switch (filterop) {
5118 5166          case '<': /* LDAP_FILTER_LE */
5119 5167          case '>': /* LDAP_FILTER_GE */
5120 5168          case '~': /* LDAP_FILTER_APPROX */
5121 5169                  break;
5122 5170          case ':':       /* extended filter - v3 only */
5123 5171                  /*
5124 5172                   * extended filter looks like this:
5125 5173                   *
5126 5174                   *      [type][':dn'][':'oid]':='value
5127 5175                   *
5128 5176                   * where one of type or :oid is required.
5129 5177                   *
5130 5178                   */
5131 5179                  s2 = s3 = NULL;
5132 5180                  if ((s2 = strrchr(str, ':')) == NULL) {
5133 5181                          goto free_and_return;
5134 5182                  }
5135 5183                  if (strcasecmp(s2, ":dn") == 0) {
5136 5184                          *s2 = '\0';
5137 5185                  } else {
5138 5186                          *s2 = '\0';
5139 5187                          if ((s3 = strrchr(str, ':')) != NULL) {
5140 5188                                  if (strcasecmp(s3, ":dn") != 0) {
5141 5189                                          goto free_and_return;
5142 5190                                  }
5143 5191                                  *s3 = '\0';
5144 5192                          }
5145 5193                  }
5146 5194                  if (unescape_filterval(value) < 0) {
5147 5195                          goto free_and_return;
5148 5196                  }
5149 5197                  rc = 0;
5150 5198                  goto free_and_return;
5151 5199                  /* break; */
5152 5200          default:
5153 5201                  if (find_star(value) == NULL) {
5154 5202                          ftype = 0; /* LDAP_FILTER_EQUALITY */
5155 5203                  } else if (strcmp(value, "*") == 0) {
5156 5204                          ftype = 1; /* LDAP_FILTER_PRESENT */
5157 5205                  } else {
5158 5206                          rc = adj_substring_filter(value);
5159 5207                          goto free_and_return;
5160 5208                  }
5161 5209                  break;
5162 5210          }
5163 5211  
5164 5212          if (ftype != 0) {       /* == LDAP_FILTER_PRESENT */
5165 5213                  rc = 0;
5166 5214          } else if (unescape_filterval(value) >= 0) {
5167 5215                  rc = 0;
5168 5216          }
5169 5217          if (rc != -1) {
5170 5218                  rc = 0;
5171 5219          }
5172 5220  
5173 5221  free_and_return:
5174 5222          free(str);
5175 5223          return (rc);
5176 5224  }
5177 5225  
5178 5226  
5179 5227  /*
5180 5228   * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
5181 5229   * sequences within the null-terminated string 'val'.
5182 5230   *
5183 5231   * If 'val' contains invalid escape sequences we return -1.
5184 5232   * Otherwise return 1
5185 5233   */
5186 5234  static int
5187 5235  unescape_filterval(char *val)
5188 5236  {
5189 5237          boolean_t escape, firstdigit;
5190 5238          char *s;
5191 5239  
5192 5240          firstdigit = B_FALSE;
5193 5241          escape = B_FALSE;
5194 5242          for (s = val; *s; s++) {
5195 5243                  if (escape) {
5196 5244                          /*
5197 5245                           * first try LDAPv3 escape (hexadecimal) sequence
5198 5246                           */
5199 5247                          if (hexchar2int(*s) < 0) {
5200 5248                                  if (firstdigit) {
5201 5249                                          /*
5202 5250                                           * LDAPv2 (RFC1960) escape sequence
5203 5251                                           */
5204 5252                                          escape = B_FALSE;
5205 5253                                  } else {
5206 5254                                          return (-1);
5207 5255                                  }
5208 5256                          }
5209 5257                          if (firstdigit) {
5210 5258                                  firstdigit = B_FALSE;
5211 5259                          } else {
5212 5260                                  escape = B_FALSE;
5213 5261                          }
5214 5262  
5215 5263                  } else if (*s != '\\') {
5216 5264                          escape = B_FALSE;
5217 5265  
5218 5266                  } else {
5219 5267                          escape = B_TRUE;
5220 5268                          firstdigit = B_TRUE;
5221 5269                  }
5222 5270          }
5223 5271  
5224 5272          return (1);
5225 5273  }
5226 5274  
5227 5275  
5228 5276  /*
5229 5277   * convert character 'c' that represents a hexadecimal digit to an integer.
5230 5278   * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
5231 5279   * otherwise the converted value is returned.
5232 5280   */
5233 5281  static int
5234 5282  hexchar2int(char c)
5235 5283  {
5236 5284          if (c >= '0' && c <= '9') {
5237 5285                  return (c - '0');
5238 5286          }
5239 5287          if (c >= 'A' && c <= 'F') {
5240 5288                  return (c - 'A' + 10);
5241 5289          }
5242 5290          if (c >= 'a' && c <= 'f') {
5243 5291                  return (c - 'a' + 10);
5244 5292          }
5245 5293          return (-1);
5246 5294  }
5247 5295  
5248 5296  static int
5249 5297  adj_substring_filter(char *val)
5250 5298  {
5251 5299          char            *nextstar;
5252 5300  
5253 5301          for (; val != NULL; val = nextstar) {
5254 5302                  if ((nextstar = find_star(val)) != NULL) {
5255 5303                          *nextstar++ = '\0';
5256 5304                  }
5257 5305  
5258 5306                  if (*val != '\0') {
5259 5307                          if (unescape_filterval(val) < 0) {
5260 5308                                  return (-1);
5261 5309                          }
5262 5310                  }
5263 5311          }
5264 5312  
5265 5313          return (0);
5266 5314  }
5267 5315  
5268 5316  /* ***** End of modified libldap.so.5 filter parser ***** */
5269 5317  
5270 5318  
5271 5319  /*
5272 5320   * Walk filter, remove redundant parentheses in-line
5273 5321   * verify that the filter is reasonable
5274 5322   */
5275 5323  static int
5276 5324  validate_filter(ns_ldap_cookie_t *cookie)
5277 5325  {
5278 5326          char                    *filter = cookie->filter;
5279 5327          int                     rc;
5280 5328  
5281 5329          /* Parse filter looking for illegal values */
5282 5330  
5283 5331          rc = adj_filter(filter);
5284 5332          if (rc != 0) {
5285 5333                  return (NS_LDAP_OP_FAILED);
5286 5334          }
5287 5335  
5288 5336          /* end of filter checking */
5289 5337  
5290 5338          return (NS_LDAP_SUCCESS);
5291 5339  }
5292 5340  
5293 5341  /*
5294 5342   * Set the account management request control that needs to be sent to server.
5295 5343   * This control is required to get the account management information of
5296 5344   * a user to do local account checking.
5297 5345   */
5298 5346  static int
5299 5347  setup_acctmgmt_params(ns_ldap_cookie_t *cookie)
5300 5348  {
5301 5349          LDAPControl     *req, **requestctrls;
5302 5350  
5303 5351          req = calloc(1, sizeof (LDAPControl));
5304 5352  
5305 5353          if (req == NULL)
5306 5354                  return (NS_LDAP_MEMORY);
5307 5355  
5308 5356          /* fill in the fields of this new control */
5309 5357          req->ldctl_iscritical = 1;
5310 5358          req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
5311 5359          if (req->ldctl_oid == NULL) {
5312 5360                  free(req);
5313 5361                  return (NS_LDAP_MEMORY);
5314 5362          }
5315 5363  
5316 5364          requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
5317 5365          if (requestctrls == NULL) {
5318 5366                  ldap_control_free(req);
5319 5367                  return (NS_LDAP_MEMORY);
5320 5368          }
5321 5369  
5322 5370          requestctrls[0] = req;
5323 5371  
5324 5372          cookie->p_serverctrls = requestctrls;
5325 5373  
5326 5374          return (NS_LDAP_SUCCESS);
5327 5375  }
5328 5376  
5329 5377  /*
5330 5378   * int get_new_acct_more_info(BerElement *ber,
5331 5379   *     AcctUsableResponse_t *acctResp)
5332 5380   *
5333 5381   * Decode the more_info data from an Account Management control response,
5334 5382   * when the account is not usable and when code style is from recent LDAP
5335 5383   * servers (see below comments for parse_acct_cont_resp_msg() to get more
5336 5384   * details on coding styles and ASN1 description).
5337 5385   *
5338 5386   * Expected BER encoding: {tbtbtbtiti}
5339 5387   *      +t: tag is 0
5340 5388   *      +b: TRUE if inactive due to account inactivation
5341 5389   *      +t: tag is 1
5342 5390   *      +b: TRUE if password has been reset
5343 5391   *      +t: tag is 2
5344 5392   *      +b: TRUE if password is expired
5345 5393   *      +t: tag is 3
5346 5394   *      +i: contains num of remaining grace, 0 means no grace
5347 5395   *      +t: tag is 4
5348 5396   *      +i: contains num of seconds before auto-unlock. -1 means acct is locked
5349 5397   *              forever (i.e. until reset)
5350 5398   *
5351 5399   * Asumptions:
5352 5400   * - ber is not null
5353 5401   * - acctResp is not null and is initialized with default values for the
5354 5402   *   fields in its AcctUsableResp.more_info structure
5355 5403   * - the ber stream is received in the correct order, per the ASN1 description.
5356 5404   *   We do not check this order and make the asumption that it is correct.
5357 5405   *   Note that the ber stream may not (and will not in most cases) contain
5358 5406   *   all fields.
5359 5407   */
5360 5408  static int
5361 5409  get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
5362 5410  {
5363 5411          int             rc = NS_LDAP_SUCCESS;
5364 5412          char            errstr[MAXERROR];
5365 5413          ber_tag_t       rTag = LBER_DEFAULT;
5366 5414          ber_len_t       rLen = 0;
5367 5415          ber_int_t       rValue;
5368 5416          char            *last;
5369 5417          int             berRC = 0;
5370 5418  
5371 5419          /*
5372 5420           * Look at what more_info BER element is/are left to be decoded.
5373 5421           * look at each of them 1 by 1, without checking on their order
5374 5422           * and possible multi values.
5375 5423           */
5376 5424          for (rTag = ber_first_element(ber, &rLen, &last);
5377 5425              rTag != LBER_END_OF_SEQORSET;
5378 5426              rTag = ber_next_element(ber, &rLen, last)) {
5379 5427  
5380 5428                  berRC = 0;
5381 5429                  switch (rTag) {
5382 5430                  case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5383 5431                          /* inactive */
5384 5432                          berRC = ber_scanf(ber, "b", &rValue);
5385 5433                          if (berRC != LBER_ERROR) {
5386 5434                                  (acctResp->AcctUsableResp).more_info.
5387 5435                                      inactive = (rValue != 0) ? 1 : 0;
5388 5436                          }
5389 5437                          break;
5390 5438  
5391 5439                  case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5392 5440                          /* reset */
5393 5441                          berRC = ber_scanf(ber, "b", &rValue);
5394 5442                          if (berRC != LBER_ERROR) {
5395 5443                                  (acctResp->AcctUsableResp).more_info.reset
5396 5444                                      = (rValue != 0) ? 1 : 0;
5397 5445                          }
5398 5446                          break;
5399 5447  
5400 5448                  case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5401 5449                          /* expired */
5402 5450                          berRC = ber_scanf(ber, "b", &rValue);
5403 5451                          if (berRC != LBER_ERROR) {
5404 5452                                  (acctResp->AcctUsableResp).more_info.expired
5405 5453                                      = (rValue != 0) ? 1 : 0;
5406 5454                          }
5407 5455                          break;
5408 5456  
5409 5457                  case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5410 5458                          /* remaining grace */
5411 5459                          berRC = ber_scanf(ber, "i", &rValue);
5412 5460                          if (berRC != LBER_ERROR) {
5413 5461                                  (acctResp->AcctUsableResp).more_info.rem_grace
5414 5462                                      = rValue;
5415 5463                          }
5416 5464                          break;
5417 5465  
5418 5466                  case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5419 5467                          /* seconds before unlock */
5420 5468                          berRC = ber_scanf(ber, "i", &rValue);
5421 5469                          if (berRC != LBER_ERROR) {
5422 5470                                  (acctResp->AcctUsableResp).more_info.
5423 5471                                      sec_b4_unlock = rValue;
5424 5472                          }
5425 5473                          break;
5426 5474  
5427 5475                  default :
5428 5476                          (void) sprintf(errstr,
5429 5477                              gettext("invalid reason tag 0x%x"), rTag);
5430 5478                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5431 5479                          rc = NS_LDAP_INTERNAL;
5432 5480                          break;
5433 5481                  }
5434 5482                  if (berRC == LBER_ERROR) {
5435 5483                          (void) sprintf(errstr,
5436 5484                              gettext("error 0x%x decoding value for "
5437 5485                              "tag 0x%x"), berRC, rTag);
5438 5486                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5439 5487                          rc = NS_LDAP_INTERNAL;
5440 5488                  }
5441 5489                  if (rc != NS_LDAP_SUCCESS) {
5442 5490                          /* exit the for loop */
5443 5491                          break;
5444 5492                  }
5445 5493          }
5446 5494  
5447 5495          return (rc);
5448 5496  }
5449 5497  
5450 5498  /*
5451 5499   * int get_old_acct_opt_more_info(BerElement *ber,
5452 5500   *     AcctUsableResponse_t *acctResp)
5453 5501   *
5454 5502   * Decode the optional more_info data from an Account Management control
5455 5503   * response, when the account is not usable and when code style is from LDAP
5456 5504   * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5457 5505   * details on coding styles and ASN1 description).
5458 5506   *
5459 5507   * Expected BER encoding: titi}
5460 5508   *      +t: tag is 2
5461 5509   *      +i: contains num of remaining grace, 0 means no grace
5462 5510   *      +t: tag is 3
5463 5511   *      +i: contains num of seconds before auto-unlock. -1 means acct is locked
5464 5512   *              forever (i.e. until reset)
5465 5513   *
5466 5514   * Asumptions:
5467 5515   * - ber is a valid BER element
5468 5516   * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5469 5517   *   structure
5470 5518   */
5471 5519  static int
5472 5520  get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
5473 5521      AcctUsableResponse_t *acctResp)
5474 5522  {
5475 5523          int             rc = NS_LDAP_SUCCESS;
5476 5524          char            errstr[MAXERROR];
5477 5525          ber_len_t       len;
5478 5526          int             rem_grace, sec_b4_unlock;
5479 5527  
5480 5528          switch (tag) {
5481 5529          case 2:
5482 5530                  /* decode and maybe 3 is following */
5483 5531                  if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
5484 5532                          (void) sprintf(errstr, gettext("Can not get "
5485 5533                              "rem_grace"));
5486 5534                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5487 5535                          rc = NS_LDAP_INTERNAL;
5488 5536                          break;
5489 5537                  }
5490 5538                  (acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
5491 5539  
5492 5540                  if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5493 5541                          /* this is a success case, break to exit */
5494 5542                          (void) sprintf(errstr, gettext("No more "
5495 5543                              "optional data"));
5496 5544                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5497 5545                          break;
5498 5546                  }
5499 5547  
5500 5548                  if (tag == 3) {
5501 5549                          if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5502 5550                                  (void) sprintf(errstr,
5503 5551                                      gettext("Can not get sec_b4_unlock "
5504 5552                                      "- 1st case"));
5505 5553                                  syslog(LOG_DEBUG, "libsldap: %s", errstr);
5506 5554                                  rc = NS_LDAP_INTERNAL;
5507 5555                                  break;
5508 5556                          }
5509 5557                          (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5510 5558                              sec_b4_unlock;
5511 5559                  } else { /* unknown tag */
5512 5560                          (void) sprintf(errstr, gettext("Unknown tag "
5513 5561                              "- 1st case"));
5514 5562                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5515 5563                          rc = NS_LDAP_INTERNAL;
5516 5564                          break;
5517 5565                  }
5518 5566                  break;
5519 5567  
5520 5568          case 3:
5521 5569                  if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5522 5570                          (void) sprintf(errstr, gettext("Can not get "
5523 5571                              "sec_b4_unlock - 2nd case"));
5524 5572                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5525 5573                          rc = NS_LDAP_INTERNAL;
5526 5574                          break;
5527 5575                  }
5528 5576                  (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5529 5577                      sec_b4_unlock;
5530 5578                  break;
5531 5579  
5532 5580          default: /* unknown tag */
5533 5581                  (void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
5534 5582                  syslog(LOG_DEBUG, "libsldap: %s", errstr);
5535 5583                  rc = NS_LDAP_INTERNAL;
5536 5584                  break;
5537 5585          }
5538 5586  
5539 5587          return (rc);
5540 5588  }
5541 5589  
5542 5590  /*
5543 5591   * **** This function needs to be moved to libldap library ****
5544 5592   * parse_acct_cont_resp_msg() parses the message received by server according to
5545 5593   * following format (ASN1 notation):
5546 5594   *
5547 5595   *      ACCOUNT_USABLE_RESPONSE::= CHOICE {
5548 5596   *              is_available            [0] INTEGER,
5549 5597   *                              ** seconds before expiration **
5550 5598   *              is_not_available        [1] more_info
5551 5599   *      }
5552 5600   *      more_info::= SEQUENCE {
5553 5601   *              inactive                [0] BOOLEAN DEFAULT FALSE,
5554 5602   *              reset                   [1] BOOLEAN DEFAULT FALSE,
5555 5603   *              expired                 [2] BOOLEAN DEFAULT FALSE,
5556 5604   *              remaining_grace         [3] INTEGER OPTIONAL,
5557 5605   *              seconds_before_unlock   [4] INTEGER OPTIONAL
5558 5606   *      }
5559 5607   */
5560 5608  /*
5561 5609   * #define used to make the difference between coding style as done
5562 5610   * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5563 5611   * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5564 5612   * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5565 5613   * - NEW_USABLE: newer LDAP servers coding style, account is usable
5566 5614   * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5567 5615   *
5568 5616   * An account would be considered not usable if for instance:
5569 5617   * - it's been made inactive in the LDAP server
5570 5618   * - or its password was reset in the LDAP server database
5571 5619   * - or its password expired
5572 5620   * - or the account has been locked, possibly forever
5573 5621   */
5574 5622  #define DS52p4_USABLE           0x00
5575 5623  #define DS52p4_NOT_USABLE       0x01
5576 5624  #define NEW_USABLE              0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5577 5625  #define NEW_NOT_USABLE          0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
5578 5626  static int
5579 5627  parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
5580 5628  {
5581 5629          int             rc = NS_LDAP_SUCCESS;
5582 5630          BerElement      *ber;
5583 5631          ber_tag_t       tag;
5584 5632          ber_len_t       len;
5585 5633          int             i;
5586 5634          char            errstr[MAXERROR];
5587 5635          /* used for any coding style when account is usable */
5588 5636          int             seconds_before_expiry;
5589 5637          /* used for 5.2p4 coding style when account is not usable */
5590 5638          int             inactive, reset, expired;
5591 5639  
5592 5640          if (ectrls == NULL) {
5593 5641                  (void) sprintf(errstr, gettext("Invalid ectrls parameter"));
5594 5642                  syslog(LOG_DEBUG, "libsldap: %s", errstr);
5595 5643                  return (NS_LDAP_INVALID_PARAM);
5596 5644          }
5597 5645  
5598 5646          for (i = 0; ectrls[i] != NULL; i++) {
5599 5647                  if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
5600 5648                      == 0) {
5601 5649                          break;
5602 5650                  }
5603 5651          }
5604 5652  
5605 5653          if (ectrls[i] == NULL) {
5606 5654                  /* Ldap control is not found */
5607 5655                  (void) sprintf(errstr, gettext("Account Usable Control "
5608 5656                      "not found"));
5609 5657                  syslog(LOG_DEBUG, "libsldap: %s", errstr);
5610 5658                  return (NS_LDAP_NOTFOUND);
5611 5659          }
5612 5660  
5613 5661          /* Allocate a BER element from the control value and parse it. */
5614 5662          if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
5615 5663                  return (NS_LDAP_MEMORY);
5616 5664  
5617 5665          if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5618 5666                  /* Ldap decoding error */
5619 5667                  (void) sprintf(errstr, gettext("Error decoding 1st tag"));
5620 5668                  syslog(LOG_DEBUG, "libsldap: %s", errstr);
5621 5669                  ber_free(ber, 1);
5622 5670                  return (NS_LDAP_INTERNAL);
5623 5671          }
5624 5672  
5625 5673          switch (tag) {
5626 5674          case DS52p4_USABLE:
5627 5675          case NEW_USABLE:
5628 5676                  acctResp->choice = 0;
5629 5677                  if (ber_scanf(ber, "i", &seconds_before_expiry)
5630 5678                      == LBER_ERROR) {
5631 5679                          /* Ldap decoding error */
5632 5680                          (void) sprintf(errstr, gettext("Can not get "
5633 5681                              "seconds_before_expiry"));
5634 5682                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5635 5683                          rc = NS_LDAP_INTERNAL;
5636 5684                          break;
5637 5685                  }
5638 5686                  /* ber_scanf() succeeded */
5639 5687                  (acctResp->AcctUsableResp).seconds_before_expiry =
5640 5688                      seconds_before_expiry;
5641 5689                  break;
5642 5690  
5643 5691          case DS52p4_NOT_USABLE:
5644 5692                  acctResp->choice = 1;
5645 5693                  if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
5646 5694                      == LBER_ERROR) {
5647 5695                          /* Ldap decoding error */
5648 5696                          (void) sprintf(errstr, gettext("Can not get "
5649 5697                              "inactive/reset/expired"));
5650 5698                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5651 5699                          rc = NS_LDAP_INTERNAL;
5652 5700                          break;
5653 5701                  }
5654 5702                  /* ber_scanf() succeeded */
5655 5703                  (acctResp->AcctUsableResp).more_info.inactive =
5656 5704                      ((inactive == 0) ? 0 : 1);
5657 5705                  (acctResp->AcctUsableResp).more_info.reset =
5658 5706                      ((reset == 0) ? 0 : 1);
5659 5707                  (acctResp->AcctUsableResp).more_info.expired =
5660 5708                      ((expired == 0) ? 0 : 1);
5661 5709                  (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5662 5710                  (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5663 5711  
5664 5712                  if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5665 5713                          /* this is a success case, break to exit */
5666 5714                          (void) sprintf(errstr, gettext("No optional data"));
5667 5715                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5668 5716                          break;
5669 5717                  }
5670 5718  
5671 5719                  /*
5672 5720                   * Look at what optional more_info BER element is/are
5673 5721                   * left to be decoded.
5674 5722                   */
5675 5723                  rc = get_old_acct_opt_more_info(tag, ber, acctResp);
5676 5724                  break;
5677 5725  
5678 5726          case NEW_NOT_USABLE:
5679 5727                  acctResp->choice = 1;
5680 5728                  /*
5681 5729                   * Recent LDAP servers won't code more_info data for default
5682 5730                   * values (see above comments on ASN1 description for what
5683 5731                   * fields have default values & what fields are optional).
5684 5732                   */
5685 5733                  (acctResp->AcctUsableResp).more_info.inactive = 0;
5686 5734                  (acctResp->AcctUsableResp).more_info.reset = 0;
5687 5735                  (acctResp->AcctUsableResp).more_info.expired = 0;
5688 5736                  (acctResp->AcctUsableResp).more_info.rem_grace = 0;
5689 5737                  (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5690 5738  
5691 5739                  if (len == 0) {
5692 5740                          /*
5693 5741                           * Nothing else to decode; this is valid and we
5694 5742                           * use default values set above.
5695 5743                           */
5696 5744                          (void) sprintf(errstr, gettext("more_info is "
5697 5745                              "empty, using default values"));
5698 5746                          syslog(LOG_DEBUG, "libsldap: %s", errstr);
5699 5747                          break;
5700 5748                  }
5701 5749  
5702 5750                  /*
5703 5751                   * Look at what more_info BER element is/are left to
5704 5752                   * be decoded.
5705 5753                   */
5706 5754                  rc = get_new_acct_more_info(ber, acctResp);
5707 5755                  break;
5708 5756  
5709 5757          default:
5710 5758                  (void) sprintf(errstr, gettext("unknwon coding style "
5711 5759                      "(tag: 0x%x)"), tag);
5712 5760                  syslog(LOG_DEBUG, "libsldap: %s", errstr);
5713 5761                  rc = NS_LDAP_INTERNAL;
5714 5762                  break;
5715 5763          }
5716 5764  
5717 5765          ber_free(ber, 1);
5718 5766          return (rc);
5719 5767  }
5720 5768  
5721 5769  /*
5722 5770   * internal function for __ns_ldap_getAcctMgmt()
5723 5771   */
5724 5772  static int
5725 5773  getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
5726 5774      ns_conn_user_t *conn_user)
5727 5775  {
5728 5776          int             scope, rc;
5729 5777          ns_ldap_cookie_t        *cookie;
5730 5778          ns_ldap_search_desc_t   **sdlist = NULL;
5731 5779          ns_ldap_search_desc_t   *dptr;
5732 5780          ns_ldap_error_t         *error = NULL;
5733 5781          char                    **dns = NULL;
5734 5782          char            service[] = "shadow";
5735 5783  
5736 5784          if (user == NULL || acctResp == NULL)
5737 5785                  return (NS_LDAP_INVALID_PARAM);
5738 5786  
5739 5787          /* Initialize State machine cookie */
5740 5788          cookie = init_search_state_machine();
5741 5789          if (cookie == NULL)
5742 5790                  return (NS_LDAP_MEMORY);
5743 5791          cookie->conn_user = conn_user;
5744 5792  
5745 5793          /* see if need to follow referrals */
5746 5794          rc = __s_api_toFollowReferrals(0,
5747 5795              &cookie->followRef, &error);
5748 5796          if (rc != NS_LDAP_SUCCESS) {
5749 5797                  (void) __ns_ldap_freeError(&error);
5750 5798                  goto out;
5751 5799          }
5752 5800  
5753 5801          /* get the service descriptor - or create a default one */
5754 5802          rc = __s_api_get_SSD_from_SSDtoUse_service(service,
5755 5803              &sdlist, &error);
5756 5804          if (rc != NS_LDAP_SUCCESS) {
5757 5805                  (void) __ns_ldap_freeError(&error);
5758 5806                  goto out;
5759 5807          }
5760 5808  
5761 5809          if (sdlist == NULL) {
5762 5810                  /* Create default service Desc */
5763 5811                  sdlist = (ns_ldap_search_desc_t **)calloc(2,
5764 5812                      sizeof (ns_ldap_search_desc_t *));
5765 5813                  if (sdlist == NULL) {
5766 5814                          rc = NS_LDAP_MEMORY;
5767 5815                          goto out;
5768 5816                  }
5769 5817                  dptr = (ns_ldap_search_desc_t *)
5770 5818                      calloc(1, sizeof (ns_ldap_search_desc_t));
5771 5819                  if (dptr == NULL) {
5772 5820                          free(sdlist);
5773 5821                          rc = NS_LDAP_MEMORY;
5774 5822                          goto out;
5775 5823                  }
5776 5824                  sdlist[0] = dptr;
5777 5825  
5778 5826                  /* default base */
5779 5827                  rc = __s_api_getDNs(&dns, service, &cookie->errorp);
5780 5828                  if (rc != NS_LDAP_SUCCESS) {
5781 5829                          if (dns) {
5782 5830                                  __s_api_free2dArray(dns);
5783 5831                                  dns = NULL;
5784 5832                          }
5785 5833                          (void) __ns_ldap_freeError(&(cookie->errorp));
5786 5834                          cookie->errorp = NULL;
5787 5835                          goto out;
5788 5836                  }
5789 5837                  dptr->basedn = strdup(dns[0]);
5790 5838                  if (dptr->basedn == NULL) {
5791 5839                          free(sdlist);
5792 5840                          free(dptr);
5793 5841                          if (dns) {
5794 5842                                  __s_api_free2dArray(dns);
5795 5843                                  dns = NULL;
5796 5844                          }
5797 5845                          rc = NS_LDAP_MEMORY;
5798 5846                          goto out;
5799 5847                  }
5800 5848                  __s_api_free2dArray(dns);
5801 5849                  dns = NULL;
5802 5850  
5803 5851                  /* default scope */
5804 5852                  scope = 0;
5805 5853                  rc = __s_api_getSearchScope(&scope, &cookie->errorp);
5806 5854                  dptr->scope = scope;
5807 5855          }
5808 5856  
5809 5857          cookie->sdlist = sdlist;
5810 5858  
5811 5859          cookie->service = strdup(service);
5812 5860          if (cookie->service == NULL) {
5813 5861                  rc = NS_LDAP_MEMORY;
5814 5862                  goto out;
5815 5863          }
5816 5864  
5817 5865          /* search for entries for this particular uid */
5818 5866          (void) asprintf(&cookie->i_filter, "(uid=%s)", user);
5819 5867          if (cookie->i_filter == NULL) {
5820 5868                  rc = NS_LDAP_MEMORY;
5821 5869                  goto out;
5822 5870          }
5823 5871  
5824 5872          /* create the control request */
5825 5873          if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
5826 5874                  goto out;
5827 5875  
5828 5876          /* Process search */
5829 5877          rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
5830 5878  
5831 5879          /* Copy results back to user */
5832 5880          rc = cookie->err_rc;
5833 5881          if (rc != NS_LDAP_SUCCESS)
5834 5882                          (void) __ns_ldap_freeError(&(cookie->errorp));
5835 5883  
5836 5884          if (cookie->result == NULL)
5837 5885                          goto out;
5838 5886  
5839 5887          if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
5840 5888              != NS_LDAP_SUCCESS)
5841 5889                  goto out;
5842 5890  
5843 5891          rc = NS_LDAP_SUCCESS;
5844 5892  
5845 5893  out:
5846 5894          delete_search_cookie(cookie);
5847 5895  
5848 5896          return (rc);
5849 5897  }
5850 5898  
5851 5899  /*
5852 5900   * __ns_ldap_getAcctMgmt() is called from pam account management stack
5853 5901   * for retrieving accounting information of users with no user password -
5854 5902   * eg. rlogin, rsh, etc. This function uses the account management control
5855 5903   * request to do a search on the server for the user in question. The
5856 5904   * response control returned from the server is got from the cookie.
5857 5905   * Input params: username of whose account mgmt information is to be got
5858 5906   *               pointer to hold the parsed account management information
5859 5907   * Return values: NS_LDAP_SUCCESS on success or appropriate error
5860 5908   *              code on failure
5861 5909   */
5862 5910  int
5863 5911  __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
5864 5912  {
5865 5913          ns_conn_user_t  *cu = NULL;
5866 5914          int             try_cnt = 0;
5867 5915          int             rc = NS_LDAP_SUCCESS;
5868 5916          ns_ldap_error_t *error = NULL;
5869 5917  
5870 5918          for (;;) {
5871 5919                  if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
5872 5920                      &try_cnt, &rc, &error) == 0)
5873 5921                          break;
5874 5922                  rc = getAcctMgmt(user, acctResp, cu);
5875 5923          }
5876 5924          return (rc);
5877 5925  }
  
    | 
      ↓ open down ↓ | 
    1559 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX