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 #ifndef lint 41 __RCSID("$NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach 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((gid_t)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((uid_t)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((int)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((int)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((int)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