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