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