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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/socket.h> 36 #include <sys/param.h> 37 #include <arpa/inet.h> 38 #include <arpa/nameser.h> 39 #include <net/if.h> 40 #include <netinet/if_ether.h> 41 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */ 42 #include <rpc/rpcent.h> 43 44 #include <assert.h> 45 #include <ctype.h> 46 #include <errno.h> 47 #include <grp.h> 48 #include <limits.h> 49 #include <netdb.h> 50 #include <pwd.h> 51 #include <stdarg.h> 52 #include <stdint.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <utmpx.h> 58 59 static int usage(void); 60 static int parsenum(const char *, unsigned long *); 61 static int ethers(int, char *[]); 62 static int group(int, char *[]); 63 static int hosts(int, char *[]); 64 static int networks(int, char *[]); 65 static int passwd(int, char *[]); 66 static int protocols(int, char *[]); 67 static int rpc(int, char *[]); 68 static int services(int, char *[]); 69 static int shells(int, char *[]); 70 static int utmpx(int, char *[]); 71 72 enum { 73 RV_OK = 0, 74 RV_USAGE = 1, 75 RV_NOTFOUND = 2, 76 RV_NOENUM = 3 77 }; 78 79 static struct getentdb { 80 const char *name; 81 int (*callback)(int, char *[]); 82 } databases[] = { 83 { "ethers", ethers, }, 84 { "group", group, }, 85 { "hosts", hosts, }, 86 { "networks", networks, }, 87 { "passwd", passwd, }, 88 { "protocols", protocols, }, 89 { "rpc", rpc, }, 90 { "services", services, }, 91 { "shells", shells, }, 92 { "utmpx", utmpx, }, 93 94 { NULL, NULL, }, 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 } 110 } 111 fprintf(stderr, "Unknown database: %s\n", argv[1]); 112 usage(); 113 /* NOTREACHED */ 114 return RV_USAGE; 115 } 116 117 static int 118 usage(void) 119 { 120 struct getentdb *curdb; 121 122 fprintf(stderr, "Usage: %s database [key ...]\n", 123 getprogname()); 124 fprintf(stderr, " database may be one of:\n\t"); 125 for (curdb = databases; curdb->name != NULL; curdb++) { 126 fprintf(stderr, " %s", curdb->name); 127 } 128 fprintf(stderr, "\n"); 129 exit(RV_USAGE); 130 /* NOTREACHED */ 131 } 132 133 static int 134 parsenum(const char *word, unsigned long *result) 135 { 136 unsigned long num; 137 char *ep; 138 139 assert(word != NULL); 140 assert(result != NULL); 141 142 if (!isdigit((unsigned char)word[0])) 143 return 0; 144 errno = 0; 145 num = strtoul(word, &ep, 10); 146 if (num == ULONG_MAX && errno == ERANGE) 147 return 0; 148 if (*ep != '\0') 149 return 0; 150 *result = num; 151 return 1; 152 } 153 154 /* 155 * printfmtstrings -- 156 * vprintf(format, ...), 157 * then the aliases (beginning with prefix, separated by sep), 158 * then a newline 159 */ 160 static void 161 printfmtstrings(char *strings[], const char *prefix, const char *sep, 162 const char *fmt, ...) 163 { 164 va_list ap; 165 const char *curpref; 166 int i; 167 168 va_start(ap, fmt); 169 vprintf(fmt, ap); 170 171 curpref = prefix; 172 for (i = 0; strings[i] != NULL; i++) { 173 printf("%s%s", curpref, strings[i]); 174 curpref = sep; 175 } 176 printf("\n"); 177 va_end(ap); 178 } 179 180 /* 181 * ethers 182 */ 183 static int 184 ethers(int argc, char *argv[]) 185 { 186 char hostname[MAXHOSTNAMELEN + 1], *hp; 187 struct ether_addr ea, *eap; 188 int i, rv; 189 190 assert(argc > 1); 191 assert(argv != NULL); 192 193 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp) 194 195 rv = RV_OK; 196 if (argc == 2) { 197 fprintf(stderr, "Enumeration not supported on ethers\n"); 198 rv = RV_NOENUM; 199 } else { 200 for (i = 2; i < argc; i++) { 201 if ((eap = ether_aton(argv[i])) == NULL) { 202 eap = &ea; 203 hp = argv[i]; 204 if (ether_hostton(hp, eap) != 0) { 205 rv = RV_NOTFOUND; 206 break; 207 } 208 } else { 209 hp = hostname; 210 if (ether_ntohost(hp, eap) != 0) { 211 rv = RV_NOTFOUND; 212 break; 213 } 214 } 215 ETHERSPRINT; 216 } 217 } 218 return rv; 219 } 220 221 /* 222 * group 223 */ 224 225 static int 226 group(int argc, char *argv[]) 227 { 228 struct group *gr; 229 unsigned long id; 230 int i, rv; 231 232 assert(argc > 1); 233 assert(argv != NULL); 234 235 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ 236 gr->gr_name, gr->gr_passwd, gr->gr_gid) 237 238 setgroupent(1); 239 rv = RV_OK; 240 if (argc == 2) { 241 while ((gr = getgrent()) != NULL) 242 GROUPPRINT; 243 } else { 244 for (i = 2; i < argc; i++) { 245 if (parsenum(argv[i], &id)) 246 gr = getgrgid((gid_t)id); 247 else 248 gr = getgrnam(argv[i]); 249 if (gr != NULL) 250 GROUPPRINT; 251 else { 252 rv = RV_NOTFOUND; 253 break; 254 } 255 } 256 } 257 endgrent(); 258 return rv; 259 } 260 261 262 /* 263 * hosts 264 */ 265 266 static void 267 hostsprint(const struct hostent *he) 268 { 269 char buf[INET6_ADDRSTRLEN]; 270 271 assert(he != NULL); 272 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) 273 strlcpy(buf, "# unknown", sizeof(buf)); 274 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); 275 } 276 277 static int 278 hosts(int argc, char *argv[]) 279 { 280 struct hostent *he4, *he6; 281 char addr[IN6ADDRSZ]; 282 int i, rv; 283 284 assert(argc > 1); 285 assert(argv != NULL); 286 287 sethostent(1); 288 he4 = he6 = NULL; 289 rv = RV_OK; 290 if (argc == 2) { 291 while ((he4 = gethostent()) != NULL) 292 hostsprint(he4); 293 } else { 294 for (i = 2; i < argc; i++) { 295 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) { 296 he6 = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); 297 if (he6 != NULL) 298 hostsprint(he6); 299 } else if (inet_pton(AF_INET, argv[i], 300 (void *)addr) > 0) { 301 he4 = gethostbyaddr(addr, INADDRSZ, AF_INET); 302 if (he4 != NULL) 303 hostsprint(he4); 304 } else { 305 he6 = gethostbyname2(argv[i], AF_INET6); 306 if (he6 != NULL) 307 hostsprint(he6); 308 he4 = gethostbyname(argv[i]); 309 if (he4 != NULL) 310 hostsprint(he4); 311 } 312 if ( he4 == NULL && he6 == NULL ) { 313 rv = RV_NOTFOUND; 314 break; 315 } 316 } 317 } 318 endhostent(); 319 return rv; 320 } 321 322 /* 323 * networks 324 */ 325 static void 326 networksprint(const struct netent *ne) 327 { 328 char buf[INET6_ADDRSTRLEN]; 329 struct in_addr ianet; 330 331 assert(ne != NULL); 332 ianet = inet_makeaddr(ne->n_net, 0); 333 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL) 334 strlcpy(buf, "# unknown", sizeof(buf)); 335 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf); 336 } 337 338 static int 339 networks(int argc, char *argv[]) 340 { 341 struct netent *ne; 342 in_addr_t net; 343 int i, rv; 344 345 assert(argc > 1); 346 assert(argv != NULL); 347 348 setnetent(1); 349 rv = RV_OK; 350 if (argc == 2) { 351 while ((ne = getnetent()) != NULL) 352 networksprint(ne); 353 } else { 354 for (i = 2; i < argc; i++) { 355 net = inet_network(argv[i]); 356 if (net != INADDR_NONE) 357 ne = getnetbyaddr(net, AF_INET); 358 else 359 ne = getnetbyname(argv[i]); 360 if (ne != NULL) 361 networksprint(ne); 362 else { 363 rv = RV_NOTFOUND; 364 break; 365 } 366 } 367 } 368 endnetent(); 369 return rv; 370 } 371 372 /* 373 * passwd 374 */ 375 static int 376 passwd(int argc, char *argv[]) 377 { 378 struct passwd *pw; 379 unsigned long id; 380 int i, rv; 381 382 assert(argc > 1); 383 assert(argv != NULL); 384 385 #define PASSWDPRINT printf("%s:%s:%u:%u:%s:%s:%s\n", \ 386 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 387 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 388 389 setpassent(1); 390 rv = RV_OK; 391 if (argc == 2) { 392 while ((pw = getpwent()) != NULL) 393 PASSWDPRINT; 394 } else { 395 for (i = 2; i < argc; i++) { 396 if (parsenum(argv[i], &id)) 397 pw = getpwuid((uid_t)id); 398 else 399 pw = getpwnam(argv[i]); 400 if (pw != NULL) 401 PASSWDPRINT; 402 else { 403 rv = RV_NOTFOUND; 404 break; 405 } 406 } 407 } 408 endpwent(); 409 return rv; 410 } 411 412 /* 413 * protocols 414 */ 415 static int 416 protocols(int argc, char *argv[]) 417 { 418 struct protoent *pe; 419 unsigned long id; 420 int i, rv; 421 422 assert(argc > 1); 423 assert(argv != NULL); 424 425 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \ 426 "%-16s %5d", pe->p_name, pe->p_proto) 427 428 setprotoent(1); 429 rv = RV_OK; 430 if (argc == 2) { 431 while ((pe = getprotoent()) != NULL) 432 PROTOCOLSPRINT; 433 } else { 434 for (i = 2; i < argc; i++) { 435 if (parsenum(argv[i], &id)) 436 pe = getprotobynumber((int)id); 437 else 438 pe = getprotobyname(argv[i]); 439 if (pe != NULL) 440 PROTOCOLSPRINT; 441 else { 442 rv = RV_NOTFOUND; 443 break; 444 } 445 } 446 } 447 endprotoent(); 448 return rv; 449 } 450 451 /* 452 * rpc 453 */ 454 static int 455 rpc(int argc, char *argv[]) 456 { 457 struct rpcent *re; 458 unsigned long id; 459 int i, rv; 460 461 assert(argc > 1); 462 assert(argv != NULL); 463 464 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \ 465 "%-16s %6d", \ 466 re->r_name, re->r_number) 467 468 setrpcent(1); 469 rv = RV_OK; 470 if (argc == 2) { 471 while ((re = getrpcent()) != NULL) 472 RPCPRINT; 473 } else { 474 for (i = 2; i < argc; i++) { 475 if (parsenum(argv[i], &id)) 476 re = getrpcbynumber((int)id); 477 else 478 re = getrpcbyname(argv[i]); 479 if (re != NULL) 480 RPCPRINT; 481 else { 482 rv = RV_NOTFOUND; 483 break; 484 } 485 } 486 } 487 endrpcent(); 488 return rv; 489 } 490 491 /* 492 * services 493 */ 494 static int 495 services(int argc, char *argv[]) 496 { 497 struct servent *se; 498 unsigned long id; 499 char *proto; 500 int i, rv; 501 502 assert(argc > 1); 503 assert(argv != NULL); 504 505 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \ 506 "%-16s %5d/%s", \ 507 se->s_name, ntohs(se->s_port), se->s_proto) 508 509 setservent(1); 510 rv = RV_OK; 511 if (argc == 2) { 512 while ((se = getservent()) != NULL) 513 SERVICESPRINT; 514 } else { 515 for (i = 2; i < argc; i++) { 516 proto = strchr(argv[i], '/'); 517 if (proto != NULL) 518 *proto++ = '\0'; 519 if (parsenum(argv[i], &id)) 520 se = getservbyport(htons((u_short)id), proto); 521 else 522 se = getservbyname(argv[i], proto); 523 if (se != NULL) 524 SERVICESPRINT; 525 else { 526 rv = RV_NOTFOUND; 527 break; 528 } 529 } 530 } 531 endservent(); 532 return rv; 533 } 534 535 /* 536 * shells 537 */ 538 static int 539 shells(int argc, char *argv[]) 540 { 541 const char *sh; 542 int i, rv; 543 544 assert(argc > 1); 545 assert(argv != NULL); 546 547 #define SHELLSPRINT printf("%s\n", sh) 548 549 setusershell(); 550 rv = RV_OK; 551 if (argc == 2) { 552 while ((sh = getusershell()) != NULL) 553 SHELLSPRINT; 554 } else { 555 for (i = 2; i < argc; i++) { 556 setusershell(); 557 while ((sh = getusershell()) != NULL) { 558 if (strcmp(sh, argv[i]) == 0) { 559 SHELLSPRINT; 560 break; 561 } 562 } 563 if (sh == NULL) { 564 rv = RV_NOTFOUND; 565 break; 566 } 567 } 568 } 569 endusershell(); 570 return rv; 571 } 572 573 /* 574 * utmpx 575 */ 576 577 #define UTMPXPRINTID do { \ 578 size_t i; \ 579 for (i = 0; i < sizeof ut->ut_id; i++) \ 580 printf("%02hhx", ut->ut_id[i]); \ 581 } while (0) 582 583 static void 584 utmpxprint(const struct utmpx *ut) 585 { 586 587 if (ut->ut_type == EMPTY) 588 return; 589 590 printf("[%jd.%06u -- %.24s] ", 591 (intmax_t)ut->ut_tv.tv_sec, (unsigned int)ut->ut_tv.tv_usec, 592 ctime(&ut->ut_tv.tv_sec)); 593 594 switch (ut->ut_type) { 595 case BOOT_TIME: 596 printf("system boot\n"); 597 return; 598 case SHUTDOWN_TIME: 599 printf("system shutdown\n"); 600 return; 601 case OLD_TIME: 602 printf("old system time\n"); 603 return; 604 case NEW_TIME: 605 printf("new system time\n"); 606 return; 607 case USER_PROCESS: 608 printf("user process: id=\""); 609 UTMPXPRINTID; 610 printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n", 611 ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host); 612 break; 613 case INIT_PROCESS: 614 printf("init process: id=\""); 615 UTMPXPRINTID; 616 printf("\" pid=\"%d\"\n", ut->ut_pid); 617 break; 618 case LOGIN_PROCESS: 619 printf("login process: id=\""); 620 UTMPXPRINTID; 621 printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n", 622 ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host); 623 break; 624 case DEAD_PROCESS: 625 printf("dead process: id=\""); 626 UTMPXPRINTID; 627 printf("\" pid=\"%d\"\n", ut->ut_pid); 628 break; 629 default: 630 printf("unknown record type %hu\n", ut->ut_type); 631 break; 632 } 633 } 634 635 static int 636 utmpx(int argc, char *argv[]) 637 { 638 const struct utmpx *ut; 639 const char *file = NULL; 640 int rv = RV_OK, db = 0; 641 642 assert(argc > 1); 643 assert(argv != NULL); 644 645 if (argc == 3 || argc == 4) { 646 if (strcmp(argv[2], "active") == 0) 647 db = UTXDB_ACTIVE; 648 else if (strcmp(argv[2], "lastlogin") == 0) 649 db = UTXDB_LASTLOGIN; 650 else if (strcmp(argv[2], "log") == 0) 651 db = UTXDB_LOG; 652 else 653 rv = RV_USAGE; 654 if (argc == 4) 655 file = argv[3]; 656 } else { 657 rv = RV_USAGE; 658 } 659 660 if (rv == RV_USAGE) { 661 fprintf(stderr, 662 "Usage: %s utmpx active | lastlogin | log [filename]\n", 663 getprogname()); 664 } else if (rv == RV_OK) { 665 if (setutxdb(db, file) != 0) 666 return (RV_NOTFOUND); 667 while ((ut = getutxent()) != NULL) 668 utmpxprint(ut); 669 endutxent(); 670 } 671 return (rv); 672 } 673