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