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