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