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 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2020 Joyent, Inc. 25 */ 26 27 #include <stdio.h> 28 #include <sys/types.h> 29 #include <stdlib.h> 30 #include <libintl.h> 31 #include <ctype.h> 32 #include <syslog.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <priv.h> 39 40 #include "ns_sldap.h" 41 #include "ns_internal.h" 42 #include "ns_cache_door.h" 43 #include "ns_connmgmt.h" 44 45 #define _NIS_FILTER "nisdomain=*" 46 #define _NIS_DOMAIN "nisdomain" 47 static const char *nis_domain_attrs[] = { 48 _NIS_DOMAIN, 49 (char *)NULL 50 }; 51 52 static int validate_filter(ns_ldap_cookie_t *cookie); 53 54 void 55 __ns_ldap_freeEntry(ns_ldap_entry_t *ep) 56 { 57 int j, k = 0; 58 59 if (ep == NULL) 60 return; 61 62 if (ep->attr_pair == NULL) { 63 free(ep); 64 return; 65 } 66 for (j = 0; j < ep->attr_count; j++) { 67 if (ep->attr_pair[j] == NULL) 68 continue; 69 if (ep->attr_pair[j]->attrname) 70 free(ep->attr_pair[j]->attrname); 71 if (ep->attr_pair[j]->attrvalue) { 72 for (k = 0; (k < ep->attr_pair[j]->value_count) && 73 (ep->attr_pair[j]->attrvalue[k]); k++) { 74 free(ep->attr_pair[j]->attrvalue[k]); 75 } 76 free(ep->attr_pair[j]->attrvalue); 77 } 78 free(ep->attr_pair[j]); 79 } 80 free(ep->attr_pair); 81 free(ep); 82 } 83 84 static void 85 _freeControlList(LDAPControl ***ctrls) 86 { 87 LDAPControl **ctrl; 88 89 if (ctrls == NULL || *ctrls == NULL) 90 return; 91 92 for (ctrl = *ctrls; *ctrl != NULL; ctrl++) 93 ldap_control_free(*ctrl); 94 free(*ctrls); 95 *ctrls = NULL; 96 } 97 /* 98 * Convert attribute type in a RDN that has an attribute mapping to the 99 * original mappped type. 100 * e.g. 101 * cn<->cn-st and iphostnumber<->iphostnumber-st 102 * cn-st=aaa+iphostnumber-st=10.10.01.01 103 * is mapped to 104 * cn=aaa+iphostnumber=10.10.01.01 105 * 106 * Input - service: e.g. hosts, passwd etc. 107 * rdn: RDN 108 * Return: NULL - No attribute mapping in the RDN 109 * Non-NULL - The attribute type(s) in the RDN are mapped and 110 * the memory is allocated for the new rdn. 111 * 112 */ 113 static char * 114 _cvtRDN(const char *service, const char *rdn) 115 { 116 char **attrs, **mapped_attrs, **mapp, *type, *value, *attr; 117 char *new_rdn = NULL; 118 int nAttr = 0, i, attr_mapped, len = 0; 119 120 /* Break down "type=value\0" pairs. Assume RDN is normalized */ 121 if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL) 122 return (NULL); 123 124 for (nAttr = 0; attrs[nAttr] != NULL; nAttr++) 125 ; 126 127 if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) { 128 ldap_value_free(attrs); 129 return (NULL); 130 } 131 132 attr_mapped = 0; 133 for (i = 0; i < nAttr; i++) { 134 /* Parse type=value pair */ 135 if ((type = strtok_r(attrs[i], "=", &value)) == NULL || 136 value == NULL) 137 goto cleanup; 138 /* Reverse map: e.g. cn-sm -> cn */ 139 mapp = __ns_ldap_getOrigAttribute(service, type); 140 if (mapp != NULL && mapp[0] != NULL) { 141 /* The attribute mapping is found */ 142 type = mapp[0]; 143 attr_mapped = 1; 144 145 /* "type=value\0" */ 146 len = strlen(type) + strlen(value) + 2; 147 148 /* Reconstruct type=value pair. A string is allocated */ 149 if ((attr = (char *)calloc(1, len)) == NULL) { 150 __s_api_free2dArray(mapp); 151 goto cleanup; 152 } 153 (void) snprintf(attr, len, "%s=%s", type, value); 154 mapped_attrs[i] = attr; 155 } else { 156 /* 157 * No attribute mapping. attrs[i] is going to be copied 158 * later. Restore "type\0value\0" back to 159 * "type=value\0". 160 */ 161 type[strlen(type)] = '='; 162 } 163 __s_api_free2dArray(mapp); 164 } 165 if (attr_mapped == 0) 166 /* No attribute mapping. Don't bother to reconstruct RDN */ 167 goto cleanup; 168 169 len = 0; 170 /* Reconstruct RDN from type=value pairs */ 171 for (i = 0; i < nAttr; i++) { 172 if (mapped_attrs[i]) 173 len += strlen(mapped_attrs[i]); 174 else 175 len += strlen(attrs[i]); 176 /* Add 1 for "+" */ 177 len++; 178 } 179 if ((new_rdn = (char *)calloc(1, ++len)) == NULL) 180 goto cleanup; 181 for (i = 0; i < nAttr; i++) { 182 if (i > 0) 183 /* Add seperator */ 184 (void) strlcat(new_rdn, "+", len); 185 186 if (mapped_attrs[i]) 187 (void) strlcat(new_rdn, mapped_attrs[i], len); 188 else 189 (void) strlcat(new_rdn, attrs[i], len); 190 191 } 192 cleanup: 193 ldap_value_free(attrs); 194 if (mapped_attrs) { 195 if (attr_mapped) { 196 for (i = 0; i < nAttr; i++) { 197 if (mapped_attrs[i]) 198 free(mapped_attrs[i]); 199 } 200 } 201 free(mapped_attrs); 202 } 203 204 return (new_rdn); 205 } 206 /* 207 * Convert attribute type in a DN that has an attribute mapping to the 208 * original mappped type. 209 * e.g 210 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm 211 * 212 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com 213 * is converted to 214 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com 215 * 216 * Input - service: e.g. hosts, passwd etc. 217 * dn: the value of a distinguished name 218 * Return - NULL: error 219 * non-NULL: A converted DN and the memory is allocated 220 */ 221 static char * 222 _cvtDN(const char *service, const char *dn) 223 { 224 char **mapped_rdns; 225 char **rdns, *new_rdn, *new_dn = NULL; 226 int nRdn = 0, i, len = 0, rdn_mapped; 227 228 if (service == NULL || dn == NULL) 229 return (NULL); 230 231 if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 232 return (NULL); 233 234 for (nRdn = 0; rdns[nRdn] != NULL; nRdn++) 235 ; 236 237 if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) { 238 ldap_value_free(rdns); 239 return (NULL); 240 } 241 242 rdn_mapped = 0; 243 /* Break down RDNs in a DN */ 244 for (i = 0; i < nRdn; i++) { 245 if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) { 246 mapped_rdns[i] = new_rdn; 247 rdn_mapped = 1; 248 } 249 } 250 if (rdn_mapped == 0) { 251 /* 252 * No RDN contains any attribute mapping. 253 * Don't bother to reconstruct DN from RDN. Copy DN directly. 254 */ 255 new_dn = strdup(dn); 256 goto cleanup; 257 } 258 /* 259 * Reconstruct dn from RDNs. 260 * Calculate the length first. 261 */ 262 for (i = 0; i < nRdn; i++) { 263 if (mapped_rdns[i]) 264 len += strlen(mapped_rdns[i]); 265 else 266 len += strlen(rdns[i]); 267 268 /* add 1 for ',' */ 269 len ++; 270 } 271 if ((new_dn = (char *)calloc(1, ++len)) == NULL) 272 goto cleanup; 273 for (i = 0; i < nRdn; i++) { 274 if (i > 0) 275 /* Add seperator */ 276 (void) strlcat(new_dn, ",", len); 277 278 if (mapped_rdns[i]) 279 (void) strlcat(new_dn, mapped_rdns[i], len); 280 else 281 (void) strlcat(new_dn, rdns[i], len); 282 283 } 284 285 cleanup: 286 ldap_value_free(rdns); 287 if (mapped_rdns) { 288 if (rdn_mapped) { 289 for (i = 0; i < nRdn; i++) { 290 if (mapped_rdns[i]) 291 free(mapped_rdns[i]); 292 } 293 } 294 free(mapped_rdns); 295 } 296 297 return (new_dn); 298 } 299 /* 300 * Convert a single ldap entry from a LDAPMessage 301 * into an ns_ldap_entry structure. 302 * Schema map the entry if specified in flags 303 */ 304 305 static int 306 __s_api_cvtEntry(LDAP *ld, const char *service, LDAPMessage *e, int flags, 307 ns_ldap_entry_t **ret, ns_ldap_error_t **error) 308 { 309 310 ns_ldap_entry_t *ep = NULL; 311 ns_ldap_attr_t **ap = NULL; 312 BerElement *ber; 313 char *attr = NULL; 314 char **vals = NULL; 315 char **mapping; 316 char *dn; 317 int nAttrs = 0; 318 int i, j, k = 0; 319 char **gecos_mapping = NULL; 320 int gecos_val_index[3] = { -1, -1, -1}; 321 char errstr[MAXERROR]; 322 int schema_mapping_existed = FALSE; 323 int gecos_mapping_existed = FALSE; 324 int gecos_attr_matched; 325 int auto_service = FALSE; 326 int rc = NS_LDAP_SUCCESS; 327 328 if (e == NULL || ret == NULL || error == NULL) 329 return (NS_LDAP_INVALID_PARAM); 330 331 *error = NULL; 332 333 ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t)); 334 if (ep == NULL) 335 return (NS_LDAP_MEMORY); 336 337 if (service != NULL && 338 (strncasecmp(service, "auto_", 5) == 0 || 339 strcasecmp(service, "automount") == 0)) 340 auto_service = TRUE; 341 /* 342 * see if schema mapping existed for the given service 343 */ 344 mapping = __ns_ldap_getOrigAttribute(service, 345 NS_HASH_SCHEMA_MAPPING_EXISTED); 346 if (mapping) { 347 schema_mapping_existed = TRUE; 348 __s_api_free2dArray(mapping); 349 mapping = NULL; 350 } else if (auto_service) { 351 /* 352 * If service == auto_* and no 353 * schema mapping found 354 * then try automount 355 * There is certain case that schema mapping exist 356 * but __ns_ldap_getOrigAttribute(service, 357 * NS_HASH_SCHEMA_MAPPING_EXISTED); 358 * returns NULL. 359 * e.g. 360 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA 361 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap 362 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject 363 * 364 * Make a check for schema_mapping_existed here 365 * so later on __s_api_convert_automountmapname won't be called 366 * unnecessarily. It is also used for attribute mapping 367 * and objectclass mapping. 368 */ 369 mapping = __ns_ldap_getOrigAttribute("automount", 370 NS_HASH_SCHEMA_MAPPING_EXISTED); 371 if (mapping) { 372 schema_mapping_existed = TRUE; 373 __s_api_free2dArray(mapping); 374 mapping = NULL; 375 } 376 } 377 378 nAttrs = 1; /* start with 1 for the DN attr */ 379 for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL; 380 attr = ldap_next_attribute(ld, e, ber)) { 381 nAttrs++; 382 ldap_memfree(attr); 383 attr = NULL; 384 } 385 ber_free(ber, 0); 386 ber = NULL; 387 388 ep->attr_count = nAttrs; 389 390 /* 391 * add 1 for "gecos" 1 to N attribute mapping, 392 * just in case it is needed. 393 * ep->attr_count will be updated later if that is true. 394 */ 395 ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1, 396 sizeof (ns_ldap_attr_t *)); 397 if (ap == NULL) { 398 __ns_ldap_freeEntry(ep); 399 ep = NULL; 400 return (NS_LDAP_MEMORY); 401 } 402 ep->attr_pair = ap; 403 404 /* DN attribute */ 405 dn = ldap_get_dn(ld, e); 406 ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t)); 407 if (ap[0] == NULL) { 408 ldap_memfree(dn); 409 dn = NULL; 410 __ns_ldap_freeEntry(ep); 411 ep = NULL; 412 return (NS_LDAP_MEMORY); 413 } 414 415 if ((ap[0]->attrname = strdup("dn")) == NULL) { 416 ldap_memfree(dn); 417 dn = NULL; 418 __ns_ldap_freeEntry(ep); 419 ep = NULL; 420 return (NS_LDAP_INVALID_PARAM); 421 } 422 ap[0]->value_count = 1; 423 if ((ap[0]->attrvalue = (char **) 424 calloc(2, sizeof (char *))) == NULL) { 425 ldap_memfree(dn); 426 dn = NULL; 427 __ns_ldap_freeEntry(ep); 428 ep = NULL; 429 return (NS_LDAP_MEMORY); 430 } 431 432 if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0)) 433 ap[0]->attrvalue[0] = _cvtDN(service, dn); 434 else 435 ap[0]->attrvalue[0] = strdup(dn); 436 437 if (ap[0]->attrvalue[0] == NULL) { 438 ldap_memfree(dn); 439 dn = NULL; 440 __ns_ldap_freeEntry(ep); 441 ep = NULL; 442 return (NS_LDAP_MEMORY); 443 } 444 ldap_memfree(dn); 445 dn = NULL; 446 447 if ((flags & NS_LDAP_NOMAP) == 0 && auto_service && 448 schema_mapping_existed) { 449 rc = __s_api_convert_automountmapname(service, 450 &ap[0]->attrvalue[0], 451 error); 452 if (rc != NS_LDAP_SUCCESS) { 453 __ns_ldap_freeEntry(ep); 454 ep = NULL; 455 return (rc); 456 } 457 } 458 459 /* other attributes */ 460 for (attr = ldap_first_attribute(ld, e, &ber), j = 1; 461 attr != NULL && j != nAttrs; 462 attr = ldap_next_attribute(ld, e, ber), j++) { 463 /* allocate new attr name */ 464 465 if ((ap[j] = (ns_ldap_attr_t *) 466 calloc(1, sizeof (ns_ldap_attr_t))) == NULL) { 467 ber_free(ber, 0); 468 ber = NULL; 469 __ns_ldap_freeEntry(ep); 470 ep = NULL; 471 if (gecos_mapping) 472 __s_api_free2dArray(gecos_mapping); 473 gecos_mapping = NULL; 474 return (NS_LDAP_MEMORY); 475 } 476 477 if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE) 478 mapping = NULL; 479 else 480 mapping = __ns_ldap_getOrigAttribute(service, attr); 481 482 if (mapping == NULL && auto_service && 483 schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0) 484 /* 485 * if service == auto_* and no schema mapping found 486 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP 487 * is not set then try automount e.g. 488 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA 489 */ 490 mapping = __ns_ldap_getOrigAttribute("automount", 491 attr); 492 493 if (mapping == NULL) { 494 if ((ap[j]->attrname = strdup(attr)) == NULL) { 495 ber_free(ber, 0); 496 ber = NULL; 497 __ns_ldap_freeEntry(ep); 498 ep = NULL; 499 if (gecos_mapping) 500 __s_api_free2dArray(gecos_mapping); 501 gecos_mapping = NULL; 502 return (NS_LDAP_MEMORY); 503 } 504 } else { 505 /* 506 * for "gecos" 1 to N mapping, 507 * do not remove the mapped attribute, 508 * just create a new gecos attribute 509 * and append it to the end of the attribute list 510 */ 511 if (strcasecmp(mapping[0], "gecos") == 0) { 512 ap[j]->attrname = strdup(attr); 513 gecos_mapping_existed = TRUE; 514 } else { 515 ap[j]->attrname = strdup(mapping[0]); 516 } 517 518 if (ap[j]->attrname == NULL) { 519 ber_free(ber, 0); 520 ber = NULL; 521 __ns_ldap_freeEntry(ep); 522 ep = NULL; 523 if (gecos_mapping) 524 __s_api_free2dArray(gecos_mapping); 525 gecos_mapping = NULL; 526 return (NS_LDAP_MEMORY); 527 } 528 /* 529 * 1 to N attribute mapping processing 530 * is only done for "gecos" 531 */ 532 533 if (strcasecmp(mapping[0], "gecos") == 0) { 534 /* 535 * get attribute mapping for "gecos", 536 * need to know the number and order of the 537 * mapped attributes 538 */ 539 if (gecos_mapping == NULL) { 540 gecos_mapping = 541 __ns_ldap_getMappedAttributes( 542 service, mapping[0]); 543 if (gecos_mapping == NULL || 544 gecos_mapping[0] == NULL) { 545 /* 546 * this should never happens, 547 * syslog the error 548 */ 549 (void) sprintf(errstr, 550 gettext( 551 "Attribute mapping " 552 "inconsistency " 553 "found for attributes " 554 "'%s' and '%s'."), 555 mapping[0], attr); 556 syslog(LOG_ERR, "libsldap: %s", 557 errstr); 558 559 ber_free(ber, 0); 560 ber = NULL; 561 __ns_ldap_freeEntry(ep); 562 ep = NULL; 563 __s_api_free2dArray(mapping); 564 mapping = NULL; 565 if (gecos_mapping) 566 __s_api_free2dArray( 567 gecos_mapping); 568 gecos_mapping = NULL; 569 return (NS_LDAP_INTERNAL); 570 } 571 } 572 573 /* 574 * is this attribute the 1st, 2nd, or 575 * 3rd attr in the mapping list? 576 */ 577 gecos_attr_matched = FALSE; 578 for (i = 0; i < 3 && gecos_mapping[i]; i++) { 579 if (gecos_mapping[i] && 580 strcasecmp(gecos_mapping[i], 581 attr) == 0) { 582 gecos_val_index[i] = j; 583 gecos_attr_matched = TRUE; 584 break; 585 } 586 } 587 if (gecos_attr_matched == FALSE) { 588 /* 589 * Not match found. 590 * This should never happens, 591 * syslog the error 592 */ 593 (void) sprintf(errstr, 594 gettext( 595 "Attribute mapping " 596 "inconsistency " 597 "found for attributes " 598 "'%s' and '%s'."), 599 mapping[0], attr); 600 syslog(LOG_ERR, "libsldap: %s", errstr); 601 602 ber_free(ber, 0); 603 ber = NULL; 604 __ns_ldap_freeEntry(ep); 605 ep = NULL; 606 __s_api_free2dArray(mapping); 607 mapping = NULL; 608 __s_api_free2dArray(gecos_mapping); 609 gecos_mapping = NULL; 610 return (NS_LDAP_INTERNAL); 611 } 612 } 613 __s_api_free2dArray(mapping); 614 mapping = NULL; 615 } 616 617 if ((vals = ldap_get_values(ld, e, attr)) != NULL) { 618 619 if ((ap[j]->value_count = 620 ldap_count_values(vals)) == 0) { 621 ldap_value_free(vals); 622 vals = NULL; 623 continue; 624 } else { 625 ap[j]->attrvalue = (char **) 626 calloc(ap[j]->value_count+1, 627 sizeof (char *)); 628 if (ap[j]->attrvalue == NULL) { 629 ber_free(ber, 0); 630 ber = NULL; 631 __ns_ldap_freeEntry(ep); 632 ep = NULL; 633 if (gecos_mapping) 634 __s_api_free2dArray( 635 gecos_mapping); 636 gecos_mapping = NULL; 637 return (NS_LDAP_MEMORY); 638 } 639 } 640 641 /* map object classes if necessary */ 642 if ((flags & NS_LDAP_NOMAP) == 0 && 643 schema_mapping_existed && ap[j]->attrname && 644 strcasecmp(ap[j]->attrname, "objectclass") == 0) { 645 for (k = 0; k < ap[j]->value_count; k++) { 646 mapping = 647 __ns_ldap_getOrigObjectClass( 648 service, vals[k]); 649 650 if (mapping == NULL && auto_service) 651 /* 652 * if service == auto_* and no 653 * schema mapping found 654 * then try automount 655 */ 656 mapping = 657 __ns_ldap_getOrigObjectClass( 658 "automount", vals[k]); 659 660 if (mapping == NULL) { 661 ap[j]->attrvalue[k] = 662 strdup(vals[k]); 663 } else { 664 ap[j]->attrvalue[k] = 665 strdup(mapping[0]); 666 __s_api_free2dArray(mapping); 667 mapping = NULL; 668 } 669 if (ap[j]->attrvalue[k] == NULL) { 670 ber_free(ber, 0); 671 ber = NULL; 672 __ns_ldap_freeEntry(ep); 673 ep = NULL; 674 if (gecos_mapping) 675 __s_api_free2dArray( 676 gecos_mapping); 677 gecos_mapping = NULL; 678 return (NS_LDAP_MEMORY); 679 } 680 } 681 } else { 682 for (k = 0; k < ap[j]->value_count; k++) { 683 if ((ap[j]->attrvalue[k] = 684 strdup(vals[k])) == NULL) { 685 ber_free(ber, 0); 686 ber = NULL; 687 __ns_ldap_freeEntry(ep); 688 ep = NULL; 689 if (gecos_mapping) 690 __s_api_free2dArray( 691 gecos_mapping); 692 gecos_mapping = NULL; 693 return (NS_LDAP_MEMORY); 694 } 695 } 696 } 697 698 ap[j]->attrvalue[k] = NULL; 699 ldap_value_free(vals); 700 vals = NULL; 701 } 702 703 ldap_memfree(attr); 704 attr = NULL; 705 } 706 707 ber_free(ber, 0); 708 ber = NULL; 709 710 if (gecos_mapping) { 711 __s_api_free2dArray(gecos_mapping); 712 gecos_mapping = NULL; 713 } 714 715 /* special processing for gecos 1 to up to 3 attribute mapping */ 716 if (schema_mapping_existed && gecos_mapping_existed) { 717 718 int f = -1; 719 720 for (i = 0; i < 3; i++) { 721 k = gecos_val_index[i]; 722 723 /* 724 * f is the index of the first returned 725 * attribute which "gecos" attribute mapped to 726 */ 727 if (k != -1 && f == -1) 728 f = k; 729 730 if (k != -1 && ap[k]->value_count > 0 && 731 ap[k]->attrvalue[0] && 732 strlen(ap[k]->attrvalue[0]) > 0) { 733 734 if (k == f) { 735 /* 736 * Create and fill in the last reserved 737 * ap with the data from the "gecos" 738 * mapping attributes 739 */ 740 ap[nAttrs] = (ns_ldap_attr_t *) 741 calloc(1, 742 sizeof (ns_ldap_attr_t)); 743 if (ap[nAttrs] == NULL) { 744 __ns_ldap_freeEntry(ep); 745 ep = NULL; 746 return (NS_LDAP_MEMORY); 747 } 748 ap[nAttrs]->attrvalue = (char **)calloc( 749 2, sizeof (char *)); 750 if (ap[nAttrs]->attrvalue == NULL) { 751 __ns_ldap_freeEntry(ep); 752 ep = NULL; 753 return (NS_LDAP_MEMORY); 754 } 755 /* add 1 more for a possible "," */ 756 ap[nAttrs]->attrvalue[0] = 757 (char *)calloc( 758 strlen(ap[f]->attrvalue[0]) + 759 2, 1); 760 if (ap[nAttrs]->attrvalue[0] == NULL) { 761 __ns_ldap_freeEntry(ep); 762 ep = NULL; 763 return (NS_LDAP_MEMORY); 764 } 765 (void) strcpy(ap[nAttrs]->attrvalue[0], 766 ap[f]->attrvalue[0]); 767 768 ap[nAttrs]->attrname = strdup("gecos"); 769 if (ap[nAttrs]->attrname == NULL) { 770 __ns_ldap_freeEntry(ep); 771 ep = NULL; 772 return (NS_LDAP_MEMORY); 773 } 774 775 ap[nAttrs]->value_count = 1; 776 ep->attr_count = nAttrs + 1; 777 778 } else { 779 char *tmp = NULL; 780 781 /* 782 * realloc to add "," and 783 * ap[k]->attrvalue[0] 784 */ 785 tmp = (char *)realloc( 786 ap[nAttrs]->attrvalue[0], 787 strlen(ap[nAttrs]-> 788 attrvalue[0]) + 789 strlen(ap[k]-> 790 attrvalue[0]) + 2); 791 if (tmp == NULL) { 792 __ns_ldap_freeEntry(ep); 793 ep = NULL; 794 return (NS_LDAP_MEMORY); 795 } 796 ap[nAttrs]->attrvalue[0] = tmp; 797 (void) strcat(ap[nAttrs]->attrvalue[0], 798 ","); 799 (void) strcat(ap[nAttrs]->attrvalue[0], 800 ap[k]->attrvalue[0]); 801 } 802 } 803 } 804 } 805 806 *ret = ep; 807 return (NS_LDAP_SUCCESS); 808 } 809 810 static int 811 __s_api_getEntry(ns_ldap_cookie_t *cookie) 812 { 813 ns_ldap_entry_t *curEntry = NULL; 814 int ret; 815 816 #ifdef DEBUG 817 (void) fprintf(stderr, "__s_api_getEntry START\n"); 818 #endif 819 820 if (cookie->resultMsg == NULL) { 821 return (NS_LDAP_INVALID_PARAM); 822 } 823 ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service, 824 cookie->resultMsg, cookie->i_flags, 825 &curEntry, &cookie->errorp); 826 if (ret != NS_LDAP_SUCCESS) { 827 return (ret); 828 } 829 830 if (cookie->result == NULL) { 831 cookie->result = (ns_ldap_result_t *) 832 calloc(1, sizeof (ns_ldap_result_t)); 833 if (cookie->result == NULL) { 834 __ns_ldap_freeEntry(curEntry); 835 curEntry = NULL; 836 return (NS_LDAP_MEMORY); 837 } 838 cookie->result->entry = curEntry; 839 cookie->nextEntry = curEntry; 840 } else { 841 cookie->nextEntry->next = curEntry; 842 cookie->nextEntry = curEntry; 843 } 844 cookie->result->entries_count++; 845 846 return (NS_LDAP_SUCCESS); 847 } 848 849 static int 850 __s_api_get_cachemgr_data(const char *type, const char *from, char **to) 851 { 852 union { 853 ldap_data_t s_d; 854 char s_b[DOORBUFFERSIZE]; 855 } space; 856 ldap_data_t *sptr; 857 int ndata; 858 int adata; 859 int rc; 860 861 #ifdef DEBUG 862 (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n"); 863 #endif 864 /* 865 * We are not going to perform DN to domain mapping 866 * in the Standalone mode 867 */ 868 if (__s_api_isStandalone()) { 869 return (-1); 870 } 871 872 if (from == NULL || from[0] == '\0' || to == NULL) 873 return (-1); 874 875 *to = NULL; 876 (void) memset(space.s_b, 0, DOORBUFFERSIZE); 877 878 space.s_d.ldap_call.ldap_callnumber = GETCACHE; 879 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname, 880 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber), 881 "%s%s%s", 882 type, 883 DOORLINESEP, 884 from); 885 ndata = sizeof (space); 886 adata = sizeof (ldap_call_t) + 887 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1; 888 sptr = &space.s_d; 889 890 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata); 891 if (rc != NS_CACHE_SUCCESS) 892 return (-1); 893 else 894 *to = strdup(sptr->ldap_ret.ldap_u.buff); 895 return (NS_LDAP_SUCCESS); 896 } 897 898 static int 899 __s_api_set_cachemgr_data(const char *type, 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 boolean_t in_quote = B_FALSE; 1075 boolean_t is_value = B_FALSE; 1076 int i, j, oc_len, len; 1077 boolean_t at_least_one = B_FALSE; 1078 filter_mapping_info_t **info, *info1; 1079 char **mapping; 1080 char *service, *filter, *err; 1081 boolean_t auto_service = B_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 == NULL) { 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 = B_TRUE; 1190 } 1191 break; 1192 case CPARATOK: 1193 /* 1194 * mark the end of the attribute value 1195 */ 1196 if (!in_quote) 1197 is_value = B_FALSE; 1198 break; 1199 case QUOTETOK: 1200 /* 1201 * switch on/off the in_quote mode 1202 */ 1203 in_quote = (in_quote == B_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, NS_LDAP_MEMORY); 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 boolean_t finished = B_FALSE; 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 NS_LDAP_MEMORY); 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 = B_TRUE; 2099 } else { 2100 if (cookie->entryCount < LISTPAGESIZE) 2101 finished = B_TRUE; 2102 else 2103 cookie->index += 2104 cookie->entryCount; 2105 } 2106 } 2107 ldap_controls_free(retCtrls); 2108 retCtrls = NULL; 2109 } else { 2110 finished = B_TRUE; 2111 } 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 NS_LDAP_MEMORY); 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 = B_TRUE; 2167 } 2168 ldap_controls_free(retCtrls); 2169 retCtrls = NULL; 2170 } else { 2171 finished = B_TRUE; 2172 } 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 NS_LDAP_MEMORY); 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 /* 2465 * If not able to reach the 2466 * server, inform the ldap 2467 * cache manager that the 2468 * server should be removed 2469 * from it's server list. 2470 * Thus, the manager will not 2471 * return this server on the next 2472 * get-server request and will 2473 * also reduce the server list 2474 * refresh TTL, so that it will 2475 * find out sooner when the server 2476 * is up again. 2477 */ 2478 if ((rc == LDAP_CONNECT_ERROR || 2479 rc == LDAP_SERVER_DOWN) && 2480 (cookie->conn_user == NULL || 2481 cookie->conn_user->conn_mt == 2482 NULL)) { 2483 ret = __s_api_removeServer( 2484 cookie->conn->serverAddr); 2485 if (ret == NS_CACHE_NOSERVER && 2486 cookie->conn_auth_type 2487 == NS_LDAP_AUTH_NONE) { 2488 /* 2489 * Couldn't remove 2490 * server from server 2491 * list. 2492 * Exit to avoid 2493 * potential infinite 2494 * loop. 2495 */ 2496 cookie->err_rc = rc; 2497 cookie->new_state = 2498 LDAP_ERROR; 2499 } 2500 if (cookie->connectionId > -1) { 2501 /* 2502 * NS_LDAP_NEW_CONN 2503 * indicates that the 2504 * connection should 2505 * be deleted, not 2506 * kept alive 2507 */ 2508 DropConnection( 2509 cookie-> 2510 connectionId, 2511 NS_LDAP_NEW_CONN); 2512 cookie->connectionId = 2513 -1; 2514 } 2515 } else if ((rc == LDAP_CONNECT_ERROR || 2516 rc == LDAP_SERVER_DOWN) && 2517 cookie->conn_user != NULL) { 2518 if (cookie-> 2519 reinit_on_retriable_err) { 2520 /* 2521 * MT connection not 2522 * usable, close it 2523 * before REINIT. 2524 * rc has already 2525 * been saved in 2526 * cookie->err_rc above. 2527 */ 2528 __s_api_conn_mt_close( 2529 cookie->conn_user, 2530 rc, 2531 &cookie->errorp); 2532 } else { 2533 /* 2534 * MT connection not 2535 * usable, close it in 2536 * the LDAP_ERROR state. 2537 * A retry will be done 2538 * next if allowed. 2539 */ 2540 cookie->err_rc = rc; 2541 cookie->new_state = 2542 LDAP_ERROR; 2543 } 2544 } 2545 break; 2546 } 2547 cookie->err_rc = rc; 2548 cookie->new_state = LDAP_ERROR; 2549 break; 2550 } 2551 cookie->new_state = cookie->next_state; 2552 break; 2553 case NEXT_RESULT: 2554 /* 2555 * Caller (e.g. __ns_ldap_list_batch_add) 2556 * does not want to block on ldap_result(). 2557 * Therefore we execute ldap_result() with 2558 * a zeroed timeval. 2559 */ 2560 if (cookie->no_wait == B_TRUE) 2561 (void) memset(&tv, 0, sizeof (tv)); 2562 else 2563 tv = cookie->search_timeout; 2564 rc = ldap_result(cookie->conn->ld, cookie->msgId, 2565 LDAP_MSG_ONE, 2566 &tv, 2567 &cookie->resultMsg); 2568 if (rc == LDAP_RES_SEARCH_RESULT) { 2569 cookie->new_state = END_RESULT; 2570 /* check and process referrals info */ 2571 if (cookie->followRef) 2572 proc_result_referrals( 2573 cookie); 2574 (void) ldap_msgfree(cookie->resultMsg); 2575 cookie->resultMsg = NULL; 2576 break; 2577 } 2578 /* handle referrals if necessary */ 2579 if (rc == LDAP_RES_SEARCH_REFERENCE) { 2580 if (cookie->followRef) 2581 proc_search_references(cookie); 2582 (void) ldap_msgfree(cookie->resultMsg); 2583 cookie->resultMsg = NULL; 2584 break; 2585 } 2586 if (rc != LDAP_RES_SEARCH_ENTRY) { 2587 switch (rc) { 2588 case 0: 2589 if (cookie->no_wait == B_TRUE) { 2590 (void) ldap_msgfree( 2591 cookie->resultMsg); 2592 cookie->resultMsg = NULL; 2593 return (cookie->new_state); 2594 } 2595 rc = LDAP_TIMEOUT; 2596 break; 2597 case -1: 2598 rc = ldap_get_lderrno(cookie->conn->ld, 2599 NULL, NULL); 2600 break; 2601 default: 2602 rc = ldap_result2error(cookie->conn->ld, 2603 cookie->resultMsg, 1); 2604 break; 2605 } 2606 if ((rc == LDAP_TIMEOUT || 2607 rc == LDAP_SERVER_DOWN) && 2608 (cookie->conn_user == NULL || 2609 cookie->conn_user->conn_mt == NULL)) { 2610 if (rc == LDAP_TIMEOUT) 2611 (void) __s_api_removeServer( 2612 cookie->conn->serverAddr); 2613 if (cookie->connectionId > -1) { 2614 DropConnection( 2615 cookie->connectionId, 2616 NS_LDAP_NEW_CONN); 2617 cookie->connectionId = -1; 2618 } 2619 cookie->err_from_result = 1; 2620 } 2621 (void) ldap_msgfree(cookie->resultMsg); 2622 cookie->resultMsg = NULL; 2623 if (rc == LDAP_BUSY || 2624 rc == LDAP_UNAVAILABLE || 2625 rc == LDAP_UNWILLING_TO_PERFORM) { 2626 if (cookie->reinit_on_retriable_err) { 2627 cookie->err_rc = rc; 2628 cookie->err_from_result = 1; 2629 cookie->new_state = REINIT; 2630 } else { 2631 cookie->new_state = 2632 NEXT_SESSION; 2633 } 2634 break; 2635 } 2636 if ((rc == LDAP_CONNECT_ERROR || 2637 rc == LDAP_SERVER_DOWN) && 2638 cookie->reinit_on_retriable_err) { 2639 ns_ldap_error_t *errorp = NULL; 2640 cookie->err_rc = rc; 2641 cookie->err_from_result = 1; 2642 cookie->new_state = REINIT; 2643 if (cookie->conn_user != NULL) 2644 __s_api_conn_mt_close( 2645 cookie->conn_user, 2646 rc, &errorp); 2647 if (errorp != NULL) { 2648 (void) __ns_ldap_freeError( 2649 &cookie->errorp); 2650 cookie->errorp = errorp; 2651 } 2652 break; 2653 } 2654 cookie->err_rc = rc; 2655 cookie->new_state = LDAP_ERROR; 2656 break; 2657 } 2658 /* else LDAP_RES_SEARCH_ENTRY */ 2659 /* get account management response control */ 2660 if (cookie->nopasswd_acct_mgmt == 1) { 2661 rc = ldap_get_entry_controls(cookie->conn->ld, 2662 cookie->resultMsg, 2663 &(cookie->resultctrl)); 2664 if (rc != LDAP_SUCCESS) { 2665 cookie->new_state = LDAP_ERROR; 2666 cookie->err_rc = rc; 2667 break; 2668 } 2669 } 2670 rc = __s_api_getEntry(cookie); 2671 (void) ldap_msgfree(cookie->resultMsg); 2672 cookie->resultMsg = NULL; 2673 if (rc != NS_LDAP_SUCCESS) { 2674 cookie->new_state = LDAP_ERROR; 2675 break; 2676 } 2677 cookie->new_state = PROCESS_RESULT; 2678 cookie->next_state = NEXT_RESULT; 2679 break; 2680 case MULTI_RESULT: 2681 if (cookie->no_wait == B_TRUE) 2682 (void) memset(&tv, 0, sizeof (tv)); 2683 else 2684 tv = cookie->search_timeout; 2685 rc = ldap_result(cookie->conn->ld, cookie->msgId, 2686 LDAP_MSG_ONE, 2687 &tv, 2688 &cookie->resultMsg); 2689 if (rc == LDAP_RES_SEARCH_RESULT) { 2690 rc = ldap_result2error(cookie->conn->ld, 2691 cookie->resultMsg, 0); 2692 if (rc == LDAP_ADMINLIMIT_EXCEEDED && 2693 cookie->listType == VLVCTRLFLAG && 2694 cookie->sortTypeTry == SSS_SINGLE_ATTR) { 2695 /* Try old "cn uid" server side sort */ 2696 cookie->sortTypeTry = SSS_CN_UID_ATTRS; 2697 cookie->new_state = NEXT_VLV; 2698 (void) ldap_msgfree(cookie->resultMsg); 2699 cookie->resultMsg = NULL; 2700 break; 2701 } 2702 if (rc != LDAP_SUCCESS) { 2703 cookie->err_rc = rc; 2704 cookie->new_state = LDAP_ERROR; 2705 (void) ldap_msgfree(cookie->resultMsg); 2706 cookie->resultMsg = NULL; 2707 break; 2708 } 2709 cookie->new_state = multi_result(cookie); 2710 (void) ldap_msgfree(cookie->resultMsg); 2711 cookie->resultMsg = NULL; 2712 break; 2713 } 2714 /* handle referrals if necessary */ 2715 if (rc == LDAP_RES_SEARCH_REFERENCE && 2716 cookie->followRef) { 2717 proc_search_references(cookie); 2718 (void) ldap_msgfree(cookie->resultMsg); 2719 cookie->resultMsg = NULL; 2720 break; 2721 } 2722 if (rc != LDAP_RES_SEARCH_ENTRY) { 2723 switch (rc) { 2724 case 0: 2725 if (cookie->no_wait == B_TRUE) { 2726 (void) ldap_msgfree( 2727 cookie->resultMsg); 2728 cookie->resultMsg = NULL; 2729 return (cookie->new_state); 2730 } 2731 rc = LDAP_TIMEOUT; 2732 break; 2733 case -1: 2734 rc = ldap_get_lderrno(cookie->conn->ld, 2735 NULL, NULL); 2736 break; 2737 default: 2738 rc = ldap_result2error(cookie->conn->ld, 2739 cookie->resultMsg, 1); 2740 break; 2741 } 2742 if ((rc == LDAP_TIMEOUT || 2743 rc == LDAP_SERVER_DOWN) && 2744 (cookie->conn_user == NULL || 2745 cookie->conn_user->conn_mt == NULL)) { 2746 if (rc == LDAP_TIMEOUT) 2747 (void) __s_api_removeServer( 2748 cookie->conn->serverAddr); 2749 if (cookie->connectionId > -1) { 2750 DropConnection( 2751 cookie->connectionId, 2752 NS_LDAP_NEW_CONN); 2753 cookie->connectionId = -1; 2754 } 2755 cookie->err_from_result = 1; 2756 } 2757 (void) ldap_msgfree(cookie->resultMsg); 2758 cookie->resultMsg = NULL; 2759 if (rc == LDAP_BUSY || 2760 rc == LDAP_UNAVAILABLE || 2761 rc == LDAP_UNWILLING_TO_PERFORM) { 2762 if (cookie->reinit_on_retriable_err) { 2763 cookie->err_rc = rc; 2764 cookie->err_from_result = 1; 2765 cookie->new_state = REINIT; 2766 } else { 2767 cookie->new_state = 2768 NEXT_SESSION; 2769 } 2770 break; 2771 } 2772 2773 if ((rc == LDAP_CONNECT_ERROR || 2774 rc == LDAP_SERVER_DOWN) && 2775 cookie->reinit_on_retriable_err) { 2776 ns_ldap_error_t *errorp = NULL; 2777 cookie->err_rc = rc; 2778 cookie->err_from_result = 1; 2779 cookie->new_state = REINIT; 2780 if (cookie->conn_user != NULL) 2781 __s_api_conn_mt_close( 2782 cookie->conn_user, 2783 rc, &errorp); 2784 if (errorp != NULL) { 2785 (void) __ns_ldap_freeError( 2786 &cookie->errorp); 2787 cookie->errorp = errorp; 2788 } 2789 break; 2790 } 2791 cookie->err_rc = rc; 2792 cookie->new_state = LDAP_ERROR; 2793 break; 2794 } 2795 /* else LDAP_RES_SEARCH_ENTRY */ 2796 cookie->entryCount++; 2797 rc = __s_api_getEntry(cookie); 2798 (void) ldap_msgfree(cookie->resultMsg); 2799 cookie->resultMsg = NULL; 2800 if (rc != NS_LDAP_SUCCESS) { 2801 cookie->new_state = LDAP_ERROR; 2802 break; 2803 } 2804 /* 2805 * If VLV search was successfull save the server 2806 * side sort type tried. 2807 */ 2808 if (cookie->listType == VLVCTRLFLAG) 2809 update_srvsidesort_type(cookie->service, 2810 cookie->sortTypeTry); 2811 2812 cookie->new_state = PROCESS_RESULT; 2813 cookie->next_state = MULTI_RESULT; 2814 break; 2815 case PROCESS_RESULT: 2816 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */ 2817 if (cookie->use_usercb && cookie->callback) { 2818 rc = 0; 2819 for (nextEntry = cookie->result->entry; 2820 nextEntry != NULL; 2821 nextEntry = nextEntry->next) { 2822 rc = (*cookie->callback)(nextEntry, 2823 cookie->userdata); 2824 2825 if (rc == NS_LDAP_CB_DONE) { 2826 /* cb doesn't want any more data */ 2827 rc = NS_LDAP_PARTIAL; 2828 cookie->err_rc = rc; 2829 break; 2830 } else if (rc != NS_LDAP_CB_NEXT) { 2831 /* invalid return code */ 2832 rc = NS_LDAP_OP_FAILED; 2833 cookie->err_rc = rc; 2834 break; 2835 } 2836 } 2837 (void) __ns_ldap_freeResult(&cookie->result); 2838 cookie->result = NULL; 2839 } 2840 if (rc != 0) { 2841 cookie->new_state = EXIT; 2842 break; 2843 } 2844 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */ 2845 cookie->new_state = cookie->next_state; 2846 break; 2847 case END_PROCESS_RESULT: 2848 cookie->new_state = cookie->next_state; 2849 break; 2850 case END_RESULT: 2851 /* 2852 * XXX DO WE NEED THIS CASE? 2853 * if (search is complete) { 2854 * cookie->new_state = EXIT; 2855 * } else 2856 */ 2857 /* 2858 * entering referral mode if necessary 2859 */ 2860 if (cookie->followRef && cookie->reflist) 2861 cookie->new_state = 2862 NEXT_REFERRAL; 2863 else 2864 cookie->new_state = 2865 NEXT_SEARCH_DESCRIPTOR; 2866 break; 2867 case NEXT_REFERRAL: 2868 /* get next referral info */ 2869 if (cookie->refpos == NULL) 2870 cookie->refpos = 2871 cookie->reflist; 2872 else 2873 cookie->refpos = 2874 cookie->refpos->next; 2875 /* check see if done with all referrals */ 2876 if (cookie->refpos != NULL) { 2877 cookie->new_state = 2878 GET_REFERRAL_SESSION; 2879 } else { 2880 __s_api_deleteRefInfo(cookie->reflist); 2881 cookie->reflist = NULL; 2882 cookie->new_state = 2883 NEXT_SEARCH_DESCRIPTOR; 2884 if (cookie->conn_user != NULL) 2885 cookie->conn_user->referral = B_FALSE; 2886 } 2887 break; 2888 case GET_REFERRAL_SESSION: 2889 if (get_referral_session(cookie) < 0) { 2890 cookie->new_state = EXIT; 2891 } else { 2892 cookie->new_state = NEXT_SEARCH; 2893 } 2894 break; 2895 case LDAP_ERROR: 2896 rc_save = cookie->err_rc; 2897 if (cookie->err_from_result) { 2898 if (cookie->err_rc == LDAP_SERVER_DOWN) { 2899 (void) sprintf(errstr, 2900 gettext("LDAP ERROR (%d): " 2901 "Error occurred during" 2902 " receiving results. " 2903 "Connection to server lost."), 2904 cookie->err_rc); 2905 } else if (cookie->err_rc == LDAP_TIMEOUT) { 2906 (void) sprintf(errstr, 2907 gettext("LDAP ERROR (%d): " 2908 "Error occurred during" 2909 " receiving results. %s" 2910 "."), cookie->err_rc, 2911 ldap_err2string( 2912 cookie->err_rc)); 2913 } 2914 } else { 2915 (void) sprintf(errstr, 2916 gettext("LDAP ERROR (%d): %s."), 2917 cookie->err_rc, 2918 ldap_err2string(cookie->err_rc)); 2919 } 2920 err = strdup(errstr); 2921 if (cookie->err_from_result) { 2922 if (cookie->err_rc == LDAP_SERVER_DOWN) { 2923 MKERROR(LOG_INFO, *errorp, 2924 cookie->err_rc, err, 2925 NS_LDAP_MEMORY); 2926 } else { 2927 MKERROR(LOG_WARNING, *errorp, 2928 cookie->err_rc, err, 2929 NS_LDAP_MEMORY); 2930 } 2931 } else { 2932 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, 2933 err, NS_LDAP_MEMORY); 2934 } 2935 cookie->err_rc = NS_LDAP_INTERNAL; 2936 cookie->errorp = *errorp; 2937 if (cookie->conn_user != NULL) { 2938 if (rc_save == LDAP_SERVER_DOWN || 2939 rc_save == LDAP_CONNECT_ERROR) { 2940 /* 2941 * MT connection is not usable, 2942 * close it. 2943 */ 2944 __s_api_conn_mt_close(cookie->conn_user, 2945 rc_save, &cookie->errorp); 2946 return (ERROR); 2947 } 2948 } 2949 return (ERROR); 2950 default: 2951 case ERROR: 2952 (void) sprintf(errstr, 2953 gettext("Internal State machine exit (%d).\n"), 2954 cookie->state); 2955 err = strdup(errstr); 2956 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, 2957 NS_LDAP_MEMORY); 2958 cookie->err_rc = NS_LDAP_INTERNAL; 2959 cookie->errorp = *errorp; 2960 return (ERROR); 2961 } 2962 2963 if (cookie->conn_user != NULL && 2964 cookie->conn_user->bad_mt_conn == B_TRUE) { 2965 __s_api_conn_mt_close(cookie->conn_user, 0, NULL); 2966 cookie->err_rc = cookie->conn_user->ns_rc; 2967 cookie->errorp = cookie->conn_user->ns_error; 2968 cookie->conn_user->ns_error = NULL; 2969 return (ERROR); 2970 } 2971 2972 if (cycle == ONE_STEP) { 2973 return (cookie->new_state); 2974 } 2975 cookie->state = cookie->new_state; 2976 } 2977 /*NOTREACHED*/ 2978 #if 0 2979 (void) sprintf(errstr, 2980 gettext("Unexpected State machine error.\n")); 2981 err = strdup(errstr); 2982 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NS_LDAP_MEMORY); 2983 cookie->err_rc = NS_LDAP_INTERNAL; 2984 cookie->errorp = *errorp; 2985 return (ERROR); 2986 #endif 2987 } 2988 2989 /* 2990 * For a lookup of shadow data, if shadow update is enabled, 2991 * check the calling process' privilege to ensure it's 2992 * allowed to perform such operation. 2993 */ 2994 static int 2995 check_shadow(ns_ldap_cookie_t *cookie, const char *service) 2996 { 2997 char errstr[MAXERROR]; 2998 char *err; 2999 boolean_t priv; 3000 /* caller */ 3001 priv_set_t *ps; 3002 /* zone */ 3003 priv_set_t *zs; 3004 3005 /* 3006 * If service is "shadow", we may need 3007 * to use privilege credentials. 3008 */ 3009 if ((strcmp(service, "shadow") == 0) && 3010 __ns_ldap_is_shadow_update_enabled()) { 3011 /* 3012 * Since we release admin credentials after 3013 * connection is closed and we do not cache 3014 * them, we allow any root or all zone 3015 * privilege process to read shadow data. 3016 */ 3017 priv = (geteuid() == 0); 3018 if (!priv) { 3019 /* caller */ 3020 ps = priv_allocset(); 3021 3022 (void) getppriv(PRIV_EFFECTIVE, ps); 3023 zs = priv_str_to_set("zone", ",", NULL); 3024 priv = priv_isequalset(ps, zs); 3025 priv_freeset(ps); 3026 priv_freeset(zs); 3027 } 3028 if (!priv) { 3029 (void) sprintf(errstr, 3030 gettext("Permission denied")); 3031 err = strdup(errstr); 3032 if (err == NULL) 3033 return (NS_LDAP_MEMORY); 3034 MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err, 3035 NS_LDAP_MEMORY); 3036 return (NS_LDAP_INTERNAL); 3037 } 3038 cookie->i_flags |= NS_LDAP_READ_SHADOW; 3039 /* 3040 * We do not want to reuse connection (hence 3041 * keep it open) with admin credentials. 3042 * If NS_LDAP_KEEP_CONN is set, reject the 3043 * request. 3044 */ 3045 if (cookie->i_flags & NS_LDAP_KEEP_CONN) 3046 return (NS_LDAP_INVALID_PARAM); 3047 cookie->i_flags |= NS_LDAP_NEW_CONN; 3048 } 3049 3050 return (NS_LDAP_SUCCESS); 3051 } 3052 3053 /* 3054 * internal function for __ns_ldap_list 3055 */ 3056 static int 3057 ldap_list( 3058 ns_ldap_list_batch_t *batch, 3059 const char *service, 3060 const char *filter, 3061 const char *sortattr, 3062 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 3063 char **realfilter, const void *userdata), 3064 const char * const *attribute, 3065 const ns_cred_t *auth, 3066 const int flags, 3067 ns_ldap_result_t **rResult, /* return result entries */ 3068 ns_ldap_error_t **errorp, 3069 int *rcp, 3070 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata), 3071 const void *userdata, ns_conn_user_t *conn_user) 3072 { 3073 ns_ldap_cookie_t *cookie; 3074 ns_ldap_search_desc_t **sdlist = NULL; 3075 ns_ldap_search_desc_t *dptr; 3076 ns_ldap_error_t *error = NULL; 3077 char **dns = NULL; 3078 int scope; 3079 int rc; 3080 int from_result; 3081 3082 *errorp = NULL; 3083 *rResult = NULL; 3084 *rcp = NS_LDAP_SUCCESS; 3085 3086 /* 3087 * Sanity check - NS_LDAP_READ_SHADOW is for our 3088 * own internal use. 3089 */ 3090 if (flags & NS_LDAP_READ_SHADOW) 3091 return (NS_LDAP_INVALID_PARAM); 3092 3093 /* Initialize State machine cookie */ 3094 cookie = init_search_state_machine(); 3095 if (cookie == NULL) { 3096 *rcp = NS_LDAP_MEMORY; 3097 return (NS_LDAP_MEMORY); 3098 } 3099 cookie->conn_user = conn_user; 3100 3101 /* see if need to follow referrals */ 3102 rc = __s_api_toFollowReferrals(flags, 3103 &cookie->followRef, errorp); 3104 if (rc != NS_LDAP_SUCCESS) { 3105 delete_search_cookie(cookie); 3106 *rcp = rc; 3107 return (rc); 3108 } 3109 3110 /* get the service descriptor - or create a default one */ 3111 rc = __s_api_get_SSD_from_SSDtoUse_service(service, 3112 &sdlist, &error); 3113 if (rc != NS_LDAP_SUCCESS) { 3114 delete_search_cookie(cookie); 3115 *errorp = error; 3116 *rcp = rc; 3117 return (rc); 3118 } 3119 3120 if (sdlist == NULL) { 3121 /* Create default service Desc */ 3122 sdlist = (ns_ldap_search_desc_t **)calloc(2, 3123 sizeof (ns_ldap_search_desc_t *)); 3124 if (sdlist == NULL) { 3125 delete_search_cookie(cookie); 3126 cookie = NULL; 3127 *rcp = NS_LDAP_MEMORY; 3128 return (NS_LDAP_MEMORY); 3129 } 3130 dptr = (ns_ldap_search_desc_t *) 3131 calloc(1, sizeof (ns_ldap_search_desc_t)); 3132 if (dptr == NULL) { 3133 free(sdlist); 3134 delete_search_cookie(cookie); 3135 cookie = NULL; 3136 *rcp = NS_LDAP_MEMORY; 3137 return (NS_LDAP_MEMORY); 3138 } 3139 sdlist[0] = dptr; 3140 3141 /* default base */ 3142 rc = __s_api_getDNs(&dns, service, &cookie->errorp); 3143 if (rc != NS_LDAP_SUCCESS) { 3144 if (dns) { 3145 __s_api_free2dArray(dns); 3146 dns = NULL; 3147 } 3148 *errorp = cookie->errorp; 3149 cookie->errorp = NULL; 3150 delete_search_cookie(cookie); 3151 cookie = NULL; 3152 *rcp = rc; 3153 return (rc); 3154 } 3155 dptr->basedn = strdup(dns[0]); 3156 __s_api_free2dArray(dns); 3157 dns = NULL; 3158 3159 /* default scope */ 3160 scope = 0; 3161 rc = __s_api_getSearchScope(&scope, &cookie->errorp); 3162 dptr->scope = scope; 3163 } 3164 3165 cookie->sdlist = sdlist; 3166 3167 /* 3168 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set 3169 */ 3170 if (flags & NS_LDAP_PAGE_CTRL) 3171 cookie->use_paging = TRUE; 3172 else 3173 cookie->use_paging = FALSE; 3174 3175 /* Set up other arguments */ 3176 cookie->userdata = userdata; 3177 if (init_filter_cb != NULL) { 3178 cookie->init_filter_cb = init_filter_cb; 3179 cookie->use_filtercb = 1; 3180 } 3181 if (callback != NULL) { 3182 cookie->callback = callback; 3183 cookie->use_usercb = 1; 3184 } 3185 3186 /* check_shadow() may add extra value to cookie->i_flags */ 3187 cookie->i_flags = flags; 3188 if (service) { 3189 cookie->service = strdup(service); 3190 if (cookie->service == NULL) { 3191 delete_search_cookie(cookie); 3192 cookie = NULL; 3193 *rcp = NS_LDAP_MEMORY; 3194 return (NS_LDAP_MEMORY); 3195 } 3196 3197 /* 3198 * If given, use the credential given by the caller, and 3199 * skip the credential check required for shadow update. 3200 */ 3201 if (auth == NULL) { 3202 rc = check_shadow(cookie, service); 3203 if (rc != NS_LDAP_SUCCESS) { 3204 *errorp = cookie->errorp; 3205 cookie->errorp = NULL; 3206 delete_search_cookie(cookie); 3207 cookie = NULL; 3208 *rcp = rc; 3209 return (rc); 3210 } 3211 } 3212 } 3213 3214 cookie->i_filter = strdup(filter); 3215 cookie->i_attr = attribute; 3216 cookie->i_auth = auth; 3217 cookie->i_sortattr = sortattr; 3218 3219 if (batch != NULL) { 3220 cookie->batch = batch; 3221 cookie->reinit_on_retriable_err = B_TRUE; 3222 cookie->no_wait = B_TRUE; 3223 (void) search_state_machine(cookie, INIT, 0); 3224 cookie->no_wait = B_FALSE; 3225 rc = cookie->err_rc; 3226 3227 if (rc == NS_LDAP_SUCCESS) { 3228 /* 3229 * Here rc == NS_LDAP_SUCCESS means that the state 3230 * machine init'ed successfully. The actual status 3231 * of the search will be determined by 3232 * __ns_ldap_list_batch_end(). Add the cookie to our 3233 * batch. 3234 */ 3235 cookie->caller_result = rResult; 3236 cookie->caller_errorp = errorp; 3237 cookie->caller_rc = rcp; 3238 cookie->next_cookie_in_batch = batch->cookie_list; 3239 batch->cookie_list = cookie; 3240 batch->nactive++; 3241 return (rc); 3242 } 3243 /* 3244 * If state machine init failed then copy error to the caller 3245 * and delete the cookie. 3246 */ 3247 } else { 3248 (void) search_state_machine(cookie, INIT, 0); 3249 } 3250 3251 /* Copy results back to user */ 3252 rc = cookie->err_rc; 3253 if (rc != NS_LDAP_SUCCESS) { 3254 if (conn_user != NULL && conn_user->ns_error != NULL) { 3255 *errorp = conn_user->ns_error; 3256 conn_user->ns_error = NULL; 3257 } else { 3258 *errorp = cookie->errorp; 3259 } 3260 } 3261 *rResult = cookie->result; 3262 from_result = cookie->err_from_result; 3263 3264 cookie->errorp = NULL; 3265 cookie->result = NULL; 3266 delete_search_cookie(cookie); 3267 cookie = NULL; 3268 3269 if (from_result == 0 && *rResult == NULL) 3270 rc = NS_LDAP_NOTFOUND; 3271 *rcp = rc; 3272 return (rc); 3273 } 3274 3275 3276 /* 3277 * __ns_ldap_list performs one or more LDAP searches to a given 3278 * directory server using service search descriptors and schema 3279 * mapping as appropriate. The operation may be retried a 3280 * couple of times in error situations. 3281 */ 3282 int 3283 __ns_ldap_list( 3284 const char *service, 3285 const char *filter, 3286 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 3287 char **realfilter, const void *userdata), 3288 const char * const *attribute, 3289 const ns_cred_t *auth, 3290 const int flags, 3291 ns_ldap_result_t **rResult, /* return result entries */ 3292 ns_ldap_error_t **errorp, 3293 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata), 3294 const void *userdata) 3295 { 3296 int mod_flags; 3297 /* 3298 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not 3299 * support this. If you want to use this option call the API 3300 * __ns_ldap_list_sort() with has the sort attribute. 3301 */ 3302 mod_flags = flags & (~NS_LDAP_PAGE_CTRL); 3303 3304 return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb, 3305 attribute, auth, mod_flags, rResult, errorp, 3306 callback, userdata)); 3307 } 3308 3309 /* 3310 * __ns_ldap_list_sort performs one or more LDAP searches to a given 3311 * directory server using service search descriptors and schema 3312 * mapping as appropriate. The operation may be retried a 3313 * couple of times in error situations. 3314 */ 3315 int 3316 __ns_ldap_list_sort( 3317 const char *service, 3318 const char *filter, 3319 const char *sortattr, 3320 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 3321 char **realfilter, const void *userdata), 3322 const char * const *attribute, 3323 const ns_cred_t *auth, 3324 const int flags, 3325 ns_ldap_result_t **rResult, /* return result entries */ 3326 ns_ldap_error_t **errorp, 3327 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata), 3328 const void *userdata) 3329 { 3330 ns_conn_user_t *cu = NULL; 3331 int try_cnt = 0; 3332 int rc = NS_LDAP_SUCCESS, trc; 3333 3334 for (;;) { 3335 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH, 3336 &try_cnt, &rc, errorp) == 0) 3337 break; 3338 rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb, 3339 attribute, auth, flags, rResult, errorp, &trc, callback, 3340 userdata, cu); 3341 } 3342 3343 return (rc); 3344 } 3345 3346 /* 3347 * Create and initialize batch for native LDAP lookups 3348 */ 3349 int 3350 __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch) 3351 { 3352 *batch = calloc(1, sizeof (ns_ldap_list_batch_t)); 3353 if (*batch == NULL) 3354 return (NS_LDAP_MEMORY); 3355 return (NS_LDAP_SUCCESS); 3356 } 3357 3358 3359 /* 3360 * Add a LDAP search request to the batch. 3361 */ 3362 int 3363 __ns_ldap_list_batch_add( 3364 ns_ldap_list_batch_t *batch, 3365 const char *service, 3366 const char *filter, 3367 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 3368 char **realfilter, const void *userdata), 3369 const char * const *attribute, 3370 const ns_cred_t *auth, 3371 const int flags, 3372 ns_ldap_result_t **rResult, /* return result entries */ 3373 ns_ldap_error_t **errorp, 3374 int *rcp, 3375 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata), 3376 const void *userdata) 3377 { 3378 ns_conn_user_t *cu; 3379 int rc; 3380 int mod_flags; 3381 3382 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0); 3383 if (cu == NULL) { 3384 if (rcp != NULL) 3385 *rcp = NS_LDAP_MEMORY; 3386 return (NS_LDAP_MEMORY); 3387 } 3388 3389 /* 3390 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not 3391 * support this. 3392 */ 3393 mod_flags = flags & (~NS_LDAP_PAGE_CTRL); 3394 3395 rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute, 3396 auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu); 3397 3398 /* 3399 * Free the conn_user if the cookie was not batched. If the cookie 3400 * was batched then __ns_ldap_list_batch_end or release will free the 3401 * conn_user. The batch API instructs the search_state_machine 3402 * to reinit and retry (max 3 times) on retriable LDAP errors. 3403 */ 3404 if (rc != NS_LDAP_SUCCESS && cu != NULL) { 3405 if (cu->conn_mt != NULL) 3406 __s_api_conn_mt_return(cu); 3407 __s_api_conn_user_free(cu); 3408 } 3409 return (rc); 3410 } 3411 3412 3413 /* 3414 * Free batch. 3415 */ 3416 void 3417 __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch) 3418 { 3419 ns_ldap_cookie_t *c, *next; 3420 3421 for (c = batch->cookie_list; c != NULL; c = next) { 3422 next = c->next_cookie_in_batch; 3423 if (c->conn_user != NULL) { 3424 if (c->conn_user->conn_mt != NULL) 3425 __s_api_conn_mt_return(c->conn_user); 3426 __s_api_conn_user_free(c->conn_user); 3427 c->conn_user = NULL; 3428 } 3429 delete_search_cookie(c); 3430 } 3431 free(batch); 3432 } 3433 3434 #define LD_USING_STATE(st) \ 3435 ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT)) 3436 3437 /* 3438 * Process batch. Everytime this function is called it selects an 3439 * active cookie from the batch and single steps through the 3440 * search_state_machine for the selected cookie. If lookup associated 3441 * with the cookie is complete (success or error) then the cookie is 3442 * removed from the batch and its memory freed. 3443 * 3444 * Returns 1 (if batch still has active cookies) 3445 * 0 (if batch has no more active cookies) 3446 * -1 (on errors, *rcp will contain the error code) 3447 * 3448 * The caller should call this function in a loop as long as it returns 1 3449 * to process all the requests added to the batch. The results (and errors) 3450 * will be available in the locations provided by the caller at the time of 3451 * __ns_ldap_list_batch_add(). 3452 */ 3453 static 3454 int 3455 __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp) 3456 { 3457 ns_ldap_cookie_t *c, *ptr, **prev; 3458 ns_state_t state; 3459 ns_ldap_error_t *errorp = NULL; 3460 int rc; 3461 3462 /* Check if are already done */ 3463 if (batch->nactive == 0) 3464 return (0); 3465 3466 /* Get the next cookie from the batch */ 3467 c = (batch->next_cookie == NULL) ? 3468 batch->cookie_list : batch->next_cookie; 3469 3470 batch->next_cookie = c->next_cookie_in_batch; 3471 3472 /* 3473 * Checks the status of the cookie's connection if it needs 3474 * to use that connection for ldap_search_ext or ldap_result. 3475 * If the connection is no longer good but worth retrying 3476 * then reinit the search_state_machine for this cookie 3477 * starting from the first search descriptor. REINIT will 3478 * clear any leftover results if max retries have not been 3479 * reached and redo the search (which may also involve 3480 * following referrals again). 3481 * 3482 * Note that each cookie in the batch will make this 3483 * determination when it reaches one of the LD_USING_STATES. 3484 */ 3485 if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) { 3486 rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp); 3487 if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE || 3488 rc == LDAP_UNWILLING_TO_PERFORM) { 3489 if (errorp != NULL) { 3490 (void) __ns_ldap_freeError(&c->errorp); 3491 c->errorp = errorp; 3492 } 3493 c->new_state = REINIT; 3494 } else if (rc == LDAP_CONNECT_ERROR || 3495 rc == LDAP_SERVER_DOWN) { 3496 if (errorp != NULL) { 3497 (void) __ns_ldap_freeError(&c->errorp); 3498 c->errorp = errorp; 3499 } 3500 c->new_state = REINIT; 3501 /* 3502 * MT connection is not usable, 3503 * close it before REINIT. 3504 */ 3505 __s_api_conn_mt_close( 3506 c->conn_user, rc, NULL); 3507 } else if (rc != NS_LDAP_SUCCESS) { 3508 if (rcp != NULL) 3509 *rcp = rc; 3510 *c->caller_result = NULL; 3511 *c->caller_errorp = errorp; 3512 *c->caller_rc = rc; 3513 return (-1); 3514 } 3515 } 3516 3517 for (;;) { 3518 /* Single step through the search_state_machine */ 3519 state = search_state_machine(c, c->new_state, ONE_STEP); 3520 switch (state) { 3521 case LDAP_ERROR: 3522 (void) search_state_machine(c, state, ONE_STEP); 3523 (void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP); 3524 /* FALLTHROUGH */ 3525 case ERROR: 3526 case EXIT: 3527 *c->caller_result = c->result; 3528 *c->caller_errorp = c->errorp; 3529 *c->caller_rc = 3530 (c->result == NULL && c->err_from_result == 0) 3531 ? NS_LDAP_NOTFOUND : c->err_rc; 3532 c->result = NULL; 3533 c->errorp = NULL; 3534 /* Remove the cookie from the batch */ 3535 ptr = batch->cookie_list; 3536 prev = &batch->cookie_list; 3537 while (ptr != NULL) { 3538 if (ptr == c) { 3539 *prev = ptr->next_cookie_in_batch; 3540 break; 3541 } 3542 prev = &ptr->next_cookie_in_batch; 3543 ptr = ptr->next_cookie_in_batch; 3544 } 3545 /* Delete cookie and decrement active cookie count */ 3546 if (c->conn_user != NULL) { 3547 if (c->conn_user->conn_mt != NULL) 3548 __s_api_conn_mt_return(c->conn_user); 3549 __s_api_conn_user_free(c->conn_user); 3550 c->conn_user = NULL; 3551 } 3552 delete_search_cookie(c); 3553 batch->nactive--; 3554 break; 3555 case NEXT_RESULT: 3556 case MULTI_RESULT: 3557 /* 3558 * This means that search_state_machine needs to do 3559 * another ldap_result() for the cookie in question. 3560 * We only do at most one ldap_result() per call in 3561 * this function and therefore we return. This allows 3562 * the caller to process results from other cookies 3563 * in the batch without getting tied up on just one 3564 * cookie. 3565 */ 3566 break; 3567 default: 3568 /* 3569 * This includes states that follow NEXT_RESULT or 3570 * MULTI_RESULT such as PROCESS_RESULT and 3571 * END_PROCESS_RESULT. We continue processing 3572 * this cookie till we reach either the error, exit 3573 * or the result states. 3574 */ 3575 continue; 3576 } 3577 break; 3578 } 3579 3580 /* Return 0 if no more cookies left otherwise 1 */ 3581 return ((batch->nactive > 0) ? 1 : 0); 3582 } 3583 3584 3585 /* 3586 * Process all the active cookies in the batch and when none 3587 * remains finalize the batch. 3588 */ 3589 int 3590 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch) 3591 { 3592 int rc = NS_LDAP_SUCCESS; 3593 while (__ns_ldap_list_batch_process(batch, &rc) > 0) 3594 ; 3595 __ns_ldap_list_batch_release(batch); 3596 return (rc); 3597 } 3598 3599 typedef struct lookup_data { 3600 const char *lkd_dn; 3601 const char *lkd_service; 3602 const char *lkd_filter; 3603 const ns_cred_t *lkd_cred; 3604 ns_conn_user_t *lkd_user; 3605 } lookup_data_t; 3606 3607 /* 3608 * This creates a service search descriptor that can be used to 3609 * retrieve a specific DN by using the DN as the basedn with a search 3610 * scope of 'base'. We don't use any service SSDs in this instance since 3611 * they are intended to search specific locations/subtrees and filter the 3612 * results, while here we are wanting to retrieve a specific entry. 3613 */ 3614 static int 3615 lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp) 3616 { 3617 ns_ldap_search_desc_t *dptr; 3618 3619 *descpp = NULL; 3620 3621 dptr = calloc(1, sizeof (ns_ldap_search_desc_t)); 3622 if (dptr == NULL) 3623 return (NS_LDAP_MEMORY); 3624 3625 dptr->basedn = strdup(dn_data->lkd_dn); 3626 dptr->scope = NS_LDAP_SCOPE_BASE; 3627 dptr->filter = strdup(UIDFILTER); 3628 3629 if (dptr->basedn == NULL || dptr->filter == NULL) { 3630 __ns_ldap_freeASearchDesc(dptr); 3631 return (NS_LDAP_MEMORY); 3632 } 3633 3634 *descpp = dptr; 3635 return (NS_LDAP_SUCCESS); 3636 } 3637 3638 static int 3639 lookup_dn(lookup_data_t *dn_data, const char **attrs, 3640 ns_ldap_result_t **resultp, ns_ldap_error_t **errorp) 3641 { 3642 ns_ldap_cookie_t *cookie; 3643 int rc = 0; 3644 int flags = 0; 3645 3646 *errorp = NULL; 3647 *resultp = NULL; 3648 3649 if (dn_data == NULL || dn_data->lkd_dn == NULL || 3650 dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL) 3651 return (NS_LDAP_INVALID_PARAM); 3652 3653 cookie = init_search_state_machine(); 3654 if (cookie == NULL) 3655 return (NS_LDAP_MEMORY); 3656 3657 rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp); 3658 if (rc != NS_LDAP_SUCCESS) 3659 goto out; 3660 3661 /* 1 for SSD, 1 for terminating NULL */ 3662 cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *)); 3663 if (cookie->sdlist == NULL) { 3664 rc = NS_LDAP_MEMORY; 3665 goto out; 3666 } 3667 3668 rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]); 3669 if (rc != NS_LDAP_SUCCESS) 3670 goto out; 3671 3672 if (dn_data->lkd_service != NULL) { 3673 /* 3674 * If a service was specified, set that on the cookie so 3675 * that search_state_machine() will properly map 3676 * attributes and objectclasses. 3677 */ 3678 cookie->service = strdup(dn_data->lkd_service); 3679 if (cookie->service == NULL) { 3680 rc = NS_LDAP_MEMORY; 3681 goto out; 3682 } 3683 } 3684 3685 cookie->i_attr = attrs; 3686 cookie->i_auth = dn_data->lkd_cred; 3687 cookie->i_flags = 0; 3688 cookie->i_filter = strdup(dn_data->lkd_filter); 3689 if (cookie->i_filter == NULL) { 3690 rc = NS_LDAP_MEMORY; 3691 goto out; 3692 } 3693 3694 /* 3695 * Actually perform the search. The return value is only used when 3696 * iterating through multiple results. Since we are searching with 3697 * a scope of base, we will always get at most one result entry, 3698 * we ignore the return value and look at err_rc to determine if 3699 * there were any errors. 3700 */ 3701 (void) search_state_machine(cookie, INIT, 0); 3702 rc = cookie->err_rc; 3703 3704 if (rc != NS_LDAP_SUCCESS) { 3705 ns_conn_user_t *user = dn_data->lkd_user; 3706 3707 if (user != NULL && user->ns_error != NULL) { 3708 *errorp = user->ns_error; 3709 user->ns_error = NULL; 3710 } else { 3711 *errorp = cookie->errorp; 3712 cookie->errorp = NULL; 3713 } 3714 } else if (cookie->result != NULL) { 3715 *resultp = cookie->result; 3716 cookie->result = NULL; 3717 } else { 3718 rc = NS_LDAP_NOTFOUND; 3719 } 3720 3721 out: 3722 delete_search_cookie(cookie); 3723 return (rc); 3724 } 3725 3726 /* 3727 * find_domainname performs one or more LDAP searches to 3728 * find the value of the nisdomain attribute associated with 3729 * the input DN (with no retry). 3730 */ 3731 3732 static int 3733 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred, 3734 ns_ldap_error_t **errorp, ns_conn_user_t *conn_user) 3735 { 3736 lookup_data_t ldata; 3737 ns_ldap_result_t *result; 3738 char **value; 3739 int rc; 3740 3741 *domainname = NULL; 3742 *errorp = NULL; 3743 3744 ldata.lkd_dn = dn; 3745 ldata.lkd_service = NULL; 3746 ldata.lkd_filter = _NIS_FILTER; 3747 ldata.lkd_cred = cred; 3748 ldata.lkd_user = conn_user; 3749 3750 rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp); 3751 if (rc != NS_LDAP_SUCCESS) 3752 return (rc); 3753 3754 value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN); 3755 3756 if (value != NULL && value[0] != NULL) { 3757 *domainname = strdup(value[0]); 3758 if (*domainname == NULL) 3759 rc = NS_LDAP_MEMORY; 3760 } else { 3761 rc = NS_LDAP_NOTFOUND; 3762 } 3763 3764 (void) __ns_ldap_freeResult(&result); 3765 return (rc); 3766 } 3767 3768 /* 3769 * __s_api_find_domainname performs one or more LDAP searches to 3770 * find the value of the nisdomain attribute associated with 3771 * the input DN (with retry). 3772 */ 3773 3774 static int 3775 __s_api_find_domainname(const char *dn, char **domainname, 3776 const ns_cred_t *cred, ns_ldap_error_t **errorp) 3777 { 3778 ns_conn_user_t *cu = NULL; 3779 int try_cnt = 0; 3780 int rc = NS_LDAP_SUCCESS; 3781 3782 for (;;) { 3783 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH, 3784 &try_cnt, &rc, errorp) == 0) 3785 break; 3786 rc = find_domainname(dn, domainname, cred, errorp, cu); 3787 } 3788 3789 return (rc); 3790 } 3791 3792 static int 3793 firstEntry( 3794 const char *service, 3795 const char *filter, 3796 const char *sortattr, 3797 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 3798 char **realfilter, const void *userdata), 3799 const char * const *attribute, 3800 const ns_cred_t *auth, 3801 const int flags, 3802 void **vcookie, 3803 ns_ldap_result_t **result, 3804 ns_ldap_error_t ** errorp, 3805 const void *userdata, 3806 ns_conn_user_t *conn_user) 3807 { 3808 ns_ldap_cookie_t *cookie = NULL; 3809 ns_ldap_error_t *error = NULL; 3810 ns_state_t state; 3811 ns_ldap_search_desc_t **sdlist; 3812 ns_ldap_search_desc_t *dptr; 3813 char **dns = NULL; 3814 int scope; 3815 int rc; 3816 3817 *errorp = NULL; 3818 *result = NULL; 3819 3820 /* 3821 * Sanity check - NS_LDAP_READ_SHADOW is for our 3822 * own internal use. 3823 */ 3824 if (flags & NS_LDAP_READ_SHADOW) 3825 return (NS_LDAP_INVALID_PARAM); 3826 3827 /* get the service descriptor - or create a default one */ 3828 rc = __s_api_get_SSD_from_SSDtoUse_service(service, 3829 &sdlist, &error); 3830 if (rc != NS_LDAP_SUCCESS) { 3831 *errorp = error; 3832 return (rc); 3833 } 3834 if (sdlist == NULL) { 3835 /* Create default service Desc */ 3836 sdlist = (ns_ldap_search_desc_t **)calloc(2, 3837 sizeof (ns_ldap_search_desc_t *)); 3838 if (sdlist == NULL) { 3839 return (NS_LDAP_MEMORY); 3840 } 3841 dptr = (ns_ldap_search_desc_t *) 3842 calloc(1, sizeof (ns_ldap_search_desc_t)); 3843 if (dptr == NULL) { 3844 free(sdlist); 3845 return (NS_LDAP_MEMORY); 3846 } 3847 sdlist[0] = dptr; 3848 3849 /* default base */ 3850 rc = __s_api_getDNs(&dns, service, &error); 3851 if (rc != NS_LDAP_SUCCESS) { 3852 if (dns) { 3853 __s_api_free2dArray(dns); 3854 dns = NULL; 3855 } 3856 if (sdlist) { 3857 (void) __ns_ldap_freeSearchDescriptors( 3858 &sdlist); 3859 3860 sdlist = NULL; 3861 } 3862 *errorp = error; 3863 return (rc); 3864 } 3865 dptr->basedn = strdup(dns[0]); 3866 __s_api_free2dArray(dns); 3867 dns = NULL; 3868 3869 /* default scope */ 3870 scope = 0; 3871 cookie = init_search_state_machine(); 3872 if (cookie == NULL) { 3873 if (sdlist) { 3874 (void) __ns_ldap_freeSearchDescriptors(&sdlist); 3875 sdlist = NULL; 3876 } 3877 return (NS_LDAP_MEMORY); 3878 } 3879 rc = __s_api_getSearchScope(&scope, &cookie->errorp); 3880 dptr->scope = scope; 3881 } 3882 3883 /* Initialize State machine cookie */ 3884 if (cookie == NULL) 3885 cookie = init_search_state_machine(); 3886 if (cookie == NULL) { 3887 if (sdlist) { 3888 (void) __ns_ldap_freeSearchDescriptors(&sdlist); 3889 sdlist = NULL; 3890 } 3891 return (NS_LDAP_MEMORY); 3892 } 3893 3894 /* identify self as a getent user */ 3895 cookie->conn_user = conn_user; 3896 3897 cookie->sdlist = sdlist; 3898 3899 /* see if need to follow referrals */ 3900 rc = __s_api_toFollowReferrals(flags, 3901 &cookie->followRef, errorp); 3902 if (rc != NS_LDAP_SUCCESS) { 3903 delete_search_cookie(cookie); 3904 return (rc); 3905 } 3906 3907 /* 3908 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set 3909 */ 3910 if (flags & NS_LDAP_NO_PAGE_CTRL) 3911 cookie->use_paging = FALSE; 3912 else 3913 cookie->use_paging = TRUE; 3914 3915 /* Set up other arguments */ 3916 cookie->userdata = userdata; 3917 if (init_filter_cb != NULL) { 3918 cookie->init_filter_cb = init_filter_cb; 3919 cookie->use_filtercb = 1; 3920 } 3921 cookie->use_usercb = 0; 3922 /* check_shadow() may add extra value to cookie->i_flags */ 3923 cookie->i_flags = flags; 3924 if (service) { 3925 cookie->service = strdup(service); 3926 if (cookie->service == NULL) { 3927 delete_search_cookie(cookie); 3928 return (NS_LDAP_MEMORY); 3929 } 3930 3931 /* 3932 * If given, use the credential given by the caller, and 3933 * skip the credential check required for shadow update. 3934 */ 3935 if (auth == NULL) { 3936 rc = check_shadow(cookie, service); 3937 if (rc != NS_LDAP_SUCCESS) { 3938 *errorp = cookie->errorp; 3939 cookie->errorp = NULL; 3940 delete_search_cookie(cookie); 3941 cookie = NULL; 3942 return (rc); 3943 } 3944 } 3945 } 3946 3947 cookie->i_filter = strdup(filter); 3948 cookie->i_attr = attribute; 3949 cookie->i_sortattr = sortattr; 3950 cookie->i_auth = auth; 3951 3952 state = INIT; 3953 for (;;) { 3954 state = search_state_machine(cookie, state, ONE_STEP); 3955 switch (state) { 3956 case PROCESS_RESULT: 3957 *result = cookie->result; 3958 cookie->result = NULL; 3959 *vcookie = (void *)cookie; 3960 return (NS_LDAP_SUCCESS); 3961 case LDAP_ERROR: 3962 state = search_state_machine(cookie, state, ONE_STEP); 3963 state = search_state_machine(cookie, CLEAR_RESULTS, 3964 ONE_STEP); 3965 /* FALLTHROUGH */ 3966 case ERROR: 3967 rc = cookie->err_rc; 3968 if (conn_user != NULL && conn_user->ns_error != NULL) { 3969 *errorp = conn_user->ns_error; 3970 conn_user->ns_error = NULL; 3971 } else { 3972 *errorp = cookie->errorp; 3973 cookie->errorp = NULL; 3974 } 3975 delete_search_cookie(cookie); 3976 return (rc); 3977 case EXIT: 3978 rc = cookie->err_rc; 3979 if (rc != NS_LDAP_SUCCESS) { 3980 *errorp = cookie->errorp; 3981 cookie->errorp = NULL; 3982 } else { 3983 rc = NS_LDAP_NOTFOUND; 3984 } 3985 3986 delete_search_cookie(cookie); 3987 return (rc); 3988 3989 default: 3990 break; 3991 } 3992 } 3993 } 3994 3995 int 3996 __ns_ldap_firstEntry( 3997 const char *service, 3998 const char *filter, 3999 const char *vlv_sort, 4000 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc, 4001 char **realfilter, const void *userdata), 4002 const char * const *attribute, 4003 const ns_cred_t *auth, 4004 const int flags, 4005 void **vcookie, 4006 ns_ldap_result_t **result, 4007 ns_ldap_error_t ** errorp, 4008 const void *userdata) 4009 { 4010 ns_conn_user_t *cu = NULL; 4011 int try_cnt = 0; 4012 int rc = NS_LDAP_SUCCESS; 4013 4014 for (;;) { 4015 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT, 4016 &try_cnt, &rc, errorp) == 0) 4017 break; 4018 rc = firstEntry(service, filter, vlv_sort, init_filter_cb, 4019 attribute, auth, flags, vcookie, result, errorp, userdata, 4020 cu); 4021 } 4022 return (rc); 4023 } 4024 4025 /*ARGSUSED2*/ 4026 int 4027 __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result, 4028 ns_ldap_error_t ** errorp) 4029 { 4030 ns_ldap_cookie_t *cookie; 4031 ns_state_t state; 4032 int rc; 4033 4034 cookie = (ns_ldap_cookie_t *)vcookie; 4035 cookie->result = NULL; 4036 *result = NULL; 4037 4038 if (cookie->conn_user != NULL) { 4039 rc = __s_api_setup_getnext(cookie->conn_user, 4040 &cookie->err_rc, errorp); 4041 if (rc != NS_LDAP_SUCCESS) 4042 return (rc); 4043 } 4044 4045 state = END_PROCESS_RESULT; 4046 for (;;) { 4047 state = search_state_machine(cookie, state, ONE_STEP); 4048 switch (state) { 4049 case PROCESS_RESULT: 4050 *result = cookie->result; 4051 cookie->result = NULL; 4052 return (NS_LDAP_SUCCESS); 4053 case LDAP_ERROR: 4054 state = search_state_machine(cookie, state, ONE_STEP); 4055 state = search_state_machine(cookie, CLEAR_RESULTS, 4056 ONE_STEP); 4057 /* FALLTHROUGH */ 4058 case ERROR: 4059 rc = cookie->err_rc; 4060 *errorp = cookie->errorp; 4061 cookie->errorp = NULL; 4062 return (rc); 4063 case EXIT: 4064 return (NS_LDAP_SUCCESS); 4065 } 4066 } 4067 } 4068 4069 int 4070 __ns_ldap_endEntry( 4071 void **vcookie, 4072 ns_ldap_error_t ** errorp) 4073 { 4074 ns_ldap_cookie_t *cookie; 4075 int rc; 4076 4077 if (*vcookie == NULL) 4078 return (NS_LDAP_INVALID_PARAM); 4079 4080 cookie = (ns_ldap_cookie_t *)(*vcookie); 4081 cookie->result = NULL; 4082 4083 /* Complete search */ 4084 rc = search_state_machine(cookie, CLEAR_RESULTS, 0); 4085 4086 /* Copy results back to user */ 4087 rc = cookie->err_rc; 4088 if (rc != NS_LDAP_SUCCESS) 4089 *errorp = cookie->errorp; 4090 4091 cookie->errorp = NULL; 4092 if (cookie->conn_user != NULL) { 4093 if (cookie->conn_user->conn_mt != NULL) 4094 __s_api_conn_mt_return(cookie->conn_user); 4095 __s_api_conn_user_free(cookie->conn_user); 4096 } 4097 delete_search_cookie(cookie); 4098 cookie = NULL; 4099 *vcookie = NULL; 4100 4101 return (rc); 4102 } 4103 4104 4105 int 4106 __ns_ldap_freeResult(ns_ldap_result_t **result) 4107 { 4108 4109 ns_ldap_entry_t *curEntry = NULL; 4110 ns_ldap_entry_t *delEntry = NULL; 4111 int i; 4112 ns_ldap_result_t *res = *result; 4113 4114 #ifdef DEBUG 4115 (void) fprintf(stderr, "__ns_ldap_freeResult START\n"); 4116 #endif 4117 if (res == NULL) 4118 return (NS_LDAP_INVALID_PARAM); 4119 4120 if (res->entry != NULL) 4121 curEntry = res->entry; 4122 4123 for (i = 0; i < res->entries_count; i++) { 4124 if (curEntry != NULL) { 4125 delEntry = curEntry; 4126 curEntry = curEntry->next; 4127 __ns_ldap_freeEntry(delEntry); 4128 } 4129 } 4130 4131 free(res); 4132 *result = NULL; 4133 return (NS_LDAP_SUCCESS); 4134 } 4135 4136 int 4137 __ns_ldap_auth(const ns_cred_t *auth, const int flags, ns_ldap_error_t **errorp, 4138 LDAPControl **serverctrls __unused, LDAPControl **clientctrls __unused) 4139 { 4140 4141 ConnectionID connectionId = -1; 4142 Connection *conp; 4143 int rc = 0; 4144 int do_not_fail_if_new_pwd_reqd = 0; 4145 int nopasswd_acct_mgmt = 0; 4146 ns_conn_user_t *conn_user; 4147 4148 4149 #ifdef DEBUG 4150 (void) fprintf(stderr, "__ns_ldap_auth START\n"); 4151 #endif 4152 4153 *errorp = NULL; 4154 if (auth == NULL) 4155 return (NS_LDAP_INVALID_PARAM); 4156 4157 conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH, 4158 NULL, B_FALSE); 4159 4160 rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN, 4161 auth, &connectionId, &conp, errorp, 4162 do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt, 4163 conn_user); 4164 4165 if (conn_user != NULL) 4166 __s_api_conn_user_free(conn_user); 4167 4168 if (rc == NS_LDAP_OP_FAILED && *errorp) 4169 (void) __ns_ldap_freeError(errorp); 4170 4171 if (connectionId > -1) 4172 DropConnection(connectionId, flags); 4173 return (rc); 4174 } 4175 4176 char ** 4177 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname) 4178 { 4179 int i; 4180 4181 if (entry == NULL) 4182 return (NULL); 4183 for (i = 0; i < entry->attr_count; i++) { 4184 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0) 4185 return (entry->attr_pair[i]->attrvalue); 4186 } 4187 return (NULL); 4188 } 4189 4190 ns_ldap_attr_t * 4191 __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname) 4192 { 4193 int i; 4194 4195 if (entry == NULL) 4196 return (NULL); 4197 for (i = 0; i < entry->attr_count; i++) { 4198 if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0) 4199 return (entry->attr_pair[i]); 4200 } 4201 return (NULL); 4202 } 4203 4204 4205 int 4206 __ns_ldap_uid2dn(const char *uid, char **userDN, const ns_cred_t *cred, 4207 ns_ldap_error_t **errorp) 4208 { 4209 ns_ldap_result_t *result = NULL; 4210 char *filter, *userdata; 4211 char errstr[MAXERROR]; 4212 char **value; 4213 int rc = 0; 4214 int i; 4215 size_t len; 4216 4217 *errorp = NULL; 4218 *userDN = NULL; 4219 if ((uid == NULL) || (uid[0] == '\0')) 4220 return (NS_LDAP_INVALID_PARAM); 4221 4222 for (i = 0; uid[i] != '\0'; i++) { 4223 if (uid[i] == '=') { 4224 *userDN = strdup(uid); 4225 return (NS_LDAP_SUCCESS); 4226 } 4227 } 4228 for (i = 0; (uid[i] != '\0') && isdigit(uid[i]); i++) 4229 ; 4230 if (uid[i] == '\0') { 4231 len = strlen(UIDNUMFILTER) + strlen(uid) + 1; 4232 filter = malloc(len); 4233 if (filter == NULL) { 4234 *userDN = NULL; 4235 return (NS_LDAP_MEMORY); 4236 } 4237 (void) snprintf(filter, len, UIDNUMFILTER, uid); 4238 4239 len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1; 4240 userdata = malloc(len); 4241 if (userdata == NULL) { 4242 *userDN = NULL; 4243 free(filter); 4244 return (NS_LDAP_MEMORY); 4245 } 4246 (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid); 4247 } else { 4248 len = strlen(UIDFILTER) + strlen(uid) + 1; 4249 filter = malloc(len); 4250 if (filter == NULL) { 4251 *userDN = NULL; 4252 return (NS_LDAP_MEMORY); 4253 } 4254 (void) snprintf(filter, len, UIDFILTER, uid); 4255 4256 len = strlen(UIDFILTER_SSD) + strlen(uid) + 1; 4257 userdata = malloc(len); 4258 if (userdata == NULL) { 4259 *userDN = NULL; 4260 free(filter); 4261 return (NS_LDAP_MEMORY); 4262 } 4263 (void) snprintf(userdata, len, UIDFILTER_SSD, uid); 4264 } 4265 4266 /* 4267 * we want to retrieve the DN as it appears in LDAP 4268 * hence the use of NS_LDAP_NOT_CVT_DN in flags 4269 */ 4270 rc = __ns_ldap_list("passwd", filter, 4271 __s_api_merge_SSD_filter, 4272 NULL, cred, NS_LDAP_NOT_CVT_DN, 4273 &result, errorp, NULL, 4274 userdata); 4275 free(filter); 4276 filter = NULL; 4277 free(userdata); 4278 userdata = NULL; 4279 if (rc != NS_LDAP_SUCCESS) { 4280 if (result) { 4281 (void) __ns_ldap_freeResult(&result); 4282 result = NULL; 4283 } 4284 return (rc); 4285 } 4286 if (result->entries_count > 1) { 4287 (void) __ns_ldap_freeResult(&result); 4288 result = NULL; 4289 *userDN = NULL; 4290 (void) sprintf(errstr, 4291 gettext("Too many entries are returned for %s"), uid); 4292 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr), 4293 NS_LDAP_MEMORY); 4294 return (NS_LDAP_INTERNAL); 4295 } 4296 4297 value = __ns_ldap_getAttr(result->entry, "dn"); 4298 *userDN = strdup(value[0]); 4299 (void) __ns_ldap_freeResult(&result); 4300 result = NULL; 4301 return (NS_LDAP_SUCCESS); 4302 } 4303 4304 #define _P_UID "uid" 4305 static const char *dn2uid_attrs[] = { 4306 _P_CN, 4307 _P_UID, 4308 (char *)NULL 4309 }; 4310 4311 int 4312 __ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred, 4313 ns_ldap_error_t **errorp) 4314 { 4315 lookup_data_t ldata; 4316 ns_ldap_result_t *result; 4317 char **value; 4318 int rc; 4319 4320 *errorp = NULL; 4321 *userIDp = NULL; 4322 if ((dn == NULL) || (dn[0] == '\0')) 4323 return (NS_LDAP_INVALID_PARAM); 4324 4325 /* 4326 * Many LDAP servers do not support using the dn in a search 4327 * filter. As a result, we unfortunately cannot use __ns_ldap_list() 4328 * to lookup the DN. Instead we perform a search with the baseDN 4329 * being the DN we are looking for with a scope of 'base' to 4330 * return the entry, as this should be supported by all LDAP servers. 4331 */ 4332 ldata.lkd_dn = dn; 4333 4334 /* 4335 * Since we are looking up a user account by its DN, use the attribute 4336 * and objectclass mappings (if present) for the passwd service. 4337 */ 4338 ldata.lkd_service = "passwd"; 4339 ldata.lkd_filter = UIDDNFILTER; 4340 ldata.lkd_cred = cred; 4341 ldata.lkd_user = NULL; 4342 4343 rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp); 4344 if (rc != NS_LDAP_SUCCESS) 4345 return (rc); 4346 4347 value = __ns_ldap_getAttr(result->entry, _P_UID); 4348 if (value != NULL && value[0] != NULL) { 4349 *userIDp = strdup(value[0]); 4350 if (*userIDp == NULL) 4351 rc = NS_LDAP_MEMORY; 4352 } else { 4353 rc = NS_LDAP_NOTFOUND; 4354 } 4355 4356 (void) __ns_ldap_freeResult(&result); 4357 return (rc); 4358 } 4359 4360 int 4361 __ns_ldap_host2dn(const char *host, const char *domain, char **hostDN, 4362 const ns_cred_t *cred, ns_ldap_error_t **errorp) 4363 { 4364 ns_ldap_result_t *result = NULL; 4365 char *filter, *userdata; 4366 char errstr[MAXERROR]; 4367 char **value; 4368 int rc; 4369 size_t len; 4370 4371 /* 4372 * XXX 4373 * the domain parameter needs to be used in case domain is not local, 4374 * if this routine is to support multi domain setups, it needs lots 4375 * of work... 4376 */ 4377 *errorp = NULL; 4378 *hostDN = NULL; 4379 if ((host == NULL) || (host[0] == '\0')) 4380 return (NS_LDAP_INVALID_PARAM); 4381 4382 len = strlen(HOSTFILTER) + strlen(host) + 1; 4383 filter = malloc(len); 4384 if (filter == NULL) { 4385 return (NS_LDAP_MEMORY); 4386 } 4387 (void) snprintf(filter, len, HOSTFILTER, host); 4388 4389 len = strlen(HOSTFILTER_SSD) + strlen(host) + 1; 4390 userdata = malloc(len); 4391 if (userdata == NULL) { 4392 free(filter); 4393 return (NS_LDAP_MEMORY); 4394 } 4395 (void) snprintf(userdata, len, HOSTFILTER_SSD, host); 4396 4397 /* 4398 * we want to retrieve the DN as it appears in LDAP 4399 * hence the use of NS_LDAP_NOT_CVT_DN in flags 4400 */ 4401 rc = __ns_ldap_list("hosts", filter, 4402 __s_api_merge_SSD_filter, 4403 NULL, cred, NS_LDAP_NOT_CVT_DN, &result, 4404 errorp, NULL, 4405 userdata); 4406 free(filter); 4407 filter = NULL; 4408 free(userdata); 4409 userdata = NULL; 4410 if (rc != NS_LDAP_SUCCESS) { 4411 if (result) { 4412 (void) __ns_ldap_freeResult(&result); 4413 result = NULL; 4414 } 4415 return (rc); 4416 } 4417 4418 if (result->entries_count > 1) { 4419 (void) __ns_ldap_freeResult(&result); 4420 result = NULL; 4421 *hostDN = NULL; 4422 (void) sprintf(errstr, 4423 gettext("Too many entries are returned for %s"), host); 4424 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr), 4425 NS_LDAP_MEMORY); 4426 return (NS_LDAP_INTERNAL); 4427 } 4428 4429 value = __ns_ldap_getAttr(result->entry, "dn"); 4430 *hostDN = strdup(value[0]); 4431 (void) __ns_ldap_freeResult(&result); 4432 result = NULL; 4433 return (NS_LDAP_SUCCESS); 4434 } 4435 4436 int 4437 __ns_ldap_dn2domain(const char *dn, char **domain, const ns_cred_t *cred, 4438 ns_ldap_error_t **errorp) 4439 { 4440 int rc, pnum, i, j, len = 0; 4441 char *newdn, **rdns = NULL; 4442 char **dns, *dn1; 4443 4444 *errorp = NULL; 4445 4446 if (domain == NULL) 4447 return (NS_LDAP_INVALID_PARAM); 4448 else 4449 *domain = NULL; 4450 4451 if ((dn == NULL) || (dn[0] == '\0')) 4452 return (NS_LDAP_INVALID_PARAM); 4453 4454 /* 4455 * break dn into rdns 4456 */ 4457 dn1 = strdup(dn); 4458 if (dn1 == NULL) 4459 return (NS_LDAP_MEMORY); 4460 rdns = ldap_explode_dn(dn1, 0); 4461 free(dn1); 4462 if (rdns == NULL || *rdns == NULL) 4463 return (NS_LDAP_INVALID_PARAM); 4464 4465 for (i = 0; rdns[i]; i++) 4466 len += strlen(rdns[i]) + 1; 4467 pnum = i; 4468 4469 newdn = (char *)malloc(len + 1); 4470 dns = (char **)calloc(pnum, sizeof (char *)); 4471 if (newdn == NULL || dns == NULL) { 4472 if (newdn) 4473 free(newdn); 4474 ldap_value_free(rdns); 4475 return (NS_LDAP_MEMORY); 4476 } 4477 4478 /* construct a semi-normalized dn, newdn */ 4479 *newdn = '\0'; 4480 for (i = 0; rdns[i]; i++) { 4481 dns[i] = newdn + strlen(newdn); 4482 (void) strcat(newdn, 4483 __s_api_remove_rdn_space(rdns[i])); 4484 (void) strcat(newdn, ","); 4485 } 4486 /* remove the last ',' */ 4487 newdn[strlen(newdn) - 1] = '\0'; 4488 ldap_value_free(rdns); 4489 4490 /* 4491 * loop and find the domain name associated with newdn, 4492 * removing rdn one by one from left to right 4493 */ 4494 for (i = 0; i < pnum; i++) { 4495 4496 if (*errorp) 4497 (void) __ns_ldap_freeError(errorp); 4498 4499 /* 4500 * try cache manager first 4501 */ 4502 rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN, 4503 dns[i], domain); 4504 if (rc != NS_LDAP_SUCCESS) { 4505 /* 4506 * try ldap server second 4507 */ 4508 rc = __s_api_find_domainname(dns[i], domain, 4509 cred, errorp); 4510 } else { 4511 /* 4512 * skip the last one, 4513 * since it is already cached by ldap_cachemgr 4514 */ 4515 i--; 4516 } 4517 if (rc == NS_LDAP_SUCCESS) { 4518 if (__s_api_nscd_proc()) { 4519 /* 4520 * If it's nscd, ask cache manager to save the 4521 * dn to domain mapping(s) 4522 */ 4523 for (j = 0; j <= i; j++) { 4524 (void) __s_api_set_cachemgr_data( 4525 NS_CACHE_DN2DOMAIN, 4526 dns[j], 4527 *domain); 4528 } 4529 } 4530 break; 4531 } 4532 } 4533 4534 free(dns); 4535 free(newdn); 4536 if (rc != NS_LDAP_SUCCESS) 4537 rc = NS_LDAP_NOTFOUND; 4538 return (rc); 4539 } 4540 4541 int 4542 __ns_ldap_getServiceAuthMethods(const char *service, ns_auth_t ***auth, 4543 ns_ldap_error_t **errorp) 4544 { 4545 char errstr[MAXERROR]; 4546 int rc, i; 4547 boolean_t done = B_FALSE; 4548 int slen; 4549 void **param; 4550 char **sam, *srv, *send; 4551 ns_auth_t **authpp = NULL, *ap; 4552 int cnt, max; 4553 ns_config_t *cfg; 4554 ns_ldap_error_t *error = NULL; 4555 4556 if (errorp == NULL) 4557 return (NS_LDAP_INVALID_PARAM); 4558 *errorp = NULL; 4559 4560 if ((service == NULL) || (service[0] == '\0') || 4561 (auth == NULL)) 4562 return (NS_LDAP_INVALID_PARAM); 4563 4564 *auth = NULL; 4565 rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, ¶m, &error); 4566 if (rc != NS_LDAP_SUCCESS || param == NULL) { 4567 *errorp = error; 4568 return (rc); 4569 } 4570 sam = (char **)param; 4571 4572 cfg = __s_api_get_default_config(); 4573 cnt = 0; 4574 4575 slen = strlen(service); 4576 4577 for (; *sam; sam++) { 4578 srv = *sam; 4579 if (strncasecmp(service, srv, slen) != 0) 4580 continue; 4581 srv += slen; 4582 if (*srv != COLONTOK) 4583 continue; 4584 send = srv; 4585 srv++; 4586 for (max = 1; (send = strchr(++send, SEMITOK)) != NULL; max++) 4587 ; 4588 authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *)); 4589 if (authpp == NULL) { 4590 (void) __ns_ldap_freeParam(¶m); 4591 __s_api_release_config(cfg); 4592 return (NS_LDAP_MEMORY); 4593 } 4594 while (!done) { 4595 send = strchr(srv, SEMITOK); 4596 if (send != NULL) { 4597 *send = '\0'; 4598 send++; 4599 } 4600 i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P); 4601 if (i == -1) { 4602 (void) __ns_ldap_freeParam(¶m); 4603 (void) sprintf(errstr, 4604 gettext("Unsupported " 4605 "serviceAuthenticationMethod: %s.\n"), srv); 4606 MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX, 4607 strdup(errstr), NS_LDAP_MEMORY); 4608 __s_api_release_config(cfg); 4609 return (NS_LDAP_CONFIG); 4610 } 4611 ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i); 4612 if (ap == NULL) { 4613 (void) __ns_ldap_freeParam(¶m); 4614 __s_api_release_config(cfg); 4615 return (NS_LDAP_MEMORY); 4616 } 4617 authpp[cnt++] = ap; 4618 if (send == NULL) 4619 done = B_TRUE; 4620 else 4621 srv = send; 4622 } 4623 } 4624 4625 *auth = authpp; 4626 (void) __ns_ldap_freeParam(¶m); 4627 __s_api_release_config(cfg); 4628 return (NS_LDAP_SUCCESS); 4629 } 4630 4631 /* 4632 * This routine is called when certain scenario occurs 4633 * e.g. 4634 * service == auto_home 4635 * SSD = automount: ou = mytest, 4636 * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA 4637 * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap 4638 * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject 4639 * 4640 * The automountMapName is prepended implicitely but is mapped 4641 * to AAA. So dn could appers as 4642 * dn: AAA=auto_home,ou=bar,dc=foo,dc=com 4643 * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com 4644 * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com 4645 * in the directory. 4646 * This function is called to covert the mapped attr back to 4647 * orig attr when the entries are searched and returned 4648 */ 4649 4650 int 4651 __s_api_convert_automountmapname(const char *service, char **dn, 4652 ns_ldap_error_t **errp) 4653 { 4654 4655 char **mapping = NULL; 4656 char *mapped_attr = NULL; 4657 char *automountmapname = "automountMapName"; 4658 char *buffer = NULL; 4659 int rc = NS_LDAP_SUCCESS; 4660 char errstr[MAXERROR]; 4661 4662 /* 4663 * dn is an input/out parameter, check it first 4664 */ 4665 4666 if (service == NULL || dn == NULL || *dn == NULL) 4667 return (NS_LDAP_INVALID_PARAM); 4668 4669 /* 4670 * Check to see if there is a mapped attribute for auto_xxx 4671 */ 4672 4673 mapping = __ns_ldap_getMappedAttributes(service, automountmapname); 4674 4675 /* 4676 * if no mapped attribute for auto_xxx, try automount 4677 */ 4678 4679 if (mapping == NULL) { 4680 mapping = __ns_ldap_getMappedAttributes( 4681 "automount", automountmapname); 4682 } 4683 4684 /* 4685 * if no mapped attribute is found, return SUCCESS (no op) 4686 */ 4687 4688 if (mapping == NULL) 4689 return (NS_LDAP_SUCCESS); 4690 4691 /* 4692 * if the mapped attribute is found and attr is not empty, 4693 * copy it 4694 */ 4695 4696 if (mapping[0] != NULL) { 4697 mapped_attr = strdup(mapping[0]); 4698 __s_api_free2dArray(mapping); 4699 if (mapped_attr == NULL) { 4700 return (NS_LDAP_MEMORY); 4701 } 4702 } else { 4703 __s_api_free2dArray(mapping); 4704 4705 (void) snprintf(errstr, (2 * MAXERROR), 4706 gettext("Attribute nisMapName is mapped to an " 4707 "empty string.\n")); 4708 4709 MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX, 4710 strdup(errstr), NS_LDAP_MEMORY); 4711 4712 return (NS_LDAP_CONFIG); 4713 } 4714 4715 /* 4716 * Locate the mapped attribute in the dn 4717 * and replace it if it exists 4718 */ 4719 4720 rc = __s_api_replace_mapped_attr_in_dn( 4721 (const char *) automountmapname, (const char *) mapped_attr, 4722 (const char *) *dn, &buffer); 4723 4724 /* clean up */ 4725 4726 free(mapped_attr); 4727 4728 /* 4729 * If mapped attr is found(buffer != NULL) 4730 * a new dn is returned 4731 * If no mapped attribute is in dn, 4732 * return NS_LDAP_SUCCESS (no op) 4733 * If no memory, 4734 * return NS_LDAP_MEMORY (no op) 4735 */ 4736 4737 if (buffer != NULL) { 4738 free(*dn); 4739 *dn = buffer; 4740 } 4741 4742 return (rc); 4743 } 4744 4745 /* 4746 * If the mapped attr is found in the dn, 4747 * return NS_LDAP_SUCCESS and a new_dn. 4748 * If no mapped attr is found, 4749 * return NS_LDAP_SUCCESS and *new_dn == NULL 4750 * If there is not enough memory, 4751 * return NS_LDAP_MEMORY and *new_dn == NULL 4752 */ 4753 4754 int 4755 __s_api_replace_mapped_attr_in_dn(const char *orig_attr, 4756 const char *mapped_attr, const char *dn, char **new_dn) 4757 { 4758 4759 char **dnArray = NULL; 4760 char *cur = NULL, *start = NULL; 4761 int i = 0; 4762 boolean_t found = B_FALSE; 4763 int len = 0, orig_len = 0, mapped_len = 0; 4764 int dn_len = 0, tmp_len = 0; 4765 4766 *new_dn = NULL; 4767 4768 /* 4769 * seperate dn into individual componets 4770 * e.g. 4771 * "automountKey=user_01" , "automountMapName_test=auto_home", ... 4772 */ 4773 dnArray = ldap_explode_dn(dn, 0); 4774 4775 /* 4776 * This will find "mapped attr=value" in dn. 4777 * It won't find match if mapped attr appears 4778 * in the value. 4779 */ 4780 for (i = 0; dnArray[i] != NULL; i++) { 4781 /* 4782 * This function is called when reading from 4783 * the directory so assume each component has "=". 4784 * Any ill formatted dn should be rejected 4785 * before adding to the directory 4786 */ 4787 cur = strchr(dnArray[i], '='); 4788 *cur = '\0'; 4789 if (strcasecmp(mapped_attr, dnArray[i]) == 0) 4790 found = B_TRUE; 4791 *cur = '='; 4792 if (found) 4793 break; 4794 } 4795 4796 if (!found) { 4797 __s_api_free2dArray(dnArray); 4798 *new_dn = NULL; 4799 return (NS_LDAP_SUCCESS); 4800 } 4801 /* 4802 * The new length is *dn length + (difference between 4803 * orig attr and mapped attr) + 1 ; 4804 * e.g. 4805 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com 4806 * ==> 4807 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com 4808 */ 4809 mapped_len = strlen(mapped_attr); 4810 orig_len = strlen(orig_attr); 4811 dn_len = strlen(dn); 4812 len = dn_len + orig_len - mapped_len + 1; 4813 *new_dn = (char *)calloc(1, len); 4814 if (*new_dn == NULL) { 4815 __s_api_free2dArray(dnArray); 4816 return (NS_LDAP_MEMORY); 4817 } 4818 4819 /* 4820 * Locate the mapped attr in the dn. 4821 * Use dnArray[i] instead of mapped_attr 4822 * because mapped_attr could appear in 4823 * the value 4824 */ 4825 4826 cur = strstr(dn, dnArray[i]); 4827 __s_api_free2dArray(dnArray); 4828 /* copy the portion before mapped attr in dn */ 4829 start = *new_dn; 4830 tmp_len = cur - dn; 4831 (void) memcpy(start, dn, tmp_len); 4832 4833 /* 4834 * Copy the orig_attr. e.g. automountMapName 4835 * This replaces mapped attr with orig attr 4836 */ 4837 start = start + (cur - dn); /* move cursor in buffer */ 4838 (void) memcpy(start, orig_attr, orig_len); 4839 4840 /* 4841 * Copy the portion after mapped attr in dn 4842 */ 4843 cur = cur + mapped_len; /* move cursor in dn */ 4844 start = start + orig_len; /* move cursor in buffer */ 4845 (void) strcpy(start, cur); 4846 4847 return (NS_LDAP_SUCCESS); 4848 } 4849 4850 /* 4851 * Validate Filter functions 4852 */ 4853 4854 /* ***** Start of modified libldap.so.5 filter parser ***** */ 4855 4856 /* filter parsing routine forward references */ 4857 static int adj_filter_list(char *str); 4858 static int adj_simple_filter(char *str); 4859 static int unescape_filterval(char *val); 4860 static int hexchar2int(char c); 4861 static int adj_substring_filter(char *val); 4862 4863 4864 /* 4865 * assumes string manipulation is in-line 4866 * and all strings are sufficient in size 4867 * return value is the position after 'c' 4868 */ 4869 4870 static char * 4871 resync_str(char *str, char *next, char c) 4872 { 4873 char *ret; 4874 4875 ret = str + strlen(str); 4876 *next = c; 4877 if (ret == next) 4878 return (ret); 4879 (void) strcat(str, next); 4880 return (ret); 4881 } 4882 4883 static char * 4884 find_right_paren(char *s) 4885 { 4886 int balance; 4887 boolean_t escape; 4888 4889 balance = 1; 4890 escape = B_FALSE; 4891 while (*s && balance) { 4892 if (escape == B_FALSE) { 4893 if (*s == '(') 4894 balance++; 4895 else if (*s == ')') 4896 balance--; 4897 } 4898 if (*s == '\\' && !escape) 4899 escape = B_TRUE; 4900 else 4901 escape = B_FALSE; 4902 if (balance) 4903 s++; 4904 } 4905 4906 return (*s ? s : NULL); 4907 } 4908 4909 static char * 4910 adj_complex_filter(char *str) 4911 { 4912 char *next; 4913 4914 /* 4915 * We have (x(filter)...) with str sitting on 4916 * the x. We have to find the paren matching 4917 * the one before the x and put the intervening 4918 * filters by calling adj_filter_list(). 4919 */ 4920 4921 str++; 4922 if ((next = find_right_paren(str)) == NULL) 4923 return (NULL); 4924 4925 *next = '\0'; 4926 if (adj_filter_list(str) == -1) 4927 return (NULL); 4928 next = resync_str(str, next, ')'); 4929 next++; 4930 4931 return (next); 4932 } 4933 4934 static int 4935 adj_filter(char *str) 4936 { 4937 char *next; 4938 int parens, balance; 4939 boolean_t escape; 4940 char *np, *cp, *dp; 4941 4942 parens = 0; 4943 while (*str) { 4944 switch (*str) { 4945 case '(': 4946 str++; 4947 parens++; 4948 switch (*str) { 4949 case '&': 4950 if ((str = adj_complex_filter(str)) == NULL) 4951 return (-1); 4952 4953 parens--; 4954 break; 4955 4956 case '|': 4957 if ((str = adj_complex_filter(str)) == NULL) 4958 return (-1); 4959 4960 parens--; 4961 break; 4962 4963 case '!': 4964 if ((str = adj_complex_filter(str)) == NULL) 4965 return (-1); 4966 4967 parens--; 4968 break; 4969 4970 case '(': 4971 /* illegal ((case - generated by conversion */ 4972 4973 /* find missing close) */ 4974 np = find_right_paren(str+1); 4975 4976 /* error if not found */ 4977 if (np == NULL) 4978 return (-1); 4979 4980 /* remove redundant (and) */ 4981 for (dp = str, cp = str+1; cp < np; ) { 4982 *dp++ = *cp++; 4983 } 4984 cp++; 4985 while (*cp) 4986 *dp++ = *cp++; 4987 *dp = '\0'; 4988 4989 /* re-start test at original ( */ 4990 parens--; 4991 str--; 4992 break; 4993 4994 default: 4995 balance = 1; 4996 escape = B_FALSE; 4997 next = str; 4998 while (*next && balance) { 4999 if (escape == B_FALSE) { 5000 if (*next == '(') 5001 balance++; 5002 else if (*next == ')') 5003 balance--; 5004 } 5005 if (*next == '\\' && !escape) 5006 escape = B_TRUE; 5007 else 5008 escape = B_FALSE; 5009 if (balance) 5010 next++; 5011 } 5012 if (balance != 0) 5013 return (-1); 5014 5015 *next = '\0'; 5016 if (adj_simple_filter(str) == -1) { 5017 return (-1); 5018 } 5019 next = resync_str(str, next, ')'); 5020 next++; 5021 str = next; 5022 parens--; 5023 break; 5024 } 5025 break; 5026 5027 case ')': 5028 str++; 5029 parens--; 5030 break; 5031 5032 case ' ': 5033 str++; 5034 break; 5035 5036 default: /* assume it's a simple type=value filter */ 5037 next = strchr(str, '\0'); 5038 if (adj_simple_filter(str) == -1) { 5039 return (-1); 5040 } 5041 str = next; 5042 break; 5043 } 5044 } 5045 5046 return (parens ? -1 : 0); 5047 } 5048 5049 5050 /* 5051 * Put a list of filters like this "(filter1)(filter2)..." 5052 */ 5053 5054 static int 5055 adj_filter_list(char *str) 5056 { 5057 char *next; 5058 char save; 5059 5060 while (*str) { 5061 while (*str && isspace(*str)) 5062 str++; 5063 if (*str == '\0') 5064 break; 5065 5066 if ((next = find_right_paren(str + 1)) == NULL) 5067 return (-1); 5068 save = *++next; 5069 5070 /* now we have "(filter)" with str pointing to it */ 5071 *next = '\0'; 5072 if (adj_filter(str) == -1) 5073 return (-1); 5074 next = resync_str(str, next, save); 5075 5076 str = next; 5077 } 5078 5079 return (0); 5080 } 5081 5082 5083 /* 5084 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side 5085 * of a filter expression, 0 otherwise. A valid string may contain only 5086 * letters, numbers, hyphens, semi-colons, colons and periods. examples: 5087 * cn 5088 * cn;lang-fr 5089 * 1.2.3.4;binary;dynamic 5090 * mail;dynamic 5091 * cn:dn:1.2.3.4 5092 * 5093 * For compatibility with older servers, we also allow underscores in 5094 * attribute types, even through they are not allowed by the LDAPv3 RFCs. 5095 */ 5096 static int 5097 is_valid_attr(char *a) 5098 { 5099 for (; *a; a++) { 5100 if (!isascii(*a)) { 5101 return (0); 5102 } else if (!isalnum(*a)) { 5103 switch (*a) { 5104 case '-': 5105 case '.': 5106 case ';': 5107 case ':': 5108 case '_': 5109 break; /* valid */ 5110 default: 5111 return (0); 5112 } 5113 } 5114 } 5115 return (1); 5116 } 5117 5118 static char * 5119 find_star(char *s) 5120 { 5121 for (; *s; ++s) { 5122 switch (*s) { 5123 case '*': 5124 return (s); 5125 case '\\': 5126 ++s; 5127 if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0) 5128 ++s; 5129 default: 5130 break; 5131 } 5132 } 5133 return (NULL); 5134 } 5135 5136 static int 5137 adj_simple_filter(char *str) 5138 { 5139 char *s, *s2, *s3, filterop; 5140 char *value; 5141 int ftype = 0; 5142 int rc; 5143 5144 rc = -1; /* pessimistic */ 5145 5146 if ((str = strdup(str)) == NULL) { 5147 return (rc); 5148 } 5149 5150 if ((s = strchr(str, '=')) == NULL) { 5151 goto free_and_return; 5152 } 5153 value = s + 1; 5154 *s-- = '\0'; 5155 filterop = *s; 5156 if (filterop == '<' || filterop == '>' || filterop == '~' || 5157 filterop == ':') { 5158 *s = '\0'; 5159 } 5160 5161 if (!is_valid_attr(str)) { 5162 goto free_and_return; 5163 } 5164 5165 switch (filterop) { 5166 case '<': /* LDAP_FILTER_LE */ 5167 case '>': /* LDAP_FILTER_GE */ 5168 case '~': /* LDAP_FILTER_APPROX */ 5169 break; 5170 case ':': /* extended filter - v3 only */ 5171 /* 5172 * extended filter looks like this: 5173 * 5174 * [type][':dn'][':'oid]':='value 5175 * 5176 * where one of type or :oid is required. 5177 * 5178 */ 5179 s2 = s3 = NULL; 5180 if ((s2 = strrchr(str, ':')) == NULL) { 5181 goto free_and_return; 5182 } 5183 if (strcasecmp(s2, ":dn") == 0) { 5184 *s2 = '\0'; 5185 } else { 5186 *s2 = '\0'; 5187 if ((s3 = strrchr(str, ':')) != NULL) { 5188 if (strcasecmp(s3, ":dn") != 0) { 5189 goto free_and_return; 5190 } 5191 *s3 = '\0'; 5192 } 5193 } 5194 if (unescape_filterval(value) < 0) { 5195 goto free_and_return; 5196 } 5197 rc = 0; 5198 goto free_and_return; 5199 /* break; */ 5200 default: 5201 if (find_star(value) == NULL) { 5202 ftype = 0; /* LDAP_FILTER_EQUALITY */ 5203 } else if (strcmp(value, "*") == 0) { 5204 ftype = 1; /* LDAP_FILTER_PRESENT */ 5205 } else { 5206 rc = adj_substring_filter(value); 5207 goto free_and_return; 5208 } 5209 break; 5210 } 5211 5212 if (ftype != 0) { /* == LDAP_FILTER_PRESENT */ 5213 rc = 0; 5214 } else if (unescape_filterval(value) >= 0) { 5215 rc = 0; 5216 } 5217 if (rc != -1) { 5218 rc = 0; 5219 } 5220 5221 free_and_return: 5222 free(str); 5223 return (rc); 5224 } 5225 5226 5227 /* 5228 * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape 5229 * sequences within the null-terminated string 'val'. 5230 * 5231 * If 'val' contains invalid escape sequences we return -1. 5232 * Otherwise return 1 5233 */ 5234 static int 5235 unescape_filterval(char *val) 5236 { 5237 boolean_t escape, firstdigit; 5238 char *s; 5239 5240 firstdigit = B_FALSE; 5241 escape = B_FALSE; 5242 for (s = val; *s; s++) { 5243 if (escape) { 5244 /* 5245 * first try LDAPv3 escape (hexadecimal) sequence 5246 */ 5247 if (hexchar2int(*s) < 0) { 5248 if (firstdigit) { 5249 /* 5250 * LDAPv2 (RFC1960) escape sequence 5251 */ 5252 escape = B_FALSE; 5253 } else { 5254 return (-1); 5255 } 5256 } 5257 if (firstdigit) { 5258 firstdigit = B_FALSE; 5259 } else { 5260 escape = B_FALSE; 5261 } 5262 5263 } else if (*s != '\\') { 5264 escape = B_FALSE; 5265 5266 } else { 5267 escape = B_TRUE; 5268 firstdigit = B_TRUE; 5269 } 5270 } 5271 5272 return (1); 5273 } 5274 5275 5276 /* 5277 * convert character 'c' that represents a hexadecimal digit to an integer. 5278 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned. 5279 * otherwise the converted value is returned. 5280 */ 5281 static int 5282 hexchar2int(char c) 5283 { 5284 if (c >= '0' && c <= '9') { 5285 return (c - '0'); 5286 } 5287 if (c >= 'A' && c <= 'F') { 5288 return (c - 'A' + 10); 5289 } 5290 if (c >= 'a' && c <= 'f') { 5291 return (c - 'a' + 10); 5292 } 5293 return (-1); 5294 } 5295 5296 static int 5297 adj_substring_filter(char *val) 5298 { 5299 char *nextstar; 5300 5301 for (; val != NULL; val = nextstar) { 5302 if ((nextstar = find_star(val)) != NULL) { 5303 *nextstar++ = '\0'; 5304 } 5305 5306 if (*val != '\0') { 5307 if (unescape_filterval(val) < 0) { 5308 return (-1); 5309 } 5310 } 5311 } 5312 5313 return (0); 5314 } 5315 5316 /* ***** End of modified libldap.so.5 filter parser ***** */ 5317 5318 5319 /* 5320 * Walk filter, remove redundant parentheses in-line 5321 * verify that the filter is reasonable 5322 */ 5323 static int 5324 validate_filter(ns_ldap_cookie_t *cookie) 5325 { 5326 char *filter = cookie->filter; 5327 int rc; 5328 5329 /* Parse filter looking for illegal values */ 5330 5331 rc = adj_filter(filter); 5332 if (rc != 0) { 5333 return (NS_LDAP_OP_FAILED); 5334 } 5335 5336 /* end of filter checking */ 5337 5338 return (NS_LDAP_SUCCESS); 5339 } 5340 5341 /* 5342 * Set the account management request control that needs to be sent to server. 5343 * This control is required to get the account management information of 5344 * a user to do local account checking. 5345 */ 5346 static int 5347 setup_acctmgmt_params(ns_ldap_cookie_t *cookie) 5348 { 5349 LDAPControl *req, **requestctrls; 5350 5351 req = calloc(1, sizeof (LDAPControl)); 5352 5353 if (req == NULL) 5354 return (NS_LDAP_MEMORY); 5355 5356 /* fill in the fields of this new control */ 5357 req->ldctl_iscritical = 1; 5358 req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL); 5359 if (req->ldctl_oid == NULL) { 5360 free(req); 5361 return (NS_LDAP_MEMORY); 5362 } 5363 5364 requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *)); 5365 if (requestctrls == NULL) { 5366 ldap_control_free(req); 5367 return (NS_LDAP_MEMORY); 5368 } 5369 5370 requestctrls[0] = req; 5371 5372 cookie->p_serverctrls = requestctrls; 5373 5374 return (NS_LDAP_SUCCESS); 5375 } 5376 5377 /* 5378 * int get_new_acct_more_info(BerElement *ber, 5379 * AcctUsableResponse_t *acctResp) 5380 * 5381 * Decode the more_info data from an Account Management control response, 5382 * when the account is not usable and when code style is from recent LDAP 5383 * servers (see below comments for parse_acct_cont_resp_msg() to get more 5384 * details on coding styles and ASN1 description). 5385 * 5386 * Expected BER encoding: {tbtbtbtiti} 5387 * +t: tag is 0 5388 * +b: TRUE if inactive due to account inactivation 5389 * +t: tag is 1 5390 * +b: TRUE if password has been reset 5391 * +t: tag is 2 5392 * +b: TRUE if password is expired 5393 * +t: tag is 3 5394 * +i: contains num of remaining grace, 0 means no grace 5395 * +t: tag is 4 5396 * +i: contains num of seconds before auto-unlock. -1 means acct is locked 5397 * forever (i.e. until reset) 5398 * 5399 * Asumptions: 5400 * - ber is not null 5401 * - acctResp is not null and is initialized with default values for the 5402 * fields in its AcctUsableResp.more_info structure 5403 * - the ber stream is received in the correct order, per the ASN1 description. 5404 * We do not check this order and make the asumption that it is correct. 5405 * Note that the ber stream may not (and will not in most cases) contain 5406 * all fields. 5407 */ 5408 static int 5409 get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp) 5410 { 5411 int rc = NS_LDAP_SUCCESS; 5412 char errstr[MAXERROR]; 5413 ber_tag_t rTag = LBER_DEFAULT; 5414 ber_len_t rLen = 0; 5415 ber_int_t rValue; 5416 char *last; 5417 int berRC = 0; 5418 5419 /* 5420 * Look at what more_info BER element is/are left to be decoded. 5421 * look at each of them 1 by 1, without checking on their order 5422 * and possible multi values. 5423 */ 5424 for (rTag = ber_first_element(ber, &rLen, &last); 5425 rTag != LBER_END_OF_SEQORSET; 5426 rTag = ber_next_element(ber, &rLen, last)) { 5427 5428 berRC = 0; 5429 switch (rTag) { 5430 case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE: 5431 /* inactive */ 5432 berRC = ber_scanf(ber, "b", &rValue); 5433 if (berRC != LBER_ERROR) { 5434 (acctResp->AcctUsableResp).more_info. 5435 inactive = (rValue != 0) ? 1 : 0; 5436 } 5437 break; 5438 5439 case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE: 5440 /* reset */ 5441 berRC = ber_scanf(ber, "b", &rValue); 5442 if (berRC != LBER_ERROR) { 5443 (acctResp->AcctUsableResp).more_info.reset 5444 = (rValue != 0) ? 1 : 0; 5445 } 5446 break; 5447 5448 case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE: 5449 /* expired */ 5450 berRC = ber_scanf(ber, "b", &rValue); 5451 if (berRC != LBER_ERROR) { 5452 (acctResp->AcctUsableResp).more_info.expired 5453 = (rValue != 0) ? 1 : 0; 5454 } 5455 break; 5456 5457 case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE: 5458 /* remaining grace */ 5459 berRC = ber_scanf(ber, "i", &rValue); 5460 if (berRC != LBER_ERROR) { 5461 (acctResp->AcctUsableResp).more_info.rem_grace 5462 = rValue; 5463 } 5464 break; 5465 5466 case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE: 5467 /* seconds before unlock */ 5468 berRC = ber_scanf(ber, "i", &rValue); 5469 if (berRC != LBER_ERROR) { 5470 (acctResp->AcctUsableResp).more_info. 5471 sec_b4_unlock = rValue; 5472 } 5473 break; 5474 5475 default : 5476 (void) sprintf(errstr, 5477 gettext("invalid reason tag 0x%x"), rTag); 5478 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5479 rc = NS_LDAP_INTERNAL; 5480 break; 5481 } 5482 if (berRC == LBER_ERROR) { 5483 (void) sprintf(errstr, 5484 gettext("error 0x%x decoding value for " 5485 "tag 0x%x"), berRC, rTag); 5486 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5487 rc = NS_LDAP_INTERNAL; 5488 } 5489 if (rc != NS_LDAP_SUCCESS) { 5490 /* exit the for loop */ 5491 break; 5492 } 5493 } 5494 5495 return (rc); 5496 } 5497 5498 /* 5499 * int get_old_acct_opt_more_info(BerElement *ber, 5500 * AcctUsableResponse_t *acctResp) 5501 * 5502 * Decode the optional more_info data from an Account Management control 5503 * response, when the account is not usable and when code style is from LDAP 5504 * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more 5505 * details on coding styles and ASN1 description). 5506 * 5507 * Expected BER encoding: titi} 5508 * +t: tag is 2 5509 * +i: contains num of remaining grace, 0 means no grace 5510 * +t: tag is 3 5511 * +i: contains num of seconds before auto-unlock. -1 means acct is locked 5512 * forever (i.e. until reset) 5513 * 5514 * Asumptions: 5515 * - ber is a valid BER element 5516 * - acctResp is initialized for the fields in its AcctUsableResp.more_info 5517 * structure 5518 */ 5519 static int 5520 get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber, 5521 AcctUsableResponse_t *acctResp) 5522 { 5523 int rc = NS_LDAP_SUCCESS; 5524 char errstr[MAXERROR]; 5525 ber_len_t len; 5526 int rem_grace, sec_b4_unlock; 5527 5528 switch (tag) { 5529 case 2: 5530 /* decode and maybe 3 is following */ 5531 if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) { 5532 (void) sprintf(errstr, gettext("Can not get " 5533 "rem_grace")); 5534 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5535 rc = NS_LDAP_INTERNAL; 5536 break; 5537 } 5538 (acctResp->AcctUsableResp).more_info.rem_grace = rem_grace; 5539 5540 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) { 5541 /* this is a success case, break to exit */ 5542 (void) sprintf(errstr, gettext("No more " 5543 "optional data")); 5544 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5545 break; 5546 } 5547 5548 if (tag == 3) { 5549 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) { 5550 (void) sprintf(errstr, 5551 gettext("Can not get sec_b4_unlock " 5552 "- 1st case")); 5553 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5554 rc = NS_LDAP_INTERNAL; 5555 break; 5556 } 5557 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 5558 sec_b4_unlock; 5559 } else { /* unknown tag */ 5560 (void) sprintf(errstr, gettext("Unknown tag " 5561 "- 1st case")); 5562 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5563 rc = NS_LDAP_INTERNAL; 5564 break; 5565 } 5566 break; 5567 5568 case 3: 5569 if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) { 5570 (void) sprintf(errstr, gettext("Can not get " 5571 "sec_b4_unlock - 2nd case")); 5572 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5573 rc = NS_LDAP_INTERNAL; 5574 break; 5575 } 5576 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 5577 sec_b4_unlock; 5578 break; 5579 5580 default: /* unknown tag */ 5581 (void) sprintf(errstr, gettext("Unknown tag - 2nd case")); 5582 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5583 rc = NS_LDAP_INTERNAL; 5584 break; 5585 } 5586 5587 return (rc); 5588 } 5589 5590 /* 5591 * **** This function needs to be moved to libldap library **** 5592 * parse_acct_cont_resp_msg() parses the message received by server according to 5593 * following format (ASN1 notation): 5594 * 5595 * ACCOUNT_USABLE_RESPONSE::= CHOICE { 5596 * is_available [0] INTEGER, 5597 * ** seconds before expiration ** 5598 * is_not_available [1] more_info 5599 * } 5600 * more_info::= SEQUENCE { 5601 * inactive [0] BOOLEAN DEFAULT FALSE, 5602 * reset [1] BOOLEAN DEFAULT FALSE, 5603 * expired [2] BOOLEAN DEFAULT FALSE, 5604 * remaining_grace [3] INTEGER OPTIONAL, 5605 * seconds_before_unlock [4] INTEGER OPTIONAL 5606 * } 5607 */ 5608 /* 5609 * #define used to make the difference between coding style as done 5610 * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values: 5611 * - DS52p4_USABLE: 5.2p4 coding style, account is usable 5612 * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable 5613 * - NEW_USABLE: newer LDAP servers coding style, account is usable 5614 * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable 5615 * 5616 * An account would be considered not usable if for instance: 5617 * - it's been made inactive in the LDAP server 5618 * - or its password was reset in the LDAP server database 5619 * - or its password expired 5620 * - or the account has been locked, possibly forever 5621 */ 5622 #define DS52p4_USABLE 0x00 5623 #define DS52p4_NOT_USABLE 0x01 5624 #define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE 5625 #define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED 5626 static int 5627 parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp) 5628 { 5629 int rc = NS_LDAP_SUCCESS; 5630 BerElement *ber; 5631 ber_tag_t tag; 5632 ber_len_t len; 5633 int i; 5634 char errstr[MAXERROR]; 5635 /* used for any coding style when account is usable */ 5636 int seconds_before_expiry; 5637 /* used for 5.2p4 coding style when account is not usable */ 5638 int inactive, reset, expired; 5639 5640 if (ectrls == NULL) { 5641 (void) sprintf(errstr, gettext("Invalid ectrls parameter")); 5642 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5643 return (NS_LDAP_INVALID_PARAM); 5644 } 5645 5646 for (i = 0; ectrls[i] != NULL; i++) { 5647 if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL) 5648 == 0) { 5649 break; 5650 } 5651 } 5652 5653 if (ectrls[i] == NULL) { 5654 /* Ldap control is not found */ 5655 (void) sprintf(errstr, gettext("Account Usable Control " 5656 "not found")); 5657 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5658 return (NS_LDAP_NOTFOUND); 5659 } 5660 5661 /* Allocate a BER element from the control value and parse it. */ 5662 if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL) 5663 return (NS_LDAP_MEMORY); 5664 5665 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) { 5666 /* Ldap decoding error */ 5667 (void) sprintf(errstr, gettext("Error decoding 1st tag")); 5668 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5669 ber_free(ber, 1); 5670 return (NS_LDAP_INTERNAL); 5671 } 5672 5673 switch (tag) { 5674 case DS52p4_USABLE: 5675 case NEW_USABLE: 5676 acctResp->choice = 0; 5677 if (ber_scanf(ber, "i", &seconds_before_expiry) 5678 == LBER_ERROR) { 5679 /* Ldap decoding error */ 5680 (void) sprintf(errstr, gettext("Can not get " 5681 "seconds_before_expiry")); 5682 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5683 rc = NS_LDAP_INTERNAL; 5684 break; 5685 } 5686 /* ber_scanf() succeeded */ 5687 (acctResp->AcctUsableResp).seconds_before_expiry = 5688 seconds_before_expiry; 5689 break; 5690 5691 case DS52p4_NOT_USABLE: 5692 acctResp->choice = 1; 5693 if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired) 5694 == LBER_ERROR) { 5695 /* Ldap decoding error */ 5696 (void) sprintf(errstr, gettext("Can not get " 5697 "inactive/reset/expired")); 5698 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5699 rc = NS_LDAP_INTERNAL; 5700 break; 5701 } 5702 /* ber_scanf() succeeded */ 5703 (acctResp->AcctUsableResp).more_info.inactive = 5704 ((inactive == 0) ? 0 : 1); 5705 (acctResp->AcctUsableResp).more_info.reset = 5706 ((reset == 0) ? 0 : 1); 5707 (acctResp->AcctUsableResp).more_info.expired = 5708 ((expired == 0) ? 0 : 1); 5709 (acctResp->AcctUsableResp).more_info.rem_grace = 0; 5710 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0; 5711 5712 if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) { 5713 /* this is a success case, break to exit */ 5714 (void) sprintf(errstr, gettext("No optional data")); 5715 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5716 break; 5717 } 5718 5719 /* 5720 * Look at what optional more_info BER element is/are 5721 * left to be decoded. 5722 */ 5723 rc = get_old_acct_opt_more_info(tag, ber, acctResp); 5724 break; 5725 5726 case NEW_NOT_USABLE: 5727 acctResp->choice = 1; 5728 /* 5729 * Recent LDAP servers won't code more_info data for default 5730 * values (see above comments on ASN1 description for what 5731 * fields have default values & what fields are optional). 5732 */ 5733 (acctResp->AcctUsableResp).more_info.inactive = 0; 5734 (acctResp->AcctUsableResp).more_info.reset = 0; 5735 (acctResp->AcctUsableResp).more_info.expired = 0; 5736 (acctResp->AcctUsableResp).more_info.rem_grace = 0; 5737 (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0; 5738 5739 if (len == 0) { 5740 /* 5741 * Nothing else to decode; this is valid and we 5742 * use default values set above. 5743 */ 5744 (void) sprintf(errstr, gettext("more_info is " 5745 "empty, using default values")); 5746 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5747 break; 5748 } 5749 5750 /* 5751 * Look at what more_info BER element is/are left to 5752 * be decoded. 5753 */ 5754 rc = get_new_acct_more_info(ber, acctResp); 5755 break; 5756 5757 default: 5758 (void) sprintf(errstr, gettext("unknwon coding style " 5759 "(tag: 0x%x)"), tag); 5760 syslog(LOG_DEBUG, "libsldap: %s", errstr); 5761 rc = NS_LDAP_INTERNAL; 5762 break; 5763 } 5764 5765 ber_free(ber, 1); 5766 return (rc); 5767 } 5768 5769 /* 5770 * internal function for __ns_ldap_getAcctMgmt() 5771 */ 5772 static int 5773 getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp, 5774 ns_conn_user_t *conn_user) 5775 { 5776 int scope, rc; 5777 ns_ldap_cookie_t *cookie; 5778 ns_ldap_search_desc_t **sdlist = NULL; 5779 ns_ldap_search_desc_t *dptr; 5780 ns_ldap_error_t *error = NULL; 5781 char **dns = NULL; 5782 char service[] = "shadow"; 5783 5784 if (user == NULL || acctResp == NULL) 5785 return (NS_LDAP_INVALID_PARAM); 5786 5787 /* Initialize State machine cookie */ 5788 cookie = init_search_state_machine(); 5789 if (cookie == NULL) 5790 return (NS_LDAP_MEMORY); 5791 cookie->conn_user = conn_user; 5792 5793 /* see if need to follow referrals */ 5794 rc = __s_api_toFollowReferrals(0, 5795 &cookie->followRef, &error); 5796 if (rc != NS_LDAP_SUCCESS) { 5797 (void) __ns_ldap_freeError(&error); 5798 goto out; 5799 } 5800 5801 /* get the service descriptor - or create a default one */ 5802 rc = __s_api_get_SSD_from_SSDtoUse_service(service, 5803 &sdlist, &error); 5804 if (rc != NS_LDAP_SUCCESS) { 5805 (void) __ns_ldap_freeError(&error); 5806 goto out; 5807 } 5808 5809 if (sdlist == NULL) { 5810 /* Create default service Desc */ 5811 sdlist = (ns_ldap_search_desc_t **)calloc(2, 5812 sizeof (ns_ldap_search_desc_t *)); 5813 if (sdlist == NULL) { 5814 rc = NS_LDAP_MEMORY; 5815 goto out; 5816 } 5817 dptr = (ns_ldap_search_desc_t *) 5818 calloc(1, sizeof (ns_ldap_search_desc_t)); 5819 if (dptr == NULL) { 5820 free(sdlist); 5821 rc = NS_LDAP_MEMORY; 5822 goto out; 5823 } 5824 sdlist[0] = dptr; 5825 5826 /* default base */ 5827 rc = __s_api_getDNs(&dns, service, &cookie->errorp); 5828 if (rc != NS_LDAP_SUCCESS) { 5829 if (dns) { 5830 __s_api_free2dArray(dns); 5831 dns = NULL; 5832 } 5833 (void) __ns_ldap_freeError(&(cookie->errorp)); 5834 cookie->errorp = NULL; 5835 goto out; 5836 } 5837 dptr->basedn = strdup(dns[0]); 5838 if (dptr->basedn == NULL) { 5839 free(sdlist); 5840 free(dptr); 5841 if (dns) { 5842 __s_api_free2dArray(dns); 5843 dns = NULL; 5844 } 5845 rc = NS_LDAP_MEMORY; 5846 goto out; 5847 } 5848 __s_api_free2dArray(dns); 5849 dns = NULL; 5850 5851 /* default scope */ 5852 scope = 0; 5853 rc = __s_api_getSearchScope(&scope, &cookie->errorp); 5854 dptr->scope = scope; 5855 } 5856 5857 cookie->sdlist = sdlist; 5858 5859 cookie->service = strdup(service); 5860 if (cookie->service == NULL) { 5861 rc = NS_LDAP_MEMORY; 5862 goto out; 5863 } 5864 5865 /* search for entries for this particular uid */ 5866 (void) asprintf(&cookie->i_filter, "(uid=%s)", user); 5867 if (cookie->i_filter == NULL) { 5868 rc = NS_LDAP_MEMORY; 5869 goto out; 5870 } 5871 5872 /* create the control request */ 5873 if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS) 5874 goto out; 5875 5876 /* Process search */ 5877 rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0); 5878 5879 /* Copy results back to user */ 5880 rc = cookie->err_rc; 5881 if (rc != NS_LDAP_SUCCESS) 5882 (void) __ns_ldap_freeError(&(cookie->errorp)); 5883 5884 if (cookie->result == NULL) 5885 goto out; 5886 5887 if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp)) 5888 != NS_LDAP_SUCCESS) 5889 goto out; 5890 5891 rc = NS_LDAP_SUCCESS; 5892 5893 out: 5894 delete_search_cookie(cookie); 5895 5896 return (rc); 5897 } 5898 5899 /* 5900 * __ns_ldap_getAcctMgmt() is called from pam account management stack 5901 * for retrieving accounting information of users with no user password - 5902 * eg. rlogin, rsh, etc. This function uses the account management control 5903 * request to do a search on the server for the user in question. The 5904 * response control returned from the server is got from the cookie. 5905 * Input params: username of whose account mgmt information is to be got 5906 * pointer to hold the parsed account management information 5907 * Return values: NS_LDAP_SUCCESS on success or appropriate error 5908 * code on failure 5909 */ 5910 int 5911 __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp) 5912 { 5913 ns_conn_user_t *cu = NULL; 5914 int try_cnt = 0; 5915 int rc = NS_LDAP_SUCCESS; 5916 ns_ldap_error_t *error = NULL; 5917 5918 for (;;) { 5919 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH, 5920 &try_cnt, &rc, &error) == 0) 5921 break; 5922 rc = getAcctMgmt(user, acctResp, cu); 5923 } 5924 return (rc); 5925 }