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