ypldap_dns.c revision 292270
150276Speter/*	$OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
2176187Srafan/*	$FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 292270 2015-12-15 15:37:58Z araujo $ */
350276Speter
450276Speter/*
550276Speter * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
650276Speter *
750276Speter * Permission to use, copy, modify, and distribute this software for any
850276Speter * purpose with or without fee is hereby granted, provided that the above
950276Speter * copyright notice and this permission notice appear in all copies.
1050276Speter *
1150276Speter * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1250276Speter * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1350276Speter * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1450276Speter * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1550276Speter * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
1650276Speter * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
1750276Speter * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1850276Speter */
1950276Speter
2050276Speter#include <sys/types.h>
2150276Speter#include <sys/param.h>
2250276Speter#include <sys/socket.h>
2350276Speter#include <sys/stat.h>
2450276Speter#include <sys/time.h>
2550276Speter#include <sys/tree.h>
2650276Speter#include <sys/queue.h>
2750276Speter
2850276Speter#include <netinet/in.h>
2950276Speter#include <arpa/nameser.h>
30166124Srafan
3150276Speter#include <netdb.h>
32166124Srafan#include <pwd.h>
3350276Speter#include <errno.h>
3450276Speter#include <event.h>
35184989Srafan#include <resolv.h>
3650276Speter#include <poll.h>
3750276Speter#include <signal.h>
3850276Speter#include <stdlib.h>
39166124Srafan#include <string.h>
4050276Speter#include <unistd.h>
4150276Speter#include <limits.h>
4250276Speter
4350276Speter#include "ypldap.h"
4450276Speter
45166124Srafanvolatile sig_atomic_t	 quit_dns = 0;
4650276Speterstruct imsgev		*iev_dns;
4750276Speter
4850276Spetervoid	dns_dispatch_imsg(int, short, void *);
4950276Spetervoid	dns_sig_handler(int, short, void *);
5050276Spetervoid	dns_shutdown(void);
5150276Speterint	host_dns(const char *s, struct ypldap_addr **hn);
5250276Speter
5350276Spetervoid
5450276Speterdns_sig_handler(int sig, short event, void *p)
5550276Speter{
56166124Srafan	switch (sig) {
5750276Speter	case SIGINT:
58166124Srafan	case SIGTERM:
5950276Speter		dns_shutdown();
6050276Speter		break;
61166124Srafan	default:
6250276Speter		fatalx("unexpected signal");
6350276Speter	}
6450276Speter}
6550276Speter
6650276Spetervoid
6750276Speterdns_shutdown(void)
6850276Speter{
6950276Speter	log_info("dns engine exiting");
7050276Speter	_exit(0);
7150276Speter}
7250276Speter
7350276Speterpid_t
7450276Speterypldap_dns(int pipe_ntp[2], struct passwd *pw)
7550276Speter{
7650276Speter	pid_t			 pid;
7750276Speter	struct event	 ev_sigint;
7850276Speter	struct event	 ev_sigterm;
7950276Speter	struct event	 ev_sighup;
8050276Speter	struct env	 env;
8150276Speter
82166124Srafan	switch (pid = fork()) {
8350276Speter	case -1:
8450276Speter		fatal("cannot fork");
8550276Speter		break;
86166124Srafan	case 0:
8750276Speter		break;
8850276Speter	default:
8950276Speter		return (pid);
90166124Srafan	}
9150276Speter
9250276Speter	setproctitle("dns engine");
9350276Speter	close(pipe_ntp[0]);
94166124Srafan
9550276Speter	if (setgroups(1, &pw->pw_gid) ||
96166124Srafan	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
9750276Speter	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
9850276Speter		fatal("can't drop privileges");
9950276Speter	endservent();
10050276Speter
101166124Srafan	event_init();
102166124Srafan	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
103166124Srafan	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
104166124Srafan	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
105166124Srafan	signal_add(&ev_sigint, NULL);
106166124Srafan	signal_add(&ev_sigterm, NULL);
107166124Srafan	signal_add(&ev_sighup, NULL);
108166124Srafan
109166124Srafan	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
110166124Srafan		fatal(NULL);
111166124Srafan
112166124Srafan	env.sc_iev->events = EV_READ;
11350276Speter	env.sc_iev->data = &env;
11450276Speter	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
11550276Speter	env.sc_iev->handler = dns_dispatch_imsg;
116166124Srafan	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
117166124Srafan	    env.sc_iev->handler, &env);
118166124Srafan	event_add(&env.sc_iev->ev, NULL);
11950276Speter
12050276Speter	event_dispatch();
121166124Srafan	dns_shutdown();
12250276Speter
12350276Speter	return (0);
12450276Speter}
12550276Speter
12650276Spetervoid
12750276Speterdns_dispatch_imsg(int fd, short events, void *p)
12850276Speter{
12950276Speter	struct imsg		 imsg;
13050276Speter	int			 n, cnt;
13150276Speter	char			*name;
13250276Speter	struct ypldap_addr	*h, *hn;
13350276Speter	struct ibuf		*buf;
13450276Speter	struct env		*env = p;
13550276Speter	struct imsgev		*iev = env->sc_iev;
13650276Speter	struct imsgbuf		*ibuf = &iev->ibuf;
13750276Speter	int			 shut = 0;
13850276Speter
13950276Speter	if ((events & (EV_READ | EV_WRITE)) == 0)
14050276Speter		fatalx("unknown event");
14150276Speter
14250276Speter	if (events & EV_READ) {
14350276Speter		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
14450276Speter			fatal("imsg_read error");
14550276Speter		if (n == 0)
14650276Speter			shut = 1;
14750276Speter	}
14850276Speter	if (events & EV_WRITE) {
14950276Speter		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
15050276Speter			fatal("msgbuf_write");
15150276Speter		if (n == 0)
15250276Speter			shut = 1;
15350276Speter		goto done;
15450276Speter	}
15550276Speter
15650276Speter	for (;;) {
15750276Speter		if ((n = imsg_get(ibuf, &imsg)) == -1)
15850276Speter			fatal("client_dispatch_imsg: imsg_get error");
15950276Speter		if (n == 0)
16050276Speter			break;
16150276Speter
16250276Speter		switch (imsg.hdr.type) {
16350276Speter		case IMSG_HOST_DNS:
16450276Speter			name = imsg.data;
165166124Srafan			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
16650276Speter				fatalx("invalid IMSG_HOST_DNS received");
16750276Speter			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
16850276Speter			if (name[imsg.hdr.len] != '\0' ||
16950276Speter			    strlen(name) != imsg.hdr.len)
17050276Speter				fatalx("invalid IMSG_HOST_DNS received");
17150276Speter			if ((cnt = host_dns(name, &hn)) == -1)
17250276Speter				break;
17350276Speter			buf = imsg_create(ibuf, IMSG_HOST_DNS,
17450276Speter			    imsg.hdr.peerid, 0,
17550276Speter			    cnt * sizeof(struct sockaddr_storage));
17650276Speter			if (buf == NULL)
17750276Speter				break;
17850276Speter			if (cnt > 0) {
17950276Speter				h = hn;
18050276Speter				while (h != NULL) {
18150276Speter					imsg_add(buf, &h->ss, sizeof(h->ss));
18250276Speter					hn = h->next;
18350276Speter					free(h);
18450276Speter					h = hn;
18550276Speter				}
18650276Speter			}
18750276Speter
18850276Speter			imsg_close(ibuf, buf);
18950276Speter			break;
19050276Speter		default:
19150276Speter			break;
19250276Speter		}
19350276Speter		imsg_free(&imsg);
19450276Speter	}
19550276Speter
19650276Speterdone:
19750276Speter	if (!shut)
19850276Speter		imsg_event_add(iev);
19950276Speter	else {
20050276Speter		/* this pipe is dead, so remove the event handler */
20150276Speter		event_del(&iev->ev);
20250276Speter		event_loopexit(NULL);
20350276Speter	}
20450276Speter}
20550276Speter
20650276Speterint
207166124Srafanhost_dns(const char *s, struct ypldap_addr **hn)
208166124Srafan{
209166124Srafan	struct addrinfo		 hints, *res0, *res;
210166124Srafan	int			 error, cnt = 0;
211166124Srafan	struct sockaddr_in	*sa_in;
212166124Srafan	struct sockaddr_in6	*sa_in6;
213166124Srafan	struct ypldap_addr	*h, *hh = NULL;
214166124Srafan
215166124Srafan	bzero(&hints, sizeof(hints));
216166124Srafan	hints.ai_family = PF_UNSPEC;
217166124Srafan	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
218166124Srafan	error = getaddrinfo(s, NULL, &hints, &res0);
219166124Srafan	if (error == EAI_AGAIN || error == EAI_NONAME)
220166124Srafan			return (0);
221166124Srafan	if (error) {
222166124Srafan		log_warnx("could not parse \"%s\": %s", s,
223166124Srafan		    gai_strerror(error));
224166124Srafan		return (-1);
225166124Srafan	}
226166124Srafan
227166124Srafan	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
228166124Srafan		if (res->ai_family != AF_INET &&
229166124Srafan		    res->ai_family != AF_INET6)
230166124Srafan			continue;
231166124Srafan		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
232166124Srafan			fatal(NULL);
233166124Srafan		h->ss.ss_family = res->ai_family;
234166124Srafan		if (res->ai_family == AF_INET) {
235166124Srafan			sa_in = (struct sockaddr_in *)&h->ss;
236166124Srafan			sa_in->sin_len = sizeof(struct sockaddr_in);
237166124Srafan			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
238166124Srafan			    res->ai_addr)->sin_addr.s_addr;
239166124Srafan		} else {
240166124Srafan			sa_in6 = (struct sockaddr_in6 *)&h->ss;
241166124Srafan			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
242166124Srafan			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
243166124Srafan			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
244166124Srafan		}
245166124Srafan
246166124Srafan		h->next = hh;
247166124Srafan		hh = h;
248166124Srafan		cnt++;
249166124Srafan	}
250166124Srafan	freeaddrinfo(res0);
251166124Srafan
252166124Srafan	*hn = hh;
253166124Srafan	return (cnt);
254166124Srafan}
255166124Srafan