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