ypldap_dns.c revision 290931
1169689Skan/*	$OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
2169689Skan/*	$FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 290931 2015-11-16 16:48:43Z rodrigc $ */
3169689Skan
4169689Skan/*
5169689Skan * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
6169689Skan *
7169689Skan * Permission to use, copy, modify, and distribute this software for any
8169689Skan * purpose with or without fee is hereby granted, provided that the above
9169689Skan * copyright notice and this permission notice appear in all copies.
10169689Skan *
11169689Skan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12169689Skan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13169689Skan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14169689Skan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15169689Skan * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16169689Skan * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17169689Skan * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18169689Skan */
19169689Skan
20169689Skan#include <sys/types.h>
21169689Skan#include <sys/socket.h>
22169689Skan#include <sys/stat.h>
23169689Skan#include <sys/time.h>
24169689Skan#include <sys/tree.h>
25169689Skan#include <sys/queue.h>
26169689Skan
27169689Skan#include <netinet/in.h>
28169689Skan#include <arpa/nameser.h>
29169689Skan
30169689Skan#include <netdb.h>
31169689Skan#include <pwd.h>
32169689Skan#include <errno.h>
33169689Skan#include <event.h>
34169689Skan#include <resolv.h>
35169689Skan#include <poll.h>
36169689Skan#include <signal.h>
37169689Skan#include <stdlib.h>
38169689Skan#include <string.h>
39169689Skan#include <unistd.h>
40169689Skan#include <limits.h>
41169689Skan
42169689Skan#include "ypldap.h"
43169689Skan
44169689Skanvolatile sig_atomic_t	 quit_dns = 0;
45169689Skanstruct imsgev		*iev_dns;
46169689Skan
47169689Skanvoid	dns_dispatch_imsg(int, short, void *);
48169689Skanvoid	dns_sig_handler(int, short, void *);
49169689Skanvoid	dns_shutdown(void);
50169689Skanint	host_dns(const char *s, struct ypldap_addr **hn);
51169689Skan
52169689Skanvoid
53169689Skandns_sig_handler(int sig, short event, void *p)
54169689Skan{
55169689Skan	switch (sig) {
56169689Skan	case SIGINT:
57169689Skan	case SIGTERM:
58169689Skan		dns_shutdown();
59169689Skan		break;
60169689Skan	default:
61169689Skan		fatalx("unexpected signal");
62169689Skan	}
63169689Skan}
64169689Skan
65169689Skanvoid
66169689Skandns_shutdown(void)
67169689Skan{
68169689Skan	log_info("dns engine exiting");
69169689Skan	_exit(0);
70169689Skan}
71169689Skan
72169689Skanpid_t
73169689Skanypldap_dns(int pipe_ntp[2], struct passwd *pw)
74169689Skan{
75169689Skan	pid_t			 pid;
76169689Skan	struct event	 ev_sigint;
77169689Skan	struct event	 ev_sigterm;
78169689Skan	struct event	 ev_sighup;
79169689Skan	struct env	 env;
80169689Skan
81169689Skan	switch (pid = fork()) {
82169689Skan	case -1:
83169689Skan		fatal("cannot fork");
84169689Skan		break;
85169689Skan	case 0:
86		break;
87	default:
88		return (pid);
89	}
90
91	setproctitle("dns engine");
92	close(pipe_ntp[0]);
93
94	if (setgroups(1, &pw->pw_gid) ||
95	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
96	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
97		fatal("can't drop privileges");
98	endservent();
99
100	event_init();
101	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
102	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
103	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
104	signal_add(&ev_sigint, NULL);
105	signal_add(&ev_sigterm, NULL);
106	signal_add(&ev_sighup, NULL);
107
108	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
109		fatal(NULL);
110
111	env.sc_iev->events = EV_READ;
112	env.sc_iev->data = &env;
113	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
114	env.sc_iev->handler = dns_dispatch_imsg;
115	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
116	    env.sc_iev->handler, &env);
117	event_add(&env.sc_iev->ev, NULL);
118
119	event_dispatch();
120	dns_shutdown();
121
122	return (0);
123}
124
125void
126dns_dispatch_imsg(int fd, short events, void *p)
127{
128	struct imsg		 imsg;
129	int			 n, cnt;
130	char			*name;
131	struct ypldap_addr	*h, *hn;
132	struct ibuf		*buf;
133	struct env		*env = p;
134	struct imsgev		*iev = env->sc_iev;
135	struct imsgbuf		*ibuf = &iev->ibuf;
136	int			 shut = 0;
137
138	if ((events & (EV_READ | EV_WRITE)) == 0)
139		fatalx("unknown event");
140
141	if (events & EV_READ) {
142		if ((n = imsg_read(ibuf)) == -1)
143			fatal("imsg_read error");
144		if (n == 0)
145			shut = 1;
146	}
147	if (events & EV_WRITE) {
148		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
149			fatal("msgbuf_write");
150		if (n == 0)
151			shut = 1;
152		goto done;
153	}
154
155	for (;;) {
156		if ((n = imsg_get(ibuf, &imsg)) == -1)
157			fatal("client_dispatch_imsg: imsg_get error");
158		if (n == 0)
159			break;
160
161		switch (imsg.hdr.type) {
162		case IMSG_HOST_DNS:
163			name = imsg.data;
164			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
165				fatalx("invalid IMSG_HOST_DNS received");
166			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
167			if (name[imsg.hdr.len] != '\0' ||
168			    strlen(name) != imsg.hdr.len)
169				fatalx("invalid IMSG_HOST_DNS received");
170			if ((cnt = host_dns(name, &hn)) == -1)
171				break;
172			buf = imsg_create(ibuf, IMSG_HOST_DNS,
173			    imsg.hdr.peerid, 0,
174			    cnt * sizeof(struct sockaddr_storage));
175			if (buf == NULL)
176				break;
177			if (cnt > 0) {
178				h = hn;
179				while (h != NULL) {
180					imsg_add(buf, &h->ss, sizeof(h->ss));
181					hn = h->next;
182					free(h);
183					h = hn;
184				}
185			}
186
187			imsg_close(ibuf, buf);
188			break;
189		default:
190			break;
191		}
192		imsg_free(&imsg);
193	}
194
195done:
196	if (!shut)
197		imsg_event_add(iev);
198	else {
199		/* this pipe is dead, so remove the event handler */
200		event_del(&iev->ev);
201		event_loopexit(NULL);
202	}
203}
204
205int
206host_dns(const char *s, struct ypldap_addr **hn)
207{
208	struct addrinfo		 hints, *res0, *res;
209	int			 error, cnt = 0;
210	struct sockaddr_in	*sa_in;
211	struct sockaddr_in6	*sa_in6;
212	struct ypldap_addr	*h, *hh = NULL;
213
214	bzero(&hints, sizeof(hints));
215	hints.ai_family = PF_UNSPEC;
216	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
217	error = getaddrinfo(s, NULL, &hints, &res0);
218	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
219			return (0);
220	if (error) {
221		log_warnx("could not parse \"%s\": %s", s,
222		    gai_strerror(error));
223		return (-1);
224	}
225
226	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
227		if (res->ai_family != AF_INET &&
228		    res->ai_family != AF_INET6)
229			continue;
230		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
231			fatal(NULL);
232		h->ss.ss_family = res->ai_family;
233		if (res->ai_family == AF_INET) {
234			sa_in = (struct sockaddr_in *)&h->ss;
235			sa_in->sin_len = sizeof(struct sockaddr_in);
236			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
237			    res->ai_addr)->sin_addr.s_addr;
238		} else {
239			sa_in6 = (struct sockaddr_in6 *)&h->ss;
240			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
241			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
242			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
243		}
244
245		h->next = hh;
246		hh = h;
247		cnt++;
248	}
249	freeaddrinfo(res0);
250
251	*hn = hh;
252	return (cnt);
253}
254