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