1 /* $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach 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 __FBSDID("$FreeBSD$"); 41 42 #include <sys/socket.h> 43 #include <sys/param.h> 44 #include <arpa/inet.h> 45 #include <arpa/nameser.h> 46 #include <net/if.h> 47 #include <netinet/if_ether.h> 48 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */ 49 #include <rpc/rpcent.h> 50 51 #include <assert.h> 52 #include <ctype.h> 53 #include <errno.h> 54 #include <grp.h> 55 #include <limits.h> 56 #include <netdb.h> 57 #include <pwd.h> 58 #include <stdio.h> 59 #include <stdarg.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 static int usage(void); 65 static int parsenum(const char *, unsigned long *); 66 static int ethers(int, char *[]); 67 static int group(int, char *[]); 68 static int hosts(int, char *[]); 69 static int networks(int, char *[]); 70 static int passwd(int, char *[]); 71 static int protocols(int, char *[]); 72 static int rpc(int, char *[]); 73 static int services(int, char *[]); 74 static int shells(int, char *[]); 75 76 enum { 77 RV_OK = 0, 78 RV_USAGE = 1, 79 RV_NOTFOUND = 2, 80 RV_NOENUM = 3 81 }; 82 83 static struct getentdb { 84 const char *name; 85 int (*callback)(int, char *[]); 86 } databases[] = { 87 { "ethers", ethers, }, 88 { "group", group, }, 89 { "hosts", hosts, }, 90 { "networks", networks, }, 91 { "passwd", passwd, }, 92 { "protocols", protocols, }, 93 { "rpc", rpc, }, 94 { "services", services, }, 95 { "shells", shells, }, 96 97 { NULL, NULL, }, 98 }; 99 100 int 101 main(int argc, char *argv[]) 102 { 103 struct getentdb *curdb; 104 105 setprogname(argv[0]); 106 107 if (argc < 2) 108 usage(); 109 for (curdb = databases; curdb->name != NULL; curdb++) { 110 if (strcmp(curdb->name, argv[1]) == 0) { 111 exit(curdb->callback(argc, argv)); 112 } 113 } 114 fprintf(stderr, "Unknown database: %s\n", argv[1]); 115 usage(); 116 /* NOTREACHED */ 117 return RV_USAGE; 118 } 119 120 static int 121 usage(void) 122 { 123 struct getentdb *curdb; 124 125 fprintf(stderr, "Usage: %s database [key ...]\n", 126 getprogname()); 127 fprintf(stderr, " database may be one of:\n\t"); 128 for (curdb = databases; curdb->name != NULL; curdb++) { 129 fprintf(stderr, " %s", curdb->name); 130 } 131 fprintf(stderr, "\n"); 132 exit(RV_USAGE); 133 /* NOTREACHED */ 134 } 135 136 static int 137 parsenum(const char *word, unsigned long *result) 138 { 139 unsigned long num; 140 char *ep; 141 142 assert(word != NULL); 143 assert(result != NULL); 144 145 if (!isdigit((unsigned char)word[0])) 146 return 0; 147 errno = 0; 148 num = strtoul(word, &ep, 10); 149 if (num == ULONG_MAX && errno == ERANGE) 150 return 0; 151 if (*ep != '\0') 152 return 0; 153 *result = num; 154 return 1; 155 } 156 157 /* 158 * printfmtstrings -- 159 * vprintf(format, ...), 160 * then the aliases (beginning with prefix, separated by sep), 161 * then a newline 162 */ 163 static void 164 printfmtstrings(char *strings[], const char *prefix, const char *sep, 165 const char *fmt, ...) 166 { 167 va_list ap; 168 const char *curpref; 169 int i; 170 171 va_start(ap, fmt); 172 vprintf(fmt, ap); 173 174 curpref = prefix; 175 for (i = 0; strings[i] != NULL; i++) { 176 printf("%s%s", curpref, strings[i]); 177 curpref = sep; 178 } 179 printf("\n"); 180 va_end(ap); 181 } 182 183 /* 184 * ethers 185 */ 186 static int 187 ethers(int argc, char *argv[]) 188 { 189 char hostname[MAXHOSTNAMELEN + 1], *hp; 190 struct ether_addr ea, *eap; 191 int i, rv; 192 193 assert(argc > 1); 194 assert(argv != NULL); 195 196 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp) 197 198 rv = RV_OK; 199 if (argc == 2) { 200 fprintf(stderr, "Enumeration not supported on ethers\n"); 201 rv = RV_NOENUM; 202 } else { 203 for (i = 2; i < argc; i++) { 204 if ((eap = ether_aton(argv[i])) == NULL) { 205 eap = &ea; 206 hp = argv[i]; 207 if (ether_hostton(hp, eap) != 0) { 208 rv = RV_NOTFOUND; 209 break; 210 } 211 } else { 212 hp = hostname; 213 if (ether_ntohost(hp, eap) != 0) { 214 rv = RV_NOTFOUND; 215 break; 216 } 217 } 218 ETHERSPRINT; 219 } 220 } 221 return rv; 222 } 223 224 /* 225 * group 226 */ 227 228 static int 229 group(int argc, char *argv[]) 230 { 231 struct group *gr; 232 unsigned long id; 233 int i, rv; 234 235 assert(argc > 1); 236 assert(argv != NULL); 237 238 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ 239 gr->gr_name, gr->gr_passwd, gr->gr_gid) 240 241 setgroupent(1); 242 rv = RV_OK; 243 if (argc == 2) { 244 while ((gr = getgrent()) != NULL) 245 GROUPPRINT; 246 } else { 247 for (i = 2; i < argc; i++) { 248 if (parsenum(argv[i], &id)) 249 gr = getgrgid((gid_t)id); 250 else 251 gr = getgrnam(argv[i]); 252 if (gr != NULL) 253 GROUPPRINT; 254 else { 255 rv = RV_NOTFOUND; 256 break; 257 } 258 } 259 } 260 endgrent(); 261 return rv; 262 } 263 264 265 /* 266 * hosts 267 */ 268 269 static void 270 hostsprint(const struct hostent *he) 271 { 272 char buf[INET6_ADDRSTRLEN]; 273 274 assert(he != NULL); 275 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) 276 strlcpy(buf, "# unknown", sizeof(buf)); 277 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); 278 } 279 280 static int 281 hosts(int argc, char *argv[]) 282 { 283 struct hostent *he; 284 char addr[IN6ADDRSZ]; 285 int i, rv; 286 287 assert(argc > 1); 288 assert(argv != NULL); 289 290 sethostent(1); 291 rv = RV_OK; 292 if (argc == 2) { 293 while ((he = gethostent()) != NULL) 294 hostsprint(he); 295 } else { 296 for (i = 2; i < argc; i++) { 297 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) 298 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); 299 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) 300 he = gethostbyaddr(addr, INADDRSZ, AF_INET); 301 else 302 he = gethostbyname(argv[i]); 303 if (he != NULL) 304 hostsprint(he); 305 else { 306 rv = RV_NOTFOUND; 307 break; 308 } 309 } 310 } 311 endhostent(); 312 return rv; 313 } 314 315 /* 316 * networks 317 */ 318 static void 319 networksprint(const struct netent *ne) 320 { 321 char buf[INET6_ADDRSTRLEN]; 322 struct in_addr ianet; 323 324 assert(ne != NULL); 325 ianet = inet_makeaddr(ne->n_net, 0); 326 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL) 327 strlcpy(buf, "# unknown", sizeof(buf)); 328 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf); 329 } 330 331 static int 332 networks(int argc, char *argv[]) 333 { 334 struct netent *ne; 335 in_addr_t net; 336 int i, rv; 337 338 assert(argc > 1); 339 assert(argv != NULL); 340 341 setnetent(1); 342 rv = RV_OK; 343 if (argc == 2) { 344 while ((ne = getnetent()) != NULL) 345 networksprint(ne); 346 } else { 347 for (i = 2; i < argc; i++) { 348 net = inet_network(argv[i]); 349 if (net != INADDR_NONE) 350 ne = getnetbyaddr(net, AF_INET); 351 else 352 ne = getnetbyname(argv[i]); 353 if (ne != NULL) 354 networksprint(ne); 355 else { 356 rv = RV_NOTFOUND; 357 break; 358 } 359 } 360 } 361 endnetent(); 362 return rv; 363 } 364 365 /* 366 * passwd 367 */ 368 static int 369 passwd(int argc, char *argv[]) 370 { 371 struct passwd *pw; 372 unsigned long id; 373 int i, rv; 374 375 assert(argc > 1); 376 assert(argv != NULL); 377 378 #define PASSWDPRINT printf("%s:%s:%u:%u:%s:%s:%s\n", \ 379 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 380 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 381 382 setpassent(1); 383 rv = RV_OK; 384 if (argc == 2) { 385 while ((pw = getpwent()) != NULL) 386 PASSWDPRINT; 387 } else { 388 for (i = 2; i < argc; i++) { 389 if (parsenum(argv[i], &id)) 390 pw = getpwuid((uid_t)id); 391 else 392 pw = getpwnam(argv[i]); 393 if (pw != NULL) 394 PASSWDPRINT; 395 else { 396 rv = RV_NOTFOUND; 397 break; 398 } 399 } 400 } 401 endpwent(); 402 return rv; 403 } 404 405 /* 406 * protocols 407 */ 408 static int 409 protocols(int argc, char *argv[]) 410 { 411 struct protoent *pe; 412 unsigned long id; 413 int i, rv; 414 415 assert(argc > 1); 416 assert(argv != NULL); 417 418 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \ 419 "%-16s %5d", pe->p_name, pe->p_proto) 420 421 setprotoent(1); 422 rv = RV_OK; 423 if (argc == 2) { 424 while ((pe = getprotoent()) != NULL) 425 PROTOCOLSPRINT; 426 } else { 427 for (i = 2; i < argc; i++) { 428 if (parsenum(argv[i], &id)) 429 pe = getprotobynumber((int)id); 430 else 431 pe = getprotobyname(argv[i]); 432 if (pe != NULL) 433 PROTOCOLSPRINT; 434 else { 435 rv = RV_NOTFOUND; 436 break; 437 } 438 } 439 } 440 endprotoent(); 441 return rv; 442 } 443 444 /* 445 * rpc 446 */ 447 static int 448 rpc(int argc, char *argv[]) 449 { 450 struct rpcent *re; 451 unsigned long id; 452 int i, rv; 453 454 assert(argc > 1); 455 assert(argv != NULL); 456 457 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \ 458 "%-16s %6d", \ 459 re->r_name, re->r_number) 460 461 setrpcent(1); 462 rv = RV_OK; 463 if (argc == 2) { 464 while ((re = getrpcent()) != NULL) 465 RPCPRINT; 466 } else { 467 for (i = 2; i < argc; i++) { 468 if (parsenum(argv[i], &id)) 469 re = getrpcbynumber((int)id); 470 else 471 re = getrpcbyname(argv[i]); 472 if (re != NULL) 473 RPCPRINT; 474 else { 475 rv = RV_NOTFOUND; 476 break; 477 } 478 } 479 } 480 endrpcent(); 481 return rv; 482 } 483 484 /* 485 * services 486 */ 487 static int 488 services(int argc, char *argv[]) 489 { 490 struct servent *se; 491 unsigned long id; 492 char *proto; 493 int i, rv; 494 495 assert(argc > 1); 496 assert(argv != NULL); 497 498 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \ 499 "%-16s %5d/%s", \ 500 se->s_name, ntohs(se->s_port), se->s_proto) 501 502 setservent(1); 503 rv = RV_OK; 504 if (argc == 2) { 505 while ((se = getservent()) != NULL) 506 SERVICESPRINT; 507 } else { 508 for (i = 2; i < argc; i++) { 509 proto = strchr(argv[i], '/'); 510 if (proto != NULL) 511 *proto++ = '\0'; 512 if (parsenum(argv[i], &id)) 513 se = getservbyport(htons((u_short)id), proto); 514 else 515 se = getservbyname(argv[i], proto); 516 if (se != NULL) 517 SERVICESPRINT; 518 else { 519 rv = RV_NOTFOUND; 520 break; 521 } 522 } 523 } 524 endservent(); 525 return rv; 526 } 527 528 /* 529 * shells 530 */ 531 static int 532 shells(int argc, char *argv[]) 533 { 534 const char *sh; 535 int i, rv; 536 537 assert(argc > 1); 538 assert(argv != NULL); 539 540 #define SHELLSPRINT printf("%s\n", sh) 541 542 setusershell(); 543 rv = RV_OK; 544 if (argc == 2) { 545 while ((sh = getusershell()) != NULL) 546 SHELLSPRINT; 547 } else { 548 for (i = 2; i < argc; i++) { 549 setusershell(); 550 while ((sh = getusershell()) != NULL) { 551 if (strcmp(sh, argv[i]) == 0) { 552 SHELLSPRINT; 553 break; 554 } 555 } 556 if (sh == NULL) { 557 rv = RV_NOTFOUND; 558 break; 559 } 560 } 561 } 562 endusershell(); 563 return rv; 564 } 565