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