1290931Srodrigc/* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */ 2290931Srodrigc/* $FreeBSD: stable/11/usr.sbin/ypldap/ypldap_dns.c 309872 2016-12-12 02:24:54Z araujo $ */ 3290931Srodrigc 4290931Srodrigc/* 5290931Srodrigc * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 6290931Srodrigc * 7290931Srodrigc * Permission to use, copy, modify, and distribute this software for any 8290931Srodrigc * purpose with or without fee is hereby granted, provided that the above 9290931Srodrigc * copyright notice and this permission notice appear in all copies. 10290931Srodrigc * 11290931Srodrigc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12290931Srodrigc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13290931Srodrigc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14290931Srodrigc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15290931Srodrigc * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16290931Srodrigc * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17290931Srodrigc * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18290931Srodrigc */ 19290931Srodrigc 20290931Srodrigc#include <sys/types.h> 21290937Srodrigc#include <sys/param.h> 22290931Srodrigc#include <sys/socket.h> 23290931Srodrigc#include <sys/stat.h> 24290931Srodrigc#include <sys/time.h> 25290931Srodrigc#include <sys/tree.h> 26290931Srodrigc#include <sys/queue.h> 27290931Srodrigc 28290931Srodrigc#include <netinet/in.h> 29290931Srodrigc#include <arpa/nameser.h> 30290931Srodrigc 31290931Srodrigc#include <netdb.h> 32290931Srodrigc#include <pwd.h> 33290931Srodrigc#include <errno.h> 34290931Srodrigc#include <event.h> 35290931Srodrigc#include <resolv.h> 36290931Srodrigc#include <poll.h> 37290931Srodrigc#include <signal.h> 38290931Srodrigc#include <stdlib.h> 39290931Srodrigc#include <string.h> 40290931Srodrigc#include <unistd.h> 41290931Srodrigc#include <limits.h> 42290931Srodrigc 43290931Srodrigc#include "ypldap.h" 44290931Srodrigc 45290931Srodrigcvolatile sig_atomic_t quit_dns = 0; 46290931Srodrigcstruct imsgev *iev_dns; 47290931Srodrigc 48290931Srodrigcvoid dns_dispatch_imsg(int, short, void *); 49290931Srodrigcvoid dns_sig_handler(int, short, void *); 50290931Srodrigcvoid dns_shutdown(void); 51297907Saraujoint host_dns(const char *, struct ypldap_addr_list *); 52290931Srodrigc 53290931Srodrigcvoid 54290931Srodrigcdns_sig_handler(int sig, short event, void *p) 55290931Srodrigc{ 56290931Srodrigc switch (sig) { 57290931Srodrigc case SIGINT: 58290931Srodrigc case SIGTERM: 59290931Srodrigc dns_shutdown(); 60290931Srodrigc break; 61290931Srodrigc default: 62290931Srodrigc fatalx("unexpected signal"); 63290931Srodrigc } 64290931Srodrigc} 65290931Srodrigc 66290931Srodrigcvoid 67290931Srodrigcdns_shutdown(void) 68290931Srodrigc{ 69290931Srodrigc log_info("dns engine exiting"); 70290931Srodrigc _exit(0); 71290931Srodrigc} 72290931Srodrigc 73290931Srodrigcpid_t 74290931Srodrigcypldap_dns(int pipe_ntp[2], struct passwd *pw) 75290931Srodrigc{ 76290931Srodrigc pid_t pid; 77290931Srodrigc struct event ev_sigint; 78290931Srodrigc struct event ev_sigterm; 79290931Srodrigc struct event ev_sighup; 80290931Srodrigc struct env env; 81290931Srodrigc 82290931Srodrigc switch (pid = fork()) { 83290931Srodrigc case -1: 84290931Srodrigc fatal("cannot fork"); 85290931Srodrigc break; 86290931Srodrigc case 0: 87290931Srodrigc break; 88290931Srodrigc default: 89290931Srodrigc return (pid); 90290931Srodrigc } 91290931Srodrigc 92290931Srodrigc setproctitle("dns engine"); 93290931Srodrigc close(pipe_ntp[0]); 94290931Srodrigc 95290931Srodrigc if (setgroups(1, &pw->pw_gid) || 96290931Srodrigc setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 97290931Srodrigc setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 98290931Srodrigc fatal("can't drop privileges"); 99290931Srodrigc endservent(); 100290931Srodrigc 101290931Srodrigc event_init(); 102290931Srodrigc signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL); 103290931Srodrigc signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL); 104290931Srodrigc signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL); 105290931Srodrigc signal_add(&ev_sigint, NULL); 106290931Srodrigc signal_add(&ev_sigterm, NULL); 107290931Srodrigc signal_add(&ev_sighup, NULL); 108290931Srodrigc 109290931Srodrigc if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 110290931Srodrigc fatal(NULL); 111290931Srodrigc 112290931Srodrigc env.sc_iev->events = EV_READ; 113290931Srodrigc env.sc_iev->data = &env; 114290931Srodrigc imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]); 115290931Srodrigc env.sc_iev->handler = dns_dispatch_imsg; 116290931Srodrigc event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 117290931Srodrigc env.sc_iev->handler, &env); 118290931Srodrigc event_add(&env.sc_iev->ev, NULL); 119290931Srodrigc 120290931Srodrigc event_dispatch(); 121290931Srodrigc dns_shutdown(); 122290931Srodrigc 123290931Srodrigc return (0); 124290931Srodrigc} 125290931Srodrigc 126290931Srodrigcvoid 127290931Srodrigcdns_dispatch_imsg(int fd, short events, void *p) 128290931Srodrigc{ 129290931Srodrigc struct imsg imsg; 130290931Srodrigc int n, cnt; 131290931Srodrigc char *name; 132297907Saraujo struct ypldap_addr_list hn = TAILQ_HEAD_INITIALIZER(hn); 133297907Saraujo struct ypldap_addr *h; 134290931Srodrigc struct ibuf *buf; 135290931Srodrigc struct env *env = p; 136290931Srodrigc struct imsgev *iev = env->sc_iev; 137290931Srodrigc struct imsgbuf *ibuf = &iev->ibuf; 138290931Srodrigc int shut = 0; 139290931Srodrigc 140290931Srodrigc if ((events & (EV_READ | EV_WRITE)) == 0) 141290931Srodrigc fatalx("unknown event"); 142290931Srodrigc 143290931Srodrigc if (events & EV_READ) { 144292270Saraujo if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 145290931Srodrigc fatal("imsg_read error"); 146290931Srodrigc if (n == 0) 147290931Srodrigc shut = 1; 148290931Srodrigc } 149290931Srodrigc if (events & EV_WRITE) { 150290931Srodrigc if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 151290931Srodrigc fatal("msgbuf_write"); 152290931Srodrigc if (n == 0) 153290931Srodrigc shut = 1; 154290931Srodrigc goto done; 155290931Srodrigc } 156290931Srodrigc 157290931Srodrigc for (;;) { 158290931Srodrigc if ((n = imsg_get(ibuf, &imsg)) == -1) 159290931Srodrigc fatal("client_dispatch_imsg: imsg_get error"); 160290931Srodrigc if (n == 0) 161290931Srodrigc break; 162290931Srodrigc 163290931Srodrigc switch (imsg.hdr.type) { 164290931Srodrigc case IMSG_HOST_DNS: 165290931Srodrigc name = imsg.data; 166290931Srodrigc if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 167290931Srodrigc fatalx("invalid IMSG_HOST_DNS received"); 168290931Srodrigc imsg.hdr.len -= 1 + IMSG_HEADER_SIZE; 169290931Srodrigc if (name[imsg.hdr.len] != '\0' || 170290931Srodrigc strlen(name) != imsg.hdr.len) 171290931Srodrigc fatalx("invalid IMSG_HOST_DNS received"); 172290931Srodrigc if ((cnt = host_dns(name, &hn)) == -1) 173290931Srodrigc break; 174290931Srodrigc buf = imsg_create(ibuf, IMSG_HOST_DNS, 175290931Srodrigc imsg.hdr.peerid, 0, 176290931Srodrigc cnt * sizeof(struct sockaddr_storage)); 177290931Srodrigc if (buf == NULL) 178290931Srodrigc break; 179290931Srodrigc if (cnt > 0) { 180297907Saraujo while(!TAILQ_EMPTY(&hn)) { 181297907Saraujo h = TAILQ_FIRST(&hn); 182297907Saraujo TAILQ_REMOVE(&hn, h, next); 183290931Srodrigc imsg_add(buf, &h->ss, sizeof(h->ss)); 184290931Srodrigc free(h); 185290931Srodrigc } 186290931Srodrigc } 187290931Srodrigc 188290931Srodrigc imsg_close(ibuf, buf); 189290931Srodrigc break; 190290931Srodrigc default: 191290931Srodrigc break; 192290931Srodrigc } 193290931Srodrigc imsg_free(&imsg); 194290931Srodrigc } 195290931Srodrigc 196290931Srodrigcdone: 197290931Srodrigc if (!shut) 198290931Srodrigc imsg_event_add(iev); 199290931Srodrigc else { 200290931Srodrigc /* this pipe is dead, so remove the event handler */ 201290931Srodrigc event_del(&iev->ev); 202290931Srodrigc event_loopexit(NULL); 203290931Srodrigc } 204290931Srodrigc} 205290931Srodrigc 206290931Srodrigcint 207297907Saraujohost_dns(const char *s, struct ypldap_addr_list *hn) 208290931Srodrigc{ 209290931Srodrigc struct addrinfo hints, *res0, *res; 210290931Srodrigc int error, cnt = 0; 211290931Srodrigc struct sockaddr_in *sa_in; 212290931Srodrigc struct sockaddr_in6 *sa_in6; 213297907Saraujo struct ypldap_addr *h; 214290931Srodrigc 215309872Saraujo memset(&hints, 0, sizeof(hints)); 216290931Srodrigc hints.ai_family = PF_UNSPEC; 217290931Srodrigc hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 218290931Srodrigc error = getaddrinfo(s, NULL, &hints, &res0); 219290934Srodrigc if (error == EAI_AGAIN || error == EAI_NONAME) 220290931Srodrigc return (0); 221290931Srodrigc if (error) { 222290931Srodrigc log_warnx("could not parse \"%s\": %s", s, 223290931Srodrigc gai_strerror(error)); 224290931Srodrigc return (-1); 225290931Srodrigc } 226290931Srodrigc 227290931Srodrigc for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) { 228290931Srodrigc if (res->ai_family != AF_INET && 229290931Srodrigc res->ai_family != AF_INET6) 230290931Srodrigc continue; 231290931Srodrigc if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL) 232290931Srodrigc fatal(NULL); 233290931Srodrigc h->ss.ss_family = res->ai_family; 234290931Srodrigc if (res->ai_family == AF_INET) { 235290931Srodrigc sa_in = (struct sockaddr_in *)&h->ss; 236290931Srodrigc sa_in->sin_len = sizeof(struct sockaddr_in); 237290931Srodrigc sa_in->sin_addr.s_addr = ((struct sockaddr_in *) 238290931Srodrigc res->ai_addr)->sin_addr.s_addr; 239290931Srodrigc } else { 240290931Srodrigc sa_in6 = (struct sockaddr_in6 *)&h->ss; 241290931Srodrigc sa_in6->sin6_len = sizeof(struct sockaddr_in6); 242290931Srodrigc memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *) 243290931Srodrigc res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 244290931Srodrigc } 245290931Srodrigc 246297907Saraujo TAILQ_INSERT_HEAD(hn, h, next); 247290931Srodrigc cnt++; 248290931Srodrigc } 249290931Srodrigc freeaddrinfo(res0); 250290931Srodrigc return (cnt); 251290931Srodrigc} 252