11573Srgrimes/*
21573Srgrimes * Copyright (c) 1985, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 4. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3189999Sobrienstatic char sccsid[] = "@(#)getusershell.c	8.1 (Berkeley) 6/4/93";
321573Srgrimes#endif /* LIBC_SCCS and not lint */
3390045Sobrien/*	$NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $	*/
3490030Sobrien#include <sys/cdefs.h>
3589999Sobrien__FBSDID("$FreeBSD$");
361573Srgrimes
37113984Snectar#include "namespace.h"
381573Srgrimes#include <sys/param.h>
391573Srgrimes#include <sys/file.h>
4065532Snectar
4165532Snectar#include <ctype.h>
4265532Snectar#include <errno.h>
4365532Snectar#include <nsswitch.h>
4465532Snectar#include <paths.h>
451573Srgrimes#include <stdio.h>
461573Srgrimes#include <stdlib.h>
4765532Snectar#include <string.h>
4865532Snectar#include <stringlist.h>
491573Srgrimes#include <unistd.h>
501573Srgrimes
5165532Snectar#ifdef HESIOD
5265532Snectar#include <hesiod.h>
5365532Snectar#endif
5465532Snectar#ifdef YP
5565532Snectar#include <rpc/rpc.h>
5665532Snectar#include <rpcsvc/ypclnt.h>
5765532Snectar#include <rpcsvc/yp_prot.h>
5865532Snectar#endif
59113984Snectar#include "un-namespace.h"
6065532Snectar
611573Srgrimes/*
621573Srgrimes * Local shells should NOT be added here.  They should be added in
631573Srgrimes * /etc/shells.
641573Srgrimes */
651573Srgrimes
6665532Snectarstatic const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
6765532Snectarstatic const char *const *curshell;
6865532Snectarstatic StringList	 *sl;
691573Srgrimes
7090045Sobrienstatic const char *const *initshells(void);
7165532Snectar
721573Srgrimes/*
7365532Snectar * Get a list of shells from "shells" nsswitch database
741573Srgrimes */
751573Srgrimeschar *
7665532Snectargetusershell(void)
771573Srgrimes{
781573Srgrimes	char *ret;
791573Srgrimes
801573Srgrimes	if (curshell == NULL)
811573Srgrimes		curshell = initshells();
8265532Snectar	/*LINTED*/
8365532Snectar	ret = (char *)*curshell;
841573Srgrimes	if (ret != NULL)
851573Srgrimes		curshell++;
861573Srgrimes	return (ret);
871573Srgrimes}
881573Srgrimes
891573Srgrimesvoid
9065532Snectarendusershell(void)
911573Srgrimes{
92112407Srobert	if (sl) {
9365532Snectar		sl_free(sl, 1);
94112407Srobert		sl = NULL;
95112407Srobert	}
961573Srgrimes	curshell = NULL;
971573Srgrimes}
981573Srgrimes
991573Srgrimesvoid
10065532Snectarsetusershell(void)
1011573Srgrimes{
1021573Srgrimes
1031573Srgrimes	curshell = initshells();
1041573Srgrimes}
1051573Srgrimes
10665532Snectar
10790045Sobrienstatic int	_local_initshells(void *, void *, va_list);
10865532Snectar
10965532Snectar/*ARGSUSED*/
11065532Snectarstatic int
11165532Snectar_local_initshells(rv, cb_data, ap)
11265532Snectar	void	*rv;
11365532Snectar	void	*cb_data;
11465532Snectar	va_list	 ap;
1151573Srgrimes{
11665532Snectar	char	*sp, *cp;
11765532Snectar	FILE	*fp;
11865532Snectar	char	 line[MAXPATHLEN + 2];
1191573Srgrimes
12065532Snectar	if (sl)
12165532Snectar		sl_free(sl, 1);
12265532Snectar	sl = sl_init();
12365532Snectar
1241573Srgrimes	if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
12565532Snectar		return NS_UNAVAIL;
12665532Snectar
127199784Swollman	cp = line;
1281573Srgrimes	while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
1291573Srgrimes		while (*cp != '#' && *cp != '/' && *cp != '\0')
1301573Srgrimes			cp++;
1311573Srgrimes		if (*cp == '#' || *cp == '\0')
1321573Srgrimes			continue;
13365532Snectar		sp = cp;
13465532Snectar		while (!isspace(*cp) && *cp != '#' && *cp != '\0')
1351573Srgrimes			cp++;
1361573Srgrimes		*cp++ = '\0';
13765532Snectar		sl_add(sl, strdup(sp));
1381573Srgrimes	}
1391573Srgrimes	(void)fclose(fp);
14065532Snectar	return NS_SUCCESS;
1411573Srgrimes}
14265532Snectar
14365532Snectar#ifdef HESIOD
14490045Sobrienstatic int	_dns_initshells(void *, void *, va_list);
14565532Snectar
14665532Snectar/*ARGSUSED*/
14765532Snectarstatic int
14865532Snectar_dns_initshells(rv, cb_data, ap)
14965532Snectar	void	*rv;
15065532Snectar	void	*cb_data;
15165532Snectar	va_list	 ap;
15265532Snectar{
15365532Snectar	char	  shellname[] = "shells-XXXXX";
15465532Snectar	int	  hsindex, hpi, r;
15565532Snectar	char	**hp;
15665532Snectar	void	 *context;
15765532Snectar
15865532Snectar	if (sl)
15965532Snectar		sl_free(sl, 1);
16065532Snectar	sl = sl_init();
16165532Snectar	r = NS_UNAVAIL;
16265532Snectar	if (hesiod_init(&context) == -1)
16365532Snectar		return (r);
16465532Snectar
16565532Snectar	for (hsindex = 0; ; hsindex++) {
16665532Snectar		snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
16765532Snectar		hp = hesiod_resolve(context, shellname, "shells");
16865532Snectar		if (hp == NULL) {
16965532Snectar			if (errno == ENOENT) {
17065532Snectar				if (hsindex == 0)
17165532Snectar					r = NS_NOTFOUND;
17265532Snectar				else
17365532Snectar					r = NS_SUCCESS;
17465532Snectar			}
17565532Snectar			break;
17665532Snectar		} else {
17765532Snectar			for (hpi = 0; hp[hpi]; hpi++)
17865532Snectar				sl_add(sl, hp[hpi]);
17965532Snectar			free(hp);
18065532Snectar		}
18165532Snectar	}
18265532Snectar	hesiod_end(context);
18365532Snectar	return (r);
18465532Snectar}
18565532Snectar#endif /* HESIOD */
18665532Snectar
18765532Snectar#ifdef YP
18890045Sobrienstatic int	_nis_initshells(void *, void *, va_list);
18965532Snectar
19065532Snectar/*ARGSUSED*/
19165532Snectarstatic int
19265532Snectar_nis_initshells(rv, cb_data, ap)
19365532Snectar	void	*rv;
19465532Snectar	void	*cb_data;
19565532Snectar	va_list	 ap;
19665532Snectar{
19765532Snectar	static char *ypdomain;
198112407Srobert	char	*key, *data;
199112407Srobert	char	*lastkey;
200112407Srobert	int	 keylen, datalen;
201112407Srobert	int	 r;
20265532Snectar
20365532Snectar	if (sl)
20465532Snectar		sl_free(sl, 1);
20565532Snectar	sl = sl_init();
20665532Snectar
20765532Snectar	if (ypdomain == NULL) {
20865532Snectar		switch (yp_get_default_domain(&ypdomain)) {
20965532Snectar		case 0:
21065532Snectar			break;
21165532Snectar		case YPERR_RESRC:
21265532Snectar			return NS_TRYAGAIN;
21365532Snectar		default:
21465532Snectar			return NS_UNAVAIL;
21565532Snectar		}
21665532Snectar	}
21765532Snectar
218112407Srobert	/*
219112407Srobert	 * `key' and `data' point to strings dynamically allocated by
220112407Srobert	 * the yp_... functions.
221112407Srobert	 * `data' is directly put into the stringlist of shells.
222112407Srobert	 */
223112407Srobert	key = data = NULL;
224112407Srobert	if (yp_first(ypdomain, "shells", &key, &keylen, &data, &datalen))
225112407Srobert		return NS_UNAVAIL;
226112407Srobert	do {
22765532Snectar		data[datalen] = '\0';		/* clear trailing \n */
22865532Snectar		sl_add(sl, data);
229112407Srobert
230112407Srobert		lastkey = key;
231112407Srobert		r = yp_next(ypdomain, "shells", lastkey, keylen,
232112407Srobert		    &key, &keylen, &data, &datalen);
233112407Srobert		free(lastkey);
234112407Srobert	} while (r == 0);
235112407Srobert
236112407Srobert	if (r == YPERR_NOMORE) {
237112407Srobert		/*
238112407Srobert		 * `data' and `key' ought to be NULL - do not try to free them.
239112407Srobert		 */
240112407Srobert		return NS_SUCCESS;
24165532Snectar	}
242112407Srobert
243112407Srobert	return NS_UNAVAIL;
24465532Snectar}
24565532Snectar#endif /* YP */
24665532Snectar
24765532Snectarstatic const char *const *
24865532Snectarinitshells()
24965532Snectar{
25065532Snectar	static const ns_dtab dtab[] = {
25165532Snectar		NS_FILES_CB(_local_initshells, NULL)
25265532Snectar		NS_DNS_CB(_dns_initshells, NULL)
25365532Snectar		NS_NIS_CB(_nis_initshells, NULL)
25465532Snectar		{ 0 }
25565532Snectar	};
25665532Snectar	if (sl)
25765532Snectar		sl_free(sl, 1);
25865532Snectar	sl = sl_init();
25965532Snectar
260113984Snectar	if (_nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
26165532Snectar	    != NS_SUCCESS) {
26265532Snectar		if (sl)
26365532Snectar			sl_free(sl, 1);
26465532Snectar		sl = NULL;
26565532Snectar		return (okshells);
26665532Snectar	}
26765532Snectar	sl_add(sl, NULL);
26865532Snectar
26965532Snectar	return (const char *const *)(sl->sl_str);
27065532Snectar}
271