xref: /netbsd-src/lib/libc/gen/getusershell.c (revision 1ca5c1b28139779176bd5c13ad7c5f25c0bcd5f8)
1 /*	$NetBSD: getusershell.c,v 1.21 2000/07/07 08:03:37 itohy Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #if defined(LIBC_SCCS) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)getusershell.c	8.1 (Berkeley) 6/4/93";
40 #else
41 __RCSID("$NetBSD: getusershell.c,v 1.21 2000/07/07 08:03:37 itohy Exp $");
42 #endif
43 #endif /* LIBC_SCCS and not lint */
44 
45 #include "namespace.h"
46 #include <sys/param.h>
47 #include <sys/file.h>
48 
49 #include <ctype.h>
50 #include <errno.h>
51 #include <nsswitch.h>
52 #include <paths.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stringlist.h>
57 #include <unistd.h>
58 
59 #ifdef __STDC__
60 #include <stdarg.h>
61 #else
62 #include <varargs.h>
63 #endif
64 
65 #ifdef HESIOD
66 #include <hesiod.h>
67 #endif
68 #ifdef YP
69 #include <rpc/rpc.h>
70 #include <rpcsvc/ypclnt.h>
71 #include <rpcsvc/yp_prot.h>
72 #endif
73 
74 #ifdef __weak_alias
75 __weak_alias(endusershell,_endusershell)
76 __weak_alias(getusershell,_getusershell)
77 __weak_alias(setusershell,_setusershell)
78 #endif
79 
80 /*
81  * Local shells should NOT be added here.  They should be added in
82  * /etc/shells.
83  */
84 
85 static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
86 static const char *const *curshell;
87 static StringList	 *sl;
88 
89 static const char *const *initshells __P((void));
90 
91 /*
92  * Get a list of shells from "shells" nsswitch database
93  */
94 __aconst char *
95 getusershell()
96 {
97 	__aconst char *ret;
98 
99 	if (curshell == NULL)
100 		curshell = initshells();
101 	/*LINTED*/
102 	ret = (__aconst char *)*curshell;
103 	if (ret != NULL)
104 		curshell++;
105 	return (ret);
106 }
107 
108 void
109 endusershell()
110 {
111 	if (sl)
112 		sl_free(sl, 1);
113 	sl = NULL;
114 	curshell = NULL;
115 }
116 
117 void
118 setusershell()
119 {
120 
121 	curshell = initshells();
122 }
123 
124 
125 static int	_local_initshells __P((void *, void *, va_list));
126 
127 /*ARGSUSED*/
128 static int
129 _local_initshells(rv, cb_data, ap)
130 	void	*rv;
131 	void	*cb_data;
132 	va_list	 ap;
133 {
134 	char	*sp, *cp;
135 	FILE	*fp;
136 	char	 line[MAXPATHLEN + 2];
137 
138 	if (sl)
139 		sl_free(sl, 1);
140 	sl = sl_init();
141 	if (!sl)
142 		return (NS_UNAVAIL);
143 
144 	if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
145 		return (NS_UNAVAIL);
146 
147 	sp = cp = line;
148 	while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
149 		while (*cp != '#' && *cp != '/' && *cp != '\0')
150 			cp++;
151 		if (*cp == '#' || *cp == '\0')
152 			continue;
153 		sp = cp;
154 		while (!isspace((unsigned char) *cp) && *cp != '#'
155 		    && *cp != '\0')
156 			cp++;
157 		*cp++ = '\0';
158 		if (sl_add(sl, strdup(sp)) == -1)
159 			return (NS_UNAVAIL);
160 	}
161 	(void)fclose(fp);
162 	return (NS_SUCCESS);
163 }
164 
165 #ifdef HESIOD
166 static int	_dns_initshells __P((void *, void *, va_list));
167 
168 /*ARGSUSED*/
169 static int
170 _dns_initshells(rv, cb_data, ap)
171 	void	*rv;
172 	void	*cb_data;
173 	va_list	 ap;
174 {
175 	char	  shellname[] = "shells-XXXXX";
176 	int	  hsindex, hpi, r;
177 	char	**hp;
178 	void	 *context;
179 
180 	if (sl)
181 		sl_free(sl, 1);
182 	sl = sl_init();
183 	if (!sl)
184 		return (NS_UNAVAIL);
185 
186 	r = NS_UNAVAIL;
187 	if (hesiod_init(&context) == -1)
188 		return (r);
189 
190 	for (hsindex = 0; ; hsindex++) {
191 		snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
192 		hp = hesiod_resolve(context, shellname, "shells");
193 		if (hp == NULL) {
194 			if (errno == ENOENT) {
195 				if (hsindex == 0)
196 					r = NS_NOTFOUND;
197 				else
198 					r = NS_SUCCESS;
199 			}
200 			break;
201 		} else {
202 			int bad = 0;
203 
204 			for (hpi = 0; hp[hpi]; hpi++)
205 				if (sl_add(sl, hp[hpi]) == -1) {
206 					bad = 1;
207 					break;
208 				}
209 			free(hp);
210 			if (bad)
211 				break;
212 		}
213 	}
214 	hesiod_end(context);
215 	return (r);
216 }
217 #endif /* HESIOD */
218 
219 #ifdef YP
220 static int	_nis_initshells __P((void *, void *, va_list));
221 
222 /*ARGSUSED*/
223 static int
224 _nis_initshells(rv, cb_data, ap)
225 	void	*rv;
226 	void	*cb_data;
227 	va_list	 ap;
228 {
229 	static char *ypdomain;
230 
231 	if (sl)
232 		sl_free(sl, 1);
233 	sl = sl_init();
234 	if (!sl)
235 		return (NS_UNAVAIL);
236 
237 	if (ypdomain == NULL) {
238 		switch (yp_get_default_domain(&ypdomain)) {
239 		case 0:
240 			break;
241 		case YPERR_RESRC:
242 			return (NS_TRYAGAIN);
243 		default:
244 			return (NS_UNAVAIL);
245 		}
246 	}
247 
248 	for (;;) {
249 		char	*ypcur = NULL;
250 		int	 ypcurlen = 0;	/* XXX: GCC */
251 		char	*key, *data;
252 		int	 keylen, datalen;
253 		int	 r;
254 
255 		key = data = NULL;
256 		if (ypcur) {
257 			r = yp_next(ypdomain, "shells", ypcur, ypcurlen,
258 					&key, &keylen, &data, &datalen);
259 			free(ypcur);
260 			switch (r) {
261 			case 0:
262 				break;
263 			case YPERR_NOMORE:
264 				free(key);
265 				free(data);
266 				return (NS_SUCCESS);
267 			default:
268 				free(key);
269 				free(data);
270 				return (NS_UNAVAIL);
271 			}
272 			ypcur = key;
273 			ypcurlen = keylen;
274 		} else {
275 			if (yp_first(ypdomain, "shells", &ypcur,
276 				    &ypcurlen, &data, &datalen)) {
277 				free(data);
278 				return (NS_UNAVAIL);
279 			}
280 		}
281 		data[datalen] = '\0';		/* clear trailing \n */
282 		if (sl_add(sl, data) == -1)
283 			return (NS_UNAVAIL);
284 	}
285 }
286 #endif /* YP */
287 
288 static const char *const *
289 initshells()
290 {
291 	static const ns_dtab dtab[] = {
292 		NS_FILES_CB(_local_initshells, NULL)
293 		NS_DNS_CB(_dns_initshells, NULL)
294 		NS_NIS_CB(_nis_initshells, NULL)
295 		{ 0 }
296 	};
297 	if (sl)
298 		sl_free(sl, 1);
299 	sl = sl_init();
300 	if (!sl)
301 		goto badinitshells;
302 
303 	if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
304 	    != NS_SUCCESS) {
305  badinitshells:
306 		if (sl)
307 			sl_free(sl, 1);
308 		sl = NULL;
309 		return (okshells);
310 	}
311 	if (sl_add(sl, NULL) == -1)
312 		goto badinitshells;
313 
314 	return (const char *const *)(sl->sl_str);
315 }
316