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