Home | History | Annotate | Line # | Download | only in getent
getent.c revision 1.9
      1 /*	$NetBSD: getent.c,v 1.9 2006/08/27 06:58:55 simonb Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2004-2006 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Luke Mewburn.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 #ifndef lint
     41 __RCSID("$NetBSD: getent.c,v 1.9 2006/08/27 06:58:55 simonb Exp $");
     42 #endif /* not lint */
     43 
     44 #include <sys/socket.h>
     45 
     46 #include <assert.h>
     47 #include <ctype.h>
     48 #include <errno.h>
     49 #include <grp.h>
     50 #include <limits.h>
     51 #include <netdb.h>
     52 #include <pwd.h>
     53 #include <stdio.h>
     54 #include <stdarg.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <unistd.h>
     58 
     59 #include <arpa/inet.h>
     60 #include <arpa/nameser.h>
     61 
     62 #include <net/if.h>
     63 #include <net/if_ether.h>
     64 
     65 #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
     66 
     67 #include <rpc/rpcent.h>
     68 
     69 static int	usage(void);
     70 static int	parsenum(const char *, unsigned long *);
     71 static int	ethers(int, char *[]);
     72 static int	group(int, char *[]);
     73 static int	hosts(int, char *[]);
     74 static int	networks(int, char *[]);
     75 static int	passwd(int, char *[]);
     76 static int	protocols(int, char *[]);
     77 static int	rpc(int, char *[]);
     78 static int	services(int, char *[]);
     79 static int	shells(int, char *[]);
     80 
     81 enum {
     82 	RV_OK		= 0,
     83 	RV_USAGE	= 1,
     84 	RV_NOTFOUND	= 2,
     85 	RV_NOENUM	= 3,
     86 };
     87 
     88 static struct getentdb {
     89 	const char	*name;
     90 	int		(*callback)(int, char *[]);
     91 } databases[] = {
     92 	{	"ethers",	ethers,		},
     93 	{	"group",	group,		},
     94 	{	"hosts",	hosts,		},
     95 	{	"networks",	networks,	},
     96 	{	"passwd",	passwd,		},
     97 	{	"protocols",	protocols,	},
     98 	{	"rpc",		rpc,		},
     99 	{	"services",	services,	},
    100 	{	"shells",	shells,		},
    101 
    102 	{	NULL,		NULL,		},
    103 };
    104 
    105 
    106 int
    107 main(int argc, char *argv[])
    108 {
    109 	struct getentdb	*curdb;
    110 
    111 	setprogname(argv[0]);
    112 
    113 	if (argc < 2)
    114 		usage();
    115 	for (curdb = databases; curdb->name != NULL; curdb++) {
    116 		if (strcmp(curdb->name, argv[1]) == 0) {
    117 			exit(curdb->callback(argc, argv));
    118 			break;
    119 		}
    120 	}
    121 	fprintf(stderr, "Unknown database: %s\n", argv[1]);
    122 	usage();
    123 	/* NOTREACHED */
    124 	return RV_USAGE;
    125 }
    126 
    127 static int
    128 usage(void)
    129 {
    130 	struct getentdb	*curdb;
    131 
    132 	fprintf(stderr, "Usage: %s database [key ...]\n",
    133 	    getprogname());
    134 	fprintf(stderr, "       database may be one of:\n\t");
    135 	for (curdb = databases; curdb->name != NULL; curdb++) {
    136 		fprintf(stderr, " %s", curdb->name);
    137 	}
    138 	fprintf(stderr, "\n");
    139 	exit(RV_USAGE);
    140 	/* NOTREACHED */
    141 }
    142 
    143 static int
    144 parsenum(const char *word, unsigned long *result)
    145 {
    146 	unsigned long	num;
    147 	char		*ep;
    148 
    149 	assert(word != NULL);
    150 	assert(result != NULL);
    151 
    152 	if (!isdigit((unsigned char)word[0]))
    153 		return 0;
    154 	errno = 0;
    155 	num = strtoul(word, &ep, 10);
    156 	if (num == ULONG_MAX && errno == ERANGE)
    157 		return 0;
    158 	if (*ep != '\0')
    159 		return 0;
    160 	*result = num;
    161 	return 1;
    162 }
    163 
    164 /*
    165  * printfmtstrings --
    166  *	vprintf(format, ...),
    167  *	then the aliases (beginning with prefix, separated by sep),
    168  *	then a newline
    169  */
    170 static void
    171 printfmtstrings(char *strings[], const char *prefix, const char *sep,
    172 	const char *fmt, ...)
    173 {
    174 	va_list		ap;
    175 	const char	*curpref;
    176 	int		i;
    177 
    178 	va_start(ap, fmt);
    179 	vprintf(fmt, ap);
    180 
    181 	curpref = prefix;
    182 	for (i = 0; strings[i] != NULL; i++) {
    183 		printf("%s%s", curpref, strings[i]);
    184 		curpref = sep;
    185 	}
    186 	printf("\n");
    187 }
    188 
    189 
    190 		/*
    191 		 * ethers
    192 		 */
    193 
    194 static int
    195 ethers(int argc, char *argv[])
    196 {
    197 	char		hostname[MAXHOSTNAMELEN + 1], *hp;
    198 	struct ether_addr ea, *eap;
    199 	int		i, rv;
    200 
    201 	assert(argc > 1);
    202 	assert(argv != NULL);
    203 
    204 #define ETHERSPRINT	printf("%-17s  %s\n", ether_ntoa(eap), hp)
    205 
    206 	rv = RV_OK;
    207 	if (argc == 2) {
    208 		fprintf(stderr, "Enumeration not supported on ethers\n");
    209 		rv = RV_NOENUM;
    210 	} else {
    211 		for (i = 2; i < argc; i++) {
    212 			if ((eap = ether_aton(argv[i])) == NULL) {
    213 				eap = &ea;
    214 				hp = argv[i];
    215 				if (ether_hostton(hp, eap) != 0) {
    216 					rv = RV_NOTFOUND;
    217 					break;
    218 				}
    219 			} else {
    220 				hp = hostname;
    221 				if (ether_ntohost(hp, eap) != 0) {
    222 					rv = RV_NOTFOUND;
    223 					break;
    224 				}
    225 			}
    226 			ETHERSPRINT;
    227 		}
    228 	}
    229 	return rv;
    230 }
    231 
    232 		/*
    233 		 * group
    234 		 */
    235 
    236 static int
    237 group(int argc, char *argv[])
    238 {
    239 	struct group	*gr;
    240 	unsigned long	id;
    241 	int		i, rv;
    242 
    243 	assert(argc > 1);
    244 	assert(argv != NULL);
    245 
    246 #define GROUPPRINT	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
    247 			    gr->gr_name, gr->gr_passwd, gr->gr_gid)
    248 
    249 	setgroupent(1);
    250 	rv = RV_OK;
    251 	if (argc == 2) {
    252 		while ((gr = getgrent()) != NULL)
    253 			GROUPPRINT;
    254 	} else {
    255 		for (i = 2; i < argc; i++) {
    256 			if (parsenum(argv[i], &id))
    257 				gr = getgrgid(id);
    258 			else
    259 				gr = getgrnam(argv[i]);
    260 			if (gr != NULL)
    261 				GROUPPRINT;
    262 			else {
    263 				rv = RV_NOTFOUND;
    264 				break;
    265 			}
    266 		}
    267 	}
    268 	endgrent();
    269 	return rv;
    270 }
    271 
    272 
    273 		/*
    274 		 * hosts
    275 		 */
    276 
    277 static void
    278 hostsprint(const struct hostent *he)
    279 {
    280 	char	buf[INET6_ADDRSTRLEN];
    281 
    282 	assert(he != NULL);
    283 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
    284 		strlcpy(buf, "# unknown", sizeof(buf));
    285 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
    286 }
    287 
    288 static int
    289 hosts(int argc, char *argv[])
    290 {
    291 	struct hostent	*he;
    292 	char		addr[IN6ADDRSZ];
    293 	int		i, rv;
    294 
    295 	assert(argc > 1);
    296 	assert(argv != NULL);
    297 
    298 	sethostent(1);
    299 	rv = RV_OK;
    300 	if (argc == 2) {
    301 		while ((he = gethostent()) != NULL)
    302 			hostsprint(he);
    303 	} else {
    304 		for (i = 2; i < argc; i++) {
    305 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
    306 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
    307 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
    308 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
    309 			else
    310 				he = gethostbyname(argv[i]);
    311 			if (he != NULL)
    312 				hostsprint(he);
    313 			else {
    314 				rv = RV_NOTFOUND;
    315 				break;
    316 			}
    317 		}
    318 	}
    319 	endhostent();
    320 	return rv;
    321 }
    322 
    323 
    324 		/*
    325 		 * networks
    326 		 */
    327 
    328 static void
    329 networksprint(const struct netent *ne)
    330 {
    331 	char		buf[INET6_ADDRSTRLEN];
    332 	struct	in_addr	ianet;
    333 
    334 	assert(ne != NULL);
    335 	ianet = inet_makeaddr(ne->n_net, 0);
    336 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
    337 		strlcpy(buf, "# unknown", sizeof(buf));
    338 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
    339 }
    340 
    341 static int
    342 networks(int argc, char *argv[])
    343 {
    344 	struct netent	*ne;
    345 	in_addr_t	net;
    346 	int		i, rv;
    347 
    348 	assert(argc > 1);
    349 	assert(argv != NULL);
    350 
    351 	setnetent(1);
    352 	rv = RV_OK;
    353 	if (argc == 2) {
    354 		while ((ne = getnetent()) != NULL)
    355 			networksprint(ne);
    356 	} else {
    357 		for (i = 2; i < argc; i++) {
    358 			net = inet_network(argv[i]);
    359 			if (net != INADDR_NONE)
    360 				ne = getnetbyaddr(net, AF_INET);
    361 			else
    362 				ne = getnetbyname(argv[i]);
    363 			if (ne != NULL)
    364 				networksprint(ne);
    365 			else {
    366 				rv = RV_NOTFOUND;
    367 				break;
    368 			}
    369 		}
    370 	}
    371 	endnetent();
    372 	return rv;
    373 }
    374 
    375 
    376 		/*
    377 		 * passwd
    378 		 */
    379 
    380 static int
    381 passwd(int argc, char *argv[])
    382 {
    383 	struct passwd	*pw;
    384 	unsigned long	id;
    385 	int		i, rv;
    386 
    387 	assert(argc > 1);
    388 	assert(argv != NULL);
    389 
    390 #define PASSWDPRINT	printf("%s:%s:%u:%u:%s:%s:%s\n", \
    391 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
    392 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
    393 
    394 	setpassent(1);
    395 	rv = RV_OK;
    396 	if (argc == 2) {
    397 		while ((pw = getpwent()) != NULL)
    398 			PASSWDPRINT;
    399 	} else {
    400 		for (i = 2; i < argc; i++) {
    401 			if (parsenum(argv[i], &id))
    402 				pw = getpwuid(id);
    403 			else
    404 				pw = getpwnam(argv[i]);
    405 			if (pw != NULL)
    406 				PASSWDPRINT;
    407 			else {
    408 				rv = RV_NOTFOUND;
    409 				break;
    410 			}
    411 		}
    412 	}
    413 	endpwent();
    414 	return rv;
    415 }
    416 
    417 
    418 		/*
    419 		 * protocols
    420 		 */
    421 
    422 static int
    423 protocols(int argc, char *argv[])
    424 {
    425 	struct protoent	*pe;
    426 	unsigned long	id;
    427 	int		i, rv;
    428 
    429 	assert(argc > 1);
    430 	assert(argv != NULL);
    431 
    432 #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
    433 			    "%-16s  %5d", pe->p_name, pe->p_proto)
    434 
    435 	setprotoent(1);
    436 	rv = RV_OK;
    437 	if (argc == 2) {
    438 		while ((pe = getprotoent()) != NULL)
    439 			PROTOCOLSPRINT;
    440 	} else {
    441 		for (i = 2; i < argc; i++) {
    442 			if (parsenum(argv[i], &id))
    443 				pe = getprotobynumber(id);
    444 			else
    445 				pe = getprotobyname(argv[i]);
    446 			if (pe != NULL)
    447 				PROTOCOLSPRINT;
    448 			else {
    449 				rv = RV_NOTFOUND;
    450 				break;
    451 			}
    452 		}
    453 	}
    454 	endprotoent();
    455 	return rv;
    456 }
    457 
    458 		/*
    459 		 * rpc
    460 		 */
    461 
    462 static int
    463 rpc(int argc, char *argv[])
    464 {
    465 	struct rpcent	*re;
    466 	unsigned long	id;
    467 	int		i, rv;
    468 
    469 	assert(argc > 1);
    470 	assert(argv != NULL);
    471 
    472 #define RPCPRINT	printfmtstrings(re->r_aliases, "  ", " ", \
    473 				"%-16s  %6d", \
    474 				re->r_name, re->r_number)
    475 
    476 	setrpcent(1);
    477 	rv = RV_OK;
    478 	if (argc == 2) {
    479 		while ((re = getrpcent()) != NULL)
    480 			RPCPRINT;
    481 	} else {
    482 		for (i = 2; i < argc; i++) {
    483 			if (parsenum(argv[i], &id))
    484 				re = getrpcbynumber(id);
    485 			else
    486 				re = getrpcbyname(argv[i]);
    487 			if (re != NULL)
    488 				RPCPRINT;
    489 			else {
    490 				rv = RV_NOTFOUND;
    491 				break;
    492 			}
    493 		}
    494 	}
    495 	endrpcent();
    496 	return rv;
    497 }
    498 
    499 		/*
    500 		 * services
    501 		 */
    502 
    503 static int
    504 services(int argc, char *argv[])
    505 {
    506 	struct servent	*se;
    507 	unsigned long	id;
    508 	char		*proto;
    509 	int		i, rv;
    510 
    511 	assert(argc > 1);
    512 	assert(argv != NULL);
    513 
    514 #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
    515 			    "%-16s  %5d/%s", \
    516 			    se->s_name, ntohs(se->s_port), se->s_proto)
    517 
    518 	setservent(1);
    519 	rv = RV_OK;
    520 	if (argc == 2) {
    521 		while ((se = getservent()) != NULL)
    522 			SERVICESPRINT;
    523 	} else {
    524 		for (i = 2; i < argc; i++) {
    525 			proto = strchr(argv[i], '/');
    526 			if (proto != NULL)
    527 				*proto++ = '\0';
    528 			if (parsenum(argv[i], &id))
    529 				se = getservbyport(htons(id), proto);
    530 			else
    531 				se = getservbyname(argv[i], proto);
    532 			if (se != NULL)
    533 				SERVICESPRINT;
    534 			else {
    535 				rv = RV_NOTFOUND;
    536 				break;
    537 			}
    538 		}
    539 	}
    540 	endservent();
    541 	return rv;
    542 }
    543 
    544 
    545 		/*
    546 		 * shells
    547 		 */
    548 
    549 static int
    550 shells(int argc, char *argv[])
    551 {
    552 	const char	*sh;
    553 	int		i, rv;
    554 
    555 	assert(argc > 1);
    556 	assert(argv != NULL);
    557 
    558 #define SHELLSPRINT	printf("%s\n", sh)
    559 
    560 	setusershell();
    561 	rv = RV_OK;
    562 	if (argc == 2) {
    563 		while ((sh = getusershell()) != NULL)
    564 			SHELLSPRINT;
    565 	} else {
    566 		for (i = 2; i < argc; i++) {
    567 			setusershell();
    568 			while ((sh = getusershell()) != NULL) {
    569 				if (strcmp(sh, argv[i]) == 0) {
    570 					SHELLSPRINT;
    571 					break;
    572 				}
    573 			}
    574 			if (sh == NULL) {
    575 				rv = RV_NOTFOUND;
    576 				break;
    577 			}
    578 		}
    579 	}
    580 	endusershell();
    581 	return rv;
    582 }
    583