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 * ns_ldap.c 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <syslog.h> 31 #include <string.h> 32 #include <ctype.h> 33 #include <nsswitch.h> 34 #include <sys/param.h> 35 #include <sys/types.h> 36 #include <rpc/rpc.h> 37 #include <rpcsvc/nfs_prot.h> 38 #include <sys/errno.h> 39 #include <libintl.h> 40 #include "automount.h" 41 #include "../../../lib/libsldap/common/ns_sldap.h" 42 43 /* 44 * LDAP schema used for automounter: 45 * 46 * automountMapName: mapname i.e. auto_home, etc. 47 * automountKey: contains the key i.e. the mount point 48 * automountInformation: contains the mount options and remote mount location 49 * description: an optional description (not used by automounter) 50 * 51 * For example, if auto_direct has the following line of data: 52 * 53 * /work -rw,intr,nosuid,noquota hosta:/export/work 54 * 55 * Then this would map to the the following LDAP entry: 56 * 57 * dn: automountKey=/work,automountMapName=auto_direct,... 58 * automountKey: /work 59 * automountInformation: -rw,intr,nosuid,noquota hosta:/export/work 60 * objectclass: top 61 * objectclass: automount 62 * 63 * In this container: 64 * 65 * dn: automountMapName=auto_direct,... 66 * automountMapName: auto_direct 67 * objectClass: top 68 * objectClass: automountMap 69 * 70 * Note that the schema can be mapped and SSD's can be used to relocate 71 * the default location of these entries. 72 * 73 */ 74 75 #define CAPCHAR '%' 76 #define MAXERROR 4000 77 78 static char *automountKey = NULL; 79 static char *automountInformation = NULL; 80 static char *defaultFilter = NULL; 81 static int encode = 0; 82 83 static int mastermap_callback_ldap(); 84 static int directmap_callback(); 85 static int ldap_err(int); 86 static int ldap_match(); 87 static int readdir_callback(); 88 89 struct loadmaster_cbdata { 90 char *ptr1; 91 char **ptr2; 92 char ***ptr3; 93 }; 94 95 struct loaddirect_cbdata { 96 char *ptr1; 97 char *ptr2; 98 char **ptr3; 99 char ***ptr4; 100 }; 101 102 struct dir_cbdata { 103 struct dir_entry **list; 104 struct dir_entry *last; 105 int error; 106 }; 107 108 static char *tosunds_str(char *); 109 static char *tounix_str(char *); 110 111 static int 112 isAttrMapped(char *orig, char *mapped) 113 { 114 char **s; 115 char **mappedschema = NULL; 116 117 mappedschema = __ns_ldap_getMappedAttributes("automount", orig); 118 if (mappedschema == NULL) 119 return (0); 120 if (strcasecmp(mappedschema[0], mapped) != 0) { 121 for (s = mappedschema; *s != NULL; s++) 122 free(*s); 123 free(mappedschema); 124 return (0); 125 } 126 for (s = mappedschema; *s != NULL; s++) 127 free(*s); 128 free(mappedschema); 129 return (1); 130 } 131 132 static int 133 isObjectMapped(char *orig, char *mapped) 134 { 135 char **s; 136 char **mappedschema = NULL; 137 138 mappedschema = __ns_ldap_getMappedObjectClass("automount", orig); 139 if (mappedschema == NULL) 140 return (0); 141 if (strcasecmp(mappedschema[0], mapped) != 0) { 142 for (s = mappedschema; *s != NULL; s++) 143 free(*s); 144 free(mappedschema); 145 return (0); 146 } 147 for (s = mappedschema; *s != NULL; s++) 148 free(*s); 149 free(mappedschema); 150 return (1); 151 } 152 153 void 154 init_ldap(char **stack, char ***stkptr) 155 { 156 /* 157 * Check for version of the profile the client is using 158 * 159 * For version 1 profiles we do encoding of attributes 160 * and use nisMap and nisObject schema for backward compatibility. 161 * 162 * For version 2 profiles we don't do encoding and use 163 * automountMap and automount as default attributes (which can 164 * then be overridden in libsldap if schema mapping is configured 165 * in the profile). 166 * 167 * If profile version is not available, use version 2 as default 168 * and syslog message. 169 */ 170 int rc, v2 = 1; 171 void **paramVal = NULL; 172 ns_ldap_error_t *errorp = NULL; 173 struct __nsw_switchconfig *conf = NULL; 174 struct __nsw_lookup *lkp = NULL; 175 enum __nsw_parse_err pserr; 176 int ldap_configured = 0; 177 178 #ifdef lint 179 stack = stack; 180 stkptr = stkptr; 181 #endif /* lint */ 182 183 /* get nsswitch info of "automount */ 184 conf = __nsw_getconfig("automount", &pserr); 185 186 /* find out if LDAP backend is configured */ 187 if (conf != NULL) { 188 for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 189 if (strcmp(lkp->service_name, "ldap") == 0) { 190 ldap_configured = 1; 191 break; 192 } 193 } 194 /* free conf at the end of "if" bracket */ 195 (void) __nsw_freeconfig(conf); 196 } 197 198 /* if ldap is not configured, init_ldap is a no op */ 199 if (!ldap_configured) 200 return; 201 202 rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, ¶mVal, &errorp); 203 if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) { 204 syslog(LOG_ERR, "Can not determine version of LDAP profile" 205 " that is used (%d, %s). Using version 2 profile" 206 " defaults", rc, (errorp && errorp->message ? 207 errorp->message : "")); 208 (void) __ns_ldap_freeError(&errorp); 209 } else { 210 if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) 211 v2 = 0; 212 (void) __ns_ldap_freeParam(¶mVal); 213 } 214 215 if (v2) { 216 if (trace > 1) 217 trace_prt(1, "init_ldap: setting up for version 2\n"); 218 automountKey = "automountKey"; 219 automountInformation = "automountInformation"; 220 defaultFilter = "(&(objectClass=automount)(automountKey=%s))"; 221 222 /* check for automountMapName mapped to nisMapName */ 223 if (!isAttrMapped("automountMapName", "nisMapName")) 224 return; 225 226 /* check for automountKey mapped to cn */ 227 if (!isAttrMapped("automountKey", "cn")) 228 return; 229 230 /* check for automountInformation mapped to nisMapEntry */ 231 if (!isAttrMapped("automountInformation", "nisMapEntry")) 232 return; 233 234 /* check for automountMap mapped to nisMap */ 235 if (!isObjectMapped("automountMap", "nisMap")) 236 return; 237 238 /* check for automount mapped to nisObject */ 239 if (!isObjectMapped("automount", "nisObject")) 240 return; 241 242 if (trace > 1) 243 trace_prt(1, "init_ldap: encode = TRUE\n"); 244 encode = 1; 245 } else { 246 if (trace > 1) { 247 trace_prt(1, "init_ldap: setting up for version 1\n"); 248 trace_prt(1, "init_ldap: encode = TRUE\n"); 249 } 250 encode = 1; 251 automountKey = "cn"; 252 automountInformation = "nisMapEntry"; 253 defaultFilter = "(&(objectClass=nisObject)(cn=%s))"; 254 } 255 } 256 257 /*ARGSUSED*/ 258 int 259 getmapent_ldap(char *key, char *map, struct mapline *ml, 260 char **stack, char ***stkptr, bool_t *iswildcard, bool_t isrestricted) 261 { 262 char *ldap_line = NULL; 263 char *lp; 264 int ldap_len, len; 265 int nserr; 266 267 if (trace > 1) 268 trace_prt(1, "getmapent_ldap called\n"); 269 270 if (trace > 1) { 271 trace_prt(1, "getmapent_ldap: key=[ %s ]\n", key); 272 } 273 274 if (iswildcard) 275 *iswildcard = FALSE; 276 nserr = ldap_match(map, key, &ldap_line, &ldap_len); 277 if (nserr) { 278 if (nserr == __NSW_NOTFOUND) { 279 /* Try the default entry "*" */ 280 if ((nserr = ldap_match(map, "\\2a", &ldap_line, 281 &ldap_len))) 282 goto done; 283 else { 284 if (iswildcard) 285 *iswildcard = TRUE; 286 } 287 } else 288 goto done; 289 } 290 291 /* 292 * at this point we are sure that ldap_match 293 * succeeded so massage the entry by 294 * 1. ignoring # and beyond 295 * 2. trim the trailing whitespace 296 */ 297 if (lp = strchr(ldap_line, '#')) 298 *lp = '\0'; 299 len = strlen(ldap_line); 300 if (len == 0) { 301 nserr = __NSW_NOTFOUND; 302 goto done; 303 } 304 lp = &ldap_line[len - 1]; 305 while (lp > ldap_line && isspace(*lp)) 306 *lp-- = '\0'; 307 if (lp == ldap_line) { 308 nserr = __NSW_NOTFOUND; 309 goto done; 310 } 311 (void) strncpy(ml->linebuf, ldap_line, LINESZ); 312 unquote(ml->linebuf, ml->lineqbuf); 313 nserr = __NSW_SUCCESS; 314 done: 315 if (ldap_line) 316 free((char *)ldap_line); 317 318 if (trace > 1) 319 trace_prt(1, "getmapent_ldap: exiting ...\n"); 320 321 return (nserr); 322 } 323 324 static int 325 ldap_match(char *map, char *key, char **ldap_line, int *ldap_len) 326 { 327 char searchfilter[LDAP_FILT_MAXSIZ]; 328 int res, attr_found; 329 ns_ldap_result_t *result = NULL; 330 ns_ldap_error_t *errp = NULL; 331 ns_ldap_entry_t *entry = NULL; 332 char *ldapkey; 333 int i; 334 335 if (trace > 1) { 336 trace_prt(1, "ldap_match called\n"); 337 trace_prt(1, "ldap_match: key =[ %s ]\n", key); 338 } 339 340 /* 341 * need to handle uppercase characters in the key because LDAP 342 * searches are case insensitive. Note, key = attribute automountKey. 343 */ 344 if (encode) 345 ldapkey = tosunds_str(key); 346 else 347 ldapkey = key; 348 349 if (trace > 1) { 350 trace_prt(1, "ldap_match: ldapkey =[ %s ]\n", ldapkey); 351 } 352 353 (void) sprintf(searchfilter, defaultFilter, ldapkey); 354 355 if (trace > 1) 356 trace_prt(1, " ldap_match: Requesting list for %s in %s\n", 357 searchfilter, map); 358 359 res = __ns_ldap_list(map, searchfilter, NULL, 360 NULL, NULL, 0, &result, &errp, NULL, NULL); 361 362 if (trace > 1) { 363 if (res != NS_LDAP_SUCCESS) 364 trace_prt(1, 365 " ldap_match: __ns_ldap_list FAILED (%d)\n", res); 366 else 367 trace_prt(1, " ldap_match: __ns_ldap_list OK\n"); 368 } 369 370 if (res != NS_LDAP_SUCCESS && res != NS_LDAP_NOTFOUND) { 371 if (errp) { 372 if (verbose) { 373 char errstr[MAXERROR]; 374 (void) sprintf(errstr, 375 gettext("ldap server can't list map," 376 " '%s': '%s' - '%d'."), 377 map, errp->message, errp->status); 378 syslog(LOG_ERR, errstr); 379 } 380 __ns_ldap_freeError(&errp); 381 } else { 382 if (verbose) { 383 char *errmsg; 384 __ns_ldap_err2str(res, &errmsg); 385 syslog(LOG_ERR, errmsg); 386 } 387 } 388 if (result) 389 __ns_ldap_freeResult(&result); 390 return (ldap_err(res)); 391 } 392 393 if (res == NS_LDAP_NOTFOUND || result == NULL || 394 result->entries_count == 0 || result->entry->attr_count == 0) { 395 if (trace > 1) 396 trace_prt(1, " ldap_match: no entries found\n"); 397 if (errp) 398 __ns_ldap_freeError(&errp); 399 if (result) 400 __ns_ldap_freeResult(&result); 401 return (__NSW_NOTFOUND); 402 } 403 404 /* 405 * get value of attribute nisMapEntry. This attribute contains a 406 * list of mount options AND mount location for a particular mount 407 * point (key). 408 * For example: 409 * 410 * key: /work 411 * ^^^^^ 412 * (mount point) 413 * 414 * nisMapEntry: -rw,intr,nosuid,noquota hosta:/export/work 415 * ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ 416 * ( mount options ) (remote mount location) 417 * 418 */ 419 attr_found = 0; 420 entry = result->entry; 421 for (i = 0; i < entry->attr_count; i++) { 422 ns_ldap_attr_t *attr; 423 424 attr = entry->attr_pair[i]; 425 if (strcasecmp(attr->attrname, automountInformation) == 0) { 426 char *attrval; 427 428 attr_found = 1; 429 if (encode) 430 attrval = tounix_str(attr->attrvalue[0]); 431 else 432 attrval = attr->attrvalue[0]; 433 *ldap_len = strlen(key) + strlen(attrval); 434 435 /* 436 * so check for the length; it should be less than 437 * LINESZ 438 */ 439 if ((*ldap_len + 2) > LINESZ) { 440 syslog(LOG_ERR, 441 "ldap server map %s, entry for %s" 442 " is too long %d chars (max %d)", 443 map, key, (*ldap_len + 2), LINESZ); 444 __ns_ldap_freeResult(&result); 445 return (__NSW_UNAVAIL); 446 } 447 *ldap_line = (char *)malloc(*ldap_len + 2); 448 if (*ldap_line == NULL) { 449 syslog(LOG_ERR, "ldap_match: malloc failed"); 450 __ns_ldap_freeResult(&result); 451 return (__NSW_UNAVAIL); 452 } 453 454 (void) sprintf(*ldap_line, "%s", attrval); 455 456 break; 457 } 458 } 459 460 __ns_ldap_freeError(&errp); 461 __ns_ldap_freeResult(&result); 462 463 if (!attr_found) 464 return (__NSW_NOTFOUND); 465 466 if (trace > 1) 467 trace_prt(1, " ldap_match: found: %s\n", *ldap_line); 468 469 return (__NSW_SUCCESS); 470 } 471 472 int 473 loadmaster_ldap(char *mapname, char *defopts, char **stack, char ***stkptr) 474 { 475 char searchfilter[LDAP_FILT_MAXSIZ]; 476 int res; 477 ns_ldap_result_t *result = NULL; 478 ns_ldap_error_t *errp = NULL; 479 struct loadmaster_cbdata master_cbdata; 480 481 if (trace > 1) 482 trace_prt(1, "loadmaster_ldap called\n"); 483 484 master_cbdata.ptr1 = defopts; 485 master_cbdata.ptr2 = stack; 486 master_cbdata.ptr3 = stkptr; 487 488 /* filter gets all the entries for the specified mapname */ 489 (void) sprintf(searchfilter, defaultFilter, "*"); 490 491 if (trace > 1) 492 trace_prt(1, "loadmaster_ldap: Requesting list for %s in %s\n", 493 searchfilter, mapname); 494 495 res = __ns_ldap_list(mapname, searchfilter, NULL, NULL, NULL, 496 0, &result, &errp, mastermap_callback_ldap, 497 (void *) &master_cbdata); 498 499 if (trace > 1) 500 trace_prt(1, 501 "loadmaster_ldap: __ns_ldap_list just returned: %d\n", 502 res); 503 504 if (res != NS_LDAP_SUCCESS) { 505 if (errp) { 506 char errstr[MAXERROR]; 507 if (verbose) { 508 (void) sprintf(errstr, gettext( 509 "ldap server can't list map," 510 "'%s': '%s' - '%d'."), 511 mapname, errp->message, errp->status); 512 syslog(LOG_ERR, errstr); 513 } 514 __ns_ldap_freeError(&errp); 515 } else { 516 if (verbose) { 517 char *errmsg; 518 __ns_ldap_err2str(res, &errmsg); 519 syslog(LOG_ERR, errmsg); 520 } 521 } 522 if (result) 523 __ns_ldap_freeResult(&result); 524 return (ldap_err(res)); 525 } 526 527 if (trace > 1) 528 trace_prt(1, 529 "loadmaster_ldap: calling __ns_ldap_freeResult...\n"); 530 531 __ns_ldap_freeResult(&result); 532 533 if (trace > 1) 534 trace_prt(1, 535 "loadmaster_ldap: about to return __NSW_SUCCESS...\n"); 536 537 return (__NSW_SUCCESS); 538 } 539 540 int 541 loaddirect_ldap(char *nsmap, char *localmap, char *opts, 542 char **stack, char ***stkptr) 543 { 544 char searchfilter[LDAP_FILT_MAXSIZ]; 545 int res; 546 ns_ldap_result_t *result = NULL; 547 ns_ldap_error_t *errp = NULL; 548 struct loaddirect_cbdata direct_cbdata; 549 550 if (trace > 1) { 551 trace_prt(1, "loaddirect_ldap called\n"); 552 } 553 554 direct_cbdata.ptr1 = opts; 555 direct_cbdata.ptr2 = localmap; 556 direct_cbdata.ptr3 = stack; 557 direct_cbdata.ptr4 = stkptr; 558 559 /* filter gets all the entries for the specified mapname */ 560 (void) sprintf(searchfilter, defaultFilter, "*"); 561 562 if (trace > 1) 563 trace_prt(1, "loaddirect_ldap: Requesting list for %s in %s\n", 564 searchfilter, nsmap); 565 566 res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, 567 NULL, 0, &result, &errp, 568 directmap_callback, (void *) &direct_cbdata); 569 570 571 if (res != NS_LDAP_SUCCESS) { 572 if (errp) { 573 char errstr[MAXERROR]; 574 if (verbose) { 575 (void) sprintf(errstr, 576 gettext("ldap server can't list map," 577 " '%s': '%s' - '%d'."), 578 nsmap, errp->message, errp->status); 579 syslog(LOG_ERR, errstr); 580 } 581 __ns_ldap_freeError(&errp); 582 } else { 583 if (verbose) { 584 char *errmsg; 585 __ns_ldap_err2str(res, &errmsg); 586 syslog(LOG_ERR, errmsg); 587 } 588 } 589 if (result) 590 __ns_ldap_freeResult(&result); 591 return (ldap_err(res)); 592 } 593 594 __ns_ldap_freeResult(&result); 595 return (__NSW_SUCCESS); 596 } 597 598 static int 599 ldap_err(int err) 600 { 601 if (trace > 1) 602 trace_prt(1, "ldap_err called\n"); 603 604 switch (err) { 605 606 case NS_LDAP_SUCCESS: 607 return (__NSW_SUCCESS); 608 609 case NS_LDAP_NOTFOUND: 610 return (__NSW_NOTFOUND); 611 612 case NS_LDAP_PARTIAL: 613 return (__NSW_TRYAGAIN); 614 615 default: 616 return (__NSW_UNAVAIL); 617 } 618 } 619 620 static int 621 mastermap_callback_ldap(ns_ldap_entry_t *entry, void *udata) 622 { 623 char *key, *contents, *pmap, *opts; 624 char dir[LINESZ], map[LINESZ], qbuff[LINESZ]; 625 char cont_temp[LINESZ], key_temp[LINESZ]; 626 int key_len, contents_len; 627 struct loadmaster_cbdata *temp = (struct loadmaster_cbdata *)udata; 628 char *defopts = temp->ptr1; 629 char **stack = temp->ptr2; 630 char ***stkptr = temp->ptr3; 631 int i; 632 633 if (trace > 1) { 634 trace_prt(1, "mastermap_callback_ldap called\n"); 635 trace_prt(1, "mastermap_callback_ldap: entry=%x\n", entry); 636 if (entry) { 637 trace_prt(1, 638 "mastermap_callback_ldap: entry->attr_count=[ %d ]\n", 639 entry->attr_count); 640 } 641 } 642 643 /* 644 * For the current entry, obtain the values of the cn and the 645 * nisMapEntry attributes and the length of each value (cn=key, 646 * nisMapEntry=contents). 647 * We skip the description. Even though LDAP allows for multiple 648 * values per attribute, we take only the 1st value for each 649 * attribute because the automount data is organized as such. 650 */ 651 key_len = 0; 652 contents_len = 0; 653 key = NULL; 654 contents = NULL; 655 for (i = 0; i < entry->attr_count; i++) { 656 ns_ldap_attr_t *attr; 657 658 attr = entry->attr_pair[i]; 659 if (trace > 1) { 660 trace_prt(1, 661 "mastermap_callback_ldap: attr[%d]: %s=%s\n", 662 i, attr->attrname, attr->attrvalue[0]); 663 } 664 if (strcasecmp(attr->attrname, automountInformation) == 0) { 665 if (encode) 666 (void) strncpy(cont_temp, 667 tounix_str(attr->attrvalue[0]), LINESZ); 668 else 669 (void) strncpy(cont_temp, attr->attrvalue[0], 670 LINESZ); 671 contents = cont_temp; 672 contents_len = strlen(contents); 673 if (trace > 1) { 674 trace_prt(1, 675 "mastermap_callback_ldap: contents=[ %s ]," 676 " contents_len=[ %d ]\n", 677 contents, contents_len); 678 } 679 } 680 if (strcasecmp(attr->attrname, automountKey) == 0) { 681 if (encode) 682 (void) strncpy(key_temp, 683 tounix_str(attr->attrvalue[0]), LINESZ); 684 else 685 (void) strncpy(key_temp, attr->attrvalue[0], 686 LINESZ); 687 key = key_temp; 688 key_len = strlen(key); 689 if (trace > 1) { 690 trace_prt(1, 691 "mastermap_callback_ldap: key=[ %s ]," 692 " key_len=[ %d ]\n", 693 key, key_len); 694 } 695 } 696 } 697 698 if (key_len >= LINESZ || contents_len >= LINESZ) 699 return (0); 700 if (key_len < 2 || contents_len < 2) 701 return (0); 702 703 while (isspace(*contents)) 704 contents++; 705 if (contents == NULL) 706 return (0); 707 if (isspace(*key) || *key == '#') 708 return (0); 709 710 (void) strncpy(dir, key, key_len); 711 dir[key_len] = '\0'; 712 if (trace > 1) 713 trace_prt(1, "mastermap_callback_ldap: dir= [ %s ]\n", dir); 714 for (i = 0; i < LINESZ; i++) 715 qbuff[i] = ' '; 716 if (macro_expand("", dir, qbuff, sizeof (dir))) { 717 syslog(LOG_ERR, 718 "%s in ldap server map: entry too long (max %d chars)", 719 dir, sizeof (dir) - 1); 720 return (0); 721 } 722 (void) strncpy(map, contents, contents_len); 723 map[contents_len] = '\0'; 724 if (trace > 1) 725 trace_prt(1, "mastermap_callback_ldap: map= [ %s ]\n", map); 726 if (macro_expand("", map, qbuff, sizeof (map))) { 727 syslog(LOG_ERR, 728 "%s in ldap server map: entry too long (max %d chars)", 729 map, sizeof (map) - 1); 730 return (0); 731 } 732 pmap = map; 733 while (*pmap && isspace(*pmap)) 734 pmap++; /* skip blanks in front of map */ 735 opts = pmap; 736 while (*opts && !isspace(*opts)) 737 opts++; 738 if (*opts) { 739 *opts++ = '\0'; 740 while (*opts && isspace(*opts)) 741 opts++; 742 if (*opts == '-') 743 opts++; 744 else 745 opts = defopts; 746 } 747 /* 748 * Check for no embedded blanks. 749 */ 750 if (strcspn(opts, " ") == strlen(opts)) { 751 if (trace > 1) 752 trace_prt(1, 753 "mastermap_callback_ldap: dir=[ %s ], pmap=[ %s ]\n", 754 dir, pmap); 755 dirinit(dir, pmap, opts, 0, stack, stkptr); 756 } else { 757 char *dn = NULL; 758 759 /* get the value for the dn */ 760 for (i = 0; i < entry->attr_count; i++) { 761 ns_ldap_attr_t *attr; 762 763 attr = entry->attr_pair[i]; 764 if (strcasecmp(attr->attrname, "dn") 765 == 0) { 766 dn = attr->attrvalue[0]; 767 break; 768 } 769 } 770 pr_msg( 771 "Warning: invalid entry for %s in ldap server" 772 " dn: %s ignored.\n", 773 dir, dn); 774 } 775 if (trace > 1) 776 trace_prt(1, "mastermap_callback_ldap exiting...\n"); 777 return (0); 778 } 779 780 static int 781 directmap_callback(ns_ldap_entry_t *entry, void *udata) 782 { 783 char *key; 784 char dir[256]; 785 int key_len; 786 struct loaddirect_cbdata *temp = (struct loaddirect_cbdata *)udata; 787 char *opts = temp->ptr1; 788 char *localmap = temp->ptr2; 789 char **stack = temp->ptr3; 790 char ***stkptr = temp->ptr4; 791 int i; 792 793 /* 794 * For the current entry, obtain the value and length of the cn i.e. 795 * the contents of key and its key length. 796 */ 797 key_len = 0; 798 key = NULL; 799 for (i = 0; i < entry->attr_count; i++) { 800 ns_ldap_attr_t *attr; 801 802 attr = entry->attr_pair[i]; 803 if (strcasecmp(attr->attrname, automountKey) == 0) { 804 if (encode) 805 key = tounix_str(attr->attrvalue[0]); 806 else 807 key = attr->attrvalue[0]; 808 key_len = strlen(key); 809 break; 810 } 811 } 812 813 if (key_len >= 100 || key_len < 2) 814 return (0); 815 816 if (isspace(*key) || *key == '#') 817 return (0); 818 (void) strncpy(dir, key, key_len); 819 dir[key_len] = '\0'; 820 821 dirinit(dir, localmap, opts, 1, stack, stkptr); 822 823 return (0); 824 } 825 826 int 827 getmapkeys_ldap(char *nsmap, struct dir_entry **list, int *error, 828 int *cache_time, char **stack, char ***stkptr) 829 { 830 char searchfilter[LDAP_FILT_MAXSIZ]; 831 int res; 832 ns_ldap_result_t *result = NULL; 833 ns_ldap_error_t *errp = NULL; 834 struct dir_cbdata readdir_cbdata; 835 836 #ifdef lint 837 stack = stack; 838 stkptr = stkptr; 839 #endif /* lint */ 840 841 if (trace > 1) 842 trace_prt(1, "getmapkeys_ldap called\n"); 843 844 *cache_time = RDDIR_CACHE_TIME; 845 *error = 0; 846 readdir_cbdata.list = list; 847 readdir_cbdata.last = NULL; 848 849 /* filter gets all the entries for the specified mapname */ 850 (void) sprintf(searchfilter, defaultFilter, "*"); 851 852 if (trace > 1) 853 trace_prt(1, "getmapkeys_ldap: Requesting list for %s in %s\n", 854 searchfilter, nsmap); 855 856 res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, NULL, 0, 857 &result, &errp, readdir_callback, (void *) &readdir_cbdata); 858 859 if (trace > 1) 860 trace_prt(1, " getmapkeys_ldap: __ns_ldap_list returned %d\n", 861 res); 862 863 if (readdir_cbdata.error) 864 *error = readdir_cbdata.error; 865 866 if (res != NS_LDAP_SUCCESS && res != NS_LDAP_NOTFOUND) { 867 if (errp) { 868 if (verbose) { 869 char errstr[MAXERROR]; 870 (void) sprintf(errstr, gettext( 871 "ldap server can't list map," 872 " '%s': '%s' - '%d'."), 873 nsmap, errp->message, errp->status); 874 syslog(LOG_ERR, errstr); 875 } 876 __ns_ldap_freeError(&errp); 877 } else { 878 if (verbose) { 879 char *errmsg; 880 __ns_ldap_err2str(res, &errmsg); 881 syslog(LOG_ERR, errmsg); 882 } 883 } 884 if (result) 885 __ns_ldap_freeResult(&result); 886 if (*error == 0) 887 *error = ECOMM; 888 return (ldap_err(res)); 889 } 890 if (result) 891 __ns_ldap_freeResult(&result); 892 893 return (__NSW_SUCCESS); 894 } 895 896 static int 897 readdir_callback(const ns_ldap_entry_t *entry, const void *udata) 898 { 899 char *key; 900 int key_len; 901 struct dir_cbdata *temp = (struct dir_cbdata *)udata; 902 struct dir_entry **list = temp->list; 903 struct dir_entry *last = temp->last; 904 int i; 905 906 if (trace > 1) 907 trace_prt(1, "readdir_callback called\n"); 908 /* 909 * For the current entry, obtain the value and length of the cn i.e. the 910 * contents of key and its key length. 911 */ 912 key_len = 0; 913 key = NULL; 914 915 if (trace > 1) 916 trace_prt(1, "readdir_callback: entry->attr_count=[ %d ]\n", 917 entry->attr_count); 918 919 for (i = 0; i < entry->attr_count; i++) { 920 ns_ldap_attr_t *attr; 921 922 attr = entry->attr_pair[i]; 923 924 if (trace > 1) 925 trace_prt(1, 926 "readdir_callback: attr->attrname=[ %s ]\n", 927 attr->attrname); 928 929 if (strcasecmp(attr->attrname, automountKey) == 0) { 930 if (encode) 931 key = tounix_str(attr->attrvalue[0]); 932 else 933 key = attr->attrvalue[0]; 934 key_len = strlen(key); 935 936 if (trace > 1) 937 trace_prt(1, 938 "readdir_callback: key=[ %s ], key_len=[ %d ]\n", 939 key, key_len); 940 941 break; 942 } 943 } 944 945 if (key_len >= 100 || key_len < 2) 946 return (0); 947 948 if (isspace(*key) || *key == '#') 949 return (0); 950 951 /* 952 * Wildcard entry should be ignored - following entries should continue 953 * to be read to corroborate with the way we search for entries in 954 * LDAP, i.e., first for an exact key match and then a wildcard 955 * if there's no exact key match. 956 */ 957 if (key[0] == '*' && key[1] == '\0') 958 return (0); 959 960 if (add_dir_entry(key, list, &last)) { 961 temp->error = ENOMEM; 962 return (1); 963 } 964 965 temp->last = last; 966 temp->error = 0; 967 968 if (trace > 1) 969 trace_prt(1, "readdir_callback returning 0...\n"); 970 971 return (0); 972 } 973 974 /* 975 * Puts CAPCHAR in front of uppercase characters or surrounds a set of 976 * contiguous uppercase characters with CAPCHARS and square brackets. 977 * 978 * For example (assuming CAPCHAR = '%'): 979 * 980 * if str = Abc, it returns %Abc 981 * if str = ABc, it returns %[AB]c 982 * if str = AbC, it returns %Ab%C 983 * 984 */ 985 static char * 986 tosunds_str(char *str) 987 { 988 static char buf[BUFSIZ]; 989 int i, j, er = FALSE; 990 #ifdef NEWCAP 991 int openBracket = FALSE, closeBracket = FALSE; 992 #endif 993 994 (void) memset(buf, 0, BUFSIZ); 995 996 j = 0; 997 for (i = 0; i < strlen(str); i++) { 998 /* Check the current element */ 999 if (isupper(str[i])) { 1000 #ifdef NEWCAP 1001 /* check the next element */ 1002 if (isupper(str[i+1])) { 1003 if (openBracket == FALSE) { 1004 openBracket = TRUE; 1005 buf[j] = CAPCHAR; 1006 buf[j+1] = '['; 1007 j += 2; 1008 } 1009 } else { 1010 if (openBracket == FALSE) { 1011 buf[j] = CAPCHAR; 1012 j++; 1013 } else { 1014 openBracket = FALSE; 1015 closeBracket = TRUE; 1016 } 1017 } 1018 #else 1019 buf[j++] = CAPCHAR; 1020 #endif 1021 } 1022 buf[j] = str[i]; 1023 j++; 1024 1025 #ifdef NEWCAP 1026 if (closeBracket == TRUE) { 1027 closeBracket = FALSE; 1028 buf[j] = ']'; 1029 j++; 1030 } 1031 #endif 1032 if (j >= BUFSIZ) { 1033 er = TRUE; 1034 break; 1035 } 1036 } 1037 1038 if (er) { 1039 syslog(LOG_ERR, "Buffer size exceeded."); 1040 (void) memset(buf, 0, BUFSIZ); 1041 } else 1042 buf[j] = '\0'; 1043 1044 return (buf); 1045 1046 } 1047 1048 /* 1049 * Reverses what tosunds_str() did 1050 */ 1051 static char * 1052 tounix_str(char *str) 1053 { 1054 static char buf[BUFSIZ]; 1055 int i, j; 1056 int openBracket = FALSE; 1057 1058 (void) memset(buf, 0, BUFSIZ); 1059 j = 0; 1060 1061 for (i = 0; i < strlen(str); i++) { 1062 if (str[i] == '%') { 1063 if (isupper(str[i+1])) { 1064 i += 1; 1065 } else if ((str[i+1] == '[') && (isupper(str[i+2]))) { 1066 i += 2; 1067 openBracket = TRUE; 1068 } 1069 } else if (str[i] == ']') { 1070 if ((isupper(str[i-1])) && (openBracket == TRUE)) 1071 i += 1; 1072 openBracket = FALSE; 1073 } 1074 buf[j] = str[i]; 1075 j++; 1076 } 1077 return (buf); 1078 } 1079