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