alicelinux

A lightweight musl + clang/llvm + libressl + busybox distro
git clone https://codeberg.org/emmett1/alicelinux
Log | Files | Refs | README | LICENSE

getent.c (9438B)


      1 /*-
      2  * Copyright (c) 2004-2006 The NetBSD Foundation, Inc.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to The NetBSD Foundation
      6  * by Luke Mewburn.
      7  * Timo Teräs cleaned up the code for use in Alpine Linux with musl libc.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/socket.h>
     32 #include <sys/param.h>
     33 #include <ctype.h>
     34 #include <errno.h>
     35 #include <limits.h>
     36 #include <netdb.h>
     37 #include <pwd.h>
     38 #include <grp.h>
     39 #include <stdio.h>
     40 #include <stdarg.h>
     41 #include <stdbool.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <unistd.h>
     45 #include <paths.h>
     46 #include <err.h>
     47 
     48 #include <arpa/inet.h>
     49 #include <arpa/nameser.h>
     50 
     51 #include <net/if.h>
     52 #include <net/ethernet.h>
     53 #include <netinet/ether.h>
     54 #include <netinet/in.h>
     55 
     56 enum {
     57 	RV_OK		= 0,
     58 	RV_USAGE	= 1,
     59 	RV_NOTFOUND	= 2,
     60 	RV_NOENUM	= 3
     61 };
     62 
     63 static int usage(const char *);
     64 
     65 static int parsenum(const char *word, unsigned long *result)
     66 {
     67 	unsigned long	num;
     68 	char		*ep;
     69 
     70 	if (!isdigit((unsigned char)word[0]))
     71 		return 0;
     72 	errno = 0;
     73 	num = strtoul(word, &ep, 10);
     74 	if (num == ULONG_MAX && errno == ERANGE)
     75 		return 0;
     76 	if (*ep != '\0')
     77 		return 0;
     78 	*result = num;
     79 	return 1;
     80 }
     81 
     82 /*
     83  * printfmtstrings --
     84  *	vprintf(format, ...),
     85  *	then the aliases (beginning with prefix, separated by sep),
     86  *	then a newline
     87  */
     88 __attribute__ ((format (printf, 4, 5)))
     89 static void printfmtstrings(char *strings[], const char *prefix, const char *sep,
     90 	const char *fmt, ...)
     91 {
     92 	va_list		ap;
     93 	const char	*curpref;
     94 	size_t		i;
     95 
     96 	va_start(ap, fmt);
     97 	(void)vprintf(fmt, ap);
     98 	va_end(ap);
     99 
    100 	curpref = prefix;
    101 	for (i = 0; strings[i] != NULL; i++) {
    102 		(void)printf("%s%s", curpref, strings[i]);
    103 		curpref = sep;
    104 	}
    105 	(void)printf("\n");
    106 }
    107 
    108 static int ethers(int argc, char *argv[])
    109 {
    110 	char		hostname[MAXHOSTNAMELEN + 1], *hp;
    111 	struct ether_addr ea, *eap;
    112 	int		i, rv;
    113 
    114 	if (argc == 2) {
    115 		warnx("Enumeration not supported on ethers");
    116 		return RV_NOENUM;
    117 	}
    118 
    119 	rv = RV_OK;
    120 	for (i = 2; i < argc; i++) {
    121 		if ((eap = ether_aton(argv[i])) == NULL) {
    122 			eap = &ea;
    123 			hp = argv[i];
    124 			if (ether_hostton(hp, eap) != 0) {
    125 				rv = RV_NOTFOUND;
    126 				break;
    127 			}
    128 		} else {
    129 			hp = hostname;
    130 			if (ether_ntohost(hp, eap) != 0) {
    131 				rv = RV_NOTFOUND;
    132 				break;
    133 			}
    134 		}
    135 		(void)printf("%-17s  %s\n", ether_ntoa(eap), hp);
    136 	}
    137 	return rv;
    138 }
    139 
    140 static void groupprint(const struct group *gr)
    141 {
    142 	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u",
    143 			gr->gr_name, gr->gr_passwd, gr->gr_gid);
    144 }
    145 
    146 static int group(int argc, char *argv[])
    147 {
    148 	struct group	*gr;
    149 	unsigned long	id;
    150 	int		i, rv;
    151 
    152 	rv = RV_OK;
    153 	if (argc == 2) {
    154 		while ((gr = getgrent()) != NULL)
    155 			groupprint(gr);
    156 	} else {
    157 		for (i = 2; i < argc; i++) {
    158 			if (parsenum(argv[i], &id))
    159 				gr = getgrgid((gid_t)id);
    160 			else
    161 				gr = getgrnam(argv[i]);
    162 			if (gr == NULL) {
    163 				rv = RV_NOTFOUND;
    164 				break;
    165 			}
    166 			groupprint(gr);
    167 		}
    168 	}
    169 	endgrent();
    170 	return rv;
    171 }
    172 
    173 static void hostsprint(const struct hostent *he)
    174 {
    175 	char	buf[INET6_ADDRSTRLEN];
    176 
    177 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
    178 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    179 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
    180 }
    181 
    182 static int hosts(int argc, char *argv[])
    183 {
    184 	struct hostent	*he;
    185 	char		addr[IN6ADDRSZ];
    186 	int		i, rv;
    187 
    188 	sethostent(1);
    189 	rv = RV_OK;
    190 	if (argc == 2) {
    191 		while ((he = gethostent()) != NULL)
    192 			hostsprint(he);
    193 	} else {
    194 		for (i = 2; i < argc; i++) {
    195 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
    196 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
    197 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
    198 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
    199 			else
    200 				he = gethostbyname(argv[i]);
    201 			if (he == NULL) {
    202 				rv = RV_NOTFOUND;
    203 				break;
    204 			}
    205 			hostsprint(he);
    206 		}
    207 	}
    208 	endhostent();
    209 	return rv;
    210 }
    211 
    212 static void networksprint(const struct netent *ne)
    213 {
    214 	char		buf[INET6_ADDRSTRLEN];
    215 	struct	in_addr	ianet;
    216 
    217 	ianet = inet_makeaddr(ne->n_net, 0);
    218 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
    219 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    220 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
    221 }
    222 
    223 static int networks(int argc, char *argv[])
    224 {
    225 	struct netent	*ne;
    226 	in_addr_t	net;
    227 	int		i, rv;
    228 
    229 	setnetent(1);
    230 	rv = RV_OK;
    231 	if (argc == 2) {
    232 		while ((ne = getnetent()) != NULL)
    233 			networksprint(ne);
    234 	} else {
    235 		for (i = 2; i < argc; i++) {
    236 			net = inet_network(argv[i]);
    237 			if (net != INADDR_NONE)
    238 				ne = getnetbyaddr(net, AF_INET);
    239 			else
    240 				ne = getnetbyname(argv[i]);
    241 			if (ne == NULL) {
    242 				rv = RV_NOTFOUND;
    243 				break;
    244 			}
    245 			networksprint(ne);
    246 		}
    247 	}
    248 	endnetent();
    249 	return rv;
    250 }
    251 
    252 static void passwdprint(struct passwd *pw)
    253 {
    254 	(void)printf("%s:%s:%u:%u:%s:%s:%s\n",
    255 		pw->pw_name, pw->pw_passwd, pw->pw_uid,
    256 		pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell);
    257 }
    258 
    259 static int passwd(int argc, char *argv[])
    260 {
    261 	struct passwd	*pw;
    262 	unsigned long	id;
    263 	int		i, rv;
    264 
    265 	rv = RV_OK;
    266 	if (argc == 2) {
    267 		while ((pw = getpwent()) != NULL)
    268 			passwdprint(pw);
    269 	} else {
    270 		for (i = 2; i < argc; i++) {
    271 			if (parsenum(argv[i], &id))
    272 				pw = getpwuid((uid_t)id);
    273 			else
    274 				pw = getpwnam(argv[i]);
    275 			if (pw == NULL) {
    276 				rv = RV_NOTFOUND;
    277 				break;
    278 			}
    279 			passwdprint(pw);
    280 		}
    281 	}
    282 	endpwent();
    283 	return rv;
    284 }
    285 
    286 static void protocolsprint(struct protoent *pe)
    287 {
    288 	printfmtstrings(pe->p_aliases, "  ", " ",
    289 			"%-16s  %5d", pe->p_name, pe->p_proto);
    290 }
    291 
    292 static int protocols(int argc, char *argv[])
    293 {
    294 	struct protoent	*pe;
    295 	unsigned long	id;
    296 	int		i, rv;
    297 
    298 	setprotoent(1);
    299 	rv = RV_OK;
    300 	if (argc == 2) {
    301 		while ((pe = getprotoent()) != NULL)
    302 			protocolsprint(pe);
    303 	} else {
    304 		for (i = 2; i < argc; i++) {
    305 			if (parsenum(argv[i], &id))
    306 				pe = getprotobynumber((int)id);
    307 			else
    308 				pe = getprotobyname(argv[i]);
    309 			if (pe == NULL) {
    310 				rv = RV_NOTFOUND;
    311 				break;
    312 			}
    313 			protocolsprint(pe);
    314 		}
    315 	}
    316 	endprotoent();
    317 	return rv;
    318 }
    319 
    320 static void servicesprint(struct servent *se)
    321 {
    322 	printfmtstrings(se->s_aliases, "  ", " ",
    323 			"%-16s  %5d/%s",
    324 			se->s_name, ntohs(se->s_port), se->s_proto);
    325 
    326 }
    327 
    328 static int services(int argc, char *argv[])
    329 {
    330 	struct servent	*se;
    331 	unsigned long	id;
    332 	char		*proto;
    333 	int		i, rv;
    334 
    335 	setservent(1);
    336 	rv = RV_OK;
    337 	if (argc == 2) {
    338 		while ((se = getservent()) != NULL)
    339 			servicesprint(se);
    340 	} else {
    341 		for (i = 2; i < argc; i++) {
    342 			proto = strchr(argv[i], '/');
    343 			if (proto != NULL)
    344 				*proto++ = '\0';
    345 			if (parsenum(argv[i], &id))
    346 				se = getservbyport(htons(id), proto);
    347 			else
    348 				se = getservbyname(argv[i], proto);
    349 			if (se == NULL) {
    350 				rv = RV_NOTFOUND;
    351 				break;
    352 			}
    353 			servicesprint(se);
    354 		}
    355 	}
    356 	endservent();
    357 	return rv;
    358 }
    359 
    360 static int shells(int argc, char *argv[])
    361 {
    362 	const char	*sh;
    363 	int		i, rv;
    364 
    365 	setusershell();
    366 	rv = RV_OK;
    367 	if (argc == 2) {
    368 		while ((sh = getusershell()) != NULL)
    369 			(void)printf("%s\n", sh);
    370 	} else {
    371 		for (i = 2; i < argc; i++) {
    372 			setusershell();
    373 			while ((sh = getusershell()) != NULL) {
    374 				if (strcmp(sh, argv[i]) == 0) {
    375 					(void)printf("%s\n", sh);
    376 					break;
    377 				}
    378 			}
    379 			if (sh == NULL) {
    380 				rv = RV_NOTFOUND;
    381 				break;
    382 			}
    383 		}
    384 	}
    385 	endusershell();
    386 	return rv;
    387 }
    388 
    389 static struct getentdb {
    390 	const char	*name;
    391 	int		(*callback)(int, char *[]);
    392 } databases[] = {
    393 	{	"ethers",	ethers,		},
    394 	{	"group",	group,		},
    395 	{	"hosts",	hosts,		},
    396 	{	"networks",	networks,	},
    397 	{	"passwd",	passwd,		},
    398 	{	"protocols",	protocols,	},
    399 	{	"services",	services,	},
    400 	{	"shells",	shells,		},
    401 
    402 	{	NULL,		NULL,		},
    403 };
    404 
    405 static int usage(const char *arg0)
    406 {
    407 	struct getentdb	*curdb;
    408 	size_t i;
    409 
    410 	(void)fprintf(stderr, "Usage: %s database [key ...]\n", arg0);
    411 	(void)fprintf(stderr, "\tdatabase may be one of:");
    412 	for (i = 0, curdb = databases; curdb->name != NULL; curdb++, i++) {
    413 		if (i % 7 == 0)
    414 			(void)fputs("\n\t\t", stderr);
    415 		(void)fprintf(stderr, "%s%s", i % 7 == 0 ? "" : " ",
    416 		    curdb->name);
    417 	}
    418 	(void)fprintf(stderr, "\n");
    419 	exit(RV_USAGE);
    420 	/* NOTREACHED */
    421 }
    422 
    423 int
    424 main(int argc, char *argv[])
    425 {
    426 	struct getentdb	*curdb;
    427 
    428 	if (argc < 2)
    429 		usage(argv[0]);
    430 	for (curdb = databases; curdb->name != NULL; curdb++)
    431 		if (strcmp(curdb->name, argv[1]) == 0)
    432 			return (*curdb->callback)(argc, argv);
    433 
    434 	warn("Unknown database `%s'", argv[1]);
    435 	usage(argv[0]);
    436 	/* NOTREACHED */
    437 }