ypldap_dns.c revision 290937
1168404Spjd/*	$OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
2168404Spjd/*	$FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 290937 2015-11-16 17:06:33Z rodrigc $ */
3168404Spjd
4168404Spjd/*
5168404Spjd * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
6168404Spjd *
7168404Spjd * Permission to use, copy, modify, and distribute this software for any
8168404Spjd * purpose with or without fee is hereby granted, provided that the above
9168404Spjd * copyright notice and this permission notice appear in all copies.
10168404Spjd *
11168404Spjd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12168404Spjd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13168404Spjd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14168404Spjd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15168404Spjd * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16168404Spjd * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17168404Spjd * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18168404Spjd */
19168404Spjd
20168404Spjd#include <sys/types.h>
21168404Spjd#include <sys/param.h>
22219089Spjd#include <sys/socket.h>
23226512Smm#include <sys/stat.h>
24284593Savg#include <sys/time.h>
25226512Smm#include <sys/tree.h>
26168404Spjd#include <sys/queue.h>
27168404Spjd
28168404Spjd#include <netinet/in.h>
29168404Spjd#include <arpa/nameser.h>
30168404Spjd
31168404Spjd#include <netdb.h>
32168404Spjd#include <pwd.h>
33168404Spjd#include <errno.h>
34168404Spjd#include <event.h>
35168404Spjd#include <resolv.h>
36168404Spjd#include <poll.h>
37219089Spjd#include <signal.h>
38219089Spjd#include <stdlib.h>
39168404Spjd#include <string.h>
40219089Spjd#include <unistd.h>
41168404Spjd#include <limits.h>
42168404Spjd
43168404Spjd#include "ypldap.h"
44168404Spjd
45168404Spjdvolatile sig_atomic_t	 quit_dns = 0;
46168404Spjdstruct imsgev		*iev_dns;
47168404Spjd
48168404Spjdvoid	dns_dispatch_imsg(int, short, void *);
49168404Spjdvoid	dns_sig_handler(int, short, void *);
50168404Spjdvoid	dns_shutdown(void);
51248571Smmint	host_dns(const char *s, struct ypldap_addr **hn);
52168404Spjd
53168404Spjdvoid
54168404Spjddns_sig_handler(int sig, short event, void *p)
55219089Spjd{
56219089Spjd	switch (sig) {
57258632Savg	case SIGINT:
58168404Spjd	case SIGTERM:
59168404Spjd		dns_shutdown();
60168404Spjd		break;
61168404Spjd	default:
62168404Spjd		fatalx("unexpected signal");
63168404Spjd	}
64168404Spjd}
65168404Spjd
66168404Spjdvoid
67168404Spjddns_shutdown(void)
68219089Spjd{
69168404Spjd	log_info("dns engine exiting");
70219089Spjd	_exit(0);
71168404Spjd}
72168404Spjd
73168404Spjdpid_t
74168404Spjdypldap_dns(int pipe_ntp[2], struct passwd *pw)
75168404Spjd{
76168404Spjd	pid_t			 pid;
77168404Spjd	struct event	 ev_sigint;
78168404Spjd	struct event	 ev_sigterm;
79168404Spjd	struct event	 ev_sighup;
80168404Spjd	struct env	 env;
81168404Spjd
82168404Spjd	switch (pid = fork()) {
83168404Spjd	case -1:
84168404Spjd		fatal("cannot fork");
85168404Spjd		break;
86168404Spjd	case 0:
87168404Spjd		break;
88168404Spjd	default:
89168404Spjd		return (pid);
90168404Spjd	}
91168404Spjd
92168404Spjd	setproctitle("dns engine");
93168404Spjd	close(pipe_ntp[0]);
94168404Spjd
95168404Spjd	if (setgroups(1, &pw->pw_gid) ||
96168404Spjd	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
97168404Spjd	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
98168404Spjd		fatal("can't drop privileges");
99168404Spjd	endservent();
100168404Spjd
101168404Spjd	event_init();
102168404Spjd	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
103168404Spjd	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
104168404Spjd	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
105168404Spjd	signal_add(&ev_sigint, NULL);
106168404Spjd	signal_add(&ev_sigterm, NULL);
107168404Spjd	signal_add(&ev_sighup, NULL);
108219089Spjd
109168404Spjd	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
110168404Spjd		fatal(NULL);
111168404Spjd
112168404Spjd	env.sc_iev->events = EV_READ;
113168404Spjd	env.sc_iev->data = &env;
114168404Spjd	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
115168404Spjd	env.sc_iev->handler = dns_dispatch_imsg;
116168404Spjd	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
117168404Spjd	    env.sc_iev->handler, &env);
118168404Spjd	event_add(&env.sc_iev->ev, NULL);
119168404Spjd
120168404Spjd	event_dispatch();
121168404Spjd	dns_shutdown();
122168404Spjd
123168404Spjd	return (0);
124168404Spjd}
125168404Spjd
126168404Spjdvoid
127168404Spjddns_dispatch_imsg(int fd, short events, void *p)
128168404Spjd{
129168404Spjd	struct imsg		 imsg;
130168404Spjd	int			 n, cnt;
131168404Spjd	char			*name;
132168404Spjd	struct ypldap_addr	*h, *hn;
133168404Spjd	struct ibuf		*buf;
134168404Spjd	struct env		*env = p;
135168404Spjd	struct imsgev		*iev = env->sc_iev;
136168404Spjd	struct imsgbuf		*ibuf = &iev->ibuf;
137168404Spjd	int			 shut = 0;
138168404Spjd
139168404Spjd	if ((events & (EV_READ | EV_WRITE)) == 0)
140168404Spjd		fatalx("unknown event");
141168404Spjd
142168404Spjd	if (events & EV_READ) {
143168404Spjd		if ((n = imsg_read(ibuf)) == -1)
144168404Spjd			fatal("imsg_read error");
145168404Spjd		if (n == 0)
146168404Spjd			shut = 1;
147168404Spjd	}
148168404Spjd	if (events & EV_WRITE) {
149168404Spjd		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
150168404Spjd			fatal("msgbuf_write");
151168404Spjd		if (n == 0)
152168404Spjd			shut = 1;
153168404Spjd		goto done;
154168404Spjd	}
155168404Spjd
156168404Spjd	for (;;) {
157168404Spjd		if ((n = imsg_get(ibuf, &imsg)) == -1)
158168404Spjd			fatal("client_dispatch_imsg: imsg_get error");
159168404Spjd		if (n == 0)
160168404Spjd			break;
161168404Spjd
162168404Spjd		switch (imsg.hdr.type) {
163168404Spjd		case IMSG_HOST_DNS:
164249195Smm			name = imsg.data;
165185029Spjd			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
166168404Spjd				fatalx("invalid IMSG_HOST_DNS received");
167168404Spjd			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
168168404Spjd			if (name[imsg.hdr.len] != '\0' ||
169168404Spjd			    strlen(name) != imsg.hdr.len)
170209962Smm				fatalx("invalid IMSG_HOST_DNS received");
171219089Spjd			if ((cnt = host_dns(name, &hn)) == -1)
172219089Spjd				break;
173209962Smm			buf = imsg_create(ibuf, IMSG_HOST_DNS,
174219089Spjd			    imsg.hdr.peerid, 0,
175219089Spjd			    cnt * sizeof(struct sockaddr_storage));
176219089Spjd			if (buf == NULL)
177219089Spjd				break;
178219089Spjd			if (cnt > 0) {
179219089Spjd				h = hn;
180209962Smm				while (h != NULL) {
181219089Spjd					imsg_add(buf, &h->ss, sizeof(h->ss));
182209962Smm					hn = h->next;
183209962Smm					free(h);
184219089Spjd					h = hn;
185209962Smm				}
186219089Spjd			}
187219089Spjd
188219089Spjd			imsg_close(ibuf, buf);
189219089Spjd			break;
190219089Spjd		default:
191219089Spjd			break;
192219089Spjd		}
193219089Spjd		imsg_free(&imsg);
194219089Spjd	}
195219089Spjd
196219089Spjddone:
197219089Spjd	if (!shut)
198209962Smm		imsg_event_add(iev);
199209962Smm	else {
200219089Spjd		/* this pipe is dead, so remove the event handler */
201219089Spjd		event_del(&iev->ev);
202209962Smm		event_loopexit(NULL);
203219089Spjd	}
204219089Spjd}
205219089Spjd
206219089Spjdint
207219089Spjdhost_dns(const char *s, struct ypldap_addr **hn)
208219089Spjd{
209219089Spjd	struct addrinfo		 hints, *res0, *res;
210219089Spjd	int			 error, cnt = 0;
211219089Spjd	struct sockaddr_in	*sa_in;
212209962Smm	struct sockaddr_in6	*sa_in6;
213209962Smm	struct ypldap_addr	*h, *hh = NULL;
214168404Spjd
215168404Spjd	bzero(&hints, sizeof(hints));
216168404Spjd	hints.ai_family = PF_UNSPEC;
217168404Spjd	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
218168404Spjd	error = getaddrinfo(s, NULL, &hints, &res0);
219168404Spjd	if (error == EAI_AGAIN || error == EAI_NONAME)
220168404Spjd			return (0);
221168404Spjd	if (error) {
222168404Spjd		log_warnx("could not parse \"%s\": %s", s,
223168404Spjd		    gai_strerror(error));
224168404Spjd		return (-1);
225168404Spjd	}
226168404Spjd
227274337Sdelphij	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
228168404Spjd		if (res->ai_family != AF_INET &&
229168404Spjd		    res->ai_family != AF_INET6)
230168404Spjd			continue;
231209962Smm		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
232219089Spjd			fatal(NULL);
233209962Smm		h->ss.ss_family = res->ai_family;
234209962Smm		if (res->ai_family == AF_INET) {
235168404Spjd			sa_in = (struct sockaddr_in *)&h->ss;
236209962Smm			sa_in->sin_len = sizeof(struct sockaddr_in);
237209962Smm			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
238209962Smm			    res->ai_addr)->sin_addr.s_addr;
239209962Smm		} else {
240168404Spjd			sa_in6 = (struct sockaddr_in6 *)&h->ss;
241209962Smm			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
242209962Smm			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
243209962Smm			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
244209962Smm		}
245209962Smm
246209962Smm		h->next = hh;
247209962Smm		hh = h;
248209962Smm		cnt++;
249209962Smm	}
250168404Spjd	freeaddrinfo(res0);
251168404Spjd
252168404Spjd	*hn = hh;
253168404Spjd	return (cnt);
254168404Spjd}
255168404Spjd