GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ypldap/ypldap_dns.c Lines: 0 117 0.0 %
Date: 2017-11-13 Branches: 0 74 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ypldap_dns.c,v 1.13 2017/04/17 16:37:39 otto 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/time.h>
23
#include <sys/tree.h>
24
#include <sys/queue.h>
25
26
#include <netinet/in.h>
27
#include <arpa/nameser.h>
28
29
#include <netdb.h>
30
#include <pwd.h>
31
#include <errno.h>
32
#include <event.h>
33
#include <resolv.h>
34
#include <poll.h>
35
#include <signal.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
#include <limits.h>
40
41
#include "ypldap.h"
42
43
volatile sig_atomic_t	 quit_dns = 0;
44
struct imsgev		*iev_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 *, struct ypldap_addr_list *);
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
	if (pledge("stdio dns flock rpath cpath wpath", NULL) == -1)
100
		fatal("pledge");
101
102
	event_init();
103
	signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
104
	signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
105
	signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
106
	signal_add(&ev_sigint, NULL);
107
	signal_add(&ev_sigterm, NULL);
108
	signal_add(&ev_sighup, NULL);
109
110
	if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
111
		fatal(NULL);
112
113
	env.sc_iev->events = EV_READ;
114
	env.sc_iev->data = &env;
115
	imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
116
	env.sc_iev->handler = dns_dispatch_imsg;
117
	event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
118
	    env.sc_iev->handler, &env);
119
	event_add(&env.sc_iev->ev, NULL);
120
121
	event_dispatch();
122
	dns_shutdown();
123
124
	return (0);
125
}
126
127
void
128
dns_dispatch_imsg(int fd, short events, void *p)
129
{
130
	struct imsg		 imsg;
131
	int			 n, cnt;
132
	char			*name;
133
	struct ypldap_addr_list	 hn = TAILQ_HEAD_INITIALIZER(hn);
134
	struct ypldap_addr	*h;
135
	struct ibuf		*buf;
136
	struct env		*env = p;
137
	struct imsgev		*iev = env->sc_iev;
138
	struct imsgbuf		*ibuf = &iev->ibuf;
139
	int			 shut = 0;
140
	size_t			 len;
141
142
	if ((events & (EV_READ | EV_WRITE)) == 0)
143
		fatalx("unknown event");
144
145
	if (events & EV_READ) {
146
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
147
			fatal("imsg_read error");
148
		if (n == 0)
149
			shut = 1;
150
	}
151
	if (events & EV_WRITE) {
152
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
153
			fatal("msgbuf_write");
154
		if (n == 0)
155
			shut = 1;
156
		goto done;
157
	}
158
159
	for (;;) {
160
		if ((n = imsg_get(ibuf, &imsg)) == -1)
161
			fatal("client_dispatch_imsg: imsg_get error");
162
		if (n == 0)
163
			break;
164
165
		switch (imsg.hdr.type) {
166
		case IMSG_HOST_DNS:
167
			name = imsg.data;
168
			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
169
				fatalx("invalid IMSG_HOST_DNS received");
170
			len = imsg.hdr.len - 1 - IMSG_HEADER_SIZE;
171
			if (name[len] != '\0' ||
172
			    strlen(name) != len)
173
				fatalx("invalid IMSG_HOST_DNS received");
174
			if ((cnt = host_dns(name, &hn)) == -1)
175
				break;
176
			buf = imsg_create(ibuf, IMSG_HOST_DNS,
177
			    imsg.hdr.peerid, 0,
178
			    cnt * sizeof(struct sockaddr_storage));
179
			if (buf == NULL)
180
				break;
181
			if (cnt > 0) {
182
				while (!TAILQ_EMPTY(&hn)) {
183
					h = TAILQ_FIRST(&hn);
184
					TAILQ_REMOVE(&hn, h, next);
185
					imsg_add(buf, &h->ss, sizeof(h->ss));
186
					free(h);
187
				}
188
			}
189
190
			imsg_close(ibuf, buf);
191
			break;
192
		default:
193
			break;
194
		}
195
		imsg_free(&imsg);
196
	}
197
198
done:
199
	if (!shut)
200
		imsg_event_add(iev);
201
	else {
202
		/* this pipe is dead, so remove the event handler */
203
		event_del(&iev->ev);
204
		event_loopexit(NULL);
205
	}
206
}
207
208
int
209
host_dns(const char *s, struct ypldap_addr_list *hn)
210
{
211
	struct addrinfo		 hints, *res0, *res;
212
	int			 error, cnt = 0;
213
	struct sockaddr_in	*sa_in;
214
	struct sockaddr_in6	*sa_in6;
215
	struct ypldap_addr	*h;
216
217
	memset(&hints, 0, sizeof(hints));
218
	hints.ai_family = PF_UNSPEC;
219
	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
220
	error = getaddrinfo(s, NULL, &hints, &res0);
221
	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
222
			return (0);
223
	if (error) {
224
		log_warnx("could not parse \"%s\": %s", s,
225
		    gai_strerror(error));
226
		return (-1);
227
	}
228
229
	for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
230
		if (res->ai_family != AF_INET &&
231
		    res->ai_family != AF_INET6)
232
			continue;
233
		if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
234
			fatal(NULL);
235
		h->ss.ss_family = res->ai_family;
236
		if (res->ai_family == AF_INET) {
237
			sa_in = (struct sockaddr_in *)&h->ss;
238
			sa_in->sin_len = sizeof(struct sockaddr_in);
239
			sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
240
			    res->ai_addr)->sin_addr.s_addr;
241
		} else {
242
			sa_in6 = (struct sockaddr_in6 *)&h->ss;
243
			sa_in6->sin6_len = sizeof(struct sockaddr_in6);
244
			memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
245
			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
246
		}
247
248
		TAILQ_INSERT_HEAD(hn, h, next);
249
		cnt++;
250
	}
251
	freeaddrinfo(res0);
252
	return (cnt);
253
}