1 /* $NetBSD: getent.c,v 1.5 2004/11/29 05:02:40 lukem 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.5 2004/11/29 05:02:40 lukem 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 static int usage(void); 65 static int parsenum(const char *, unsigned long *); 66 static int group(int, char *[]); 67 static int hosts(int, char *[]); 68 static int networks(int, char *[]); 69 static int passwd(int, char *[]); 70 static int protocols(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 { "group", group, }, 86 { "hosts", hosts, }, 87 { "networks", networks, }, 88 { "passwd", passwd, }, 89 { "protocols", protocols, }, 90 { "services", services, }, 91 { "shells", shells, }, 92 93 { NULL, NULL, }, 94 }; 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 break; 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 } 179 180 181 /* 182 * group 183 */ 184 185 static int 186 group(int argc, char *argv[]) 187 { 188 struct group *gr; 189 unsigned long id; 190 int i, rv; 191 192 assert(argc > 1); 193 assert(argv != NULL); 194 195 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ 196 gr->gr_name, gr->gr_passwd, gr->gr_gid) 197 198 setgroupent(1); 199 rv = RV_OK; 200 if (argc == 2) { 201 while ((gr = getgrent()) != NULL) 202 GROUPPRINT; 203 } else { 204 for (i = 2; i < argc; i++) { 205 if (parsenum(argv[i], &id)) 206 gr = getgrgid((gid_t)id); 207 else 208 gr = getgrnam(argv[i]); 209 if (gr != NULL) 210 GROUPPRINT; 211 else { 212 rv = RV_NOTFOUND; 213 break; 214 } 215 } 216 } 217 endgrent(); 218 return rv; 219 } 220 221 222 /* 223 * hosts 224 */ 225 226 static void 227 hostsprint(const struct hostent *he) 228 { 229 char buf[INET6_ADDRSTRLEN]; 230 231 assert(he != NULL); 232 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) 233 strlcpy(buf, "# unknown", sizeof(buf)); 234 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); 235 } 236 237 static int 238 hosts(int argc, char *argv[]) 239 { 240 struct hostent *he; 241 char addr[IN6ADDRSZ]; 242 int i, rv; 243 244 assert(argc > 1); 245 assert(argv != NULL); 246 247 sethostent(1); 248 rv = RV_OK; 249 if (argc == 2) { 250 while ((he = gethostent()) != NULL) 251 hostsprint(he); 252 } else { 253 for (i = 2; i < argc; i++) { 254 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) 255 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); 256 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) 257 he = gethostbyaddr(addr, INADDRSZ, AF_INET); 258 else 259 he = gethostbyname(argv[i]); 260 if (he != NULL) 261 hostsprint(he); 262 else { 263 rv = RV_NOTFOUND; 264 break; 265 } 266 } 267 } 268 endhostent(); 269 return rv; 270 } 271 272 273 /* 274 * networks 275 */ 276 277 static void 278 networksprint(const struct netent *ne) 279 { 280 char buf[INET6_ADDRSTRLEN]; 281 struct in_addr ianet; 282 283 assert(ne != NULL); 284 ianet = inet_makeaddr(ne->n_net, 0); 285 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL) 286 strlcpy(buf, "# unknown", sizeof(buf)); 287 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf); 288 } 289 290 static int 291 networks(int argc, char *argv[]) 292 { 293 struct netent *ne; 294 in_addr_t net; 295 int i, rv; 296 297 assert(argc > 1); 298 assert(argv != NULL); 299 300 setnetent(1); 301 rv = RV_OK; 302 if (argc == 2) { 303 while ((ne = getnetent()) != NULL) 304 networksprint(ne); 305 } else { 306 for (i = 2; i < argc; i++) { 307 net = inet_network(argv[i]); 308 if (net != INADDR_NONE) 309 ne = getnetbyaddr(net, AF_INET); 310 else 311 ne = getnetbyname(argv[i]); 312 if (ne != NULL) 313 networksprint(ne); 314 else { 315 rv = RV_NOTFOUND; 316 break; 317 } 318 } 319 } 320 endnetent(); 321 return rv; 322 } 323 324 325 /* 326 * passwd 327 */ 328 329 static int 330 passwd(int argc, char *argv[]) 331 { 332 struct passwd *pw; 333 unsigned long id; 334 int i, rv; 335 336 assert(argc > 1); 337 assert(argv != NULL); 338 339 #define PASSWDPRINT printf("%s:%s:%u:%u:%s:%s:%s\n", \ 340 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 341 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 342 343 setpassent(1); 344 rv = RV_OK; 345 if (argc == 2) { 346 while ((pw = getpwent()) != NULL) 347 PASSWDPRINT; 348 } else { 349 for (i = 2; i < argc; i++) { 350 if (parsenum(argv[i], &id)) 351 pw = getpwuid((uid_t)id); 352 else 353 pw = getpwnam(argv[i]); 354 if (pw != NULL) 355 PASSWDPRINT; 356 else { 357 rv = RV_NOTFOUND; 358 break; 359 } 360 } 361 } 362 endpwent(); 363 return rv; 364 } 365 366 367 /* 368 * protocols 369 */ 370 371 static int 372 protocols(int argc, char *argv[]) 373 { 374 struct protoent *pe; 375 unsigned long id; 376 int i, rv; 377 378 assert(argc > 1); 379 assert(argv != NULL); 380 381 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \ 382 "%-16s %5d", pe->p_name, pe->p_proto) 383 384 setprotoent(1); 385 rv = RV_OK; 386 if (argc == 2) { 387 while ((pe = getprotoent()) != NULL) 388 PROTOCOLSPRINT; 389 } else { 390 for (i = 2; i < argc; i++) { 391 if (parsenum(argv[i], &id)) 392 pe = getprotobynumber((int)id); 393 else 394 pe = getprotobyname(argv[i]); 395 if (pe != NULL) 396 PROTOCOLSPRINT; 397 else { 398 rv = RV_NOTFOUND; 399 break; 400 } 401 } 402 } 403 endprotoent(); 404 return rv; 405 } 406 407 408 /* 409 * services 410 */ 411 412 static int 413 services(int argc, char *argv[]) 414 { 415 struct servent *se; 416 unsigned long id; 417 char *proto; 418 int i, rv; 419 420 assert(argc > 1); 421 assert(argv != NULL); 422 423 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \ 424 "%-16s %5d/%s", \ 425 se->s_name, ntohs(se->s_port), se->s_proto) 426 427 setservent(1); 428 rv = RV_OK; 429 if (argc == 2) { 430 while ((se = getservent()) != NULL) 431 SERVICESPRINT; 432 } else { 433 for (i = 2; i < argc; i++) { 434 proto = strchr(argv[i], '/'); 435 if (proto != NULL) 436 *proto++ = '\0'; 437 if (parsenum(argv[i], &id)) 438 se = getservbyport((int)id, proto); 439 else 440 se = getservbyname(argv[i], proto); 441 if (se != NULL) 442 SERVICESPRINT; 443 else { 444 rv = RV_NOTFOUND; 445 break; 446 } 447 } 448 } 449 endservent(); 450 return rv; 451 } 452 453 454 /* 455 * shells 456 */ 457 458 static int 459 shells(int argc, char *argv[]) 460 { 461 const char *sh; 462 int i, rv; 463 464 assert(argc > 1); 465 assert(argv != NULL); 466 467 #define SHELLSPRINT printf("%s\n", sh) 468 469 setusershell(); 470 rv = RV_OK; 471 if (argc == 2) { 472 while ((sh = getusershell()) != NULL) 473 SHELLSPRINT; 474 } else { 475 for (i = 2; i < argc; i++) { 476 setusershell(); 477 while ((sh = getusershell()) != NULL) { 478 if (strcmp(sh, argv[i]) == 0) { 479 SHELLSPRINT; 480 break; 481 } 482 } 483 if (sh == NULL) { 484 rv = RV_NOTFOUND; 485 break; 486 } 487 } 488 } 489 endusershell(); 490 return rv; 491 } 492