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