1 /* $OpenBSD: getent.c,v 1.9 2015/01/16 06:40:08 deraadt Exp $ */ 2 /* $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $ */ 3 4 /*- 5 * Copyright (c) 2004 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Luke Mewburn. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 36 #include <ctype.h> 37 #include <errno.h> 38 #include <grp.h> 39 #include <limits.h> 40 #include <netdb.h> 41 #include <pwd.h> 42 #include <stdio.h> 43 #include <stdarg.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include <net/if.h> 49 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */ 50 #include <netinet/if_ether.h> 51 52 #include <arpa/inet.h> 53 #include <arpa/nameser.h> 54 55 #include <rpc/rpc.h> 56 57 static int usage(void); 58 static int ethers(int, char *[]); 59 static int group(int, char *[]); 60 static int hosts(int, char *[]); 61 static int passwd(int, char *[]); 62 static int protocols(int, char *[]); 63 static int rpc(int, char *[]); 64 static int services(int, char *[]); 65 static int shells(int, char *[]); 66 extern char *__progname; 67 68 enum { 69 RV_OK = 0, 70 RV_USAGE = 1, 71 RV_NOTFOUND = 2, 72 RV_NOENUM = 3 73 }; 74 75 static struct getentdb { 76 const char *name; 77 int (*fn)(int, char *[]); 78 } databases[] = { 79 { "ethers", ethers, }, 80 { "group", group, }, 81 { "hosts", hosts, }, 82 { "passwd", passwd, }, 83 { "protocols", protocols, }, 84 { "rpc", rpc, }, 85 { "services", services, }, 86 { "shells", shells, }, 87 88 { NULL, NULL, }, 89 }; 90 91 int 92 main(int argc, char *argv[]) 93 { 94 struct getentdb *curdb; 95 96 if (argc < 2) 97 usage(); 98 for (curdb = databases; curdb->name != NULL; curdb++) { 99 if (strcmp(curdb->name, argv[1]) == 0) { 100 exit(curdb->fn(argc, argv)); 101 break; 102 } 103 } 104 fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]); 105 return RV_USAGE; 106 } 107 108 static int 109 usage(void) 110 { 111 fprintf(stderr, "usage: %s database [key ...]\n", __progname); 112 exit(RV_USAGE); 113 /* NOTREACHED */ 114 } 115 116 /* 117 * printfmtstrings -- 118 * vprintf(format, ...), 119 * then the aliases (beginning with prefix, separated by sep), 120 * then a newline 121 */ 122 static void 123 printfmtstrings(char *strings[], const char *prefix, const char *sep, 124 const char *fmt, ...) 125 { 126 va_list ap; 127 const char *curpref; 128 int i; 129 130 va_start(ap, fmt); 131 vprintf(fmt, ap); 132 va_end(ap); 133 134 curpref = prefix; 135 for (i = 0; strings[i] != NULL; i++) { 136 printf("%s%s", curpref, strings[i]); 137 curpref = sep; 138 } 139 printf("\n"); 140 } 141 142 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp) 143 144 static int 145 ethers(int argc, char *argv[]) 146 { 147 char hostname[HOST_NAME_MAX+1], *hp; 148 int i, rv = RV_OK; 149 struct ether_addr ea, *eap; 150 151 if (argc == 2) { 152 fprintf(stderr, "%s: Enumeration not supported on ethers\n", 153 __progname); 154 rv = RV_NOENUM; 155 } else { 156 for (i = 2; i < argc; i++) { 157 if ((eap = ether_aton(argv[i])) == NULL) { 158 eap = &ea; 159 hp = argv[i]; 160 if (ether_hostton(hp, eap) != 0) { 161 rv = RV_NOTFOUND; 162 break; 163 } 164 } else { 165 hp = hostname; 166 if (ether_ntohost(hp, eap) != 0) { 167 rv = RV_NOTFOUND; 168 break; 169 } 170 } 171 ETHERSPRINT; 172 } 173 } 174 return rv; 175 } 176 177 #define GROUPPRINT \ 178 printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ 179 gr->gr_name, gr->gr_passwd, gr->gr_gid) 180 181 static int 182 group(int argc, char *argv[]) 183 { 184 int i, rv = RV_OK; 185 struct group *gr; 186 187 setgroupent(1); 188 if (argc == 2) { 189 while ((gr = getgrent()) != NULL) 190 GROUPPRINT; 191 } else { 192 for (i = 2; i < argc; i++) { 193 const char *err; 194 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 195 196 if (!err) 197 gr = getgrgid((gid_t)id); 198 else 199 gr = getgrnam(argv[i]); 200 if (gr != NULL) 201 GROUPPRINT; 202 else { 203 rv = RV_NOTFOUND; 204 break; 205 } 206 } 207 } 208 endgrent(); 209 return rv; 210 } 211 212 static void 213 hostsprint(const struct hostent *he) 214 { 215 char buf[INET6_ADDRSTRLEN]; 216 217 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) 218 strlcpy(buf, "# unknown", sizeof(buf)); 219 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); 220 } 221 static int 222 hostsaddrinfo(char* name) 223 { 224 struct addrinfo hints, *res, *res0; 225 void *src; 226 int rv; 227 char buf[INET6_ADDRSTRLEN]; 228 229 rv = RV_NOTFOUND; 230 memset(buf, 0, sizeof(buf)); 231 memset(&hints, 0, sizeof(hints)); 232 hints.ai_family = PF_UNSPEC; 233 hints.ai_socktype = SOCK_DGRAM; 234 235 if (getaddrinfo(name, NULL, &hints, &res0) == 0) { 236 for (res = res0; res; res = res->ai_next) { 237 switch (res->ai_family) { 238 case AF_INET: 239 src = &((struct sockaddr_in*) 240 res->ai_addr)->sin_addr; 241 break; 242 case AF_INET6: 243 src = &((struct sockaddr_in6*) 244 res->ai_addr)->sin6_addr; 245 break; 246 default: /* not reached */ 247 src = NULL; 248 } 249 if (src==NULL || inet_ntop(res->ai_family, src, buf, 250 sizeof(buf)) == NULL) 251 strlcpy(buf, "# unknown", sizeof(buf)); 252 else 253 rv = RV_OK; 254 printf("%-39s %s\n", buf, name); 255 } 256 freeaddrinfo(res0); 257 } 258 259 return (rv); 260 } 261 262 static int 263 hosts(int argc, char *argv[]) 264 { 265 char addr[IN6ADDRSZ]; 266 int i, rv = RV_OK; 267 struct hostent *he; 268 269 if (argc == 2) { 270 fprintf(stderr, "%s: Enumeration not supported on hosts\n", 271 __progname); 272 rv = RV_NOENUM; 273 } else { 274 for (i = 2; i < argc; i++) { 275 he = NULL; 276 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) 277 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); 278 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) 279 he = gethostbyaddr(addr, INADDRSZ, AF_INET); 280 if (he != NULL) 281 hostsprint(he); 282 else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND) 283 break; 284 } 285 } 286 return rv; 287 } 288 289 #define PASSWDPRINT \ 290 printf("%s:%s:%u:%u:%s:%s:%s\n", \ 291 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 292 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 293 294 static int 295 passwd(int argc, char *argv[]) 296 { 297 int i, rv = RV_OK; 298 struct passwd *pw; 299 300 setpassent(1); 301 if (argc == 2) { 302 while ((pw = getpwent()) != NULL) 303 PASSWDPRINT; 304 } else { 305 for (i = 2; i < argc; i++) { 306 const char *err; 307 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 308 309 if (!err) 310 pw = getpwuid((uid_t)id); 311 else 312 pw = getpwnam(argv[i]); 313 if (pw != NULL) 314 PASSWDPRINT; 315 else { 316 rv = RV_NOTFOUND; 317 break; 318 } 319 } 320 } 321 endpwent(); 322 return rv; 323 } 324 325 #define PROTOCOLSPRINT \ 326 printfmtstrings(pe->p_aliases, " ", " ", \ 327 "%-16s %5d", pe->p_name, pe->p_proto) 328 329 static int 330 protocols(int argc, char *argv[]) 331 { 332 struct protoent *pe; 333 int i, rv = RV_OK; 334 335 setprotoent(1); 336 if (argc == 2) { 337 while ((pe = getprotoent()) != NULL) 338 PROTOCOLSPRINT; 339 } else { 340 for (i = 2; i < argc; i++) { 341 const char *err; 342 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 343 344 if (!err) 345 pe = getprotobynumber((int)id); 346 else 347 pe = getprotobyname(argv[i]); 348 if (pe != NULL) 349 PROTOCOLSPRINT; 350 else { 351 rv = RV_NOTFOUND; 352 break; 353 } 354 } 355 } 356 endprotoent(); 357 return rv; 358 } 359 360 #define RPCPRINT \ 361 printfmtstrings(re->r_aliases, " ", " ", \ 362 "%-16s %6d", re->r_name, re->r_number) 363 364 static int 365 rpc(int argc, char *argv[]) 366 { 367 struct rpcent *re; 368 int i, rv = RV_OK; 369 370 setrpcent(1); 371 if (argc == 2) { 372 while ((re = getrpcent()) != NULL) 373 RPCPRINT; 374 } else { 375 for (i = 2; i < argc; i++) { 376 const char *err; 377 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 378 379 if (!err) 380 re = getrpcbynumber((int)id); 381 else 382 re = getrpcbyname(argv[i]); 383 if (re != NULL) 384 RPCPRINT; 385 else { 386 rv = RV_NOTFOUND; 387 break; 388 } 389 } 390 } 391 endrpcent(); 392 return rv; 393 } 394 395 #define SERVICESPRINT \ 396 printfmtstrings(se->s_aliases, " ", " ", \ 397 "%-16s %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto) 398 399 static int 400 services(int argc, char *argv[]) 401 { 402 struct servent *se; 403 int i, rv = RV_OK; 404 405 setservent(1); 406 if (argc == 2) { 407 while ((se = getservent()) != NULL) 408 SERVICESPRINT; 409 } else { 410 for (i = 2; i < argc; i++) { 411 const char *err; 412 long long id; 413 char *proto = strchr(argv[i], '/'); 414 415 if (proto != NULL) 416 *proto++ = '\0'; 417 id = strtonum(argv[i], 0, UINT_MAX, &err); 418 if (!err) 419 se = getservbyport(htons((u_short)id), proto); 420 else 421 se = getservbyname(argv[i], proto); 422 if (se != NULL) 423 SERVICESPRINT; 424 else { 425 rv = RV_NOTFOUND; 426 break; 427 } 428 } 429 } 430 endservent(); 431 return rv; 432 } 433 434 #define SHELLSPRINT printf("%s\n", sh) 435 436 static int 437 shells(int argc, char *argv[]) 438 { 439 const char *sh; 440 int i, rv = RV_OK; 441 442 setusershell(); 443 if (argc == 2) { 444 while ((sh = getusershell()) != NULL) 445 SHELLSPRINT; 446 } else { 447 for (i = 2; i < argc; i++) { 448 setusershell(); 449 while ((sh = getusershell()) != NULL) { 450 if (strcmp(sh, argv[i]) == 0) { 451 SHELLSPRINT; 452 break; 453 } 454 } 455 if (sh == NULL) { 456 rv = RV_NOTFOUND; 457 break; 458 } 459 } 460 } 461 endusershell(); 462 return rv; 463 } 464