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