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