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