Home | History | Annotate | Line # | Download | only in getent
getent.c revision 1.5
      1 /*	$NetBSD: getent.c,v 1.5 2004/11/29 05:02:40 lukem Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2004 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.5 2004/11/29 05:02:40 lukem 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 <netinet/in.h>		/* for INET6_ADDRSTRLEN */
     63 
     64 static int	usage(void);
     65 static int	parsenum(const char *, unsigned long *);
     66 static int	group(int, char *[]);
     67 static int	hosts(int, char *[]);
     68 static int	networks(int, char *[]);
     69 static int	passwd(int, char *[]);
     70 static int	protocols(int, char *[]);
     71 static int	services(int, char *[]);
     72 static int	shells(int, char *[]);
     73 
     74 enum {
     75 	RV_OK		= 0,
     76 	RV_USAGE	= 1,
     77 	RV_NOTFOUND	= 2,
     78 	RV_NOENUM	= 3,
     79 };
     80 
     81 static struct getentdb {
     82 	const char	*name;
     83 	int		(*callback)(int, char *[]);
     84 } databases[] = {
     85 	{	"group",	group,		},
     86 	{	"hosts",	hosts,		},
     87 	{	"networks",	networks,	},
     88 	{	"passwd",	passwd,		},
     89 	{	"protocols",	protocols,	},
     90 	{	"services",	services,	},
     91 	{	"shells",	shells,		},
     92 
     93 	{	NULL,		NULL,		},
     94 };
     95 
     96 
     97 int
     98 main(int argc, char *argv[])
     99 {
    100 	struct getentdb	*curdb;
    101 
    102 	setprogname(argv[0]);
    103 
    104 	if (argc < 2)
    105 		usage();
    106 	for (curdb = databases; curdb->name != NULL; curdb++) {
    107 		if (strcmp(curdb->name, argv[1]) == 0) {
    108 			exit(curdb->callback(argc, argv));
    109 			break;
    110 		}
    111 	}
    112 	fprintf(stderr, "Unknown database: %s\n", argv[1]);
    113 	usage();
    114 	/* NOTREACHED */
    115 	return RV_USAGE;
    116 }
    117 
    118 static int
    119 usage(void)
    120 {
    121 	struct getentdb	*curdb;
    122 
    123 	fprintf(stderr, "Usage: %s database [key ...]\n",
    124 	    getprogname());
    125 	fprintf(stderr, "       database may be one of:\n\t");
    126 	for (curdb = databases; curdb->name != NULL; curdb++) {
    127 		fprintf(stderr, " %s", curdb->name);
    128 	}
    129 	fprintf(stderr, "\n");
    130 	exit(RV_USAGE);
    131 	/* NOTREACHED */
    132 }
    133 
    134 static int
    135 parsenum(const char *word, unsigned long *result)
    136 {
    137 	unsigned long	num;
    138 	char		*ep;
    139 
    140 	assert(word != NULL);
    141 	assert(result != NULL);
    142 
    143 	if (!isdigit((unsigned char)word[0]))
    144 		return 0;
    145 	errno = 0;
    146 	num = strtoul(word, &ep, 10);
    147 	if (num == ULONG_MAX && errno == ERANGE)
    148 		return 0;
    149 	if (*ep != '\0')
    150 		return 0;
    151 	*result = num;
    152 	return 1;
    153 }
    154 
    155 /*
    156  * printfmtstrings --
    157  *	vprintf(format, ...),
    158  *	then the aliases (beginning with prefix, separated by sep),
    159  *	then a newline
    160  */
    161 static void
    162 printfmtstrings(char *strings[], const char *prefix, const char *sep,
    163 	const char *fmt, ...)
    164 {
    165 	va_list		ap;
    166 	const char	*curpref;
    167 	int		i;
    168 
    169 	va_start(ap, fmt);
    170 	vprintf(fmt, ap);
    171 
    172 	curpref = prefix;
    173 	for (i = 0; strings[i] != NULL; i++) {
    174 		printf("%s%s", curpref, strings[i]);
    175 		curpref = sep;
    176 	}
    177 	printf("\n");
    178 }
    179 
    180 
    181 		/*
    182 		 * group
    183 		 */
    184 
    185 static int
    186 group(int argc, char *argv[])
    187 {
    188 	struct group	*gr;
    189 	unsigned long	id;
    190 	int		i, rv;
    191 
    192 	assert(argc > 1);
    193 	assert(argv != NULL);
    194 
    195 #define GROUPPRINT	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
    196 			    gr->gr_name, gr->gr_passwd, gr->gr_gid)
    197 
    198 	setgroupent(1);
    199 	rv = RV_OK;
    200 	if (argc == 2) {
    201 		while ((gr = getgrent()) != NULL)
    202 			GROUPPRINT;
    203 	} else {
    204 		for (i = 2; i < argc; i++) {
    205 			if (parsenum(argv[i], &id))
    206 				gr = getgrgid((gid_t)id);
    207 			else
    208 				gr = getgrnam(argv[i]);
    209 			if (gr != NULL)
    210 				GROUPPRINT;
    211 			else {
    212 				rv = RV_NOTFOUND;
    213 				break;
    214 			}
    215 		}
    216 	}
    217 	endgrent();
    218 	return rv;
    219 }
    220 
    221 
    222 		/*
    223 		 * hosts
    224 		 */
    225 
    226 static void
    227 hostsprint(const struct hostent *he)
    228 {
    229 	char	buf[INET6_ADDRSTRLEN];
    230 
    231 	assert(he != NULL);
    232 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
    233 		strlcpy(buf, "# unknown", sizeof(buf));
    234 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
    235 }
    236 
    237 static int
    238 hosts(int argc, char *argv[])
    239 {
    240 	struct hostent	*he;
    241 	char		addr[IN6ADDRSZ];
    242 	int		i, rv;
    243 
    244 	assert(argc > 1);
    245 	assert(argv != NULL);
    246 
    247 	sethostent(1);
    248 	rv = RV_OK;
    249 	if (argc == 2) {
    250 		while ((he = gethostent()) != NULL)
    251 			hostsprint(he);
    252 	} else {
    253 		for (i = 2; i < argc; i++) {
    254 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
    255 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
    256 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
    257 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
    258 			else
    259 				he = gethostbyname(argv[i]);
    260 			if (he != NULL)
    261 				hostsprint(he);
    262 			else {
    263 				rv = RV_NOTFOUND;
    264 				break;
    265 			}
    266 		}
    267 	}
    268 	endhostent();
    269 	return rv;
    270 }
    271 
    272 
    273 		/*
    274 		 * networks
    275 		 */
    276 
    277 static void
    278 networksprint(const struct netent *ne)
    279 {
    280 	char		buf[INET6_ADDRSTRLEN];
    281 	struct	in_addr	ianet;
    282 
    283 	assert(ne != NULL);
    284 	ianet = inet_makeaddr(ne->n_net, 0);
    285 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
    286 		strlcpy(buf, "# unknown", sizeof(buf));
    287 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
    288 }
    289 
    290 static int
    291 networks(int argc, char *argv[])
    292 {
    293 	struct netent	*ne;
    294 	in_addr_t	net;
    295 	int		i, rv;
    296 
    297 	assert(argc > 1);
    298 	assert(argv != NULL);
    299 
    300 	setnetent(1);
    301 	rv = RV_OK;
    302 	if (argc == 2) {
    303 		while ((ne = getnetent()) != NULL)
    304 			networksprint(ne);
    305 	} else {
    306 		for (i = 2; i < argc; i++) {
    307 			net = inet_network(argv[i]);
    308 			if (net != INADDR_NONE)
    309 				ne = getnetbyaddr(net, AF_INET);
    310 			else
    311 				ne = getnetbyname(argv[i]);
    312 			if (ne != NULL)
    313 				networksprint(ne);
    314 			else {
    315 				rv = RV_NOTFOUND;
    316 				break;
    317 			}
    318 		}
    319 	}
    320 	endnetent();
    321 	return rv;
    322 }
    323 
    324 
    325 		/*
    326 		 * passwd
    327 		 */
    328 
    329 static int
    330 passwd(int argc, char *argv[])
    331 {
    332 	struct passwd	*pw;
    333 	unsigned long	id;
    334 	int		i, rv;
    335 
    336 	assert(argc > 1);
    337 	assert(argv != NULL);
    338 
    339 #define PASSWDPRINT	printf("%s:%s:%u:%u:%s:%s:%s\n", \
    340 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
    341 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
    342 
    343 	setpassent(1);
    344 	rv = RV_OK;
    345 	if (argc == 2) {
    346 		while ((pw = getpwent()) != NULL)
    347 			PASSWDPRINT;
    348 	} else {
    349 		for (i = 2; i < argc; i++) {
    350 			if (parsenum(argv[i], &id))
    351 				pw = getpwuid((uid_t)id);
    352 			else
    353 				pw = getpwnam(argv[i]);
    354 			if (pw != NULL)
    355 				PASSWDPRINT;
    356 			else {
    357 				rv = RV_NOTFOUND;
    358 				break;
    359 			}
    360 		}
    361 	}
    362 	endpwent();
    363 	return rv;
    364 }
    365 
    366 
    367 		/*
    368 		 * protocols
    369 		 */
    370 
    371 static int
    372 protocols(int argc, char *argv[])
    373 {
    374 	struct protoent	*pe;
    375 	unsigned long	id;
    376 	int		i, rv;
    377 
    378 	assert(argc > 1);
    379 	assert(argv != NULL);
    380 
    381 #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
    382 			    "%-16s  %5d", pe->p_name, pe->p_proto)
    383 
    384 	setprotoent(1);
    385 	rv = RV_OK;
    386 	if (argc == 2) {
    387 		while ((pe = getprotoent()) != NULL)
    388 			PROTOCOLSPRINT;
    389 	} else {
    390 		for (i = 2; i < argc; i++) {
    391 			if (parsenum(argv[i], &id))
    392 				pe = getprotobynumber((int)id);
    393 			else
    394 				pe = getprotobyname(argv[i]);
    395 			if (pe != NULL)
    396 				PROTOCOLSPRINT;
    397 			else {
    398 				rv = RV_NOTFOUND;
    399 				break;
    400 			}
    401 		}
    402 	}
    403 	endprotoent();
    404 	return rv;
    405 }
    406 
    407 
    408 		/*
    409 		 * services
    410 		 */
    411 
    412 static int
    413 services(int argc, char *argv[])
    414 {
    415 	struct servent	*se;
    416 	unsigned long	id;
    417 	char		*proto;
    418 	int		i, rv;
    419 
    420 	assert(argc > 1);
    421 	assert(argv != NULL);
    422 
    423 #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
    424 			    "%-16s  %5d/%s", \
    425 			    se->s_name, ntohs(se->s_port), se->s_proto)
    426 
    427 	setservent(1);
    428 	rv = RV_OK;
    429 	if (argc == 2) {
    430 		while ((se = getservent()) != NULL)
    431 			SERVICESPRINT;
    432 	} else {
    433 		for (i = 2; i < argc; i++) {
    434 			proto = strchr(argv[i], '/');
    435 			if (proto != NULL)
    436 				*proto++ = '\0';
    437 			if (parsenum(argv[i], &id))
    438 				se = getservbyport((int)id, proto);
    439 			else
    440 				se = getservbyname(argv[i], proto);
    441 			if (se != NULL)
    442 				SERVICESPRINT;
    443 			else {
    444 				rv = RV_NOTFOUND;
    445 				break;
    446 			}
    447 		}
    448 	}
    449 	endservent();
    450 	return rv;
    451 }
    452 
    453 
    454 		/*
    455 		 * shells
    456 		 */
    457 
    458 static int
    459 shells(int argc, char *argv[])
    460 {
    461 	const char	*sh;
    462 	int		i, rv;
    463 
    464 	assert(argc > 1);
    465 	assert(argv != NULL);
    466 
    467 #define SHELLSPRINT	printf("%s\n", sh)
    468 
    469 	setusershell();
    470 	rv = RV_OK;
    471 	if (argc == 2) {
    472 		while ((sh = getusershell()) != NULL)
    473 			SHELLSPRINT;
    474 	} else {
    475 		for (i = 2; i < argc; i++) {
    476 			setusershell();
    477 			while ((sh = getusershell()) != NULL) {
    478 				if (strcmp(sh, argv[i]) == 0) {
    479 					SHELLSPRINT;
    480 					break;
    481 				}
    482 			}
    483 			if (sh == NULL) {
    484 				rv = RV_NOTFOUND;
    485 				break;
    486 			}
    487 		}
    488 	}
    489 	endusershell();
    490 	return rv;
    491 }
    492