ypldap_dns.c revision 290937
1168404Spjd/* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */ 2168404Spjd/* $FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 290937 2015-11-16 17:06:33Z rodrigc $ */ 3168404Spjd 4168404Spjd/* 5168404Spjd * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 6168404Spjd * 7168404Spjd * Permission to use, copy, modify, and distribute this software for any 8168404Spjd * purpose with or without fee is hereby granted, provided that the above 9168404Spjd * copyright notice and this permission notice appear in all copies. 10168404Spjd * 11168404Spjd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12168404Spjd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13168404Spjd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14168404Spjd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15168404Spjd * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16168404Spjd * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17168404Spjd * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18168404Spjd */ 19168404Spjd 20168404Spjd#include <sys/types.h> 21168404Spjd#include <sys/param.h> 22219089Spjd#include <sys/socket.h> 23226512Smm#include <sys/stat.h> 24284593Savg#include <sys/time.h> 25226512Smm#include <sys/tree.h> 26168404Spjd#include <sys/queue.h> 27168404Spjd 28168404Spjd#include <netinet/in.h> 29168404Spjd#include <arpa/nameser.h> 30168404Spjd 31168404Spjd#include <netdb.h> 32168404Spjd#include <pwd.h> 33168404Spjd#include <errno.h> 34168404Spjd#include <event.h> 35168404Spjd#include <resolv.h> 36168404Spjd#include <poll.h> 37219089Spjd#include <signal.h> 38219089Spjd#include <stdlib.h> 39168404Spjd#include <string.h> 40219089Spjd#include <unistd.h> 41168404Spjd#include <limits.h> 42168404Spjd 43168404Spjd#include "ypldap.h" 44168404Spjd 45168404Spjdvolatile sig_atomic_t quit_dns = 0; 46168404Spjdstruct imsgev *iev_dns; 47168404Spjd 48168404Spjdvoid dns_dispatch_imsg(int, short, void *); 49168404Spjdvoid dns_sig_handler(int, short, void *); 50168404Spjdvoid dns_shutdown(void); 51248571Smmint host_dns(const char *s, struct ypldap_addr **hn); 52168404Spjd 53168404Spjdvoid 54168404Spjddns_sig_handler(int sig, short event, void *p) 55219089Spjd{ 56219089Spjd switch (sig) { 57258632Savg case SIGINT: 58168404Spjd case SIGTERM: 59168404Spjd dns_shutdown(); 60168404Spjd break; 61168404Spjd default: 62168404Spjd fatalx("unexpected signal"); 63168404Spjd } 64168404Spjd} 65168404Spjd 66168404Spjdvoid 67168404Spjddns_shutdown(void) 68219089Spjd{ 69168404Spjd log_info("dns engine exiting"); 70219089Spjd _exit(0); 71168404Spjd} 72168404Spjd 73168404Spjdpid_t 74168404Spjdypldap_dns(int pipe_ntp[2], struct passwd *pw) 75168404Spjd{ 76168404Spjd pid_t pid; 77168404Spjd struct event ev_sigint; 78168404Spjd struct event ev_sigterm; 79168404Spjd struct event ev_sighup; 80168404Spjd struct env env; 81168404Spjd 82168404Spjd switch (pid = fork()) { 83168404Spjd case -1: 84168404Spjd fatal("cannot fork"); 85168404Spjd break; 86168404Spjd case 0: 87168404Spjd break; 88168404Spjd default: 89168404Spjd return (pid); 90168404Spjd } 91168404Spjd 92168404Spjd setproctitle("dns engine"); 93168404Spjd close(pipe_ntp[0]); 94168404Spjd 95168404Spjd if (setgroups(1, &pw->pw_gid) || 96168404Spjd setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 97168404Spjd setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 98168404Spjd fatal("can't drop privileges"); 99168404Spjd endservent(); 100168404Spjd 101168404Spjd event_init(); 102168404Spjd signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL); 103168404Spjd signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL); 104168404Spjd signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL); 105168404Spjd signal_add(&ev_sigint, NULL); 106168404Spjd signal_add(&ev_sigterm, NULL); 107168404Spjd signal_add(&ev_sighup, NULL); 108219089Spjd 109168404Spjd if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 110168404Spjd fatal(NULL); 111168404Spjd 112168404Spjd env.sc_iev->events = EV_READ; 113168404Spjd env.sc_iev->data = &env; 114168404Spjd imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]); 115168404Spjd env.sc_iev->handler = dns_dispatch_imsg; 116168404Spjd event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 117168404Spjd env.sc_iev->handler, &env); 118168404Spjd event_add(&env.sc_iev->ev, NULL); 119168404Spjd 120168404Spjd event_dispatch(); 121168404Spjd dns_shutdown(); 122168404Spjd 123168404Spjd return (0); 124168404Spjd} 125168404Spjd 126168404Spjdvoid 127168404Spjddns_dispatch_imsg(int fd, short events, void *p) 128168404Spjd{ 129168404Spjd struct imsg imsg; 130168404Spjd int n, cnt; 131168404Spjd char *name; 132168404Spjd struct ypldap_addr *h, *hn; 133168404Spjd struct ibuf *buf; 134168404Spjd struct env *env = p; 135168404Spjd struct imsgev *iev = env->sc_iev; 136168404Spjd struct imsgbuf *ibuf = &iev->ibuf; 137168404Spjd int shut = 0; 138168404Spjd 139168404Spjd if ((events & (EV_READ | EV_WRITE)) == 0) 140168404Spjd fatalx("unknown event"); 141168404Spjd 142168404Spjd if (events & EV_READ) { 143168404Spjd if ((n = imsg_read(ibuf)) == -1) 144168404Spjd fatal("imsg_read error"); 145168404Spjd if (n == 0) 146168404Spjd shut = 1; 147168404Spjd } 148168404Spjd if (events & EV_WRITE) { 149168404Spjd if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 150168404Spjd fatal("msgbuf_write"); 151168404Spjd if (n == 0) 152168404Spjd shut = 1; 153168404Spjd goto done; 154168404Spjd } 155168404Spjd 156168404Spjd for (;;) { 157168404Spjd if ((n = imsg_get(ibuf, &imsg)) == -1) 158168404Spjd fatal("client_dispatch_imsg: imsg_get error"); 159168404Spjd if (n == 0) 160168404Spjd break; 161168404Spjd 162168404Spjd switch (imsg.hdr.type) { 163168404Spjd case IMSG_HOST_DNS: 164249195Smm name = imsg.data; 165185029Spjd if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 166168404Spjd fatalx("invalid IMSG_HOST_DNS received"); 167168404Spjd imsg.hdr.len -= 1 + IMSG_HEADER_SIZE; 168168404Spjd if (name[imsg.hdr.len] != '\0' || 169168404Spjd strlen(name) != imsg.hdr.len) 170209962Smm fatalx("invalid IMSG_HOST_DNS received"); 171219089Spjd if ((cnt = host_dns(name, &hn)) == -1) 172219089Spjd break; 173209962Smm buf = imsg_create(ibuf, IMSG_HOST_DNS, 174219089Spjd imsg.hdr.peerid, 0, 175219089Spjd cnt * sizeof(struct sockaddr_storage)); 176219089Spjd if (buf == NULL) 177219089Spjd break; 178219089Spjd if (cnt > 0) { 179219089Spjd h = hn; 180209962Smm while (h != NULL) { 181219089Spjd imsg_add(buf, &h->ss, sizeof(h->ss)); 182209962Smm hn = h->next; 183209962Smm free(h); 184219089Spjd h = hn; 185209962Smm } 186219089Spjd } 187219089Spjd 188219089Spjd imsg_close(ibuf, buf); 189219089Spjd break; 190219089Spjd default: 191219089Spjd break; 192219089Spjd } 193219089Spjd imsg_free(&imsg); 194219089Spjd } 195219089Spjd 196219089Spjddone: 197219089Spjd if (!shut) 198209962Smm imsg_event_add(iev); 199209962Smm else { 200219089Spjd /* this pipe is dead, so remove the event handler */ 201219089Spjd event_del(&iev->ev); 202209962Smm event_loopexit(NULL); 203219089Spjd } 204219089Spjd} 205219089Spjd 206219089Spjdint 207219089Spjdhost_dns(const char *s, struct ypldap_addr **hn) 208219089Spjd{ 209219089Spjd struct addrinfo hints, *res0, *res; 210219089Spjd int error, cnt = 0; 211219089Spjd struct sockaddr_in *sa_in; 212209962Smm struct sockaddr_in6 *sa_in6; 213209962Smm struct ypldap_addr *h, *hh = NULL; 214168404Spjd 215168404Spjd bzero(&hints, sizeof(hints)); 216168404Spjd hints.ai_family = PF_UNSPEC; 217168404Spjd hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 218168404Spjd error = getaddrinfo(s, NULL, &hints, &res0); 219168404Spjd if (error == EAI_AGAIN || error == EAI_NONAME) 220168404Spjd return (0); 221168404Spjd if (error) { 222168404Spjd log_warnx("could not parse \"%s\": %s", s, 223168404Spjd gai_strerror(error)); 224168404Spjd return (-1); 225168404Spjd } 226168404Spjd 227274337Sdelphij for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) { 228168404Spjd if (res->ai_family != AF_INET && 229168404Spjd res->ai_family != AF_INET6) 230168404Spjd continue; 231209962Smm if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL) 232219089Spjd fatal(NULL); 233209962Smm h->ss.ss_family = res->ai_family; 234209962Smm if (res->ai_family == AF_INET) { 235168404Spjd sa_in = (struct sockaddr_in *)&h->ss; 236209962Smm sa_in->sin_len = sizeof(struct sockaddr_in); 237209962Smm sa_in->sin_addr.s_addr = ((struct sockaddr_in *) 238209962Smm res->ai_addr)->sin_addr.s_addr; 239209962Smm } else { 240168404Spjd sa_in6 = (struct sockaddr_in6 *)&h->ss; 241209962Smm sa_in6->sin6_len = sizeof(struct sockaddr_in6); 242209962Smm memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *) 243209962Smm res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 244209962Smm } 245209962Smm 246209962Smm h->next = hh; 247209962Smm hh = h; 248209962Smm cnt++; 249209962Smm } 250168404Spjd freeaddrinfo(res0); 251168404Spjd 252168404Spjd *hn = hh; 253168404Spjd return (cnt); 254168404Spjd} 255168404Spjd