1d2078e3rodrigc/*	$OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
2d2078e3rodrigc/*	$FreeBSD$ */
3d2078e3rodrigc
4d2078e3rodrigc/*
5d2078e3rodrigc * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
6d2078e3rodrigc *
7d2078e3rodrigc * Permission to use, copy, modify, and distribute this software for any
8d2078e3rodrigc * purpose with or without fee is hereby granted, provided that the above
9d2078e3rodrigc * copyright notice and this permission notice appear in all copies.
10d2078e3rodrigc *
11d2078e3rodrigc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12d2078e3rodrigc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13d2078e3rodrigc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14d2078e3rodrigc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15d2078e3rodrigc * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16d2078e3rodrigc * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17d2078e3rodrigc * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18d2078e3rodrigc */
19d2078e3rodrigc
20d2078e3rodrigc#include <sys/types.h>
211ca8285rodrigc#include <sys/param.h>
22d2078e3rodrigc#include <sys/socket.h>
23d2078e3rodrigc#include <sys/stat.h>
24d2078e3rodrigc#include <sys/time.h>
25d2078e3rodrigc#include <sys/tree.h>
26d2078e3rodrigc#include <sys/queue.h>
27d2078e3rodrigc
28d2078e3rodrigc#include <netinet/in.h>
29d2078e3rodrigc#include <arpa/nameser.h>
30d2078e3rodrigc
31d2078e3rodrigc#include <netdb.h>
32d2078e3rodrigc#include <pwd.h>
33d2078e3rodrigc#include <errno.h>
34d2078e3rodrigc#include <event.h>
35d2078e3rodrigc#include <resolv.h>
36d2078e3rodrigc#include <poll.h>
37d2078e3rodrigc#include <signal.h>
38d2078e3rodrigc#include <stdlib.h>
39d2078e3rodrigc#include <string.h>
40d2078e3rodrigc#include <unistd.h>
41d2078e3rodrigc#include <limits.h>
42d2078e3rodrigc
43d2078e3rodrigc#include "ypldap.h"
44d2078e3rodrigc
45d2078e3rodrigcvolatile sig_atomic_t	 quit_dns = 0;
46d2078e3rodrigcstruct imsgev		*iev_dns;
47d2078e3rodrigc
48d2078e3rodrigcvoid	dns_dispatch_imsg(int, short, void *);
49d2078e3rodrigcvoid	dns_sig_handler(int, short, void *);
50d2078e3rodrigcvoid	dns_shutdown(void);
517e0cb41araujoint	host_dns(const char *, struct ypldap_addr_list *);
52d2078e3rodrigc
53d2078e3rodrigcvoid
54d2078e3rodrigcdns_sig_handler(int sig, short event, void *p)
55d2078e3rodrigc{
56d2078e3rodrigc	switch (sig) {
57d2078e3rodrigc	case SIGINT:
58d2078e3rodrigc	case SIGTERM:
59d2078e3rodrigc		dns_shutdown();
60d2078e3rodrigc		break;
61d2078e3rodrigc	default:
62d2078e3rodrigc		fatalx("unexpected signal");
63d2078e3rodrigc	}
64d2078e3rodrigc}
65d2078e3rodrigc
66d2078e3rodrigcvoid
67d2078e3rodrigcdns_shutdown(void)
68d2078e3rodrigc{
69d2078e3rodrigc	log_info("dns engine exiting");
70d2078e3rodrigc	_exit(0);
71d2078e3rodrigc}
72d2078e3rodrigc
73d2078e3rodrigcpid_t
74d2078e3rodrigcypldap_dns(int pipe_ntp[2], struct passwd *pw)
75d2078e3rodrigc{
76d2078e3rodrigc	pid_t			 pid;
77d2078e3rodrigc	struct event	 ev_sigint;
78d2078e3rodrigc	struct event	 ev_sigterm;
79d2078e3rodrigc	struct event	 ev_sighup;
80d2078e3rodrigc	struct env	 env;
81d2078e3rodrigc
82d2078e3rodrigc	switch (pid = fork()) {
83d2078e3rodrigc	case -1:
84d2078e3rodrigc		fatal("cannot fork");
85d2078e3rodrigc		break;
86d2078e3rodrigc	case 0:
87d2078e3rodrigc		break;
88d2078e3rodrigc	default:
89d2078e3rodrigc		return (pid);
90d2078e3rodrigc	}
91d2078e3rodrigc
92d2078e3rodrigc	setproctitle("dns engine");
93d2078e3rodrigc	close(pipe_ntp[0]);
94d2078e3rodrigc
95d2078e3rodrigc	if (setgroups(1, &pw->pw_gid) ||
96d2078e3rodrigc	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
97d2078e3rodrigc	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
98d2078e3rodrigc		fatal("can't drop privileges");
99d2078e3rodrigc	endservent();
100d2078e3rodrigc
101d2078e3rodrigc	event_init();
102d2078e3rodrigc	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
103d2078e3rodrigc	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
104d2078e3rodrigc	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
105d2078e3rodrigc	signal_add(&ev_sigint, NULL);
106d2078e3rodrigc	signal_add(&ev_sigterm, NULL);
107d2078e3rodrigc	signal_add(&ev_sighup, NULL);
108d2078e3rodrigc
109d2078e3rodrigc	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
110d2078e3rodrigc		fatal(NULL);
111d2078e3rodrigc
112d2078e3rodrigc	env.sc_iev->events = EV_READ;
113d2078e3rodrigc	env.sc_iev->data = &env;
114d2078e3rodrigc	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
115d2078e3rodrigc	env.sc_iev->handler = dns_dispatch_imsg;
116d2078e3rodrigc	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
117d2078e3rodrigc	    env.sc_iev->handler, &env);
118d2078e3rodrigc	event_add(&env.sc_iev->ev, NULL);
119d2078e3rodrigc
120d2078e3rodrigc	event_dispatch();
121d2078e3rodrigc	dns_shutdown();
122d2078e3rodrigc
123d2078e3rodrigc	return (0);
124d2078e3rodrigc}
125d2078e3rodrigc
126d2078e3rodrigcvoid
127d2078e3rodrigcdns_dispatch_imsg(int fd, short events, void *p)
128d2078e3rodrigc{
129d2078e3rodrigc	struct imsg		 imsg;
130d2078e3rodrigc	int			 n, cnt;
131d2078e3rodrigc	char			*name;
1327e0cb41araujo	struct ypldap_addr_list	hn = TAILQ_HEAD_INITIALIZER(hn);
1337e0cb41araujo	struct ypldap_addr	*h;
134d2078e3rodrigc	struct ibuf		*buf;
135d2078e3rodrigc	struct env		*env = p;
136d2078e3rodrigc	struct imsgev		*iev = env->sc_iev;
137d2078e3rodrigc	struct imsgbuf		*ibuf = &iev->ibuf;
138d2078e3rodrigc	int			 shut = 0;
139d2078e3rodrigc
140d2078e3rodrigc	if ((events & (EV_READ | EV_WRITE)) == 0)
141d2078e3rodrigc		fatalx("unknown event");
142d2078e3rodrigc
143d2078e3rodrigc	if (events & EV_READ) {
14499a0984araujo		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
145d2078e3rodrigc			fatal("imsg_read error");
146d2078e3rodrigc		if (n == 0)
147d2078e3rodrigc			shut = 1;
148d2078e3rodrigc	}
149d2078e3rodrigc	if (events & EV_WRITE) {
150d2078e3rodrigc		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
151d2078e3rodrigc			fatal("msgbuf_write");
152d2078e3rodrigc		if (n == 0)
153d2078e3rodrigc			shut = 1;
154d2078e3rodrigc		goto done;
155d2078e3rodrigc	}
156d2078e3rodrigc
157d2078e3rodrigc	for (;;) {
158d2078e3rodrigc		if ((n = imsg_get(ibuf, &imsg)) == -1)
159d2078e3rodrigc			fatal("client_dispatch_imsg: imsg_get error");
160d2078e3rodrigc		if (n == 0)
161d2078e3rodrigc			break;
162d2078e3rodrigc
163d2078e3rodrigc		switch (imsg.hdr.type) {
164d2078e3rodrigc		case IMSG_HOST_DNS:
165d2078e3rodrigc			name = imsg.data;
166d2078e3rodrigc			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
167d2078e3rodrigc				fatalx("invalid IMSG_HOST_DNS received");
168d2078e3rodrigc			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
169d2078e3rodrigc			if (name[imsg.hdr.len] != '\0' ||
170d2078e3rodrigc			    strlen(name) != imsg.hdr.len)
171d2078e3rodrigc				fatalx("invalid IMSG_HOST_DNS received");
172d2078e3rodrigc			if ((cnt = host_dns(name, &hn)) == -1)
173d2078e3rodrigc				break;
174d2078e3rodrigc			buf = imsg_create(ibuf, IMSG_HOST_DNS,
175d2078e3rodrigc			    imsg.hdr.peerid, 0,
176d2078e3rodrigc			    cnt * sizeof(struct sockaddr_storage));
177d2078e3rodrigc			if (buf == NULL)
178d2078e3rodrigc				break;
179d2078e3rodrigc			if (cnt > 0) {
1807e0cb41araujo				while(!TAILQ_EMPTY(&hn)) {
1817e0cb41araujo					h = TAILQ_FIRST(&hn);
1827e0cb41araujo					TAILQ_REMOVE(&hn, h, next);
183d2078e3rodrigc					imsg_add(buf, &h->ss, sizeof(h->ss));
184d2078e3rodrigc					free(h);
185d2078e3rodrigc				}
186d2078e3rodrigc			}
187d2078e3rodrigc
188d2078e3rodrigc			imsg_close(ibuf, buf);
189d2078e3rodrigc			break;
190d2078e3rodrigc		default:
191d2078e3rodrigc			break;
192d2078e3rodrigc		}
193d2078e3rodrigc		imsg_free(&imsg);
194d2078e3rodrigc	}
195d2078e3rodrigc
196d2078e3rodrigcdone:
197d2078e3rodrigc	if (!shut)
198d2078e3rodrigc		imsg_event_add(iev);
199d2078e3rodrigc	else {
200d2078e3rodrigc		/* this pipe is dead, so remove the event handler */
201d2078e3rodrigc		event_del(&iev->ev);
202d2078e3rodrigc		event_loopexit(NULL);
203d2078e3rodrigc	}
204d2078e3rodrigc}
205d2078e3rodrigc
206d2078e3rodrigcint
2077e0cb41araujohost_dns(const char *s, struct ypldap_addr_list *hn)
208d2078e3rodrigc{
209d2078e3rodrigc	struct addrinfo		 hints, *res0, *res;
210d2078e3rodrigc	int			 error, cnt = 0;
211d2078e3rodrigc	struct sockaddr_in	*sa_in;
212d2078e3rodrigc	struct sockaddr_in6	*sa_in6;
2137e0cb41araujo	struct ypldap_addr	*h;
214d2078e3rodrigc
215dcae55daraujo	memset(&hints, 0, sizeof(hints));
216d2078e3rodrigc	hints.ai_family = PF_UNSPEC;
217d2078e3rodrigc	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
218d2078e3rodrigc	error = getaddrinfo(s, NULL, &hints, &res0);
2199dc16cbrodrigc	if (error == EAI_AGAIN || error == EAI_NONAME)
220d2078e3rodrigc			return (0);
221d2078e3rodrigc	if (error) {
222d2078e3rodrigc		log_warnx("could not parse \"%s\": %s", s,
223d2078e3rodrigc		    gai_strerror(error));
224d2078e3rodrigc		return (-1);
225d2078e3rodrigc	}
226d2078e3rodrigc
227d2078e3rodrigc	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
228d2078e3rodrigc		if (res->ai_family != AF_INET &&
229d2078e3rodrigc		    res->ai_family != AF_INET6)
230d2078e3rodrigc			continue;
231d2078e3rodrigc		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
232d2078e3rodrigc			fatal(NULL);
233d2078e3rodrigc		h->ss.ss_family = res->ai_family;
234d2078e3rodrigc		if (res->ai_family == AF_INET) {
235d2078e3rodrigc			sa_in = (struct sockaddr_in *)&h->ss;
236d2078e3rodrigc			sa_in->sin_len = sizeof(struct sockaddr_in);
237d2078e3rodrigc			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
238d2078e3rodrigc			    res->ai_addr)->sin_addr.s_addr;
239d2078e3rodrigc		} else {
240d2078e3rodrigc			sa_in6 = (struct sockaddr_in6 *)&h->ss;
241d2078e3rodrigc			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
242d2078e3rodrigc			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
243d2078e3rodrigc			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
244d2078e3rodrigc		}
245d2078e3rodrigc
2467e0cb41araujo		TAILQ_INSERT_HEAD(hn, h, next);
247d2078e3rodrigc		cnt++;
248d2078e3rodrigc	}
249d2078e3rodrigc	freeaddrinfo(res0);
250d2078e3rodrigc	return (cnt);
251d2078e3rodrigc}
252