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