xref: /illumos-gate/usr/src/cmd/fs.d/autofs/ns_nis.c (revision 4bc0a2ef2b7ba50a7a717e7ddbf31472ad28e358)
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_nis.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 <unistd.h>
34 #include <syslog.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <nsswitch.h>
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/systeminfo.h>
41 #include <rpc/rpc.h>
42 #include <rpcsvc/nfs_prot.h>
43 #include <rpcsvc/ypclnt.h>
44 #include <rpcsvc/yp_prot.h>
45 #include <sys/errno.h>
46 #include "automount.h"
47 
48 #define	KEY		0
49 #define	CONTENTS	1
50 
51 static int replace_undscr_by_dot(char *);
52 static int nis_err(int);
53 
54 static char nis_mydomain[YPMAXDOMAIN];
55 
56 struct dir_cbdata {
57 	struct dir_entry **list;
58 	struct dir_entry *last;
59 	int error;
60 };
61 
62 static int readdir_callback(int, char *, int, const char *,
63 				int, struct dir_cbdata *);
64 
65 void
66 init_nis(char **stack, char ***stkptr)
67 {
68 #ifdef lint
69 	stack = stack;
70 	stkptr = stkptr;
71 #endif /* lint */
72 
73 	(void) sysinfo(SI_SRPC_DOMAIN, nis_mydomain, sizeof (nis_mydomain));
74 	(void) __nis_reset_state();	/* XXX temporary hack for csh bug */
75 }
76 
77 /*ARGSUSED*/
78 int
79 getmapent_nis(key, map, ml, stack, stkptr, iswildcard, isrestricted)
80 	char *key, *map;
81 	struct mapline *ml;
82 	char **stack;
83 	char ***stkptr;
84 	bool_t *iswildcard;
85 	bool_t isrestricted;
86 {
87 	char *nisline = NULL;
88 	char *my_map = NULL;
89 	char *lp, *lq;
90 	int nislen, len;
91 	int nserr;
92 
93 	if (iswildcard)
94 		*iswildcard = FALSE;
95 	nserr = yp_match(nis_mydomain, map, key, strlen(key),
96 						&nisline, &nislen);
97 	if (nserr == YPERR_MAP) {
98 		my_map = strdup(map);
99 		if (my_map == NULL) {
100 			syslog(LOG_ERR,
101 				"getmapent_nis: memory alloc failed: %m");
102 			return (__NSW_UNAVAIL);
103 		}
104 		if (replace_undscr_by_dot(my_map))
105 			nserr = yp_match(nis_mydomain, my_map, key,
106 					strlen(key), &nisline, &nislen);
107 	}
108 
109 	if (nserr) {
110 		if (nserr == YPERR_KEY) {
111 			/*
112 			 * Try the default entry "*"
113 			 */
114 			if (my_map == NULL)
115 				nserr = yp_match(nis_mydomain, map, "*", 1,
116 						&nisline, &nislen);
117 			else
118 				nserr = yp_match(nis_mydomain, my_map, "*", 1,
119 						&nisline, &nislen);
120 			if (!nserr && iswildcard)
121 				*iswildcard = TRUE;
122 		} else {
123 			if (verbose)
124 				syslog(LOG_ERR, "%s: %s",
125 					map, yperr_string(nserr));
126 			nserr = 1;
127 		}
128 	}
129 	if (my_map != NULL)
130 		free(my_map);
131 
132 	nserr = nis_err(nserr);
133 	if (nserr)
134 		goto done;
135 
136 	/*
137 	 * at this point we are sure that yp_match succeeded
138 	 * so massage the entry by
139 	 * 1. ignoring # and beyond
140 	 * 2. trim the trailing whitespace
141 	 */
142 	if (lp = strchr(nisline, '#'))
143 		*lp = '\0';
144 	len = strlen(nisline);
145 	if (len == 0) {
146 		nserr = __NSW_NOTFOUND;
147 		goto done;
148 	}
149 	lp = &nisline[len - 1];
150 	while (lp > nisline && isspace(*lp))
151 		*lp-- = '\0';
152 	if (lp == nisline) {
153 		nserr = __NSW_NOTFOUND;
154 		goto done;
155 	}
156 	(void) strcpy(ml->linebuf, nisline);
157 	lp = ml->linebuf;
158 	lq = ml->lineqbuf;
159 	unquote(lp, lq);
160 	/* now we have the correct line */
161 
162 	nserr = __NSW_SUCCESS;
163 done:
164 	if (nisline)
165 		free((char *)nisline);
166 	return (nserr);
167 
168 }
169 
170 int
171 loadmaster_nis(mapname, defopts, stack, stkptr)
172 	char *mapname, *defopts;
173 	char **stack;
174 	char ***stkptr;
175 {
176 	int first, err;
177 	char *key, *nkey, *val;
178 	int kl, nkl, vl;
179 	char dir[256], map[256], qbuff[256];
180 	char *pmap, *opts, *my_mapname;
181 	int count = 0;
182 
183 	first = 1;
184 	key  = NULL; kl  = 0;
185 	nkey = NULL; nkl = 0;
186 	val  = NULL; vl  = 0;
187 
188 	/*
189 	 * need a private copy of mapname, because we may change
190 	 * the underscores by dots. We however do not want the
191 	 * orignal to be changed, as we may want to use the
192 	 * original name in some other name service
193 	 */
194 	my_mapname = strdup(mapname);
195 	if (my_mapname == NULL) {
196 		syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
197 		/* not the name svc's fault but ... */
198 		return (__NSW_UNAVAIL);
199 	}
200 	for (;;) {
201 		if (first) {
202 			first = 0;
203 			err = yp_first(nis_mydomain, my_mapname,
204 				&nkey, &nkl, &val, &vl);
205 
206 			if ((err == YPERR_MAP) &&
207 			    (replace_undscr_by_dot(my_mapname)))
208 				err = yp_first(nis_mydomain, my_mapname,
209 					&nkey, &nkl, &val, &vl);
210 
211 			if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
212 				syslog(LOG_ERR,
213 					"can't read nis map %s: %s - retrying",
214 					my_mapname, yperr_string(err));
215 				while ((err == YPERR_DOMAIN) ||
216 					(err == YPERR_YPBIND)) {
217 					(void) sleep(20);
218 					err = yp_first(nis_mydomain, my_mapname,
219 						&nkey, &nkl, &val, &vl);
220 				}
221 				syslog(LOG_ERR,
222 					"nis map %s: read OK.", my_mapname);
223 			}
224 		} else {
225 			err = yp_next(nis_mydomain, my_mapname, key, kl,
226 				&nkey, &nkl, &val, &vl);
227 		}
228 		if (err) {
229 			if (err != YPERR_NOMORE && err != YPERR_MAP)
230 				if (verbose)
231 					syslog(LOG_ERR, "%s: %s",
232 					my_mapname, yperr_string(err));
233 			break;
234 		}
235 		if (key)
236 			free(key);
237 		key = nkey;
238 		kl = nkl;
239 
240 
241 		if (kl >= 256 || vl >= 256)
242 			break;
243 		if (kl < 2 || vl < 1)
244 			break;
245 		if (isspace(*key) || *key == '#')
246 			break;
247 		(void) strncpy(dir, key, kl);
248 		dir[kl] = '\0';
249 		if (macro_expand("", dir, qbuff, sizeof (dir))) {
250 			syslog(LOG_ERR,
251 			    "%s in NIS map %s: entry too long (max %d chars)",
252 			    dir, my_mapname, sizeof (dir) - 1);
253 			break;
254 		}
255 		(void) strncpy(map, val, vl);
256 		map[vl] = '\0';
257 		if (macro_expand(dir, map, qbuff, sizeof (map))) {
258 			syslog(LOG_ERR,
259 			    "%s in NIS map %s: entry too long (max %d chars)",
260 			    map, my_mapname, sizeof (map) - 1);
261 			break;
262 		}
263 		pmap = map;
264 		while (*pmap && isspace(*pmap))
265 			pmap++;		/* skip blanks in front of map */
266 		opts = pmap;
267 		while (*opts && !isspace(*opts))
268 			opts++;
269 		if (*opts) {
270 			*opts++ = '\0';
271 			while (*opts && isspace(*opts))
272 				opts++;
273 			if (*opts == '-')
274 				opts++;
275 			else
276 				opts = defopts;
277 		}
278 		free(val);
279 
280 		/*
281 		 * Check for no embedded blanks.
282 		 */
283 		if (strcspn(opts, " 	") == strlen(opts)) {
284 			dirinit(dir, pmap, opts, 0, stack, stkptr);
285 			count++;
286 		} else {
287 pr_msg("Warning: invalid entry for %s in NIS map %s ignored.\n", dir, mapname);
288 		}
289 
290 	}
291 	if (my_mapname)
292 		free(my_mapname);
293 
294 	/*
295 	 * In the context of a master map, if no entry is
296 	 * found, it is like NOTFOUND
297 	 */
298 	if (count > 0 && err == YPERR_NOMORE)
299 		return (__NSW_SUCCESS);
300 	else {
301 		if (err)
302 			return (nis_err(err));
303 		else
304 			/*
305 			 * This case will happen if map is empty
306 			 *  or none of the entries is valid
307 			 */
308 			return (__NSW_NOTFOUND);
309 	}
310 }
311 
312 int
313 loaddirect_nis(nismap, localmap, opts, stack, stkptr)
314 	char *nismap, *localmap, *opts;
315 	char **stack;
316 	char ***stkptr;
317 {
318 	int first, err, count;
319 	char *key, *nkey, *val, *my_nismap;
320 	int kl, nkl, vl;
321 	char dir[100];
322 
323 	first = 1;
324 	key  = NULL; kl  = 0;
325 	nkey = NULL; nkl = 0;
326 	val  = NULL; vl  = 0;
327 	count = 0;
328 	my_nismap = NULL;
329 
330 	my_nismap = strdup(nismap);
331 	if (my_nismap == NULL) {
332 		syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
333 		return (__NSW_UNAVAIL);
334 	}
335 	for (;;) {
336 		if (first) {
337 			first = 0;
338 			err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl,
339 					&val, &vl);
340 
341 			if ((err == YPERR_MAP) &&
342 			    (replace_undscr_by_dot(my_nismap)))
343 				err = yp_first(nis_mydomain, my_nismap,
344 						&nkey, &nkl, &val, &vl);
345 
346 			if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
347 				syslog(LOG_ERR,
348 					"can't read nis map %s: %s - retrying",
349 					my_nismap, yperr_string(err));
350 				while ((err == YPERR_DOMAIN) ||
351 					(err == YPERR_YPBIND)) {
352 					(void) sleep(20);
353 					err = yp_first(nis_mydomain, my_nismap,
354 						&nkey, &nkl, &val, &vl);
355 				}
356 				syslog(LOG_ERR,
357 					"nis map %s: read OK.", my_nismap);
358 			}
359 		} else {
360 			err = yp_next(nis_mydomain, my_nismap, key, kl,
361 					&nkey, &nkl, &val, &vl);
362 		}
363 		if (err) {
364 			if (err != YPERR_NOMORE && err != YPERR_MAP)
365 				syslog(LOG_ERR, "%s: %s",
366 					my_nismap, yperr_string(err));
367 			break;
368 		}
369 		if (key)
370 			free(key);
371 		key = nkey;
372 		kl = nkl;
373 
374 		if (kl < 2 || kl >= 100)
375 			continue;
376 		if (isspace(*key) || *key == '#')
377 			continue;
378 		(void) strncpy(dir, key, kl);
379 		dir[kl] = '\0';
380 
381 		dirinit(dir, localmap, opts, 1, stack, stkptr);
382 		count++;
383 		free(val);
384 	}
385 
386 	if (my_nismap)
387 		free(my_nismap);
388 
389 	if (count > 0 && err == YPERR_NOMORE)
390 			return (__NSW_SUCCESS);
391 	else
392 		return (nis_err(err));
393 
394 }
395 
396 static int
397 replace_undscr_by_dot(map)
398 	char *map;
399 {
400 	int ret_val = 0;
401 
402 	while (*map) {
403 		if (*map == '_') {
404 			ret_val = 1;
405 			*map = '.';
406 		}
407 		map++;
408 	}
409 	return (ret_val);
410 }
411 
412 static int
413 nis_err(err)
414 	int err;
415 {
416 	switch (err) {
417 	case 0:
418 		return (__NSW_SUCCESS);
419 	case YPERR_KEY:
420 		return (__NSW_NOTFOUND);
421 	case YPERR_MAP:
422 		return (__NSW_UNAVAIL);
423 	default:
424 		return (__NSW_UNAVAIL);
425 	}
426 }
427 
428 int
429 getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr)
430 	char *nsmap;
431 	struct dir_entry **list;
432 	int *error;
433 	int *cache_time;
434 	char **stack;
435 	char ***stkptr;
436 {
437 	int nserr;
438 	struct dir_cbdata readdir_cbdata;
439 	struct ypall_callback cback;
440 	char *my_map = NULL;
441 
442 	char *key = NULL, *val = NULL;
443 	int nkl, vl;
444 
445 #ifdef lint
446 	stack = stack;
447 	stkptr = stkptr;
448 #endif /* lint */
449 
450 	*cache_time = RDDIR_CACHE_TIME;
451 
452 	/*
453 	 * XXX Hack to determine if we need to replace '_' with '.'
454 	 * Have to use yp_first() since yp_all() simply fails if
455 	 * the map is not present
456 	 */
457 	my_map = strdup(nsmap);
458 	if (my_map == NULL) {
459 		syslog(LOG_ERR,
460 			"getmapkeys_nis: memory alloc failed: %m");
461 		*error = ENOMEM;
462 		return (__NSW_UNAVAIL);
463 	}
464 	nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl);
465 	if (nserr == YPERR_MAP) {
466 		if (replace_undscr_by_dot(my_map)) {
467 			nserr = yp_first(nis_mydomain, my_map,
468 					&key, &nkl, &val, &vl);
469 		}
470 		if (nserr == YPERR_MAP) {
471 			/*
472 			 * map not found
473 			 */
474 			*error = 0;	/* return an empty list */
475 			if (verbose) {
476 				syslog(LOG_ERR, "%s: %s",
477 					nsmap, yperr_string(nserr));
478 			}
479 			free(my_map);
480 			return (nis_err(nserr));
481 		}
482 		if (key)
483 			free(key);
484 		if (val)
485 			free(val);
486 	}
487 
488 	readdir_cbdata.list = list;
489 	readdir_cbdata.last = NULL;
490 	readdir_cbdata.error = 0;
491 
492 	cback.foreach = readdir_callback;
493 	cback.data = (char *)&readdir_cbdata;
494 
495 	/*
496 	 * after all this song and dance we finally
497 	 * ask for the list of entries
498 	 */
499 	nserr = yp_all(nis_mydomain, my_map, &cback);
500 
501 	free(my_map);
502 	*error = readdir_cbdata.error;
503 	if (nserr) {
504 		if (verbose)
505 			syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr));
506 		nserr = 1;
507 		if (*error == 0)
508 			*error = ENOENT;
509 
510 		return (nis_err(nserr));
511 	}
512 
513 	return (__NSW_SUCCESS);
514 }
515 
516 static int
517 readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata)
518 	int instatus;
519 	char *inkey;
520 	int inkeylen;
521 	const char *inval;
522 	int invallen;
523 	struct dir_cbdata *indata;
524 {
525 	struct dir_entry **list = indata->list;
526 	struct dir_entry *last = indata->last;
527 	char key[MAXPATHLEN];
528 
529 #ifdef lint
530 	inval = inval;
531 	invallen = invallen;
532 #endif
533 
534 	if (instatus != YP_TRUE)
535 		return (0);	/* next entry. yp_all may decide otherwise... */
536 
537 	if (inkeylen == 0 || isspace(*inkey) || *inkey == '#')
538 		return (0);
539 
540 	/*
541 	 * yp_all allocates inkey with two extra bytes which contain
542 	 * NEWLINE and null but these two bytes are not reflected in
543 	 * inkeylen.
544 	 */
545 	strncpy(key, inkey, inkeylen);
546 	key[inkeylen] = '\0';
547 
548 	/*
549 	 * Wildcard entry should be ignored - following entries should continue
550 	 * to be read to corroborate with the way we search for entries in yp,
551 	 * i.e., first for an exact key match and then a wildcard, if there's
552 	 * no exact key match.
553 	 */
554 	if (key[0] == '*' && key[1] == '\0')
555 		return (0);
556 
557 	if (add_dir_entry(key, list, &last)) {
558 		indata->error = ENOMEM;
559 		return (1);	/* get no more entries */
560 	}
561 
562 	indata->last = last;
563 	indata->error = 0;
564 
565 	return (0);
566 }
567