1 #include "error.h"
2 #include "config.h"
3 #include "version.h"
4 #include "ldapdns.h"
5 #include "env.h"
6 #include "ip.h"
7 #include "dns.h"
8 
9 #include "supervise.h"
10 #include "profile.h"
11 
12 #include <stdio.h>
13 #include <sys/stat.h>
14 
15 #ifndef LDAP_PORT
16 #define LDAP_PORT	389
17 #endif
18 
19 static void inline add_peer_ns(dns_ctx *c, int inc);
20 
21 static int default_refresh	= 10800;
22 static int default_retry	= 7200;
23 static int default_expire	= 604800;
24 static int default_minimum	= 86400;
25 
26 static list_t other_threads = 0;
27 pthread_mutex_t handler_lock;
28 pthread_mutex_t log_lock;
29 pthread_mutex_t host_lock;
30 list_t host_lp;
31 config_t ldapdns;
32 ldap_ctx *ldap_thread;
33 dns_ctx *handler;
34 
35 static int engine_message = 0;
36 static pthread_cond_t engine_pause_cond;
37 static pthread_mutex_t engine_message_mutex;
38 static pthread_t eph;
39 
handle_messages(void)40 static void handle_messages(void)
41 {
42 	pthread_mutex_lock(&engine_message_mutex);
43 	switch (engine_message) {
44 	case 0: /* do nothing */
45 		break;
46 	case 1: /* paused */
47 		while (engine_message) {
48 			pthread_cond_wait(&engine_pause_cond,
49 					&engine_message_mutex);
50 			if (engine_message == 2)
51 				break;
52 		}
53 		if (engine_message == 0)
54 			break;
55 	case 2: /* please exit */
56 		pthread_mutex_unlock(&engine_message_mutex);
57 		pthread_exit(0);
58 		exit(0);
59 		break;
60 	};
61 	pthread_mutex_unlock(&engine_message_mutex);
62 }
kill_threads(void)63 static void kill_threads(void)
64 {
65 	ldap_ctx *o;
66 	pthread_t *x;
67 	int i;
68 
69 #ifdef HAVE_pthread_kill_other_threads_np
70 	pthread_kill_other_threads_np();
71 	return;
72 #endif
73 
74 	for (i = 0; i < ldapdns.ldap_threads; i++) {
75 		o = &ldap_thread[i];
76 		if (o->id != pthread_self())
77 			pthread_cancel(o->id);
78 	}
79 	while ((x = (pthread_t *)list_pop(&other_threads)) != 0) {
80 		pthread_cancel(*x);
81 		mem_free(x);
82 	}
83 }
handle_signal(int signo)84 static void handle_signal(int signo)
85 {
86 	if (pthread_self() != eph) {
87 		/* we are NOT the main thread */
88 		switch (signo) {
89 		case SIGTERM:
90 		case SIGINT:
91 			pthread_exit(0);
92 		};
93 		return;
94 
95 	}
96 
97 	switch (signo) {
98 	case SIGSTOP:
99 		if (engine_message == 0) {
100 			pthread_mutex_lock(&engine_message_mutex);
101 			engine_message = 1;
102 			pthread_mutex_unlock(&engine_message_mutex);
103 			pthread_mutex_lock(&log_lock);
104 			log(log_info, "pausing");
105 			pthread_mutex_unlock(&log_lock);
106 		}
107 		break;
108 	case SIGCONT:
109 		if (engine_message == 1) {
110 			pthread_mutex_lock(&engine_message_mutex);
111 			engine_message = 0;
112 			pthread_cond_broadcast(&engine_pause_cond);
113 			pthread_mutex_unlock(&engine_message_mutex);
114 			pthread_mutex_lock(&log_lock);
115 			log(log_info, "resuming");
116 			pthread_mutex_unlock(&log_lock);
117 		}
118 		break;
119 	case SIGTERM:
120 	case SIGINT:
121 		pthread_mutex_lock(&log_lock);
122 		log(log_info, "shutting down");
123 		pthread_mutex_unlock(&log_lock);
124 		pthread_mutex_lock(&engine_message_mutex);
125 		if (engine_message == 1) {
126 			pthread_cond_broadcast(&engine_pause_cond);
127 		}
128 		engine_message = 2;
129 		pthread_mutex_unlock(&engine_message_mutex);
130 		kill_threads();
131 		/* ask the parent to die nicely */
132 		if (getppid() != 1)
133 			kill(getppid(), SIGTERM);
134 		pthread_exit(0);
135 		exit(0);
136 		break;
137 	case SIGHUP:
138 		/* unused signals (for now) */
139 		break;
140 	};
141 }
cleanup_lists(dns_ctx * c,int ex)142 static void inline cleanup_lists(dns_ctx *c, int ex)
143 {
144 	char *x;
145 #define cleanup_l(LL) if (c->LL) while ((x = list_pop(&c->LL))) mem_free(x)
146 	if (ex & 1) cleanup_l(subreq_tries);
147 	if (ex & 1) cleanup_l(subreq_done);
148 	if (ex & 2) {
149 		cleanup_l(NS);
150 		mem_free(c->search_base);
151 		c->search_base = 0;
152 		c->adlen = -1;
153 	}
154 	cleanup_l(DNSRecord);
155 	cleanup_l(A);
156 	cleanup_l(CNAME);
157 	cleanup_l(ADM);
158 	cleanup_l(MX);
159 	cleanup_l(SRV);
160 	cleanup_l(TXT);
161 	cleanup_l(PTR);
162 	cleanup_l(Generic);
163 #undef cleanup_l
164 }
165 
start_ldap_connection(ldap_ctx * o,char * hostnamestr)166 static int start_ldap_connection(ldap_ctx *o, char *hostnamestr)
167 {
168 	int r;
169 	char *x;
170 	int port;
171 #ifdef LDAP_OPT_PROTOCOL_VERSION
172 	int version;
173 #endif
174 
175 	x = strchr(hostnamestr, ':');
176 	if (!x || (*(x+1) && *(x+1) == '/')) {
177 		port = LDAP_PORT;
178 	} else {
179 		port = atoi(x+1);
180 		*x = 0;
181 	}
182 
183 	o->message_sent = 0;
184 	o->message_wait = 0; // XXX
185 	if (ldap_is_ldap_url(hostnamestr)) {
186 		ldap_initialize(&o->ldap_con, hostnamestr);
187 	} else {
188 		o->ldap_con = ldap_init(hostnamestr, port);
189 		if (x) *x = ':'; /* egad */
190 	}
191 
192 	if (!o->ldap_con)
193 		return -1;
194 
195 #ifdef LDAP_OPT_PROTOCOL_VERSION
196 	o->protocol_version = version = 3;
197 	if (ldap_set_option(o->ldap_con, LDAP_OPT_PROTOCOL_VERSION, &version)
198 			!= LDAP_SUCCESS) {
199 
200 		o->protocol_version = version = 2;
201 		if (ldap_set_option(o->ldap_con, LDAP_OPT_PROTOCOL_VERSION,
202 					&version) != LDAP_SUCCESS) {
203 			ldap_unbind(o->ldap_con);
204 			o->ldap_con = 0;
205 		}
206 
207 		return -1;
208 	}
209 #else
210 	o->protocol_version = 2;
211 #endif
212 
213 #ifdef ACCELERATE_CACHE
214 	if (ldapdns.accelerate_cache)
215 		ldap_enable_cache(o->ldap_con, ldapdns.accelerate_cache, 0);
216 #endif
217 
218 	if (ldapdns.auth_mode == AUTH_MODE_SASL) {
219 		/* to be tested; prefer the DSA */
220 		r = ldap_bind_s(o->ldap_con,
221 				ldapdns.ldap_name,
222 				ldapdns.ldap_cred,
223 				LDAP_AUTH_KRBV42);
224 		if (r != LDAP_SUCCESS) {
225 			/* then try kerberos against LDAP */
226 			r = ldap_bind_s(o->ldap_con,
227 					ldapdns.ldap_name,
228 					ldapdns.ldap_cred,
229 					LDAP_AUTH_KRBV41);
230 		}
231 	} else if (ldapdns.auth_mode == AUTH_MODE_SIMPLE) {
232 		r = ldap_simple_bind_s(o->ldap_con,
233 				ldapdns.ldap_name,
234 				ldapdns.ldap_cred);
235 	} else if (ldapdns.auth_mode == AUTH_MODE_ANONYMOUS) {
236 		r = ldap_simple_bind_s(o->ldap_con, "", "");
237 	}
238 
239 	if (r == LDAP_SUCCESS) {
240 		return 1;
241 	}
242 
243 	/* no need to keep synchronous here */
244 	ldap_unbind(o->ldap_con);
245 	o->ldap_con = 0;
246 	return -1;
247 
248 }
249 static void complete_phase(dns_ctx *c, int flag);
restart_ldap_connection(ldap_ctx * o)250 static void restart_ldap_connection(ldap_ctx *o)
251 {
252 	list_t lp;
253 	dns_ctx *x;
254 
255 	pthread_mutex_lock(&handler_lock);
256 	x = handler;
257 	pthread_mutex_unlock(&handler_lock);
258 	for (; x; x = x->next) {
259 		if (x->c == o) {
260 			pthread_mutex_lock(&log_lock);
261 			warning("handler %d being closed (ldap went away)", x->n);
262 			pthread_mutex_unlock(&log_lock);
263 
264 			complete_phase(x, '?');
265 			x->c = 0; /* give it up */
266 			x->phase = PHASE_IDLE;
267 		}
268 	}
269 
270 	/* hopefully this will only be called by LDAP_SERVERDOWN */
271 	if (o->ldap_con)
272 		ldap_unbind(o->ldap_con);
273 	o->ldap_con = 0;
274 
275 	pthread_mutex_lock(&log_lock);
276 	warning("handler %d was hung up on, restarting", o->n);
277 	pthread_mutex_unlock(&log_lock);
278 
279 	pthread_mutex_lock(&host_lock);
280 top_restart_l:
281 	for (lp = host_lp; lp; lp = lp->next) {
282 		if (start_ldap_connection(o, lp->str) == 1)
283 			goto done_restart_l;
284 	}
285 	for (lp = ldapdns.hosts; lp; lp = lp->next) {
286 		if (start_ldap_connection(o, lp->str) == 1)
287 			goto done_restart_l;
288 	}
289 	goto top_restart_l;
290 done_restart_l:
291 	host_lp = lp;
292 	pthread_mutex_unlock(&host_lock);
293 }
complete_phase(dns_ctx * c,int flag)294 static void complete_phase(dns_ctx *c, int flag)
295 {
296 	str_t out;
297 	char *q;
298 	char id[2];
299 
300 	/* it is possible for these to be uninitialized here */
301 	if (c->response && caddr(c->response) && clen(c->response))
302 		tp_write(c);
303 
304 	/* dynamic */
305 	if (c->axfr_base) mem_free(c->axfr_base);
306 
307 	c->message_id = -1;
308 	c->phase = PHASE_IDLE;
309 
310 	if (c->c) {
311 		pthread_mutex_lock(&c->c->load_lock);
312 		c->c->load--;
313 		pthread_mutex_unlock(&c->c->load_lock);
314 	}
315 
316 
317 	if (ldapdns.always_hangup || (flag != '+' && flag != '-')) {
318 		/* okay, something "weird" happened
319 		 * we want to signal a hangup on this hangle
320 		 */
321 		tp_close(c);
322 	}
323 
324 	if (use_syslog) {
325 		/* encouragement: don't use syslog :) */
326 		return;
327 	}
328 
329 	pthread_mutex_lock(&log_lock);
330 	if (c->request_name_alloc) {
331 		dns_to_name(out, c->request_name_alloc, 0);
332 		q = str(out);
333 	} else {
334 		q = "(unknown)";
335 	}
336 	if (c->response && c->response->buf)  {
337 		id[0] = c->response->buf[0];
338 		id[1] = c->response->buf[1];
339 	} else {
340 		id[0] = c->request_buf[0];
341 		id[1] = c->request_buf[1];
342 	}
343 	status("%02x%02x%02x%02x:%02x%02x:%02x%02x %c %02x%02x %s",
344 			(unsigned char)c->ip[0],
345 			(unsigned char)c->ip[1],
346 			(unsigned char)c->ip[2],
347 			(unsigned char)c->ip[3],
348 			(unsigned char)(c->port & 0xFF00) >> 8,
349 			(unsigned char)(c->port & 0x00FF),
350 			(unsigned char)id[0],
351 			(unsigned char)id[1],
352 
353 			flag,
354 
355 			(unsigned char)c->request_record[0],
356 			(unsigned char)c->request_record[1],
357 			q);
358 
359 	if (c->request_name_alloc) mem_free(q);
360 	pthread_mutex_unlock(&log_lock);
361 }
362 static void do_zonesearch(dns_ctx *c, char *q);
try_subrequest(dns_ctx * c,char * trydomain)363 static void try_subrequest(dns_ctx *c, char *trydomain)
364 {
365 	/* put it back into phase 1 with the subrequest flag set... */
366 	c->subreq++;
367 	c->subreq_in = c->subreq_in_alloc = trydomain;
368 	do_zonesearch(c, trydomain);
369 }
finish_subrequest(dns_ctx * c)370 static void finish_subrequest(dns_ctx *c)
371 {
372 	char *q;
373 	list_t lp;
374 
375 	/* nuke old A list */
376 	while ((q = list_pop(&c->A))) {
377 		mem_free(q);
378 	}
379 	/* nuke old PTR list */
380 	while ((q = list_pop(&c->PTR))) {
381 		mem_free(q);
382 	}
383 	/* nuke old Generic list */
384 	while ((q = list_pop(&c->Generic))) {
385 		mem_free(q);
386 	}
387 
388 	c->subreq--;
389 	if (c->subreq_in_alloc) {
390 		mem_free(c->subreq_in_alloc);
391 		c->subreq_in = 0;
392 		c->subreq_in_alloc = 0;
393 	}
394 
395 	if (c->subreq_tries) {
396 		for (;;) {
397 			q = list_pop(&c->subreq_tries);
398 			/* out of requests */
399 			if (!q) {
400 				complete_phase(c, '+');
401 				return;
402 			}
403 
404 			/* make sure we haven't done this guy yet */
405 			for (lp = c->subreq_done; lp; lp = lp->next) {
406 				if (str_equali(lp->str, q)) {
407 					/* skip this round */
408 					mem_free(q);
409 					q = 0;
410 					break;
411 				}
412 			}
413 			/* got one? */
414 			if (q) {
415 				list_push(&c->subreq_done, str_dup(q));
416 				try_subrequest(c, q);
417 				return;
418 			}
419 		}
420 	} else
421 		complete_phase(c, '+');
422 }
do_axfrsearch(dns_ctx * c,char * q)423 static void do_axfrsearch(dns_ctx *c, char *q)
424 {
425 	const char *attrs[6] = {
426 				"mail",
427 				"nSRecord",
428 				"sOARecord",
429 				"modifyTimestamp"
430 	};
431 	str_t sa, sb;
432 	int r;
433 
434 retry_axfr_search_top_l:
435 	if (ldapdns.dn_mode == DN_MODE_RFC1279
436 			|| ldapdns.dn_mode == DN_MODE_MSDNS) {
437 		attrs[4] = (const char *)"dNSRecord";
438 		attrs[5] = (const char *)0;
439 	} else if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
440 
441 		response_refuse(c);
442 		complete_phase(c, '-');
443 		return;
444 	} else {
445 		attrs[4] = (const char *)0;
446 	}
447 
448 	/* q is valid: safe */
449 	dns_to_name(sa, q, 0);
450 	name_to_ldap(sb, str(sa)); /* calls str_init sb */
451 	if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
452 		str_cat(sb, ", ");
453 		str_cat(sb, ldapdns.ldap_suffix);
454 	}
455 
456 	pthread_mutex_lock(&c->c->lock);
457 	r = ldap_search(c->c->ldap_con,
458 			str(sb),		/* base */
459 			LDAP_SCOPE_BASE,	/* scope */
460 			"(objectClass=*)",	/* ldap filter */
461 			(char **)attrs,		/* attrs */
462 			0);			/* attrsonly */
463 	mem_free(str(sa));
464 	mem_free(str(sb));
465 
466 	if (r == -1) {
467 		/* uh oh: possibly an out of memory error */
468 		restart_ldap_connection(c->c);
469 		pthread_mutex_unlock(&c->c->lock);
470 		goto retry_axfr_search_top_l;
471 	}
472 
473 	//printf("sent query for %d (was %d)\n", r, c->message_id);
474 	c->message_id = r;
475 	c->phase = PHASE_AXFRFIRST;
476 
477 	c->c->message_sent++;
478 	//warning("axfrfirst %d / %d", c->c->message_sent, c->c->message_wait);
479 	if (c->c->message_wait)
480 		pthread_cond_broadcast(&c->c->active);
481 
482 	pthread_mutex_unlock(&c->c->lock);
483 }
do_simple_search(dns_ctx * c,char * q)484 static void do_simple_search(dns_ctx *c, char *q)
485 {
486 	const char *attrs[12];
487 	str_t sb, sr;
488 	register int i, j;
489 	int r;
490 
491 	str_init(sr);
492 	str_copy(sr, "(");
493 	str_cat(sr, c->request_attr);
494 	str_addch(sr, '=');
495 	for (i = 0; i < *q; i++) {
496 		j = q[i+1];
497 		if (!isdigit(((unsigned int)j))
498 				&& !isalpha(((unsigned int)j)) && j != '-') {
499 			/* not even going to try... */
500 			response_refuse(c);
501 			complete_phase(c, '-');
502 			mem_free(str(sr));
503 			return;
504 		}
505 		str_addch(sr, j);
506 	}
507 	str_addch(sr, ')');
508 
509 retry_simple_search_top_l:
510 	attrs[0] = (const char *)"aRecord";
511 	attrs[1] = (const char *)"mXRecord";
512 	attrs[2] = (const char *)"cNAMERecord";
513 	attrs[3] = (const char *)"seeAlso";
514 	attrs[4] = (const char *)"description";
515 	attrs[5] = (const char *)"photo";
516 	attrs[6] = (const char *)"mail";
517 	attrs[7] = (const char *)"nSRecord";
518 	attrs[8] = (const char *)"sOARecord";
519 	attrs[9] = (const char *)"modifyTimestamp";
520 
521 	if (ldapdns.dn_mode == DN_MODE_RFC1279
522 			|| ldapdns.dn_mode == DN_MODE_MSDNS) {
523 		attrs[10] = (const char *)"dNSRecord";
524 		attrs[11] = (const char *)0;
525 	} else {
526 		attrs[10] = (const char *)0;
527 	}
528 
529 	/* q is valid: safe */
530 	str_init(sb);
531 	if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
532 		str_cat(sb, ldapdns.ldap_suffix);
533 	}
534 
535 	pthread_mutex_lock(&c->c->lock);
536 	r = ldap_search(c->c->ldap_con,
537 			str(sb),		/* base */
538 			LDAP_SCOPE_ONELEVEL,	/* scope */
539 			str(sr),		/* ldap filter */
540 			(char **)attrs,		/* attrs */
541 			0);			/* attrsonly */
542 	mem_free(str(sr));
543 	mem_free(str(sb));
544 
545 	if (r == -1) {
546 		/* uh oh: possibly an out of memory error */
547 		restart_ldap_connection(c->c);
548 		pthread_mutex_unlock(&c->c->lock);
549 		goto retry_simple_search_top_l;
550 	}
551 
552 	//printf("sent query for %d (was %d)\n", r, c->message_id);
553 	c->message_id = r;
554 	c->phase = PHASE_SIMPLESEARCH;
555 
556 	c->c->message_sent++;
557 	//warning("simplesearch %d / %d", c->c->message_sent, c->c->message_wait);
558 	if (c->c->message_wait)
559 		pthread_cond_broadcast(&c->c->active);
560 
561 	pthread_mutex_unlock(&c->c->lock);
562 }
do_attrsearch(dns_ctx * c,char * q,int wild)563 static void do_attrsearch(dns_ctx *c, char *q, int wild)
564 {
565 	const char *attrs[10];
566 	str_t sa, sb;
567 	list_t lp;
568 	int r;
569 
570 retry_attr_search_top_l:
571 	if (!q || !*q) {
572 		if (c->subreq) {
573 			finish_subrequest(c);
574 		} else {
575 			response_nxdomain(c);
576 			complete_phase(c, '-');
577 		}
578 		return;
579 	}
580 
581 	attrs[0] = (const char *)"aRecord";
582 	attrs[1] = (const char *)"mXRecord";
583 	attrs[2] = (const char *)"cNAMERecord";
584 	attrs[3] = (const char *)"seeAlso";
585 	attrs[4] = (const char *)"description";
586 	attrs[5] = (const char *)"photo";
587 	attrs[6] = (const char *)"mail";
588 	attrs[7] = (const char *)"modifyTimestamp";
589 
590 	if (ldapdns.dn_mode == DN_MODE_RFC1279
591 			|| ldapdns.dn_mode == DN_MODE_MSDNS) {
592 		attrs[8] = (const char *)"dNSRecord";
593 		attrs[9] = (const char *)0;
594 	} else {
595 		attrs[8] = (const char *)0;
596 	}
597 
598 	dns_to_name(sa, q, 0);
599 	if (wild) {
600 		/* wildcard search */
601 		str_init(sb);
602 		str_copy(sb, "*.");
603 		str_cat(sb, str(sa));
604 		str_copy(sa, str(sb));
605 		mem_free(str(sb));
606 	}
607 
608 	if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
609 		//printf("sa=%d, ad=%d\n", str_len(sa), c->adlen);
610 		if (str_len(sa) <= c->adlen) {
611 			str_init(sb);
612 			str_copy(sb, c->search_base);
613 		} else {
614 			str(sa)[str_len(sa) - c->adlen] = 0;
615 			name_to_ldap(sb, str(sa)); /* calls str_init sb */
616 			str_cat(sb, ", ");
617 			str_cat(sb, c->search_base);
618 		}
619 	} else {
620 		/* q is valid: safe */
621 		name_to_ldap(sb, str(sa)); /* calls str_init sb */
622 		if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
623 			str_cat(sb, ", ");
624 			str_cat(sb, ldapdns.ldap_suffix);
625 		}
626 	}
627 
628 	// printf("X2 searching (%p) [%s]\n", c, str(sb));
629 	pthread_mutex_lock(&c->c->lock);
630 	r = ldap_search(c->c->ldap_con,
631 			str(sb),		/* base */
632 			LDAP_SCOPE_BASE,	/* scope */
633 			"(objectClass=*)",	/* ldap filter */
634 			(char **)attrs,		/* attrs */
635 			0);			/* attrsonly */
636 	mem_free(str(sa));
637 	mem_free(str(sb));
638 
639 	if (r == -1) {
640 		/* uh oh: possibly an out of memory error */
641 		restart_ldap_connection(c->c);
642 		pthread_mutex_unlock(&c->c->lock);
643 		goto retry_attr_search_top_l;
644 	}
645 
646 	//printf("attr: sent query for %d (was %d)\n", r, c->message_id);
647 	c->message_id = r;
648 	c->phase = PHASE_ATTRSEARCH;
649 
650 	c->c->message_sent++;
651 	//warning("attrsearch %d / %d", c->c->message_sent, c->c->message_wait);
652 	if (c->c->message_wait)
653 		pthread_cond_broadcast(&c->c->active);
654 
655 	pthread_mutex_unlock(&c->c->lock);
656 }
do_zonesearch(dns_ctx * c,char * q)657 static void do_zonesearch(dns_ctx *c, char *q)
658 {
659 	const char *attrs[5];
660 	str_t sa, sb;
661 	char *base;
662 	char *filter;
663 	int r;
664 
665 	if (c->search_base) {
666 		mem_free(c->search_base);
667 		c->search_base = 0;
668 	}
669 	c->adlen = -1;
670 
671 retry_zone_search_top_l:
672 	if (!q || !*q) {
673 		if (c->subreq) {
674 			finish_subrequest(c);
675 		} else {
676 			response_nxdomain(c);
677 			complete_phase(c, '-');
678 		}
679 		return;
680 	}
681 
682 	attrs[0] = (const char *)"nSRecord";
683 	attrs[1] = (const char *)"sOARecord";
684 	attrs[2] = (const char *)"modifyTimestamp";
685 	if (ldapdns.dn_mode == DN_MODE_RFC1279
686 			|| ldapdns.dn_mode == DN_MODE_MSDNS) {
687 		attrs[3] = (const char *)"dNSRecord";
688 		attrs[4] = (const char *)0;
689 	} else if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
690 		attrs[3] = (const char *)"associatedDomain";
691 		attrs[4] = (const char *)0;
692 	} else {
693 		attrs[3] = (const char *)0;
694 	}
695 
696 	/* q is valid: safe */
697 	dns_to_name(sa, q, 0);
698 	if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
699 		str_init(sb);
700 		str_copy(sb, "(|(associatedDomain=");
701 		str_cat(sb, str(sa));
702 		for (r = 0; str(sa)[r]; r++) {
703 			if (str(sa)[r] == '.') {
704 				while (str(sa)[r] == '.') r++;
705 				str_cat(sb, ")(associatedDomain=");
706 				str_cat(sb, str(sa)+r);
707 			}
708 		}
709 		str_cat(sb, "))");
710 		filter = str(sb);
711 
712 		if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
713 			base = ldapdns.ldap_suffix;
714 		} else {
715 			base = "";
716 		}
717 	} else {
718 		name_to_ldap(sb, str(sa)); /* calls str_init */
719 		if (! str(sb) || ! str(sb)[0]) {
720 			mem_free(str(sa));
721 			mem_free(str(sb));
722 
723 			/* hrm... we're empty... */
724 			if (c->subreq) {
725 				finish_subrequest(c);
726 			} else {
727 				response_refuse(c);
728 				complete_phase(c, '-');
729 			}
730 			return;
731 		}
732 
733 
734 		if (ldapdns.dn_mode == DN_MODE_MSDNS) {
735 			/* msdns is like dc=@, dc=domain for this phase */
736 			str_copy(sa, "dc=@, ");
737 			str_cat(sa, str(sb));
738 			str_copy(sb, str(sa));
739 		}
740 		if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
741 			str_cat(sb, ", ");
742 			str_cat(sb, ldapdns.ldap_suffix);
743 		}
744 		base = str(sb);
745 		filter = "(objectClass=*)";
746 	}
747 
748 	//printf("searching (%p) [%s]\n", c, str(sb));
749 	pthread_mutex_lock(&c->c->lock);
750 	r = ldap_search(c->c->ldap_con,
751 			base,			/* base */
752 ldapdns.dn_mode == DN_MODE_LDAPDNS ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE,
753 			filter,			/* ldap filter */
754 			(char **)attrs,		/* attrs */
755 			0);			/* attrsonly */
756 	mem_free(str(sa));
757 	mem_free(str(sb));
758 
759 	if (r == -1) {
760 		/* uh oh: possibly an out of memory error */
761 		restart_ldap_connection(c->c);
762 		pthread_mutex_unlock(&c->c->lock);
763 		goto retry_zone_search_top_l;
764 	}
765 
766 	c->message_id = r;
767 	c->phase = PHASE_ZONESEARCH;
768 
769 	c->c->message_sent++;
770 	//warning("zonesearch %d / %d", c->c->message_sent, c->c->message_wait);
771 	if (c->c->message_wait)
772 		pthread_cond_broadcast(&c->c->active);
773 
774 	pthread_mutex_unlock(&c->c->lock);
775 }
776 
engine_dns_answer_notify(dns_ctx * c,char header[12])777 static void engine_dns_answer_notify(dns_ctx *c, char header[12])
778 {
779 	char *q, qtype[2], qclass[2];
780 	str_t d;
781 	int r, pid, status;
782 
783 	/* query */
784 	q = 0;
785 	if (!dns_packet_getname(c, &q)) goto NOQ;
786 	if (!dns_packet_copy(c, qtype, 2)) goto NOQ;
787 	if (!dns_packet_copy(c, qclass, 2)) goto NOQ;
788 	if (!q) goto NOQ; /* offensive */
789 
790 	/* setup notify response */
791 	if (!response_notify(c, q, qtype, qclass)) goto NOQ;
792 	response_id(c, header);
793 
794 	if (qclass[0] == DNS_C_IN[0] && qclass[1] == DNS_C_IN[1]) {
795 		c->response->buf[2] |= 4;
796 	} else if (qclass[0] != DNS_C_ANY[0] || qclass[1] != DNS_C_ANY[1]) {
797 		goto WEIRDCLASS;
798 	}
799 	if (qtype[0] != DNS_T_SOA[0] && qtype[1] != DNS_T_SOA[1]) {
800 		/* okie... */
801 		goto NOTIMP;
802 	}
803 
804 	/* handle axfr processing on domain (q) */
805 	dns_to_name(d, q, 0);
806 
807 	/* double fork */
808 	pid = fork();
809 	if (pid == 0) {
810 		pid = fork();
811 		if (pid == 0) {
812 			/* run notify tool */
813 			char ip[64];
814 			/* Clib */
815 			/* IPv4 */
816 			sprintf(ip, "%d.%d.%d.%d", c->ip[0],
817 					c->ip[1], c->ip[2], c->ip[3]);
818 			env_put("REMOTE_ADDR", ip);
819 			execlp(ldapdns.notify, ldapdns.notify, str(d), 0);
820 			_exit(127);
821 		}
822 		_exit(pid == -1 ? 127 : 0);
823 	} else if (pid == -1) {
824 		mem_free(str(d));
825 		goto SERVFAIL;
826 	}
827 	/* wait for first child (almost immediately) */
828 	while ((r = wait(&status)) != pid && r != -1);
829 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
830 		mem_free(str(d));
831 		goto SERVFAIL;
832 	}
833 
834 	/* respond success */
835 	mem_free(str(d));
836 	complete_phase(c, '+');
837 	return;
838 SERVFAIL:
839 	response_rcode(c, DNS_R_SERVFAIL);
840 	complete_phase(c, 'S');
841 	return;
842 NOTIMP:
843 	response_rcode(c, DNS_R_NOTIMP);
844 	complete_phase(c, 'I');
845 	return;
846 WEIRDCLASS:
847 	response_rcode(c, DNS_R_FORMERR);
848 	complete_phase(c, 'C');
849 	return;
850 NOQ:
851 	complete_phase(c, '/');
852 	return;
853 }
translate_netbios(dns_ctx * c,char * q)854 static int translate_netbios(dns_ctx *c, char *q)
855 {
856 	register int i, j;
857 
858 	/* convert in place if it makes sense */
859 	if (q[0] != 32) {
860 		warning("i'm configured to do NETBIOS but this packet isn't right");
861 		return 0;
862 	}
863 
864 	/* convert to ascii :) */
865 	for (i = j = 1; i < 33; i++, j++, j++) {
866 		q[i] = ((q[j] - 0x41) << 4) | ((q[j+1] - 0x41));
867 	}
868 	q[0] = 16; q[17] = 0;
869 
870 	/* spaces are nulls */
871 	for (i = 1; i < 17; i++) {
872 		if (q[i] == 0x20 || q[i] == 0) {
873 			q[i+1] = 0;
874 			q[0] = i;
875 			break;
876 		}
877 	}
878 	/* slide over the rest of the query */
879 	for (j = 33; q[j]; i++, j++) {
880 		q[i] = q[j];
881 	}
882 	return 1;
883 }
engine_dns_answer_query(dns_ctx * c,char header[12])884 static void engine_dns_answer_query(dns_ctx *c, char header[12])
885 {
886 	char *q, *x, *y, qtype[2], qclass[2];
887 
888 	/* query */
889 	q = 0;
890 	if (!dns_packet_getname(c, &q)) goto NOQ;
891 	if (!dns_packet_copy(c, qtype, 2)) goto NOQ;
892 	if (!dns_packet_copy(c, qclass, 2)) goto NOQ;
893 	if (!q) goto NOQ; /* offensive */
894 
895 	if (c->request_name_alloc) {
896 		mem_free(c->request_name_alloc);
897 		c->request_name_alloc = 0;
898 	}
899 
900 	/* if this is a netbios request, do funny things */
901 	if (ldapdns.netbios
902 			/* these numbers are magic to NBT */
903 			&& qtype[0] == 0
904 				&& (qtype[1] == 0x20 || qtype[1] == 0x21)
905 			&& qclass[0] == 0 && qclass[1] == 0x01) {
906 		if (!translate_netbios(c, q))
907 			goto WEIRDCLASS;
908 
909 		/* mark this lookup as netbios */
910 		c->protnum = PROT_NETBIOS;
911 	} else
912 		c->protnum = PROT_DNS;
913 
914 	/* set default SOA */
915 	c->refresh = default_refresh;
916 	c->retry = default_retry;
917 	c->expire = default_expire;
918 	c->minimum = default_minimum;
919 	c->ttl = default_minimum;
920 
921 	c->subreq = 0;
922 	c->subreq_valid = 0;
923 	c->request_name_zone = 0;
924 	c->subreq_in = c->subreq_in_alloc = 0;
925 	c->wantdie = 0;
926 	c->search_base = 0;
927 	c->adlen = -1;
928 
929 	cleanup_lists(c, 3);
930 	while ((x = list_pop(&c->ns))) {
931 		mem_free(x);
932 	}
933 	c->ns = 0;
934 
935 	if (!response_query(c, q, qtype, qclass)) goto NOQ;
936 	response_id(c, header);
937 	if (qclass[0] == DNS_C_IN[0] && qclass[1] == DNS_C_IN[1]) {
938 		c->response->buf[2] |= 4;
939 	} else if (qclass[0] != DNS_C_ANY[0] || qclass[1] != DNS_C_ANY[1]) {
940 		goto WEIRDCLASS;
941 	}
942 
943 	c->response->buf[3] &= ~128;
944 
945 	/* QR flag: set response */
946 	if (!(header[2] & 1)) c->response->buf[2] &= ~1;
947 
948 	/* lowercase domainname */
949 	dns_domain_lower(q);
950 
951 	/* fill this up */
952 	c->request_name_alloc = c->request_name = q;
953 	c->request_record[0] = qtype[0];
954 	c->request_record[1] = qtype[1];
955 
956 	/* cache? */
957 #if 0
958 	if (ldapdns.roots && header[2] & 1) {
959 		/* recursion desired */
960 		/* XXX: cache hooks start here */
961 		return;
962 	}
963 #endif
964 	/* try to retarget this */
965 	if (*q) {
966 		y = q + (*q)+1;
967 		x = ht_fetch(&ldapdns.search, y, __str_clen(y));
968 		if (x) {
969 			/* simple rewritten search */
970 			c->request_attr = x;
971 			do_simple_search(c, q);
972 			return;
973 		}
974 	}
975 
976 	if ((qtype[0] == DNS_T_AXFR[0] && qtype[1] == DNS_T_AXFR[1])
977 	|| (qtype[0] == DNS_T_IXFR[0] && qtype[1] == DNS_T_IXFR[1])) {
978 		if (!c->axfr_base) {
979 			/* no AXFR allowed on this session */
980 			warning("no AXFR base");
981 			goto NOTIMP;
982 		}
983 		if (c->axfr_base[0] == '\0') {
984 			/* anywhere: single dot */
985 			do_axfrsearch(c, q);
986 			return;
987 		}
988 
989 		/* q MUST be a valid dns domain */
990 		for (x = q; *x; x += ((*x) + 1)) {
991 			if (str_equali(x, c->axfr_base)) {
992 				/* okay! this is nice */
993 				do_axfrsearch(c, q);
994 				return;
995 			}
996 		}
997 		goto NOTIMP;
998 	}
999 
1000 	/* zone search */
1001 	do_zonesearch(c, q);
1002 	return;
1003 NOTIMP:
1004 	response_rcode(c, DNS_R_NOTIMP);
1005 	complete_phase(c, 'I');
1006 	return;
1007 WEIRDCLASS:
1008 	response_rcode(c, DNS_R_FORMERR);
1009 	complete_phase(c, 'C');
1010 	return;
1011 NOQ:
1012 	complete_phase(c, '/');
1013 	return;
1014 }
do_update_section(dns_ctx * c,char * d,char header[12],int section,list_t * p)1015 static int do_update_section(dns_ctx *c, char *d, char header[12], int section, list_t *p)
1016 {
1017 	char *x, xtype[2], xclass[2], xttl[4];
1018 	unsigned short n, m;
1019 	bin_t r;
1020 	int i, j;
1021 
1022 	/* read off sections */
1023 	/* Clib */
1024 	memcpy(&n, header + section, 2); n = ntohs(n);
1025 	for (i = 0; i < n; i++) {
1026 		x = 0;
1027 		if (!(j=dns_packet_getname(c, &x))) return 0;
1028 		if (!dns_packet_copy(c, xtype, 2)) return 0;
1029 		if (!dns_packet_copy(c, xclass, 2)) return 0;
1030 		if (!dns_packet_copy(c, xttl, 4)) return 0;
1031 		if (!dns_packet_copy(c, (char *)&m, sizeof(m))) return 0;
1032 		m = ntohs(m); /* m = length of packet; Clib */
1033 
1034 		bin_init(r);
1035 		bin_copy(r, xclass, 2);
1036 		bin_cat(r, xtype, 2);
1037 		bin_cat(r, xttl, 2);
1038 		bin_cat(r, x, __str_clen(x));
1039 		bin_cat(r, d, __str_clen(d)+1);/* also get \0 */
1040 		mem_free(x);
1041 		bin_cat(r, (char *)&m, sizeof(m)); /* length of rrdata */
1042 		if (m > 0) {
1043 			j = clen(r);
1044 			bin_needplus(r, m);
1045 			if (!dns_packet_copy(c, caddr(r)+j, m)) return 0;
1046 		}
1047 
1048 		list_push(p, caddr(r));
1049 	}
1050 	return 1;
1051 }
handle_generic_compare(dns_ctx * c,const unsigned char * p,const unsigned char * pdata,unsigned int plen)1052 static int inline handle_generic_compare(dns_ctx *c, const unsigned char *p,
1053 		const unsigned char *pdata, unsigned int plen) {
1054 	unsigned short glen;
1055 	int nl;
1056 
1057 	glen = *(unsigned short *)(p+2);
1058 	p += 4;
1059 	while (glen > 0) {
1060 		if (*p == 0xFF) {
1061 			glen--; p++;
1062 			if (glen <= 0) {
1063 				return 0;
1064 			}
1065 			if (*p == 0x00) {
1066 				/* expecting a \0377 */
1067 				if (*pdata != 0xFF) {
1068 					return 0;
1069 				}
1070 				pdata++; plen--;
1071 				glen--; p++;
1072 			} else {
1073 				/* dns-encoded name */
1074 				for (;;) {
1075 					if (*pdata != *p)
1076 						return 0;
1077 					if (*p == 0) {
1078 						glen--; p++;
1079 						pdata++; plen--;
1080 						break;
1081 					}
1082 					if (glen <= 0)
1083 						return 0;
1084 					nl = ((*p)+1);
1085 					pdata += nl; plen -= nl;
1086 					p += nl; glen -= nl;
1087 				}
1088 			}
1089 		} else if (*p == *pdata) {
1090 			glen--; p++;
1091 			pdata++; plen--;
1092 		} else {
1093 			return 0;
1094 		}
1095 	}
1096 	return 1;
1097 }
rrset_test(dns_ctx * c,char * pdata)1098 static int rrset_test(dns_ctx *c, char *pdata)
1099 {
1100 	char *xtype = pdata;
1101 	char *domain, *q;
1102 	unsigned short n;
1103 	list_t *r;
1104 	int offset, i;
1105 
1106 	pdata++;pdata++; /* TTL */
1107 	pdata++;pdata++; /* domain */
1108 	domain = pdata;
1109 	while (*pdata) pdata++; pdata++;
1110 	memcpy(&n, pdata, sizeof(n)); /* length of rrdata */
1111 	pdata++; pdata++;
1112 
1113 	/* Generic test first */
1114 	if (c->Generic) {
1115 		/* Generic first; should handle compression ! */
1116 		while ((q = list_pop(&c->Generic))) {
1117 			if (q[0] == xtype[0] && q[1] == xtype[1]) {
1118 				i = handle_generic_compare(c, q, pdata, n);
1119 				if (i != -1)
1120 					return i;
1121 			} else
1122 				mem_free(q);
1123 		}
1124 	}
1125 
1126 	offset = 0;
1127 	if (xtype[0] == DNS_T_A[0] && xtype[1] == DNS_T_A[1]) {
1128 		/* A record test */
1129 		if (c->A) {
1130 			if (n == 0) return 1;
1131 			if (n != 4) return 0;
1132 			while ((q = list_pop(&c->A))) {
1133 				/* Clib */
1134 				if (memcmp(q, pdata, 4) == 0) {
1135 					mem_free(q);
1136 					return 1;
1137 				}
1138 				mem_free(q);
1139 			}
1140 		}
1141 		return 0;
1142 	} else if (xtype[0] == DNS_T_MX[0] && xtype[1] == DNS_T_MX[1]) {
1143 		/* ignore preference (it's easier) */
1144 		offset = 2;
1145 		r = &c->MX;
1146 	} else if (xtype[0] == DNS_T_CNAME[0] && xtype[1] == DNS_T_CNAME[1]) {
1147 		r = &c->CNAME;
1148 	} else if (xtype[0] == DNS_T_TXT[0] && xtype[1] == DNS_T_TXT[1]) {
1149 		r = &c->TXT;
1150 	} else if (xtype[0] == DNS_T_PTR[0] && xtype[1] == DNS_T_PTR[1]) {
1151 		r = &c->PTR;
1152 	} else {
1153 		return 0;
1154 	}
1155 
1156 	if (!*r) return 0;
1157 	if (n == 0) return 1;
1158 	while ((q = list_pop(r))) {
1159 		for (i = offset; i < n; i++) {
1160 			if (q[i] != pdata[i])
1161 				break;
1162 		}
1163 		mem_free(q);
1164 		if (i == n)
1165 			return 1;
1166 	}
1167 	return 0;
1168 }
start_next_update_operation(dns_ctx * c)1169 static void start_next_update_operation(dns_ctx *c)
1170 {
1171 	str_t s;
1172 	char *p,*d;
1173 	int r;
1174 
1175 next_l:
1176 	p = list_pop(&c->sec_update);
1177 	if (!p) {
1178 		/* all done? */
1179 		response_rcode(c, DNS_R_NOERROR);
1180 		complete_phase(c, '+');
1181 		return;
1182 	}
1183 
1184 	d = p+6;
1185 	r = -1;
1186 	dns_to_name(s, d, 0);
1187 	/* XXX this will actually do the work */
1188 	if (p[0] == DNS_C_ANY[0] && p[1] == DNS_C_ANY[1]) {
1189 		if (p[2] == DNS_T_ANY[0] && p[2] == DNS_T_ANY[1]) {
1190 			/* delete all rrs from a name */
1191 			warning("NS-UPDATE: Delete all RR's from: %s", str(s));
1192 		} else {
1193 			/* delete all of an rr */
1194 			warning("NS-UPDATE: Delete all RR of a type from: %s", str(s));
1195 		}
1196 	} else if (p[0] == DNS_C_NONE[0] && p[1] == DNS_C_NONE[1]) {
1197 		/* delete rr from rrset */
1198 		if (p[2] == DNS_T_ANY[0] && p[2] == DNS_T_ANY[1]) {
1199 			response_rcode(c, DNS_R_FORMERR);
1200 			complete_phase(c, 'C');
1201 			return;
1202 		}
1203 		warning("NS-UPDATE: Delete an RR in an rrset from: %s", str(s));
1204 	} else {
1205 		/* add rrset */
1206 		warning("NS-UPDATE: Add an RR to: %s", str(s));
1207 	}
1208 	if (r == -1) goto next_l;
1209 }
ldapdns_process_update(dns_ctx * c)1210 static void ldapdns_process_update(dns_ctx *c)
1211 {
1212 	int err_code;
1213 	int exists;
1214 	str_t sa, sb;
1215 	char *p;
1216 	int r;
1217 
1218 	if (!c->message) {
1219 		goto start_next_l;
1220 	}
1221 
1222 	//printf("phase1\n");
1223 	ldap_parse_result(c->c->ldap_con, c->message,
1224 			&err_code,
1225 			0,0,0,0,0);
1226 	if (err_code != LDAP_SUCCESS) {
1227 		if (err_code == LDAP_SERVER_DOWN) {
1228 			pthread_mutex_lock(&c->c->lock);
1229 			restart_ldap_connection(c->c);
1230 			pthread_mutex_unlock(&c->c->lock);
1231 			/* we need to resend query */
1232 			c->request_name = c->request_name_alloc;
1233 			do_zonesearch(c, c->request_name_alloc);
1234 			return;
1235 		} else if (err_code == LDAP_TIMEOUT) {
1236 			/*response_refuse(c);*/
1237 			complete_phase(c, '?');
1238 			return;
1239 		} else if (err_code == LDAP_NO_SUCH_OBJECT
1240 		|| err_code == LDAP_LOOP_DETECT
1241 		|| err_code == LDAP_UNWILLING_TO_PERFORM
1242 		|| err_code == LDAP_ALIAS_PROBLEM
1243 		|| err_code == LDAP_INVALID_SYNTAX
1244 		|| err_code == LDAP_INAPPROPRIATE_MATCHING
1245 		|| err_code == LDAP_NO_SUCH_ATTRIBUTE) {
1246 			/* okay did not exist... */
1247 			exists = 0;
1248 		} else
1249 			fatal("ldap_result (nsupdate): %s", ldap_err2string(err_code));
1250 	} else {
1251 		exists = 1;
1252 
1253 		/* we have results... process SOA/NS */
1254 		ldap_load_dns_attributes(c, 0, 1);
1255 	}
1256 	p = list_pop(&c->sec_prereq);
1257 	if (p) {
1258 		/* test on exists */
1259 		if (p[0] == DNS_C_NONE[0] && p[1] == DNS_C_NONE[1]) {
1260 			if (exists) {
1261 				if (p[2] == DNS_T_ANY[0] && p[3] == DNS_T_ANY[1]) {
1262 					/* nxdomain */
1263 					response_rcode(c, DNS_R_NXDOMAIN);
1264 					response_nxdomain(c);
1265 					complete_phase(c, 'N');
1266 					return;
1267 				} else if (rrset_test(c, p+2)) {
1268 					/* nxrrset */
1269 					response_rcode(c, DNS_R_NXRRSET);
1270 					response_nxdomain(c);
1271 					complete_phase(c, 'n');
1272 					return;
1273 				}
1274 			}
1275 			/* succeeded */
1276 		} else if ((p[0] == DNS_C_IN[0] && p[1] == DNS_C_IN[1])
1277 				|| (p[0] == DNS_C_ANY[0] && p[1] == DNS_C_ANY[1])) {
1278 			if (!exists) {
1279 				/* nxdomain */
1280 				response_rcode(c, DNS_R_YXDOMAIN);
1281 				response_nxdomain(c);
1282 				complete_phase(c, 'Y');
1283 				return;
1284 			}
1285 			if (p[2] != DNS_T_ANY[0] && p[3] != DNS_T_ANY[1]) {
1286 				if (!rrset_test(c, p+2)) {
1287 					/* yxrrset */
1288 					response_rcode(c, DNS_R_YXRRSET);
1289 					response_nxdomain(c);
1290 					complete_phase(c, 'y');
1291 					return;
1292 				}
1293 			}
1294 		}
1295 	}
1296 
1297 start_next_l:
1298 	cleanup_lists(c, 3); /* keep NS data (if we got any) */
1299 
1300 	if (c->sec_prereq && c->sec_prereq->str) {
1301 		p = c->sec_prereq->str + 6;
1302 	} else if (c->sec_update && c->sec_update->str) {
1303 		start_next_update_operation(c);
1304 		return;
1305 	} else {
1306 		/* all done? */
1307 		response_rcode(c, DNS_R_NOERROR);
1308 		complete_phase(c, '+');
1309 		return;
1310 	}
1311 
1312 retry_nsupdate_top_l:
1313 	/* start request on domain name p */
1314 	/* q is valid: safe */
1315 	dns_to_name(sa, p, 0);
1316 	name_to_ldap(sb, str(sa)); /* calls str_init sb */
1317 	if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
1318 		str_cat(sb, ", ");
1319 		str_cat(sb, ldapdns.ldap_suffix);
1320 	}
1321 
1322 	pthread_mutex_lock(&c->c->lock);
1323 	r = ldap_search(c->c->ldap_con,
1324 			str(sb),		/* base */
1325 			LDAP_SCOPE_BASE,	/* scope */
1326 			"(objectClass=*)",	/* ldap filter */
1327 			NULL,			/* all attributes */
1328 			0);			/* attrsonly */
1329 	mem_free(str(sa));
1330 	mem_free(str(sb));
1331 
1332 	if (r == -1) {
1333 		/* uh oh: possibly an out of memory error */
1334 		restart_ldap_connection(c->c);
1335 		pthread_mutex_unlock(&c->c->lock);
1336 		goto retry_nsupdate_top_l;
1337 	}
1338 
1339 	//printf("sent query for %d (was %d)\n", r, c->message_id);
1340 	c->message_id = r;
1341 	c->phase = PHASE_NSUPDATE;
1342 
1343 	c->c->message_sent++;
1344 	//warning("nsupdate %d / %d", c->c->message_sent, c->c->message_wait);
1345 	if (c->c->message_wait) pthread_cond_broadcast(&c->c->active);
1346 
1347 	pthread_mutex_unlock(&c->c->lock);
1348 }
engine_dns_answer_update(dns_ctx * c,int op,char header[12])1349 static void engine_dns_answer_update(dns_ctx *c, int op, char header[12])
1350 {
1351 	char *q, qtype[2], qclass[2];
1352 	char *z, ztype[2], zclass[2], zttl[4], zrd[2], zip[4];
1353 	bin_t b;
1354 	int i;
1355 
1356 	/* flush this */
1357 	while (list_pop(&c->sec_prereq));
1358 	while (list_pop(&c->sec_update));
1359 
1360 	/* query */
1361 	q = 0;
1362 	if (!dns_packet_getname(c, &q)) goto NOQ;
1363 	if (!dns_packet_copy(c, qtype, 2)) goto NOQ;
1364 	if (!dns_packet_copy(c, qclass, 2)) goto NOQ;
1365 	if (!q) goto NOQ; /* offensive */
1366 
1367 	if (c->request_name_alloc) {
1368 		mem_free(c->request_name_alloc);
1369 		c->request_name_alloc = 0;
1370 	}
1371 	c->request_name_alloc = q;
1372 
1373 	/* in netbios mode, the sections are faked
1374 	 * we verify that the address being added/removed
1375 	 * is the one the client is on
1376 	 *
1377 	 * NB NAME REGISTRATION encodes data in the question+additional parts
1378 	 * NS UPDATE encodes data in the answer+authority parts
1379 	 *
1380 	 * kind of sick, yeah?
1381 	 */
1382 	if (ldapdns.netbios
1383 			/* these numbers are magic to NBT :) */
1384 			&& qtype[0] == 0
1385 				&& (qtype[1] == 0x20 || qtype[1] == 0x21)
1386 			&& qclass[0] == 0 && qclass[1] == 0x01) {
1387 		/* we need to fast-forward to additional section
1388 		 *
1389 		 * skip len at position
1390 		 *
1391 		 */
1392 		z = 0;
1393 		if (!dns_packet_getname(c, &z)) goto NOQ;
1394 		if (!z) goto NOQ;
1395 		if (str_diff(z, q)) goto NOQ;
1396 		if (!dns_packet_copy(c, ztype, 2)) goto NOQ;
1397 		if (!dns_packet_copy(c, zclass, 2)) goto NOQ;
1398 
1399 		if (ztype[0] != qtype[0]) goto NOQ;
1400 		if (ztype[1] != qtype[1]) goto NOQ;
1401 		if (zclass[0] != qclass[0]) goto NOQ;
1402 		if (zclass[1] != qclass[1]) goto NOQ;
1403 
1404 		if (!dns_packet_copy(c, zttl, 4)) goto NOQ;
1405 		if (!dns_packet_copy(c, zrd, 2)) goto NOQ;
1406 		if (zrd[0] != 0 && zrd[1] != 6) goto NOQ;
1407 
1408 		/* load the flags */
1409 		if (!dns_packet_copy(c, zrd, 2)) goto NOQ;
1410 
1411 		/* requested node IP */
1412 		if (!dns_packet_copy(c, zip, 4)) goto NOQ;
1413 
1414 		/* standard protection: TODO make this possible from gateway */
1415 		if (zip[0] != c->ip[0]) goto NOQ;
1416 		if (zip[1] != c->ip[1]) goto NOQ;
1417 		if (zip[2] != c->ip[2]) goto NOQ;
1418 		if (zip[3] != c->ip[3]) goto NOQ;
1419 
1420 		/* translate the name */
1421 		if (!translate_netbios(c, q))
1422 			goto NOQ;
1423 
1424 		/* *-* translate the sections *-* */
1425 
1426 		if (op == DNS_O_RELEASE) {
1427 			/* UPDATE: NB record */
1428 			bin_init(b);
1429 			bin_addch(b, DNS_C_NONE[0]);
1430 			bin_addch(b, DNS_C_NONE[1]);
1431 			bin_addch(b, DNS_T_NB[0]);
1432 			bin_addch(b, DNS_T_NB[1]);
1433 			bin_addch(b, 0);bin_addch(b, 6);
1434 			bin_addch(b, zrd[0]);
1435 			bin_addch(b, zrd[1]);
1436 			bin_cat(b, zip, 4);
1437 			list_push(&c->sec_update, caddr(b));
1438 
1439 			/* UPDATE: A record */
1440 			bin_init(b);
1441 			bin_addch(b, DNS_C_NONE[0]);
1442 			bin_addch(b, DNS_C_NONE[1]);
1443 			bin_addch(b, DNS_T_A[0]);
1444 			bin_addch(b, DNS_T_A[1]);
1445 			bin_addch(b, 0);bin_addch(b, 4);
1446 			bin_cat(b, zip, 4);
1447 			list_push(&c->sec_update, caddr(b));
1448 		} else {
1449 			if (op == DNS_O_UPDATE) {
1450 				/* NXRRSET; address record */
1451 				bin_init(b);
1452 				bin_addch(b, DNS_C_NONE[0]);
1453 				bin_addch(b, DNS_C_NONE[1]);
1454 				bin_addch(b, DNS_T_A[0]);
1455 				bin_addch(b, DNS_T_A[1]);
1456 				bin_addch(b, 0);bin_addch(b, 4);
1457 				bin_cat(b, c->ip, 4);
1458 				list_push(&c->sec_update, caddr(b));
1459 
1460 				/* NXRRSET: NB record */
1461 				bin_init(b);
1462 				bin_addch(b, DNS_C_NONE[0]);
1463 				bin_addch(b, DNS_C_NONE[1]);
1464 				bin_addch(b, DNS_T_NB[0]);
1465 				bin_addch(b, DNS_T_NB[1]);
1466 				bin_addch(b, 0);bin_addch(b, 6);
1467 				bin_addch(b, '\x00');	/* NB mode explicitly ignores this */
1468 				bin_addch(b, '\x00');
1469 				bin_cat(b, zip, 4);
1470 				list_push(&c->sec_update, caddr(b));
1471 			}
1472 
1473 			/* UPDATE: NB record */
1474 			bin_init(b);
1475 			bin_addch(b, DNS_C_IN[0]);
1476 			bin_addch(b, DNS_C_IN[1]);
1477 			bin_addch(b, DNS_T_NB[0]);
1478 			bin_addch(b, DNS_T_NB[1]);
1479 			bin_addch(b, 0);bin_addch(b, 6);
1480 			bin_addch(b, zrd[0]);
1481 			bin_addch(b, zrd[1]);
1482 			bin_cat(b, zip, 4);
1483 			list_push(&c->sec_update, caddr(b));
1484 
1485 			/* UPDATE: A record */
1486 			bin_init(b);
1487 			bin_addch(b, DNS_C_IN[0]);
1488 			bin_addch(b, DNS_C_IN[1]);
1489 			bin_addch(b, DNS_T_A[0]);
1490 			bin_addch(b, DNS_T_A[1]);
1491 			bin_addch(b, 0);bin_addch(b, 4);
1492 			bin_cat(b, zip, 4);
1493 			list_push(&c->sec_update, caddr(b));
1494 		}
1495 
1496 		/* mark this lookup as netbios */
1497 		c->protnum = PROT_NETBIOS;
1498 	} else {
1499 		c->protnum = PROT_DNS;
1500 
1501 		/* load sections */
1502 		if (!do_update_section(c, q, header,
1503 				REQUEST_PRE, &c->sec_prereq)) goto NOQ;
1504 		if (!do_update_section(c, q, header,
1505 				REQUEST_UPDATE, &c->sec_update)) goto NOQ;
1506 
1507 		/* reverse these... (order MAY be important...) */
1508 		list_reverse(&c->sec_prereq);
1509 		list_reverse(&c->sec_update);
1510 	}
1511 
1512 	/* copy response... */
1513 	c->response->used = 0;
1514 	response_addbytes(c, header, 12);
1515 	/* turn off question bit */
1516 	c->response->buf[2] &= ~1;
1517 	c->response->buf[2] |= 128;
1518 	c->response->buf[2] &= ~(0x0F<<3);
1519 	c->response->buf[2] |= 5<<3;
1520 	c->response->buf[3] = 0;
1521 	for (i = 4; i < 12; i++) c->response->buf[i] = 0;
1522 	c->response->used = 12;
1523 	response_id(c, header);
1524 
1525 	/* okay, for each entry, start the appropriate ldap query */
1526 	c->message = 0;
1527 	c->phase = PHASE_NSUPDATE;
1528 	ldapdns_process_update(c); /* this also starts up the request */
1529 	return;
1530 NOQ:
1531 	c->response->used = 0;
1532 	complete_phase(c, '/');
1533 	return;
1534 }
engine_dns_answer(dns_ctx * c,time_t now)1535 static void engine_dns_answer(dns_ctx *c, time_t now)
1536 {
1537 	/* first, we need to setup/parse the headers of the dns request */
1538 	char header[12];
1539 	int op;
1540 
1541 	/* default serial is always */
1542 
1543 	c->serial = now;
1544 	c->soahack = 0;
1545 
1546 	/* copy the header and make sure this is infact a question */
1547 	if (!dns_packet_copy(c, header, 12)) goto NOQ;
1548 	if (header[2] & 128) goto NOQ; /* response flag */
1549 
1550 	/* do something with the opcode? */
1551 	op = (header[2] >> 3) & 0xF;
1552 	switch (op) {
1553 	case DNS_O_QUERY:
1554 		/* query; there must be exactly 1 query */
1555 		if (header[4]) goto NOQ;
1556 		if (header[5] != 1) goto NOQ;
1557 		engine_dns_answer_query(c, header);
1558 		return;
1559 	case DNS_O_UPDATE:
1560 	case DNS_O_RELEASE:
1561 		if (!ldapdns.update)
1562 			goto NOTIMP;
1563 		/* only one zone allowed (duh) */
1564 		if (header[4]) goto NOQ;
1565 		if (header[5] != 1) goto NOQ;
1566 		engine_dns_answer_update(c, op, header);
1567 		return;
1568 	case DNS_O_NOTIFY:
1569 		if (!ldapdns.notify)
1570 			goto NOTIMP;
1571 		/* do we have a notify helper-program? */
1572 		if (header[4]) goto NOQ;
1573 		if (header[5] != 1) goto NOQ;
1574 		engine_dns_answer_notify(c, header);
1575 		return;
1576 
1577 	case DNS_O_IQUERY:
1578 	case DNS_O_STATUS:
1579 		goto NOTIMP;
1580 	};
1581 NOTIMP:
1582 	/* copy the entire query */
1583 	c->response->used = 0;
1584 	response_addbytes(c, c->request_buf, c->request_len);
1585 	/* turn off question bit */
1586 	c->response->buf[2] &= ~1;
1587 	c->response->buf[3] &= ~128;
1588 	response_rcode(c, DNS_R_NOTIMP);
1589 	complete_phase(c, 'I');
1590 	return;
1591 NOQ:
1592 	complete_phase(c, '/');
1593 	return;
1594 }
ldapdns_process_zonesearch(dns_ctx * c)1595 static void ldapdns_process_zonesearch(dns_ctx *c)
1596 {
1597 	int err_code;
1598 	char *x;
1599 
1600 	list_t saved_NS;
1601 	unsigned long saved_soa[6];
1602 	int saved_wantdie;
1603 	int saved_adlen;
1604 
1605 	/* process NS/SOA search results; possibly rerun */
1606 	if (!c->message) {
1607 		/* odd... no message waiting? */
1608 		fatal("assertion: zonesearch processing without message!");
1609 	}
1610 
1611 	//printf("phase1\n");
1612 	ldap_parse_result(c->c->ldap_con, c->message,
1613 			&err_code,
1614 			0,0,0,0,0);
1615 	if (err_code != LDAP_SUCCESS) {
1616 		if (err_code == LDAP_SERVER_DOWN) {
1617 			pthread_mutex_lock(&c->c->lock);
1618 			restart_ldap_connection(c->c);
1619 			pthread_mutex_unlock(&c->c->lock);
1620 			/* we need to resend query */
1621 			c->request_name = c->request_name_alloc;
1622 			do_zonesearch(c, c->request_name_alloc);
1623 			return;
1624 		} else if (err_code == LDAP_TIMEOUT) {
1625 			/*response_refuse(c);*/
1626 			complete_phase(c, '?');
1627 			return;
1628 		} else if (err_code == LDAP_NO_SUCH_OBJECT
1629 		|| err_code == LDAP_LOOP_DETECT
1630 		|| err_code == LDAP_UNWILLING_TO_PERFORM
1631 		|| err_code == LDAP_ALIAS_PROBLEM
1632 		|| err_code == LDAP_INVALID_SYNTAX
1633 		|| err_code == LDAP_INAPPROPRIATE_MATCHING
1634 		|| err_code == LDAP_NO_SUCH_ATTRIBUTE) {
1635 			/* doesn't exist... let's chop the base up */
1636 			//printf("shoten\n");
1637 
1638 			if (c->subreq) {
1639 				/* skip the first dot and try again */
1640 				if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1641 					finish_subrequest(c);
1642 				} else {
1643 					c->subreq_in += ((*c->subreq_in)+1);
1644 					do_zonesearch(c, c->subreq_in);
1645 				}
1646 			} else if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1647 				response_nxdomain(c);
1648 				complete_phase(c, '-');
1649 			} else {
1650 				c->request_name += ((*c->request_name)+1);
1651 				do_zonesearch(c, c->request_name);
1652 			}
1653 			return;
1654 		}
1655 
1656 		fatal("ldap_result (zonesearch): %s", ldap_err2string(err_code));
1657 	}
1658 
1659 	/* we have results... process SOA/NS */
1660 	if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1661 		/* save list pointers */
1662 		if (c->adlen > -1) {
1663 			saved_NS = c->NS;
1664 			saved_soa[0] = c->serial;
1665 			saved_soa[1] = c->refresh;
1666 			saved_soa[2] = c->retry;
1667 			saved_soa[3] = c->expire;
1668 			saved_soa[4] = c->minimum;
1669 			saved_soa[5] = c->ttl;
1670 			saved_wantdie = c->wantdie;
1671 
1672 			c->refresh = default_refresh;
1673 			c->retry = default_retry;
1674 			c->expire = default_expire;
1675 			c->minimum = default_minimum;
1676 			c->ttl = c->minimum;
1677 
1678 			c->NS = 0;
1679 			c->wantdie = 0;
1680 			c->serial = c->lastt;
1681 		}
1682 		saved_adlen = c->adlen;
1683 		c->adlen = -1;
1684 	}
1685 
1686 	ldap_load_dns_attributes(c, &c->search_base, 0);
1687 
1688 	if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1689 //		if (c->adlen > -1)
1690 		add_peer_ns(c, 1);
1691 
1692 	}
1693 
1694 	if (ldapdns.dn_mode == DN_MODE_LDAPDNS && c->adlen > -1
1695 			&& saved_adlen > -1) {
1696 		if (saved_adlen > c->adlen) {
1697 			/* okay, we already had a better shot... free the
1698 			 * new ones and restore */
1699 			while ((x = list_pop(&c->NS))) mem_free(x);
1700 
1701 			c->NS = saved_NS;
1702 			c->serial = saved_soa[0];
1703 			c->refresh = saved_soa[1];
1704 			c->retry = saved_soa[2];
1705 			c->expire = saved_soa[3];
1706 			c->minimum = saved_soa[4];
1707 			c->ttl = saved_soa[5];
1708 			c->wantdie = saved_wantdie;
1709 			c->adlen = saved_adlen;
1710 
1711 		} else {
1712 			/* this one is better... free the saved */
1713 			while ((x = list_pop(&saved_NS))) mem_free(x);
1714 		}
1715 	}
1716 	if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1717 		/* more on the way... */
1718 		if (ldap_msgtype(c->message) == LDAP_RES_SEARCH_RESULT)
1719 			return;
1720 	}
1721 
1722 	/* try lowering ourselves... */
1723 	if (c->subreq) {
1724 		//printf("lower ourselves\n");
1725 		if (c->subreq_valid < c->subreq) {
1726 			if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1727 				finish_subrequest(c);
1728 			} else {
1729 				c->subreq_in += ((*c->subreq_in)+1);
1730 				do_zonesearch(c, c->subreq_in);
1731 			}
1732 			return;
1733 		}
1734 	} else if (!c->NS) {
1735 		/* still not good enough */
1736 		/* skip the first dot and try again */
1737 		if (ldapdns.dn_mode == DN_MODE_LDAPDNS) {
1738 			response_nxdomain(c);
1739 			complete_phase(c, '-');
1740 		} else {
1741 			c->request_name += ((*c->request_name)+1);
1742 			do_zonesearch(c, c->request_name);
1743 		}
1744 		return;
1745 	}
1746 
1747 	/* okay, back up to original request and send it */
1748 	if (c->subreq) {
1749 		c->subreq_in = c->subreq_in_alloc;
1750 		c->attr_wild = 0;
1751 		do_attrsearch(c, c->subreq_in, 0);
1752 	} else {
1753 		//printf("okay, move back up to %s\n", c->request_name_alloc);
1754 		c->request_name_zone = c->request_name;
1755 		c->request_name = c->request_name_alloc;
1756 		if (c->axfr) {
1757 			do_axfrsearch(c, c->request_name);
1758 		} else {
1759 			c->attr_wild = 0;
1760 			do_attrsearch(c, c->request_name, 0);
1761 		}
1762 	}
1763 }
push_subreq(dns_ctx * c,char * q)1764 static void inline push_subreq(dns_ctx *c, char *q)
1765 {
1766 	list_t lp;
1767 
1768 	/* make sure we haven't done this guy yet (save ourselves time) */
1769 	for (lp = c->subreq_done; lp; lp = lp->next) {
1770 		if (str_equali(lp->str, q)) return;
1771 	}
1772 
1773 	/* add to the lists */
1774 	list_push(&c->subreq_tries, str_dup(q));
1775 }
1776 
1777 static void inline
response_generic(dns_ctx * c,int ax,char * q,unsigned char * p,unsigned long ttl)1778 response_generic(dns_ctx *c, int ax, char *q, unsigned char *p, unsigned long ttl)
1779 {
1780 	unsigned short glen;
1781 	int dlen;
1782 
1783 	glen = *(unsigned short *)(p+2);
1784 	if (ax) {
1785 		if (!response_axstart(c, 0, q, p, DNS_C_IN, ttl)) {
1786 			fatal("could not construct generic");
1787 		}
1788 	} else {
1789 		if (!response_rstart(c, q, p, ttl)) {
1790 			fatal("could not construct generic");
1791 		}
1792 	}
1793 	p += 4;
1794 	while (glen > 0) {
1795 		if (*p == 0xFF) {
1796 			glen--; p++;
1797 			if (glen <= 0) {
1798 				fatal("could not construct generic");
1799 			}
1800 			if (*p == 0x00) {
1801 				if (!response_addbytes(c, "\377", 1)) {
1802 					fatal("could not construct generic");
1803 				}
1804 				glen--; p++;
1805 			} else {
1806 				/* dns-encoded name */
1807 				if (!response_addname(c, p)) {
1808 					fatal("could not construct generic");
1809 				}
1810 				dlen = dns_domain_length(p);
1811 				/* do we want to do subrequests? */
1812 				if (!ldapdns.no_additionals)
1813 					push_subreq(c, p);
1814 				glen -= dlen; p += dlen;
1815 			}
1816 		} else {
1817 			if (!response_addbytes(c, p, 1)) {
1818 				fatal("could not construct generic");
1819 			}
1820 			glen--; p++;
1821 		}
1822 	}
1823 }
add_peer_ns(dns_ctx * c,int inc)1824 static void inline add_peer_ns(dns_ctx *c, int inc) {
1825 	list_t lp;
1826 	char *x;
1827 
1828 	if (inc) {
1829 		/* then also attach peer_ns and self_ns */
1830 		for (lp = ldapdns.peer_ns; lp; lp = lp->next) {
1831 			list_push(&c->NS, str_dup(lp->str));
1832 		}
1833 		if (ldapdns.self_ns)
1834 			list_push(&c->NS, str_dup(ldapdns.self_ns));
1835 	}
1836 
1837 	/* don't add nameservers unless we've already got one (including @) */
1838 	if (c->NS) {
1839 		/* make sure only unique nameservers are listed */
1840 		ldapdns_list_unique(&c->NS);
1841 
1842 		lp = 0;
1843 		while ((x = list_pop(&c->NS))) {
1844 			if (x[0] == 1 && x[1] == '@' && x[2] == 0) {
1845 				mem_free(x);
1846 				continue;
1847 			}
1848 			list_push(&lp, x);
1849 		}
1850 		list_reverse(&lp);
1851 		c->NS = lp;
1852 	}
1853 }
ldapdns_process_attrsearch(dns_ctx * c,int no_wild)1854 static void ldapdns_process_attrsearch(dns_ctx *c, int no_wild)
1855 {
1856 	int err_code;
1857 	char *dat;
1858 	list_t lp;
1859 	int ext_records, selfmatch;
1860 	int didany = 0;
1861 
1862 	/* process NS/SOA search results; possibly rerun */
1863 	if (!c->message) {
1864 		/* odd... no message waiting? */
1865 		fatal("assertion: attrsearch processing without message!");
1866 	}
1867 
1868 	//printf("attrsearch\n");
1869 	ldap_parse_result(c->c->ldap_con, c->message,
1870 			&err_code,
1871 			0,0,0,0,0);
1872 	if (err_code != LDAP_SUCCESS) {
1873 		if (err_code == LDAP_SERVER_DOWN) {
1874 			pthread_mutex_lock(&c->c->lock);
1875 			restart_ldap_connection(c->c);
1876 			pthread_mutex_unlock(&c->c->lock);
1877 			if (no_wild) {
1878 				/* resend original */
1879 				do_simple_search(c, c->request_name);
1880 			} else
1881 			/* resend phase-2 query */
1882 			if (c->subreq) {
1883 				do_attrsearch(c, c->subreq_in, c->attr_wild);
1884 			} else {
1885 				do_attrsearch(c, c->request_name, c->attr_wild);
1886 			}
1887 			return;
1888 		} else if (err_code == LDAP_TIMEOUT) {
1889 			/*response_refuse(c);*/
1890 			complete_phase(c, '?');
1891 			return;
1892 		} else if (err_code == LDAP_NO_SUCH_OBJECT
1893 		|| err_code == LDAP_LOOP_DETECT
1894 		|| err_code == LDAP_UNWILLING_TO_PERFORM
1895 		|| err_code == LDAP_ALIAS_PROBLEM
1896 		|| err_code == LDAP_INVALID_SYNTAX
1897 		|| err_code == LDAP_INAPPROPRIATE_MATCHING
1898 		|| err_code == LDAP_NO_SUCH_ATTRIBUTE) {
1899 			/* doesn't exist... let's chop the base up */
1900 			/* and put it in wildmode */
1901 			//printf("did not exist?\n");
1902 			//
1903 			if (no_wild) {
1904 				/* this is a real failure */
1905 				response_refuse(c);
1906 				complete_phase(c, '-');
1907 				return;
1908 			}
1909 
1910 			/* skip the first dot and try again */
1911 			c->attr_wild = 1;
1912 			if (c->subreq) {
1913 				c->subreq_in += ((*c->subreq_in)+1);
1914 				do_attrsearch(c, c->subreq_in, 1);
1915 			} else {
1916 				c->request_name += ((*c->request_name)+1);
1917 				do_attrsearch(c, c->request_name, 1);
1918 			}
1919 			return;
1920 		}
1921 
1922 		fatal("ldap_result (zonesearch): %s", ldap_err2string(err_code));
1923 	}
1924 
1925 	/* we have results... load them into lists*/
1926 	//printf("go in here?\n");
1927 	ldap_load_dns_attributes(c, 0, 1);
1928 	//printf("go out here?\n");
1929 
1930 	/* randomize arecords if requested */
1931 	switch (ldapdns.schedule_arecord) {
1932 	case SCHEDULE_A_RANDOM:
1933 		list_randomize(&c->A);
1934 		break;
1935 	}
1936 
1937 	if (c->subreq) {
1938 		//printf("eating addresses?\n");
1939 		if (c->A) {
1940 			while ((dat = list_pop(&c->A))) {
1941 				if (!response_rstart(c, c->subreq_in_alloc,
1942 							DNS_T_A, c->ttl)
1943 				|| !response_addbytes(c, dat, 4)) {
1944 					fatal("could not construct address");
1945 				}
1946 				response_rfinish(c, RESPONSE_ADDITIONAL);
1947 				mem_free(dat);
1948 			}
1949 		}
1950 		finish_subrequest(c);
1951 		return;
1952 	}
1953 
1954 	/* makes it "easy" to kill records */
1955 	if (c->wantdie) {
1956 		response_refuse(c);
1957 		complete_phase(c, '-');
1958 		return;
1959 	}
1960 
1961 #define _eq2(a) (a[0] == c->request_record[0] && a[1] == c->request_record[1])
1962 	if (_eq2(DNS_T_SOA)) {
1963 		/* SOA needs: NS1, original query, and hostmaster */
1964 		if (!c->NS) {
1965 			response_refuse(c);
1966 			complete_phase(c, '-');
1967 			return;
1968 		}
1969 
1970 		add_peer_ns(c, 0);
1971 		response_aa(c, 1);
1972 
1973 		if (!response_rstart(c, c->request_name_alloc, DNS_T_SOA, c->ttl)
1974 		|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
1975 		|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
1976 		|| !response_addulong(c, c->serial)
1977 		|| !response_addulong(c, c->refresh)
1978 		|| !response_addulong(c, c->retry)
1979 		|| !response_addulong(c, c->expire)
1980 		|| !response_addulong(c, c->minimum)) {
1981 			fatal("could not construct SOA");
1982 		}
1983 		response_rfinish(c, RESPONSE_ANSWER);
1984 		while ((dat = list_pop(&c->NS))) {
1985 			if (!response_rstart(c, c->request_name_zone, DNS_T_NS, c->ttl)
1986 			|| !response_addname(c, dat)) {
1987 				fatal("could not construct NS");
1988 			}
1989 			response_rfinish(c, RESPONSE_AUTHORITY);
1990 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
1991 				push_subreq(c, dat);
1992 			mem_free(dat);
1993 		}
1994 		if (no_wild)
1995 			complete_phase(c, '+');
1996 		else if (c->subreq_tries) {
1997 			c->subreq++;
1998 			finish_subrequest(c);
1999 		} else
2000 			complete_phase(c, '+');
2001 		return;
2002 	}
2003 
2004 	ext_records = 0;
2005 	if (c->Generic) {
2006 		/* Generic first */
2007 		while ((dat = list_pop(&c->Generic))) {
2008 			if (dat[0] != DNS_T_NS[0] && dat[1] != DNS_T_NS[1])
2009 				ext_records++;
2010 
2011 			if (_eq2(dat)) {
2012 				response_generic(c, 0, c->request_name_alloc,
2013 						dat, c->ttl);
2014 				response_rfinish(c, RESPONSE_ANSWER);
2015 			}
2016 
2017 			mem_free(dat);
2018 		}
2019 	}
2020 
2021 	/* flip the AA bit */
2022 	add_peer_ns(c, 0);
2023 	response_aa(c, 1);
2024 
2025 	/* address-style requests */
2026 	if (_eq2(DNS_T_ANY)) {
2027 		/* CNAME:A and MX */
2028 		if (c->A) {
2029 			/* so we don't say it again */
2030 			if (!ldapdns.no_additionals)
2031 				list_push(&c->subreq_done,
2032 					str_dup(c->request_name_alloc));
2033 
2034 			/* pop off each entry and add it's response */
2035 			while ((dat = list_pop(&c->A))) {
2036 				if (!response_rstart(c, c->request_name_alloc,
2037 							DNS_T_A, c->ttl)
2038 				|| !response_addbytes(c, dat, 4)) {
2039 					fatal("could not construct address");
2040 				}
2041 				response_rfinish(c, RESPONSE_ANSWER);
2042 				mem_free(dat);
2043 			}
2044 		} else if (c->CNAME) {
2045 			while ((dat = list_pop(&c->CNAME))) {
2046 				if (!response_rstart(c, c->request_name_alloc,
2047 							DNS_T_CNAME, c->ttl)
2048 				|| !response_addname(c, dat)) {
2049 					fatal("could not construct address");
2050 				}
2051 				response_rfinish(c, RESPONSE_ANSWER);
2052 				if (!ldapdns.no_additionals)
2053 					push_subreq(c, dat);
2054 				mem_free(dat);
2055 			}
2056 		}
2057 
2058 		if (c->PTR) {
2059 			/* this is silly */
2060 			while ((dat = list_pop(&c->PTR))) {
2061 				if (!response_rstart(c, c->request_name_alloc,
2062 							DNS_T_PTR, c->ttl)
2063 				|| !response_addname(c, dat)) {
2064 					fatal("could not construct address");
2065 				}
2066 				response_rfinish(c, RESPONSE_ANSWER);
2067 				mem_free(dat);
2068 			}
2069 		}
2070 
2071 		if (c->MX) {
2072 			while ((dat = list_pop(&c->MX))) {
2073 				if (!response_rstart(c, c->request_name_alloc,
2074 							DNS_T_MX, c->ttl)
2075 				|| !response_addbytes(c, dat, 2)
2076 				|| !response_addname(c, dat+2)) {
2077 					fatal("could not construct address");
2078 				}
2079 				response_rfinish(c, RESPONSE_ANSWER);
2080 				if (!ldapdns.no_additionals)
2081 					push_subreq(c, dat+2);
2082 				mem_free(dat);
2083 			}
2084 		}
2085 
2086 		/* return a SOA */
2087 		if ((no_wild && ldapdns.self_ns) || c->NS) {
2088 			if (!response_rstart(c, c->request_name_zone, DNS_T_SOA, c->ttl)
2089 			|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
2090 			|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2091 			|| !response_addulong(c, c->serial)
2092 			|| !response_addulong(c, c->refresh)
2093 			|| !response_addulong(c, c->retry)
2094 			|| !response_addulong(c, c->expire)
2095 			|| !response_addulong(c, c->minimum)) {
2096 				fatal("could not construct SOA");
2097 			}
2098 			response_rfinish(c, RESPONSE_ANSWER);
2099 		}
2100 
2101 		/* also included SOA */
2102 		for (lp = c->NS; lp; lp = lp->next) {
2103 			dat = lp->str;
2104 			if (!response_rstart(c, c->request_name_zone,
2105 						DNS_T_NS, c->ttl)
2106 			|| !response_addname(c, dat)) {
2107 				fatal("could not construct NS");
2108 			}
2109 			response_rfinish(c, RESPONSE_ANSWER);
2110 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2111 				push_subreq(c, dat);
2112 		}
2113 
2114 		/* also included SOA */
2115 		while ((dat = list_pop(&c->NS))) {
2116 			if (!response_rstart(c, c->request_name_zone,
2117 						DNS_T_NS, c->ttl)
2118 			|| !response_addname(c, dat)) {
2119 				fatal("could not construct NS");
2120 			}
2121 			response_rfinish(c, RESPONSE_AUTHORITY);
2122 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2123 				push_subreq(c, dat);
2124 			mem_free(dat);
2125 		}
2126 
2127 
2128 	} else if (_eq2(DNS_T_A)) {
2129 		/* CNAME:A */
2130 		if (c->A) {
2131 			if (!ldapdns.no_additionals)
2132 				list_push(&c->subreq_done,
2133 						str_dup(c->request_name_alloc));
2134 			while ((dat = list_pop(&c->A))) {
2135 				if (!response_rstart(c, c->request_name_alloc,
2136 							DNS_T_A, c->ttl)
2137 				|| !response_addbytes(c, dat, 4)) {
2138 					fatal("could not construct address");
2139 				}
2140 				response_rfinish(c, RESPONSE_ANSWER);
2141 				didany++;
2142 				mem_free(dat);
2143 			}
2144 		} else if (c->CNAME) {
2145 			while ((dat = list_pop(&c->CNAME))) {
2146 				if (!response_rstart(c, c->request_name_alloc,
2147 							DNS_T_CNAME, c->ttl)
2148 				|| !response_addname(c, dat)) {
2149 					fatal("could not construct address");
2150 				}
2151 				response_rfinish(c, RESPONSE_ANSWER);
2152 				if (!ldapdns.no_additionals)
2153 					push_subreq(c, dat);
2154 				didany++;
2155 				mem_free(dat);
2156 			}
2157 		}
2158 
2159 		if (!didany && c->NS) {
2160 			/* if no answers, but we're NS, we give SOA */
2161 			if (!response_rstart(c, c->request_name_zone, DNS_T_SOA, c->ttl)
2162 			|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
2163 			|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2164 			|| !response_addulong(c, c->serial)
2165 			|| !response_addulong(c, c->refresh)
2166 			|| !response_addulong(c, c->retry)
2167 			|| !response_addulong(c, c->expire)
2168 			|| !response_addulong(c, c->minimum)) {
2169 				fatal("could not construct SOA");
2170 			}
2171 			response_rfinish(c, RESPONSE_ANSWER);
2172 		}
2173 
2174 		/* also included SOA */
2175 		while ((dat = list_pop(&c->NS))) {
2176 			if (!response_rstart(c, c->request_name_zone,
2177 						DNS_T_NS, c->ttl)
2178 			|| !response_addname(c, dat)) {
2179 				fatal("could not construct NS");
2180 			}
2181 			response_rfinish(c, RESPONSE_AUTHORITY);
2182 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2183 				push_subreq(c, dat);
2184 			mem_free(dat);
2185 		}
2186 
2187 	} else if (ldapdns.netbios && _eq2(DNS_T_NB)) {
2188 		if (c->A) {
2189 			/* okay, normally these things are generic.
2190 			 * but we'll translate A records for them
2191 			 */
2192 			while ((dat = list_pop(&c->A))) {
2193 				if (!response_rstart(c, c->request_name_alloc,
2194 							DNS_T_NB, c->ttl)
2195 				/* netbios flags:
2196 				 * 	0x80 (unique)		'G'
2197 				 * 	0x20 P-node		'ont'
2198 				 */
2199 				|| !response_addbytes(c, "\x60\x00", 2)
2200 				|| !response_addbytes(c, dat, 4)) {
2201 					fatal("could not construct address");
2202 				}
2203 				response_rfinish(c, RESPONSE_ANSWER);
2204 				mem_free(dat);
2205 			}
2206 		}
2207 
2208 	} else if (_eq2(DNS_T_MX)) {
2209 		/* CNAME:A:MX */
2210 		selfmatch = 1;
2211 		if (c->MX) {
2212 			selfmatch = 0;
2213 			while ((dat = list_pop(&c->MX))) {
2214 				if (!response_rstart(c, c->request_name_alloc,
2215 							DNS_T_MX, c->ttl)
2216 				|| !response_addbytes(c, dat, 2)
2217 				|| !response_addname(c, dat+2)) {
2218 					fatal("could not construct address");
2219 				}
2220 				response_rfinish(c, RESPONSE_ANSWER);
2221 				if (str_equal(c->request_name_alloc, dat+2)) {
2222 					selfmatch = 2;
2223 				} else if (!ldapdns.no_additionals)
2224 					push_subreq(c, dat+2);
2225 				didany++;
2226 				mem_free(dat);
2227 			}
2228 		}
2229 
2230 		if (selfmatch == 1) {
2231 			if (c->A) {
2232 				if (!ldapdns.no_additionals)
2233 					list_push(&c->subreq_done,
2234 							str_dup(c->request_name_alloc));
2235 				while ((dat = list_pop(&c->A))) {
2236 					if (!response_rstart(c, c->request_name_alloc,
2237 								DNS_T_A, c->ttl)
2238 					|| !response_addbytes(c, dat, 4)) {
2239 						fatal("could not construct address");
2240 					}
2241 					didany++;
2242 					response_rfinish(c, RESPONSE_ANSWER);
2243 					mem_free(dat);
2244 				}
2245 			} else if (c->CNAME) {
2246 				while ((dat = list_pop(&c->CNAME))) {
2247 					if (!response_rstart(c, c->request_name_alloc,
2248 								DNS_T_CNAME, c->ttl)
2249 					|| !response_addname(c, dat)) {
2250 						fatal("could not construct address");
2251 					}
2252 					response_rfinish(c, RESPONSE_ANSWER);
2253 					didany++;
2254 					if (!ldapdns.no_additionals)
2255 						push_subreq(c, dat);
2256 					mem_free(dat);
2257 				}
2258 			}
2259 		}
2260 		if (!didany && c->NS) {
2261 			/* if no answers, but we're NS, we give SOA */
2262 			if (!response_rstart(c, c->request_name_zone, DNS_T_SOA, c->ttl)
2263 			|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
2264 			|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2265 			|| !response_addulong(c, c->serial)
2266 			|| !response_addulong(c, c->refresh)
2267 			|| !response_addulong(c, c->retry)
2268 			|| !response_addulong(c, c->expire)
2269 			|| !response_addulong(c, c->minimum)) {
2270 				fatal("could not construct SOA");
2271 			}
2272 			response_rfinish(c, RESPONSE_ANSWER);
2273 		}
2274 
2275 		/* also included SOA */
2276 		while ((dat = list_pop(&c->NS))) {
2277 			if (!response_rstart(c, c->request_name_zone,
2278 						DNS_T_NS, c->ttl)
2279 			|| !response_addname(c, dat)) {
2280 				fatal("could not construct NS");
2281 			}
2282 			response_rfinish(c, RESPONSE_AUTHORITY);
2283 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2284 				push_subreq(c, dat);
2285 			mem_free(dat);
2286 		}
2287 
2288 		if (selfmatch == 2) {
2289 			if (c->A) {
2290 				if (!ldapdns.no_additionals)
2291 					list_push(&c->subreq_done,
2292 							str_dup(c->request_name_alloc));
2293 				while ((dat = list_pop(&c->A))) {
2294 					if (!response_rstart(c, c->request_name_alloc,
2295 								DNS_T_A, c->ttl)
2296 					|| !response_addbytes(c, dat, 4)) {
2297 						fatal("could not construct address");
2298 					}
2299 					response_rfinish(c, RESPONSE_ADDITIONAL);
2300 					mem_free(dat);
2301 				}
2302 			} else if (c->CNAME) {
2303 				while ((dat = list_pop(&c->CNAME))) {
2304 					if (!response_rstart(c, c->request_name_alloc,
2305 								DNS_T_CNAME, c->ttl)
2306 					|| !response_addname(c, dat)) {
2307 						fatal("could not construct address");
2308 					}
2309 					response_rfinish(c, RESPONSE_ADDITIONAL);
2310 					if (!ldapdns.no_additionals)
2311 						push_subreq(c, dat);
2312 					mem_free(dat);
2313 				}
2314 			}
2315 		}
2316 
2317 	} else if (_eq2(DNS_T_CNAME)) {
2318 		while ((dat = list_pop(&c->CNAME))) {
2319 			if (!response_rstart(c, c->request_name_alloc, DNS_T_CNAME, c->ttl)
2320 			|| !response_addname(c, dat)) {
2321 				fatal("could not construct CNAME");
2322 			}
2323 			didany++;
2324 			response_rfinish(c, RESPONSE_ANSWER);
2325 			mem_free(dat);
2326 		}
2327 
2328 		if (!didany && c->NS) {
2329 			/* if no answers, but we're NS, we give SOA */
2330 			if (!response_rstart(c, c->request_name_zone, DNS_T_SOA, c->ttl)
2331 			|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
2332 			|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2333 			|| !response_addulong(c, c->serial)
2334 			|| !response_addulong(c, c->refresh)
2335 			|| !response_addulong(c, c->retry)
2336 			|| !response_addulong(c, c->expire)
2337 			|| !response_addulong(c, c->minimum)) {
2338 				fatal("could not construct SOA");
2339 			}
2340 			response_rfinish(c, RESPONSE_ANSWER);
2341 		}
2342 
2343 		/* also included SOA */
2344 		while ((dat = list_pop(&c->NS))) {
2345 			if (!response_rstart(c, c->request_name_zone,
2346 						DNS_T_NS, c->ttl)
2347 			|| !response_addname(c, dat)) {
2348 				fatal("could not construct NS");
2349 			}
2350 			response_rfinish(c, RESPONSE_AUTHORITY);
2351 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2352 				push_subreq(c, dat);
2353 			mem_free(dat);
2354 		}
2355 
2356 	} else if (_eq2(DNS_T_PTR)) {
2357 		while ((dat = list_pop(&c->PTR))) {
2358 			if (!response_rstart(c, c->request_name_alloc,
2359 						DNS_T_PTR, c->ttl)
2360 			|| !response_addname(c, dat)) {
2361 				fatal("could not construct address");
2362 			}
2363 			didany++;
2364 			response_rfinish(c, RESPONSE_ANSWER);
2365 			mem_free(dat);
2366 		}
2367 		if (!didany && c->NS) {
2368 			/* if no answers, but we're NS, we give SOA */
2369 			if (!response_rstart(c, c->request_name_zone, DNS_T_SOA, c->ttl)
2370 			|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
2371 			|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2372 			|| !response_addulong(c, c->serial)
2373 			|| !response_addulong(c, c->refresh)
2374 			|| !response_addulong(c, c->retry)
2375 			|| !response_addulong(c, c->expire)
2376 			|| !response_addulong(c, c->minimum)) {
2377 				fatal("could not construct SOA");
2378 			}
2379 			response_rfinish(c, RESPONSE_ANSWER);
2380 		}
2381 
2382 		/* also included SOA */
2383 		while ((dat = list_pop(&c->NS))) {
2384 			if (!response_rstart(c, c->request_name_zone,
2385 						DNS_T_NS, c->ttl)
2386 			|| !response_addname(c, dat)) {
2387 				fatal("could not construct NS");
2388 			}
2389 			response_rfinish(c, RESPONSE_AUTHORITY);
2390 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2391 				push_subreq(c, dat);
2392 			mem_free(dat);
2393 		}
2394 	} else if (_eq2(DNS_T_NS)) {
2395 		/* NS returns both answer and authority (since we asked nicely) */
2396 		for (lp = c->NS; lp; lp = lp->next) {
2397 			dat = lp->str;
2398 			if (!response_rstart(c, c->request_name_alloc, DNS_T_NS, c->ttl)
2399 			|| !response_addname(c, lp->str)) {
2400 				fatal("could not construct NS");
2401 			}
2402 			response_rfinish(c, RESPONSE_ANSWER);
2403 		}
2404 		while ((dat = list_pop(&c->NS))) {
2405 			if (!response_rstart(c, c->request_name_zone, DNS_T_NS, c->ttl)
2406 			|| !response_addname(c, dat)) {
2407 				fatal("could not construct NS");
2408 			}
2409 			response_rfinish(c, RESPONSE_AUTHORITY);
2410 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2411 				push_subreq(c, dat);
2412 			mem_free(dat);
2413 		}
2414 	} else if (_eq2(DNS_T_TXT)) {
2415 		/* TXT */
2416 		while ((dat = list_pop(&c->TXT))) {
2417 			if (!response_rstart(c, c->request_name_alloc, DNS_T_TXT, c->ttl)
2418 			|| !response_addbytes(c, dat, dns_domain_length(dat)-1)) {
2419 				fatal("could not construct TXT");
2420 			}
2421 			response_rfinish(c, RESPONSE_ANSWER);
2422 			didany++;
2423 			mem_free(dat);
2424 		}
2425 		if (!didany && c->NS) {
2426 			/* if no answers, but we're NS, we give SOA */
2427 			if (!response_rstart(c, c->request_name_zone, DNS_T_SOA, c->ttl)
2428 			|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : (c->NS ? c->NS->str : ""))
2429 			|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2430 			|| !response_addulong(c, c->serial)
2431 			|| !response_addulong(c, c->refresh)
2432 			|| !response_addulong(c, c->retry)
2433 			|| !response_addulong(c, c->expire)
2434 			|| !response_addulong(c, c->minimum)) {
2435 				fatal("could not construct SOA");
2436 			}
2437 			response_rfinish(c, RESPONSE_ANSWER);
2438 		}
2439 		while ((dat = list_pop(&c->NS))) {
2440 			if (!response_rstart(c, c->request_name_zone, DNS_T_NS, c->ttl)
2441 			|| !response_addname(c, dat)) {
2442 				fatal("could not construct NS");
2443 			}
2444 			response_rfinish(c, RESPONSE_AUTHORITY);
2445 			if (!ldapdns.no_additionals && !ldapdns.no_additionals_ns)
2446 				push_subreq(c, dat);
2447 			mem_free(dat);
2448 		}
2449 	}
2450 
2451 #undef _eq2
2452 	if (no_wild)
2453 		complete_phase(c, '+');
2454 	else if (c->subreq_tries) {
2455 		c->subreq++;
2456 		finish_subrequest(c);
2457 	} else
2458 		complete_phase(c, '+');
2459 	//printf("outta here\n");
2460 }
ldapdns_process_axfrsearch_mid(dns_ctx * c,char * autodn)2461 static void ldapdns_process_axfrsearch_mid(dns_ctx *c, char *autodn)
2462 {
2463 	int err_code;
2464 	char *dn, *dat;
2465 	str_t rn, n;
2466 	list_t y;
2467 
2468 	if (autodn) {
2469 		dn = autodn;
2470 	} else {
2471 		/* process multi-record results... blech */
2472 		if (!c->message) {
2473 			/* odd... no message waiting? */
2474 			fatal("assertion: axfrsearch processing without message!");
2475 		}
2476 
2477 		//printf("phase3\n");
2478 		ldap_parse_result(c->c->ldap_con, c->message,
2479 				&err_code,
2480 				0,0,0,0,0);
2481 		if (err_code != LDAP_SUCCESS) {
2482 			if (err_code == LDAP_SERVER_DOWN) {
2483 				pthread_mutex_lock(&c->c->lock);
2484 				restart_ldap_connection(c->c);
2485 				pthread_mutex_unlock(&c->c->lock);
2486 				/* resend axfr-query */
2487 				do_axfrsearch(c, c->request_name);
2488 				return;
2489 			} else if (err_code == LDAP_TIMEOUT) {
2490 				/*response_refuse(c);*/
2491 				complete_phase(c, '?');
2492 				return;
2493 			} else if (err_code == LDAP_NO_SUCH_OBJECT
2494 			|| err_code == LDAP_LOOP_DETECT
2495 			|| err_code == LDAP_UNWILLING_TO_PERFORM
2496 			|| err_code == LDAP_ALIAS_PROBLEM
2497 			|| err_code == LDAP_INVALID_SYNTAX
2498 			|| err_code == LDAP_INAPPROPRIATE_MATCHING
2499 			|| err_code == LDAP_NO_SUCH_ATTRIBUTE) {
2500 				/* doesn't exist... VERY strange... */
2501 				//printf("did not exist?\n");
2502 				response_refuse(c);
2503 				complete_phase(c, '-');
2504 				return;
2505 			}
2506 
2507 			fatal("ldap_result (zonesearch): %s", ldap_err2string(err_code));
2508 		}
2509 
2510 		if (!ldap_load_dns_attributes(c, &dn, 0)) {
2511 			goto finish_axfr_l;
2512 		}
2513 	}
2514 
2515 	ldap_to_name(n, dn);
2516 	mem_free(dn);
2517 
2518 	if (! *(str(n))) /* invalid name? */
2519 		goto pass_this_round_l;
2520 
2521 	name_to_dns(rn, str(n));
2522 	mem_free(str(n));
2523 
2524 	/* nameservers */
2525 	if (!autodn) {
2526 		while ((dat = list_pop(&c->NS))) {
2527 			if (!response_axstart(c, 0, str(rn), DNS_T_NS, DNS_C_IN, c->ttl)
2528 			|| !response_addname(c, dat)) {
2529 				fatal("could not construct NS");
2530 			}
2531 			mem_free(dat);
2532 			response_axfinish(c);
2533 		}
2534 	}
2535 
2536 	/* addresses */
2537 	while ((dat = list_pop(&c->A))) {
2538 		if (!response_axstart(c, 0, str(rn), DNS_T_A, DNS_C_IN, c->ttl)
2539 		|| !response_addbytes(c, dat, 4)) {
2540 			fatal("could not construct address");
2541 		}
2542 		mem_free(dat);
2543 		response_axfinish(c);
2544 	}
2545 
2546 	/* cnames */
2547 	while ((dat = list_pop(&c->CNAME))) {
2548 		if (!response_axstart(c, 0, str(rn),
2549 				DNS_T_CNAME, DNS_C_IN, c->ttl)
2550 		|| !response_addname(c, dat)) {
2551 			fatal("could not construct address");
2552 		}
2553 		response_axfinish(c);
2554 		mem_free(dat);
2555 	}
2556 
2557 	/* exchanges */
2558 	while ((dat = list_pop(&c->MX))) {
2559 		if (!response_axstart(c, 0, str(rn),
2560 					DNS_T_MX, DNS_C_IN, c->ttl)
2561 		|| !response_addbytes(c, dat, 2)
2562 		|| !response_addname(c, dat+2)) {
2563 			fatal("could not construct address");
2564 		}
2565 		response_axfinish(c);
2566 		mem_free(dat);
2567 	}
2568 	/* text */
2569 	while ((dat = list_pop(&c->TXT))) {
2570 		if (!response_axstart(c, 0, str(rn), DNS_T_TXT,
2571 					DNS_C_IN, c->ttl)
2572 		|| !response_addbytes(c, dat, dns_domain_length(dat)-1)) {
2573 			fatal("could not construct TXT");
2574 		}
2575 		response_axfinish(c);
2576 		mem_free(dat);
2577 	}
2578 	/* pointers */
2579 	while ((dat = list_pop(&c->PTR))) {
2580 		if (!response_axstart(c, 0, str(rn), DNS_T_PTR,
2581 					DNS_C_IN, c->ttl)
2582 		|| !response_addname(c, dat)) {
2583 			fatal("could not construct PTR");
2584 		}
2585 		response_axfinish(c);
2586 		mem_free(dat);
2587 	}
2588 	/* srv and everything else */
2589 	while ((dat = list_pop(&c->Generic))) {
2590 		response_generic(c, 1, c->request_name_alloc,
2591 				dat, c->ttl);
2592 		response_axfinish(c);
2593 		mem_free(dat);
2594 	}
2595 
2596 	mem_free(str(rn));
2597 
2598 pass_this_round_l:
2599 	c->still_using_message = 1;
2600 	return;
2601 
2602 finish_axfr_l:
2603 	if (!response_axstart(c, 1, c->request_name, DNS_T_SOA, DNS_C_IN, c->ttl)
2604 	|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : c->ns->str)
2605 	|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2606 	|| !response_addulong(c, c->serial)
2607 	|| !response_addulong(c, c->refresh)
2608 	|| !response_addulong(c, c->retry)
2609 	|| !response_addulong(c, c->expire)
2610 	|| !response_addulong(c, c->minimum)) {
2611 		fatal("could not construct SOA");
2612 	}
2613 	while ((dat = list_pop(&c->ns))) {
2614 		mem_free(dat);
2615 	}
2616 	c->ns = 0;
2617 	response_axfinish(c);
2618 	complete_phase(c, '+');
2619 }
ldapdns_process_axfrsearch_start(dns_ctx * c)2620 static void ldapdns_process_axfrsearch_start(dns_ctx *c)
2621 {
2622 	const char *attrs[11] = {
2623 				"aRecord",
2624 				"mXRecord",
2625 				"cNAMERecord",
2626 				"seeAlso",
2627 				"description",
2628 				"photo",
2629 				"mail",
2630 				"nSRecord",
2631 				"modifyTimestamp"
2632 	};
2633 	int r;
2634 	int err_code;
2635 	char *dn, *dat;
2636 	list_t y;
2637 
2638 	/* process multi-record results... blech */
2639 	if (!c->message) {
2640 		/* odd... no message waiting? */
2641 		fatal("assertion: axfrsearch processing without message!");
2642 	}
2643 
2644 	//printf("phase3\n");
2645 	ldap_parse_result(c->c->ldap_con, c->message,
2646 			&err_code,
2647 			0,0,0,0,0);
2648 	if (err_code != LDAP_SUCCESS) {
2649 		if (err_code == LDAP_SERVER_DOWN) {
2650 			pthread_mutex_lock(&c->c->lock);
2651 			restart_ldap_connection(c->c);
2652 			pthread_mutex_unlock(&c->c->lock);
2653 			/* resend axfr-query */
2654 			do_axfrsearch(c, c->request_name);
2655 			return;
2656 		} else if (err_code == LDAP_TIMEOUT) {
2657 			/*response_refuse(c);*/
2658 			complete_phase(c, '?');
2659 			return;
2660 		} else if (err_code == LDAP_NO_SUCH_OBJECT
2661 		|| err_code == LDAP_LOOP_DETECT
2662 		|| err_code == LDAP_UNWILLING_TO_PERFORM
2663 		|| err_code == LDAP_ALIAS_PROBLEM
2664 		|| err_code == LDAP_INVALID_SYNTAX
2665 		|| err_code == LDAP_INAPPROPRIATE_MATCHING
2666 		|| err_code == LDAP_NO_SUCH_ATTRIBUTE) {
2667 			/* doesn't exist... VERY strange... */
2668 			//printf("did not exist?\n");
2669 			response_refuse(c);
2670 			complete_phase(c, '-');
2671 			return;
2672 		}
2673 
2674 		fatal("ldap_result (zonesearch): %s", ldap_err2string(err_code));
2675 	}
2676 
2677 	/* we have results... load them into lists*/
2678 	if (!ldap_load_dns_attributes(c, &dn, 1) || !c->NS) {
2679 		response_refuse(c);
2680 		complete_phase(c, '-');
2681 		return;
2682 	}
2683 
2684 	add_peer_ns(c, 0);
2685 //	response_aa(c, 1);
2686 
2687 	/* add these nameservers to plan-for-authority */
2688 	c->ns = c->NS; c->NS = 0;
2689 
2690 	/* before you can call any axfr calls */
2691 	response_axfr(c);
2692 
2693 	/* SOA comes first...
2694 	 */
2695 	if (!response_axstart(c, 1, c->request_name, DNS_T_SOA, DNS_C_IN, c->ttl)
2696 	|| !response_addname(c, ldapdns.self_ns ? ldapdns.self_ns : c->ns->str)
2697 	|| !response_addname(c, c->ADM ? c->ADM->str : ldapdns.hostmaster)
2698 	|| !response_addulong(c, c->serial)
2699 	|| !response_addulong(c, c->refresh)
2700 	|| !response_addulong(c, c->retry)
2701 	|| !response_addulong(c, c->expire)
2702 	|| !response_addulong(c, c->minimum)) {
2703 		fatal("could not construct SOA");
2704 	}
2705 	response_axfinish(c);
2706 
2707 retry_axfr_next_top_l:
2708 	if (ldapdns.dn_mode == DN_MODE_RFC1279
2709 			|| ldapdns.dn_mode == DN_MODE_MSDNS) {
2710 		attrs[9] = (const char *)"dNSRecord";
2711 		attrs[10] = (const char *)0;
2712 	} else {
2713 		attrs[9] = (const char *)0;
2714 	}
2715 
2716 	pthread_mutex_lock(&c->c->lock);
2717 	r = ldap_search(c->c->ldap_con,
2718 			dn,			/* base */
2719 			LDAP_SCOPE_SUBTREE,	/* scope */
2720 			"(objectClass=*)",	/* ldap filter */
2721 			(char **)attrs,		/* attrs */
2722 			0);			/* attrsonly */
2723 
2724 	if (r == -1) {
2725 		/* uh oh: possibly an out of memory error */
2726 		restart_ldap_connection(c->c);
2727 		pthread_mutex_unlock(&c->c->lock);
2728 		goto retry_axfr_next_top_l;
2729 	}
2730 
2731 	//printf("sent query for %d (was %d)\n", r, c->message_id);
2732 	c->message_id = r;
2733 	c->phase = PHASE_AXFRSEARCH;
2734 
2735 	c->c->message_sent++;
2736 	//warning("axfrfirst %d / %d", c->c->message_sent, c->c->message_wait);
2737 	if (c->c->message_wait)
2738 		pthread_cond_broadcast(&c->c->active);
2739 
2740 	pthread_mutex_unlock(&c->c->lock);
2741 	c->still_using_message = 0;
2742 
2743 	return;
2744 }
2745 
initialize_handler(int i,dns_ctx * c)2746 static void inline initialize_handler(int i, dns_ctx *c)
2747 {
2748 	c->n = i;
2749 	if (pthread_mutex_init(&c->lock, NULL) != 0)
2750 		cfatal("pthread_mutex_init(h%d): %s", i);
2751 
2752 	c->sec_update = 0;
2753 	c->sec_prereq = 0;
2754 	c->sock = -1;
2755 	c->swm = 0;
2756 	c->axfr = 0;
2757 	c->axfr_base = 0;
2758 	c->ns = 0;
2759 	c->phase = PHASE_IDLE;
2760 	c->subreq = c->subreq_valid = 0;
2761 	c->subreq_in = c->subreq_in_alloc = 0;
2762 	c->response_names.b = 0;
2763 	c->response_names.s = 0;
2764 	c->request_name_alloc = 0;
2765 	c->request_attr = 0;
2766 	c->message = 0;
2767 //	c->message_entry = 0;
2768 	c->NS = 0;
2769 	c->adlen = -1;
2770 	c->wantdie = 0;
2771 	c->subreq_tries = 0;
2772 	c->subreq_done = 0;
2773 	c->DNSRecord = c->A = c->CNAME = c->MX = c->SRV = c->TXT =
2774 		c->ADM = c->PTR = c->Generic = 0;
2775 	bin_init(c->response);
2776 }
one2one_msgwait_loop(void * o_void)2777 static void *one2one_msgwait_loop(void *o_void)
2778 {
2779 	struct timeval tv;
2780 	LDAPMessage *result;
2781 	dns_ctx *c;
2782 	ldap_ctx *o;
2783 	list_t lp;
2784 	time_t now;
2785 	int r;
2786 
2787 	/* setup linkage */
2788 	o = (ldap_ctx *)o_void;
2789 	for (c = handler; c; c = c->next) {
2790 		if (c->n == o->n) break;
2791 	}
2792 	if (!c) {
2793 		fatal("Could not find matching 1:1 handler (%d)", o->n);
2794 	}
2795 
2796 	c->c = o;
2797 
2798 	for (;;) {
2799 		/* do upkeep */
2800 		time(&now);
2801 		tp_housekeeping((long *)&now);
2802 		handle_messages();
2803 		if (tp_read(c) < 1) continue;
2804 
2805 		/* switch it */
2806 		c->swm = 0;
2807 		for (lp = ldapdns.swm; lp; lp = lp->next) {
2808 			if (!lp->str) continue;
2809 			if (lp->str[0] == 0x04) {
2810 				if (ipv4_in_subnet(lp->str+1, c->ip)) {
2811 					c->swm = lp->str + 9;
2812 					if (!ipv4_null(lp->str+1))
2813 						break;
2814 				}
2815 #ifdef HAVE_IPV6
2816 			} else if (lp->str[0] == 0x06) {
2817 				if (ipv6_in_subnet(lp->str+1, c->ip)) {
2818 					c->swm = lp->str + 33;
2819 					if (!ipv6_null(lp->str+1))
2820 						break;
2821 				}
2822 #endif
2823 			}
2824 		}
2825 
2826 		o->load++;
2827 
2828 		/* start phase 1 */
2829 		time(&c->lastt);
2830 		engine_dns_answer(c, c->lastt);
2831 
2832 		/* phase is now zonesearch */
2833 		while (c->phase != PHASE_IDLE) {
2834 			tv.tv_usec = 0;
2835 			tv.tv_sec = 14;
2836 			pthread_mutex_lock(&o->lock);
2837 			r = ldap_result(o->ldap_con, c->message_id, 0,
2838 					&tv, &result);
2839 
2840 			if (r == -1) {
2841 				complete_phase(c, '?');
2842 				c->c = 0; /* give it up */
2843 				c->phase = PHASE_IDLE;
2844 				restart_ldap_connection(o);
2845 				pthread_mutex_unlock(&o->lock);
2846 				break;
2847 			}
2848 
2849 			pthread_mutex_unlock(&o->lock);
2850 			time(&now);
2851 
2852 			if (r == 0 && now - c->lastt > 12) {
2853 				pthread_mutex_lock(&log_lock);
2854 				warning("handler %d has waited too long", c->n);
2855 				pthread_mutex_unlock(&log_lock);
2856 
2857 				/* whoops; abort this biotch */
2858 				if (c->message_id > -1) {
2859 					pthread_mutex_lock(&o->lock);
2860 					/* we don't want to do this if we're
2861 					 * using the openldap client-side
2862 					 * cache
2863 					 */
2864 #ifdef ACCELERATE_CACHE
2865 					if (!ldapdns.accelerate_cache)
2866 #endif
2867 						ldap_abandon(o->ldap_con,
2868 							c->message_id);
2869 					c->message_id = -1;
2870 					pthread_mutex_unlock(&o->lock);
2871 				}
2872 
2873 				complete_phase(c, '?');
2874 				break;
2875 			}
2876 
2877 			c->message = result;
2878 			c->still_using_message = 0;
2879 			switch (c->phase) {
2880 			case PHASE_ZONESEARCH:
2881 				ldapdns_process_zonesearch(c);
2882 				break;
2883 			case PHASE_ATTRSEARCH:
2884 				ldapdns_process_attrsearch(c, 0);
2885 				break;
2886 			case PHASE_AXFRFIRST:
2887 				ldapdns_process_axfrsearch_start(c);
2888 				break;
2889 			case PHASE_AXFRSEARCH:
2890 				ldapdns_process_axfrsearch_mid(c, 0);
2891 				break;
2892 			case PHASE_NSUPDATE:
2893 				ldapdns_process_update(c);
2894 				break;
2895 			case PHASE_SIMPLESEARCH:
2896 				ldapdns_process_attrsearch(c, 1);
2897 				break;
2898 			};
2899 			if (!c->still_using_message) {
2900 				if (ldap_msgfree(result) == -1) {
2901 					cfatal("ldap_msgfree: %s");
2902 				}
2903 				c->message = 0;
2904 				o->message_sent--;
2905 			}
2906 
2907 			c->lastt = now;
2908 		}
2909 	}
2910 }
dns_msgwait_loop(void * d_void)2911 static void *dns_msgwait_loop(void *d_void)
2912 {
2913 	time_t now;
2914 	int need_second_round, did_second_round;
2915 	dns_ctx *c;
2916 	int j, p, noavail;
2917 	list_t lp;
2918 
2919 	/* we don't do anything with d_void */
2920 	for (;;) {
2921 		/* do upkeep */
2922 		time(&now);
2923 		tp_housekeeping((long *)&now);
2924 		handle_messages();
2925 		pthread_mutex_lock(&handler_lock);
2926 		c = handler;
2927 		pthread_mutex_unlock(&handler_lock);
2928 		need_second_round = did_second_round = 0;
2929 		noavail = 1;
2930 round_top_l:
2931 		for (; c; c = c->next) {
2932 			if ((volatile)c->phase != PHASE_IDLE)
2933 				continue;
2934 			break;
2935 		}
2936 		if (!c) {
2937 			if (!noavail) {/* restart from top  */
2938 				if (need_second_round && !did_second_round) {
2939 					did_second_round = 1;
2940 					pthread_mutex_lock(&handler_lock);
2941 					c = handler;
2942 					pthread_mutex_unlock(&handler_lock);
2943 					noavail = 1;
2944 					goto round_top_l;
2945 				}
2946 				continue;
2947 			}
2948 
2949 			c = mem_alloc(sizeof(dns_ctx));
2950 			if (!c) {
2951 				cfatal("new_handler:mem_alloc: %s");
2952 			}
2953 			pthread_mutex_lock(&handler_lock);
2954 			initialize_handler(ldapdns.handlers, c);
2955 			ldapdns.handlers++;
2956 			c->next = handler;
2957 			c->prev = 0;
2958 			handler = c;
2959 			if (c->next) /* should never fail */
2960 				c->next->prev = c;
2961 			pthread_mutex_unlock(&handler_lock);
2962 			continue;
2963 		}
2964 		noavail = 0;
2965 		/* this blocks until data can be read */
2966 		//warning("tp read");
2967 		switch (tp_read(c)) {
2968 		case -1: /* they need a second round just-in-case */
2969 			need_second_round = 1;
2970 			/* fall through */
2971 		case 0:
2972 			c = c->next;
2973 			goto round_top_l;
2974 		};
2975 
2976 		/* switch it */
2977 		c->swm = 0;
2978 		for (lp = ldapdns.swm; lp; lp = lp->next) {
2979 			if (!lp->str) continue;
2980 			if (lp->str[0] == 0x04) {
2981 				if (ipv4_in_subnet(lp->str+1, c->ip)) {
2982 					c->swm = lp->str + 9;
2983 					if (!ipv4_null(lp->str+1))
2984 						break;
2985 				}
2986 #ifdef HAVE_IPV6
2987 			} else if (lp->str[0] == 0x06) {
2988 				if (ipv6_in_subnet(lp->str+1, c->ip)) {
2989 					c->swm = lp->str + 33;
2990 					if (!ipv6_null(lp->str+1))
2991 						break;
2992 				}
2993 #endif
2994 			}
2995 		}
2996 
2997 		/* find the lowest-loaded thread */
2998 		for (j = 0, p = -1; j < ldapdns.ldap_threads; j++) {
2999 			if (ldap_thread[j].load == 0)	/* 0 is good :) */
3000 				break;
3001 			if (p == -1 || ldap_thread[p].load > ldap_thread[j].load)
3002 				p = j;
3003 		}
3004 		if (j == ldapdns.ldap_threads) {
3005 			j = p;
3006 			if (p == -1) {
3007 				/* this should never happen */
3008 				fatal("ldapdns.ldap_threads got zero'd somehow");
3009 			}
3010 		}
3011 
3012 		/* assign it to a thread */
3013 		c->c = &ldap_thread[j];
3014 
3015 		/* and increase the load */
3016 		pthread_mutex_lock(&ldap_thread[j].load_lock);
3017 		ldap_thread[j].load++;
3018 		pthread_mutex_unlock(&ldap_thread[j].load_lock);
3019 
3020 		/* start phase 1 */
3021 		time(&c->lastt);
3022 		engine_dns_answer(c, c->lastt);
3023 		/* (phase will be set to PHASE_ZONESEARCH) */
3024 
3025 		c = c->next;
3026 		goto round_top_l;
3027 	}
3028 
3029 	return 0;
3030 }
ldap_msgwait_loop(void * c_void)3031 static void *ldap_msgwait_loop(void *c_void)
3032 {
3033 	LDAPMessage *result, *exresult;
3034 	struct timeval tv;
3035 	int r, i, msgid, answered;
3036 	time_t now;
3037 	ldap_ctx *c;
3038 	dns_ctx *x;
3039 
3040 	/* here's our context */
3041 	c = c_void;
3042 
3043 	/* message loop */
3044 	for (answered = 0;;) {
3045 		pthread_mutex_lock(&c->lock);
3046 		//warning("%d answered", answered);
3047 		c->message_sent -= answered; answered = 0;
3048 did_restart_l:
3049 		//warning("enter sent-block %d", c->message_sent);
3050 		while (!c->message_sent) {
3051 			c->message_wait++;
3052 			pthread_cond_wait(&c->active, &c->lock);
3053 			c->message_wait--;
3054 		}
3055 		//warning("exit sent-block %d", c->message_sent);
3056 		tv.tv_usec = 0;
3057 		tv.tv_sec = 14;
3058 		result = 0;
3059 		//warning("ldap_result (wait)");
3060 		r = ldap_result(c->ldap_con, LDAP_RES_ANY, 0, &tv, &result);
3061 		//warning("ldap_result (done)");
3062 		if (r == -1) {
3063 			/* it remains locked */
3064 			restart_ldap_connection(c);
3065 			goto did_restart_l;
3066 		}
3067 		pthread_mutex_unlock(&c->lock);
3068 
3069 		if (r == 0)
3070 			msgid = -1;
3071 		else {
3072 			msgid = ldap_msgid(result);
3073 			if (msgid == -1) {
3074 				/* err... */
3075 				ldap_msgfree(result);
3076 				pthread_mutex_lock(&log_lock);
3077 				warning("msgid on handler %d returned -1", i);
3078 				pthread_mutex_unlock(&log_lock);
3079 				continue;
3080 			}
3081 		}
3082 
3083 		time(&now);
3084 		pthread_mutex_lock(&handler_lock);
3085 		x = handler;
3086 		pthread_mutex_unlock(&handler_lock);
3087 		for (; x; x = x->next) {
3088 			/* not _our_ running handler */
3089 			if (x->c != c)
3090 				continue;
3091 
3092 			/* not a running handler */
3093 			if ((volatile)x->phase == PHASE_IDLE)
3094 				continue;
3095 			/* bind's resolver waits 10 seconds...
3096 			 * we'll wait 12...
3097 			 */
3098 			if (msgid != -1 && msgid == x->message_id) {
3099 				/* do nothing; fall though */
3100 				x->message = result;
3101 				msgid = -1;
3102 			} else if (now - x->lastt > 12) {
3103 				pthread_mutex_lock(&log_lock);
3104 				warning("handler %d has waited too long", x->n);
3105 				pthread_mutex_unlock(&log_lock);
3106 
3107 				/* whoops; abort this biotch */
3108 				if (x->message_id > -1) {
3109 					pthread_mutex_lock(&c->lock);
3110 					/* we don't want to do this if we're
3111 					 * using the openldap client-side
3112 					 * cache
3113 					 */
3114 #ifdef ACCELERATE_CACHE
3115 					if (!ldapdns.accelerate_cache)
3116 #endif
3117 						ldap_abandon(c->ldap_con,
3118 							x->message_id);
3119 					x->message_id = -1;
3120 					c->message_sent--;
3121 					pthread_mutex_unlock(&c->lock);
3122 				}
3123 
3124 				complete_phase(x, '?');
3125 				continue;
3126 			} else if (x->message_id == -1) {
3127 				continue;
3128 			} else if (c->message_sent > 0) {
3129 				tv.tv_sec = 0;
3130 				tv.tv_usec = 0;
3131 				//pthread_mutex_lock(&c->lock);
3132 				exresult = 0;
3133 				r = ldap_result(c->ldap_con, x->message_id,
3134 						0, &tv, &exresult);
3135 				if (r == 0) {
3136 					//pthread_mutex_unlock(&c->lock);
3137 					continue;
3138 				}
3139 				if (r == -1) {
3140 					pthread_mutex_lock(&c->lock);
3141 					restart_ldap_connection(c);
3142 					pthread_mutex_unlock(&c->lock);
3143 					goto did_restart_l;
3144 				}
3145 
3146 				x->message = exresult;
3147 				//pthread_mutex_unlock(&c->lock);
3148 				/* fall through */
3149 			} else {
3150 				continue;
3151 			}
3152 
3153 			x->still_using_message = 0;
3154 			switch (x->phase) {
3155 			case PHASE_ZONESEARCH:
3156 				ldapdns_process_zonesearch(x);
3157 				break;
3158 			case PHASE_ATTRSEARCH:
3159 				ldapdns_process_attrsearch(x, 0);
3160 				break;
3161 			case PHASE_AXFRFIRST:
3162 				ldapdns_process_axfrsearch_start(x);
3163 				break;
3164 			case PHASE_AXFRSEARCH:
3165 				ldapdns_process_axfrsearch_mid(x, 0);
3166 				break;
3167 			case PHASE_NSUPDATE:
3168 				ldapdns_process_update(x);
3169 				break;
3170 			case PHASE_SIMPLESEARCH:
3171 				ldapdns_process_attrsearch(x, 1);
3172 				break;
3173 			};
3174 			/* update lastt timer */
3175 			x->lastt = now;
3176 
3177 			if (!x->still_using_message) {
3178 				if (ldap_msgfree(x->message) == -1) {
3179 					cfatal("ldap_msgfree: %s");
3180 				}
3181 				x->message = 0;
3182 				answered++;
3183 			}
3184 		}
3185 	}
3186 }
parse_read_search(char * d)3187 static void parse_read_search(char *d)
3188 {
3189 	char *x;
3190 	str_t p;
3191 
3192 	if (!d) return;
3193 
3194 	x = d;
3195 	while (*x && !isspace((unsigned int)*x)) x++;
3196 	if (*x == 0) return;
3197 	*x = 0; x++;
3198 	while (isspace((unsigned int)*x)) x++;
3199 
3200 	name_to_dns(p, d);
3201 
3202 	switch (ht_store(&ldapdns.search, str(p), str_len(p), str_dup(x))) {
3203 	case -1: cfatal("parse_read_search: %s");
3204 	case 0: fatal("cannot (presently) search for %s twice", d);
3205 	case 1: break;
3206 	};
3207 	mem_free(str(p));	/* ht_store makes it's own copy */
3208 }
__search_hash(const void * str,unsigned len)3209 static unsigned long __search_hash(const void *str, unsigned len)
3210 {
3211 	const char *h;
3212 	unsigned long d;
3213 	unsigned i;
3214 
3215 	d = 5431;
3216 	for (i = 0, h = str; i < len; i++) {
3217 		/* Clib */
3218 		d = (d << 5) ^ (tolower((int)h[i]));
3219 	}
3220 
3221 	return d;
3222 }
root_read_search(void)3223 static int root_read_search(void)
3224 {
3225 	FILE *fp;
3226 	str_t line;
3227 	int c;
3228 
3229 	ht_init(&ldapdns.search, 7, __search_hash);
3230 
3231 	fp = fopen("search", "r");
3232 	if (!fp)
3233 		return 0;
3234 
3235 	str_init(line);
3236 	/* could hang if we attached to a device node... but it's in
3237 	 * initialization only, so np here
3238 	 */
3239 	while ((c = fgetc(fp)) != EOF) {
3240 		if (c == '\r' || c == '\n') {
3241 			if (str(line)[0] && str(line)[0] != '#') {
3242 				/* parse out this data */
3243 				parse_read_search(str(line));
3244 			}
3245 			str_copy(line, "");
3246 		} else {
3247 			str_addch(line, c);
3248 		}
3249 	}
3250 	fclose(fp);
3251 	return 1;
3252 }
root_read_sw(const char * filename,list_t * p)3253 static int root_read_sw(const char *filename, list_t *p)
3254 {
3255 	FILE *fp;
3256 	str_t line;
3257 	bin_t res;
3258 	unsigned char *x, cidr[IP_LEN*2];
3259 	int c;
3260 
3261 	fp = fopen(filename, "r");
3262 	if (!fp)
3263 		return 0;
3264 
3265 	str_init(line);
3266 	bin_init(res);
3267 	/* could hang if we attached to a device node... but it's in
3268 	 * initialization only, so np here
3269 	 */
3270 	while ((c = fgetc(fp)) != EOF) {
3271 		if (c == '\r' || c == '\n' || c == ' ' || c == '\t') {
3272 			if (str(line)[0] && str(line)[0] != '#') {
3273 				/* parse as follows */
3274 				/* key=cidr */
3275 				for (x = str(line); *x && *x != '='; x++);
3276 				if (*x == '=') {
3277 					*x = 0;
3278 					x++;
3279 #ifdef HAVE_IPV6
3280 					if (ipv6_cidr(x, cidr)) {
3281 						bin_copy(res, "\x06", 1);
3282 						bin_cat(res, cidr, 32);
3283 						bin_cat(res, str(line), str_len(line));
3284 						bin_0(res);
3285 						list_push(p, caddr(res));
3286 						bin_init(res);
3287 					} else
3288 #endif
3289 					if (ipv4_cidr(x, cidr)) {
3290 						bin_copy(res, "\x04", 1);
3291 						bin_cat(res, cidr, 8);
3292 						bin_cat(res, str(line), str_len(line));
3293 						bin_0(res);
3294 						list_push(p, caddr(res));
3295 						bin_init(res);
3296 					}
3297 				}
3298 
3299 			}
3300 			str_copy(line, "");
3301 		} else {
3302 			str_addch(line, c);
3303 		}
3304 	}
3305 	fclose(fp);
3306 	return 1;
3307 }
3308 
root_read(const char * filename,char ** buf,int secure)3309 static int root_read(const char *filename, char **buf, int secure)
3310 {
3311 	str_t retbuf;
3312 	FILE *fp;
3313 	int c, sp;
3314 
3315 	fp = fopen(filename, "r");
3316 	if (!fp)
3317 		return 0;
3318 
3319 	if (secure) {
3320 		struct stat sb;
3321 
3322 		if (fstat(fileno(fp), &sb) == -1) {
3323 			fclose(fp);
3324 			return 0;
3325 		}
3326 		if (sb.st_mode & 0377) {
3327 			fclose(fp);
3328 			fatal("$ROOT/%s must have mode 0400", filename);
3329 		}
3330 	}
3331 
3332 	str_init(retbuf);
3333 	sp = 0;
3334 	/* could hang if we attached to a device node... but it's in
3335 	 * initialization only, so np here
3336 	 */
3337 	while ((c = fgetc(fp)) != EOF) {
3338 		if (c == '\r' || c == '\n' || c == ' ' || c == '\t') {
3339 			sp = 1;
3340 		} else {
3341 			if (sp) {
3342 				sp = 0;
3343 				str_addch(retbuf, ' ');
3344 			}
3345 			str_addch(retbuf, c);
3346 		}
3347 	}
3348 	fclose(fp);
3349 	*buf = str(retbuf);
3350 	return 1;
3351 }
gc_ldap_cache(void * ignore)3352 static int gc_ldap_cache(void *ignore)
3353 {
3354 	register int i;
3355 
3356 #ifdef ACCELERATE_CACHE
3357 	if (!ldapdns.accelerate_cache)
3358 #endif
3359 		return 0;
3360 
3361 #ifdef ACCELERATE_CACHE
3362 	pthread_mutex_lock(&host_lock);
3363 	for (i = 0; i < ldapdns.ldap_threads; i++) {
3364 		pthread_mutex_lock(&ldap_thread[i].lock);
3365 		ldap_destroy_cache(ldap_thread[i].ldap_con);
3366 		ldap_enable_cache(ldap_thread[i].ldap_con, ldapdns.accelerate_cache, 0);
3367 		pthread_mutex_unlock(&ldap_thread[i].lock);
3368 	}
3369 	pthread_mutex_unlock(&host_lock);
3370 #endif
3371 
3372 	return 1;
3373 }
main(int argc,char * argv[])3374 int main(int argc, char *argv[])
3375 {
3376 	char *x, *y, *h;
3377 	int i, j, p;
3378 	static pthread_attr_t helper_thread_attr;
3379 	str_t retbuf, hbuf;
3380 	char spbuf[32];
3381 	pthread_t dummy;
3382 	list_t lp;
3383 	bin_t res;
3384 
3385 	/* try and get logging up first */
3386 	x = env_get("LOG");
3387 	log_init(x);
3388 
3389 	/* allow self-supervise */
3390 	x = env_get("SUPERVISE");
3391 	if (x) {
3392 		supervise(x);
3393 	}
3394 
3395 	/* setup signals */
3396 	signal(SIGSTOP, handle_signal);
3397 	signal(SIGCONT, handle_signal);
3398 	signal(SIGTERM, handle_signal);
3399 	signal(SIGHUP, handle_signal);
3400 	signal(SIGINT, handle_signal);
3401 
3402 	/* load AXFR early */
3403 	x = env_get("AXFR");
3404 	if (!x)
3405 		x = env_get("LDAP_AXFR");
3406 	if (x && *x) {
3407 		/* save it in dns form... i'm just silly like that */
3408 		name_to_dns(retbuf, x);
3409 		ldapdns.axfr_base = str(retbuf);
3410 	} else
3411 		ldapdns.axfr_base = 0;
3412 
3413 	if (pthread_attr_init(&helper_thread_attr) != 0)
3414 		cfatal("pthread_attr_init: %s");
3415 	if (pthread_attr_setdetachstate(&helper_thread_attr,
3416 				PTHREAD_CREATE_DETACHED))
3417 		cfatal("pthread_attr_setdetachstate: %s");
3418 
3419 	ldapdns.ldap_threads = -1;
3420 	ldapdns.dns_threads = -1;
3421 	x = env_get("THREADS");
3422 	if (x) {
3423 		ldapdns.ldap_threads = atoi(x);
3424 		if (ldapdns.ldap_threads > 1) {
3425 			ldapdns.dns_threads = ldapdns.ldap_threads / 2;
3426 			if (ldapdns.ldap_threads % 2 == 1)
3427 				ldapdns.dns_threads++;
3428 		}
3429 	}
3430 
3431 	x = env_get("DEFAULT_REFRESH"); if (x) default_refresh = atoi(x);
3432 	x = env_get("DEFAULT_RETRY"); if (x) default_retry = atoi(x);
3433 	x = env_get("DEFAULT_EXPIRE"); if (x) default_expire = atoi(x);
3434 	x = env_get("DEFAULT_MINIMUM"); if (x) default_minimum = atoi(x);
3435 
3436 	x = env_get("LDAP_THREADS");
3437 	if (x) ldapdns.ldap_threads = atoi(x);
3438 
3439 	x = env_get("DNS_THREADS");
3440 	if (x) ldapdns.dns_threads = atoi(x);
3441 
3442 	if (ldapdns.ldap_threads < 1)
3443 		ldapdns.ldap_threads = 1;
3444 	if (ldapdns.dns_threads < 1)
3445 		ldapdns.dns_threads = 1;
3446 
3447 	ldapdns.handlers = (ldapdns.ldap_threads + ldapdns.dns_threads)*2;
3448 	if (ldapdns.handlers < 128) ldapdns.handlers = 128;
3449 
3450 	x = env_get("HANDLERS");
3451 	if (x) {
3452 		j = atoi(x);
3453 		if (j > 0)
3454 			ldapdns.handlers = j;
3455 	}
3456 
3457 	/* setup TCP options */
3458 	x = env_get("TIMEOUT_TCP");
3459 	if (!x)
3460 		x = env_get("TIMEOUT");
3461 	if (x) {
3462 		/* barg */
3463 		ldapdns.timeout_tcp = atoi(x);
3464 	} else
3465 		ldapdns.timeout_tcp = 0;
3466 
3467 	x = env_get("ALWAYS_HANGUP_TCP");
3468 	if (!x)
3469 		x = env_get("ALWAYS_HANGUP");
3470 	ldapdns.always_hangup = (x ? 1 : 0);
3471 
3472 	/* get listening socket */
3473 	tp_initialize();
3474 		/* !!! tcpserver modifies ldapdns.handlers */
3475 
3476 	if (ldapdns.handlers == 1) {
3477 		/* special handler mode... */
3478 		ldapdns.one2one_mode = 1;
3479 		if (ldapdns.dns_threads > ldapdns.ldap_threads) {
3480 			/* silly... */
3481 			ldapdns.handlers = ldapdns.ldap_threads = ldapdns.dns_threads;
3482 		} else {
3483 			ldapdns.handlers = ldapdns.dns_threads = ldapdns.ldap_threads;
3484 		}
3485 	} else {
3486 		ldapdns.one2one_mode = 0;
3487 	}
3488 
3489 	ldap_thread = mem_alloc(ldapdns.ldap_threads * sizeof(ldap_ctx));
3490 	if (!ldap_thread)
3491 		cfatal("thread:mem_alloc: %s");
3492 	for (i = 0; i <ldapdns.ldap_threads; i++) {
3493 		ldap_thread[i].ldap_con = 0;
3494 
3495 		/* one2one mode doesn't need these ... */
3496 		if (pthread_mutex_init(&ldap_thread[i].lock, NULL) != 0)
3497 			cfatal("pthread_mutex_init(t%d): %s", i);
3498 		if (pthread_mutex_init(&ldap_thread[i].load_lock, NULL) != 0)
3499 			cfatal("pthread_mutex_init(t%d): %s", i);
3500 		if (pthread_cond_init(&ldap_thread[i].active, NULL) != 0)
3501 			cfatal("pthread_cond_init(t%d): %s", i);
3502 	}
3503 	if (pthread_mutex_init(&log_lock, NULL) != 0)
3504 		cfatal("pthread_mutex_init(log_lock): %s");
3505 	if (pthread_mutex_init(&host_lock, NULL) != 0)
3506 		cfatal("pthread_mutex_init(host_lock): %s");
3507 	if (pthread_mutex_init(&handler_lock, NULL) != 0)
3508 		cfatal("pthread_mutex_init(handler_lock): %s");
3509 	if (pthread_mutex_init(&engine_message_mutex, NULL) != 0)
3510 		cfatal("pthread_mutex_init(pause_lock): %s");
3511 	if (pthread_cond_init(&engine_pause_cond, NULL) != 0)
3512 		cfatal("pthread_cond_init(pause_cond): %s");
3513 
3514 	x = env_get("ROOT");
3515 	if (!x)
3516 		fatal("$ROOT not set");
3517 	if (chdir(x) == -1)
3518 		cfatal("unable to chdir to %s: %s", x);
3519 
3520 	/* 0 is ok. */
3521 	ldapdns.notify = env_get("HELPER_NOTIFY");
3522 
3523 	ldapdns.dn_mode = DN_MODE_COSINE;
3524 	x = env_get("SCHEMA");
3525 	if (x) {
3526 		if (str_equali(x, "rfc1279"))
3527 			ldapdns.dn_mode = DN_MODE_RFC1279;
3528 		else if (str_equal(x, "msdns") || str_equal(x, "ad"))
3529 			ldapdns.dn_mode = DN_MODE_MSDNS;
3530 		else if (str_equal(x, "cosine") || str_equali(x, "ldapdns1")
3531 					|| str_equali(x, "ldapdns-1"))
3532 			ldapdns.dn_mode = DN_MODE_COSINE;
3533 		else if (str_equal(x, "ldapdns") || str_equali(x, "ldapdns2")
3534 					|| str_equali(x, "ldapdns-2"))
3535 			ldapdns.dn_mode = DN_MODE_LDAPDNS;
3536 		else
3537 			fatal("$SCHEMA set to an invalid setting");
3538 	} else {
3539 		x = env_get("RFC1279");
3540 		if (x)
3541 			ldapdns.dn_mode = DN_MODE_RFC1279;
3542 		else {
3543 			x = env_get("DNSRECORD");
3544 			if (x) {
3545 				if (str_equali(x, "rfc1279"))
3546 					ldapdns.dn_mode = DN_MODE_RFC1279;
3547 				else if (str_equal(x, "msdns") || str_equal(x, "ad"))
3548 					ldapdns.dn_mode = DN_MODE_MSDNS;
3549 				else
3550 					fatal("$DNSRECORD set to an invalid setting");
3551 			}
3552 		}
3553 	}
3554 
3555 	x = env_get("NSUPDATE");
3556 	if (x) {
3557 		name_to_dns(retbuf, x);
3558 		ldapdns.update = str(retbuf);
3559 	} else
3560 		ldapdns.update = 0;
3561 
3562 	x = env_get("LDAP_SUFFIX");
3563 	if (!x)
3564 		ldapdns.ldap_suffix = "";
3565 	else {
3566 		/* ldap_suffix is dynamically generated */
3567 		str_init(retbuf);
3568 		str_copy(retbuf, x);
3569 		ldapdns.ldap_suffix = str(retbuf);
3570 
3571 		/* x came from env; so it's ASCIIZ */
3572 		lp = ldap_into_parts(x);
3573 		/* reverse the list: the interesting stuff is at the other end */
3574 		list_reverse(&lp);
3575 		y = list_pop(&lp);
3576 		mem_free(y);
3577 
3578 		y = list_pop(&lp);
3579 		/* test for the microsoft DNS suffix */
3580 		if (y && str_equali(y, "cn=system")) {
3581 			mem_free(y);
3582 			y = list_pop(&lp);
3583 			if (y && str_equali(y, "cn=microsoftdns")) {
3584 				mem_free(y);
3585 				ldapdns.dn_mode = DN_MODE_MSDNS;
3586 			} else
3587 				mem_free(y);
3588 		} else
3589 			mem_free(y);
3590 		while ((y = list_pop(&lp)))
3591 			mem_free(y);
3592 	}
3593 
3594 	/* this is a performance thing; PDNS claims 10k requests,
3595 	 * i think it's a bad idea...
3596 	 */
3597 	x = env_get("NO_ADDITIONALS");
3598 	if (!x) {
3599 		x = env_get("NO_ADDITIONALS_NS");
3600 		if (x)
3601 			ldapdns.no_additionals = ldapdns.no_additionals_ns = 1;
3602 		else
3603 			ldapdns.no_additionals = ldapdns.no_additionals_ns = 0;
3604 	} else {
3605 		ldapdns.no_additionals = 1;
3606 		ldapdns.no_additionals_ns = 0;
3607 	}
3608 
3609 	ldapdns.schedule_arecord = SCHEDULE_A_NONE;
3610 	x = env_get("SCHEDULE_ARECORD");
3611 	if (x) {
3612 		if (str_equali(x, "random")) {
3613 			ldapdns.schedule_arecord = SCHEDULE_A_RANDOM;
3614 		}
3615 	}
3616 
3617 	/* this should be fine. */
3618 	srand(time(NULL)^(getpid() << 5)^(getppid()));
3619 
3620 	/* mwahahahah */
3621 	x = env_get("NETBIOS");
3622 	if (x)
3623 		ldapdns.netbios = 1;
3624 	else
3625 		ldapdns.netbios = 0;
3626 
3627 	/* self nameserver */
3628 	ldapdns.self_ns = 0;
3629 	x = env_get("NS_SELF");
3630 	if (!x) x = env_get("NSSELF");
3631 	if (!x) x = env_get("SELFNS");
3632 	if (!x) x = env_get("SELF_NS");
3633 	if (x) {
3634 		str_init(retbuf);
3635 		name_to_dns(retbuf, x);
3636 		ldapdns.self_ns = str(retbuf);
3637 	}
3638 
3639 	/* this adds nameservers */
3640 	ldapdns.peer_ns = 0;
3641 	x = env_get("NS");
3642 	if (!x) {
3643 		for (i = 1;; i++) {
3644 			sprintf(spbuf, "NS%d", i);
3645 			x = env_get(spbuf);
3646 			if (!x) break;
3647 			str_init(retbuf);
3648 			name_to_dns(retbuf, x);
3649 			list_push(&ldapdns.peer_ns, str(retbuf));
3650 		}
3651 	} else {
3652 		for (i = j = 0; x[i]; i++) {
3653 			if (x[i] == '\r' || x[i] == '\n' || x[i] == ' '
3654 					|| x[i] == '\t') {
3655 				if (j < i-1) {
3656 					str_init(retbuf);
3657 					str_catb(retbuf, x+j, i-j);
3658 
3659 					str_init(hbuf);
3660 					name_to_dns(hbuf, str(retbuf));
3661 					mem_free(str(retbuf));
3662 
3663 					list_push(&ldapdns.peer_ns, str(hbuf));
3664 				}
3665 				j = i+1;
3666 			}
3667 		}
3668 		if (j < i-1) {
3669 			str_init(retbuf);
3670 			name_to_dns(retbuf, x+j);
3671 			list_push(&ldapdns.peer_ns, str(retbuf));
3672 		}
3673 	}
3674 
3675 	/* you know what you doing... */
3676 	ldapdns.accelerate_cache = 0;
3677 	x = env_get("ACCELERATE_CACHE");
3678 	if (!x)
3679 		x = env_get("CACHE");
3680 	if (x)
3681 		ldapdns.accelerate_cache = atoi(x);
3682 	if (ldapdns.accelerate_cache < 0)
3683 		ldapdns.accelerate_cache = 0;
3684 #ifdef ACCELERATE_CACHE
3685 	if (ldapdns.accelerate_cache) {
3686 		/* register garbage collection */
3687 		mem_register_gc(0, gc_ldap_cache);
3688 	}
3689 #endif
3690 
3691 	handler = mem_alloc(ldapdns.handlers * sizeof(dns_ctx));
3692 	if (!handler)
3693 		cfatal("handler:mem_alloc: %s");
3694 	for (i = 0; i < ldapdns.handlers; i++) {
3695 		/* flush handlers */
3696 		dns_ctx *c = &handler[i];
3697 		initialize_handler(i, c);
3698 
3699 		c->prev = (i == 0 ? 0 : &handler[i-1]);
3700 		c->next = (i == ldapdns.handlers-1 ? 0 : &handler[i+1]);
3701 	}
3702 
3703 /* core */
3704 	x = env_get("HOSTMASTER");
3705 	if (!x)
3706 		fatal("$HOSTMASTER not set");
3707 	str_init(retbuf);
3708 	name_to_dns_fix(retbuf, x, 2);
3709 	ldapdns.hostmaster = str(retbuf);
3710 
3711 	ldapdns.auth_mode = AUTH_MODE_ANONYMOUS;
3712 	x = env_get("LDAP_AUTH");
3713 	if (x) {
3714 		if (str_equali(x, "simple"))
3715 			ldapdns.auth_mode = AUTH_MODE_SIMPLE;
3716 		else if (str_equali(x, "sasl"))
3717 			ldapdns.auth_mode = AUTH_MODE_SASL;
3718 	}
3719 
3720 	x = env_get("LDAP_SASL");
3721 	if (x) {
3722 		ldapdns.auth_mode = AUTH_MODE_SASL;
3723 		ldapdns.ldap_name = x;
3724 	} else {
3725 		x = env_get("LDAP_AUTH_NAME");
3726 		if (!x)
3727 			x = env_get("LDAP_BINDDN");
3728 		if (x && *x) {
3729 			ldapdns.ldap_name = x;
3730 			/* fixup for no $LDAP_AUTH */
3731 			if (ldapdns.auth_mode == AUTH_MODE_ANONYMOUS)
3732 				ldapdns.auth_mode = AUTH_MODE_SIMPLE;
3733 		}
3734 	}
3735 
3736 	x = env_get("RELATIVE_NAMES");
3737 	ldapdns.relative_names = (x ? 1 : 0);
3738 
3739 	if (!root_read("password", &ldapdns.ldap_cred, 1)) {
3740 		if (ldapdns.auth_mode == AUTH_MODE_SIMPLE) {
3741 			/* no password file */
3742 			fatal("$ROOT/password is empty");
3743 		}
3744 	}
3745 	/* load the search table (if present) */
3746 	root_read_search();
3747 
3748 	/* read switch values (if present) */
3749 	ldapdns.swm = 0;
3750 	root_read_sw("switch", &ldapdns.swm);
3751 	ldapdns.swaxfr = 0;
3752 	root_read_sw("axfr", &ldapdns.swaxfr);
3753 
3754 	/* try both host and hosts */
3755 	x = env_get("LDAP_HOSTS");
3756 	if (!x)
3757 		x = env_get("LDAP_HOST");
3758 	if (!x)
3759 		fatal("$LDAP_HOST not set");
3760 
3761 	/* load connection host/strings */
3762 	ldapdns.hosts = 0;
3763 	str_init(retbuf);
3764 	str_copy(retbuf, x);
3765 	for (h = str(retbuf); h && *h;) { /* on init: np if it infinites */
3766 		int uri=0;
3767 		for (x = h; *x && *x != ',' && *x != ' '
3768 				&& *x != ';' && *x != '\t'; x++);
3769 		if (*x) {
3770 			*x = 0;
3771 			x++;
3772 		} else
3773 			x = 0;
3774 
3775 		p = LDAP_PORT;
3776 		for (y = h; *y && *y != ':'; y++);
3777 		if (*y && *y == ':') {
3778 			if (*(y+1) && *(y+1) == '/') { /* detect ldap:// uri */
3779 				uri=1;
3780 			} else {
3781 				*y = 0;
3782 				y++;
3783 				p = atoi(y);
3784 				if (p == -1)
3785 					p = LDAP_PORT;
3786 			}
3787 		}
3788 
3789 		str_init(hbuf);
3790 		str_copy(hbuf, h);
3791 		if (!uri) {
3792 			str_addch(hbuf, ':');
3793 			sprintf(spbuf, "%d", p);
3794 			str_cat(hbuf, spbuf);
3795 		}
3796 
3797 		list_push(&ldapdns.hosts, str(hbuf));
3798 		h = x;
3799 	}
3800 
3801 	if (!ldapdns.hosts) {
3802 		fatal("No hosts were loaded");
3803 	}
3804 
3805 	j = 1;
3806 	for (i = 0, lp=ldapdns.hosts; i < ldapdns.ldap_threads; lp = lp->next) {
3807 		if (!lp) {
3808 			lp = ldapdns.hosts;
3809 			if (!j) {
3810 				fatal("cannot contact any LDAP servers (thread %d)", i);
3811 			}
3812 			j = 0;
3813 		}
3814 
3815 		if (start_ldap_connection(&ldap_thread[i], lp->str) != -1) {
3816 			i++;
3817 			j = 1;
3818 		}
3819 	}
3820 	/* save last used */
3821 	host_lp = lp;
3822 	if (!lp) host_lp = ldapdns.hosts;
3823 
3824 	/* chroot */
3825 	if (chroot(".") == -1)
3826 		cfatal("chroot: %s");
3827 
3828 	x = env_get("UID");
3829 	if (!x)
3830 		fatal("$UID not set");
3831 	i = atoi(x);
3832 	if (i < 0)
3833 		fatal("$UID invalid (not numeric)");
3834 	x = env_get("GID");
3835 	if (!x)
3836 		fatal("$GID not set");
3837 	j = atoi(x);
3838 	if (j < 0)
3839 		fatal("$GID invalid (not numeric)");
3840 
3841 	x = env_get("I_AM_STUPID_LET_ME_RUN_LDAPDNS_AS_ROOT");
3842 	if (x)
3843 		warning("doing something very stupid (running as root)");
3844 	else if (i == 0 || j == 0)
3845 		fatal("refuse to run ldapdns as root");
3846 
3847 	/* drop privs */
3848 	if (j != getgid() && setgid(j) == -1) cfatal("setgid: %s");
3849 	if (i != getuid() && setuid(i) == -1) cfatal("setuid: %s");
3850 
3851 	/* setup signals */
3852 	signal(SIGPIPE, SIG_IGN); /* i ignore this... but it's okay... */
3853 
3854 	eph = pthread_self();
3855 	if (ldapdns.one2one_mode) {
3856 #ifdef ACCELERATE_CACHE
3857 		if (ldapdns.accelerate_cache)
3858 			log(log_info, "ldap client caching enabled!");
3859 #endif
3860 
3861 		log(log_info, "starting ldapdns %s (1:1/%d)", VERSION,
3862 				ldapdns.handlers);
3863 
3864 		/* alternate message loop */
3865 		for (i = 0; i < ldapdns.dns_threads-1; i++) {
3866 			ldap_thread[i].n = i;
3867 			if (pthread_create(&ldap_thread[i].id, &helper_thread_attr,
3868 					one2one_msgwait_loop, &ldap_thread[i]) != 0) {
3869 				cfatal("pthread_create(%d): %s", i);
3870 			}
3871 		}
3872 		/* use the main thread for something :) */
3873 		ldap_thread[i].n = i;
3874 		ldap_thread[i].id = pthread_self();
3875 		one2one_msgwait_loop(&ldap_thread[i]);
3876 		return 0;
3877 	}
3878 
3879 	/* start helper thread */
3880 	for (i = 0; i < ldapdns.ldap_threads; i++) {
3881 
3882 		/* save index */
3883 		ldap_thread[i].n = i;
3884 		/* null these out here */
3885 		ldap_thread[i].message_wait = 0;
3886 		ldap_thread[i].message_sent = 0;
3887 		if (pthread_create(&ldap_thread[i].id, &helper_thread_attr,
3888 					ldap_msgwait_loop, &ldap_thread[i]) != 0) {
3889 			cfatal("pthread_create(%d): %s", i);
3890 		}
3891 	}
3892 
3893 	if (ldapdns.accelerate_cache)
3894 		log(log_info, "ldap client caching enabled!");
3895 
3896 	log(log_info, "starting ldapdns %s (%d:%d/%d)", VERSION,
3897 				ldapdns.ldap_threads, ldapdns.dns_threads,
3898 				ldapdns.handlers);
3899 
3900 	for (i = 0; i < ldapdns.dns_threads-1; i++) {
3901 		if (pthread_create(&dummy, &helper_thread_attr,
3902 					dns_msgwait_loop, 0) != 0) {
3903 			cfatal("pthread_create(%d): %s", i);
3904 		}
3905 		bin_init(res);
3906 		bin_copy(res, (char *)&dummy, sizeof(pthread_t));
3907 		list_push(&other_threads, caddr(res));
3908 	}
3909 	dns_msgwait_loop(0);
3910 	return 0; /* never reached */
3911 }
3912 
3913