xref: /illumos-gate/usr/src/cmd/fs.d/autofs/ns_nis.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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_nis.c
23  *
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.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 <sys/systeminfo.h>
40 #include <rpc/rpc.h>
41 #include <rpcsvc/nfs_prot.h>
42 #include <rpcsvc/ypclnt.h>
43 #include <rpcsvc/yp_prot.h>
44 #include <sys/errno.h>
45 #include "automount.h"
46 
47 #define	KEY		0
48 #define	CONTENTS	1
49 
50 static int replace_undscr_by_dot(char *);
51 static int nis_err(int);
52 
53 static char nis_mydomain[YPMAXDOMAIN];
54 
55 struct dir_cbdata {
56 	struct dir_entry **list;
57 	struct dir_entry *last;
58 	int error;
59 };
60 
61 static int readdir_callback(int, char *, int, const char *,
62 				int, struct dir_cbdata *);
63 
64 void
65 init_nis(char **stack, char ***stkptr)
66 {
67 #ifdef lint
68 	stack = stack;
69 	stkptr = stkptr;
70 #endif /* lint */
71 
72 	(void) sysinfo(SI_SRPC_DOMAIN, nis_mydomain, sizeof (nis_mydomain));
73 	(void) __nis_reset_state();	/* XXX temporary hack for csh bug */
74 }
75 
76 /*ARGSUSED*/
77 int
78 getmapent_nis(key, map, ml, stack, stkptr, iswildcard, isrestricted)
79 	char *key, *map;
80 	struct mapline *ml;
81 	char **stack;
82 	char ***stkptr;
83 	bool_t *iswildcard;
84 	bool_t isrestricted;
85 {
86 	char *nisline = NULL;
87 	char *my_map = NULL;
88 	char *lp, *lq;
89 	int nislen, len;
90 	int nserr;
91 
92 	if (iswildcard)
93 		*iswildcard = FALSE;
94 	nserr = yp_match(nis_mydomain, map, key, strlen(key),
95 						&nisline, &nislen);
96 	if (nserr == YPERR_MAP) {
97 		my_map = strdup(map);
98 		if (my_map == NULL) {
99 			syslog(LOG_ERR,
100 				"getmapent_nis: memory alloc failed: %m");
101 			return (__NSW_UNAVAIL);
102 		}
103 		if (replace_undscr_by_dot(my_map))
104 			nserr = yp_match(nis_mydomain, my_map, key,
105 					strlen(key), &nisline, &nislen);
106 	}
107 
108 	if (nserr) {
109 		if (nserr == YPERR_KEY) {
110 			/*
111 			 * Try the default entry "*"
112 			 */
113 			if (my_map == NULL)
114 				nserr = yp_match(nis_mydomain, map, "*", 1,
115 						&nisline, &nislen);
116 			else
117 				nserr = yp_match(nis_mydomain, my_map, "*", 1,
118 						&nisline, &nislen);
119 			if (!nserr && iswildcard)
120 				*iswildcard = TRUE;
121 		} else {
122 			if (verbose)
123 				syslog(LOG_ERR, "%s: %s",
124 					map, yperr_string(nserr));
125 			nserr = 1;
126 		}
127 	}
128 	if (my_map != NULL)
129 		free(my_map);
130 
131 	nserr = nis_err(nserr);
132 	if (nserr)
133 		goto done;
134 
135 	/*
136 	 * at this point we are sure that yp_match succeeded
137 	 * so massage the entry by
138 	 * 1. ignoring # and beyond
139 	 * 2. trim the trailing whitespace
140 	 */
141 	if (lp = strchr(nisline, '#'))
142 		*lp = '\0';
143 	len = strlen(nisline);
144 	if (len == 0) {
145 		nserr = __NSW_NOTFOUND;
146 		goto done;
147 	}
148 	lp = &nisline[len - 1];
149 	while (lp > nisline && isspace(*lp))
150 		*lp-- = '\0';
151 	if (lp == nisline) {
152 		nserr = __NSW_NOTFOUND;
153 		goto done;
154 	}
155 	(void) strcpy(ml->linebuf, nisline);
156 	lp = ml->linebuf;
157 	lq = ml->lineqbuf;
158 	unquote(lp, lq);
159 	/* now we have the correct line */
160 
161 	nserr = __NSW_SUCCESS;
162 done:
163 	if (nisline)
164 		free((char *)nisline);
165 	return (nserr);
166 
167 }
168 
169 int
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 int
312 loaddirect_nis(nismap, localmap, opts, stack, stkptr)
313 	char *nismap, *localmap, *opts;
314 	char **stack;
315 	char ***stkptr;
316 {
317 	int first, err, count;
318 	char *key, *nkey, *val, *my_nismap;
319 	int kl, nkl, vl;
320 	char dir[100];
321 
322 	first = 1;
323 	key  = NULL; kl  = 0;
324 	nkey = NULL; nkl = 0;
325 	val  = NULL; vl  = 0;
326 	count = 0;
327 	my_nismap = NULL;
328 
329 	my_nismap = strdup(nismap);
330 	if (my_nismap == NULL) {
331 		syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
332 		return (__NSW_UNAVAIL);
333 	}
334 	for (;;) {
335 		if (first) {
336 			first = 0;
337 			err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl,
338 					&val, &vl);
339 
340 			if ((err == YPERR_MAP) &&
341 			    (replace_undscr_by_dot(my_nismap)))
342 				err = yp_first(nis_mydomain, my_nismap,
343 						&nkey, &nkl, &val, &vl);
344 
345 			if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
346 				syslog(LOG_ERR,
347 					"can't read nis map %s: %s - retrying",
348 					my_nismap, yperr_string(err));
349 				while ((err == YPERR_DOMAIN) ||
350 					(err == YPERR_YPBIND)) {
351 					(void) sleep(20);
352 					err = yp_first(nis_mydomain, my_nismap,
353 						&nkey, &nkl, &val, &vl);
354 				}
355 				syslog(LOG_ERR,
356 					"nis map %s: read OK.", my_nismap);
357 			}
358 		} else {
359 			err = yp_next(nis_mydomain, my_nismap, key, kl,
360 					&nkey, &nkl, &val, &vl);
361 		}
362 		if (err) {
363 			if (err != YPERR_NOMORE && err != YPERR_MAP)
364 				syslog(LOG_ERR, "%s: %s",
365 					my_nismap, yperr_string(err));
366 			break;
367 		}
368 		if (key)
369 			free(key);
370 		key = nkey;
371 		kl = nkl;
372 
373 		if (kl < 2 || kl >= 100)
374 			continue;
375 		if (isspace(*key) || *key == '#')
376 			continue;
377 		(void) strncpy(dir, key, kl);
378 		dir[kl] = '\0';
379 
380 		dirinit(dir, localmap, opts, 1, stack, stkptr);
381 		count++;
382 		free(val);
383 	}
384 
385 	if (my_nismap)
386 		free(my_nismap);
387 
388 	if (count > 0 && err == YPERR_NOMORE)
389 			return (__NSW_SUCCESS);
390 	else
391 		return (nis_err(err));
392 
393 }
394 
395 static int
396 replace_undscr_by_dot(map)
397 	char *map;
398 {
399 	int ret_val = 0;
400 
401 	while (*map) {
402 		if (*map == '_') {
403 			ret_val = 1;
404 			*map = '.';
405 		}
406 		map++;
407 	}
408 	return (ret_val);
409 }
410 
411 static int
412 nis_err(err)
413 	int err;
414 {
415 	switch (err) {
416 	case 0:
417 		return (__NSW_SUCCESS);
418 	case YPERR_KEY:
419 		return (__NSW_NOTFOUND);
420 	case YPERR_MAP:
421 		return (__NSW_UNAVAIL);
422 	default:
423 		return (__NSW_UNAVAIL);
424 	}
425 }
426 
427 int
428 getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr)
429 	char *nsmap;
430 	struct dir_entry **list;
431 	int *error;
432 	int *cache_time;
433 	char **stack;
434 	char ***stkptr;
435 {
436 	int nserr;
437 	struct dir_cbdata readdir_cbdata;
438 	struct ypall_callback cback;
439 	char *my_map = NULL;
440 
441 	char *key = NULL, *val = NULL;
442 	int nkl, vl;
443 
444 #ifdef lint
445 	stack = stack;
446 	stkptr = stkptr;
447 #endif /* lint */
448 
449 	*cache_time = RDDIR_CACHE_TIME;
450 
451 	/*
452 	 * XXX Hack to determine if we need to replace '_' with '.'
453 	 * Have to use yp_first() since yp_all() simply fails if
454 	 * the map is not present
455 	 */
456 	my_map = strdup(nsmap);
457 	if (my_map == NULL) {
458 		syslog(LOG_ERR,
459 			"getmapkeys_nis: memory alloc failed: %m");
460 		*error = ENOMEM;
461 		return (__NSW_UNAVAIL);
462 	}
463 	nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl);
464 	if (nserr == YPERR_MAP) {
465 		if (replace_undscr_by_dot(my_map)) {
466 			nserr = yp_first(nis_mydomain, my_map,
467 					&key, &nkl, &val, &vl);
468 		}
469 		if (nserr == YPERR_MAP) {
470 			/*
471 			 * map not found
472 			 */
473 			*error = 0;	/* return an empty list */
474 			if (verbose) {
475 				syslog(LOG_ERR, "%s: %s",
476 					nsmap, yperr_string(nserr));
477 			}
478 			free(my_map);
479 			return (nis_err(nserr));
480 		}
481 	}
482 	if (key)
483 		free(key);
484 	if (val)
485 		free(val);
486 
487 	readdir_cbdata.list = list;
488 	readdir_cbdata.last = NULL;
489 	readdir_cbdata.error = 0;
490 
491 	cback.foreach = readdir_callback;
492 	cback.data = (char *)&readdir_cbdata;
493 
494 	/*
495 	 * after all this song and dance we finally
496 	 * ask for the list of entries
497 	 */
498 	nserr = yp_all(nis_mydomain, my_map, &cback);
499 
500 	free(my_map);
501 	*error = readdir_cbdata.error;
502 	if (nserr) {
503 		if (verbose)
504 			syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr));
505 		nserr = 1;
506 		if (*error == 0)
507 			*error = ENOENT;
508 
509 		return (nis_err(nserr));
510 	}
511 
512 	return (__NSW_SUCCESS);
513 }
514 
515 static int
516 readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata)
517 	int instatus;
518 	char *inkey;
519 	int inkeylen;
520 	const char *inval;
521 	int invallen;
522 	struct dir_cbdata *indata;
523 {
524 	struct dir_entry **list = indata->list;
525 	struct dir_entry *last = indata->last;
526 	char key[MAXPATHLEN];
527 
528 #ifdef lint
529 	inval = inval;
530 	invallen = invallen;
531 #endif
532 
533 	if (instatus != YP_TRUE)
534 		return (0);	/* next entry. yp_all may decide otherwise... */
535 
536 	if (inkeylen == 0 || isspace(*inkey) || *inkey == '#')
537 		return (0);
538 
539 	/*
540 	 * yp_all allocates inkey with two extra bytes which contain
541 	 * NEWLINE and null but these two bytes are not reflected in
542 	 * inkeylen.
543 	 */
544 	strncpy(key, inkey, inkeylen);
545 	key[inkeylen] = '\0';
546 
547 	/*
548 	 * Wildcard entry should be ignored - following entries should continue
549 	 * to be read to corroborate with the way we search for entries in yp,
550 	 * i.e., first for an exact key match and then a wildcard, if there's
551 	 * no exact key match.
552 	 */
553 	if (key[0] == '*' && key[1] == '\0')
554 		return (0);
555 
556 	if (add_dir_entry(key, list, &last)) {
557 		indata->error = ENOMEM;
558 		return (1);	/* get no more entries */
559 	}
560 
561 	indata->last = last;
562 	indata->error = 0;
563 
564 	return (0);
565 }
566