xref: /openbsd-src/usr.sbin/nsd/verify.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*
2  * verify.c -- running verifiers and serving the zone to be verified.
3  *
4  * Copyright (c) 2012-2020, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #include <assert.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #ifdef HAVE_SYSLOG_H
20 #include <syslog.h>
21 #endif /* HAVE_SYSLOG_H */
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/wait.h>
25 
26 #include "region-allocator.h"
27 #include "namedb.h"
28 #include "nsd.h"
29 #include "options.h"
30 #include "difffile.h"
31 #include "verify.h"
32 #include "popen3.h"
33 
34 struct zone *verify_next_zone(struct nsd *nsd, struct zone *zone)
35 {
36 	int verify;
37 	struct radnode *node;
38 
39 	if(zone != NULL) {
40 		node = radix_next(zone->node);
41 	} else {
42 		node = radix_first(nsd->db->zonetree);
43 	}
44 
45 	while(node != NULL) {
46 		zone = (struct zone *)node->elem;
47 		verify = zone->opts->pattern->verify_zone;
48 		if(verify == VERIFY_ZONE_INHERIT) {
49 			verify = nsd->options->verify_zones;
50 		}
51 		if(verify && zone->is_updated && !zone->is_checked) {
52 			return zone;
53 		}
54 		node = radix_next(node);
55 	}
56 
57 	return NULL;
58 }
59 
60 static inline ssize_t fill_buffer(struct verifier_stream *stream)
61 {
62 	ssize_t cnt = 0;
63 
64 	assert(stream);
65 	assert(stream->fd != -1);
66 	assert(stream->cnt <= LOGBUFSIZE);
67 	assert(stream->off <= stream->cnt);
68 
69 	// move data to start of buffer assuming all complete lines are printed
70 	if (stream->off) {
71 		size_t len = stream->cnt - stream->off;
72 		memmove(stream->buf, stream->buf + stream->off, len);
73 		stream->off = 0;
74 		stream->cnt = len;
75 		stream->buf[stream->cnt] = '\0'; // always null-terminate
76 	}
77 
78 	// read data if space is available
79 	cnt = read(stream->fd, stream->buf + stream->cnt, LOGBUFSIZE - stream->cnt);
80 	if (cnt > 0)
81 		stream->cnt += (size_t)cnt;
82 	assert(stream->cnt <= LOGBUFSIZE);
83 	assert(stream->off <= stream->cnt);
84 	stream->buf[stream->cnt] = '\0'; // always null-terminate
85 
86 	return cnt;
87 }
88 
89 static inline size_t print_line(struct verifier_stream *stream, int eof)
90 {
91 	char *eol = NULL;
92 	size_t len;
93 	const char *fmt;
94 
95 	if (stream->cnt == 0)
96 		return 0;
97 	assert(stream->off <= stream->cnt);
98 	if (stream->off == stream->cnt)
99 		return 0;
100 
101 	// try to locate natural line break
102 	assert(stream->buf[stream->cnt] == '\0');
103 	if ((eol = strchr(stream->buf + stream->off, '\n'))) {
104 		len = eol - (stream->buf + stream->off);
105 	} else {
106 		len = stream->cnt - stream->off;
107 	}
108 
109 	assert(len <= (stream->cnt - stream->off));
110 	// wait for buffer to contain a full line except on eof
111 	if (len < LOGLINELEN && !eol && !eof)
112 		return 0;
113 
114 	if (len > LOGLINELEN) {
115 		fmt = stream->cut ? ".. %.*s .." : "%.*s ..";
116 		len = LOGLINELEN; // remainder printed next iteration
117 		stream->cut = 1;
118 	} else {
119 		fmt = stream->cut ? ".. %.*s" : "%.*s";
120 		stream->cut = 0;
121 	}
122 	log_msg(stream->priority, fmt, len, stream->buf + stream->off);
123 
124 	stream->off += len + (eol != NULL);
125 	assert(stream->off <= stream->cnt);
126 	return len;
127 }
128 
129 /*
130  * Log verifier output on STDOUT and STDERR. Lines longer than LOGLINELEN are
131  * split over multiple lines. Line-breaks are indicated in the log with "...".
132  */
133 static void verify_handle_stream(int fd, short event, void *arg)
134 {
135 	int eof = 0;
136 	ssize_t cnt;
137 	struct verifier *verifier;
138 	struct verifier_stream *stream;
139 
140 	assert(event & EV_READ);
141 	assert(arg != NULL);
142 
143 	verifier = (struct verifier *)arg;
144 	if (fd == verifier->output_stream.fd) {
145 		stream = &verifier->output_stream;
146 	} else {
147 		assert(fd == verifier->error_stream.fd);
148 		stream = &verifier->error_stream;
149 	}
150 
151 	assert(stream);
152 	assert(stream->fd != -1);
153 
154 	do {
155 		cnt = fill_buffer(stream);
156 		eof = !cnt || (cnt < 0 && errno != EAGAIN && errno != EINTR);
157 		while (print_line(stream, eof)) ;
158 	} while (cnt > 0);
159 
160 	if(eof) {
161 		event_del(&stream->event);
162 		close(stream->fd);
163 		stream->fd = -1;
164 	}
165 }
166 
167 static void kill_verifier(struct verifier *verifier)
168 {
169 	assert(verifier != NULL);
170 	assert(verifier->zone != NULL);
171 
172 	if(kill(verifier->pid, SIGTERM) == -1) {
173 		log_msg(LOG_ERR, "verify: cannot kill verifier for "
174 		                 "zone %s (pid %d): %s",
175 		                 verifier->zone->opts->name,
176 		                 verifier->pid,
177 		                 strerror(errno));
178 	}
179 }
180 
181 static void close_stream(struct verifier *verifier, struct verifier_stream *stream)
182 {
183 	if (stream->fd == -1)
184 		return;
185 	verify_handle_stream(stream->fd, EV_READ, verifier);
186 	if (stream->fd == -1)
187 		return;
188 	event_del(&stream->event);
189 	close(stream->fd);
190 	stream->fd = -1;
191 }
192 
193 static void close_verifier(struct verifier *verifier)
194 {
195 	/* unregister events and close streams (in that order) */
196 	if(verifier->timeout.tv_sec > 0) {
197 		event_del(&verifier->timeout_event);
198 		verifier->timeout.tv_sec = 0;
199 		verifier->timeout.tv_usec = 0;
200 	}
201 
202 	if(verifier->zone_feed.fh != NULL) {
203 		event_del(&verifier->zone_feed.event);
204 		fclose(verifier->zone_feed.fh);
205 		verifier->zone_feed.fh = NULL;
206 		region_destroy(verifier->zone_feed.region);
207 	}
208 
209 	close_stream(verifier, &verifier->error_stream);
210 	close_stream(verifier, &verifier->output_stream);
211 
212 	verifier->zone->is_ok = verifier->was_ok;
213 	verifier->pid = -1;
214 	verifier->zone = NULL;
215 }
216 
217 /*
218  * Feed zone to verifier over STDIN as it becomes available.
219  */
220 static void verify_handle_feed(int fd, short event, void *arg)
221 {
222 	struct verifier *verifier;
223 	struct rr *rr;
224 
225 	(void)fd;
226 	assert(event == EV_WRITE);
227 	assert(arg != NULL);
228 
229 	verifier = (struct verifier *)arg;
230 	if((rr = zone_rr_iter_next(&verifier->zone_feed.rriter)) != NULL) {
231 		print_rr(verifier->zone_feed.fh,
232 		         verifier->zone_feed.rrprinter,
233 		         rr,
234 		         verifier->zone_feed.region,
235 		         verifier->zone_feed.buffer);
236 	} else {
237 		event_del(&verifier->zone_feed.event);
238 		fclose(verifier->zone_feed.fh);
239 		verifier->zone_feed.fh = NULL;
240 		region_destroy(verifier->zone_feed.region);
241 	}
242 }
243 
244 /*
245  * This handler will be called when a verifier-timeout alarm goes off. It just
246  * kills the verifier. server_verify_zones will make sure the zone will be
247  * considered bad.
248  */
249 void verify_handle_timeout(int fd, short event, void *arg)
250 {
251 	struct verifier *verifier;
252 
253 	(void)fd;
254 	assert(event & EV_TIMEOUT);
255 	assert(arg != NULL);
256 
257 	verifier = (struct verifier *)arg;
258 	verifier->zone->is_bad = 1;
259 
260 	log_msg(LOG_ERR, "verify: verifier for zone %s (pid %d) timed out",
261 	                 verifier->zone->opts->name, verifier->pid);
262 
263 	/* kill verifier, process reaped by exit handler */
264 	kill_verifier(verifier);
265 }
266 
267 void verify_handle_signal(int sig, short event, void *arg)
268 {
269 	char buf[1] = { '\0' };
270 	struct nsd *nsd;
271 
272 	assert(sig == SIGCHLD);
273 	assert(event & EV_SIGNAL);
274 	assert(arg != NULL);
275 
276 	nsd = (struct nsd *)arg;
277 	(void)write(nsd->verifier_pipe[1], buf, sizeof(buf));
278 }
279 
280 /*
281  * Reap process and update status of respective zone based on the exit code
282  * of a verifier. Everything from STDOUT and STDERR still available is read and
283  * written to the log as it might contain valuable information.
284  *
285  * NOTE: A timeout might have caused the verifier to be terminated.
286  */
287 void verify_handle_exit(int fd, short event, void *arg)
288 {
289 	int wstatus;
290 	pid_t pid;
291 	struct nsd *nsd;
292 	char buf[1];
293 	size_t i;
294 
295 	assert(event & EV_READ);
296 	assert(arg != NULL);
297 
298 	nsd = (struct nsd *)arg;
299 
300 	(void)read(fd, buf, sizeof(buf));
301 
302 	while(((pid = waitpid(-1, &wstatus, WNOHANG)) == -1 && errno == EINTR)
303 	    || (pid > 0))
304 	{
305 		struct verifier *verifier = NULL;
306 
307 		for(i = 0; !verifier && i < nsd->verifier_limit; i++) {
308 			if(nsd->verifiers[i].zone != NULL &&
309 			   nsd->verifiers[i].pid == pid)
310 			{
311 				verifier = &nsd->verifiers[i];
312 			}
313 		}
314 
315 		if(verifier == NULL) {
316 			continue;
317 		}
318 
319 		if(!WIFEXITED(wstatus)) {
320 			log_msg(LOG_ERR, "verify: verifier for zone %s "
321 			                 "(pid %d) exited abnormally",
322 			                 verifier->zone->opts->name, pid);
323 		} else {
324 			int priority = LOG_INFO;
325 			int status = WEXITSTATUS(wstatus);
326 			if(status != 0) {
327 				priority = LOG_ERR;
328 				verifier->zone->is_bad = 1;
329 			}
330 			log_msg(priority, "verify: verifier for zone %s "
331 			                  "(pid %d) exited with %d",
332 			                  verifier->zone->opts->name, pid, status);
333 		}
334 
335 		close_verifier(verifier);
336 		nsd->verifier_count--;
337 	}
338 
339 	while(nsd->mode == NSD_RUN &&
340 	      nsd->verifier_count < nsd->verifier_limit &&
341 	      nsd->next_zone_to_verify != NULL)
342 	{
343 		verify_zone(nsd, nsd->next_zone_to_verify);
344 		nsd->next_zone_to_verify
345 			= verify_next_zone(nsd, nsd->next_zone_to_verify);
346 	}
347 
348 	if(nsd->next_zone_to_verify == NULL && nsd->verifier_count == 0) {
349 		event_base_loopexit(nsd->event_base, NULL);
350 		return;
351 	}
352 }
353 
354 /*
355  * A parent may be terminated (by the NSD_QUIT signal (nsdc stop command)).
356  * When a reload server process is running, the parent will then send a
357  * NSD_QUIT command to that server. This handler makes sure that this command
358  * is not neglected and that the reload server process will exit (gracefully).
359  */
360 void
361 verify_handle_command(int fd, short event, void *arg)
362 {
363 	struct nsd *nsd = (struct nsd *)arg;
364 	int len;
365 	sig_atomic_t mode;
366 	size_t i;
367 
368 	assert(nsd != NULL);
369 	assert(event & (EV_READ
370 #ifdef EV_CLOSED
371 	| EV_CLOSED
372 #endif
373 	));
374 
375 	if((len = read(fd, &mode, sizeof(mode))) == -1) {
376 		log_msg(LOG_ERR, "verify: verify_handle_command: read: %s",
377 		                 strerror(errno));
378 		return;
379 	} else if(len == 0) {
380 		log_msg(LOG_INFO, "verify: command channel closed");
381 		mode = NSD_QUIT;
382 	} else if(mode != NSD_QUIT) {
383 		log_msg(LOG_ERR, "verify: bad command: %d", (int)mode);
384 		return;
385 	}
386 
387 	nsd->mode = mode;
388 
389 	if(nsd->verifier_count == 0) {
390 		event_base_loopexit(nsd->event_base, NULL);
391 		return; /* exit early if no verifiers are executing */
392 	}
393 
394 	/* kill verifiers, processes reaped elsewhere */
395 	for(i = 0; i < nsd->verifier_limit; i++) {
396 		if(nsd->verifiers[i].zone != NULL) {
397 			kill_verifier(&nsd->verifiers[i]);
398 		}
399 	}
400 }
401 
402 /*
403  * A verifier is executed for the specified zone (if a verifier is configured
404  * and the zone has not been verified before). If one of the verifiers exits
405  * with non-zero, the zone is marked bad and nsd drops the zone update and
406  * reloads again.
407  */
408 void verify_zone(struct nsd *nsd, struct zone *zone)
409 {
410 	struct verifier *verifier = NULL;
411 	int32_t timeout;
412 	char **command;
413 	FILE *fin;
414 	int fdin, fderr, fdout, flags;
415 	size_t i;
416 
417 	assert(nsd != NULL);
418 	assert(nsd->verifier_count < nsd->verifier_limit);
419 	assert(zone != NULL);
420 
421 	fin = NULL;
422 	fdin = fdout = fderr = -1;
423 
424 	/* search for available verifier slot */
425 	for(i = 0; i < nsd->verifier_limit && !verifier; i++) {
426 		if(nsd->verifiers[i].zone == NULL) {
427 			verifier = &nsd->verifiers[i];
428 		}
429 	}
430 
431 	assert(verifier != NULL);
432 
433 	if(zone->opts->pattern->verifier != NULL) {
434 		command = zone->opts->pattern->verifier;
435 	} else if (nsd->options->verifier != NULL) {
436 		command = nsd->options->verifier;
437 	} else {
438 		log_msg(LOG_ERR, "verify: no verifier for zone %s",
439 		                 zone->opts->name);
440 		return;
441 	}
442 
443 	if(zone->opts->pattern->verifier_timeout
444 		!= VERIFIER_TIMEOUT_INHERIT)
445 	{
446 		timeout = zone->opts->pattern->verifier_timeout;
447 	} else {
448 		timeout = nsd->options->verifier_timeout;
449 	}
450 
451 	if(zone->opts->pattern->verifier_feed_zone
452 		!= VERIFIER_FEED_ZONE_INHERIT)
453 	{
454 		fdin = zone->opts->pattern->verifier_feed_zone ? -2 : -1;
455 	} else {
456 		fdin = nsd->options->verifier_feed_zone ? -2 : -1;
457 	}
458 
459 	assert(timeout >= 0);
460 
461 	setenv("VERIFY_ZONE", zone->opts->name, 1);
462 	setenv("VERIFY_ZONE_ON_STDIN", fdin == -2 ? "yes" : "no", 1);
463 
464 	verifier->pid = popen3(
465 		command, fdin == -2 ? &fdin : NULL, &fdout, &fderr);
466 	if(verifier->pid == -1) {
467 		log_msg(LOG_ERR, "verify: could not start verifier for zone "
468 				 "%s: %s", zone->opts->name, strerror(errno));
469 		goto fail_popen3;
470 	}
471 	flags = fcntl(fderr, F_GETFL, 0);
472 	if (fcntl(fderr, F_SETFL, flags | O_NONBLOCK) == -1) {
473 		log_msg(LOG_ERR, "verify: fcntl(stderr, ..., O_NONBLOCK) for "
474 		                 "zone %s: %s",
475 		                 zone->opts->name, strerror(errno));
476 		goto fail_fcntl;
477 	}
478 	flags = fcntl(fdout, F_GETFL, 0);
479 	if(fcntl(fdout, F_SETFL, flags | O_NONBLOCK) == -1) {
480 		log_msg(LOG_ERR, "verify: fcntl(stdout, ..., O_NONBLOCK) for "
481 		                 "zone %s: %s",
482 		                 zone->opts->name, strerror(errno));
483 		goto fail_fcntl;
484 	}
485 	if (fdin >= 0) {
486 		if ((fin = fdopen(fdin, "w")) == NULL) {
487 			log_msg(LOG_ERR, "verify: fdopen(stdin, ...) for "
488 			                 "zone %s: %s",
489 		                         zone->opts->name, strerror(errno));
490 			goto fail_fcntl;
491 		}
492 		/* write unbuffered */
493 		setbuf(fin, NULL);
494 	}
495 
496 	verifier->zone = zone;
497 	verifier->was_ok = zone->is_ok;
498 
499 	unsetenv("VERIFY_ZONE");
500 	unsetenv("VERIFY_ZONE_ON_STDIN");
501 
502 	verifier->error_stream.fd = fderr;
503 	verifier->error_stream.cnt = 0;
504 	verifier->error_stream.off = 0;
505 	verifier->error_stream.buf[0] = '\0';
506 	event_set(&verifier->error_stream.event,
507 	          verifier->error_stream.fd,
508 	          EV_READ|EV_PERSIST,
509 	          verify_handle_stream,
510 		  verifier);
511 	event_base_set(nsd->event_base, &verifier->error_stream.event);
512 	if(event_add(&verifier->error_stream.event, NULL) != 0) {
513 		log_msg(LOG_ERR, "verify: could not add error event for "
514 		                 "zone %s", zone->opts->name);
515 		goto fail_stderr;
516 	}
517 
518 	verifier->output_stream.fd = fdout;
519 	verifier->output_stream.cnt = 0;
520 	verifier->output_stream.off = 0;
521 	verifier->output_stream.buf[0] = '\0';
522 	event_set(&verifier->output_stream.event,
523 	          verifier->output_stream.fd,
524 	          EV_READ|EV_PERSIST,
525 	          verify_handle_stream,
526 	          verifier);
527 	event_base_set(nsd->event_base, &verifier->output_stream.event);
528 	if(event_add(&verifier->output_stream.event, NULL) != 0) {
529 		log_msg(LOG_ERR, "verify: could not add output event for "
530 		                 "zone %s", zone->opts->name);
531 		goto fail_stdout;
532 	}
533 
534 	if(fin != NULL) {
535 		verifier->zone_feed.fh = fin;
536 
537 		zone_rr_iter_init(&verifier->zone_feed.rriter, zone);
538 
539 		verifier->zone_feed.rrprinter
540 			= create_pretty_rr(nsd->server_region);
541 		verifier->zone_feed.region
542 			= region_create(xalloc, free);
543 		verifier->zone_feed.buffer
544 			= buffer_create(nsd->server_region, MAX_RDLENGTH);
545 
546 		event_set(&verifier->zone_feed.event,
547 		          fileno(verifier->zone_feed.fh),
548 			  EV_WRITE|EV_PERSIST,
549 			  &verify_handle_feed,
550 			  verifier);
551 		event_base_set(nsd->event_base, &verifier->zone_feed.event);
552 		if(event_add(&verifier->zone_feed.event, NULL) != 0) {
553 			log_msg(LOG_ERR, "verify: could not add input event "
554 			                 "for zone %s", zone->opts->name);
555 			goto fail_stdin;
556 		}
557 	}
558 
559 	if(timeout > 0) {
560 		verifier->timeout.tv_sec = timeout;
561 		verifier->timeout.tv_usec = 0;
562 		event_set(&verifier->timeout_event,
563 		          -1,
564 		          EV_TIMEOUT,
565 		          verify_handle_timeout,
566 		          verifier);
567 		event_base_set(nsd->event_base, &verifier->timeout_event);
568 		if(event_add(&verifier->timeout_event, &verifier->timeout) != 0) {
569 			log_msg(LOG_ERR, "verify: could not add timeout event "
570 			                 "for zone %s", zone->opts->name);
571 			goto fail_timeout;
572 		}
573 
574 		log_msg(LOG_INFO, "verify: started verifier for zone %s "
575 		                  "(pid %d), timeout is %d seconds",
576 		                  zone->opts->name, verifier->pid, timeout);
577 	} else {
578 		log_msg(LOG_INFO, "verify: started verifier for zone %s "
579 		                  "(pid %d)", zone->opts->name, verifier->pid);
580 	}
581 
582 	zone->is_ok = 1;
583 	nsd->verifier_count++;
584 	return;
585 
586 fail_timeout:
587 	verifier->timeout.tv_sec = 0;
588 	verifier->timeout.tv_usec = 0;
589 	if(fin != NULL) {
590 		event_del(&verifier->zone_feed.event);
591 	}
592 fail_stdin:
593 	verifier->zone_feed.fh = NULL;
594 	event_del(&verifier->output_stream.event);
595 fail_stdout:
596 	verifier->output_stream.fd = -1;
597 	event_del(&verifier->error_stream.event);
598 fail_stderr:
599 	verifier->error_stream.fd = -1;
600 fail_fcntl:
601 	kill_verifier(verifier);
602 	if(fin != NULL) {
603 		fclose(fin);
604 	} else if (fdin >= 0) {
605 		close(fdin);
606 	}
607 	close(fdout);
608 	close(fderr);
609 fail_popen3:
610 	zone->is_bad = 1;
611 	verifier->pid = -1;
612 	verifier->zone = NULL;
613 }
614