xref: /openbsd-src/usr.sbin/ntpd/ntp_dns.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: ntp_dns.c,v 1.24 2019/06/27 15:18:42 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 USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/resource.h>
21 #include <sys/time.h>
22 #include <netinet/in.h>
23 #include <arpa/nameser.h>
24 #include <resolv.h>
25 
26 #include <netinet/in.h>
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <poll.h>
31 #include <fcntl.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <resolv.h>
37 #include <unistd.h>
38 
39 #include "ntpd.h"
40 
41 volatile sig_atomic_t	 quit_dns = 0;
42 struct imsgbuf		*ibuf_dns;
43 
44 void	sighdlr_dns(int);
45 int	dns_dispatch_imsg(struct ntpd_conf *);
46 int	probe_root_ns(void);
47 void	probe_root(void);
48 
49 void
50 sighdlr_dns(int sig)
51 {
52 	switch (sig) {
53 	case SIGTERM:
54 	case SIGINT:
55 		quit_dns = 1;
56 		break;
57 	}
58 }
59 
60 void
61 ntp_dns(struct ntpd_conf *nconf, struct passwd *pw)
62 {
63 	struct pollfd		 pfd[1];
64 	int			 nfds, nullfd;
65 
66 	res_init();
67 	if (setpriority(PRIO_PROCESS, 0, 0) == -1)
68 		log_warn("could not set priority");
69 
70 	log_init(nconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG, nconf->verbose,
71 	    LOG_DAEMON);
72 	if (!nconf->debug && setsid() == -1)
73 		fatal("setsid");
74 	log_procinit("dns");
75 
76 	if ((nullfd = open("/dev/null", O_RDWR, 0)) == -1)
77 		fatal(NULL);
78 
79 	if (!nconf->debug) {
80 		dup2(nullfd, STDIN_FILENO);
81 		dup2(nullfd, STDOUT_FILENO);
82 		dup2(nullfd, STDERR_FILENO);
83 	}
84 	close(nullfd);
85 
86 	setproctitle("dns engine");
87 
88 	if (setgroups(1, &pw->pw_gid) ||
89 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
90 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
91 		fatal("can't drop privileges");
92 
93 	signal(SIGTERM, sighdlr_dns);
94 	signal(SIGINT, sighdlr_dns);
95 	signal(SIGHUP, SIG_IGN);
96 
97 	if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL)
98 		fatal(NULL);
99 	imsg_init(ibuf_dns, PARENT_SOCK_FILENO);
100 
101 	if (pledge("stdio dns", NULL) == -1)
102 		err(1, "pledge");
103 
104 	probe_root();
105 
106 	while (quit_dns == 0) {
107 		pfd[0].fd = ibuf_dns->fd;
108 		pfd[0].events = POLLIN;
109 		if (ibuf_dns->w.queued)
110 			pfd[0].events |= POLLOUT;
111 
112 		if ((nfds = poll(pfd, 1, INFTIM)) == -1)
113 			if (errno != EINTR) {
114 				log_warn("poll error");
115 				quit_dns = 1;
116 			}
117 
118 		if (nfds > 0 && (pfd[0].revents & POLLOUT))
119 			if (msgbuf_write(&ibuf_dns->w) <= 0 &&
120 			    errno != EAGAIN) {
121 				log_warn("pipe write error (to ntp engine)");
122 				quit_dns = 1;
123 			}
124 
125 		if (nfds > 0 && pfd[0].revents & POLLIN) {
126 			nfds--;
127 			if (dns_dispatch_imsg(nconf) == -1)
128 				quit_dns = 1;
129 		}
130 	}
131 
132 	msgbuf_clear(&ibuf_dns->w);
133 	free(ibuf_dns);
134 	exit(0);
135 }
136 
137 int
138 dns_dispatch_imsg(struct ntpd_conf *nconf)
139 {
140 	struct imsg		 imsg;
141 	int			 n, cnt;
142 	char			*name;
143 	struct ntp_addr		*h, *hn;
144 	struct ibuf		*buf;
145 	const char		*str;
146 	size_t			 len;
147 
148 	if (((n = imsg_read(ibuf_dns)) == -1 && errno != EAGAIN) || n == 0)
149 		return (-1);
150 
151 	for (;;) {
152 		if ((n = imsg_get(ibuf_dns, &imsg)) == -1)
153 			return (-1);
154 
155 		if (n == 0)
156 			break;
157 
158 		switch (imsg.hdr.type) {
159 		case IMSG_HOST_DNS:
160 		case IMSG_CONSTRAINT_DNS:
161 			if (imsg.hdr.type == IMSG_HOST_DNS)
162 				str = "IMSG_HOST_DNS";
163 			else
164 				str = "IMSG_CONSTRAINT_DNS";
165 			name = imsg.data;
166 			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
167 				fatalx("invalid %s received", str);
168 			len = imsg.hdr.len - 1 - IMSG_HEADER_SIZE;
169 			if (name[len] != '\0' ||
170 			    strlen(name) != len)
171 				fatalx("invalid %s received", str);
172 			if ((cnt = host_dns(name, nconf->status.synced,
173 			    &hn)) == -1)
174 				break;
175 			buf = imsg_create(ibuf_dns, imsg.hdr.type,
176 			    imsg.hdr.peerid, 0,
177 			    cnt * (sizeof(struct sockaddr_storage) + sizeof(int)));
178 			if (cnt > 0) {
179 				if (buf) {
180 					for (h = hn; h != NULL; h = h->next) {
181 						if (imsg_add(buf, &h->ss,
182 						    sizeof(h->ss)) == -1) {
183 							buf = NULL;
184 							break;
185 						}
186 						if (imsg_add(buf, &h->notauth,
187 						    sizeof(int)) == -1) {
188 							buf = NULL;
189 							break;
190 						}
191 					}
192 				}
193 				host_dns_free(hn);
194 				hn = NULL;
195 			}
196 			if (buf)
197 				imsg_close(ibuf_dns, buf);
198 			break;
199 		case IMSG_SYNCED:
200 			nconf->status.synced = 1;
201 			break;
202 		case IMSG_UNSYNCED:
203 			nconf->status.synced = 0;
204 			break;
205 		default:
206 			break;
207 		}
208 		imsg_free(&imsg);
209 	}
210 	return (0);
211 }
212 
213 int
214 probe_root_ns(void)
215 {
216 	int ret;
217 	int old_retrans, old_retry, old_options;
218 	unsigned char buf[4096];
219 
220 	old_retrans = _res.retrans;
221 	old_retry = _res.retry;
222 	old_options = _res.options;
223 	_res.retrans = 1;
224 	_res.retry = 1;
225 	_res.options |= RES_USE_CD;
226 
227 	ret = res_query(".", C_IN, T_NS, buf, sizeof(buf));
228 
229 	_res.retrans = old_retrans;
230 	_res.retry = old_retry;
231 	_res.options = old_options;
232 
233 	return ret;
234 }
235 
236 void
237 probe_root(void)
238 {
239 	int		n;
240 
241 	n = probe_root_ns();
242 	if (n < 0) {
243 		/* give programs like unwind a second chance */
244 		sleep(1);
245 		n = probe_root_ns();
246 	}
247 	if (imsg_compose(ibuf_dns, IMSG_PROBE_ROOT, 0, 0, -1, &n,
248 	    sizeof(int)) == -1)
249 		fatalx("probe_root");
250 }
251