xref: /openbsd-src/usr.bin/getent/getent.c (revision 78cdb4e33370cfed39da961f7ca4be41be3d3041)
1*78cdb4e3Sderaadt /*	$OpenBSD: getent.c,v 1.23 2021/10/11 14:28:26 deraadt Exp $	*/
273803d35Sotto /*	$NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $	*/
373803d35Sotto 
473803d35Sotto /*-
573803d35Sotto  * Copyright (c) 2004 The NetBSD Foundation, Inc.
673803d35Sotto  * All rights reserved.
773803d35Sotto  *
873803d35Sotto  * This code is derived from software contributed to The NetBSD Foundation
973803d35Sotto  * by Luke Mewburn.
1073803d35Sotto  *
1173803d35Sotto  * Redistribution and use in source and binary forms, with or without
1273803d35Sotto  * modification, are permitted provided that the following conditions
1373803d35Sotto  * are met:
1473803d35Sotto  * 1. Redistributions of source code must retain the above copyright
1573803d35Sotto  *    notice, this list of conditions and the following disclaimer.
1673803d35Sotto  * 2. Redistributions in binary form must reproduce the above copyright
1773803d35Sotto  *    notice, this list of conditions and the following disclaimer in the
1873803d35Sotto  *    documentation and/or other materials provided with the distribution.
1973803d35Sotto  *
2073803d35Sotto  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2173803d35Sotto  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2273803d35Sotto  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2373803d35Sotto  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2473803d35Sotto  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2573803d35Sotto  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2673803d35Sotto  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2773803d35Sotto  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2873803d35Sotto  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2973803d35Sotto  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3073803d35Sotto  * POSSIBILITY OF SUCH DAMAGE.
3173803d35Sotto  */
3273803d35Sotto 
3373803d35Sotto #include <sys/types.h>
3473803d35Sotto #include <sys/socket.h>
3573803d35Sotto 
3673803d35Sotto #include <ctype.h>
3720bf8b67Sdoug #include <err.h>
3873803d35Sotto #include <errno.h>
3973803d35Sotto #include <grp.h>
4073803d35Sotto #include <limits.h>
4173803d35Sotto #include <netdb.h>
4273803d35Sotto #include <pwd.h>
4373803d35Sotto #include <stdio.h>
4473803d35Sotto #include <stdarg.h>
4573803d35Sotto #include <stdlib.h>
4673803d35Sotto #include <string.h>
4773803d35Sotto #include <unistd.h>
4873803d35Sotto 
4973803d35Sotto #include <net/if.h>
5073803d35Sotto #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
5173803d35Sotto #include <netinet/if_ether.h>
5273803d35Sotto 
53bddaccdbSmillert #include <arpa/inet.h>
54bddaccdbSmillert 
5573803d35Sotto #include <rpc/rpc.h>
5673803d35Sotto 
577fb2109dSkn static void	usage(void);
5873803d35Sotto static int	ethers(int, char *[]);
5973803d35Sotto static int	group(int, char *[]);
6073803d35Sotto static int	hosts(int, char *[]);
6173803d35Sotto static int	passwd(int, char *[]);
6273803d35Sotto static int	protocols(int, char *[]);
6373803d35Sotto static int	rpc(int, char *[]);
6473803d35Sotto static int	services(int, char *[]);
6573803d35Sotto static int	shells(int, char *[]);
6621c0d692Sderaadt extern char *__progname;
6773803d35Sotto 
6873803d35Sotto enum {
6973803d35Sotto 	RV_OK		= 0,
7073803d35Sotto 	RV_USAGE	= 1,
7173803d35Sotto 	RV_NOTFOUND	= 2,
7221c0d692Sderaadt 	RV_NOENUM	= 3
7373803d35Sotto };
7473803d35Sotto 
7573803d35Sotto static struct getentdb {
7673803d35Sotto 	const char	*name;
7721c0d692Sderaadt 	int		(*fn)(int, char *[]);
7820bf8b67Sdoug 	const char	*pledge;
79048d4bd7Smestre 	const char	*unveil;
8073803d35Sotto } databases[] = {
81048d4bd7Smestre 	{	"ethers",	ethers,		"stdio rpath",	"/etc/ethers"	},
82048d4bd7Smestre 	{	"group",	group,		"stdio getpw",	NULL	},
83048d4bd7Smestre 	{	"hosts",	hosts,		"stdio dns",	NULL	},
84048d4bd7Smestre 	{	"passwd",	passwd,		"stdio getpw",	NULL	},
85048d4bd7Smestre 	{	"protocols",	protocols,	"stdio rpath",	"/etc/protocols"	},
86048d4bd7Smestre 	{	"rpc",		rpc,		"stdio rpath",	"/etc/rpc"	},
87048d4bd7Smestre 	{	"services",	services,	"stdio rpath",	"/etc/services"	},
88048d4bd7Smestre 	{	"shells",	shells,		"stdio rpath",	"/etc/shells"	},
8973803d35Sotto 
9073803d35Sotto 	{	NULL,		NULL,				},
9173803d35Sotto };
9273803d35Sotto 
9373803d35Sotto int
main(int argc,char * argv[])9473803d35Sotto main(int argc, char *argv[])
9573803d35Sotto {
9673803d35Sotto 	struct getentdb	*curdb;
9773803d35Sotto 
9873803d35Sotto 	if (argc < 2)
9973803d35Sotto 		usage();
10073803d35Sotto 	for (curdb = databases; curdb->name != NULL; curdb++) {
10173803d35Sotto 		if (strcmp(curdb->name, argv[1]) == 0) {
102048d4bd7Smestre 			if (curdb->unveil != NULL) {
103048d4bd7Smestre 				if (unveil(curdb->unveil, "r") == -1)
104bc5a8259Sbeck 					err(1, "unveil %s", curdb->unveil);
105048d4bd7Smestre 			}
10620bf8b67Sdoug 			if (pledge(curdb->pledge, NULL) == -1)
10720bf8b67Sdoug 				err(1, "pledge");
10820bf8b67Sdoug 
10921c0d692Sderaadt 			exit(curdb->fn(argc, argv));
11073803d35Sotto 			break;
11173803d35Sotto 		}
11273803d35Sotto 	}
11321c0d692Sderaadt 	fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]);
11473803d35Sotto 	return RV_USAGE;
11573803d35Sotto }
11673803d35Sotto 
1177fb2109dSkn static void
usage(void)11873803d35Sotto usage(void)
11973803d35Sotto {
12021c0d692Sderaadt 	fprintf(stderr, "usage: %s database [key ...]\n", __progname);
12173803d35Sotto 	exit(RV_USAGE);
12273803d35Sotto }
12373803d35Sotto 
12473803d35Sotto /*
12573803d35Sotto  * printfmtstrings --
12673803d35Sotto  *	vprintf(format, ...),
12773803d35Sotto  *	then the aliases (beginning with prefix, separated by sep),
12873803d35Sotto  *	then a newline
12973803d35Sotto  */
13073803d35Sotto static void
printfmtstrings(char * strings[],const char * prefix,const char * sep,const char * fmt,...)13173803d35Sotto printfmtstrings(char *strings[], const char *prefix, const char *sep,
13273803d35Sotto 	const char *fmt, ...)
13373803d35Sotto {
13473803d35Sotto 	va_list		ap;
13573803d35Sotto 	const char	*curpref;
13673803d35Sotto 	int		i;
13773803d35Sotto 
13873803d35Sotto 	va_start(ap, fmt);
13973803d35Sotto 	vprintf(fmt, ap);
14021c0d692Sderaadt 	va_end(ap);
14173803d35Sotto 
14273803d35Sotto 	curpref = prefix;
14373803d35Sotto 	for (i = 0; strings[i] != NULL; i++) {
14473803d35Sotto 		printf("%s%s", curpref, strings[i]);
14573803d35Sotto 		curpref = sep;
14673803d35Sotto 	}
14773803d35Sotto 	printf("\n");
14873803d35Sotto }
14973803d35Sotto 
15021c0d692Sderaadt #define ETHERSPRINT	printf("%-17s  %s\n", ether_ntoa(eap), hp)
15173803d35Sotto 
15273803d35Sotto static int
ethers(int argc,char * argv[])15373803d35Sotto ethers(int argc, char *argv[])
15473803d35Sotto {
155b9fc9a72Sderaadt 	char		hostname[HOST_NAME_MAX+1], *hp;
15621c0d692Sderaadt 	int		i, rv = RV_OK;
15773803d35Sotto 	struct ether_addr ea, *eap;
15873803d35Sotto 
15973803d35Sotto 	if (argc == 2) {
16021c0d692Sderaadt 		fprintf(stderr, "%s: Enumeration not supported on ethers\n",
16121c0d692Sderaadt 		    __progname);
16273803d35Sotto 		rv = RV_NOENUM;
16373803d35Sotto 	} else {
16473803d35Sotto 		for (i = 2; i < argc; i++) {
16573803d35Sotto 			if ((eap = ether_aton(argv[i])) == NULL) {
16673803d35Sotto 				eap = &ea;
16773803d35Sotto 				hp = argv[i];
16873803d35Sotto 				if (ether_hostton(hp, eap) != 0) {
16973803d35Sotto 					rv = RV_NOTFOUND;
17073803d35Sotto 					break;
17173803d35Sotto 				}
17273803d35Sotto 			} else {
17373803d35Sotto 				hp = hostname;
17473803d35Sotto 				if (ether_ntohost(hp, eap) != 0) {
17573803d35Sotto 					rv = RV_NOTFOUND;
17673803d35Sotto 					break;
17773803d35Sotto 				}
17873803d35Sotto 			}
17973803d35Sotto 			ETHERSPRINT;
18073803d35Sotto 		}
18173803d35Sotto 	}
18273803d35Sotto 	return rv;
18373803d35Sotto }
18473803d35Sotto 
18521c0d692Sderaadt #define GROUPPRINT	\
18621c0d692Sderaadt 	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
18721c0d692Sderaadt 	    gr->gr_name, gr->gr_passwd, gr->gr_gid)
18873803d35Sotto 
18973803d35Sotto static int
group(int argc,char * argv[])19073803d35Sotto group(int argc, char *argv[])
19173803d35Sotto {
19273803d35Sotto 	struct group	*gr;
193d150c7b2Skn 	const char	*err;
194d150c7b2Skn 	gid_t		gid;
195d150c7b2Skn 	int		i, rv = RV_OK;
19673803d35Sotto 
19773803d35Sotto 	setgroupent(1);
19873803d35Sotto 	if (argc == 2) {
19973803d35Sotto 		while ((gr = getgrent()) != NULL)
20073803d35Sotto 			GROUPPRINT;
20173803d35Sotto 	} else {
20273803d35Sotto 		for (i = 2; i < argc; i++) {
203927b549bSkn 			if ((gr = getgrnam(argv[i])) == NULL) {
204d150c7b2Skn 				gid = strtonum(argv[i], 0, GID_MAX, &err);
205927b549bSkn 				if (err == NULL)
206d150c7b2Skn 					gr = getgrgid(gid);
207927b549bSkn 			}
20873803d35Sotto 			if (gr != NULL)
20973803d35Sotto 				GROUPPRINT;
21073803d35Sotto 			else {
21173803d35Sotto 				rv = RV_NOTFOUND;
21273803d35Sotto 				break;
21373803d35Sotto 			}
21473803d35Sotto 		}
21573803d35Sotto 	}
21673803d35Sotto 	endgrent();
21773803d35Sotto 	return rv;
21873803d35Sotto }
21973803d35Sotto 
22073803d35Sotto static void
hostsprint(const struct hostent * he)22173803d35Sotto hostsprint(const struct hostent *he)
22273803d35Sotto {
22373803d35Sotto 	char	buf[INET6_ADDRSTRLEN];
22473803d35Sotto 
22573803d35Sotto 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
22673803d35Sotto 		strlcpy(buf, "# unknown", sizeof(buf));
227b7993beaSkn 	printfmtstrings(he->h_aliases, "  ", " ", "%-39s %s", buf, he->h_name);
22873803d35Sotto }
229b2587a20Sflorian static int
hostsaddrinfo(const char * name)2307f55ab29Skn hostsaddrinfo(const char *name)
231b2587a20Sflorian {
232b2587a20Sflorian 	struct addrinfo	 hints, *res, *res0;
233b2587a20Sflorian 	char		 buf[INET6_ADDRSTRLEN];
2347f55ab29Skn 	int		 rv;
235b2587a20Sflorian 
236b2587a20Sflorian 	rv = RV_NOTFOUND;
237b2587a20Sflorian 	memset(buf, 0, sizeof(buf));
238b2587a20Sflorian 	memset(&hints, 0, sizeof(hints));
2397f55ab29Skn 	hints.ai_family = AF_UNSPEC;
240b2587a20Sflorian 	hints.ai_socktype = SOCK_DGRAM;
241b2587a20Sflorian 
2427f55ab29Skn 	if (getaddrinfo(name, NULL, &hints, &res0) != 0)
2437f55ab29Skn 		return (rv);
244b2587a20Sflorian 	for (res = res0; res; res = res->ai_next) {
2457f55ab29Skn 		if ((res->ai_family != AF_INET6 && res->ai_family != AF_INET) ||
2467f55ab29Skn 		    getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf),
2477f55ab29Skn 		    NULL, 0, NI_NUMERICHOST) != 0)
248b2587a20Sflorian 			strlcpy(buf, "# unknown", sizeof(buf));
249b2587a20Sflorian 		else
250b2587a20Sflorian 			rv = RV_OK;
251b2587a20Sflorian 		printf("%-39s %s\n", buf, name);
252b2587a20Sflorian 	}
253b2587a20Sflorian 	freeaddrinfo(res0);
254b2587a20Sflorian 
255b2587a20Sflorian 	return (rv);
256b2587a20Sflorian }
25773803d35Sotto 
25873803d35Sotto static int
hosts(int argc,char * argv[])25973803d35Sotto hosts(int argc, char *argv[])
26073803d35Sotto {
261*78cdb4e3Sderaadt 	struct in6_addr	in6;
262*78cdb4e3Sderaadt 	struct in_addr	in;
26321c0d692Sderaadt 	int		i, rv = RV_OK;
26421c0d692Sderaadt 	struct hostent	*he;
26573803d35Sotto 
26673803d35Sotto 	if (argc == 2) {
2671865cfe2Sschwarze 		fprintf(stderr, "%s: Enumeration not supported on hosts\n",
2681865cfe2Sschwarze 		    __progname);
2691865cfe2Sschwarze 		rv = RV_NOENUM;
27073803d35Sotto 	} else {
27173803d35Sotto 		for (i = 2; i < argc; i++) {
272b2587a20Sflorian 			he = NULL;
273*78cdb4e3Sderaadt 			if (inet_pton(AF_INET6, argv[i], (void *)&in6) > 0)
274*78cdb4e3Sderaadt 				he = gethostbyaddr(&in6, sizeof(in6), AF_INET6);
275*78cdb4e3Sderaadt 			else if (inet_pton(AF_INET, argv[i], (void *)&in) > 0)
276*78cdb4e3Sderaadt 				he = gethostbyaddr(&in, sizeof(in), AF_INET);
27773803d35Sotto 			if (he != NULL)
27873803d35Sotto 				hostsprint(he);
279b2587a20Sflorian 			else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND)
28073803d35Sotto 				break;
28173803d35Sotto 		}
28273803d35Sotto 	}
28373803d35Sotto 	return rv;
28473803d35Sotto }
28573803d35Sotto 
28621c0d692Sderaadt #define PASSWDPRINT	\
28721c0d692Sderaadt 	printf("%s:%s:%u:%u:%s:%s:%s\n", \
28821c0d692Sderaadt 	    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
28921c0d692Sderaadt 	    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
29073803d35Sotto 
29173803d35Sotto static int
passwd(int argc,char * argv[])29273803d35Sotto passwd(int argc, char *argv[])
29373803d35Sotto {
29473803d35Sotto 	struct passwd	*pw;
295d150c7b2Skn 	const char	*err;
296d150c7b2Skn 	uid_t		uid;
297d150c7b2Skn 	int		i, rv = RV_OK;
29873803d35Sotto 
29973803d35Sotto 	setpassent(1);
30073803d35Sotto 	if (argc == 2) {
30173803d35Sotto 		while ((pw = getpwent()) != NULL)
30273803d35Sotto 			PASSWDPRINT;
30373803d35Sotto 	} else {
30473803d35Sotto 		for (i = 2; i < argc; i++) {
305927b549bSkn 			if ((pw = getpwnam(argv[i])) == NULL) {
306d150c7b2Skn 				uid = strtonum(argv[i], 0, UID_MAX, &err);
307927b549bSkn 				if (err == NULL)
308d150c7b2Skn 					pw = getpwuid(uid);
309927b549bSkn 			}
31073803d35Sotto 			if (pw != NULL)
31173803d35Sotto 				PASSWDPRINT;
31273803d35Sotto 			else {
31373803d35Sotto 				rv = RV_NOTFOUND;
31473803d35Sotto 				break;
31573803d35Sotto 			}
31673803d35Sotto 		}
31773803d35Sotto 	}
31873803d35Sotto 	endpwent();
31973803d35Sotto 	return rv;
32073803d35Sotto }
32173803d35Sotto 
32221c0d692Sderaadt #define PROTOCOLSPRINT	\
32321c0d692Sderaadt 	printfmtstrings(pe->p_aliases, "  ", " ", \
32421c0d692Sderaadt 	    "%-16s  %5d", pe->p_name, pe->p_proto)
32573803d35Sotto 
32673803d35Sotto static int
protocols(int argc,char * argv[])32773803d35Sotto protocols(int argc, char *argv[])
32873803d35Sotto {
32973803d35Sotto 	struct protoent	*pe;
330d150c7b2Skn 	const char	*err;
331d150c7b2Skn 	int		proto;
33221c0d692Sderaadt 	int		i, rv = RV_OK;
33373803d35Sotto 
33473803d35Sotto 	setprotoent(1);
33573803d35Sotto 	if (argc == 2) {
33673803d35Sotto 		while ((pe = getprotoent()) != NULL)
33773803d35Sotto 			PROTOCOLSPRINT;
33873803d35Sotto 	} else {
33973803d35Sotto 		for (i = 2; i < argc; i++) {
340d150c7b2Skn 			proto = strtonum(argv[i], 0, INT_MAX, &err);
34121c0d692Sderaadt 			if (!err)
342d150c7b2Skn 				pe = getprotobynumber(proto);
34373803d35Sotto 			else
34473803d35Sotto 				pe = getprotobyname(argv[i]);
34573803d35Sotto 			if (pe != NULL)
34673803d35Sotto 				PROTOCOLSPRINT;
34773803d35Sotto 			else {
34873803d35Sotto 				rv = RV_NOTFOUND;
34973803d35Sotto 				break;
35073803d35Sotto 			}
35173803d35Sotto 		}
35273803d35Sotto 	}
35373803d35Sotto 	endprotoent();
35473803d35Sotto 	return rv;
35573803d35Sotto }
35673803d35Sotto 
35721c0d692Sderaadt #define RPCPRINT	\
35821c0d692Sderaadt 	printfmtstrings(re->r_aliases, "  ", " ", \
35921c0d692Sderaadt 	    "%-16s  %6d", re->r_name, re->r_number)
36073803d35Sotto 
36173803d35Sotto static int
rpc(int argc,char * argv[])36273803d35Sotto rpc(int argc, char *argv[])
36373803d35Sotto {
36473803d35Sotto 	struct rpcent	*re;
365d150c7b2Skn 	const char	*err;
366d150c7b2Skn 	int		rpc;
36721c0d692Sderaadt 	int		i, rv = RV_OK;
36873803d35Sotto 
36973803d35Sotto 	setrpcent(1);
37073803d35Sotto 	if (argc == 2) {
37173803d35Sotto 		while ((re = getrpcent()) != NULL)
37273803d35Sotto 			RPCPRINT;
37373803d35Sotto 	} else {
37473803d35Sotto 		for (i = 2; i < argc; i++) {
375d150c7b2Skn 			rpc = strtonum(argv[i], 0, INT_MAX, &err);
37621c0d692Sderaadt 			if (!err)
377d150c7b2Skn 				re = getrpcbynumber(rpc);
37873803d35Sotto 			else
37973803d35Sotto 				re = getrpcbyname(argv[i]);
38073803d35Sotto 			if (re != NULL)
38173803d35Sotto 				RPCPRINT;
38273803d35Sotto 			else {
38373803d35Sotto 				rv = RV_NOTFOUND;
38473803d35Sotto 				break;
38573803d35Sotto 			}
38673803d35Sotto 		}
38773803d35Sotto 	}
38873803d35Sotto 	endrpcent();
38973803d35Sotto 	return rv;
39073803d35Sotto }
39173803d35Sotto 
39221c0d692Sderaadt #define SERVICESPRINT	\
39321c0d692Sderaadt 	printfmtstrings(se->s_aliases, "  ", " ", \
39421c0d692Sderaadt 	    "%-16s  %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto)
39573803d35Sotto 
39673803d35Sotto static int
services(int argc,char * argv[])39773803d35Sotto services(int argc, char *argv[])
39873803d35Sotto {
39973803d35Sotto 	struct servent	*se;
400d150c7b2Skn 	const char	*err;
401d150c7b2Skn 	char		*proto;
402d150c7b2Skn 	in_port_t	port;
40321c0d692Sderaadt 	int		i, rv = RV_OK;
40473803d35Sotto 
40573803d35Sotto 	setservent(1);
40673803d35Sotto 	if (argc == 2) {
40773803d35Sotto 		while ((se = getservent()) != NULL)
40873803d35Sotto 			SERVICESPRINT;
40973803d35Sotto 	} else {
41073803d35Sotto 		for (i = 2; i < argc; i++) {
411d150c7b2Skn 			if ((proto = strchr(argv[i], '/')) != NULL)
41273803d35Sotto 				*proto++ = '\0';
413d150c7b2Skn 			port = strtonum(argv[i], 0, IPPORT_HILASTAUTO, &err);
41421c0d692Sderaadt 			if (!err)
415d150c7b2Skn 				se = getservbyport(htons(port), proto);
41673803d35Sotto 			else
41773803d35Sotto 				se = getservbyname(argv[i], proto);
41873803d35Sotto 			if (se != NULL)
41973803d35Sotto 				SERVICESPRINT;
42073803d35Sotto 			else {
42173803d35Sotto 				rv = RV_NOTFOUND;
42273803d35Sotto 				break;
42373803d35Sotto 			}
42473803d35Sotto 		}
42573803d35Sotto 	}
42673803d35Sotto 	endservent();
42773803d35Sotto 	return rv;
42873803d35Sotto }
42973803d35Sotto 
4308baee4b3Sjca #define SHELLSPRINT	printf("%s\n", sh)
4318baee4b3Sjca 
43273803d35Sotto static int
shells(int argc,char * argv[])43373803d35Sotto shells(int argc, char *argv[])
43473803d35Sotto {
43573803d35Sotto 	const char	*sh;
43621c0d692Sderaadt 	int		i, rv = RV_OK;
43773803d35Sotto 
43873803d35Sotto 	setusershell();
43973803d35Sotto 	if (argc == 2) {
44073803d35Sotto 		while ((sh = getusershell()) != NULL)
4418baee4b3Sjca 			SHELLSPRINT;
44273803d35Sotto 	} else {
44373803d35Sotto 		for (i = 2; i < argc; i++) {
44473803d35Sotto 			setusershell();
44573803d35Sotto 			while ((sh = getusershell()) != NULL) {
44673803d35Sotto 				if (strcmp(sh, argv[i]) == 0) {
4478baee4b3Sjca 					SHELLSPRINT;
44873803d35Sotto 					break;
44973803d35Sotto 				}
45073803d35Sotto 			}
45173803d35Sotto 			if (sh == NULL) {
45273803d35Sotto 				rv = RV_NOTFOUND;
45373803d35Sotto 				break;
45473803d35Sotto 			}
45573803d35Sotto 		}
45673803d35Sotto 	}
45773803d35Sotto 	endusershell();
45873803d35Sotto 	return rv;
45973803d35Sotto }
460