133965Sjdp/* $OpenBSD: getent.c,v 1.23 2021/10/11 14:28:26 deraadt Exp $ */ 2218822Sdim/* $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $ */ 389857Sobrien 433965Sjdp/*- 533965Sjdp * Copyright (c) 2004 The NetBSD Foundation, Inc. 633965Sjdp * All rights reserved. 733965Sjdp * 833965Sjdp * This code is derived from software contributed to The NetBSD Foundation 933965Sjdp * by Luke Mewburn. 1033965Sjdp * 1133965Sjdp * Redistribution and use in source and binary forms, with or without 1233965Sjdp * modification, are permitted provided that the following conditions 1333965Sjdp * are met: 1433965Sjdp * 1. Redistributions of source code must retain the above copyright 1533965Sjdp * notice, this list of conditions and the following disclaimer. 1633965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1733965Sjdp * notice, this list of conditions and the following disclaimer in the 1833965Sjdp * documentation and/or other materials provided with the distribution. 1933965Sjdp * 20218822Sdim * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2133965Sjdp * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22218822Sdim * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2333965Sjdp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2433965Sjdp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2533965Sjdp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2633965Sjdp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2733965Sjdp * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2833965Sjdp * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2933965Sjdp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3033965Sjdp * POSSIBILITY OF SUCH DAMAGE. 3133965Sjdp */ 3233965Sjdp 3333965Sjdp#include <sys/types.h> 3433965Sjdp#include <sys/socket.h> 3533965Sjdp 3633965Sjdp#include <ctype.h> 3733965Sjdp#include <err.h> 3833965Sjdp#include <errno.h> 3933965Sjdp#include <grp.h> 4033965Sjdp#include <limits.h> 4133965Sjdp#include <netdb.h> 4233965Sjdp#include <pwd.h> 4333965Sjdp#include <stdio.h> 4433965Sjdp#include <stdarg.h> 4533965Sjdp#include <stdlib.h> 4633965Sjdp#include <string.h> 4733965Sjdp#include <unistd.h> 4833965Sjdp 4933965Sjdp#include <net/if.h> 5033965Sjdp#include <netinet/in.h> /* for INET6_ADDRSTRLEN */ 5133965Sjdp#include <netinet/if_ether.h> 5233965Sjdp 5333965Sjdp#include <arpa/inet.h> 5433965Sjdp 5533965Sjdp#include <rpc/rpc.h> 5633965Sjdp 5733965Sjdpstatic void usage(void); 5833965Sjdpstatic int ethers(int, char *[]); 5933965Sjdpstatic int group(int, char *[]); 6033965Sjdpstatic int hosts(int, char *[]); 6133965Sjdpstatic int passwd(int, char *[]); 6233965Sjdpstatic int protocols(int, char *[]); 6333965Sjdpstatic int rpc(int, char *[]); 6433965Sjdpstatic int services(int, char *[]); 6533965Sjdpstatic int shells(int, char *[]); 6633965Sjdpextern char *__progname; 6733965Sjdp 6833965Sjdpenum { 6933965Sjdp RV_OK = 0, 7033965Sjdp RV_USAGE = 1, 7133965Sjdp RV_NOTFOUND = 2, 7233965Sjdp RV_NOENUM = 3 7333965Sjdp}; 7433965Sjdp 7533965Sjdpstatic struct getentdb { 7633965Sjdp const char *name; 7733965Sjdp int (*fn)(int, char *[]); 7833965Sjdp const char *pledge; 7933965Sjdp const char *unveil; 8033965Sjdp} databases[] = { 8189857Sobrien { "ethers", ethers, "stdio rpath", "/etc/ethers" }, 8289857Sobrien { "group", group, "stdio getpw", NULL }, 8389857Sobrien { "hosts", hosts, "stdio dns", NULL }, 8489857Sobrien { "passwd", passwd, "stdio getpw", NULL }, 8533965Sjdp { "protocols", protocols, "stdio rpath", "/etc/protocols" }, 8633965Sjdp { "rpc", rpc, "stdio rpath", "/etc/rpc" }, 8733965Sjdp { "services", services, "stdio rpath", "/etc/services" }, 88 { "shells", shells, "stdio rpath", "/etc/shells" }, 89 90 { NULL, NULL, }, 91}; 92 93int 94main(int argc, char *argv[]) 95{ 96 struct getentdb *curdb; 97 98 if (argc < 2) 99 usage(); 100 for (curdb = databases; curdb->name != NULL; curdb++) { 101 if (strcmp(curdb->name, argv[1]) == 0) { 102 if (curdb->unveil != NULL) { 103 if (unveil(curdb->unveil, "r") == -1) 104 err(1, "unveil %s", curdb->unveil); 105 } 106 if (pledge(curdb->pledge, NULL) == -1) 107 err(1, "pledge"); 108 109 exit(curdb->fn(argc, argv)); 110 break; 111 } 112 } 113 fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]); 114 return RV_USAGE; 115} 116 117static void 118usage(void) 119{ 120 fprintf(stderr, "usage: %s database [key ...]\n", __progname); 121 exit(RV_USAGE); 122} 123 124/* 125 * printfmtstrings -- 126 * vprintf(format, ...), 127 * then the aliases (beginning with prefix, separated by sep), 128 * then a newline 129 */ 130static void 131printfmtstrings(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 152static int 153ethers(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 189static int 190group(int argc, char *argv[]) 191{ 192 struct group *gr; 193 const char *err; 194 gid_t gid; 195 int i, rv = RV_OK; 196 197 setgroupent(1); 198 if (argc == 2) { 199 while ((gr = getgrent()) != NULL) 200 GROUPPRINT; 201 } else { 202 for (i = 2; i < argc; i++) { 203 if ((gr = getgrnam(argv[i])) == NULL) { 204 gid = strtonum(argv[i], 0, GID_MAX, &err); 205 if (err == NULL) 206 gr = getgrgid(gid); 207 } 208 if (gr != NULL) 209 GROUPPRINT; 210 else { 211 rv = RV_NOTFOUND; 212 break; 213 } 214 } 215 } 216 endgrent(); 217 return rv; 218} 219 220static void 221hostsprint(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, " ", " ", "%-39s %s", buf, he->h_name); 228} 229static int 230hostsaddrinfo(const char *name) 231{ 232 struct addrinfo hints, *res, *res0; 233 char buf[INET6_ADDRSTRLEN]; 234 int rv; 235 236 rv = RV_NOTFOUND; 237 memset(buf, 0, sizeof(buf)); 238 memset(&hints, 0, sizeof(hints)); 239 hints.ai_family = AF_UNSPEC; 240 hints.ai_socktype = SOCK_DGRAM; 241 242 if (getaddrinfo(name, NULL, &hints, &res0) != 0) 243 return (rv); 244 for (res = res0; res; res = res->ai_next) { 245 if ((res->ai_family != AF_INET6 && res->ai_family != AF_INET) || 246 getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf), 247 NULL, 0, NI_NUMERICHOST) != 0) 248 strlcpy(buf, "# unknown", sizeof(buf)); 249 else 250 rv = RV_OK; 251 printf("%-39s %s\n", buf, name); 252 } 253 freeaddrinfo(res0); 254 255 return (rv); 256} 257 258static int 259hosts(int argc, char *argv[]) 260{ 261 struct in6_addr in6; 262 struct in_addr in; 263 int i, rv = RV_OK; 264 struct hostent *he; 265 266 if (argc == 2) { 267 fprintf(stderr, "%s: Enumeration not supported on hosts\n", 268 __progname); 269 rv = RV_NOENUM; 270 } else { 271 for (i = 2; i < argc; i++) { 272 he = NULL; 273 if (inet_pton(AF_INET6, argv[i], (void *)&in6) > 0) 274 he = gethostbyaddr(&in6, sizeof(in6), AF_INET6); 275 else if (inet_pton(AF_INET, argv[i], (void *)&in) > 0) 276 he = gethostbyaddr(&in, sizeof(in), AF_INET); 277 if (he != NULL) 278 hostsprint(he); 279 else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND) 280 break; 281 } 282 } 283 return rv; 284} 285 286#define PASSWDPRINT \ 287 printf("%s:%s:%u:%u:%s:%s:%s\n", \ 288 pw->pw_name, pw->pw_passwd, pw->pw_uid, \ 289 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell) 290 291static int 292passwd(int argc, char *argv[]) 293{ 294 struct passwd *pw; 295 const char *err; 296 uid_t uid; 297 int i, rv = RV_OK; 298 299 setpassent(1); 300 if (argc == 2) { 301 while ((pw = getpwent()) != NULL) 302 PASSWDPRINT; 303 } else { 304 for (i = 2; i < argc; i++) { 305 if ((pw = getpwnam(argv[i])) == NULL) { 306 uid = strtonum(argv[i], 0, UID_MAX, &err); 307 if (err == NULL) 308 pw = getpwuid(uid); 309 } 310 if (pw != NULL) 311 PASSWDPRINT; 312 else { 313 rv = RV_NOTFOUND; 314 break; 315 } 316 } 317 } 318 endpwent(); 319 return rv; 320} 321 322#define PROTOCOLSPRINT \ 323 printfmtstrings(pe->p_aliases, " ", " ", \ 324 "%-16s %5d", pe->p_name, pe->p_proto) 325 326static int 327protocols(int argc, char *argv[]) 328{ 329 struct protoent *pe; 330 const char *err; 331 int proto; 332 int i, rv = RV_OK; 333 334 setprotoent(1); 335 if (argc == 2) { 336 while ((pe = getprotoent()) != NULL) 337 PROTOCOLSPRINT; 338 } else { 339 for (i = 2; i < argc; i++) { 340 proto = strtonum(argv[i], 0, INT_MAX, &err); 341 if (!err) 342 pe = getprotobynumber(proto); 343 else 344 pe = getprotobyname(argv[i]); 345 if (pe != NULL) 346 PROTOCOLSPRINT; 347 else { 348 rv = RV_NOTFOUND; 349 break; 350 } 351 } 352 } 353 endprotoent(); 354 return rv; 355} 356 357#define RPCPRINT \ 358 printfmtstrings(re->r_aliases, " ", " ", \ 359 "%-16s %6d", re->r_name, re->r_number) 360 361static int 362rpc(int argc, char *argv[]) 363{ 364 struct rpcent *re; 365 const char *err; 366 int rpc; 367 int i, rv = RV_OK; 368 369 setrpcent(1); 370 if (argc == 2) { 371 while ((re = getrpcent()) != NULL) 372 RPCPRINT; 373 } else { 374 for (i = 2; i < argc; i++) { 375 rpc = strtonum(argv[i], 0, INT_MAX, &err); 376 if (!err) 377 re = getrpcbynumber(rpc); 378 else 379 re = getrpcbyname(argv[i]); 380 if (re != NULL) 381 RPCPRINT; 382 else { 383 rv = RV_NOTFOUND; 384 break; 385 } 386 } 387 } 388 endrpcent(); 389 return rv; 390} 391 392#define SERVICESPRINT \ 393 printfmtstrings(se->s_aliases, " ", " ", \ 394 "%-16s %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto) 395 396static int 397services(int argc, char *argv[]) 398{ 399 struct servent *se; 400 const char *err; 401 char *proto; 402 in_port_t port; 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 if ((proto = strchr(argv[i], '/')) != NULL) 412 *proto++ = '\0'; 413 port = strtonum(argv[i], 0, IPPORT_HILASTAUTO, &err); 414 if (!err) 415 se = getservbyport(htons(port), proto); 416 else 417 se = getservbyname(argv[i], proto); 418 if (se != NULL) 419 SERVICESPRINT; 420 else { 421 rv = RV_NOTFOUND; 422 break; 423 } 424 } 425 } 426 endservent(); 427 return rv; 428} 429 430#define SHELLSPRINT printf("%s\n", sh) 431 432static int 433shells(int argc, char *argv[]) 434{ 435 const char *sh; 436 int i, rv = RV_OK; 437 438 setusershell(); 439 if (argc == 2) { 440 while ((sh = getusershell()) != NULL) 441 SHELLSPRINT; 442 } else { 443 for (i = 2; i < argc; i++) { 444 setusershell(); 445 while ((sh = getusershell()) != NULL) { 446 if (strcmp(sh, argv[i]) == 0) { 447 SHELLSPRINT; 448 break; 449 } 450 } 451 if (sh == NULL) { 452 rv = RV_NOTFOUND; 453 break; 454 } 455 } 456 } 457 endusershell(); 458 return rv; 459} 460