6253 F_GETLK doesn't always return lock owner
[illumos-gate.git] / usr / src / cmd / fs.d / autofs / ns_ldap.c
blob419a0911878fb943ed525292f224414a3809e017
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * ns_ldap.c
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
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"
44 * LDAP schema used for automounter:
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)
51 * For example, if auto_direct has the following line of data:
53 * /work -rw,intr,nosuid,noquota hosta:/export/work
55 * Then this would map to the the following LDAP entry:
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
63 * In this container:
65 * dn: automountMapName=auto_direct,...
66 * automountMapName: auto_direct
67 * objectClass: top
68 * objectClass: automountMap
70 * Note that the schema can be mapped and SSD's can be used to relocate
71 * the default location of these entries.
75 #define CAPCHAR '%'
76 #define MAXERROR 4000
78 static char *automountKey = NULL;
79 static char *automountInformation = NULL;
80 static char *defaultFilter = NULL;
81 static int encode = 0;
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();
89 struct loadmaster_cbdata {
90 char *ptr1;
91 char **ptr2;
92 char ***ptr3;
95 struct loaddirect_cbdata {
96 char *ptr1;
97 char *ptr2;
98 char **ptr3;
99 char ***ptr4;
102 struct dir_cbdata {
103 struct dir_entry **list;
104 struct dir_entry *last;
105 int error;
108 static char *tosunds_str(char *);
109 static char *tounix_str(char *);
111 static int
112 isAttrMapped(char *orig, char *mapped)
114 char **s;
115 char **mappedschema = NULL;
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);
126 for (s = mappedschema; *s != NULL; s++)
127 free(*s);
128 free(mappedschema);
129 return (1);
132 static int
133 isObjectMapped(char *orig, char *mapped)
135 char **s;
136 char **mappedschema = NULL;
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);
147 for (s = mappedschema; *s != NULL; s++)
148 free(*s);
149 free(mappedschema);
150 return (1);
153 void
154 init_ldap(char **stack, char ***stkptr)
157 * Check for version of the profile the client is using
159 * For version 1 profiles we do encoding of attributes
160 * and use nisMap and nisObject schema for backward compatibility.
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).
167 * If profile version is not available, use version 2 as default
168 * and syslog message.
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;
178 #ifdef lint
179 stack = stack;
180 stkptr = stkptr;
181 #endif /* lint */
183 /* get nsswitch info of "automount */
184 conf = __nsw_getconfig("automount", &pserr);
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;
194 /* free conf at the end of "if" bracket */
195 (void) __nsw_freeconfig(conf);
198 /* if ldap is not configured, init_ldap is a no op */
199 if (!ldap_configured)
200 return;
202 rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, &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(&paramVal);
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))";
222 /* check for automountMapName mapped to nisMapName */
223 if (!isAttrMapped("automountMapName", "nisMapName"))
224 return;
226 /* check for automountKey mapped to cn */
227 if (!isAttrMapped("automountKey", "cn"))
228 return;
230 /* check for automountInformation mapped to nisMapEntry */
231 if (!isAttrMapped("automountInformation", "nisMapEntry"))
232 return;
234 /* check for automountMap mapped to nisMap */
235 if (!isObjectMapped("automountMap", "nisMap"))
236 return;
238 /* check for automount mapped to nisObject */
239 if (!isObjectMapped("automount", "nisObject"))
240 return;
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");
250 encode = 1;
251 automountKey = "cn";
252 automountInformation = "nisMapEntry";
253 defaultFilter = "(&(objectClass=nisObject)(cn=%s))";
257 /*ARGSUSED*/
259 getmapent_ldap(char *key, char *map, struct mapline *ml,
260 char **stack, char ***stkptr, bool_t *iswildcard, bool_t isrestricted)
262 char *ldap_line = NULL;
263 char *lp;
264 int ldap_len, len;
265 int nserr;
267 if (trace > 1)
268 trace_prt(1, "getmapent_ldap called\n");
270 if (trace > 1) {
271 trace_prt(1, "getmapent_ldap: key=[ %s ]\n", key);
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;
287 } else
288 goto done;
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
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;
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;
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);
318 if (trace > 1)
319 trace_prt(1, "getmapent_ldap: exiting ...\n");
321 return (nserr);
324 static int
325 ldap_match(char *map, char *key, char **ldap_line, int *ldap_len)
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;
335 if (trace > 1) {
336 trace_prt(1, "ldap_match called\n");
337 trace_prt(1, "ldap_match: key =[ %s ]\n", key);
341 * need to handle uppercase characters in the key because LDAP
342 * searches are case insensitive. Note, key = attribute automountKey.
344 if (encode)
345 ldapkey = tosunds_str(key);
346 else
347 ldapkey = key;
349 if (trace > 1) {
350 trace_prt(1, "ldap_match: ldapkey =[ %s ]\n", ldapkey);
353 (void) sprintf(searchfilter, defaultFilter, ldapkey);
355 if (trace > 1)
356 trace_prt(1, " ldap_match: Requesting list for %s in %s\n",
357 searchfilter, map);
359 res = __ns_ldap_list(map, searchfilter, NULL,
360 NULL, NULL, 0, &result, &errp, NULL, NULL);
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");
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);
380 __ns_ldap_freeError(&errp);
381 } else {
382 if (verbose) {
383 char *errmsg;
384 __ns_ldap_err2str(res, &errmsg);
385 syslog(LOG_ERR, errmsg);
388 if (result)
389 __ns_ldap_freeResult(&result);
390 return (ldap_err(res));
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);
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:
410 * key: /work
411 * ^^^^^
412 * (mount point)
414 * nisMapEntry: -rw,intr,nosuid,noquota hosta:/export/work
415 * ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
416 * ( mount options ) (remote mount location)
419 attr_found = 0;
420 entry = result->entry;
421 for (i = 0; i < entry->attr_count; i++) {
422 ns_ldap_attr_t *attr;
424 attr = entry->attr_pair[i];
425 if (strcasecmp(attr->attrname, automountInformation) == 0) {
426 char *attrval;
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);
436 * so check for the length; it should be less than
437 * LINESZ
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);
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);
454 (void) sprintf(*ldap_line, "%s", attrval);
456 break;
460 __ns_ldap_freeError(&errp);
461 __ns_ldap_freeResult(&result);
463 if (!attr_found)
464 return (__NSW_NOTFOUND);
466 if (trace > 1)
467 trace_prt(1, " ldap_match: found: %s\n", *ldap_line);
469 return (__NSW_SUCCESS);
473 loadmaster_ldap(char *mapname, char *defopts, char **stack, char ***stkptr)
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;
481 if (trace > 1)
482 trace_prt(1, "loadmaster_ldap called\n");
484 master_cbdata.ptr1 = defopts;
485 master_cbdata.ptr2 = stack;
486 master_cbdata.ptr3 = stkptr;
488 /* filter gets all the entries for the specified mapname */
489 (void) sprintf(searchfilter, defaultFilter, "*");
491 if (trace > 1)
492 trace_prt(1, "loadmaster_ldap: Requesting list for %s in %s\n",
493 searchfilter, mapname);
495 res = __ns_ldap_list(mapname, searchfilter, NULL, NULL, NULL,
496 0, &result, &errp, mastermap_callback_ldap,
497 (void *) &master_cbdata);
499 if (trace > 1)
500 trace_prt(1,
501 "loadmaster_ldap: __ns_ldap_list just returned: %d\n",
502 res);
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);
514 __ns_ldap_freeError(&errp);
515 } else {
516 if (verbose) {
517 char *errmsg;
518 __ns_ldap_err2str(res, &errmsg);
519 syslog(LOG_ERR, errmsg);
522 if (result)
523 __ns_ldap_freeResult(&result);
524 return (ldap_err(res));
527 if (trace > 1)
528 trace_prt(1,
529 "loadmaster_ldap: calling __ns_ldap_freeResult...\n");
531 __ns_ldap_freeResult(&result);
533 if (trace > 1)
534 trace_prt(1,
535 "loadmaster_ldap: about to return __NSW_SUCCESS...\n");
537 return (__NSW_SUCCESS);
541 loaddirect_ldap(char *nsmap, char *localmap, char *opts,
542 char **stack, char ***stkptr)
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;
550 if (trace > 1) {
551 trace_prt(1, "loaddirect_ldap called\n");
554 direct_cbdata.ptr1 = opts;
555 direct_cbdata.ptr2 = localmap;
556 direct_cbdata.ptr3 = stack;
557 direct_cbdata.ptr4 = stkptr;
559 /* filter gets all the entries for the specified mapname */
560 (void) sprintf(searchfilter, defaultFilter, "*");
562 if (trace > 1)
563 trace_prt(1, "loaddirect_ldap: Requesting list for %s in %s\n",
564 searchfilter, nsmap);
566 res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL,
567 NULL, 0, &result, &errp,
568 directmap_callback, (void *) &direct_cbdata);
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);
581 __ns_ldap_freeError(&errp);
582 } else {
583 if (verbose) {
584 char *errmsg;
585 __ns_ldap_err2str(res, &errmsg);
586 syslog(LOG_ERR, errmsg);
589 if (result)
590 __ns_ldap_freeResult(&result);
591 return (ldap_err(res));
594 __ns_ldap_freeResult(&result);
595 return (__NSW_SUCCESS);
598 static int
599 ldap_err(int err)
601 if (trace > 1)
602 trace_prt(1, "ldap_err called\n");
604 switch (err) {
606 case NS_LDAP_SUCCESS:
607 return (__NSW_SUCCESS);
609 case NS_LDAP_NOTFOUND:
610 return (__NSW_NOTFOUND);
612 case NS_LDAP_PARTIAL:
613 return (__NSW_TRYAGAIN);
615 default:
616 return (__NSW_UNAVAIL);
620 static int
621 mastermap_callback_ldap(ns_ldap_entry_t *entry, void *udata)
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;
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);
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.
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;
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]);
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);
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);
698 if (key_len >= LINESZ || contents_len >= LINESZ)
699 return (0);
700 if (key_len < 2 || contents_len < 2)
701 return (0);
703 while (isspace(*contents))
704 contents++;
705 if (contents == NULL)
706 return (0);
707 if (isspace(*key) || *key == '#')
708 return (0);
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);
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);
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;
748 * Check for no embedded blanks.
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;
759 /* get the value for the dn */
760 for (i = 0; i < entry->attr_count; i++) {
761 ns_ldap_attr_t *attr;
763 attr = entry->attr_pair[i];
764 if (strcasecmp(attr->attrname, "dn")
765 == 0) {
766 dn = attr->attrvalue[0];
767 break;
770 pr_msg(
771 "Warning: invalid entry for %s in ldap server"
772 " dn: %s ignored.\n",
773 dir, dn);
775 if (trace > 1)
776 trace_prt(1, "mastermap_callback_ldap exiting...\n");
777 return (0);
780 static int
781 directmap_callback(ns_ldap_entry_t *entry, void *udata)
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;
794 * For the current entry, obtain the value and length of the cn i.e.
795 * the contents of key and its key length.
797 key_len = 0;
798 key = NULL;
799 for (i = 0; i < entry->attr_count; i++) {
800 ns_ldap_attr_t *attr;
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;
813 if (key_len >= 100 || key_len < 2)
814 return (0);
816 if (isspace(*key) || *key == '#')
817 return (0);
818 (void) strncpy(dir, key, key_len);
819 dir[key_len] = '\0';
821 dirinit(dir, localmap, opts, 1, stack, stkptr);
823 return (0);
827 getmapkeys_ldap(char *nsmap, struct dir_entry **list, int *error,
828 int *cache_time, char **stack, char ***stkptr)
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;
836 #ifdef lint
837 stack = stack;
838 stkptr = stkptr;
839 #endif /* lint */
841 if (trace > 1)
842 trace_prt(1, "getmapkeys_ldap called\n");
844 *cache_time = RDDIR_CACHE_TIME;
845 *error = 0;
846 readdir_cbdata.list = list;
847 readdir_cbdata.last = NULL;
849 /* filter gets all the entries for the specified mapname */
850 (void) sprintf(searchfilter, defaultFilter, "*");
852 if (trace > 1)
853 trace_prt(1, "getmapkeys_ldap: Requesting list for %s in %s\n",
854 searchfilter, nsmap);
856 res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, NULL, 0,
857 &result, &errp, readdir_callback, (void *) &readdir_cbdata);
859 if (trace > 1)
860 trace_prt(1, " getmapkeys_ldap: __ns_ldap_list returned %d\n",
861 res);
863 if (readdir_cbdata.error)
864 *error = readdir_cbdata.error;
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);
876 __ns_ldap_freeError(&errp);
877 } else {
878 if (verbose) {
879 char *errmsg;
880 __ns_ldap_err2str(res, &errmsg);
881 syslog(LOG_ERR, errmsg);
884 if (result)
885 __ns_ldap_freeResult(&result);
886 if (*error == 0)
887 *error = ECOMM;
888 return (ldap_err(res));
890 if (result)
891 __ns_ldap_freeResult(&result);
893 return (__NSW_SUCCESS);
896 static int
897 readdir_callback(const ns_ldap_entry_t *entry, const void *udata)
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;
906 if (trace > 1)
907 trace_prt(1, "readdir_callback called\n");
909 * For the current entry, obtain the value and length of the cn i.e. the
910 * contents of key and its key length.
912 key_len = 0;
913 key = NULL;
915 if (trace > 1)
916 trace_prt(1, "readdir_callback: entry->attr_count=[ %d ]\n",
917 entry->attr_count);
919 for (i = 0; i < entry->attr_count; i++) {
920 ns_ldap_attr_t *attr;
922 attr = entry->attr_pair[i];
924 if (trace > 1)
925 trace_prt(1,
926 "readdir_callback: attr->attrname=[ %s ]\n",
927 attr->attrname);
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);
936 if (trace > 1)
937 trace_prt(1,
938 "readdir_callback: key=[ %s ], key_len=[ %d ]\n",
939 key, key_len);
941 break;
945 if (key_len >= 100 || key_len < 2)
946 return (0);
948 if (isspace(*key) || *key == '#')
949 return (0);
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.
957 if (key[0] == '*' && key[1] == '\0')
958 return (0);
960 if (add_dir_entry(key, list, &last)) {
961 temp->error = ENOMEM;
962 return (1);
965 temp->last = last;
966 temp->error = 0;
968 if (trace > 1)
969 trace_prt(1, "readdir_callback returning 0...\n");
971 return (0);
975 * Puts CAPCHAR in front of uppercase characters or surrounds a set of
976 * contiguous uppercase characters with CAPCHARS and square brackets.
978 * For example (assuming CAPCHAR = '%'):
980 * if str = Abc, it returns %Abc
981 * if str = ABc, it returns %[AB]c
982 * if str = AbC, it returns %Ab%C
985 static char *
986 tosunds_str(char *str)
988 static char buf[BUFSIZ];
989 int i, j, er = FALSE;
990 #ifdef NEWCAP
991 int openBracket = FALSE, closeBracket = FALSE;
992 #endif
994 (void) memset(buf, 0, BUFSIZ);
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;
1009 } else {
1010 if (openBracket == FALSE) {
1011 buf[j] = CAPCHAR;
1012 j++;
1013 } else {
1014 openBracket = FALSE;
1015 closeBracket = TRUE;
1018 #else
1019 buf[j++] = CAPCHAR;
1020 #endif
1022 buf[j] = str[i];
1023 j++;
1025 #ifdef NEWCAP
1026 if (closeBracket == TRUE) {
1027 closeBracket = FALSE;
1028 buf[j] = ']';
1029 j++;
1031 #endif
1032 if (j >= BUFSIZ) {
1033 er = TRUE;
1034 break;
1038 if (er) {
1039 syslog(LOG_ERR, "Buffer size exceeded.");
1040 (void) memset(buf, 0, BUFSIZ);
1041 } else
1042 buf[j] = '\0';
1044 return (buf);
1049 * Reverses what tosunds_str() did
1051 static char *
1052 tounix_str(char *str)
1054 static char buf[BUFSIZ];
1055 int i, j;
1056 int openBracket = FALSE;
1058 (void) memset(buf, 0, BUFSIZ);
1059 j = 0;
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;
1069 } else if (str[i] == ']') {
1070 if ((isupper(str[i-1])) && (openBracket == TRUE))
1071 i += 1;
1072 openBracket = FALSE;
1074 buf[j] = str[i];
1075 j++;
1077 return (buf);