xref: /titanic_51/usr/src/cmd/fs.d/autofs/ns_nis.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2004 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <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 loadmaster_nis(mapname, defopts, stack, stkptr)
171 	char *mapname, *defopts;
172 	char **stack;
173 	char ***stkptr;
174 {
175 	int first, err;
176 	char *key, *nkey, *val;
177 	int kl, nkl, vl;
178 	char dir[256], map[256], qbuff[256];
179 	char *pmap, *opts, *my_mapname;
180 	int count = 0;
181 
182 	first = 1;
183 	key  = NULL; kl  = 0;
184 	nkey = NULL; nkl = 0;
185 	val  = NULL; vl  = 0;
186 
187 	/*
188 	 * need a private copy of mapname, because we may change
189 	 * the underscores by dots. We however do not want the
190 	 * orignal to be changed, as we may want to use the
191 	 * original name in some other name service
192 	 */
193 	my_mapname = strdup(mapname);
194 	if (my_mapname == NULL) {
195 		syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
196 		/* not the name svc's fault but ... */
197 		return (__NSW_UNAVAIL);
198 	}
199 	for (;;) {
200 		if (first) {
201 			first = 0;
202 			err = yp_first(nis_mydomain, my_mapname,
203 				&nkey, &nkl, &val, &vl);
204 
205 			if ((err == YPERR_MAP) &&
206 			    (replace_undscr_by_dot(my_mapname)))
207 				err = yp_first(nis_mydomain, my_mapname,
208 					&nkey, &nkl, &val, &vl);
209 
210 			if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
211 				syslog(LOG_ERR,
212 					"can't read nis map %s: %s - retrying",
213 					my_mapname, yperr_string(err));
214 				while ((err == YPERR_DOMAIN) ||
215 					(err == YPERR_YPBIND)) {
216 					(void) sleep(20);
217 					err = yp_first(nis_mydomain, my_mapname,
218 						&nkey, &nkl, &val, &vl);
219 				}
220 				syslog(LOG_ERR,
221 					"nis map %s: read OK.", my_mapname);
222 			}
223 		} else {
224 			err = yp_next(nis_mydomain, my_mapname, key, kl,
225 				&nkey, &nkl, &val, &vl);
226 		}
227 		if (err) {
228 			if (err != YPERR_NOMORE && err != YPERR_MAP)
229 				if (verbose)
230 					syslog(LOG_ERR, "%s: %s",
231 					my_mapname, yperr_string(err));
232 			break;
233 		}
234 		if (key)
235 			free(key);
236 		key = nkey;
237 		kl = nkl;
238 
239 
240 		if (kl >= 256 || vl >= 256)
241 			break;
242 		if (kl < 2 || vl < 1)
243 			break;
244 		if (isspace(*key) || *key == '#')
245 			break;
246 		(void) strncpy(dir, key, kl);
247 		dir[kl] = '\0';
248 		if (macro_expand("", dir, qbuff, sizeof (dir))) {
249 			syslog(LOG_ERR,
250 			    "%s in NIS map %s: entry too long (max %d chars)",
251 			    dir, my_mapname, sizeof (dir) - 1);
252 			break;
253 		}
254 		(void) strncpy(map, val, vl);
255 		map[vl] = '\0';
256 		if (macro_expand(dir, map, qbuff, sizeof (map))) {
257 			syslog(LOG_ERR,
258 			    "%s in NIS map %s: entry too long (max %d chars)",
259 			    map, my_mapname, sizeof (map) - 1);
260 			break;
261 		}
262 		pmap = map;
263 		while (*pmap && isspace(*pmap))
264 			pmap++;		/* skip blanks in front of map */
265 		opts = pmap;
266 		while (*opts && !isspace(*opts))
267 			opts++;
268 		if (*opts) {
269 			*opts++ = '\0';
270 			while (*opts && isspace(*opts))
271 				opts++;
272 			if (*opts == '-')
273 				opts++;
274 			else
275 				opts = defopts;
276 		}
277 		free(val);
278 
279 		/*
280 		 * Check for no embedded blanks.
281 		 */
282 		if (strcspn(opts, " 	") == strlen(opts)) {
283 			dirinit(dir, pmap, opts, 0, stack, stkptr);
284 			count++;
285 		} else {
286 pr_msg("Warning: invalid entry for %s in NIS map %s ignored.\n", dir, mapname);
287 		}
288 
289 	}
290 	if (my_mapname)
291 		free(my_mapname);
292 
293 	/*
294 	 * In the context of a master map, if no entry is
295 	 * found, it is like NOTFOUND
296 	 */
297 	if (count > 0 && err == YPERR_NOMORE)
298 		return (__NSW_SUCCESS);
299 	else {
300 		if (err)
301 			return (nis_err(err));
302 		else
303 			/*
304 			 * This case will happen if map is empty
305 			 *  or none of the entries is valid
306 			 */
307 			return (__NSW_NOTFOUND);
308 	}
309 }
310 
311 loaddirect_nis(nismap, localmap, opts, stack, stkptr)
312 	char *nismap, *localmap, *opts;
313 	char **stack;
314 	char ***stkptr;
315 {
316 	int first, err, count;
317 	char *key, *nkey, *val, *my_nismap;
318 	int kl, nkl, vl;
319 	char dir[100];
320 
321 	first = 1;
322 	key  = NULL; kl  = 0;
323 	nkey = NULL; nkl = 0;
324 	val  = NULL; vl  = 0;
325 	count = 0;
326 	my_nismap = NULL;
327 
328 	my_nismap = strdup(nismap);
329 	if (my_nismap == NULL) {
330 		syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
331 		return (__NSW_UNAVAIL);
332 	}
333 	for (;;) {
334 		if (first) {
335 			first = 0;
336 			err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl,
337 					&val, &vl);
338 
339 			if ((err == YPERR_MAP) &&
340 			    (replace_undscr_by_dot(my_nismap)))
341 				err = yp_first(nis_mydomain, my_nismap,
342 						&nkey, &nkl, &val, &vl);
343 
344 			if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
345 				syslog(LOG_ERR,
346 					"can't read nis map %s: %s - retrying",
347 					my_nismap, yperr_string(err));
348 				while ((err == YPERR_DOMAIN) ||
349 					(err == YPERR_YPBIND)) {
350 					(void) sleep(20);
351 					err = yp_first(nis_mydomain, my_nismap,
352 						&nkey, &nkl, &val, &vl);
353 				}
354 				syslog(LOG_ERR,
355 					"nis map %s: read OK.", my_nismap);
356 			}
357 		} else {
358 			err = yp_next(nis_mydomain, my_nismap, key, kl,
359 					&nkey, &nkl, &val, &vl);
360 		}
361 		if (err) {
362 			if (err != YPERR_NOMORE && err != YPERR_MAP)
363 				syslog(LOG_ERR, "%s: %s",
364 					my_nismap, yperr_string(err));
365 			break;
366 		}
367 		if (key)
368 			free(key);
369 		key = nkey;
370 		kl = nkl;
371 
372 		if (kl < 2 || kl >= 100)
373 			continue;
374 		if (isspace(*key) || *key == '#')
375 			continue;
376 		(void) strncpy(dir, key, kl);
377 		dir[kl] = '\0';
378 
379 		dirinit(dir, localmap, opts, 1, stack, stkptr);
380 		count++;
381 		free(val);
382 	}
383 
384 	if (my_nismap)
385 		free(my_nismap);
386 
387 	if (count > 0 && err == YPERR_NOMORE)
388 			return (__NSW_SUCCESS);
389 	else
390 		return (nis_err(err));
391 
392 }
393 
394 static int
395 replace_undscr_by_dot(map)
396 	char *map;
397 {
398 	int ret_val = 0;
399 
400 	while (*map) {
401 		if (*map == '_') {
402 			ret_val = 1;
403 			*map = '.';
404 		}
405 		map++;
406 	}
407 	return (ret_val);
408 }
409 
410 static int
411 nis_err(err)
412 	int err;
413 {
414 	switch (err) {
415 	case 0:
416 		return (__NSW_SUCCESS);
417 	case YPERR_KEY:
418 		return (__NSW_NOTFOUND);
419 	case YPERR_MAP:
420 		return (__NSW_UNAVAIL);
421 	default:
422 		return (__NSW_UNAVAIL);
423 	}
424 }
425 
426 int
427 getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr)
428 	char *nsmap;
429 	struct dir_entry **list;
430 	int *error;
431 	int *cache_time;
432 	char **stack;
433 	char ***stkptr;
434 {
435 	int nserr;
436 	struct dir_cbdata readdir_cbdata;
437 	struct ypall_callback cback;
438 	char *my_map = NULL;
439 
440 	char *key = NULL, *val = NULL;
441 	int nkl, vl;
442 
443 #ifdef lint
444 	stack = stack;
445 	stkptr = stkptr;
446 #endif /* lint */
447 
448 	*cache_time = RDDIR_CACHE_TIME;
449 
450 	/*
451 	 * XXX Hack to determine if we need to replace '_' with '.'
452 	 * Have to use yp_first() since yp_all() simply fails if
453 	 * the map is not present
454 	 */
455 	my_map = strdup(nsmap);
456 	if (my_map == NULL) {
457 		syslog(LOG_ERR,
458 			"getmapkeys_nis: memory alloc failed: %m");
459 		*error = ENOMEM;
460 		return (__NSW_UNAVAIL);
461 	}
462 	nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl);
463 	if (nserr == YPERR_MAP) {
464 		if (replace_undscr_by_dot(my_map)) {
465 			nserr = yp_first(nis_mydomain, my_map,
466 					&key, &nkl, &val, &vl);
467 		}
468 		if (nserr == YPERR_MAP) {
469 			/*
470 			 * map not found
471 			 */
472 			*error = 0;	/* return an empty list */
473 			if (verbose) {
474 				syslog(LOG_ERR, "%s: %s",
475 					nsmap, yperr_string(nserr));
476 			}
477 			free(my_map);
478 			return (nis_err(nserr));
479 		}
480 		if (key)
481 			free(key);
482 		if (val)
483 			free(val);
484 	}
485 
486 	readdir_cbdata.list = list;
487 	readdir_cbdata.last = NULL;
488 	readdir_cbdata.error = 0;
489 
490 	cback.foreach = readdir_callback;
491 	cback.data = (char *)&readdir_cbdata;
492 
493 	/*
494 	 * after all this song and dance we finally
495 	 * ask for the list of entries
496 	 */
497 	nserr = yp_all(nis_mydomain, my_map, &cback);
498 
499 	free(my_map);
500 	*error = readdir_cbdata.error;
501 	if (nserr) {
502 		if (verbose)
503 			syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr));
504 		nserr = 1;
505 		if (*error == 0)
506 			*error = ENOENT;
507 
508 		return (nis_err(nserr));
509 	}
510 
511 	return (__NSW_SUCCESS);
512 }
513 
514 static int
515 readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata)
516 	int instatus;
517 	char *inkey;
518 	int inkeylen;
519 	const char *inval;
520 	int invallen;
521 	struct dir_cbdata *indata;
522 {
523 	struct dir_entry **list = indata->list;
524 	struct dir_entry *last = indata->last;
525 	char key[MAXPATHLEN];
526 
527 #ifdef lint
528 	inval = inval;
529 	invallen = invallen;
530 #endif
531 
532 	if (instatus != YP_TRUE)
533 		return (0);	/* next entry. yp_all may decide otherwise... */
534 
535 	if (inkeylen == 0 || isspace(*inkey) || *inkey == '#')
536 		return (0);
537 
538 	/*
539 	 * yp_all allocates inkey with two extra bytes which contain
540 	 * NEWLINE and null but these two bytes are not reflected in
541 	 * inkeylen.
542 	 */
543 	strncpy(key, inkey, inkeylen);
544 	key[inkeylen] = '\0';
545 
546 	/*
547 	 * Wildcard entry should be ignored - following entries should continue
548 	 * to be read to corroborate with the way we search for entries in yp,
549 	 * i.e., first for an exact key match and then a wildcard, if there's
550 	 * no exact key match.
551 	 */
552 	if (key[0] == '*' && key[1] == '\0')
553 		return (0);
554 
555 	if (add_dir_entry(key, list, &last)) {
556 		indata->error = ENOMEM;
557 		return (1);	/* get no more entries */
558 	}
559 
560 	indata->last = last;
561 	indata->error = 0;
562 
563 	return (0);
564 }
565