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