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
isAttrMapped(char * orig,char * mapped)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
isObjectMapped(char * orig,char * mapped)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
init_ldap(char ** stack,char *** stkptr)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
getmapent_ldap(char * key,char * map,struct mapline * ml,char ** stack,char *** stkptr,bool_t * iswildcard,bool_t isrestricted)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
ldap_match(char * map,char * key,char ** ldap_line,int * ldap_len)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
loadmaster_ldap(char * mapname,char * defopts,char ** stack,char *** stkptr)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
loaddirect_ldap(char * nsmap,char * localmap,char * opts,char ** stack,char *** stkptr)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
ldap_err(int err)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
mastermap_callback_ldap(ns_ldap_entry_t * entry,void * udata)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
directmap_callback(ns_ldap_entry_t * entry,void * udata)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
getmapkeys_ldap(char * nsmap,struct dir_entry ** list,int * error,int * cache_time,char ** stack,char *** stkptr)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
readdir_callback(const ns_ldap_entry_t * entry,const void * udata)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 *
tosunds_str(char * str)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 *
tounix_str(char * str)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