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 2005 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 int 476 loadmaster_ldap(char *mapname, char *defopts, char **stack, char ***stkptr) 477 { 478 char searchfilter[LDAP_FILT_MAXSIZ]; 479 int res; 480 ns_ldap_result_t *result = NULL; 481 ns_ldap_error_t *errp = NULL; 482 struct loadmaster_cbdata master_cbdata; 483 484 if (trace > 1) 485 trace_prt(1, "loadmaster_ldap called\n"); 486 487 master_cbdata.ptr1 = defopts; 488 master_cbdata.ptr2 = stack; 489 master_cbdata.ptr3 = stkptr; 490 491 /* filter gets all the entries for the specified mapname */ 492 (void) sprintf(searchfilter, defaultFilter, "*"); 493 494 if (trace > 1) 495 trace_prt(1, "loadmaster_ldap: Requesting list for %s in %s\n", 496 searchfilter, mapname); 497 498 res = __ns_ldap_list(mapname, searchfilter, NULL, NULL, NULL, 499 0, &result, &errp, mastermap_callback_ldap, 500 (void *) &master_cbdata); 501 502 if (trace > 1) 503 trace_prt(1, 504 "loadmaster_ldap: __ns_ldap_list just returned: %d\n", 505 res); 506 507 if (res != NS_LDAP_SUCCESS) { 508 if (errp) { 509 char errstr[MAXERROR]; 510 if (verbose) { 511 (void) sprintf(errstr, gettext( 512 "ldap server can't list map," 513 "'%s': '%s' - '%d'."), 514 mapname, errp->message, errp->status); 515 syslog(LOG_ERR, errstr); 516 } 517 __ns_ldap_freeError(&errp); 518 } else { 519 if (verbose) { 520 char *errmsg; 521 __ns_ldap_err2str(res, &errmsg); 522 syslog(LOG_ERR, errmsg); 523 } 524 } 525 if (result) 526 __ns_ldap_freeResult(&result); 527 return (ldap_err(res)); 528 } 529 530 if (trace > 1) 531 trace_prt(1, 532 "loadmaster_ldap: calling __ns_ldap_freeResult...\n"); 533 534 __ns_ldap_freeResult(&result); 535 536 if (trace > 1) 537 trace_prt(1, 538 "loadmaster_ldap: about to return __NSW_SUCCESS...\n"); 539 540 return (__NSW_SUCCESS); 541 } 542 543 int 544 loaddirect_ldap(char *nsmap, char *localmap, char *opts, 545 char **stack, char ***stkptr) 546 { 547 char searchfilter[LDAP_FILT_MAXSIZ]; 548 int res; 549 ns_ldap_result_t *result = NULL; 550 ns_ldap_error_t *errp = NULL; 551 struct loaddirect_cbdata direct_cbdata; 552 553 if (trace > 1) { 554 trace_prt(1, "loaddirect_ldap called\n"); 555 } 556 557 direct_cbdata.ptr1 = opts; 558 direct_cbdata.ptr2 = localmap; 559 direct_cbdata.ptr3 = stack; 560 direct_cbdata.ptr4 = stkptr; 561 562 /* filter gets all the entries for the specified mapname */ 563 (void) sprintf(searchfilter, defaultFilter, "*"); 564 565 if (trace > 1) 566 trace_prt(1, "loaddirect_ldap: Requesting list for %s in %s\n", 567 searchfilter, nsmap); 568 569 res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, 570 NULL, 0, &result, &errp, 571 directmap_callback, (void *) &direct_cbdata); 572 573 574 if (res != NS_LDAP_SUCCESS) { 575 if (errp) { 576 char errstr[MAXERROR]; 577 if (verbose) { 578 (void) sprintf(errstr, 579 gettext("ldap server can't list map," 580 " '%s': '%s' - '%d'."), 581 nsmap, errp->message, errp->status); 582 syslog(LOG_ERR, errstr); 583 } 584 __ns_ldap_freeError(&errp); 585 } else { 586 if (verbose) { 587 char *errmsg; 588 __ns_ldap_err2str(res, &errmsg); 589 syslog(LOG_ERR, errmsg); 590 } 591 } 592 if (result) 593 __ns_ldap_freeResult(&result); 594 return (ldap_err(res)); 595 } 596 597 __ns_ldap_freeResult(&result); 598 return (__NSW_SUCCESS); 599 } 600 601 static int 602 ldap_err(int err) 603 { 604 if (trace > 1) 605 trace_prt(1, "ldap_err called\n"); 606 607 switch (err) { 608 609 case NS_LDAP_SUCCESS: 610 return (__NSW_SUCCESS); 611 612 case NS_LDAP_NOTFOUND: 613 return (__NSW_NOTFOUND); 614 615 case NS_LDAP_PARTIAL: 616 return (__NSW_TRYAGAIN); 617 618 default: 619 return (__NSW_UNAVAIL); 620 } 621 } 622 623 static int 624 mastermap_callback_ldap(ns_ldap_entry_t *entry, void *udata) 625 { 626 char *key, *contents, *pmap, *opts; 627 char dir[LINESZ], map[LINESZ], qbuff[LINESZ]; 628 char cont_temp[LINESZ], key_temp[LINESZ]; 629 int key_len, contents_len; 630 struct loadmaster_cbdata *temp = (struct loadmaster_cbdata *)udata; 631 char *defopts = temp->ptr1; 632 char **stack = temp->ptr2; 633 char ***stkptr = temp->ptr3; 634 int i; 635 636 if (trace > 1) { 637 trace_prt(1, "mastermap_callback_ldap called\n"); 638 trace_prt(1, "mastermap_callback_ldap: entry=%x\n", entry); 639 if (entry) { 640 trace_prt(1, 641 "mastermap_callback_ldap: entry->attr_count=[ %d ]\n", 642 entry->attr_count); 643 } 644 } 645 646 /* 647 * For the current entry, obtain the values of the cn and the 648 * nisMapEntry attributes and the length of each value (cn=key, 649 * nisMapEntry=contents). 650 * We skip the description. Even though LDAP allows for multiple 651 * values per attribute, we take only the 1st value for each 652 * attribute because the automount data is organized as such 653 * (same as NIS+). 654 */ 655 key_len = 0; 656 contents_len = 0; 657 key = NULL; 658 contents = NULL; 659 for (i = 0; i < entry->attr_count; i++) { 660 ns_ldap_attr_t *attr; 661 662 attr = entry->attr_pair[i]; 663 if (trace > 1) { 664 trace_prt(1, 665 "mastermap_callback_ldap: attr[%d]: %s=%s\n", 666 i, attr->attrname, attr->attrvalue[0]); 667 } 668 if (strcasecmp(attr->attrname, automountInformation) == 0) { 669 if (encode) 670 (void) strncpy(cont_temp, 671 tounix_str(attr->attrvalue[0]), LINESZ); 672 else 673 (void) strncpy(cont_temp, attr->attrvalue[0], 674 LINESZ); 675 contents = cont_temp; 676 contents_len = strlen(contents); 677 if (trace > 1) { 678 trace_prt(1, 679 "mastermap_callback_ldap: contents=[ %s ], contents_len=[ %d ]\n", 680 contents, contents_len); 681 } 682 } 683 if (strcasecmp(attr->attrname, automountKey) == 0) { 684 if (encode) 685 (void) strncpy(key_temp, 686 tounix_str(attr->attrvalue[0]), LINESZ); 687 else 688 (void) strncpy(key_temp, attr->attrvalue[0], 689 LINESZ); 690 key = key_temp; 691 key_len = strlen(key); 692 if (trace > 1) { 693 trace_prt(1, 694 "mastermap_callback_ldap: key=[ %s ], key_len=[ %d ]\n", 695 key, key_len); 696 } 697 } 698 } 699 700 if (key_len >= LINESZ || contents_len >= LINESZ) 701 return (0); 702 if (key_len < 2 || contents_len < 2) 703 return (0); 704 705 while (isspace(*contents)) 706 contents++; 707 if (contents == NULL) 708 return (0); 709 if (isspace(*key) || *key == '#') 710 return (0); 711 712 (void) strncpy(dir, key, key_len); 713 dir[key_len] = '\0'; 714 if (trace > 1) 715 trace_prt(1, "mastermap_callback_ldap: dir= [ %s ]\n", dir); 716 for (i = 0; i < LINESZ; i++) 717 qbuff[i] = ' '; 718 if (macro_expand("", dir, qbuff, sizeof (dir))) { 719 syslog(LOG_ERR, 720 "%s in ldap server map: entry too long (max %d chars)", 721 dir, sizeof (dir) - 1); 722 return (0); 723 } 724 (void) strncpy(map, contents, contents_len); 725 map[contents_len] = '\0'; 726 if (trace > 1) 727 trace_prt(1, "mastermap_callback_ldap: map= [ %s ]\n", map); 728 if (macro_expand("", map, qbuff, sizeof (map))) { 729 syslog(LOG_ERR, 730 "%s in ldap server map: entry too long (max %d chars)", 731 map, sizeof (map) - 1); 732 return (0); 733 } 734 pmap = map; 735 while (*pmap && isspace(*pmap)) 736 pmap++; /* skip blanks in front of map */ 737 opts = pmap; 738 while (*opts && !isspace(*opts)) 739 opts++; 740 if (*opts) { 741 *opts++ = '\0'; 742 while (*opts && isspace(*opts)) 743 opts++; 744 if (*opts == '-') 745 opts++; 746 else 747 opts = defopts; 748 } 749 /* 750 * Check for no embedded blanks. 751 */ 752 if (strcspn(opts, " ") == strlen(opts)) { 753 if (trace > 1) 754 trace_prt(1, 755 "mastermap_callback_ldap: dir=[ %s ], pmap=[ %s ]\n", 756 dir, pmap); 757 dirinit(dir, pmap, opts, 0, stack, stkptr); 758 } else { 759 char *dn = NULL; 760 761 /* get the value for the dn */ 762 for (i = 0; i < entry->attr_count; i++) { 763 ns_ldap_attr_t *attr; 764 765 attr = entry->attr_pair[i]; 766 if (strcasecmp(attr->attrname, "dn") 767 == 0) { 768 dn = attr->attrvalue[0]; 769 break; 770 } 771 } 772 pr_msg( 773 "Warning: invalid entry for %s in ldap server dn: %s ignored.\n", 774 dir, dn); 775 } 776 if (trace > 1) 777 trace_prt(1, "mastermap_callback_ldap exiting...\n"); 778 return (0); 779 } 780 781 static int 782 directmap_callback(ns_ldap_entry_t *entry, void *udata) 783 { 784 char *key; 785 char dir[256]; 786 int key_len; 787 struct loaddirect_cbdata *temp = (struct loaddirect_cbdata *)udata; 788 char *opts = temp->ptr1; 789 char *localmap = temp->ptr2; 790 char **stack = temp->ptr3; 791 char ***stkptr = temp->ptr4; 792 int i; 793 794 /* 795 * For the current entry, obtain the value and length of the cn i.e. 796 * the contents of key and its key length. 797 */ 798 key_len = 0; 799 key = NULL; 800 for (i = 0; i < entry->attr_count; i++) { 801 ns_ldap_attr_t *attr; 802 803 attr = entry->attr_pair[i]; 804 if (strcasecmp(attr->attrname, automountKey) == 0) { 805 if (encode) 806 key = tounix_str(attr->attrvalue[0]); 807 else 808 key = attr->attrvalue[0]; 809 key_len = strlen(key); 810 break; 811 } 812 } 813 814 if (key_len >= 100 || key_len < 2) 815 return (0); 816 817 if (isspace(*key) || *key == '#') 818 return (0); 819 (void) strncpy(dir, key, key_len); 820 dir[key_len] = '\0'; 821 822 dirinit(dir, localmap, opts, 1, stack, stkptr); 823 824 return (0); 825 } 826 827 int 828 getmapkeys_ldap(char *nsmap, struct dir_entry **list, int *error, 829 int *cache_time, char **stack, char ***stkptr) 830 { 831 char searchfilter[LDAP_FILT_MAXSIZ]; 832 int res; 833 ns_ldap_result_t *result = NULL; 834 ns_ldap_error_t *errp = NULL; 835 struct dir_cbdata readdir_cbdata; 836 837 #ifdef lint 838 stack = stack; 839 stkptr = stkptr; 840 #endif /* lint */ 841 842 if (trace > 1) 843 trace_prt(1, "getmapkeys_ldap called\n"); 844 845 *cache_time = RDDIR_CACHE_TIME; 846 *error = 0; 847 readdir_cbdata.list = list; 848 readdir_cbdata.last = NULL; 849 850 /* filter gets all the entries for the specified mapname */ 851 (void) sprintf(searchfilter, defaultFilter, "*"); 852 853 if (trace > 1) 854 trace_prt(1, "getmapkeys_ldap: Requesting list for %s in %s\n", 855 searchfilter, nsmap); 856 857 res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, NULL, 0, 858 &result, &errp, readdir_callback, (void *) &readdir_cbdata); 859 860 if (trace > 1) 861 trace_prt(1, " getmapkeys_ldap: __ns_ldap_list returned %d\n", 862 res); 863 864 if (readdir_cbdata.error) 865 *error = readdir_cbdata.error; 866 867 if (res != NS_LDAP_SUCCESS && res != NS_LDAP_NOTFOUND) { 868 if (errp) { 869 if (verbose) { 870 char errstr[MAXERROR]; 871 (void) sprintf(errstr, gettext( 872 "ldap server can't list map," 873 " '%s': '%s' - '%d'."), 874 nsmap, errp->message, errp->status); 875 syslog(LOG_ERR, errstr); 876 } 877 __ns_ldap_freeError(&errp); 878 } else { 879 if (verbose) { 880 char *errmsg; 881 __ns_ldap_err2str(res, &errmsg); 882 syslog(LOG_ERR, errmsg); 883 } 884 } 885 if (result) 886 __ns_ldap_freeResult(&result); 887 if (*error == 0) 888 *error = ECOMM; 889 return (ldap_err(res)); 890 } 891 if (result) 892 __ns_ldap_freeResult(&result); 893 894 return (__NSW_SUCCESS); 895 } 896 897 static int 898 readdir_callback(const ns_ldap_entry_t *entry, const void *udata) 899 { 900 char *key; 901 int key_len; 902 struct dir_cbdata *temp = (struct dir_cbdata *)udata; 903 struct dir_entry **list = temp->list; 904 struct dir_entry *last = temp->last; 905 int i; 906 907 if (trace > 1) 908 trace_prt(1, "readdir_callback called\n"); 909 /* 910 * For the current entry, obtain the value and length of the cn i.e. the 911 * contents of key and its key length. 912 */ 913 key_len = 0; 914 key = NULL; 915 916 if (trace > 1) 917 trace_prt(1, "readdir_callback: entry->attr_count=[ %d ]\n", 918 entry->attr_count); 919 920 for (i = 0; i < entry->attr_count; i++) { 921 ns_ldap_attr_t *attr; 922 923 attr = entry->attr_pair[i]; 924 925 if (trace > 1) 926 trace_prt(1, 927 "readdir_callback: attr->attrname=[ %s ]\n", 928 attr->attrname); 929 930 if (strcasecmp(attr->attrname, automountKey) == 0) { 931 if (encode) 932 key = tounix_str(attr->attrvalue[0]); 933 else 934 key = attr->attrvalue[0]; 935 key_len = strlen(key); 936 937 if (trace > 1) 938 trace_prt(1, 939 "readdir_callback: key=[ %s ], key_len=[ %d ]\n", 940 key, key_len); 941 942 break; 943 } 944 } 945 946 if (key_len >= 100 || key_len < 2) 947 return (0); 948 949 if (isspace(*key) || *key == '#') 950 return (0); 951 952 /* 953 * Wildcard entry should be ignored - following entries should continue 954 * to be read to corroborate with the way we search for entries in 955 * LDAP, i.e., first for an exact key match and then a wildcard 956 * if there's no exact key match. 957 */ 958 if (key[0] == '*' && key[1] == '\0') 959 return (0); 960 961 if (add_dir_entry(key, list, &last)) { 962 temp->error = ENOMEM; 963 return (1); 964 } 965 966 temp->last = last; 967 temp->error = 0; 968 969 if (trace > 1) 970 trace_prt(1, "readdir_callback returning 0...\n"); 971 972 return (0); 973 } 974 975 /* 976 * Puts CAPCHAR in front of uppercase characters or surrounds a set of 977 * contiguous uppercase characters with CAPCHARS and square brackets. 978 * 979 * For example (assuming CAPCHAR = '%'): 980 * 981 * if str = Abc, it returns %Abc 982 * if str = ABc, it returns %[AB]c 983 * if str = AbC, it returns %Ab%C 984 * 985 */ 986 static char * 987 tosunds_str(char *str) 988 { 989 static char buf[BUFSIZ]; 990 int i, j, er = FALSE; 991 #ifdef NEWCAP 992 int openBracket = FALSE, closeBracket = FALSE; 993 #endif 994 995 (void) memset(buf, 0, BUFSIZ); 996 997 j = 0; 998 for (i = 0; i < strlen(str); i++) { 999 /* Check the current element */ 1000 if (isupper(str[i])) { 1001 #ifdef NEWCAP 1002 /* check the next element */ 1003 if (isupper(str[i+1])) { 1004 if (openBracket == FALSE) { 1005 openBracket = TRUE; 1006 buf[j] = CAPCHAR; 1007 buf[j+1] = '['; 1008 j += 2; 1009 } 1010 } else { 1011 if (openBracket == FALSE) { 1012 buf[j] = CAPCHAR; 1013 j++; 1014 } else { 1015 openBracket = FALSE; 1016 closeBracket = TRUE; 1017 } 1018 } 1019 #else 1020 buf[j++] = CAPCHAR; 1021 #endif 1022 } 1023 buf[j] = str[i]; 1024 j++; 1025 1026 #ifdef NEWCAP 1027 if (closeBracket == TRUE) { 1028 closeBracket = FALSE; 1029 buf[j] = ']'; 1030 j++; 1031 } 1032 #endif 1033 if (j >= BUFSIZ) { 1034 er = TRUE; 1035 break; 1036 } 1037 } 1038 1039 if (er) { 1040 syslog(LOG_ERR, "Buffer size exceeded."); 1041 (void) memset(buf, 0, BUFSIZ); 1042 } else 1043 buf[j] = '\0'; 1044 1045 return (buf); 1046 1047 } 1048 1049 /* 1050 * Reverses what tosunds_str() did 1051 */ 1052 static char * 1053 tounix_str(char *str) 1054 { 1055 static char buf[BUFSIZ]; 1056 int i, j; 1057 int openBracket = FALSE; 1058 1059 (void) memset(buf, 0, BUFSIZ); 1060 j = 0; 1061 1062 for (i = 0; i < strlen(str); i++) { 1063 if (str[i] == '%') { 1064 if (isupper(str[i+1])) { 1065 i += 1; 1066 } else if ((str[i+1] == '[') && (isupper(str[i+2]))) { 1067 i += 2; 1068 openBracket = TRUE; 1069 } 1070 } else if (str[i] == ']') { 1071 if ((isupper(str[i-1])) && (openBracket == TRUE)) 1072 i += 1; 1073 openBracket = FALSE; 1074 } 1075 buf[j] = str[i]; 1076 j++; 1077 } 1078 return (buf); 1079 } 1080