1 /*- 2 * Copyright (c) 2004 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Luke Mewburn. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the NetBSD 19 * Foundation, Inc. and its contributors. 20 * 4. Neither the name of The NetBSD Foundation nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 * 36 * $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $ 37 * $DragonFly: src/usr.bin/getent/getent.c,v 1.1 2007/12/04 18:13:09 dillon Exp $ 38 */ 39 40 #include <sys/socket.h> 41 #include <sys/param.h> 42 #include <arpa/inet.h> 43 #include <arpa/nameser.h> 44 #include <net/if.h> 45 #include <netinet/if_ether.h> 46 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */ 47 #include <rpc/rpc.h> 48 49 #include <assert.h> 50 #include <ctype.h> 51 #include <errno.h> 52 #include <grp.h> 53 #include <limits.h> 54 #include <netdb.h> 55 #include <pwd.h> 56 #include <stdio.h> 57 #include <stdarg.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 static int usage(void); 63 static int parsenum(const char *, unsigned long *); 64 static int ethers(int, char *[]); 65 static int group(int, char *[]); 66 static int hosts(int, char *[]); 67 static int networks(int, char *[]); 68 static int passwd(int, char *[]); 69 static int protocols(int, char *[]); 70 static int rpc(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 { "ethers", ethers, }, 86 { "group", group, }, 87 { "hosts", hosts, }, 88 { "networks", networks, }, 89 { "passwd", passwd, }, 90 { "protocols", protocols, }, 91 { "rpc", rpc, }, 92 { "services", services, }, 93 { "shells", shells, }, 94 95 { NULL, NULL, }, 96 }; 97 98 int 99 main(int argc, char *argv[]) 100 { 101 struct getentdb *curdb; 102 103 setprogname(argv[0]); 104 105 if (argc < 2) 106 usage(); 107 for (curdb = databases; curdb->name != NULL; curdb++) { 108 if (strcmp(curdb->name, argv[1]) == 0) { 109 exit(curdb->callback(argc, argv)); 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 va_end(ap); 179 } 180 181 /* 182 * ethers 183 */ 184 static int 185 ethers(int argc, char *argv[]) 186 { 187 char hostname[MAXHOSTNAMELEN + 1], *hp; 188 struct ether_addr ea, *eap; 189 int i, rv; 190 191 assert(argc > 1); 192 assert(argv != NULL); 193 194 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp) 195 196 rv = RV_OK; 197 if (argc == 2) { 198 fprintf(stderr, "Enumeration not supported on ethers\n"); 199 rv = RV_NOENUM; 200 } else { 201 for (i = 2; i < argc; i++) { 202 if ((eap = ether_aton(argv[i])) == NULL) { 203 eap = &ea; 204 hp = argv[i]; 205 if (ether_hostton(hp, eap) != 0) { 206 rv = RV_NOTFOUND; 207 break; 208 } 209 } else { 210 hp = hostname; 211 if (ether_ntohost(hp, eap) != 0) { 212 rv = RV_NOTFOUND; 213 break; 214 } 215 } 216 ETHERSPRINT; 217 } 218 } 219 return rv; 220 } 221 222 /* 223 * group 224 */ 225 226 static int 227 group(int argc, char *argv[]) 228 { 229 struct group *gr; 230 unsigned long id; 231 int i, rv; 232 233 assert(argc > 1); 234 assert(argv != NULL); 235 236 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ 237 gr->gr_name, gr->gr_passwd, gr->gr_gid) 238 239 setgroupent(1); 240 rv = RV_OK; 241 if (argc == 2) { 242 while ((gr = getgrent()) != NULL) 243 GROUPPRINT; 244 } else { 245 for (i = 2; i < argc; i++) { 246 if (parsenum(argv[i], &id)) 247 gr = getgrgid((gid_t)id); 248 else 249 gr = getgrnam(argv[i]); 250 if (gr != NULL) 251 GROUPPRINT; 252 else { 253 rv = RV_NOTFOUND; 254 break; 255 } 256 } 257 } 258 endgrent(); 259 return rv; 260 } 261 262 263 /* 264 * hosts 265 */ 266 267 static void 268 hostsprint(const struct hostent *he) 269 { 270 char buf[INET6_ADDRSTRLEN]; 271 272 assert(he != NULL); 273 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) 274 strlcpy(buf, "# unknown", sizeof(buf)); 275 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); 276 } 277 278 static int 279 hosts(int argc, char *argv[]) 280 { 281 struct hostent *he; 282 char addr[IN6ADDRSZ]; 283 int i, rv; 284 285 assert(argc > 1); 286 assert(argv != NULL); 287 288 sethostent(1); 289 rv = RV_OK; 290 if (argc == 2) { 291 while ((he = gethostent()) != NULL) 292 hostsprint(he); 293 } else { 294 for (i = 2; i < argc; i++) { 295 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) 296 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); 297 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) 298 he = gethostbyaddr(addr, INADDRSZ, AF_INET); 299 else 300 he = gethostbyname(argv[i]); 301 if (he != NULL) 302 hostsprint(he); 303 else { 304 rv = RV_NOTFOUND; 305 break; 306 } 307 } 308 } 309 endhostent(); 310 return rv; 311 } 312 313 /* 314 * networks 315 */ 316 static void 317 networksprint(const struct netent *ne) 318 { 319 char buf[INET6_ADDRSTRLEN]; 320 struct in_addr ianet; 321 322 assert(ne != NULL); 323 ianet = inet_makeaddr(ne->n_net, 0); 324 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL) 325 strlcpy(buf, "# unknown", sizeof(buf)); 326 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf); 327 } 328 329 static int 330 networks(int argc, char *argv[]) 331 { 332 struct netent *ne; 333 in_addr_t net; 334 int i, rv; 335 336 assert(argc > 1); 337 assert(argv != NULL); 338 339 setnetent(1); 340 rv = RV_OK; 341 if (argc == 2) { 342 while ((ne = getnetent()) != NULL) 343 networksprint(ne); 344 } else { 345 for (i = 2; i < argc; i++) { 346 net = inet_network(argv[i]); 347 if (net != INADDR_NONE) 348 ne = getnetbyaddr(net, AF_INET); 349 else 350 ne = getnetbyname(argv[i]); 351 if (ne != NULL) 352 networksprint(ne); 353 else { 354 rv = RV_NOTFOUND; 355 break; 356 } 357 } 358 } 359 endnetent(); 360 return rv; 361 } 362 363 /* 364 * passwd 365 */ 366 static int 367 passwd(int argc, char *argv[]) 368 { 369 struct passwd *pw; 370 unsigned long id; 371 int i, rv; 372 373 assert(argc > 1); 374 assert(argv != NULL); 375 376 #define PASSWDPRINT printf("%s:%s:%u:%u:%s:%s:%s\n", \ 377 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 378 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 379 380 setpassent(1); 381 rv = RV_OK; 382 if (argc == 2) { 383 while ((pw = getpwent()) != NULL) 384 PASSWDPRINT; 385 } else { 386 for (i = 2; i < argc; i++) { 387 if (parsenum(argv[i], &id)) 388 pw = getpwuid((uid_t)id); 389 else 390 pw = getpwnam(argv[i]); 391 if (pw != NULL) 392 PASSWDPRINT; 393 else { 394 rv = RV_NOTFOUND; 395 break; 396 } 397 } 398 } 399 endpwent(); 400 return rv; 401 } 402 403 /* 404 * protocols 405 */ 406 static int 407 protocols(int argc, char *argv[]) 408 { 409 struct protoent *pe; 410 unsigned long id; 411 int i, rv; 412 413 assert(argc > 1); 414 assert(argv != NULL); 415 416 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \ 417 "%-16s %5d", pe->p_name, pe->p_proto) 418 419 setprotoent(1); 420 rv = RV_OK; 421 if (argc == 2) { 422 while ((pe = getprotoent()) != NULL) 423 PROTOCOLSPRINT; 424 } else { 425 for (i = 2; i < argc; i++) { 426 if (parsenum(argv[i], &id)) 427 pe = getprotobynumber((int)id); 428 else 429 pe = getprotobyname(argv[i]); 430 if (pe != NULL) 431 PROTOCOLSPRINT; 432 else { 433 rv = RV_NOTFOUND; 434 break; 435 } 436 } 437 } 438 endprotoent(); 439 return rv; 440 } 441 442 /* 443 * rpc 444 */ 445 static int 446 rpc(int argc, char *argv[]) 447 { 448 struct rpcent *re; 449 unsigned long id; 450 int i, rv; 451 452 assert(argc > 1); 453 assert(argv != NULL); 454 455 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \ 456 "%-16s %6d", \ 457 re->r_name, re->r_number) 458 459 setrpcent(1); 460 rv = RV_OK; 461 if (argc == 2) { 462 while ((re = getrpcent()) != NULL) 463 RPCPRINT; 464 } else { 465 for (i = 2; i < argc; i++) { 466 if (parsenum(argv[i], &id)) 467 re = getrpcbynumber((int)id); 468 else 469 re = getrpcbyname(argv[i]); 470 if (re != NULL) 471 RPCPRINT; 472 else { 473 rv = RV_NOTFOUND; 474 break; 475 } 476 } 477 } 478 endrpcent(); 479 return rv; 480 } 481 482 /* 483 * services 484 */ 485 static int 486 services(int argc, char *argv[]) 487 { 488 struct servent *se; 489 unsigned long id; 490 char *proto; 491 int i, rv; 492 493 assert(argc > 1); 494 assert(argv != NULL); 495 496 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \ 497 "%-16s %5d/%s", \ 498 se->s_name, ntohs(se->s_port), se->s_proto) 499 500 setservent(1); 501 rv = RV_OK; 502 if (argc == 2) { 503 while ((se = getservent()) != NULL) 504 SERVICESPRINT; 505 } else { 506 for (i = 2; i < argc; i++) { 507 proto = strchr(argv[i], '/'); 508 if (proto != NULL) 509 *proto++ = '\0'; 510 if (parsenum(argv[i], &id)) 511 se = getservbyport(htons((u_short)id), proto); 512 else 513 se = getservbyname(argv[i], proto); 514 if (se != NULL) 515 SERVICESPRINT; 516 else { 517 rv = RV_NOTFOUND; 518 break; 519 } 520 } 521 } 522 endservent(); 523 return rv; 524 } 525 526 /* 527 * shells 528 */ 529 static int 530 shells(int argc, char *argv[]) 531 { 532 const char *sh; 533 int i, rv; 534 535 assert(argc > 1); 536 assert(argv != NULL); 537 538 #define SHELLSPRINT printf("%s\n", sh) 539 540 setusershell(); 541 rv = RV_OK; 542 if (argc == 2) { 543 while ((sh = getusershell()) != NULL) 544 SHELLSPRINT; 545 } else { 546 for (i = 2; i < argc; i++) { 547 setusershell(); 548 while ((sh = getusershell()) != NULL) { 549 if (strcmp(sh, argv[i]) == 0) { 550 SHELLSPRINT; 551 break; 552 } 553 } 554 if (sh == NULL) { 555 rv = RV_NOTFOUND; 556 break; 557 } 558 } 559 } 560 endusershell(); 561 return rv; 562 } 563