xref: /freebsd/usr.sbin/ypldap/ypldap_dns.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
19e7c127fSCraig Rodrigues /*	$OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
29e7c127fSCraig Rodrigues 
39e7c127fSCraig Rodrigues /*
49e7c127fSCraig Rodrigues  * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
59e7c127fSCraig Rodrigues  *
69e7c127fSCraig Rodrigues  * Permission to use, copy, modify, and distribute this software for any
79e7c127fSCraig Rodrigues  * purpose with or without fee is hereby granted, provided that the above
89e7c127fSCraig Rodrigues  * copyright notice and this permission notice appear in all copies.
99e7c127fSCraig Rodrigues  *
109e7c127fSCraig Rodrigues  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119e7c127fSCraig Rodrigues  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129e7c127fSCraig Rodrigues  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
139e7c127fSCraig Rodrigues  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149e7c127fSCraig Rodrigues  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
159e7c127fSCraig Rodrigues  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
169e7c127fSCraig Rodrigues  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179e7c127fSCraig Rodrigues  */
189e7c127fSCraig Rodrigues 
199e7c127fSCraig Rodrigues #include <sys/types.h>
2066b5c05dSCraig Rodrigues #include <sys/param.h>
219e7c127fSCraig Rodrigues #include <sys/socket.h>
229e7c127fSCraig Rodrigues #include <sys/stat.h>
239e7c127fSCraig Rodrigues #include <sys/time.h>
249e7c127fSCraig Rodrigues #include <sys/tree.h>
259e7c127fSCraig Rodrigues #include <sys/queue.h>
269e7c127fSCraig Rodrigues 
279e7c127fSCraig Rodrigues #include <netinet/in.h>
289e7c127fSCraig Rodrigues #include <arpa/nameser.h>
299e7c127fSCraig Rodrigues 
309e7c127fSCraig Rodrigues #include <netdb.h>
319e7c127fSCraig Rodrigues #include <pwd.h>
329e7c127fSCraig Rodrigues #include <errno.h>
339e7c127fSCraig Rodrigues #include <event.h>
349e7c127fSCraig Rodrigues #include <resolv.h>
359e7c127fSCraig Rodrigues #include <poll.h>
369e7c127fSCraig Rodrigues #include <signal.h>
379e7c127fSCraig Rodrigues #include <stdlib.h>
389e7c127fSCraig Rodrigues #include <string.h>
399e7c127fSCraig Rodrigues #include <unistd.h>
409e7c127fSCraig Rodrigues #include <limits.h>
419e7c127fSCraig Rodrigues 
429e7c127fSCraig Rodrigues #include "ypldap.h"
439e7c127fSCraig Rodrigues 
449e7c127fSCraig Rodrigues volatile sig_atomic_t	 quit_dns = 0;
459e7c127fSCraig Rodrigues struct imsgev		*iev_dns;
469e7c127fSCraig Rodrigues 
479e7c127fSCraig Rodrigues void	dns_dispatch_imsg(int, short, void *);
489e7c127fSCraig Rodrigues void	dns_sig_handler(int, short, void *);
499e7c127fSCraig Rodrigues void	dns_shutdown(void);
50eaf209deSMarcelo Araujo int	host_dns(const char *, struct ypldap_addr_list *);
519e7c127fSCraig Rodrigues 
529e7c127fSCraig Rodrigues void
dns_sig_handler(int sig,short event,void * p)539e7c127fSCraig Rodrigues dns_sig_handler(int sig, short event, void *p)
549e7c127fSCraig Rodrigues {
559e7c127fSCraig Rodrigues 	switch (sig) {
569e7c127fSCraig Rodrigues 	case SIGINT:
579e7c127fSCraig Rodrigues 	case SIGTERM:
589e7c127fSCraig Rodrigues 		dns_shutdown();
599e7c127fSCraig Rodrigues 		break;
609e7c127fSCraig Rodrigues 	default:
619e7c127fSCraig Rodrigues 		fatalx("unexpected signal");
629e7c127fSCraig Rodrigues 	}
639e7c127fSCraig Rodrigues }
649e7c127fSCraig Rodrigues 
659e7c127fSCraig Rodrigues void
dns_shutdown(void)669e7c127fSCraig Rodrigues dns_shutdown(void)
679e7c127fSCraig Rodrigues {
689e7c127fSCraig Rodrigues 	log_info("dns engine exiting");
699e7c127fSCraig Rodrigues 	_exit(0);
709e7c127fSCraig Rodrigues }
719e7c127fSCraig Rodrigues 
729e7c127fSCraig Rodrigues pid_t
ypldap_dns(int pipe_ntp[2],struct passwd * pw)739e7c127fSCraig Rodrigues ypldap_dns(int pipe_ntp[2], struct passwd *pw)
749e7c127fSCraig Rodrigues {
759e7c127fSCraig Rodrigues 	pid_t			 pid;
769e7c127fSCraig Rodrigues 	struct event	 ev_sigint;
779e7c127fSCraig Rodrigues 	struct event	 ev_sigterm;
789e7c127fSCraig Rodrigues 	struct event	 ev_sighup;
799e7c127fSCraig Rodrigues 	struct env	 env;
809e7c127fSCraig Rodrigues 
819e7c127fSCraig Rodrigues 	switch (pid = fork()) {
829e7c127fSCraig Rodrigues 	case -1:
839e7c127fSCraig Rodrigues 		fatal("cannot fork");
849e7c127fSCraig Rodrigues 		break;
859e7c127fSCraig Rodrigues 	case 0:
869e7c127fSCraig Rodrigues 		break;
879e7c127fSCraig Rodrigues 	default:
889e7c127fSCraig Rodrigues 		return (pid);
899e7c127fSCraig Rodrigues 	}
909e7c127fSCraig Rodrigues 
919e7c127fSCraig Rodrigues 	setproctitle("dns engine");
929e7c127fSCraig Rodrigues 	close(pipe_ntp[0]);
939e7c127fSCraig Rodrigues 
949e7c127fSCraig Rodrigues 	if (setgroups(1, &pw->pw_gid) ||
959e7c127fSCraig Rodrigues 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
969e7c127fSCraig Rodrigues 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
979e7c127fSCraig Rodrigues 		fatal("can't drop privileges");
989e7c127fSCraig Rodrigues 	endservent();
999e7c127fSCraig Rodrigues 
1009e7c127fSCraig Rodrigues 	event_init();
1019e7c127fSCraig Rodrigues 	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
1029e7c127fSCraig Rodrigues 	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
1039e7c127fSCraig Rodrigues 	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
1049e7c127fSCraig Rodrigues 	signal_add(&ev_sigint, NULL);
1059e7c127fSCraig Rodrigues 	signal_add(&ev_sigterm, NULL);
1069e7c127fSCraig Rodrigues 	signal_add(&ev_sighup, NULL);
1079e7c127fSCraig Rodrigues 
1089e7c127fSCraig Rodrigues 	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
1099e7c127fSCraig Rodrigues 		fatal(NULL);
1109e7c127fSCraig Rodrigues 
1119e7c127fSCraig Rodrigues 	env.sc_iev->events = EV_READ;
1129e7c127fSCraig Rodrigues 	env.sc_iev->data = &env;
1139e7c127fSCraig Rodrigues 	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
1149e7c127fSCraig Rodrigues 	env.sc_iev->handler = dns_dispatch_imsg;
1159e7c127fSCraig Rodrigues 	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
1169e7c127fSCraig Rodrigues 	    env.sc_iev->handler, &env);
1179e7c127fSCraig Rodrigues 	event_add(&env.sc_iev->ev, NULL);
1189e7c127fSCraig Rodrigues 
1199e7c127fSCraig Rodrigues 	event_dispatch();
1209e7c127fSCraig Rodrigues 	dns_shutdown();
1219e7c127fSCraig Rodrigues 
1229e7c127fSCraig Rodrigues 	return (0);
1239e7c127fSCraig Rodrigues }
1249e7c127fSCraig Rodrigues 
1259e7c127fSCraig Rodrigues void
dns_dispatch_imsg(int fd,short events,void * p)1269e7c127fSCraig Rodrigues dns_dispatch_imsg(int fd, short events, void *p)
1279e7c127fSCraig Rodrigues {
1289e7c127fSCraig Rodrigues 	struct imsg		 imsg;
1299e7c127fSCraig Rodrigues 	int			 n, cnt;
1309e7c127fSCraig Rodrigues 	char			*name;
131eaf209deSMarcelo Araujo 	struct ypldap_addr_list	hn = TAILQ_HEAD_INITIALIZER(hn);
132eaf209deSMarcelo Araujo 	struct ypldap_addr	*h;
1339e7c127fSCraig Rodrigues 	struct ibuf		*buf;
1349e7c127fSCraig Rodrigues 	struct env		*env = p;
1359e7c127fSCraig Rodrigues 	struct imsgev		*iev = env->sc_iev;
1369e7c127fSCraig Rodrigues 	struct imsgbuf		*ibuf = &iev->ibuf;
1379e7c127fSCraig Rodrigues 	int			 shut = 0;
1389e7c127fSCraig Rodrigues 
1399e7c127fSCraig Rodrigues 	if ((events & (EV_READ | EV_WRITE)) == 0)
1409e7c127fSCraig Rodrigues 		fatalx("unknown event");
1419e7c127fSCraig Rodrigues 
1429e7c127fSCraig Rodrigues 	if (events & EV_READ) {
1437433efffSMarcelo Araujo 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1449e7c127fSCraig Rodrigues 			fatal("imsg_read error");
1459e7c127fSCraig Rodrigues 		if (n == 0)
1469e7c127fSCraig Rodrigues 			shut = 1;
1479e7c127fSCraig Rodrigues 	}
1489e7c127fSCraig Rodrigues 	if (events & EV_WRITE) {
1499e7c127fSCraig Rodrigues 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
1509e7c127fSCraig Rodrigues 			fatal("msgbuf_write");
1519e7c127fSCraig Rodrigues 		if (n == 0)
1529e7c127fSCraig Rodrigues 			shut = 1;
1539e7c127fSCraig Rodrigues 		goto done;
1549e7c127fSCraig Rodrigues 	}
1559e7c127fSCraig Rodrigues 
1569e7c127fSCraig Rodrigues 	for (;;) {
1579e7c127fSCraig Rodrigues 		if ((n = imsg_get(ibuf, &imsg)) == -1)
1589e7c127fSCraig Rodrigues 			fatal("client_dispatch_imsg: imsg_get error");
1599e7c127fSCraig Rodrigues 		if (n == 0)
1609e7c127fSCraig Rodrigues 			break;
1619e7c127fSCraig Rodrigues 
1629e7c127fSCraig Rodrigues 		switch (imsg.hdr.type) {
1639e7c127fSCraig Rodrigues 		case IMSG_HOST_DNS:
1649e7c127fSCraig Rodrigues 			name = imsg.data;
1659e7c127fSCraig Rodrigues 			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
1669e7c127fSCraig Rodrigues 				fatalx("invalid IMSG_HOST_DNS received");
1679e7c127fSCraig Rodrigues 			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
1689e7c127fSCraig Rodrigues 			if (name[imsg.hdr.len] != '\0' ||
1699e7c127fSCraig Rodrigues 			    strlen(name) != imsg.hdr.len)
1709e7c127fSCraig Rodrigues 				fatalx("invalid IMSG_HOST_DNS received");
1719e7c127fSCraig Rodrigues 			if ((cnt = host_dns(name, &hn)) == -1)
1729e7c127fSCraig Rodrigues 				break;
1739e7c127fSCraig Rodrigues 			buf = imsg_create(ibuf, IMSG_HOST_DNS,
1749e7c127fSCraig Rodrigues 			    imsg.hdr.peerid, 0,
1759e7c127fSCraig Rodrigues 			    cnt * sizeof(struct sockaddr_storage));
1769e7c127fSCraig Rodrigues 			if (buf == NULL)
1779e7c127fSCraig Rodrigues 				break;
1789e7c127fSCraig Rodrigues 			if (cnt > 0) {
179eaf209deSMarcelo Araujo 				while(!TAILQ_EMPTY(&hn)) {
180eaf209deSMarcelo Araujo 					h = TAILQ_FIRST(&hn);
181eaf209deSMarcelo Araujo 					TAILQ_REMOVE(&hn, h, next);
1829e7c127fSCraig Rodrigues 					imsg_add(buf, &h->ss, sizeof(h->ss));
1839e7c127fSCraig Rodrigues 					free(h);
1849e7c127fSCraig Rodrigues 				}
1859e7c127fSCraig Rodrigues 			}
1869e7c127fSCraig Rodrigues 
1879e7c127fSCraig Rodrigues 			imsg_close(ibuf, buf);
1889e7c127fSCraig Rodrigues 			break;
1899e7c127fSCraig Rodrigues 		default:
1909e7c127fSCraig Rodrigues 			break;
1919e7c127fSCraig Rodrigues 		}
1929e7c127fSCraig Rodrigues 		imsg_free(&imsg);
1939e7c127fSCraig Rodrigues 	}
1949e7c127fSCraig Rodrigues 
1959e7c127fSCraig Rodrigues done:
1969e7c127fSCraig Rodrigues 	if (!shut)
1979e7c127fSCraig Rodrigues 		imsg_event_add(iev);
1989e7c127fSCraig Rodrigues 	else {
1999e7c127fSCraig Rodrigues 		/* this pipe is dead, so remove the event handler */
2009e7c127fSCraig Rodrigues 		event_del(&iev->ev);
2019e7c127fSCraig Rodrigues 		event_loopexit(NULL);
2029e7c127fSCraig Rodrigues 	}
2039e7c127fSCraig Rodrigues }
2049e7c127fSCraig Rodrigues 
2059e7c127fSCraig Rodrigues int
host_dns(const char * s,struct ypldap_addr_list * hn)206eaf209deSMarcelo Araujo host_dns(const char *s, struct ypldap_addr_list *hn)
2079e7c127fSCraig Rodrigues {
2089e7c127fSCraig Rodrigues 	struct addrinfo		 hints, *res0, *res;
2099e7c127fSCraig Rodrigues 	int			 error, cnt = 0;
2109e7c127fSCraig Rodrigues 	struct sockaddr_in	*sa_in;
2119e7c127fSCraig Rodrigues 	struct sockaddr_in6	*sa_in6;
212eaf209deSMarcelo Araujo 	struct ypldap_addr	*h;
2139e7c127fSCraig Rodrigues 
214*bbdfc8f1SMarcelo Araujo 	memset(&hints, 0, sizeof(hints));
2159e7c127fSCraig Rodrigues 	hints.ai_family = PF_UNSPEC;
2169e7c127fSCraig Rodrigues 	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
2179e7c127fSCraig Rodrigues 	error = getaddrinfo(s, NULL, &hints, &res0);
218468878d9SCraig Rodrigues 	if (error == EAI_AGAIN || error == EAI_NONAME)
2199e7c127fSCraig Rodrigues 			return (0);
2209e7c127fSCraig Rodrigues 	if (error) {
2219e7c127fSCraig Rodrigues 		log_warnx("could not parse \"%s\": %s", s,
2229e7c127fSCraig Rodrigues 		    gai_strerror(error));
2239e7c127fSCraig Rodrigues 		return (-1);
2249e7c127fSCraig Rodrigues 	}
2259e7c127fSCraig Rodrigues 
2269e7c127fSCraig Rodrigues 	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
2279e7c127fSCraig Rodrigues 		if (res->ai_family != AF_INET &&
2289e7c127fSCraig Rodrigues 		    res->ai_family != AF_INET6)
2299e7c127fSCraig Rodrigues 			continue;
2309e7c127fSCraig Rodrigues 		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
2319e7c127fSCraig Rodrigues 			fatal(NULL);
2329e7c127fSCraig Rodrigues 		h->ss.ss_family = res->ai_family;
2339e7c127fSCraig Rodrigues 		if (res->ai_family == AF_INET) {
2349e7c127fSCraig Rodrigues 			sa_in = (struct sockaddr_in *)&h->ss;
2359e7c127fSCraig Rodrigues 			sa_in->sin_len = sizeof(struct sockaddr_in);
2369e7c127fSCraig Rodrigues 			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
2379e7c127fSCraig Rodrigues 			    res->ai_addr)->sin_addr.s_addr;
2389e7c127fSCraig Rodrigues 		} else {
2399e7c127fSCraig Rodrigues 			sa_in6 = (struct sockaddr_in6 *)&h->ss;
2409e7c127fSCraig Rodrigues 			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
2419e7c127fSCraig Rodrigues 			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
2429e7c127fSCraig Rodrigues 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
2439e7c127fSCraig Rodrigues 		}
2449e7c127fSCraig Rodrigues 
245eaf209deSMarcelo Araujo 		TAILQ_INSERT_HEAD(hn, h, next);
2469e7c127fSCraig Rodrigues 		cnt++;
2479e7c127fSCraig Rodrigues 	}
2489e7c127fSCraig Rodrigues 	freeaddrinfo(res0);
2499e7c127fSCraig Rodrigues 	return (cnt);
2509e7c127fSCraig Rodrigues }
251