ypldap_dns.c revision 290934
116125Swpaul/*	$OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
216125Swpaul/*	$FreeBSD: head/usr.sbin/ypldap/ypldap_dns.c 290934 2015-11-16 16:58:09Z rodrigc $ */
316125Swpaul
416125Swpaul/*
516125Swpaul * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
616125Swpaul *
716125Swpaul * Permission to use, copy, modify, and distribute this software for any
816125Swpaul * purpose with or without fee is hereby granted, provided that the above
916125Swpaul * copyright notice and this permission notice appear in all copies.
1016125Swpaul *
1116125Swpaul * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1216125Swpaul * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1316125Swpaul * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1416125Swpaul * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1516125Swpaul * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
1616125Swpaul * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
1716125Swpaul * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1816125Swpaul */
1916125Swpaul
2016125Swpaul#include <sys/types.h>
2116125Swpaul#include <sys/socket.h>
2216125Swpaul#include <sys/stat.h>
2316125Swpaul#include <sys/time.h>
2416125Swpaul#include <sys/tree.h>
2516125Swpaul#include <sys/queue.h>
2616125Swpaul
2716125Swpaul#include <netinet/in.h>
2816125Swpaul#include <arpa/nameser.h>
2916125Swpaul
3016125Swpaul#include <netdb.h>
3116125Swpaul#include <pwd.h>
3216125Swpaul#include <errno.h>
33114601Sobrien#include <event.h>
34114601Sobrien#include <resolv.h>
3530378Scharnier#include <poll.h>
3616125Swpaul#include <signal.h>
3730378Scharnier#include <stdlib.h>
3830378Scharnier#include <string.h>
3969793Sobrien#include <unistd.h>
4016125Swpaul#include <limits.h>
4116125Swpaul
4223716Speter#include "ypldap.h"
4316125Swpaul
44129654Sstefanfvolatile sig_atomic_t	 quit_dns = 0;
4516125Swpaulstruct imsgev		*iev_dns;
4616125Swpaul
4716125Swpaulvoid	dns_dispatch_imsg(int, short, void *);
4816125Swpaulvoid	dns_sig_handler(int, short, void *);
4916125Swpaulvoid	dns_shutdown(void);
5016125Swpaulint	host_dns(const char *s, struct ypldap_addr **hn);
5116125Swpaul
5216125Swpaulvoid
5316125Swpauldns_sig_handler(int sig, short event, void *p)
5416125Swpaul{
5516125Swpaul	switch (sig) {
5616125Swpaul	case SIGINT:
5716125Swpaul	case SIGTERM:
5816125Swpaul		dns_shutdown();
5916125Swpaul		break;
6016125Swpaul	default:
6116125Swpaul		fatalx("unexpected signal");
6216125Swpaul	}
6316125Swpaul}
6416125Swpaul
6516125Swpaulvoid
6616125Swpauldns_shutdown(void)
6716125Swpaul{
6816125Swpaul	log_info("dns engine exiting");
6916125Swpaul	_exit(0);
7016125Swpaul}
7116125Swpaul
7216125Swpaulpid_t
7316125Swpaulypldap_dns(int pipe_ntp[2], struct passwd *pw)
7416125Swpaul{
7516125Swpaul	pid_t			 pid;
7616125Swpaul	struct event	 ev_sigint;
7716125Swpaul	struct event	 ev_sigterm;
7816125Swpaul	struct event	 ev_sighup;
7916125Swpaul	struct env	 env;
8016125Swpaul
8116125Swpaul	switch (pid = fork()) {
8290298Sdes	case -1:
8390298Sdes		fatal("cannot fork");
8416125Swpaul		break;
8516125Swpaul	case 0:
8616125Swpaul		break;
8762989Skris	default:
8816125Swpaul		return (pid);
8930378Scharnier	}
9016125Swpaul
9162989Skris	setproctitle("dns engine");
9216125Swpaul	close(pipe_ntp[0]);
9316125Swpaul
9416125Swpaul	if (setgroups(1, &pw->pw_gid) ||
9516125Swpaul	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
9616125Swpaul	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
9716125Swpaul		fatal("can't drop privileges");
9816125Swpaul	endservent();
9916125Swpaul
10016125Swpaul	event_init();
10116125Swpaul	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
10216125Swpaul	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
10316125Swpaul	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
10416125Swpaul	signal_add(&ev_sigint, NULL);
10516125Swpaul	signal_add(&ev_sigterm, NULL);
10616125Swpaul	signal_add(&ev_sighup, NULL);
10716125Swpaul
10816125Swpaul	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
10916125Swpaul		fatal(NULL);
11016125Swpaul
11116125Swpaul	env.sc_iev->events = EV_READ;
11216125Swpaul	env.sc_iev->data = &env;
11316125Swpaul	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
11416125Swpaul	env.sc_iev->handler = dns_dispatch_imsg;
11516125Swpaul	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
11616125Swpaul	    env.sc_iev->handler, &env);
11716125Swpaul	event_add(&env.sc_iev->ev, NULL);
11816125Swpaul
11916125Swpaul	event_dispatch();
12016125Swpaul	dns_shutdown();
12116125Swpaul
12216125Swpaul	return (0);
12390298Sdes}
12416125Swpaul
12516125Swpaulvoid
12616125Swpauldns_dispatch_imsg(int fd, short events, void *p)
12716125Swpaul{
12816125Swpaul	struct imsg		 imsg;
12916125Swpaul	int			 n, cnt;
13016125Swpaul	char			*name;
13116125Swpaul	struct ypldap_addr	*h, *hn;
13216125Swpaul	struct ibuf		*buf;
13316125Swpaul	struct env		*env = p;
13416125Swpaul	struct imsgev		*iev = env->sc_iev;
13516125Swpaul	struct imsgbuf		*ibuf = &iev->ibuf;
13616125Swpaul	int			 shut = 0;
13716125Swpaul
13816125Swpaul	if ((events & (EV_READ | EV_WRITE)) == 0)
13916125Swpaul		fatalx("unknown event");
14016125Swpaul
14116125Swpaul	if (events & EV_READ) {
14216125Swpaul		if ((n = imsg_read(ibuf)) == -1)
14316125Swpaul			fatal("imsg_read error");
14416125Swpaul		if (n == 0)
14516125Swpaul			shut = 1;
14616125Swpaul	}
14716125Swpaul	if (events & EV_WRITE) {
14816125Swpaul		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
14930378Scharnier			fatal("msgbuf_write");
15016125Swpaul		if (n == 0)
15116125Swpaul			shut = 1;
15216125Swpaul		goto done;
15316125Swpaul	}
15416125Swpaul
15516125Swpaul	for (;;) {
15616125Swpaul		if ((n = imsg_get(ibuf, &imsg)) == -1)
15716125Swpaul			fatal("client_dispatch_imsg: imsg_get error");
15816125Swpaul		if (n == 0)
15916125Swpaul			break;
16016125Swpaul
16190298Sdes		switch (imsg.hdr.type) {
16216125Swpaul		case IMSG_HOST_DNS:
16336642Swpaul			name = imsg.data;
16436642Swpaul			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
16516125Swpaul				fatalx("invalid IMSG_HOST_DNS received");
16636642Swpaul			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
16736642Swpaul			if (name[imsg.hdr.len] != '\0' ||
16816125Swpaul			    strlen(name) != imsg.hdr.len)
16916125Swpaul				fatalx("invalid IMSG_HOST_DNS received");
17036642Swpaul			if ((cnt = host_dns(name, &hn)) == -1)
17116125Swpaul				break;
17216125Swpaul			buf = imsg_create(ibuf, IMSG_HOST_DNS,
17316125Swpaul			    imsg.hdr.peerid, 0,
17416125Swpaul			    cnt * sizeof(struct sockaddr_storage));
17516125Swpaul			if (buf == NULL)
17616125Swpaul				break;
17716125Swpaul			if (cnt > 0) {
17816125Swpaul				h = hn;
17916125Swpaul				while (h != NULL) {
18016125Swpaul					imsg_add(buf, &h->ss, sizeof(h->ss));
18136642Swpaul					hn = h->next;
18236642Swpaul					free(h);
18336642Swpaul					h = hn;
18416125Swpaul				}
18516125Swpaul			}
18690298Sdes
18790298Sdes			imsg_close(ibuf, buf);
18816125Swpaul			break;
18930378Scharnier		default:
19016125Swpaul			break;
19116125Swpaul		}
19216125Swpaul		imsg_free(&imsg);
19330378Scharnier	}
19490298Sdes
19516125Swpauldone:
19630378Scharnier	if (!shut)
19716125Swpaul		imsg_event_add(iev);
19830378Scharnier	else {
19916125Swpaul		/* this pipe is dead, so remove the event handler */
20016125Swpaul		event_del(&iev->ev);
20116125Swpaul		event_loopexit(NULL);
20216125Swpaul	}
20324428Simp}
20490297Sdes
20516125Swpaulint
20616125Swpaulhost_dns(const char *s, struct ypldap_addr **hn)
20716125Swpaul{
20816125Swpaul	struct addrinfo		 hints, *res0, *res;
20916125Swpaul	int			 error, cnt = 0;
21016125Swpaul	struct sockaddr_in	*sa_in;
21116125Swpaul	struct sockaddr_in6	*sa_in6;
21216125Swpaul	struct ypldap_addr	*h, *hh = NULL;
21316125Swpaul
21416125Swpaul	bzero(&hints, sizeof(hints));
21516125Swpaul	hints.ai_family = PF_UNSPEC;
21616125Swpaul	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
21716125Swpaul	error = getaddrinfo(s, NULL, &hints, &res0);
21816125Swpaul	if (error == EAI_AGAIN || error == EAI_NONAME)
21916125Swpaul			return (0);
22016125Swpaul	if (error) {
22116125Swpaul		log_warnx("could not parse \"%s\": %s", s,
22216125Swpaul		    gai_strerror(error));
22316125Swpaul		return (-1);
22416125Swpaul	}
22516125Swpaul
22616125Swpaul	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
22716125Swpaul		if (res->ai_family != AF_INET &&
22816125Swpaul		    res->ai_family != AF_INET6)
22916125Swpaul			continue;
23016125Swpaul		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
23116125Swpaul			fatal(NULL);
23216125Swpaul		h->ss.ss_family = res->ai_family;
23316125Swpaul		if (res->ai_family == AF_INET) {
23430378Scharnier			sa_in = (struct sockaddr_in *)&h->ss;
23530378Scharnier			sa_in->sin_len = sizeof(struct sockaddr_in);
23616125Swpaul			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
23716125Swpaul			    res->ai_addr)->sin_addr.s_addr;
23816125Swpaul		} else {
23916125Swpaul			sa_in6 = (struct sockaddr_in6 *)&h->ss;
24016125Swpaul			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
24169793Sobrien			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
24216125Swpaul			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
24316125Swpaul		}
24469793Sobrien
24516125Swpaul		h->next = hh;
24616125Swpaul		hh = h;
24716125Swpaul		cnt++;
24816125Swpaul	}
24916125Swpaul	freeaddrinfo(res0);
25016125Swpaul
25116125Swpaul	*hn = hh;
25216125Swpaul	return (cnt);
25316125Swpaul}
25416125Swpaul