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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <sys/types.h> 31 #include <stdlib.h> 32 #include <libintl.h> 33 #include <ctype.h> 34 #include <syslog.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <strings.h> 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) 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 && 485 (flags & NS_LDAP_NOMAP) == 0) 486 /* 487 * if service == auto_* and no 488 * schema mapping found 489 * and schema_mapping_existed is TRUE 490 * and NS_LDAP_NOMAP is not set 491 * then try automount 492 * e.g. 493 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA 494 */ 495 mapping = __ns_ldap_getOrigAttribute("automount", attr); 496 497 if (mapping == NULL) { 498 if ((ap[j]->attrname = strdup(attr)) == NULL) { 499 ber_free(ber, 0); 500 ber = NULL; 501 __ns_ldap_freeEntry(ep); 502 ep = NULL; 503 if (gecos_mapping) 504 __s_api_free2dArray(gecos_mapping); 505 gecos_mapping = NULL; 506 return (NS_LDAP_MEMORY); 507 } 508 } else { 509 /* 510 * for "gecos" 1 to N mapping, 511 * do not remove the mapped attribute, 512 * just create a new gecos attribute 513 * and append it to the end of the attribute list 514 */ 515 if (strcasecmp(mapping[0], "gecos") == 0) { 516 ap[j]->attrname = strdup(attr); 517 gecos_mapping_existed = TRUE; 518 } else 519 ap[j]->attrname = strdup(mapping[0]); 520 521 if (ap[j]->attrname == NULL) { 522 ber_free(ber, 0); 523 ber = NULL; 524 __ns_ldap_freeEntry(ep); 525 ep = NULL; 526 if (gecos_mapping) 527 __s_api_free2dArray(gecos_mapping); 528 gecos_mapping = NULL; 529 return (NS_LDAP_MEMORY); 530 } 531 /* 532 * 1 to N attribute mapping processing 533 * is only done for "gecos" 534 */ 535 536 if (strcasecmp(mapping[0], "gecos") == 0) { 537 /* 538 * get attribute mapping for "gecos", 539 * need to know the number and order of the 540 * mapped attributes 541 */ 542 if (gecos_mapping == NULL) { 543 gecos_mapping = 544 __ns_ldap_getMappedAttributes(service, 545 mapping[0]); 546 if (gecos_mapping == NULL || 547 gecos_mapping[0] == NULL) { 548 /* 549 * this should never happens, 550 * syslog the error 551 */ 552 (void) sprintf(errstr, 553 gettext( 554 "Attribute mapping " 555 "inconsistency " 556 "found for attributes " 557 "'%s' and '%s'."), 558 mapping[0], attr); 559 syslog(LOG_ERR, "libsldap: %s", errstr); 560 561 ber_free(ber, 0); 562 ber = NULL; 563 __ns_ldap_freeEntry(ep); 564 ep = NULL; 565 __s_api_free2dArray(mapping); 566 mapping = NULL; 567 if (gecos_mapping) 568 __s_api_free2dArray( 569 gecos_mapping); 570 gecos_mapping = NULL; 571 return (NS_LDAP_INTERNAL); 572 } 573 } 574 575 /* 576 * is this attribute the 1st, 2nd, or 577 * 3rd attr in the mapping list? 578 */ 579 gecos_attr_matched = FALSE; 580 for (i = 0; i < 3 && gecos_mapping[i]; i++) { 581 if (gecos_mapping[i] && 582 strcasecmp(gecos_mapping[i], 583 attr) == 0) { 584 gecos_val_index[i] = j; 585 gecos_attr_matched = TRUE; 586 break; 587 } 588 } 589 if (gecos_attr_matched == FALSE) { 590 /* 591 * Not match found. 592 * This should never happens, 593 * syslog the error 594 */ 595 (void) sprintf(errstr, 596 gettext( 597 "Attribute mapping " 598 "inconsistency " 599 "found for attributes " 600 "'%s' and '%s'."), 601 mapping[0], attr); 602 syslog(LOG_ERR, "libsldap: %s", errstr); 603 604 ber_free(ber, 0); 605 ber = NULL; 606 __ns_ldap_freeEntry(ep); 607 ep = NULL; 608 __s_api_free2dArray(mapping); 609 mapping = NULL; 610 __s_api_free2dArray(gecos_mapping); 611 gecos_mapping = NULL; 612 return (NS_LDAP_INTERNAL); 613 } 614 } 615 __s_api_free2dArray(mapping); 616 mapping = NULL; 617 } 618 619 if ((vals = ldap_get_values(ld, e, attr)) != NULL) { 620 621 if ((ap[j]->value_count = ldap_count_values(vals)) == 0) { 622 ldap_value_free(vals); 623 vals = NULL; 624 continue; 625 } else { 626 ap[j]->attrvalue = (char **) 627 calloc(ap[j]->value_count+1, 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(gecos_mapping); 635 gecos_mapping = NULL; 636 return (NS_LDAP_MEMORY); 637 } 638 } 639 640 /* map object classes if necessary */ 641 if ((flags & NS_LDAP_NOMAP) == 0 && 642 schema_mapping_existed && ap[j]->attrname && 643 strcasecmp(ap[j]->attrname, "objectclass") == 0) { 644 for (k = 0; k < ap[j]->value_count; k++) { 645 mapping = 646 __ns_ldap_getOrigObjectClass(service, vals[k]); 647 648 if (mapping == NULL && auto_service) 649 /* 650 * if service == auto_* and no 651 * schema mapping found 652 * then try automount 653 */ 654 mapping = 655 __ns_ldap_getOrigObjectClass( 656 "automount", vals[k]); 657 658 if (mapping == NULL) { 659 ap[j]->attrvalue[k] = strdup(vals[k]); 660 } else { 661 ap[j]->attrvalue[k] = strdup(mapping[0]); 662 __s_api_free2dArray(mapping); 663 mapping = NULL; 664 } 665 if (ap[j]->attrvalue[k] == NULL) { 666 ber_free(ber, 0); 667 ber = NULL; 668 __ns_ldap_freeEntry(ep); 669 ep = NULL; 670 if (gecos_mapping) 671 __s_api_free2dArray(gecos_mapping); 672 gecos_mapping = NULL; 673 return (NS_LDAP_MEMORY); 674 } 675 } 676 } else { 677 for (k = 0; k < ap[j]->value_count; k++) { 678 if ((ap[j]->attrvalue[k] = strdup(vals[k])) == NULL) { 679 ber_free(ber, 0); 680 ber = NULL; 681 __ns_ldap_freeEntry(ep); 682 ep = NULL; 683 if (gecos_mapping) 684 __s_api_free2dArray(gecos_mapping); 685 gecos_mapping = NULL; 686 return (NS_LDAP_MEMORY); 687 } 688 } 689 } 690 691 ap[j]->attrvalue[k] = NULL; 692 ldap_value_free(vals); 693 vals = NULL; 694 } 695 696 ldap_memfree(attr); 697 attr = NULL; 698 } 699 700 ber_free(ber, 0); 701 ber = NULL; 702 703 if (gecos_mapping) { 704 __s_api_free2dArray(gecos_mapping); 705 gecos_mapping = NULL; 706 } 707 708 /* special processing for gecos 1 to up to 3 attribute mapping */ 709 if (schema_mapping_existed && gecos_mapping_existed) { 710 711 int f = -1; 712 713 for (i = 0; i < 3; i++) { 714 k = gecos_val_index[i]; 715 716 /* 717 * f is the index of the first returned 718 * attribute which "gecos" attribute mapped to 719 */ 720 if (k != -1 && f == -1) 721 f = k; 722 723 if (k != -1 && ap[k]->value_count > 0 && 724 ap[k]->attrvalue[0] && 725 strlen(ap[k]->attrvalue[0]) > 0) { 726 727 if (k == f) { 728 /* 729 * Create and fill in the last reserved 730 * ap with the data from the "gecos" 731 * mapping attributes 732 */ 733 ap[nAttrs] = (ns_ldap_attr_t *) 734 calloc(1, 735 sizeof (ns_ldap_attr_t)); 736 if (ap[nAttrs] == NULL) { 737 __ns_ldap_freeEntry(ep); 738 ep = NULL; 739 return (NS_LDAP_MEMORY); 740 } 741 ap[nAttrs]->attrvalue = (char **)calloc( 742 2, sizeof (char *)); 743 if (ap[nAttrs]->attrvalue == NULL) { 744 __ns_ldap_freeEntry(ep); 745 ep = NULL; 746 return (NS_LDAP_MEMORY); 747 } 748 /* add 1 more for a possible "," */ 749 ap[nAttrs]->attrvalue[0] = 750 (char *)calloc( 751 strlen(ap[f]->attrvalue[0]) + 752 2, 1); 753 if (ap[nAttrs]->attrvalue[0] == NULL) { 754 __ns_ldap_freeEntry(ep); 755 ep = NULL; 756 return (NS_LDAP_MEMORY); 757 } 758 (void) strcpy(ap[nAttrs]->attrvalue[0], 759 ap[f]->attrvalue[0]); 760 761 ap[nAttrs]->attrname = strdup("gecos"); 762 if (ap[nAttrs]->attrname == NULL) { 763 __ns_ldap_freeEntry(ep); 764 ep = NULL; 765 return (NS_LDAP_MEMORY); 766 } 767 768 ap[nAttrs]->value_count = 1; 769 ep->attr_count = nAttrs + 1; 770 771 } else { 772 (void) strcat(ap[nAttrs]->attrvalue[0], 773 ","); 774 ap[nAttrs]->attrvalue[0] = 775 (char *)realloc( 776 ap[nAttrs]->attrvalue[0], 777 strlen(ap[nAttrs]-> 778 attrvalue[0]) + 2); 779 if (ap[nAttrs]->attrvalue[0] == NULL) { 780 __ns_ldap_freeEntry(ep); 781 ep = NULL; 782 return (NS_LDAP_MEMORY); 783 } 784 (void) strcat(ap[nAttrs]->attrvalue[0], 785 ap[k]->attrvalue[0]); 786 } 787 } 788 } 789 } 790 791 *ret = ep; 792 return (NS_LDAP_SUCCESS); 793 } 794 795 static int 796 __s_api_getEntry(ns_ldap_cookie_t *cookie) 797 { 798 ns_ldap_entry_t *curEntry = NULL; 799 int ret; 800 801 #ifdef DEBUG 802 (void) fprintf(stderr, "__s_api_getEntry START\n"); 803 #endif 804 805 if (cookie->resultMsg == NULL) { 806 return (NS_LDAP_INVALID_PARAM); 807 } 808 ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service, 809 cookie->resultMsg, cookie->i_flags, 810 &curEntry, &cookie->errorp); 811 if (ret != NS_LDAP_SUCCESS) { 812 return (ret); 813 } 814 815 if (cookie->result == NULL) { 816 cookie->result = (ns_ldap_result_t *) 817 calloc(1, sizeof (ns_ldap_result_t)); 818 if (cookie->result == NULL) { 819 __ns_ldap_freeEntry(curEntry); 820 curEntry = NULL; 821 return (NS_LDAP_MEMORY); 822 } 823 cookie->result->entry = curEntry; 824 cookie->nextEntry = curEntry; 825 } else { 826 cookie->nextEntry->next = curEntry; 827 cookie->nextEntry = curEntry; 828 } 829 cookie->result->entries_count++; 830 831 return (NS_LDAP_SUCCESS); 832 } 833 834 static int 835 __s_api_get_cachemgr_data(const char *type, 836 const char *from, char **to) 837 { 838 union { 839 ldap_data_t s_d; 840 char s_b[DOORBUFFERSIZE]; 841 } space; 842 ldap_data_t *sptr; 843 int ndata; 844 int adata; 845 int rc; 846 847 #ifdef DEBUG 848 (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n"); 849 #endif 850 851 if (from == NULL || from[0] == '\0' || to == NULL) 852 return (-1); 853 854 *to = NULL; 855 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 856 857 space.s_d.ldap_call.ldap_callnumber = GETCACHE; 858 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname, 859 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber), 860 "%s%s%s", 861 type, 862 DOORLINESEP, 863 from); 864 ndata = sizeof (space); 865 adata = sizeof (ldap_call_t) + 866 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1; 867 sptr = &space.s_d; 868 869 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata); 870 if (rc != SUCCESS) 871 return (-1); 872 else 873 *to = strdup(sptr->ldap_ret.ldap_u.buff); 874 return (NS_LDAP_SUCCESS); 875 } 876 877 static int 878 __s_api_set_cachemgr_data(const char *type, 879 const char *from, const char *to) 880 { 881 union { 882 ldap_data_t s_d; 883 char s_b[DOORBUFFERSIZE]; 884 } space; 885 ldap_data_t *sptr; 886 int ndata; 887 int adata; 888 int rc; 889 890 #ifdef DEBUG 891 (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n"); 892 #endif 893 894 if ((from == NULL) || (from[0] == '\0') || 895 (to == NULL) || (to[0] == '\0')) 896 return (-1); 897 898 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 899 900 space.s_d.ldap_call.ldap_callnumber = SETCACHE; 901 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname, 902 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber), 903 "%s%s%s%s%s", 904 type, 905 DOORLINESEP, 906 from, 907 DOORLINESEP, 908 to); 909 910 ndata = sizeof (space); 911 adata = sizeof (ldap_call_t) + 912 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1; 913 sptr = &space.s_d; 914 915 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata); 916 if (rc != SUCCESS) 917 return (-1); 918 919 return (NS_LDAP_SUCCESS); 920 } 921 922 923 static char * 924 __s_api_remove_rdn_space(char *rdn) 925 { 926 char *tf, *tl, *vf, *vl, *eqsign; 927 928 /* if no space(s) to remove, return */ 929 if (strchr(rdn, SPACETOK) == NULL) 930 return (rdn); 931 932 /* if no '=' separator, return */ 933 eqsign = strchr(rdn, '='); 934 if (eqsign == NULL) 935 return (rdn); 936 937 tf = rdn; 938 tl = eqsign - 1; 939 vf = eqsign + 1; 940 vl = rdn + strlen(rdn) - 1; 941 942 /* now two strings, type and value */ 943 *eqsign = '\0'; 944 945 /* remove type's leading spaces */ 946 while (tf < tl && *tf == SPACETOK) 947 tf++; 948 /* remove type's trailing spaces */ 949 while (tf < tl && *tl == SPACETOK) 950 tl--; 951 /* add '=' separator back */ 952 *(++tl) = '='; 953 /* remove value's leading spaces */ 954 while (vf < vl && *vf == SPACETOK) 955 vf++; 956 /* remove value's trailing spaces */ 957 while (vf < vl && *vl == SPACETOK) 958 *vl-- = '\0'; 959 960 /* move value up if necessary */ 961 if (vf != tl + 1) 962 (void) strcpy(tl + 1, vf); 963 964 return (tf); 965 } 966 967 static 968 ns_ldap_cookie_t * 969 init_search_state_machine() 970 { 971 ns_ldap_cookie_t *cookie; 972 ns_config_t *cfg; 973 974 cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t)); 975 if (cookie == NULL) 976 return (NULL); 977 cookie->state = INIT; 978 /* assign other state variables */ 979 cfg = __s_api_loadrefresh_config(); 980 cookie->connectionId = -1; 981 if (cfg == NULL || 982 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) { 983 cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT; 984 } else { 985 cookie->search_timeout.tv_sec = 986 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i; 987 } 988 if (cfg != NULL) 989 __s_api_release_config(cfg); 990 cookie->search_timeout.tv_usec = 0; 991 992 return (cookie); 993 } 994 995 static void 996 delete_search_cookie(ns_ldap_cookie_t *cookie) 997 { 998 if (cookie == NULL) 999 return; 1000 if (cookie->connectionId > -1) 1001 DropConnection(cookie->connectionId, cookie->i_flags); 1002 if (cookie->filter) 1003 free(cookie->filter); 1004 if (cookie->i_filter) 1005 free(cookie->i_filter); 1006 if (cookie->service) 1007 free(cookie->service); 1008 if (cookie->sdlist) 1009 (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist)); 1010 if (cookie->result) 1011 (void) __ns_ldap_freeResult(&cookie->result); 1012 if (cookie->attribute) 1013 __s_api_free2dArray(cookie->attribute); 1014 if (cookie->errorp) 1015 (void) __ns_ldap_freeError(&cookie->errorp); 1016 if (cookie->reflist) 1017 __s_api_deleteRefInfo(cookie->reflist); 1018 if (cookie->basedn) 1019 free(cookie->basedn); 1020 if (cookie->ctrlCookie) 1021 ber_bvfree(cookie->ctrlCookie); 1022 _freeControlList(&cookie->p_serverctrls); 1023 free(cookie); 1024 } 1025 1026 static int 1027 get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter) 1028 { 1029 1030 typedef struct filter_mapping_info { 1031 char oc_or_attr; 1032 char *name_start; 1033 char *name_end; 1034 char *veq_pos; 1035 char *from_name; 1036 char *to_name; 1037 char **mapping; 1038 } filter_mapping_info_t; 1039 1040 char *c, *last_copied; 1041 char *filter_c, *filter_c_next; 1042 char *key, *tail, *head; 1043 char errstr[MAXERROR]; 1044 int num_eq = 0, num_veq = 0; 1045 int in_quote = FALSE; 1046 int i, j, oc_len, len; 1047 int at_least_one = FALSE; 1048 filter_mapping_info_t **info, *info1; 1049 char **mapping; 1050 char *service, *filter, *err; 1051 int auto_service = FALSE; 1052 1053 if (cookie == NULL || new_filter == NULL) 1054 return (NS_LDAP_INVALID_PARAM); 1055 1056 *new_filter = NULL; 1057 service = cookie->service; 1058 filter = cookie->filter; 1059 1060 /* 1061 * count the number of '=' char 1062 */ 1063 for (c = filter; *c; c++) { 1064 if (*c == TOKENSEPARATOR) 1065 num_eq++; 1066 } 1067 1068 if (service != NULL && strncasecmp(service, "auto_", 5) == 0) 1069 auto_service = TRUE; 1070 1071 /* 1072 * See if schema mapping existed for the given service. 1073 * If not, just return success. 1074 */ 1075 mapping = __ns_ldap_getOrigAttribute(service, 1076 NS_HASH_SCHEMA_MAPPING_EXISTED); 1077 1078 if (mapping == NULL && auto_service) 1079 /* 1080 * if service == auto_* and no 1081 * schema mapping found 1082 * then try automount 1083 */ 1084 mapping = __ns_ldap_getOrigAttribute( 1085 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED); 1086 1087 if (mapping) 1088 __s_api_free2dArray(mapping); 1089 else 1090 return (NS_LDAP_SUCCESS); 1091 1092 /* 1093 * no '=' sign, just say OK and return nothing 1094 */ 1095 if (num_eq == 0) 1096 return (NS_LDAP_SUCCESS); 1097 1098 /* 1099 * Make a copy of the filter string 1100 * for saving the name of the objectclasses or 1101 * attributes that need to be passed to the 1102 * objectclass or attribute mapping functions. 1103 * pointer "info->from_name" points to the locations 1104 * within this string. 1105 * 1106 * The input filter string, filter, will be used 1107 * to indicate where these names start and end. 1108 * pointers "info->name_start" and "info->name_end" 1109 * point to locations within the input filter string, 1110 * and are used at the end of this function to 1111 * merge the original filter data with the 1112 * mapped objectclass or attribute names. 1113 */ 1114 filter_c = strdup(filter); 1115 if (filter_c == NULL) 1116 return (NS_LDAP_MEMORY); 1117 filter_c_next = filter_c; 1118 1119 /* 1120 * get memory for info arrays 1121 */ 1122 info = (filter_mapping_info_t **)calloc(num_eq + 1, 1123 sizeof (filter_mapping_info_t *)); 1124 1125 if (info == NULL) { 1126 free(filter_c); 1127 return (NS_LDAP_MEMORY); 1128 } 1129 1130 /* 1131 * find valid '=' for further processing, 1132 * ignore the "escaped =" (.i.e. "\="), or 1133 * "=" in quoted string 1134 */ 1135 for (c = filter_c; *c; c++) { 1136 1137 switch (*c) { 1138 case TOKENSEPARATOR: 1139 if (!in_quote) { 1140 info1 = (filter_mapping_info_t *)calloc(1, 1141 sizeof (filter_mapping_info_t)); 1142 if (!info1) { 1143 free(filter_c); 1144 for (i = 0; i < num_veq; i++) 1145 free(info[i]); 1146 free(info); 1147 return (NS_LDAP_MEMORY); 1148 } 1149 info[num_veq] = info1; 1150 1151 /* 1152 * remember the location of this "=" 1153 */ 1154 info[num_veq++]->veq_pos = c; 1155 } 1156 break; 1157 case QUOTETOK: 1158 /* 1159 * switch on/off the in_quote mode 1160 */ 1161 in_quote = (in_quote == FALSE); 1162 break; 1163 case '\\': 1164 /* 1165 * ignore escape characters 1166 * don't skip if next char is '\0' 1167 */ 1168 if (!in_quote) 1169 if (*(++c) == '\0') 1170 c--; 1171 break; 1172 } 1173 1174 } 1175 1176 /* 1177 * for each valid "=" found, get the name to 1178 * be mapped 1179 */ 1180 oc_len = strlen("objectclass"); 1181 for (i = 0; i < num_veq; i++) { 1182 1183 /* 1184 * look at the left side of "=" to see 1185 * if assertion is "objectclass=<ocname>" 1186 * or "<attribute name>=<attribute value>" 1187 * 1188 * first skip spaces before "=". 1189 * Note that filter_c_next may not point to the 1190 * start of the filter string. For i > 0, 1191 * it points to the end of the last name processed + 2 1192 */ 1193 for (tail = info[i]->veq_pos; (tail > filter_c_next) && 1194 (*(tail - 1) == SPACETOK); tail--); 1195 1196 /* 1197 * mark the end of the left side string (the key) 1198 */ 1199 *tail = '\0'; 1200 info[i]->name_end = tail - filter_c - 1 + filter; 1201 1202 /* 1203 * find the start of the key 1204 */ 1205 key = filter_c_next; 1206 for (c = tail; filter_c_next <= c; c--) { 1207 /* OPARATOK is '(' */ 1208 if (*c == OPARATOK || 1209 *c == SPACETOK) { 1210 key = c + 1; 1211 break; 1212 } 1213 } 1214 info[i]->name_start = key - filter_c + filter; 1215 1216 if ((key + oc_len) <= tail) { 1217 if (strncasecmp(key, "objectclass", 1218 oc_len) == 0) { 1219 /* 1220 * assertion is "objectclass=ocname", 1221 * ocname is the one needs to be mapped 1222 * 1223 * skip spaces after "=" to find start 1224 * of the ocname 1225 */ 1226 head = info[i]->veq_pos; 1227 for (head = info[i]->veq_pos + 1; 1228 *head && *head == SPACETOK; head++); 1229 1230 /* ignore empty ocname */ 1231 if (!(*head)) 1232 continue; 1233 1234 info[i]->name_start = head - filter_c + 1235 filter; 1236 1237 /* 1238 * now find the end of the ocname 1239 */ 1240 for (c = head; ; c++) { 1241 /* CPARATOK is ')' */ 1242 if (*c == CPARATOK || 1243 *c == '\0' || 1244 *c == SPACETOK) { 1245 *c = '\0'; 1246 info[i]->name_end = 1247 c - filter_c - 1 + 1248 filter; 1249 filter_c_next = c + 1; 1250 info[i]->oc_or_attr = 'o'; 1251 info[i]->from_name = head; 1252 break; 1253 } 1254 } 1255 } 1256 } 1257 1258 /* 1259 * assertion is not "objectclass=ocname", 1260 * assume assertion is "<key> = <value>", 1261 * <key> is the one needs to be mapped 1262 */ 1263 if (info[i]->from_name == NULL && strlen(key) > 0) { 1264 info[i]->oc_or_attr = 'a'; 1265 info[i]->from_name = key; 1266 } 1267 } 1268 1269 /* perform schema mapping */ 1270 for (i = 0; i < num_veq; i++) { 1271 if (info[i]->from_name == NULL) 1272 continue; 1273 1274 if (info[i]->oc_or_attr == 'a') 1275 info[i]->mapping = 1276 __ns_ldap_getMappedAttributes(service, 1277 info[i]->from_name); 1278 else 1279 info[i]->mapping = 1280 __ns_ldap_getMappedObjectClass(service, 1281 info[i]->from_name); 1282 1283 if (info[i]->mapping == NULL && auto_service) { 1284 /* 1285 * If no mapped attribute/objectclass is found 1286 * and service == auto* 1287 * try to find automount's 1288 * mapped attribute/objectclass 1289 */ 1290 if (info[i]->oc_or_attr == 'a') 1291 info[i]->mapping = 1292 __ns_ldap_getMappedAttributes("automount", 1293 info[i]->from_name); 1294 else 1295 info[i]->mapping = 1296 __ns_ldap_getMappedObjectClass("automount", 1297 info[i]->from_name); 1298 } 1299 1300 if (info[i]->mapping == NULL || 1301 info[i]->mapping[0] == NULL) { 1302 info[i]->to_name = NULL; 1303 } else if (info[i]->mapping[1] == NULL) { 1304 info[i]->to_name = info[i]->mapping[0]; 1305 at_least_one = TRUE; 1306 } else { 1307 __s_api_free2dArray(info[i]->mapping); 1308 /* 1309 * multiple mapping 1310 * not allowed 1311 */ 1312 (void) sprintf(errstr, 1313 gettext( 1314 "Multiple attribute or objectclass " 1315 "mapping for '%s' in filter " 1316 "'%s' not allowed."), 1317 info[i]->from_name, filter); 1318 err = strdup(errstr); 1319 if (err) 1320 MKERROR(LOG_WARNING, cookie->errorp, 1321 NS_CONFIG_SYNTAX, 1322 err, NULL); 1323 1324 free(filter_c); 1325 for (j = 0; j < num_veq; j++) { 1326 if (info[j]->mapping) 1327 __s_api_free2dArray( 1328 info[j]->mapping); 1329 free(info[j]); 1330 } 1331 free(info); 1332 return (NS_LDAP_CONFIG); 1333 } 1334 } 1335 1336 1337 if (at_least_one) { 1338 1339 len = strlen(filter); 1340 last_copied = filter - 1; 1341 1342 for (i = 0; i < num_veq; i++) { 1343 if (info[i]->to_name) 1344 len += strlen(info[i]->to_name); 1345 } 1346 1347 *new_filter = (char *)calloc(1, len); 1348 if (*new_filter == NULL) { 1349 free(filter_c); 1350 for (j = 0; j < num_veq; j++) { 1351 if (info[j]->mapping) 1352 __s_api_free2dArray( 1353 info[j]->mapping); 1354 free(info[j]); 1355 } 1356 free(info); 1357 return (NS_LDAP_MEMORY); 1358 } 1359 1360 for (i = 0; i < num_veq; i++) { 1361 if (info[i]->to_name != NULL && 1362 info[i]->to_name != NULL) { 1363 1364 /* 1365 * copy the original filter data 1366 * between the last name and current 1367 * name 1368 */ 1369 if ((last_copied + 1) != info[i]->name_start) 1370 (void) strncat(*new_filter, last_copied + 1, 1371 info[i]->name_start - 1372 last_copied - 1); 1373 1374 /* the data is copied */ 1375 last_copied = info[i]->name_end; 1376 1377 /* 1378 * replace the name with 1379 * the mapped name 1380 */ 1381 (void) strcat(*new_filter, info[i]->to_name); 1382 } 1383 1384 /* copy the filter data after the last name */ 1385 if (i == (num_veq -1) && 1386 info[i]->name_end < 1387 (filter + strlen(filter))) 1388 (void) strncat(*new_filter, last_copied + 1, 1389 filter + strlen(filter) - 1390 last_copied - 1); 1391 } 1392 1393 } 1394 1395 /* free memory */ 1396 free(filter_c); 1397 for (j = 0; j < num_veq; j++) { 1398 if (info[j]->mapping) 1399 __s_api_free2dArray(info[j]->mapping); 1400 free(info[j]); 1401 } 1402 free(info); 1403 1404 return (NS_LDAP_SUCCESS); 1405 } 1406 1407 static int 1408 setup_next_search(ns_ldap_cookie_t *cookie) 1409 { 1410 ns_ldap_search_desc_t *dptr; 1411 int scope; 1412 char *filter, *str; 1413 int baselen; 1414 int rc; 1415 void **param; 1416 1417 dptr = *cookie->sdpos; 1418 scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE | 1419 NS_LDAP_SCOPE_ONELEVEL | 1420 NS_LDAP_SCOPE_SUBTREE); 1421 if (scope) 1422 cookie->scope = scope; 1423 else 1424 cookie->scope = dptr->scope; 1425 switch (cookie->scope) { 1426 case NS_LDAP_SCOPE_BASE: 1427 cookie->scope = LDAP_SCOPE_BASE; 1428 break; 1429 case NS_LDAP_SCOPE_ONELEVEL: 1430 cookie->scope = LDAP_SCOPE_ONELEVEL; 1431 break; 1432 case NS_LDAP_SCOPE_SUBTREE: 1433 cookie->scope = LDAP_SCOPE_SUBTREE; 1434 break; 1435 } 1436 1437 filter = NULL; 1438 if (cookie->use_filtercb && cookie->init_filter_cb && 1439 dptr->filter && strlen(dptr->filter) > 0) { 1440 (*cookie->init_filter_cb)(dptr, &filter, 1441 cookie->userdata); 1442 } 1443 if (filter == NULL) { 1444 if (cookie->i_filter == NULL) { 1445 cookie->err_rc = NS_LDAP_INVALID_PARAM; 1446 return (-1); 1447 } else { 1448 cookie->filter = strdup(cookie->i_filter); 1449 if (cookie->filter == NULL) { 1450 cookie->err_rc = NS_LDAP_MEMORY; 1451 return (-1); 1452 } 1453 } 1454 } else { 1455 cookie->filter = strdup(filter); 1456 free(filter); 1457 if (cookie->filter == NULL) { 1458 cookie->err_rc = NS_LDAP_MEMORY; 1459 return (-1); 1460 } 1461 } 1462 1463 /* 1464 * perform attribute/objectclass mapping on filter 1465 */ 1466 filter = NULL; 1467 1468 if (cookie->service) { 1469 rc = get_mapped_filter(cookie, &filter); 1470 if (rc != NS_LDAP_SUCCESS) { 1471 cookie->err_rc = rc; 1472 return (-1); 1473 } else { 1474 /* 1475 * get_mapped_filter returns 1476 * NULL filter pointer, if 1477 * no mapping was done 1478 */ 1479 if (filter) { 1480 free(cookie->filter); 1481 cookie->filter = filter; 1482 } 1483 } 1484 } 1485 1486 /* 1487 * validate filter to make sure it's legal 1488 * [remove redundant ()'s] 1489 */ 1490 rc = validate_filter(cookie); 1491 if (rc != NS_LDAP_SUCCESS) { 1492 cookie->err_rc = rc; 1493 return (-1); 1494 } 1495 1496 baselen = strlen(dptr->basedn); 1497 if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) { 1498 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P, 1499 (void ***)¶m, &cookie->errorp); 1500 if (rc != NS_LDAP_SUCCESS) { 1501 cookie->err_rc = rc; 1502 return (-1); 1503 } 1504 str = ((char **)param)[0]; 1505 baselen += strlen(str)+1; 1506 cookie->basedn = (char *)malloc(baselen); 1507 if (cookie->basedn == NULL) { 1508 cookie->err_rc = NS_LDAP_MEMORY; 1509 return (-1); 1510 } 1511 (void) strcpy(cookie->basedn, dptr->basedn); 1512 (void) strcat(cookie->basedn, str); 1513 (void) __ns_ldap_freeParam(¶m); 1514 } else { 1515 cookie->basedn = strdup(dptr->basedn); 1516 } 1517 return (0); 1518 } 1519 1520 static int 1521 setup_referral_search(ns_ldap_cookie_t *cookie) 1522 { 1523 ns_referral_info_t *ref; 1524 1525 ref = cookie->refpos; 1526 cookie->scope = ref->refScope; 1527 if (cookie->filter) { 1528 free(cookie->filter); 1529 } 1530 cookie->filter = strdup(ref->refFilter); 1531 if (cookie->basedn) { 1532 free(cookie->basedn); 1533 } 1534 cookie->basedn = strdup(ref->refDN); 1535 if (cookie->filter == NULL || cookie->basedn == NULL) { 1536 cookie->err_rc = NS_LDAP_MEMORY; 1537 return (-1); 1538 } 1539 return (0); 1540 } 1541 1542 static int 1543 get_current_session(ns_ldap_cookie_t *cookie) 1544 { 1545 ConnectionID connectionId = -1; 1546 Connection *conp = NULL; 1547 int rc; 1548 int fail_if_new_pwd_reqd = 1; 1549 1550 rc = __s_api_getConnection(NULL, cookie->i_flags, 1551 cookie->i_auth, &connectionId, &conp, 1552 &cookie->errorp, fail_if_new_pwd_reqd); 1553 1554 /* 1555 * If password control attached in *cookie->errorp, 1556 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1557 * free the error structure (we do not need 1558 * the sec_to_expired info). 1559 * Reset rc to NS_LDAP_SUCCESS. 1560 */ 1561 if (rc == NS_LDAP_SUCCESS_WITH_INFO) { 1562 (void) __ns_ldap_freeError( 1563 &cookie->errorp); 1564 cookie->errorp = NULL; 1565 rc = NS_LDAP_SUCCESS; 1566 } 1567 1568 if (rc != NS_LDAP_SUCCESS) { 1569 cookie->err_rc = rc; 1570 return (-1); 1571 } 1572 cookie->conn = conp; 1573 cookie->connectionId = connectionId; 1574 1575 return (0); 1576 } 1577 1578 static int 1579 get_next_session(ns_ldap_cookie_t *cookie) 1580 { 1581 ConnectionID connectionId = -1; 1582 Connection *conp = NULL; 1583 int rc; 1584 int fail_if_new_pwd_reqd = 1; 1585 1586 if (cookie->connectionId > -1) 1587 DropConnection(cookie->connectionId, cookie->i_flags); 1588 1589 rc = __s_api_getConnection(NULL, cookie->i_flags, 1590 cookie->i_auth, &connectionId, &conp, 1591 &cookie->errorp, fail_if_new_pwd_reqd); 1592 1593 /* 1594 * If password control attached in *cookie->errorp, 1595 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1596 * free the error structure (we do not need 1597 * the sec_to_expired info). 1598 * Reset rc to NS_LDAP_SUCCESS. 1599 */ 1600 if (rc == NS_LDAP_SUCCESS_WITH_INFO) { 1601 (void) __ns_ldap_freeError( 1602 &cookie->errorp); 1603 cookie->errorp = NULL; 1604 rc = NS_LDAP_SUCCESS; 1605 } 1606 1607 if (rc != NS_LDAP_SUCCESS) { 1608 cookie->err_rc = rc; 1609 return (-1); 1610 } 1611 cookie->conn = conp; 1612 cookie->connectionId = connectionId; 1613 return (0); 1614 } 1615 1616 static int 1617 get_referral_session(ns_ldap_cookie_t *cookie) 1618 { 1619 ConnectionID connectionId = -1; 1620 Connection *conp = NULL; 1621 int rc; 1622 int fail_if_new_pwd_reqd = 1; 1623 1624 if (cookie->connectionId > -1) 1625 DropConnection(cookie->connectionId, cookie->i_flags); 1626 1627 rc = __s_api_getConnection(cookie->refpos->refHost, 0, 1628 cookie->i_auth, &connectionId, &conp, 1629 &cookie->errorp, fail_if_new_pwd_reqd); 1630 1631 /* 1632 * If password control attached in *cookie->errorp, 1633 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO, 1634 * free the error structure (we do not need 1635 * the sec_to_expired info). 1636 * Reset rc to NS_LDAP_SUCCESS. 1637 */ 1638 if (rc == NS_LDAP_SUCCESS_WITH_INFO) { 1639 (void) __ns_ldap_freeError( 1640 &cookie->errorp); 1641 cookie->errorp = NULL; 1642 rc = NS_LDAP_SUCCESS; 1643 } 1644 1645 if (rc != NS_LDAP_SUCCESS) { 1646 cookie->err_rc = rc; 1647 return (-1); 1648 } 1649 cookie->conn = conp; 1650 cookie->connectionId = connectionId; 1651 return (0); 1652 } 1653 1654 static int 1655 paging_supported(ns_ldap_cookie_t *cookie) 1656 { 1657 int rc; 1658 1659 cookie->listType = 0; 1660 rc = __s_api_isCtrlSupported(cookie->conn, 1661 LDAP_CONTROL_VLVREQUEST); 1662 if (rc == NS_LDAP_SUCCESS) { 1663 cookie->listType = VLVCTRLFLAG; 1664 return (1); 1665 } 1666 rc = __s_api_isCtrlSupported(cookie->conn, 1667 LDAP_CONTROL_SIMPLE_PAGE); 1668 if (rc == NS_LDAP_SUCCESS) { 1669 cookie->listType = SIMPLEPAGECTRLFLAG; 1670 return (1); 1671 } 1672 return (0); 1673 } 1674 1675 static int 1676 setup_vlv_params(ns_ldap_cookie_t *cookie) 1677 { 1678 LDAPControl **ctrls; 1679 LDAPsortkey **sortkeylist; 1680 LDAPControl *sortctrl = NULL; 1681 LDAPControl *vlvctrl = NULL; 1682 LDAPVirtualList vlist; 1683 int rc; 1684 1685 _freeControlList(&cookie->p_serverctrls); 1686 1687 rc = ldap_create_sort_keylist(&sortkeylist, SORTKEYLIST); 1688 if (rc != LDAP_SUCCESS) { 1689 (void) ldap_get_option(cookie->conn->ld, 1690 LDAP_OPT_ERROR_NUMBER, &rc); 1691 return (rc); 1692 } 1693 rc = ldap_create_sort_control(cookie->conn->ld, 1694 sortkeylist, 1, &sortctrl); 1695 ldap_free_sort_keylist(sortkeylist); 1696 if (rc != LDAP_SUCCESS) { 1697 (void) ldap_get_option(cookie->conn->ld, 1698 LDAP_OPT_ERROR_NUMBER, &rc); 1699 return (rc); 1700 } 1701 1702 vlist.ldvlist_index = cookie->index; 1703 vlist.ldvlist_size = 0; 1704 1705 vlist.ldvlist_before_count = 0; 1706 vlist.ldvlist_after_count = LISTPAGESIZE-1; 1707 vlist.ldvlist_attrvalue = NULL; 1708 vlist.ldvlist_extradata = NULL; 1709 1710 rc = ldap_create_virtuallist_control(cookie->conn->ld, 1711 &vlist, &vlvctrl); 1712 if (rc != LDAP_SUCCESS) { 1713 ldap_control_free(sortctrl); 1714 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER, 1715 &rc); 1716 return (rc); 1717 } 1718 1719 ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *)); 1720 if (ctrls == NULL) { 1721 ldap_control_free(sortctrl); 1722 ldap_control_free(vlvctrl); 1723 return (LDAP_NO_MEMORY); 1724 } 1725 1726 ctrls[0] = sortctrl; 1727 ctrls[1] = vlvctrl; 1728 1729 cookie->p_serverctrls = ctrls; 1730 return (LDAP_SUCCESS); 1731 } 1732 1733 static int 1734 setup_simplepg_params(ns_ldap_cookie_t *cookie) 1735 { 1736 LDAPControl **ctrls; 1737 LDAPControl *pgctrl = NULL; 1738 int rc; 1739 1740 _freeControlList(&cookie->p_serverctrls); 1741 1742 rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE, 1743 cookie->ctrlCookie, (char)0, &pgctrl); 1744 if (rc != LDAP_SUCCESS) { 1745 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER, 1746 &rc); 1747 return (rc); 1748 } 1749 1750 ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *)); 1751 if (ctrls == NULL) { 1752 ldap_control_free(pgctrl); 1753 return (LDAP_NO_MEMORY); 1754 } 1755 ctrls[0] = pgctrl; 1756 cookie->p_serverctrls = ctrls; 1757 return (LDAP_SUCCESS); 1758 } 1759 1760 static void 1761 proc_result_referrals(ns_ldap_cookie_t *cookie) 1762 { 1763 int errCode, i, rc; 1764 char **referrals = NULL; 1765 1766 /* 1767 * Only follow one level of referrals, i.e. 1768 * if already in referral mode, do nothing 1769 */ 1770 if (cookie->refpos == NULL) { 1771 cookie->new_state = END_RESULT; 1772 rc = ldap_parse_result(cookie->conn->ld, 1773 cookie->resultMsg, 1774 &errCode, NULL, 1775 NULL, &referrals, 1776 NULL, 0); 1777 if (rc != NS_LDAP_SUCCESS) { 1778 (void) ldap_get_option(cookie->conn->ld, 1779 LDAP_OPT_ERROR_NUMBER, 1780 &cookie->err_rc); 1781 cookie->new_state = LDAP_ERROR; 1782 return; 1783 } 1784 if (errCode == LDAP_REFERRAL) { 1785 for (i = 0; referrals[i] != NULL; 1786 i++) { 1787 /* add to referral list */ 1788 rc = __s_api_addRefInfo( 1789 &cookie->reflist, 1790 referrals[i], 1791 cookie->basedn, 1792 &cookie->scope, 1793 cookie->filter, 1794 cookie->conn->ld); 1795 if (rc != NS_LDAP_SUCCESS) { 1796 cookie->new_state = 1797 ERROR; 1798 break; 1799 } 1800 } 1801 ldap_value_free(referrals); 1802 } 1803 } 1804 } 1805 1806 static void 1807 proc_search_references(ns_ldap_cookie_t *cookie) 1808 { 1809 char **refurls = NULL; 1810 int i, rc; 1811 1812 /* 1813 * Only follow one level of referrals, i.e. 1814 * if already in referral mode, do nothing 1815 */ 1816 if (cookie->refpos == NULL) { 1817 refurls = ldap_get_reference_urls( 1818 cookie->conn->ld, 1819 cookie->resultMsg); 1820 if (refurls == NULL) { 1821 (void) ldap_get_option(cookie->conn->ld, 1822 LDAP_OPT_ERROR_NUMBER, 1823 &cookie->err_rc); 1824 cookie->new_state = LDAP_ERROR; 1825 return; 1826 } 1827 for (i = 0; refurls[i] != NULL; i++) { 1828 /* add to referral list */ 1829 rc = __s_api_addRefInfo( 1830 &cookie->reflist, 1831 refurls[i], 1832 cookie->basedn, 1833 &cookie->scope, 1834 cookie->filter, 1835 cookie->conn->ld); 1836 if (rc != NS_LDAP_SUCCESS) { 1837 cookie->new_state = 1838 ERROR; 1839 break; 1840 } 1841 } 1842 /* free allocated storage */ 1843 for (i = 0; refurls[i] != NULL; i++) 1844 free(refurls[i]); 1845 } 1846 } 1847 1848 static ns_state_t 1849 multi_result(ns_ldap_cookie_t *cookie) 1850 { 1851 char errstr[MAXERROR]; 1852 char *err; 1853 ns_ldap_error_t **errorp = NULL; 1854 LDAPControl **retCtrls = NULL; 1855 int i, rc; 1856 int errCode; 1857 int finished = 0; 1858 unsigned long target_posp = 0; 1859 unsigned long list_size = 0; 1860 unsigned int count = 0; 1861 char **referrals = NULL; 1862 1863 if (cookie->listType == VLVCTRLFLAG) { 1864 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg, 1865 &errCode, NULL, NULL, &referrals, &retCtrls, 0); 1866 if (rc != LDAP_SUCCESS) { 1867 (void) ldap_get_option(cookie->conn->ld, 1868 LDAP_OPT_ERROR_NUMBER, 1869 &cookie->err_rc); 1870 (void) sprintf(errstr, 1871 gettext("LDAP ERROR (%d): %s.\n"), 1872 cookie->err_rc, 1873 gettext(ldap_err2string(cookie->err_rc))); 1874 err = strdup(errstr); 1875 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, 1876 NULL); 1877 cookie->err_rc = NS_LDAP_INTERNAL; 1878 cookie->errorp = *errorp; 1879 return (LDAP_ERROR); 1880 } 1881 if (errCode == LDAP_REFERRAL) { 1882 for (i = 0; referrals[i] != NULL; 1883 i++) { 1884 /* add to referral list */ 1885 rc = __s_api_addRefInfo( 1886 &cookie->reflist, 1887 referrals[i], 1888 cookie->basedn, 1889 &cookie->scope, 1890 cookie->filter, 1891 cookie->conn->ld); 1892 if (rc != NS_LDAP_SUCCESS) { 1893 ldap_value_free( 1894 referrals); 1895 if (retCtrls) 1896 ldap_controls_free( 1897 retCtrls); 1898 return (ERROR); 1899 } 1900 } 1901 ldap_value_free(referrals); 1902 if (retCtrls) 1903 ldap_controls_free(retCtrls); 1904 return (END_RESULT); 1905 } 1906 if (retCtrls) { 1907 rc = ldap_parse_virtuallist_control( 1908 cookie->conn->ld, retCtrls, 1909 &target_posp, &list_size, &errCode); 1910 if (rc == LDAP_SUCCESS) { 1911 cookie->index = target_posp + LISTPAGESIZE; 1912 if (cookie->index >= list_size) { 1913 finished = 1; 1914 } 1915 } 1916 ldap_controls_free(retCtrls); 1917 retCtrls = NULL; 1918 } 1919 else 1920 finished = 1; 1921 } else if (cookie->listType == SIMPLEPAGECTRLFLAG) { 1922 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg, 1923 &errCode, NULL, NULL, &referrals, &retCtrls, 0); 1924 if (rc != LDAP_SUCCESS) { 1925 (void) ldap_get_option(cookie->conn->ld, 1926 LDAP_OPT_ERROR_NUMBER, 1927 &cookie->err_rc); 1928 (void) sprintf(errstr, 1929 gettext("LDAP ERROR (%d): %s.\n"), 1930 cookie->err_rc, 1931 gettext(ldap_err2string(cookie->err_rc))); 1932 err = strdup(errstr); 1933 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, 1934 NULL); 1935 cookie->err_rc = NS_LDAP_INTERNAL; 1936 cookie->errorp = *errorp; 1937 return (LDAP_ERROR); 1938 } 1939 if (errCode == LDAP_REFERRAL) { 1940 for (i = 0; referrals[i] != NULL; 1941 i++) { 1942 /* add to referral list */ 1943 rc = __s_api_addRefInfo( 1944 &cookie->reflist, 1945 referrals[i], 1946 cookie->basedn, 1947 &cookie->scope, 1948 cookie->filter, 1949 cookie->conn->ld); 1950 if (rc != NS_LDAP_SUCCESS) { 1951 ldap_value_free( 1952 referrals); 1953 if (retCtrls) 1954 ldap_controls_free( 1955 retCtrls); 1956 return (ERROR); 1957 } 1958 } 1959 ldap_value_free(referrals); 1960 if (retCtrls) 1961 ldap_controls_free(retCtrls); 1962 return (END_RESULT); 1963 } 1964 if (retCtrls) { 1965 if (cookie->ctrlCookie) 1966 ber_bvfree(cookie->ctrlCookie); 1967 cookie->ctrlCookie = NULL; 1968 rc = ldap_parse_page_control( 1969 cookie->conn->ld, retCtrls, 1970 &count, &cookie->ctrlCookie); 1971 if (rc == LDAP_SUCCESS) { 1972 if ((cookie->ctrlCookie == NULL) || 1973 (cookie->ctrlCookie->bv_val == NULL) || 1974 (*cookie->ctrlCookie->bv_val == NULL)) 1975 finished = 1; 1976 } 1977 ldap_controls_free(retCtrls); 1978 retCtrls = NULL; 1979 } 1980 else 1981 finished = 1; 1982 } 1983 if (!finished && cookie->listType == VLVCTRLFLAG) 1984 return (NEXT_VLV); 1985 if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG) 1986 return (NEXT_PAGE); 1987 if (finished) 1988 return (END_RESULT); 1989 return (ERROR); 1990 } 1991 1992 /* 1993 * This state machine performs one or more LDAP searches to a given 1994 * directory server using service search descriptors and schema 1995 * mapping as appropriate. The approximate pseudocode for 1996 * this routine is the following: 1997 * Given the current configuration [set/reset connection etc.] 1998 * and the current service search descriptor list 1999 * or default search filter parameters 2000 * foreach (service search filter) { 2001 * initialize the filter [via filter_init if appropriate] 2002 * get a valid session/connection (preferably the current one) 2003 * Recover if the connection is lost 2004 * perform the search 2005 * foreach (result entry) { 2006 * process result [via callback if appropriate] 2007 * save result for caller if accepted. 2008 * exit and return all collected if allResults found; 2009 * } 2010 * } 2011 * return collected results and exit 2012 */ 2013 2014 static 2015 ns_state_t 2016 search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle) 2017 { 2018 char errstr[MAXERROR]; 2019 char *err; 2020 int rc, ret; 2021 ns_ldap_entry_t *nextEntry; 2022 ns_ldap_error_t *error = NULL; 2023 ns_ldap_error_t **errorp; 2024 2025 errorp = &error; 2026 cookie->err_rc = 0; 2027 cookie->state = state; 2028 2029 for (;;) { 2030 switch (cookie->state) { 2031 case EXIT: 2032 /* state engine/connection cleaned up in delete */ 2033 if (cookie->attribute) { 2034 __s_api_free2dArray(cookie->attribute); 2035 cookie->attribute = NULL; 2036 } 2037 if (cookie->reflist) { 2038 __s_api_deleteRefInfo(cookie->reflist); 2039 cookie->reflist = NULL; 2040 } 2041 return (EXIT); 2042 case INIT: 2043 cookie->sdpos = NULL; 2044 cookie->new_state = NEXT_SEARCH_DESCRIPTOR; 2045 if (cookie->attribute) { 2046 __s_api_free2dArray(cookie->attribute); 2047 cookie->attribute = NULL; 2048 } 2049 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 && 2050 cookie->i_attr) { 2051 cookie->attribute = 2052 __ns_ldap_mapAttributeList( 2053 cookie->service, 2054 cookie->i_attr); 2055 } 2056 break; 2057 case NEXT_SEARCH_DESCRIPTOR: 2058 /* get next search descriptor */ 2059 if (cookie->sdpos == NULL) { 2060 cookie->sdpos = cookie->sdlist; 2061 cookie->new_state = GET_SESSION; 2062 } else { 2063 cookie->sdpos++; 2064 cookie->new_state = NEXT_SEARCH; 2065 } 2066 if (*cookie->sdpos == NULL) 2067 cookie->new_state = EXIT; 2068 break; 2069 case GET_SESSION: 2070 if (get_current_session(cookie) < 0) 2071 cookie->new_state = NEXT_SESSION; 2072 else 2073 cookie->new_state = NEXT_SEARCH; 2074 break; 2075 case NEXT_SESSION: 2076 if (get_next_session(cookie) < 0) 2077 cookie->new_state = RESTART_SESSION; 2078 else 2079 cookie->new_state = NEXT_SEARCH; 2080 break; 2081 case RESTART_SESSION: 2082 if (cookie->i_flags & NS_LDAP_HARD) { 2083 cookie->new_state = NEXT_SESSION; 2084 break; 2085 } 2086 (void) sprintf(errstr, 2087 gettext("Session error no available conn.\n"), 2088 state); 2089 err = strdup(errstr); 2090 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, 2091 NULL); 2092 cookie->err_rc = NS_LDAP_INTERNAL; 2093 cookie->errorp = *errorp; 2094 cookie->new_state = EXIT; 2095 break; 2096 case NEXT_SEARCH: 2097 /* setup referrals search if necessary */ 2098 if (cookie->refpos) { 2099 if (setup_referral_search(cookie) < 0) { 2100 cookie->new_state = EXIT; 2101 break; 2102 } 2103 } else if (setup_next_search(cookie) < 0) { 2104 cookie->new_state = EXIT; 2105 break; 2106 } 2107 /* only do VLV/PAGE on scopes onelevel/subtree */ 2108 if (paging_supported(cookie)) { 2109 if (cookie->use_paging && 2110 (cookie->scope != LDAP_SCOPE_BASE)) { 2111 cookie->index = 1; 2112 if (cookie->listType == VLVCTRLFLAG) 2113 cookie->new_state = NEXT_VLV; 2114 else 2115 cookie->new_state = NEXT_PAGE; 2116 break; 2117 } 2118 } 2119 cookie->new_state = ONE_SEARCH; 2120 break; 2121 case NEXT_VLV: 2122 rc = setup_vlv_params(cookie); 2123 if (rc != LDAP_SUCCESS) { 2124 cookie->err_rc = rc; 2125 cookie->new_state = LDAP_ERROR; 2126 break; 2127 } 2128 cookie->next_state = MULTI_RESULT; 2129 cookie->new_state = DO_SEARCH; 2130 break; 2131 case NEXT_PAGE: 2132 rc = setup_simplepg_params(cookie); 2133 if (rc != LDAP_SUCCESS) { 2134 cookie->err_rc = rc; 2135 cookie->new_state = LDAP_ERROR; 2136 break; 2137 } 2138 cookie->next_state = MULTI_RESULT; 2139 cookie->new_state = DO_SEARCH; 2140 break; 2141 case ONE_SEARCH: 2142 cookie->next_state = NEXT_RESULT; 2143 cookie->new_state = DO_SEARCH; 2144 break; 2145 case DO_SEARCH: 2146 rc = ldap_search_ext(cookie->conn->ld, 2147 cookie->basedn, 2148 cookie->scope, 2149 cookie->filter, 2150 cookie->attribute, 2151 0, 2152 cookie->p_serverctrls, 2153 NULL, 2154 &cookie->search_timeout, 0, 2155 &cookie->msgId); 2156 if (rc != LDAP_SUCCESS) { 2157 if (rc == LDAP_BUSY || 2158 rc == LDAP_UNAVAILABLE || 2159 rc == LDAP_UNWILLING_TO_PERFORM || 2160 rc == LDAP_CONNECT_ERROR || 2161 rc == LDAP_SERVER_DOWN) { 2162 2163 cookie->new_state = NEXT_SESSION; 2164 2165 /* 2166 * If not able to reach the 2167 * server, inform the ldap 2168 * cache manager that the 2169 * server should be removed 2170 * from it's server list. 2171 * Thus, the manager will not 2172 * return this server on the next 2173 * get-server request and will 2174 * also reduce the server list 2175 * refresh TTL, so that it will 2176 * find out sooner when the server 2177 * is up again. 2178 */ 2179 if (rc == LDAP_CONNECT_ERROR || 2180 rc == LDAP_SERVER_DOWN) { 2181 ret = __s_api_removeServer( 2182 cookie->conn->serverAddr); 2183 if (ret == NOSERVER && 2184 cookie->conn_auth_type 2185 == NS_LDAP_AUTH_NONE) { 2186 /* 2187 * Couldn't remove 2188 * server from server 2189 * list. 2190 * Exit to avoid 2191 * potential infinite 2192 * loop. 2193 */ 2194 cookie->err_rc = rc; 2195 cookie->new_state = 2196 LDAP_ERROR; 2197 } 2198 if (cookie->connectionId > -1) { 2199 DropConnection( 2200 cookie->connectionId, 2201 NS_LDAP_NEW_CONN); 2202 cookie->connectionId = -1; 2203 } 2204 } 2205 break; 2206 } 2207 cookie->err_rc = rc; 2208 cookie->new_state = LDAP_ERROR; 2209 break; 2210 } 2211 cookie->new_state = cookie->next_state; 2212 break; 2213 case NEXT_RESULT: 2214 rc = ldap_result(cookie->conn->ld, cookie->msgId, 2215 LDAP_MSG_ONE, 2216 (struct timeval *)&cookie->search_timeout, 2217 &cookie->resultMsg); 2218 if (rc == LDAP_RES_SEARCH_RESULT) { 2219 cookie->new_state = END_RESULT; 2220 /* check and process referrals info */ 2221 if (cookie->followRef) 2222 proc_result_referrals( 2223 cookie); 2224 (void) ldap_msgfree(cookie->resultMsg); 2225 cookie->resultMsg = NULL; 2226 break; 2227 } 2228 /* handle referrals if necessary */ 2229 if (rc == LDAP_RES_SEARCH_REFERENCE) { 2230 if (cookie->followRef) 2231 proc_search_references(cookie); 2232 (void) ldap_msgfree(cookie->resultMsg); 2233 cookie->resultMsg = NULL; 2234 break; 2235 } 2236 if (rc != LDAP_RES_SEARCH_ENTRY) { 2237 switch (rc) { 2238 case 0: 2239 rc = LDAP_TIMEOUT; 2240 break; 2241 case -1: 2242 rc = ldap_get_lderrno(cookie->conn->ld, 2243 NULL, NULL); 2244 break; 2245 default: 2246 rc = ldap_result2error(cookie->conn->ld, 2247 cookie->resultMsg, 1); 2248 break; 2249 } 2250 (void) ldap_msgfree(cookie->resultMsg); 2251 cookie->resultMsg = NULL; 2252 if (rc == LDAP_BUSY || 2253 rc == LDAP_UNAVAILABLE || 2254 rc == LDAP_UNWILLING_TO_PERFORM || 2255 rc == LDAP_SERVER_DOWN) { 2256 cookie->new_state = NEXT_SESSION; 2257 break; 2258 } 2259 cookie->err_rc = rc; 2260 cookie->new_state = LDAP_ERROR; 2261 break; 2262 } 2263 /* else LDAP_RES_SEARCH_ENTRY */ 2264 rc = __s_api_getEntry(cookie); 2265 (void) ldap_msgfree(cookie->resultMsg); 2266 cookie->resultMsg = NULL; 2267 if (rc != NS_LDAP_SUCCESS) { 2268 cookie->new_state = LDAP_ERROR; 2269 break; 2270 } 2271 cookie->new_state = PROCESS_RESULT; 2272 cookie->next_state = NEXT_RESULT; 2273 break; 2274 case MULTI_RESULT: 2275 rc = ldap_result(cookie->conn->ld, cookie->msgId, 2276 LDAP_MSG_ONE, 2277 (struct timeval *)&cookie->search_timeout, 2278 &cookie->resultMsg); 2279 if (rc == LDAP_RES_SEARCH_RESULT) { 2280 rc = ldap_result2error(cookie->conn->ld, 2281 cookie->resultMsg, 0); 2282 if (rc != LDAP_SUCCESS) { 2283 cookie->err_rc = rc; 2284 cookie->new_state = LDAP_ERROR; 2285 (void) ldap_msgfree(cookie->resultMsg); 2286 break; 2287 } 2288 cookie->new_state = multi_result(cookie); 2289 (void) ldap_msgfree(cookie->resultMsg); 2290 cookie->resultMsg = NULL; 2291 break; 2292 } 2293 /* handle referrals if necessary */ 2294 if (rc == LDAP_RES_SEARCH_REFERENCE && 2295 cookie->followRef) { 2296 proc_search_references(cookie); 2297 (void) ldap_msgfree(cookie->resultMsg); 2298 cookie->resultMsg = NULL; 2299 break; 2300 } 2301 if (rc != LDAP_RES_SEARCH_ENTRY) { 2302 switch (rc) { 2303 case 0: 2304 rc = LDAP_TIMEOUT; 2305 break; 2306 case -1: 2307 rc = ldap_get_lderrno(cookie->conn->ld, 2308 NULL, NULL); 2309 break; 2310 default: 2311 rc = ldap_result2error(cookie->conn->ld, 2312 cookie->resultMsg, 1); 2313 break; 2314 } 2315 (void) ldap_msgfree(cookie->resultMsg); 2316 cookie->resultMsg = NULL; 2317 if (rc == LDAP_BUSY || 2318 rc == LDAP_UNAVAILABLE || 2319 rc == LDAP_UNWILLING_TO_PERFORM || 2320 rc == LDAP_SERVER_DOWN) { 2321 cookie->new_state = NEXT_SESSION; 2322 break; 2323 } 2324 cookie->err_rc = rc; 2325 cookie->new_state = LDAP_ERROR; 2326 break; 2327 } 2328 /* else LDAP_RES_SEARCH_ENTRY */ 2329 rc = __s_api_getEntry(cookie); 2330 (void) ldap_msgfree(cookie->resultMsg); 2331 cookie->resultMsg = NULL; 2332 if (rc != NS_LDAP_SUCCESS) { 2333 cookie->new_state = LDAP_ERROR; 2334 break; 2335 } 2336 cookie->new_state = PROCESS_RESULT; 2337 cookie->next_state = MULTI_RESULT; 2338 break; 2339 case PROCESS_RESULT: 2340 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */ 2341 if (cookie->use_usercb && cookie->callback) { 2342 rc = 0; 2343 for (nextEntry = cookie->result->entry; 2344 nextEntry != NULL; 2345 nextEntry = nextEntry->next) { 2346 rc = (*cookie->callback)(nextEntry, 2347 cookie->userdata); 2348 2349 if (rc == NS_LDAP_CB_DONE) { 2350 /* cb doesn't want any more data */ 2351 rc = NS_LDAP_PARTIAL; 2352 cookie->err_rc = rc; 2353 break; 2354 } else if (rc != NS_LDAP_CB_NEXT) { 2355 /* invalid return code */ 2356 rc = NS_LDAP_OP_FAILED; 2357 cookie->err_rc = rc; 2358 break; 2359 } 2360 } 2361 (void) __ns_ldap_freeResult(&cookie->result); 2362 cookie->result = NULL; 2363 } 2364 if (rc != 0) { 2365 cookie->new_state = EXIT; 2366 break; 2367 } 2368 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */ 2369 cookie->new_state = cookie->next_state; 2370 break; 2371 case END_PROCESS_RESULT: 2372 cookie->new_state = cookie->next_state; 2373 break; 2374 case END_RESULT: 2375 /* 2376 * XXX DO WE NEED THIS CASE? 2377 * if (search is complete) { 2378 * cookie->new_state = EXIT; 2379 * } else 2380 */ 2381 /* 2382 * entering referral mode if necessary 2383 */ 2384 if (cookie->followRef && cookie->reflist) 2385 cookie->new_state = 2386 NEXT_REFERRAL; 2387 else 2388 cookie->new_state = 2389 NEXT_SEARCH_DESCRIPTOR; 2390 break; 2391 case NEXT_REFERRAL: 2392 /* get next referral info */ 2393 if (cookie->refpos == NULL) 2394 cookie->refpos = 2395 cookie->reflist; 2396 else 2397 cookie->refpos = 2398 cookie->refpos->next; 2399 /* check see if done with all referrals */ 2400 if (cookie->refpos != NULL) 2401 cookie->new_state = 2402 GET_REFERRAL_SESSION; 2403 else { 2404 __s_api_deleteRefInfo(cookie->reflist); 2405 cookie->reflist = NULL; 2406 cookie->new_state = 2407 NEXT_SEARCH_DESCRIPTOR; 2408 } 2409 break; 2410 case GET_REFERRAL_SESSION: 2411 if (get_referral_session(cookie) < 0) 2412 cookie->new_state = EXIT; 2413 else { 2414 cookie->new_state = NEXT_SEARCH; 2415 } 2416 break; 2417 case LDAP_ERROR: 2418 (void) sprintf(errstr, 2419 gettext("LDAP ERROR (%d): %s."), 2420 cookie->err_rc, 2421 ldap_err2string(cookie->err_rc)); 2422 err = strdup(errstr); 2423 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, 2424 NULL); 2425 cookie->err_rc = NS_LDAP_INTERNAL; 2426 cookie->errorp = *errorp; 2427 return (ERROR); 2428 default: 2429 case ERROR: 2430 (void) sprintf(errstr, 2431 gettext("Internal State machine exit (%d).\n"), 2432 cookie->state); 2433 err = strdup(errstr); 2434 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, 2435 NULL); 2436 cookie->err_rc = NS_LDAP_INTERNAL; 2437 cookie->errorp = *errorp; 2438 return (ERROR); 2439 } 2440 2441 if (cycle == ONE_STEP) { 2442 return (cookie->new_state); 2443 } 2444 cookie->state = cookie->new_state; 2445 } 2446 /*NOTREACHED*/ 2447 #if 0 2448 (void) sprintf(errstr, 2449 gettext("Unexpected State machine error.\n")); 2450 err = strdup(errstr); 2451 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL); 2452 cookie->err_rc = NS_LDAP_INTERNAL; 2453 cookie->errorp = *errorp; 2454 return (ERROR); 2455 #endif 2456 } 2457 2458 2459 2460 /* 2461 * __ns_ldap_list performs one or more LDAP searches to a given 2462 * directory server using service search descriptors and schema 2463 * mapping as appropriate. 2464 */ 2465 2466 int 2467 __ns_ldap_list( 2468 const char *service, 2469 const char *filter, 2470 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 2471 char **realfilter, const void *userdata), 2472 const char * const *attribute, 2473 const ns_cred_t *auth, 2474 const int flags, 2475 ns_ldap_result_t **rResult, /* return result entries */ 2476 ns_ldap_error_t **errorp, 2477 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata), 2478 const void *userdata) 2479 { 2480 ns_ldap_cookie_t *cookie; 2481 ns_ldap_search_desc_t **sdlist = NULL; 2482 ns_ldap_search_desc_t *dptr; 2483 ns_ldap_error_t *error = NULL; 2484 char **dns = NULL; 2485 int scope; 2486 int rc; 2487 2488 *errorp = NULL; 2489 2490 /* Initialize State machine cookie */ 2491 cookie = init_search_state_machine(); 2492 if (cookie == NULL) { 2493 return (NS_LDAP_MEMORY); 2494 } 2495 2496 /* see if need to follow referrals */ 2497 rc = __s_api_toFollowReferrals(flags, 2498 &cookie->followRef, errorp); 2499 if (rc != NS_LDAP_SUCCESS) { 2500 delete_search_cookie(cookie); 2501 return (rc); 2502 } 2503 2504 /* get the service descriptor - or create a default one */ 2505 rc = __s_api_get_SSD_from_SSDtoUse_service(service, 2506 &sdlist, errorp); 2507 if (rc != NS_LDAP_SUCCESS) { 2508 delete_search_cookie(cookie); 2509 *errorp = error; 2510 return (rc); 2511 } 2512 2513 if (sdlist == NULL) { 2514 /* Create default service Desc */ 2515 sdlist = (ns_ldap_search_desc_t **)calloc(2, 2516 sizeof (ns_ldap_search_desc_t *)); 2517 if (sdlist == NULL) { 2518 delete_search_cookie(cookie); 2519 cookie = NULL; 2520 return (NS_LDAP_MEMORY); 2521 } 2522 dptr = (ns_ldap_search_desc_t *) 2523 calloc(1, sizeof (ns_ldap_search_desc_t)); 2524 if (dptr == NULL) { 2525 free(sdlist); 2526 delete_search_cookie(cookie); 2527 cookie = NULL; 2528 return (NS_LDAP_MEMORY); 2529 } 2530 sdlist[0] = dptr; 2531 2532 /* default base */ 2533 rc = __s_api_getDNs(&dns, service, &cookie->errorp); 2534 if (rc != NS_LDAP_SUCCESS) { 2535 if (dns) { 2536 __s_api_free2dArray(dns); 2537 dns = NULL; 2538 } 2539 *errorp = cookie->errorp; 2540 cookie->errorp = NULL; 2541 delete_search_cookie(cookie); 2542 cookie = NULL; 2543 return (rc); 2544 } 2545 dptr->basedn = strdup(dns[0]); 2546 __s_api_free2dArray(dns); 2547 dns = NULL; 2548 2549 /* default scope */ 2550 scope = 0; 2551 rc = __s_api_getSearchScope(&scope, &cookie->errorp); 2552 dptr->scope = scope; 2553 } 2554 2555 cookie->sdlist = sdlist; 2556 2557 /* 2558 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set 2559 */ 2560 if (flags & NS_LDAP_PAGE_CTRL) 2561 cookie->use_paging = TRUE; 2562 else 2563 cookie->use_paging = FALSE; 2564 2565 /* Set up other arguments */ 2566 cookie->userdata = userdata; 2567 if (init_filter_cb != NULL) { 2568 cookie->init_filter_cb = init_filter_cb; 2569 cookie->use_filtercb = 1; 2570 } 2571 if (callback != NULL) { 2572 cookie->callback = callback; 2573 cookie->use_usercb = 1; 2574 } 2575 if (service) { 2576 cookie->service = strdup(service); 2577 if (cookie->service == NULL) { 2578 delete_search_cookie(cookie); 2579 cookie = NULL; 2580 return (NS_LDAP_MEMORY); 2581 } 2582 } 2583 2584 cookie->i_filter = strdup(filter); 2585 cookie->i_attr = attribute; 2586 cookie->i_auth = auth; 2587 cookie->i_flags = flags; 2588 2589 /* Process search */ 2590 rc = search_state_machine(cookie, INIT, 0); 2591 2592 /* Copy results back to user */ 2593 rc = cookie->err_rc; 2594 if (rc != NS_LDAP_SUCCESS) 2595 *errorp = cookie->errorp; 2596 *rResult = cookie->result; 2597 2598 cookie->errorp = NULL; 2599 cookie->result = NULL; 2600 delete_search_cookie(cookie); 2601 cookie = NULL; 2602 2603 if (*rResult == NULL) 2604 rc = NS_LDAP_NOTFOUND; 2605 return (rc); 2606 } 2607 2608 /* 2609 * __s_api_find_domainname performs one or more LDAP searches to 2610 * find the value of the nisdomain attribute associated with 2611 * the input DN 2612 */ 2613 2614 static int 2615 __s_api_find_domainname( 2616 const char *dn, 2617 char **domainname, 2618 const ns_cred_t *cred, 2619 ns_ldap_error_t **errorp) 2620 { 2621 2622 ns_ldap_cookie_t *cookie; 2623 ns_ldap_search_desc_t **sdlist; 2624 ns_ldap_search_desc_t *dptr; 2625 int rc; 2626 char **value; 2627 int flags = 0; 2628 2629 *domainname = NULL; 2630 *errorp = NULL; 2631 2632 /* Initialize State machine cookie */ 2633 cookie = init_search_state_machine(); 2634 if (cookie == NULL) { 2635 return (NS_LDAP_MEMORY); 2636 } 2637 2638 /* see if need to follow referrals */ 2639 rc = __s_api_toFollowReferrals(flags, 2640 &cookie->followRef, errorp); 2641 if (rc != NS_LDAP_SUCCESS) { 2642 delete_search_cookie(cookie); 2643 return (rc); 2644 } 2645 2646 /* Create default service Desc */ 2647 sdlist = (ns_ldap_search_desc_t **)calloc(2, 2648 sizeof (ns_ldap_search_desc_t *)); 2649 if (sdlist == NULL) { 2650 delete_search_cookie(cookie); 2651 cookie = NULL; 2652 return (NS_LDAP_MEMORY); 2653 } 2654 dptr = (ns_ldap_search_desc_t *) 2655 calloc(1, sizeof (ns_ldap_search_desc_t)); 2656 if (dptr == NULL) { 2657 free(sdlist); 2658 delete_search_cookie(cookie); 2659 cookie = NULL; 2660 return (NS_LDAP_MEMORY); 2661 } 2662 sdlist[0] = dptr; 2663 2664 /* search base is dn */ 2665 dptr->basedn = strdup(dn); 2666 2667 /* search scope is base */ 2668 dptr->scope = NS_LDAP_SCOPE_BASE; 2669 2670 /* search filter is "nisdomain=*" */ 2671 dptr->filter = strdup(_NIS_FILTER); 2672 2673 cookie->sdlist = sdlist; 2674 cookie->i_filter = strdup(dptr->filter); 2675 cookie->i_attr = nis_domain_attrs; 2676 cookie->i_auth = cred; 2677 cookie->i_flags = 0; 2678 2679 /* Process search */ 2680 rc = search_state_machine(cookie, INIT, 0); 2681 2682 /* Copy domain name if found */ 2683 rc = cookie->err_rc; 2684 if (rc != NS_LDAP_SUCCESS) 2685 *errorp = cookie->errorp; 2686 if (cookie->result == NULL) 2687 rc = NS_LDAP_NOTFOUND; 2688 if (rc == NS_LDAP_SUCCESS) { 2689 value = __ns_ldap_getAttr(cookie->result->entry, 2690 _NIS_DOMAIN); 2691 if (value[0]) 2692 *domainname = strdup(value[0]); 2693 else 2694 rc = NS_LDAP_NOTFOUND; 2695 } 2696 if (cookie->result != NULL) 2697 (void) __ns_ldap_freeResult(&cookie->result); 2698 cookie->errorp = NULL; 2699 delete_search_cookie(cookie); 2700 cookie = NULL; 2701 return (rc); 2702 } 2703 2704 int 2705 __ns_ldap_firstEntry( 2706 const char *service, 2707 const char *filter, 2708 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 2709 char **realfilter, const void *userdata), 2710 const char * const *attribute, 2711 const ns_cred_t *auth, 2712 const int flags, 2713 void **vcookie, 2714 ns_ldap_result_t **result, 2715 ns_ldap_error_t ** errorp, 2716 const void *userdata) 2717 { 2718 ns_ldap_cookie_t *cookie = NULL; 2719 ns_ldap_error_t *error = NULL; 2720 ns_state_t state; 2721 ns_ldap_search_desc_t **sdlist; 2722 ns_ldap_search_desc_t *dptr; 2723 char **dns = NULL; 2724 int scope; 2725 int rc; 2726 2727 *errorp = NULL; 2728 *result = NULL; 2729 2730 /* get the service descriptor - or create a default one */ 2731 rc = __s_api_get_SSD_from_SSDtoUse_service(service, 2732 &sdlist, errorp); 2733 if (rc != NS_LDAP_SUCCESS) { 2734 *errorp = error; 2735 return (rc); 2736 } 2737 if (sdlist == NULL) { 2738 /* Create default service Desc */ 2739 sdlist = (ns_ldap_search_desc_t **)calloc(2, 2740 sizeof (ns_ldap_search_desc_t *)); 2741 if (sdlist == NULL) { 2742 return (NS_LDAP_MEMORY); 2743 } 2744 dptr = (ns_ldap_search_desc_t *) 2745 calloc(1, sizeof (ns_ldap_search_desc_t)); 2746 if (dptr == NULL) { 2747 free(sdlist); 2748 return (NS_LDAP_MEMORY); 2749 } 2750 sdlist[0] = dptr; 2751 2752 /* default base */ 2753 rc = __s_api_getDNs(&dns, service, &error); 2754 if (rc != NS_LDAP_SUCCESS) { 2755 if (dns) { 2756 __s_api_free2dArray(dns); 2757 dns = NULL; 2758 } 2759 if (sdlist) { 2760 (void) __ns_ldap_freeSearchDescriptors( 2761 &sdlist); 2762 2763 sdlist = NULL; 2764 } 2765 *errorp = error; 2766 return (rc); 2767 } 2768 dptr->basedn = strdup(dns[0]); 2769 __s_api_free2dArray(dns); 2770 dns = NULL; 2771 2772 /* default scope */ 2773 scope = 0; 2774 cookie = init_search_state_machine(); 2775 if (cookie == NULL) { 2776 if (sdlist) { 2777 (void) __ns_ldap_freeSearchDescriptors(&sdlist); 2778 sdlist = NULL; 2779 } 2780 return (NS_LDAP_MEMORY); 2781 } 2782 rc = __s_api_getSearchScope(&scope, &cookie->errorp); 2783 dptr->scope = scope; 2784 } 2785 2786 /* Initialize State machine cookie */ 2787 if (cookie == NULL) 2788 cookie = init_search_state_machine(); 2789 if (cookie == NULL) { 2790 if (sdlist) { 2791 (void) __ns_ldap_freeSearchDescriptors(&sdlist); 2792 sdlist = NULL; 2793 } 2794 return (NS_LDAP_MEMORY); 2795 } 2796 2797 cookie->sdlist = sdlist; 2798 2799 /* see if need to follow referrals */ 2800 rc = __s_api_toFollowReferrals(flags, 2801 &cookie->followRef, errorp); 2802 if (rc != NS_LDAP_SUCCESS) { 2803 delete_search_cookie(cookie); 2804 return (rc); 2805 } 2806 2807 /* 2808 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set 2809 */ 2810 if (flags & NS_LDAP_NO_PAGE_CTRL) 2811 cookie->use_paging = FALSE; 2812 else 2813 cookie->use_paging = TRUE; 2814 2815 /* Set up other arguments */ 2816 cookie->userdata = userdata; 2817 if (init_filter_cb != NULL) { 2818 cookie->init_filter_cb = init_filter_cb; 2819 cookie->use_filtercb = 1; 2820 } 2821 cookie->use_usercb = 0; 2822 if (service) { 2823 cookie->service = strdup(service); 2824 if (cookie->service == NULL) { 2825 delete_search_cookie(cookie); 2826 return (NS_LDAP_MEMORY); 2827 } 2828 } 2829 2830 cookie->i_filter = strdup(filter); 2831 cookie->i_attr = attribute; 2832 cookie->i_auth = auth; 2833 cookie->i_flags = flags; 2834 2835 state = INIT; 2836 for (;;) { 2837 state = search_state_machine(cookie, state, ONE_STEP); 2838 switch (state) { 2839 case PROCESS_RESULT: 2840 *result = cookie->result; 2841 cookie->result = NULL; 2842 *vcookie = (void *)cookie; 2843 return (NS_LDAP_SUCCESS); 2844 case ERROR: 2845 case LDAP_ERROR: 2846 rc = cookie->err_rc; 2847 *errorp = cookie->errorp; 2848 cookie->errorp = NULL; 2849 delete_search_cookie(cookie); 2850 return (rc); 2851 case EXIT: 2852 rc = cookie->err_rc; 2853 if (rc != NS_LDAP_SUCCESS) { 2854 *errorp = cookie->errorp; 2855 cookie->errorp = NULL; 2856 } else { 2857 rc = NS_LDAP_NOTFOUND; 2858 } 2859 2860 delete_search_cookie(cookie); 2861 return (rc); 2862 2863 default: 2864 break; 2865 } 2866 } 2867 } 2868 2869 /*ARGSUSED2*/ 2870 int 2871 __ns_ldap_nextEntry( 2872 void *vcookie, 2873 ns_ldap_result_t **result, 2874 ns_ldap_error_t ** errorp) 2875 { 2876 ns_ldap_cookie_t *cookie; 2877 ns_state_t state; 2878 int rc; 2879 2880 cookie = (ns_ldap_cookie_t *)vcookie; 2881 cookie->result = NULL; 2882 *result = NULL; 2883 2884 state = END_PROCESS_RESULT; 2885 for (;;) { 2886 state = search_state_machine(cookie, state, ONE_STEP); 2887 switch (state) { 2888 case PROCESS_RESULT: 2889 *result = cookie->result; 2890 cookie->result = NULL; 2891 return (NS_LDAP_SUCCESS); 2892 case ERROR: 2893 case LDAP_ERROR: 2894 rc = cookie->err_rc; 2895 *errorp = cookie->errorp; 2896 cookie->errorp = NULL; 2897 return (rc); 2898 case EXIT: 2899 return (NS_LDAP_SUCCESS); 2900 } 2901 } 2902 } 2903 2904 int 2905 __ns_ldap_endEntry( 2906 void **vcookie, 2907 ns_ldap_error_t ** errorp) 2908 { 2909 ns_ldap_cookie_t *cookie; 2910 int rc; 2911 2912 if (*vcookie == NULL) 2913 return (NS_LDAP_INVALID_PARAM); 2914 2915 cookie = (ns_ldap_cookie_t *)(*vcookie); 2916 cookie->result = NULL; 2917 2918 /* Complete search */ 2919 rc = search_state_machine(cookie, EXIT, 0); 2920 2921 /* Copy results back to user */ 2922 rc = cookie->err_rc; 2923 if (rc != NS_LDAP_SUCCESS) 2924 *errorp = cookie->errorp; 2925 2926 cookie->errorp = NULL; 2927 delete_search_cookie(cookie); 2928 cookie = NULL; 2929 *vcookie = NULL; 2930 2931 return (rc); 2932 } 2933 2934 2935 int 2936 __ns_ldap_freeResult(ns_ldap_result_t **result) 2937 { 2938 2939 ns_ldap_entry_t *curEntry = NULL; 2940 ns_ldap_entry_t *delEntry = NULL; 2941 int i; 2942 ns_ldap_result_t *res = *result; 2943 2944 #ifdef DEBUG 2945 (void) fprintf(stderr, "__ns_ldap_freeResult START\n"); 2946 #endif 2947 if (res == NULL) 2948 return (NS_LDAP_INVALID_PARAM); 2949 2950 if (res->entry != NULL) 2951 curEntry = res->entry; 2952 2953 for (i = 0; i < res->entries_count; i++) { 2954 if (curEntry != NULL) { 2955 delEntry = curEntry; 2956 curEntry = curEntry->next; 2957 __ns_ldap_freeEntry(delEntry); 2958 } 2959 } 2960 2961 free(res); 2962 *result = NULL; 2963 return (NS_LDAP_SUCCESS); 2964 } 2965 2966 /*ARGSUSED*/ 2967 int 2968 __ns_ldap_auth(const ns_cred_t *auth, 2969 const int flags, 2970 ns_ldap_error_t **errorp, 2971 LDAPControl **serverctrls, 2972 LDAPControl **clientctrls) 2973 { 2974 2975 ConnectionID connectionId = -1; 2976 Connection *conp; 2977 int rc = 0; 2978 int do_not_fail_if_new_pwd_reqd = 0; 2979 2980 2981 #ifdef DEBUG 2982 (void) fprintf(stderr, "__ns_ldap_auth START\n"); 2983 #endif 2984 2985 *errorp = NULL; 2986 if (!auth) 2987 return (NS_LDAP_INVALID_PARAM); 2988 2989 rc = __s_api_getConnection(NULL, flags, 2990 auth, &connectionId, &conp, errorp, 2991 do_not_fail_if_new_pwd_reqd); 2992 if (rc == NS_LDAP_OP_FAILED && *errorp) 2993 (void) __ns_ldap_freeError(errorp); 2994 2995 if (connectionId > -1) 2996 DropConnection(connectionId, flags); 2997 return (rc); 2998 } 2999 3000 char ** 3001 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname) 3002 { 3003 int i; 3004 3005 if (entry == NULL) 3006 return (NULL); 3007 for (i = 0; i < entry->attr_count; i++) { 3008 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL) 3009 return (entry->attr_pair[i]->attrvalue); 3010 } 3011 return (NULL); 3012 } 3013 3014 3015 /*ARGSUSED*/ 3016 int 3017 __ns_ldap_uid2dn(const char *uid, 3018 char **userDN, 3019 const ns_cred_t *cred, /* cred is ignored */ 3020 ns_ldap_error_t **errorp) 3021 { 3022 ns_ldap_result_t *result = NULL; 3023 char *filter, *userdata; 3024 char errstr[MAXERROR]; 3025 char **value; 3026 int rc = 0; 3027 int i = 0; 3028 size_t len; 3029 3030 *errorp = NULL; 3031 *userDN = NULL; 3032 if ((uid == NULL) || (uid[0] == '\0')) 3033 return (NS_LDAP_INVALID_PARAM); 3034 3035 while (uid[i] != '\0') { 3036 if (uid[i] == '=') { 3037 *userDN = strdup(uid); 3038 return (NS_LDAP_SUCCESS); 3039 } 3040 i++; 3041 } 3042 i = 0; 3043 while ((uid[i] != '\0') && (isdigit(uid[i]))) 3044 i++; 3045 if (uid[i] == '\0') { 3046 len = strlen(UIDNUMFILTER) + strlen(uid) + 1; 3047 filter = (char *)malloc(len); 3048 if (filter == NULL) { 3049 *userDN = NULL; 3050 return (NS_LDAP_MEMORY); 3051 } 3052 (void) snprintf(filter, len, UIDNUMFILTER, uid); 3053 3054 len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1; 3055 userdata = (char *)malloc(len); 3056 if (userdata == NULL) { 3057 *userDN = NULL; 3058 return (NS_LDAP_MEMORY); 3059 } 3060 (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid); 3061 } else { 3062 len = strlen(UIDFILTER) + strlen(uid) + 1; 3063 filter = (char *)malloc(len); 3064 if (filter == NULL) { 3065 *userDN = NULL; 3066 return (NS_LDAP_MEMORY); 3067 } 3068 (void) snprintf(filter, len, UIDFILTER, uid); 3069 3070 len = strlen(UIDFILTER_SSD) + strlen(uid) + 1; 3071 userdata = (char *)malloc(len); 3072 if (userdata == NULL) { 3073 *userDN = NULL; 3074 return (NS_LDAP_MEMORY); 3075 } 3076 (void) snprintf(userdata, len, UIDFILTER_SSD, uid); 3077 } 3078 3079 rc = __ns_ldap_list("passwd", filter, 3080 __s_api_merge_SSD_filter, 3081 NULL, cred, 0, 3082 &result, errorp, NULL, 3083 userdata); 3084 free(filter); 3085 filter = NULL; 3086 free(userdata); 3087 userdata = NULL; 3088 if (rc != NS_LDAP_SUCCESS) { 3089 if (result) { 3090 (void) __ns_ldap_freeResult(&result); 3091 result = NULL; 3092 } 3093 return (rc); 3094 } 3095 if (result->entries_count > 1) { 3096 (void) __ns_ldap_freeResult(&result); 3097 result = NULL; 3098 *userDN = NULL; 3099 (void) sprintf(errstr, 3100 gettext("Too many entries are returned for %s"), uid); 3101 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr), 3102 NULL); 3103 return (NS_LDAP_INTERNAL); 3104 } 3105 3106 value = __ns_ldap_getAttr(result->entry, "dn"); 3107 *userDN = strdup(value[0]); 3108 (void) __ns_ldap_freeResult(&result); 3109 result = NULL; 3110 return (NS_LDAP_SUCCESS); 3111 } 3112 3113 3114 /*ARGSUSED*/ 3115 int 3116 __ns_ldap_host2dn(const char *host, 3117 const char *domain, 3118 char **hostDN, 3119 const ns_cred_t *cred, /* cred is ignored */ 3120 ns_ldap_error_t **errorp) 3121 { 3122 ns_ldap_result_t *result = NULL; 3123 char *filter, *userdata; 3124 char errstr[MAXERROR]; 3125 char **value; 3126 int rc; 3127 size_t len; 3128 3129 /* 3130 * XXX 3131 * the domain parameter needs to be used in case domain is not local, if 3132 * this routine is to support multi domain setups, it needs lots of work... 3133 */ 3134 *errorp = NULL; 3135 *hostDN = NULL; 3136 if ((host == NULL) || (host[0] == '\0')) 3137 return (NS_LDAP_INVALID_PARAM); 3138 3139 len = strlen(HOSTFILTER) + strlen(host) + 1; 3140 filter = (char *)malloc(len); 3141 if (filter == NULL) { 3142 return (NS_LDAP_MEMORY); 3143 } 3144 (void) snprintf(filter, len, HOSTFILTER, host); 3145 3146 len = strlen(HOSTFILTER_SSD) + strlen(host) + 1; 3147 userdata = (char *)malloc(len); 3148 if (userdata == NULL) { 3149 return (NS_LDAP_MEMORY); 3150 } 3151 (void) snprintf(userdata, len, HOSTFILTER_SSD, host); 3152 3153 rc = __ns_ldap_list("hosts", filter, 3154 __s_api_merge_SSD_filter, 3155 NULL, cred, 0, &result, 3156 errorp, NULL, 3157 userdata); 3158 free(filter); 3159 filter = NULL; 3160 free(userdata); 3161 userdata = NULL; 3162 if (rc != NS_LDAP_SUCCESS) { 3163 if (result) { 3164 (void) __ns_ldap_freeResult(&result); 3165 result = NULL; 3166 } 3167 return (rc); 3168 } 3169 3170 if (result->entries_count > 1) { 3171 (void) __ns_ldap_freeResult(&result); 3172 result = NULL; 3173 *hostDN = NULL; 3174 (void) sprintf(errstr, 3175 gettext("Too many entries are returned for %s"), host); 3176 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr), 3177 NULL); 3178 return (NS_LDAP_INTERNAL); 3179 } 3180 3181 value = __ns_ldap_getAttr(result->entry, "dn"); 3182 *hostDN = strdup(value[0]); 3183 (void) __ns_ldap_freeResult(&result); 3184 result = NULL; 3185 return (NS_LDAP_SUCCESS); 3186 } 3187 3188 /*ARGSUSED*/ 3189 int 3190 __ns_ldap_dn2domain(const char *dn, 3191 char **domain, 3192 const ns_cred_t *cred, 3193 ns_ldap_error_t **errorp) 3194 { 3195 int rc, pnum, i, j, len = 0; 3196 char *newdn, **rdns = NULL; 3197 char **dns, *dn1; 3198 3199 *errorp = NULL; 3200 3201 if (domain == NULL) 3202 return (NS_LDAP_INVALID_PARAM); 3203 else 3204 *domain = NULL; 3205 3206 if ((dn == NULL) || (dn[0] == '\0')) 3207 return (NS_LDAP_INVALID_PARAM); 3208 3209 /* 3210 * break dn into rdns 3211 */ 3212 dn1 = strdup(dn); 3213 if (dn1 == NULL) 3214 return (NS_LDAP_MEMORY); 3215 rdns = ldap_explode_dn(dn1, 0); 3216 free(dn1); 3217 if (rdns == NULL || *rdns == NULL) 3218 return (NS_LDAP_INVALID_PARAM); 3219 3220 for (i = 0; rdns[i]; i++) 3221 len += strlen(rdns[i]) + 1; 3222 pnum = i; 3223 3224 newdn = (char *)malloc(len + 1); 3225 dns = (char **)calloc(pnum, sizeof (char *)); 3226 if (newdn == NULL || dns == NULL) { 3227 if (newdn) 3228 free(newdn); 3229 ldap_value_free(rdns); 3230 return (NS_LDAP_MEMORY); 3231 } 3232 3233 /* construct a semi-normalized dn, newdn */ 3234 *newdn = '\0'; 3235 for (i = 0; rdns[i]; i++) { 3236 dns[i] = newdn + strlen(newdn); 3237 (void) strcat(newdn, 3238 __s_api_remove_rdn_space(rdns[i])); 3239 (void) strcat(newdn, ","); 3240 } 3241 /* remove the last ',' */ 3242 newdn[strlen(newdn) - 1] = '\0'; 3243 ldap_value_free(rdns); 3244 3245 /* 3246 * loop and find the domain name associated with newdn, 3247 * removing rdn one by one from left to right 3248 */ 3249 for (i = 0; i < pnum; i++) { 3250 3251 if (*errorp) 3252 (void) __ns_ldap_freeError(errorp); 3253 3254 /* 3255 * try cache manager first 3256 */ 3257 rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN, 3258 dns[i], domain); 3259 if (rc != NS_LDAP_SUCCESS) { 3260 /* 3261 * try ldap server second 3262 */ 3263 rc = __s_api_find_domainname(dns[i], domain, 3264 cred, errorp); 3265 } else { 3266 /* 3267 * skip the last one, 3268 * since it is already cached by ldap_cachemgr 3269 */ 3270 i--; 3271 } 3272 if (rc == NS_LDAP_SUCCESS) { 3273 /* 3274 * ask cache manager to save the 3275 * dn to domain mapping(s) 3276 */ 3277 for (j = 0; j <= i; j++) { 3278 (void) __s_api_set_cachemgr_data( 3279 NS_CACHE_DN2DOMAIN, 3280 dns[j], 3281 *domain); 3282 } 3283 break; 3284 } 3285 } 3286 3287 free(dns); 3288 free(newdn); 3289 if (rc != NS_LDAP_SUCCESS) 3290 rc = NS_LDAP_NOTFOUND; 3291 return (rc); 3292 } 3293 3294 /*ARGSUSED*/ 3295 int 3296 __ns_ldap_getServiceAuthMethods(const char *service, 3297 ns_auth_t ***auth, 3298 ns_ldap_error_t **errorp) 3299 { 3300 char errstr[MAXERROR]; 3301 int rc, i, done = 0; 3302 int slen; 3303 void **param; 3304 char **sam, *srv, *send; 3305 ns_auth_t **authpp = NULL, *ap; 3306 int cnt, max; 3307 ns_config_t *cfg; 3308 ns_ldap_error_t *error = NULL; 3309 3310 if (errorp == NULL) 3311 return (NS_LDAP_INVALID_PARAM); 3312 *errorp = NULL; 3313 3314 if ((service == NULL) || (service[0] == '\0') || 3315 (auth == NULL)) 3316 return (NS_LDAP_INVALID_PARAM); 3317 3318 *auth = NULL; 3319 rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, ¶m, &error); 3320 if (rc != NS_LDAP_SUCCESS || param == NULL) { 3321 *errorp = error; 3322 return (rc); 3323 } 3324 sam = (char **)param; 3325 3326 cfg = __s_api_get_default_config(); 3327 cnt = 0; 3328 3329 slen = strlen(service); 3330 3331 for (; *sam; sam++) { 3332 srv = *sam; 3333 if (strncasecmp(service, srv, slen) != 0) 3334 continue; 3335 srv += slen; 3336 if (*srv != COLONTOK) 3337 continue; 3338 send = srv; 3339 srv++; 3340 for (max = 1; (send = strchr(++send, SEMITOK)) != NULL; 3341 max++) {} 3342 authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *)); 3343 if (authpp == NULL) { 3344 (void) __ns_ldap_freeParam(¶m); 3345 __s_api_release_config(cfg); 3346 return (NS_LDAP_MEMORY); 3347 } 3348 while (!done) { 3349 send = strchr(srv, SEMITOK); 3350 if (send != NULL) { 3351 *send = '\0'; 3352 send++; 3353 } 3354 i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P); 3355 if (i == -1) { 3356 (void) __ns_ldap_freeParam(¶m); 3357 (void) sprintf(errstr, 3358 gettext("Unsupported serviceAuthenticationMethod: %s.\n"), srv); 3359 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX, 3360 strdup(errstr), NULL); 3361 __s_api_release_config(cfg); 3362 return (NS_LDAP_CONFIG); 3363 } 3364 ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i); 3365 if (ap == NULL) { 3366 (void) __ns_ldap_freeParam(¶m); 3367 __s_api_release_config(cfg); 3368 return (NS_LDAP_MEMORY); 3369 } 3370 authpp[cnt++] = ap; 3371 if (send == NULL) 3372 done = TRUE; 3373 else 3374 srv = send; 3375 } 3376 } 3377 3378 *auth = authpp; 3379 (void) __ns_ldap_freeParam(¶m); 3380 __s_api_release_config(cfg); 3381 return (NS_LDAP_SUCCESS); 3382 } 3383 3384 /* 3385 * This routine is called when certain scenario occurs 3386 * e.g. 3387 * service == auto_home 3388 * SSD = automount: ou = mytest, 3389 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA 3390 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap 3391 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject 3392 * 3393 * The automountMapName is prepended implicitely but is mapped 3394 * to AAA. So dn could appers as 3395 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com 3396 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com 3397 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com 3398 * in the directory. 3399 * This function is called to covert the mapped attr back to 3400 * orig attr when the entries are searched and returned 3401 */ 3402 3403 int 3404 __s_api_convert_automountmapname(const char *service, char **dn, 3405 ns_ldap_error_t **errp) { 3406 3407 char **mapping = NULL; 3408 char *mapped_attr = NULL; 3409 char *automountmapname = "automountMapName"; 3410 char *buffer = NULL; 3411 int rc = NS_LDAP_SUCCESS; 3412 char errstr[MAXERROR]; 3413 3414 /* 3415 * dn is an input/out parameter, check it first 3416 */ 3417 3418 if (service == NULL || dn == NULL || *dn == NULL) 3419 return (NS_LDAP_INVALID_PARAM); 3420 3421 /* 3422 * Check to see if there is a mapped attribute for auto_xxx 3423 */ 3424 3425 mapping = __ns_ldap_getMappedAttributes(service, automountmapname); 3426 3427 /* 3428 * if no mapped attribute for auto_xxx, try automount 3429 */ 3430 3431 if (mapping == NULL) 3432 mapping = __ns_ldap_getMappedAttributes( 3433 "automount", automountmapname); 3434 3435 /* 3436 * if no mapped attribute is found, return SUCCESS (no op) 3437 */ 3438 3439 if (mapping == NULL) 3440 return (NS_LDAP_SUCCESS); 3441 3442 /* 3443 * if the mapped attribute is found and attr is not empty, 3444 * copy it 3445 */ 3446 3447 if (mapping[0] != NULL) { 3448 mapped_attr = strdup(mapping[0]); 3449 __s_api_free2dArray(mapping); 3450 if (mapped_attr == NULL) { 3451 return (NS_LDAP_MEMORY); 3452 } 3453 } else { 3454 __s_api_free2dArray(mapping); 3455 3456 (void) snprintf(errstr, (2 * MAXERROR), 3457 gettext( 3458 "Attribute nisMapName is mapped to an " 3459 "empty string.\n")); 3460 3461 MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX, 3462 strdup(errstr), NULL); 3463 3464 return (NS_LDAP_CONFIG); 3465 } 3466 3467 /* 3468 * Locate the mapped attribute in the dn 3469 * and replace it if it exists 3470 */ 3471 3472 rc = __s_api_replace_mapped_attr_in_dn( 3473 (const char *) automountmapname, (const char *) mapped_attr, 3474 (const char *) *dn, &buffer); 3475 3476 /* clean up */ 3477 3478 free(mapped_attr); 3479 3480 /* 3481 * If mapped attr is found(buffer != NULL) 3482 * a new dn is returned 3483 * If no mapped attribute is in dn, 3484 * return NS_LDAP_SUCCESS (no op) 3485 * If no memory, 3486 * return NS_LDAP_MEMORY (no op) 3487 */ 3488 3489 if (buffer != NULL) { 3490 free(*dn); 3491 *dn = buffer; 3492 } 3493 3494 return (rc); 3495 } 3496 3497 /* 3498 * If the mapped attr is found in the dn, 3499 * return NS_LDAP_SUCCESS and a new_dn. 3500 * If no mapped attr is found, 3501 * return NS_LDAP_SUCCESS and *new_dn == NULL 3502 * If there is not enough memory, 3503 * return NS_LDAP_MEMORY and *new_dn == NULL 3504 */ 3505 3506 int 3507 __s_api_replace_mapped_attr_in_dn( 3508 const char *orig_attr, const char *mapped_attr, 3509 const char *dn, char **new_dn) { 3510 3511 char **dnArray = NULL; 3512 char *cur = NULL, *start = NULL; 3513 int i = 0, found = 0; 3514 int len = 0, orig_len = 0, mapped_len = 0; 3515 int dn_len = 0, tmp_len = 0; 3516 3517 *new_dn = NULL; 3518 3519 /* 3520 * seperate dn into individual componets 3521 * e.g. 3522 * "automountKey=user_01" , "automountMapName_test=auto_home", ... 3523 */ 3524 dnArray = ldap_explode_dn(dn, 0); 3525 3526 /* 3527 * This will find "mapped attr=value" in dn. 3528 * It won't find match if mapped attr appears 3529 * in the value. 3530 */ 3531 for (i = 0; dnArray[i] != NULL; i++) { 3532 /* 3533 * This function is called when reading from 3534 * the directory so assume each component has "=". 3535 * Any ill formatted dn should be rejected 3536 * before adding to the directory 3537 */ 3538 cur = strchr(dnArray[i], '='); 3539 *cur = '\0'; 3540 if (strcasecmp(mapped_attr, dnArray[i]) == 0) 3541 found = 1; 3542 *cur = '='; 3543 if (found) break; 3544 } 3545 3546 if (!found) { 3547 __s_api_free2dArray(dnArray); 3548 *new_dn = NULL; 3549 return (NS_LDAP_SUCCESS); 3550 } 3551 /* 3552 * The new length is *dn length + (difference between 3553 * orig attr and mapped attr) + 1 ; 3554 * e.g. 3555 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com 3556 * ==> 3557 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com 3558 */ 3559 mapped_len = strlen(mapped_attr); 3560 orig_len = strlen(orig_attr); 3561 dn_len = strlen(dn); 3562 len = dn_len + orig_len - mapped_len + 1; 3563 *new_dn = (char *)calloc(1, len); 3564 if (*new_dn == NULL) { 3565 __s_api_free2dArray(dnArray); 3566 return (NS_LDAP_MEMORY); 3567 } 3568 3569 /* 3570 * Locate the mapped attr in the dn. 3571 * Use dnArray[i] instead of mapped_attr 3572 * because mapped_attr could appear in 3573 * the value 3574 */ 3575 3576 cur = strstr(dn, dnArray[i]); 3577 __s_api_free2dArray(dnArray); 3578 /* copy the portion before mapped attr in dn */ 3579 start = *new_dn; 3580 tmp_len = cur - dn; 3581 (void) memcpy((void *) start, (const void*) dn, tmp_len); 3582 3583 /* 3584 * Copy the orig_attr. e.g. automountMapName 3585 * This replaces mapped attr with orig attr 3586 */ 3587 start = start + (cur - dn); /* move cursor in buffer */ 3588 (void) memcpy((void *) start, (const void*) orig_attr, orig_len); 3589 3590 /* 3591 * Copy the portion after mapped attr in dn 3592 */ 3593 cur = cur + mapped_len; /* move cursor in dn */ 3594 start = start + orig_len; /* move cursor in buffer */ 3595 (void) strcpy(start, cur); 3596 3597 return (NS_LDAP_SUCCESS); 3598 } 3599 3600 /* 3601 * Validate Filter functions 3602 */ 3603 3604 /* ***** Start of modified libldap.so.5 filter parser ***** */ 3605 3606 /* filter parsing routine forward references */ 3607 static int adj_filter_list(char *str); 3608 static int adj_simple_filter(char *str); 3609 static int unescape_filterval(char *val); 3610 static int hexchar2int(char c); 3611 static int adj_substring_filter(char *val); 3612 3613 3614 /* 3615 * assumes string manipulation is in-line 3616 * and all strings are sufficient in size 3617 * return value is the position after 'c' 3618 */ 3619 3620 static char * 3621 resync_str(char *str, char *next, char c) 3622 { 3623 char *ret; 3624 3625 ret = str + strlen(str); 3626 *next = c; 3627 if (ret == next) 3628 return (ret); 3629 (void) strcat(str, next); 3630 return (ret); 3631 } 3632 3633 static char * 3634 find_right_paren(char *s) 3635 { 3636 int balance, escape; 3637 3638 balance = 1; 3639 escape = 0; 3640 while (*s && balance) { 3641 if (escape == 0) { 3642 if (*s == '(') 3643 balance++; 3644 else if (*s == ')') 3645 balance--; 3646 } 3647 if (*s == '\\' && ! escape) 3648 escape = 1; 3649 else 3650 escape = 0; 3651 if (balance) 3652 s++; 3653 } 3654 3655 return (*s ? s : NULL); 3656 } 3657 3658 static char * 3659 adj_complex_filter(char *str) 3660 { 3661 char *next; 3662 3663 /* 3664 * We have (x(filter)...) with str sitting on 3665 * the x. We have to find the paren matching 3666 * the one before the x and put the intervening 3667 * filters by calling adj_filter_list(). 3668 */ 3669 3670 str++; 3671 if ((next = find_right_paren(str)) == NULL) 3672 return (NULL); 3673 3674 *next = '\0'; 3675 if (adj_filter_list(str) == -1) 3676 return (NULL); 3677 next = resync_str(str, next, ')'); 3678 next++; 3679 3680 return (next); 3681 } 3682 3683 static int 3684 adj_filter(char *str) 3685 { 3686 char *next; 3687 int parens, balance, escape; 3688 char *np, *cp, *dp; 3689 3690 parens = 0; 3691 while (*str) { 3692 switch (*str) { 3693 case '(': 3694 str++; 3695 parens++; 3696 switch (*str) { 3697 case '&': 3698 if ((str = adj_complex_filter(str)) == NULL) 3699 return (-1); 3700 3701 parens--; 3702 break; 3703 3704 case '|': 3705 if ((str = adj_complex_filter(str)) == NULL) 3706 return (-1); 3707 3708 parens--; 3709 break; 3710 3711 case '!': 3712 if ((str = adj_complex_filter(str)) == NULL) 3713 return (-1); 3714 3715 parens--; 3716 break; 3717 3718 case '(': 3719 /* illegal ((case - generated by conversion */ 3720 3721 /* find missing close) */ 3722 np = find_right_paren(str+1); 3723 3724 /* error if not found */ 3725 if (np == NULL) 3726 return (-1); 3727 3728 /* remove redundant (and) */ 3729 for (dp = str, cp = str+1; cp < np; ) { 3730 *dp++ = *cp++; 3731 } 3732 cp++; 3733 while (*cp) 3734 *dp++ = *cp++; 3735 *dp = '\0'; 3736 3737 /* re-start test at original ( */ 3738 parens--; 3739 str--; 3740 break; 3741 3742 default: 3743 balance = 1; 3744 escape = 0; 3745 next = str; 3746 while (*next && balance) { 3747 if (escape == 0) { 3748 if (*next == '(') 3749 balance++; 3750 else if (*next == ')') 3751 balance--; 3752 } 3753 if (*next == '\\' && ! escape) 3754 escape = 1; 3755 else 3756 escape = 0; 3757 if (balance) 3758 next++; 3759 } 3760 if (balance != 0) 3761 return (-1); 3762 3763 *next = '\0'; 3764 if (adj_simple_filter(str) == -1) { 3765 return (-1); 3766 } 3767 next = resync_str(str, next, ')'); 3768 next++; 3769 str = next; 3770 parens--; 3771 break; 3772 } 3773 break; 3774 3775 case ')': 3776 str++; 3777 parens--; 3778 break; 3779 3780 case ' ': 3781 str++; 3782 break; 3783 3784 default: /* assume it's a simple type=value filter */ 3785 next = strchr(str, '\0'); 3786 if (adj_simple_filter(str) == -1) { 3787 return (-1); 3788 } 3789 str = next; 3790 break; 3791 } 3792 } 3793 3794 return (parens ? -1 : 0); 3795 } 3796 3797 3798 /* 3799 * Put a list of filters like this "(filter1)(filter2)..." 3800 */ 3801 3802 static int 3803 adj_filter_list(char *str) 3804 { 3805 char *next; 3806 char save; 3807 3808 while (*str) { 3809 while (*str && isspace(*str)) 3810 str++; 3811 if (*str == '\0') 3812 break; 3813 3814 if ((next = find_right_paren(str + 1)) == NULL) 3815 return (-1); 3816 save = *++next; 3817 3818 /* now we have "(filter)" with str pointing to it */ 3819 *next = '\0'; 3820 if (adj_filter(str) == -1) 3821 return (-1); 3822 next = resync_str(str, next, save); 3823 3824 str = next; 3825 } 3826 3827 return (0); 3828 } 3829 3830 3831 /* 3832 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side 3833 * of a filter expression, 0 otherwise. A valid string may contain only 3834 * letters, numbers, hyphens, semi-colons, colons and periods. examples: 3835 * cn 3836 * cn;lang-fr 3837 * 1.2.3.4;binary;dynamic 3838 * mail;dynamic 3839 * cn:dn:1.2.3.4 3840 * 3841 * For compatibility with older servers, we also allow underscores in 3842 * attribute types, even through they are not allowed by the LDAPv3 RFCs. 3843 */ 3844 static int 3845 is_valid_attr(char *a) 3846 { 3847 for (; *a; a++) { 3848 if (!isascii(*a)) { 3849 return (0); 3850 } else if (!isalnum(*a)) { 3851 switch (*a) { 3852 case '-': 3853 case '.': 3854 case ';': 3855 case ':': 3856 case '_': 3857 break; /* valid */ 3858 default: 3859 return (0); 3860 } 3861 } 3862 } 3863 return (1); 3864 } 3865 3866 static char * 3867 find_star(char *s) 3868 { 3869 for (; *s; ++s) { 3870 switch (*s) { 3871 case '*': 3872 return (s); 3873 case '\\': 3874 ++s; 3875 if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0) 3876 ++s; 3877 default: 3878 break; 3879 } 3880 } 3881 return (NULL); 3882 } 3883 3884 static int 3885 adj_simple_filter(char *str) 3886 { 3887 char *s, *s2, *s3, filterop; 3888 char *value; 3889 int ftype = 0; 3890 int rc; 3891 3892 rc = -1; /* pessimistic */ 3893 3894 if ((str = strdup(str)) == NULL) { 3895 return (rc); 3896 } 3897 3898 if ((s = strchr(str, '=')) == NULL) { 3899 goto free_and_return; 3900 } 3901 value = s + 1; 3902 *s-- = '\0'; 3903 filterop = *s; 3904 if (filterop == '<' || filterop == '>' || filterop == '~' || 3905 filterop == ':') { 3906 *s = '\0'; 3907 } 3908 3909 if (! is_valid_attr(str)) { 3910 goto free_and_return; 3911 } 3912 3913 switch (filterop) { 3914 case '<': /* LDAP_FILTER_LE */ 3915 case '>': /* LDAP_FILTER_GE */ 3916 case '~': /* LDAP_FILTER_APPROX */ 3917 break; 3918 case ':': /* extended filter - v3 only */ 3919 /* 3920 * extended filter looks like this: 3921 * 3922 * [type][':dn'][':'oid]':='value 3923 * 3924 * where one of type or :oid is required. 3925 * 3926 */ 3927 s2 = s3 = NULL; 3928 if ((s2 = strrchr(str, ':')) == NULL) { 3929 goto free_and_return; 3930 } 3931 if (strcasecmp(s2, ":dn") == 0) { 3932 *s2 = '\0'; 3933 } else { 3934 *s2 = '\0'; 3935 if ((s3 = strrchr(str, ':')) != NULL) { 3936 if (strcasecmp(s3, ":dn") != 0) { 3937 goto free_and_return; 3938 } 3939 *s3 = '\0'; 3940 } 3941 } 3942 if (unescape_filterval(value) < 0) { 3943 goto free_and_return; 3944 } 3945 rc = 0; 3946 goto free_and_return; 3947 /* break; */ 3948 default: 3949 if (find_star(value) == NULL) { 3950 ftype = 0; /* LDAP_FILTER_EQUALITY */ 3951 } else if (strcmp(value, "*") == 0) { 3952 ftype = 1; /* LDAP_FILTER_PRESENT */ 3953 } else { 3954 rc = adj_substring_filter(value); 3955 goto free_and_return; 3956 } 3957 break; 3958 } 3959 3960 if (ftype != 0) { /* == LDAP_FILTER_PRESENT */ 3961 rc = 0; 3962 } else if (unescape_filterval(value) >= 0) { 3963 rc = 0; 3964 } 3965 if (rc != -1) { 3966 rc = 0; 3967 } 3968 3969 free_and_return: 3970 free(str); 3971 return (rc); 3972 } 3973 3974 3975 /* 3976 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape 3977 * sequences within the null-terminated string 'val'. 3978 * 3979 * If 'val' contains invalid escape sequences we return -1. 3980 * Otherwise return 1 3981 */ 3982 static int 3983 unescape_filterval(char *val) 3984 { 3985 int escape, firstdigit; 3986 char *s; 3987 3988 firstdigit = 0; 3989 escape = 0; 3990 for (s = val; *s; s++) { 3991 if (escape) { 3992 /* 3993 * first try LDAPv3 escape (hexadecimal) sequence 3994 */ 3995 if (hexchar2int(*s) < 0) { 3996 if (firstdigit) { 3997 /* 3998 * LDAPv2 (RFC1960) escape sequence 3999 */ 4000 escape = 0; 4001 } else { 4002 return (-1); 4003 } 4004 } 4005 if (firstdigit) { 4006 firstdigit = 0; 4007 } else { 4008 escape = 0; 4009 } 4010 4011 } else if (*s != '\\') { 4012 escape = 0; 4013 4014 } else { 4015 escape = 1; 4016 firstdigit = 1; 4017 } 4018 } 4019 4020 return (1); 4021 } 4022 4023 4024 /* 4025 * convert character 'c' that represents a hexadecimal digit to an integer. 4026 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned. 4027 * otherwise the converted value is returned. 4028 */ 4029 static int 4030 hexchar2int(char c) 4031 { 4032 if (c >= '0' && c <= '9') { 4033 return (c - '0'); 4034 } 4035 if (c >= 'A' && c <= 'F') { 4036 return (c - 'A' + 10); 4037 } 4038 if (c >= 'a' && c <= 'f') { 4039 return (c - 'a' + 10); 4040 } 4041 return (-1); 4042 } 4043 4044 static int 4045 adj_substring_filter(char *val) 4046 { 4047 char *nextstar; 4048 4049 for (; val != NULL; val = nextstar) { 4050 if ((nextstar = find_star(val)) != NULL) { 4051 *nextstar++ = '\0'; 4052 } 4053 4054 if (*val != '\0') { 4055 if (unescape_filterval(val) < 0) { 4056 return (-1); 4057 } 4058 } 4059 } 4060 4061 return (0); 4062 } 4063 4064 /* ***** End of modified libldap.so.5 filter parser ***** */ 4065 4066 4067 /* 4068 * Walk filter, remove redundant parentheses in-line 4069 * verify that the filter is reasonable 4070 */ 4071 static int 4072 validate_filter(ns_ldap_cookie_t *cookie) 4073 { 4074 char *filter = cookie->filter; 4075 int rc; 4076 4077 /* Parse filter looking for illegal values */ 4078 4079 rc = adj_filter(filter); 4080 if (rc != 0) { 4081 return (NS_LDAP_OP_FAILED); 4082 } 4083 4084 /* end of filter checking */ 4085 4086 return (NS_LDAP_SUCCESS); 4087 } 4088