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