Home | History | Annotate | Line # | Download | only in getent
getent.c revision 1.10
      1 /*	$NetBSD: getent.c,v 1.10 2008/02/01 22:39:21 christos 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.10 2008/02/01 22:39:21 christos 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 #include <paths.h>
     59 #include <err.h>
     60 
     61 #include <arpa/inet.h>
     62 #include <arpa/nameser.h>
     63 
     64 #include <net/if.h>
     65 #include <net/if_ether.h>
     66 
     67 #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
     68 
     69 #include <rpc/rpcent.h>
     70 
     71 #include <disktab.h>
     72 
     73 static int	usage(void) __attribute__((__noreturn__));
     74 static int	parsenum(const char *, unsigned long *);
     75 static int	disktab(int, char *[]);
     76 static int	ethers(int, char *[]);
     77 static int	group(int, char *[]);
     78 static int	hosts(int, char *[]);
     79 static int	networks(int, char *[]);
     80 static int	passwd(int, char *[]);
     81 static int	printcap(int, char *[]);
     82 static int	protocols(int, char *[]);
     83 static int	rpc(int, char *[]);
     84 static int	services(int, char *[]);
     85 static int	shells(int, char *[]);
     86 static int	termcap(int, char *[]);
     87 
     88 enum {
     89 	RV_OK		= 0,
     90 	RV_USAGE	= 1,
     91 	RV_NOTFOUND	= 2,
     92 	RV_NOENUM	= 3
     93 };
     94 
     95 static struct getentdb {
     96 	const char	*name;
     97 	int		(*callback)(int, char *[]);
     98 } databases[] = {
     99 	{	"disktab",	disktab,	},
    100 	{	"ethers",	ethers,		},
    101 	{	"group",	group,		},
    102 	{	"hosts",	hosts,		},
    103 	{	"networks",	networks,	},
    104 	{	"passwd",	passwd,		},
    105 	{	"princap",	printcap,	},
    106 	{	"protocols",	protocols,	},
    107 	{	"rpc",		rpc,		},
    108 	{	"services",	services,	},
    109 	{	"shells",	shells,		},
    110 	{	"termcap",	termcap,	},
    111 
    112 	{	NULL,		NULL,		},
    113 };
    114 
    115 
    116 int
    117 main(int argc, char *argv[])
    118 {
    119 	struct getentdb	*curdb;
    120 
    121 	setprogname(argv[0]);
    122 
    123 	if (argc < 2)
    124 		usage();
    125 	for (curdb = databases; curdb->name != NULL; curdb++)
    126 		if (strcmp(curdb->name, argv[1]) == 0)
    127 			return (*curdb->callback)(argc, argv);
    128 
    129 	warn("Unknown database `%s'", argv[1]);
    130 	usage();
    131 	/* NOTREACHED */
    132 }
    133 
    134 static int
    135 usage(void)
    136 {
    137 	struct getentdb	*curdb;
    138 
    139 	(void)fprintf(stderr, "Usage: %s database [key ...]\n",
    140 	    getprogname());
    141 	(void)fprintf(stderr, "       database may be one of:\n\t");
    142 	for (curdb = databases; curdb->name != NULL; curdb++)
    143 		(void)fprintf(stderr, " %s", curdb->name);
    144 	(void)fprintf(stderr, "\n");
    145 	exit(RV_USAGE);
    146 	/* NOTREACHED */
    147 }
    148 
    149 static int
    150 parsenum(const char *word, unsigned long *result)
    151 {
    152 	unsigned long	num;
    153 	char		*ep;
    154 
    155 	assert(word != NULL);
    156 	assert(result != NULL);
    157 
    158 	if (!isdigit((unsigned char)word[0]))
    159 		return 0;
    160 	errno = 0;
    161 	num = strtoul(word, &ep, 10);
    162 	if (num == ULONG_MAX && errno == ERANGE)
    163 		return 0;
    164 	if (*ep != '\0')
    165 		return 0;
    166 	*result = num;
    167 	return 1;
    168 }
    169 
    170 /*
    171  * printfmtstrings --
    172  *	vprintf(format, ...),
    173  *	then the aliases (beginning with prefix, separated by sep),
    174  *	then a newline
    175  */
    176 static void
    177 printfmtstrings(char *strings[], const char *prefix, const char *sep,
    178     const char *fmt, ...)
    179 {
    180 	va_list		ap;
    181 	const char	*curpref;
    182 	size_t		i;
    183 
    184 	va_start(ap, fmt);
    185 	(void)vprintf(fmt, ap);
    186 	va_end(ap);
    187 
    188 	curpref = prefix;
    189 	for (i = 0; strings[i] != NULL; i++) {
    190 		(void)printf("%s%s", curpref, strings[i]);
    191 		curpref = sep;
    192 	}
    193 	(void)printf("\n");
    194 }
    195 
    196 
    197 		/*
    198 		 * ethers
    199 		 */
    200 
    201 static int
    202 ethers(int argc, char *argv[])
    203 {
    204 	char		hostname[MAXHOSTNAMELEN + 1], *hp;
    205 	struct ether_addr ea, *eap;
    206 	int		i, rv;
    207 
    208 	assert(argc > 1);
    209 	assert(argv != NULL);
    210 
    211 #define ETHERSPRINT	(void)printf("%-17s  %s\n", ether_ntoa(eap), hp)
    212 
    213 	rv = RV_OK;
    214 	if (argc == 2) {
    215 		warnx("Enumeration not supported on ethers");
    216 		rv = RV_NOENUM;
    217 	} else {
    218 		for (i = 2; i < argc; i++) {
    219 			if ((eap = ether_aton(argv[i])) == NULL) {
    220 				eap = &ea;
    221 				hp = argv[i];
    222 				if (ether_hostton(hp, eap) != 0) {
    223 					rv = RV_NOTFOUND;
    224 					break;
    225 				}
    226 			} else {
    227 				hp = hostname;
    228 				if (ether_ntohost(hp, eap) != 0) {
    229 					rv = RV_NOTFOUND;
    230 					break;
    231 				}
    232 			}
    233 			ETHERSPRINT;
    234 		}
    235 	}
    236 	return rv;
    237 }
    238 
    239 		/*
    240 		 * group
    241 		 */
    242 
    243 static int
    244 group(int argc, char *argv[])
    245 {
    246 	struct group	*gr;
    247 	unsigned long	id;
    248 	int		i, rv;
    249 
    250 	assert(argc > 1);
    251 	assert(argv != NULL);
    252 
    253 #define GROUPPRINT	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
    254 			    gr->gr_name, gr->gr_passwd, gr->gr_gid)
    255 
    256 	(void)setgroupent(1);
    257 	rv = RV_OK;
    258 	if (argc == 2) {
    259 		while ((gr = getgrent()) != NULL)
    260 			GROUPPRINT;
    261 	} else {
    262 		for (i = 2; i < argc; i++) {
    263 			if (parsenum(argv[i], &id))
    264 				gr = getgrgid((gid_t)id);
    265 			else
    266 				gr = getgrnam(argv[i]);
    267 			if (gr != NULL)
    268 				GROUPPRINT;
    269 			else {
    270 				rv = RV_NOTFOUND;
    271 				break;
    272 			}
    273 		}
    274 	}
    275 	endgrent();
    276 	return rv;
    277 }
    278 
    279 
    280 		/*
    281 		 * hosts
    282 		 */
    283 
    284 static void
    285 hostsprint(const struct hostent *he)
    286 {
    287 	char	buf[INET6_ADDRSTRLEN];
    288 
    289 	assert(he != NULL);
    290 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
    291 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    292 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
    293 }
    294 
    295 static int
    296 hosts(int argc, char *argv[])
    297 {
    298 	struct hostent	*he;
    299 	char		addr[IN6ADDRSZ];
    300 	int		i, rv;
    301 
    302 	assert(argc > 1);
    303 	assert(argv != NULL);
    304 
    305 	sethostent(1);
    306 	rv = RV_OK;
    307 	if (argc == 2) {
    308 		while ((he = gethostent()) != NULL)
    309 			hostsprint(he);
    310 	} else {
    311 		for (i = 2; i < argc; i++) {
    312 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
    313 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
    314 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
    315 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
    316 			else
    317 				he = gethostbyname(argv[i]);
    318 			if (he != NULL)
    319 				hostsprint(he);
    320 			else {
    321 				rv = RV_NOTFOUND;
    322 				break;
    323 			}
    324 		}
    325 	}
    326 	endhostent();
    327 	return rv;
    328 }
    329 
    330 
    331 		/*
    332 		 * networks
    333 		 */
    334 
    335 static void
    336 networksprint(const struct netent *ne)
    337 {
    338 	char		buf[INET6_ADDRSTRLEN];
    339 	struct	in_addr	ianet;
    340 
    341 	assert(ne != NULL);
    342 	ianet = inet_makeaddr(ne->n_net, 0);
    343 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
    344 		(void)strlcpy(buf, "# unknown", sizeof(buf));
    345 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
    346 }
    347 
    348 static int
    349 networks(int argc, char *argv[])
    350 {
    351 	struct netent	*ne;
    352 	in_addr_t	net;
    353 	int		i, rv;
    354 
    355 	assert(argc > 1);
    356 	assert(argv != NULL);
    357 
    358 	setnetent(1);
    359 	rv = RV_OK;
    360 	if (argc == 2) {
    361 		while ((ne = getnetent()) != NULL)
    362 			networksprint(ne);
    363 	} else {
    364 		for (i = 2; i < argc; i++) {
    365 			net = inet_network(argv[i]);
    366 			if (net != INADDR_NONE)
    367 				ne = getnetbyaddr(net, AF_INET);
    368 			else
    369 				ne = getnetbyname(argv[i]);
    370 			if (ne != NULL)
    371 				networksprint(ne);
    372 			else {
    373 				rv = RV_NOTFOUND;
    374 				break;
    375 			}
    376 		}
    377 	}
    378 	endnetent();
    379 	return rv;
    380 }
    381 
    382 
    383 		/*
    384 		 * passwd
    385 		 */
    386 
    387 static int
    388 passwd(int argc, char *argv[])
    389 {
    390 	struct passwd	*pw;
    391 	unsigned long	id;
    392 	int		i, rv;
    393 
    394 	assert(argc > 1);
    395 	assert(argv != NULL);
    396 
    397 #define PASSWDPRINT	(void)printf("%s:%s:%u:%u:%s:%s:%s\n", \
    398 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
    399 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
    400 
    401 	(void)setpassent(1);
    402 	rv = RV_OK;
    403 	if (argc == 2) {
    404 		while ((pw = getpwent()) != NULL)
    405 			PASSWDPRINT;
    406 	} else {
    407 		for (i = 2; i < argc; i++) {
    408 			if (parsenum(argv[i], &id))
    409 				pw = getpwuid((uid_t)id);
    410 			else
    411 				pw = getpwnam(argv[i]);
    412 			if (pw != NULL)
    413 				PASSWDPRINT;
    414 			else {
    415 				rv = RV_NOTFOUND;
    416 				break;
    417 			}
    418 		}
    419 	}
    420 	endpwent();
    421 	return rv;
    422 }
    423 
    424 static char *
    425 mygetent(const char * const * db_array, const char *name)
    426 {
    427 	char *buf = NULL;
    428 	int error;
    429 
    430 	switch (error = cgetent(&buf, db_array, name)) {
    431 	case -3:
    432 		warnx("tc= loop in record `%s' in `%s'", name, db_array[0]);
    433 		break;
    434 	case -2:
    435 		warn("system error fetching record `%s' in `%s'", name,
    436 		    db_array[0]);
    437 		break;
    438 	case -1:
    439 	case 0:
    440 		break;
    441 	case 1:
    442 		warnx("tc= reference not found in record for `%s' in `%s'",
    443 		    name, db_array[0]);
    444 		break;
    445 	default:
    446 		warnx("unknown error %d in record `%s' in `%s'", error, name,
    447 		    db_array[0]);
    448 		break;
    449 	}
    450 	return buf;
    451 }
    452 
    453 static char *
    454 mygetone(const char * const * db_array, int first)
    455 {
    456 	char *buf = NULL;
    457 	int error;
    458 
    459 	switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) {
    460 	case -2:
    461 		warnx("tc= loop in `%s'", db_array[0]);
    462 		break;
    463 	case -1:
    464 		warn("system error fetching record in `%s'", db_array[0]);
    465 		break;
    466 	case 0:
    467 	case 1:
    468 		break;
    469 	case 2:
    470 		warnx("tc= reference not found in `%s'", db_array[0]);
    471 		break;
    472 	default:
    473 		warnx("unknown error %d in `%s'", error, db_array[0]);
    474 		break;
    475 	}
    476 	return buf;
    477 }
    478 
    479 static void
    480 capprint(const char *cap)
    481 {
    482 	char *c = strchr(cap, ':');
    483 	if (c)
    484 		if (c == cap)
    485 			(void)printf("true\n");
    486 		else {
    487 			int l = (int)(c - cap);
    488 			(void)printf("%*.*s\n", l, l, cap);
    489 		}
    490 	else
    491 		(void)printf("%s\n", cap);
    492 }
    493 
    494 static int
    495 handlecap(const char *db, int argc, char *argv[])
    496 {
    497 	static const char sfx[] = "=#:";
    498 	const char *db_array[] = { db, NULL };
    499 	char	*b, *cap;
    500 	int	i, j, rv;
    501 
    502 	assert(argc > 1);
    503 	assert(argv != NULL);
    504 
    505 	rv = RV_OK;
    506 	if (argc == 2) {
    507 		for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) {
    508 			(void)printf("%s\n", b);
    509 			free(b);
    510 		}
    511 	} else {
    512 		if ((b = mygetent(db_array, argv[2])) == NULL)
    513 			return RV_NOTFOUND;
    514 		if (argc == 3)
    515 			(void)printf("%s\n", b);
    516 		else {
    517 			for (i = 3; i < argc; i++) {
    518 				for (j = 0; j < sizeof(sfx) - 1; j++) {
    519 					cap = cgetcap(b, argv[i], sfx[j]);
    520 					if (cap) {
    521 						capprint(cap);
    522 						break;
    523 					}
    524 				}
    525 				if (j == sizeof(sfx) - 1)
    526 					printf("false\n");
    527 			}
    528 		}
    529 		free(b);
    530 	}
    531 	return rv;
    532 }
    533 
    534 		/*
    535 		 * printcap
    536 		 */
    537 
    538 static int
    539 printcap(int argc, char *argv[])
    540 {
    541 	return handlecap(_PATH_PRINTCAP, argc, argv);
    542 }
    543 
    544 		/*
    545 		 * disktab
    546 		 */
    547 
    548 static int
    549 disktab(int argc, char *argv[])
    550 {
    551 	return handlecap(_PATH_DISKTAB, argc, argv);
    552 }
    553 
    554 		/*
    555 		 * termcap
    556 		 */
    557 
    558 static int
    559 termcap(int argc, char *argv[])
    560 {
    561 	return handlecap(_PATH_TERMCAP, argc, argv);
    562 }
    563 		/*
    564 		 * protocols
    565 		 */
    566 
    567 static int
    568 protocols(int argc, char *argv[])
    569 {
    570 	struct protoent	*pe;
    571 	unsigned long	id;
    572 	int		i, rv;
    573 
    574 	assert(argc > 1);
    575 	assert(argv != NULL);
    576 
    577 #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
    578 			    "%-16s  %5d", pe->p_name, pe->p_proto)
    579 
    580 	setprotoent(1);
    581 	rv = RV_OK;
    582 	if (argc == 2) {
    583 		while ((pe = getprotoent()) != NULL)
    584 			PROTOCOLSPRINT;
    585 	} else {
    586 		for (i = 2; i < argc; i++) {
    587 			if (parsenum(argv[i], &id))
    588 				pe = getprotobynumber((int)id);
    589 			else
    590 				pe = getprotobyname(argv[i]);
    591 			if (pe != NULL)
    592 				PROTOCOLSPRINT;
    593 			else {
    594 				rv = RV_NOTFOUND;
    595 				break;
    596 			}
    597 		}
    598 	}
    599 	endprotoent();
    600 	return rv;
    601 }
    602 
    603 		/*
    604 		 * rpc
    605 		 */
    606 
    607 static int
    608 rpc(int argc, char *argv[])
    609 {
    610 	struct rpcent	*re;
    611 	unsigned long	id;
    612 	int		i, rv;
    613 
    614 	assert(argc > 1);
    615 	assert(argv != NULL);
    616 
    617 #define RPCPRINT	printfmtstrings(re->r_aliases, "  ", " ", \
    618 				"%-16s  %6d", \
    619 				re->r_name, re->r_number)
    620 
    621 	setrpcent(1);
    622 	rv = RV_OK;
    623 	if (argc == 2) {
    624 		while ((re = getrpcent()) != NULL)
    625 			RPCPRINT;
    626 	} else {
    627 		for (i = 2; i < argc; i++) {
    628 			if (parsenum(argv[i], &id))
    629 				re = getrpcbynumber((int)id);
    630 			else
    631 				re = getrpcbyname(argv[i]);
    632 			if (re != NULL)
    633 				RPCPRINT;
    634 			else {
    635 				rv = RV_NOTFOUND;
    636 				break;
    637 			}
    638 		}
    639 	}
    640 	endrpcent();
    641 	return rv;
    642 }
    643 
    644 		/*
    645 		 * services
    646 		 */
    647 
    648 static int
    649 services(int argc, char *argv[])
    650 {
    651 	struct servent	*se;
    652 	unsigned long	id;
    653 	char		*proto;
    654 	int		i, rv;
    655 
    656 	assert(argc > 1);
    657 	assert(argv != NULL);
    658 
    659 #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
    660 			    "%-16s  %5d/%s", \
    661 			    se->s_name, ntohs(se->s_port), se->s_proto)
    662 
    663 	setservent(1);
    664 	rv = RV_OK;
    665 	if (argc == 2) {
    666 		while ((se = getservent()) != NULL)
    667 			SERVICESPRINT;
    668 	} else {
    669 		for (i = 2; i < argc; i++) {
    670 			proto = strchr(argv[i], '/');
    671 			if (proto != NULL)
    672 				*proto++ = '\0';
    673 			if (parsenum(argv[i], &id))
    674 				se = getservbyport(htons(id), proto);
    675 			else
    676 				se = getservbyname(argv[i], proto);
    677 			if (se != NULL)
    678 				SERVICESPRINT;
    679 			else {
    680 				rv = RV_NOTFOUND;
    681 				break;
    682 			}
    683 		}
    684 	}
    685 	endservent();
    686 	return rv;
    687 }
    688 
    689 
    690 		/*
    691 		 * shells
    692 		 */
    693 
    694 static int
    695 shells(int argc, char *argv[])
    696 {
    697 	const char	*sh;
    698 	int		i, rv;
    699 
    700 	assert(argc > 1);
    701 	assert(argv != NULL);
    702 
    703 #define SHELLSPRINT	(void)printf("%s\n", sh)
    704 
    705 	setusershell();
    706 	rv = RV_OK;
    707 	if (argc == 2) {
    708 		while ((sh = getusershell()) != NULL)
    709 			SHELLSPRINT;
    710 	} else {
    711 		for (i = 2; i < argc; i++) {
    712 			setusershell();
    713 			while ((sh = getusershell()) != NULL) {
    714 				if (strcmp(sh, argv[i]) == 0) {
    715 					SHELLSPRINT;
    716 					break;
    717 				}
    718 			}
    719 			if (sh == NULL) {
    720 				rv = RV_NOTFOUND;
    721 				break;
    722 			}
    723 		}
    724 	}
    725 	endusershell();
    726 	return rv;
    727 }
    728