ypldap_dns.c revision 290934
116125Swpaul/* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */ 216125Swpaul/* $FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 290934 2015-11-16 16:58:09Z rodrigc $ */ 316125Swpaul 416125Swpaul/* 516125Swpaul * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 616125Swpaul * 716125Swpaul * Permission to use, copy, modify, and distribute this software for any 816125Swpaul * purpose with or without fee is hereby granted, provided that the above 916125Swpaul * copyright notice and this permission notice appear in all copies. 1016125Swpaul * 1116125Swpaul * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1216125Swpaul * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1316125Swpaul * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1416125Swpaul * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1516125Swpaul * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 1616125Swpaul * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 1716125Swpaul * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1816125Swpaul */ 1916125Swpaul 2016125Swpaul#include <sys/types.h> 2116125Swpaul#include <sys/socket.h> 2216125Swpaul#include <sys/stat.h> 2316125Swpaul#include <sys/time.h> 2416125Swpaul#include <sys/tree.h> 2516125Swpaul#include <sys/queue.h> 2616125Swpaul 2716125Swpaul#include <netinet/in.h> 2816125Swpaul#include <arpa/nameser.h> 2916125Swpaul 3016125Swpaul#include <netdb.h> 3116125Swpaul#include <pwd.h> 3216125Swpaul#include <errno.h> 33114601Sobrien#include <event.h> 34114601Sobrien#include <resolv.h> 3530378Scharnier#include <poll.h> 3616125Swpaul#include <signal.h> 3730378Scharnier#include <stdlib.h> 3830378Scharnier#include <string.h> 3969793Sobrien#include <unistd.h> 4016125Swpaul#include <limits.h> 4116125Swpaul 4223716Speter#include "ypldap.h" 4316125Swpaul 44129654Sstefanfvolatile sig_atomic_t quit_dns = 0; 4516125Swpaulstruct imsgev *iev_dns; 4616125Swpaul 4716125Swpaulvoid dns_dispatch_imsg(int, short, void *); 4816125Swpaulvoid dns_sig_handler(int, short, void *); 4916125Swpaulvoid dns_shutdown(void); 5016125Swpaulint host_dns(const char *s, struct ypldap_addr **hn); 5116125Swpaul 5216125Swpaulvoid 5316125Swpauldns_sig_handler(int sig, short event, void *p) 5416125Swpaul{ 5516125Swpaul switch (sig) { 5616125Swpaul case SIGINT: 5716125Swpaul case SIGTERM: 5816125Swpaul dns_shutdown(); 5916125Swpaul break; 6016125Swpaul default: 6116125Swpaul fatalx("unexpected signal"); 6216125Swpaul } 6316125Swpaul} 6416125Swpaul 6516125Swpaulvoid 6616125Swpauldns_shutdown(void) 6716125Swpaul{ 6816125Swpaul log_info("dns engine exiting"); 6916125Swpaul _exit(0); 7016125Swpaul} 7116125Swpaul 7216125Swpaulpid_t 7316125Swpaulypldap_dns(int pipe_ntp[2], struct passwd *pw) 7416125Swpaul{ 7516125Swpaul pid_t pid; 7616125Swpaul struct event ev_sigint; 7716125Swpaul struct event ev_sigterm; 7816125Swpaul struct event ev_sighup; 7916125Swpaul struct env env; 8016125Swpaul 8116125Swpaul switch (pid = fork()) { 8290298Sdes case -1: 8390298Sdes fatal("cannot fork"); 8416125Swpaul break; 8516125Swpaul case 0: 8616125Swpaul break; 8762989Skris default: 8816125Swpaul return (pid); 8930378Scharnier } 9016125Swpaul 9162989Skris setproctitle("dns engine"); 9216125Swpaul close(pipe_ntp[0]); 9316125Swpaul 9416125Swpaul if (setgroups(1, &pw->pw_gid) || 9516125Swpaul setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 9616125Swpaul setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 9716125Swpaul fatal("can't drop privileges"); 9816125Swpaul endservent(); 9916125Swpaul 10016125Swpaul event_init(); 10116125Swpaul signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL); 10216125Swpaul signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL); 10316125Swpaul signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL); 10416125Swpaul signal_add(&ev_sigint, NULL); 10516125Swpaul signal_add(&ev_sigterm, NULL); 10616125Swpaul signal_add(&ev_sighup, NULL); 10716125Swpaul 10816125Swpaul if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 10916125Swpaul fatal(NULL); 11016125Swpaul 11116125Swpaul env.sc_iev->events = EV_READ; 11216125Swpaul env.sc_iev->data = &env; 11316125Swpaul imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]); 11416125Swpaul env.sc_iev->handler = dns_dispatch_imsg; 11516125Swpaul event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 11616125Swpaul env.sc_iev->handler, &env); 11716125Swpaul event_add(&env.sc_iev->ev, NULL); 11816125Swpaul 11916125Swpaul event_dispatch(); 12016125Swpaul dns_shutdown(); 12116125Swpaul 12216125Swpaul return (0); 12390298Sdes} 12416125Swpaul 12516125Swpaulvoid 12616125Swpauldns_dispatch_imsg(int fd, short events, void *p) 12716125Swpaul{ 12816125Swpaul struct imsg imsg; 12916125Swpaul int n, cnt; 13016125Swpaul char *name; 13116125Swpaul struct ypldap_addr *h, *hn; 13216125Swpaul struct ibuf *buf; 13316125Swpaul struct env *env = p; 13416125Swpaul struct imsgev *iev = env->sc_iev; 13516125Swpaul struct imsgbuf *ibuf = &iev->ibuf; 13616125Swpaul int shut = 0; 13716125Swpaul 13816125Swpaul if ((events & (EV_READ | EV_WRITE)) == 0) 13916125Swpaul fatalx("unknown event"); 14016125Swpaul 14116125Swpaul if (events & EV_READ) { 14216125Swpaul if ((n = imsg_read(ibuf)) == -1) 14316125Swpaul fatal("imsg_read error"); 14416125Swpaul if (n == 0) 14516125Swpaul shut = 1; 14616125Swpaul } 14716125Swpaul if (events & EV_WRITE) { 14816125Swpaul if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 14930378Scharnier fatal("msgbuf_write"); 15016125Swpaul if (n == 0) 15116125Swpaul shut = 1; 15216125Swpaul goto done; 15316125Swpaul } 15416125Swpaul 15516125Swpaul for (;;) { 15616125Swpaul if ((n = imsg_get(ibuf, &imsg)) == -1) 15716125Swpaul fatal("client_dispatch_imsg: imsg_get error"); 15816125Swpaul if (n == 0) 15916125Swpaul break; 16016125Swpaul 16190298Sdes switch (imsg.hdr.type) { 16216125Swpaul case IMSG_HOST_DNS: 16336642Swpaul name = imsg.data; 16436642Swpaul if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 16516125Swpaul fatalx("invalid IMSG_HOST_DNS received"); 16636642Swpaul imsg.hdr.len -= 1 + IMSG_HEADER_SIZE; 16736642Swpaul if (name[imsg.hdr.len] != '\0' || 16816125Swpaul strlen(name) != imsg.hdr.len) 16916125Swpaul fatalx("invalid IMSG_HOST_DNS received"); 17036642Swpaul if ((cnt = host_dns(name, &hn)) == -1) 17116125Swpaul break; 17216125Swpaul buf = imsg_create(ibuf, IMSG_HOST_DNS, 17316125Swpaul imsg.hdr.peerid, 0, 17416125Swpaul cnt * sizeof(struct sockaddr_storage)); 17516125Swpaul if (buf == NULL) 17616125Swpaul break; 17716125Swpaul if (cnt > 0) { 17816125Swpaul h = hn; 17916125Swpaul while (h != NULL) { 18016125Swpaul imsg_add(buf, &h->ss, sizeof(h->ss)); 18136642Swpaul hn = h->next; 18236642Swpaul free(h); 18336642Swpaul h = hn; 18416125Swpaul } 18516125Swpaul } 18690298Sdes 18790298Sdes imsg_close(ibuf, buf); 18816125Swpaul break; 18930378Scharnier default: 19016125Swpaul break; 19116125Swpaul } 19216125Swpaul imsg_free(&imsg); 19330378Scharnier } 19490298Sdes 19516125Swpauldone: 19630378Scharnier if (!shut) 19716125Swpaul imsg_event_add(iev); 19830378Scharnier else { 19916125Swpaul /* this pipe is dead, so remove the event handler */ 20016125Swpaul event_del(&iev->ev); 20116125Swpaul event_loopexit(NULL); 20216125Swpaul } 20324428Simp} 20490297Sdes 20516125Swpaulint 20616125Swpaulhost_dns(const char *s, struct ypldap_addr **hn) 20716125Swpaul{ 20816125Swpaul struct addrinfo hints, *res0, *res; 20916125Swpaul int error, cnt = 0; 21016125Swpaul struct sockaddr_in *sa_in; 21116125Swpaul struct sockaddr_in6 *sa_in6; 21216125Swpaul struct ypldap_addr *h, *hh = NULL; 21316125Swpaul 21416125Swpaul bzero(&hints, sizeof(hints)); 21516125Swpaul hints.ai_family = PF_UNSPEC; 21616125Swpaul hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 21716125Swpaul error = getaddrinfo(s, NULL, &hints, &res0); 21816125Swpaul if (error == EAI_AGAIN || error == EAI_NONAME) 21916125Swpaul return (0); 22016125Swpaul if (error) { 22116125Swpaul log_warnx("could not parse \"%s\": %s", s, 22216125Swpaul gai_strerror(error)); 22316125Swpaul return (-1); 22416125Swpaul } 22516125Swpaul 22616125Swpaul for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) { 22716125Swpaul if (res->ai_family != AF_INET && 22816125Swpaul res->ai_family != AF_INET6) 22916125Swpaul continue; 23016125Swpaul if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL) 23116125Swpaul fatal(NULL); 23216125Swpaul h->ss.ss_family = res->ai_family; 23316125Swpaul if (res->ai_family == AF_INET) { 23430378Scharnier sa_in = (struct sockaddr_in *)&h->ss; 23530378Scharnier sa_in->sin_len = sizeof(struct sockaddr_in); 23616125Swpaul sa_in->sin_addr.s_addr = ((struct sockaddr_in *) 23716125Swpaul res->ai_addr)->sin_addr.s_addr; 23816125Swpaul } else { 23916125Swpaul sa_in6 = (struct sockaddr_in6 *)&h->ss; 24016125Swpaul sa_in6->sin6_len = sizeof(struct sockaddr_in6); 24169793Sobrien memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *) 24216125Swpaul res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 24316125Swpaul } 24469793Sobrien 24516125Swpaul h->next = hh; 24616125Swpaul hh = h; 24716125Swpaul cnt++; 24816125Swpaul } 24916125Swpaul freeaddrinfo(res0); 25016125Swpaul 25116125Swpaul *hn = hh; 25216125Swpaul return (cnt); 25316125Swpaul} 25416125Swpaul