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