1 /* $OpenBSD: getent.c,v 1.14 2016/02/01 19:57:28 jca 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 <err.h> 38 #include <errno.h> 39 #include <grp.h> 40 #include <limits.h> 41 #include <netdb.h> 42 #include <pwd.h> 43 #include <stdio.h> 44 #include <stdarg.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include <net/if.h> 50 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */ 51 #include <netinet/if_ether.h> 52 53 #include <arpa/inet.h> 54 #include <arpa/nameser.h> 55 56 #include <rpc/rpc.h> 57 58 static int usage(void); 59 static int ethers(int, char *[]); 60 static int group(int, char *[]); 61 static int hosts(int, char *[]); 62 static int passwd(int, char *[]); 63 static int protocols(int, char *[]); 64 static int rpc(int, char *[]); 65 static int services(int, char *[]); 66 static int shells(int, char *[]); 67 extern char *__progname; 68 69 enum { 70 RV_OK = 0, 71 RV_USAGE = 1, 72 RV_NOTFOUND = 2, 73 RV_NOENUM = 3 74 }; 75 76 static struct getentdb { 77 const char *name; 78 int (*fn)(int, char *[]); 79 const char *pledge; 80 } databases[] = { 81 { "ethers", ethers, "stdio rpath" }, 82 { "group", group, "stdio getpw" }, 83 { "hosts", hosts, "stdio dns" }, 84 { "passwd", passwd, "stdio getpw" }, 85 { "protocols", protocols, "stdio rpath" }, 86 { "rpc", rpc, "stdio rpath" }, 87 { "services", services, "stdio rpath" }, 88 { "shells", shells, "stdio rpath" }, 89 90 { NULL, NULL, }, 91 }; 92 93 int 94 main(int argc, char *argv[]) 95 { 96 struct getentdb *curdb; 97 98 if (pledge("stdio dns rpath getpw", NULL) == -1) 99 err(1, "pledge"); 100 101 if (argc < 2) 102 usage(); 103 for (curdb = databases; curdb->name != NULL; curdb++) { 104 if (strcmp(curdb->name, argv[1]) == 0) { 105 if (pledge(curdb->pledge, NULL) == -1) 106 err(1, "pledge"); 107 108 exit(curdb->fn(argc, argv)); 109 break; 110 } 111 } 112 fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]); 113 return RV_USAGE; 114 } 115 116 static int 117 usage(void) 118 { 119 fprintf(stderr, "usage: %s database [key ...]\n", __progname); 120 exit(RV_USAGE); 121 /* NOTREACHED */ 122 } 123 124 /* 125 * printfmtstrings -- 126 * vprintf(format, ...), 127 * then the aliases (beginning with prefix, separated by sep), 128 * then a newline 129 */ 130 static void 131 printfmtstrings(char *strings[], const char *prefix, const char *sep, 132 const char *fmt, ...) 133 { 134 va_list ap; 135 const char *curpref; 136 int i; 137 138 va_start(ap, fmt); 139 vprintf(fmt, ap); 140 va_end(ap); 141 142 curpref = prefix; 143 for (i = 0; strings[i] != NULL; i++) { 144 printf("%s%s", curpref, strings[i]); 145 curpref = sep; 146 } 147 printf("\n"); 148 } 149 150 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp) 151 152 static int 153 ethers(int argc, char *argv[]) 154 { 155 char hostname[HOST_NAME_MAX+1], *hp; 156 int i, rv = RV_OK; 157 struct ether_addr ea, *eap; 158 159 if (argc == 2) { 160 fprintf(stderr, "%s: Enumeration not supported on ethers\n", 161 __progname); 162 rv = RV_NOENUM; 163 } else { 164 for (i = 2; i < argc; i++) { 165 if ((eap = ether_aton(argv[i])) == NULL) { 166 eap = &ea; 167 hp = argv[i]; 168 if (ether_hostton(hp, eap) != 0) { 169 rv = RV_NOTFOUND; 170 break; 171 } 172 } else { 173 hp = hostname; 174 if (ether_ntohost(hp, eap) != 0) { 175 rv = RV_NOTFOUND; 176 break; 177 } 178 } 179 ETHERSPRINT; 180 } 181 } 182 return rv; 183 } 184 185 #define GROUPPRINT \ 186 printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \ 187 gr->gr_name, gr->gr_passwd, gr->gr_gid) 188 189 static int 190 group(int argc, char *argv[]) 191 { 192 int i, rv = RV_OK; 193 struct group *gr; 194 195 setgroupent(1); 196 if (argc == 2) { 197 while ((gr = getgrent()) != NULL) 198 GROUPPRINT; 199 } else { 200 for (i = 2; i < argc; i++) { 201 const char *err; 202 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 203 204 if (!err) 205 gr = getgrgid((gid_t)id); 206 else 207 gr = getgrnam(argv[i]); 208 if (gr != NULL) 209 GROUPPRINT; 210 else { 211 rv = RV_NOTFOUND; 212 break; 213 } 214 } 215 } 216 endgrent(); 217 return rv; 218 } 219 220 static void 221 hostsprint(const struct hostent *he) 222 { 223 char buf[INET6_ADDRSTRLEN]; 224 225 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) 226 strlcpy(buf, "# unknown", sizeof(buf)); 227 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); 228 } 229 static int 230 hostsaddrinfo(char* name) 231 { 232 struct addrinfo hints, *res, *res0; 233 void *src; 234 int rv; 235 char buf[INET6_ADDRSTRLEN]; 236 237 rv = RV_NOTFOUND; 238 memset(buf, 0, sizeof(buf)); 239 memset(&hints, 0, sizeof(hints)); 240 hints.ai_family = PF_UNSPEC; 241 hints.ai_socktype = SOCK_DGRAM; 242 243 if (getaddrinfo(name, NULL, &hints, &res0) == 0) { 244 for (res = res0; res; res = res->ai_next) { 245 switch (res->ai_family) { 246 case AF_INET: 247 src = &((struct sockaddr_in*) 248 res->ai_addr)->sin_addr; 249 break; 250 case AF_INET6: 251 src = &((struct sockaddr_in6*) 252 res->ai_addr)->sin6_addr; 253 break; 254 default: /* not reached */ 255 src = NULL; 256 } 257 if (src==NULL || inet_ntop(res->ai_family, src, buf, 258 sizeof(buf)) == NULL) 259 strlcpy(buf, "# unknown", sizeof(buf)); 260 else 261 rv = RV_OK; 262 printf("%-39s %s\n", buf, name); 263 } 264 freeaddrinfo(res0); 265 } 266 267 return (rv); 268 } 269 270 static int 271 hosts(int argc, char *argv[]) 272 { 273 char addr[IN6ADDRSZ]; 274 int i, rv = RV_OK; 275 struct hostent *he; 276 277 if (argc == 2) { 278 fprintf(stderr, "%s: Enumeration not supported on hosts\n", 279 __progname); 280 rv = RV_NOENUM; 281 } else { 282 for (i = 2; i < argc; i++) { 283 he = NULL; 284 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) 285 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); 286 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) 287 he = gethostbyaddr(addr, INADDRSZ, AF_INET); 288 if (he != NULL) 289 hostsprint(he); 290 else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND) 291 break; 292 } 293 } 294 return rv; 295 } 296 297 #define PASSWDPRINT \ 298 printf("%s:%s:%u:%u:%s:%s:%s\n", \ 299 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 300 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 301 302 static int 303 passwd(int argc, char *argv[]) 304 { 305 int i, rv = RV_OK; 306 struct passwd *pw; 307 308 setpassent(1); 309 if (argc == 2) { 310 while ((pw = getpwent()) != NULL) 311 PASSWDPRINT; 312 } else { 313 for (i = 2; i < argc; i++) { 314 const char *err; 315 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 316 317 if (!err) 318 pw = getpwuid((uid_t)id); 319 else 320 pw = getpwnam(argv[i]); 321 if (pw != NULL) 322 PASSWDPRINT; 323 else { 324 rv = RV_NOTFOUND; 325 break; 326 } 327 } 328 } 329 endpwent(); 330 return rv; 331 } 332 333 #define PROTOCOLSPRINT \ 334 printfmtstrings(pe->p_aliases, " ", " ", \ 335 "%-16s %5d", pe->p_name, pe->p_proto) 336 337 static int 338 protocols(int argc, char *argv[]) 339 { 340 struct protoent *pe; 341 int i, rv = RV_OK; 342 343 setprotoent(1); 344 if (argc == 2) { 345 while ((pe = getprotoent()) != NULL) 346 PROTOCOLSPRINT; 347 } else { 348 for (i = 2; i < argc; i++) { 349 const char *err; 350 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 351 352 if (!err) 353 pe = getprotobynumber((int)id); 354 else 355 pe = getprotobyname(argv[i]); 356 if (pe != NULL) 357 PROTOCOLSPRINT; 358 else { 359 rv = RV_NOTFOUND; 360 break; 361 } 362 } 363 } 364 endprotoent(); 365 return rv; 366 } 367 368 #define RPCPRINT \ 369 printfmtstrings(re->r_aliases, " ", " ", \ 370 "%-16s %6d", re->r_name, re->r_number) 371 372 static int 373 rpc(int argc, char *argv[]) 374 { 375 struct rpcent *re; 376 int i, rv = RV_OK; 377 378 setrpcent(1); 379 if (argc == 2) { 380 while ((re = getrpcent()) != NULL) 381 RPCPRINT; 382 } else { 383 for (i = 2; i < argc; i++) { 384 const char *err; 385 long long id = strtonum(argv[i], 0, UINT_MAX, &err); 386 387 if (!err) 388 re = getrpcbynumber((int)id); 389 else 390 re = getrpcbyname(argv[i]); 391 if (re != NULL) 392 RPCPRINT; 393 else { 394 rv = RV_NOTFOUND; 395 break; 396 } 397 } 398 } 399 endrpcent(); 400 return rv; 401 } 402 403 #define SERVICESPRINT \ 404 printfmtstrings(se->s_aliases, " ", " ", \ 405 "%-16s %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto) 406 407 static int 408 services(int argc, char *argv[]) 409 { 410 struct servent *se; 411 int i, rv = RV_OK; 412 413 setservent(1); 414 if (argc == 2) { 415 while ((se = getservent()) != NULL) 416 SERVICESPRINT; 417 } else { 418 for (i = 2; i < argc; i++) { 419 const char *err; 420 long long id; 421 char *proto = strchr(argv[i], '/'); 422 423 if (proto != NULL) 424 *proto++ = '\0'; 425 id = strtonum(argv[i], 0, UINT_MAX, &err); 426 if (!err) 427 se = getservbyport(htons((u_short)id), proto); 428 else 429 se = getservbyname(argv[i], proto); 430 if (se != NULL) 431 SERVICESPRINT; 432 else { 433 rv = RV_NOTFOUND; 434 break; 435 } 436 } 437 } 438 endservent(); 439 return rv; 440 } 441 442 #define SHELLSPRINT printf("%s\n", sh) 443 444 static int 445 shells(int argc, char *argv[]) 446 { 447 const char *sh; 448 int i, rv = RV_OK; 449 450 setusershell(); 451 if (argc == 2) { 452 while ((sh = getusershell()) != NULL) 453 SHELLSPRINT; 454 } else { 455 for (i = 2; i < argc; i++) { 456 setusershell(); 457 while ((sh = getusershell()) != NULL) { 458 if (strcmp(sh, argv[i]) == 0) { 459 SHELLSPRINT; 460 break; 461 } 462 } 463 if (sh == NULL) { 464 rv = RV_NOTFOUND; 465 break; 466 } 467 } 468 } 469 endusershell(); 470 return rv; 471 } 472