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