1 /* this file contains information for navigating the various LDAP schema */
2 #include "ldapdns.h"
3 #include "config.h"
4 #include "dns.h"
5 #include "ip.h"
6
7 #include <time.h>
8
ldapdns_list_unique(list_t * p)9 void inline ldapdns_list_unique(list_t *p)
10 {
11 list_t x = 0;
12 list_t seen = 0;
13 list_t lp, sp;
14
15 for (lp = (*p); lp; lp = lp->next) {
16 for (sp = seen; sp; sp = sp->next) {
17 if (str_equal(sp->str, lp->str)) {
18 goto HIT;
19 }
20 }
21 list_push(&x, lp->str);
22 list_push(&seen, lp->str);
23 HIT:
24 continue;
25 }
26
27 lp = *p;
28 while (list_pop(&lp));
29 while (list_pop(&seen));
30 *p = x;
31 }
32
ldap_escape(str_t retbuf,char * s)33 static void inline ldap_escape(str_t retbuf, char *s)
34 {
35 while (*s) {
36 if (*s == ',') {
37 str_addch(retbuf, '\\');
38 }
39 str_addch(retbuf, *s);
40 s++;
41 }
42 }
43
name_to_ldap(str_t retbuf,char * name)44 void name_to_ldap(str_t retbuf, char *name)
45 {
46 list_t p = 0;
47 char *x;
48 int i;
49
50 str_init(retbuf);
51
52 switch (ldapdns.dn_mode) {
53 case DN_MODE_COSINE:
54 case DN_MODE_LDAPDNS: /* dc=www, dc=example, dc=com */
55 case DN_MODE_RFC1279: /* dc=www, dc=example, dc=com */
56 p = split_name_parts(name);
57 i = 0; while ((x = list_pop(&p))) {
58 str_cat(retbuf, "dc=");
59 ldap_escape(retbuf, x);
60 str_cat(retbuf, ", ");
61 i++;
62 }
63 if (i) str_chopn(retbuf, 2);
64 break;
65 case DN_MODE_MSDNS: /* dc=www.example.com */
66 str_cat(retbuf, "dc=");
67 ldap_escape(retbuf, x);
68 break;
69 };
70 }
71
ldap_into_parts(char * dn)72 list_t ldap_into_parts(char *dn)
73 {
74 /* safe if dn is infact an asciiZ string */
75 list_t p = 0;
76 register char *x = dn, *y;
77 str_t s;
78
79 /* split into parts */
80 str_init(s);
81 while (*x == ' ' || *x == ',') x++; /* mostly safe :) */
82 while (*x) {
83 /* looking for: \s*,\s* but !~ \\. */
84 if (*x == '\\') {
85 x++;
86 str_addch(s, *x);
87 x++;
88 } else if (*x == ',') {
89 /* pull off excess whitespace from previous */
90 y = strchr(str(s), '\0');
91 if (y) {
92 y--;
93 while (*y == ' ') y--;
94 if (*y) y++;
95 if (*y) *y = 0;
96 }
97
98 list_push(&p, str(s));
99 str_init(s);
100 while (*x == ',' || *x == ' ') x++;
101 } else {
102 str_addch(s, *x);
103 x++;
104 }
105 }
106
107 return p;
108 }
109
ldap_to_name(str_t retbuf,char * dn)110 void ldap_to_name(str_t retbuf, char *dn)
111 {
112 /* safe if dn is asciiz */
113 list_t z, b, p = ldap_into_parts(dn);
114 char *x, *y, *q;
115
116 /* we need the suffix here in order to pull it off */
117 if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
118 b = ldap_into_parts(ldapdns.ldap_suffix);
119
120 for (z = b; z; z = z->next) {
121 if (str_diffi(z->str, p->str)) {
122 break;
123 } else {
124 q = list_pop(&p);
125 mem_free(q);
126 }
127 }
128 while ((x = list_pop(&b))) {
129 if (str_diffi(x, p->str)) {
130 mem_free(x);
131 while ((x = list_pop(&b)))
132 mem_free(x);
133 break;
134 }
135 q = list_pop(&p);
136 mem_free(q);
137 mem_free(x);
138 }
139 }
140
141 /* flip p around; we have to have this in it's own list */
142 list_reverse(&p);
143
144 str_init(retbuf);
145 while ((x = list_pop(&p))) {
146 if (str_start(x, "dc=")) {
147 y = x + 3;
148 while (*y == ' ') y++;
149 if (*y != ',') {
150 str_cat(retbuf, y);
151 str_addch(retbuf, '.');
152 }
153 }
154 mem_free(x);
155 }
156 str_chop(retbuf);
157 }
158
__parse_soa(dns_ctx * c,bin_t rrdata,int flag)159 static int inline __parse_soa(dns_ctx *c, bin_t rrdata, int flag)
160 {
161 register unsigned int i, j;
162 unsigned long ar[5];
163 register char *q;
164 str_t tmp, tmp2;
165
166 q = caddr(rrdata);
167 if (flag) {
168 if (clen(rrdata) >= 1 && *q == '*') {
169 c->wantdie=1;
170 return 0;
171 }
172 /* don't want anything else */
173 if (clen(rrdata) == 1)
174 return 0;
175 }
176 if (c->soahack) return 1; /* skip */
177
178 /* remainder is of the format is serial [ttl retry expire minimum] */
179 for (j = i = 0; j < 5; j++) { /* safe: bounded */
180 if (!(i < clen(rrdata))) break;
181 while (isspace(((unsigned int)q[i])) && i < clen(rrdata)) i++;
182 if (!(i < clen(rrdata))) break;
183 ar[j] = 0;
184 while (isdigit(((unsigned int)q[i])) && i < clen(rrdata)) {
185 ar[j] *= 10;
186 switch (q[i]) {
187 case '0': ar[j] += 0; break;
188 case '1': ar[j] += 1; break;
189 case '2': ar[j] += 2; break;
190 case '3': ar[j] += 3; break;
191 case '4': ar[j] += 4; break;
192 case '5': ar[j] += 5; break;
193 case '6': ar[j] += 6; break;
194 case '7': ar[j] += 7; break;
195 case '8': ar[j] += 8; break;
196 case '9': ar[j] += 9; break;
197 };
198 i++;
199 }
200 }
201 if (j < 4 || ar[4] == 0) {
202 /* if j == 1 then... */
203 switch (j) {
204 case 2: c->refresh = ar[1];
205 case 1: if (ar[0]) c->serial = ar[0];
206 };
207 return 0;
208 }
209 /* these are kept in host-endian form (for now) */
210 if (ar[0]) c->serial = ar[0];
211 c->refresh = ar[1];
212 c->retry = ar[2];
213 c->expire = ar[3];
214 c->minimum = ar[4];
215 c->ttl = c->minimum;
216 if (i < clen(rrdata)) {
217 /* grap ADM as well */
218 str_init(tmp);
219 str_catb(tmp, caddr(rrdata)+i, clen(rrdata)-i);
220 name_to_dns_fix(tmp2, str(tmp), 2); /* email address? */
221 list_push(&c->ADM, str(tmp2));
222 mem_free(str(tmp));
223 }
224 c->soahack = 1;
225
226 return 1;
227 }
__parse_name(dns_ctx * c,bin_t rrdata)228 static char inline *__parse_name(dns_ctx *c, bin_t rrdata)
229 {
230 str_t tmp;
231 bin_t retval;
232 int addzone;
233
234 /* name is in ascii form.... convert to DNS */
235 bin_init(retval);
236 bin_copy(retval, caddr(rrdata), clen(rrdata));
237 addzone = 0;
238 if (ldapdns.relative_names) {
239 /* if . is the last character... */
240 if (clen(retval) && caddr(retval)[clen(retval)-1] != '.') {
241 addzone = 1;
242 }
243 }
244 bin_0(retval);
245 name_to_dns(tmp, (char *)caddr(retval));
246 if (addzone && c->request_name_zone) {
247 /* add the zone to the end */
248 str_cat(tmp, c->request_name_zone);
249 }
250 bin_copy(retval, str(tmp), dns_domain_length(str(tmp)));
251
252 return (char *)caddr(retval);
253 }
__parse_mx(dns_ctx * c,bin_t rrdata)254 static char inline *__parse_mx(dns_ctx *c, bin_t rrdata)
255 {
256 str_t tmp;
257 bin_t retval;
258 unsigned short pref;
259 char *q;
260 register int b, len;
261 int addzone;
262
263 /* name is in ascii form.... convert to DNS */
264 bin_init(retval);
265 q = (char *)caddr(rrdata);
266 len = clen(rrdata);
267 pref = 0;
268 while (len > 0 && *q) {
269 switch (*q) {
270 case '0': b = 0; break;
271 case '1': b = 1; break;
272 case '2': b = 2; break;
273 case '3': b = 3; break;
274 case '4': b = 4; break;
275 case '5': b = 5; break;
276 case '6': b = 6; break;
277 case '7': b = 7; break;
278 case '8': b = 8; break;
279 case '9': b = 9; break;
280 default: b = -1; break;
281 };
282 if (b == -1) break;
283 pref *= 10;
284 pref += b;
285 q++; len--;
286 }
287 while (len > 0 && *q == ' ') { q++; len--; }
288
289 bin_copy(retval, q, len);
290 addzone = 0;
291 if (ldapdns.relative_names) {
292 /* if . is the last character... */
293 if (caddr(retval)[clen(retval)-1] != '.') {
294 addzone = 1;
295 }
296 }
297 bin_0(retval);
298 name_to_dns(tmp, (char *)caddr(retval));
299 if (addzone && c->request_name_zone) {
300 /* add the zone to the end */
301 str_cat(tmp, c->request_name_zone);
302 }
303
304 /* Clib */
305 pref = htons(pref);
306 bin_copy(retval, (char *)&pref, 2);
307 bin_cat(retval, str(tmp), dns_domain_length(str(tmp)));
308 mem_free(str(tmp));
309
310 return (char *)caddr(retval);
311 }
__parse_ipv4(dns_ctx * c,bin_t rrdata)312 static char inline *__parse_ipv4(dns_ctx *c, bin_t rrdata)
313 {
314 /* rrdata is in the form of A.B.C.D; so length bind it... */
315 unsigned char ip[8];
316 register int i, j, a, b, r;
317 bin_t retval;
318 int cflag;
319
320 bin_init(retval);
321 ip[4] = ip[5] = ip[6] = ip[7] = 0;
322 for (i = j = a = cflag = 0; (cflag || j < 4) && i < clen(rrdata); i++) {
323 switch (rrdata->buf[i]) {
324 case '0': b = 0; break;
325 case '1': b = 1; break;
326 case '2': b = 2; break;
327 case '3': b = 3; break;
328 case '4': b = 4; break;
329 case '5': b = 5; break;
330 case '6': b = 6; break;
331 case '7': b = 7; break;
332 case '8': b = 8; break;
333 case '9': b = 9; break;
334 case '.': ip[j] = a; a = 0; j++; continue;
335 case '/': /* i think we're making a subnet-switch */
336 if (!c) /* fail early */
337 return 0;
338 ip[j] = a;
339 j = 4;
340 a = 0;
341 cflag = 1;
342 continue;
343 case '=':
344 if (!c) /* fail early */
345 return 0;
346 ip[j] = a;
347 if (j == 0) {
348 ip[4] = 0xff;
349 ip[5] = ip[6] = ip[7] = 0;
350 } else if (j == 1) {
351 ip[4] = ip[5] = 0xff;
352 ip[6] = ip[7] = 0;
353 } else if (j == 2) {
354 ip[4] = ip[5] = ip[6] = 0xff;
355 ip[7] = 0;
356 } else if (j == 3) {
357 ip[4] = ip[5] = ip[6] = ip[7] = 0xff;
358 } else if (j == 4) {
359 if (ip[4] == 0) {
360 /* exact match */
361 ip[4] = ip[5] = ip[6] = ip[7] = 255;
362 } else if (ip[4] == 255) {
363 /* 255.0.0.0 */
364 ip[4] = 255;
365 ip[5] = ip[6] = ip[7] = 0;
366 } else {
367 /* okay /CIDR notation */
368 r = ip[4];
369 ip[4] = ip[5] = ip[6] = ip[7] = 255;
370 if (r < 8) {
371 ip[4] = (255 << (8 - r));
372 ip[5] = ip[6] = ip[7] = 0;
373 } else if (r < 16) {
374 ip[5] = (255 << (16 - r));
375 ip[6] = ip[7] = 0;
376 } else if (r < 24) {
377 ip[6] = (255 << (24 - r));
378 ip[7] = 0;
379 } else {
380 ip[7] = (255 << (32 - r));
381 }
382 }
383 }
384 if (ipv4_in_subnet(ip, c->ip)) {
385 /* reset and start over */
386 j = b = a = 0;
387 cflag = 0;
388 /* note, we also blop
389 * 'c' so we can't do this again */
390 c = (dns_ctx *)0;
391 continue;
392 }
393 return 0; /* don't return anything */
394 case '%':
395 if (c && j == 3) {
396 if (!c->swm) return 0;
397 /* next chars are "switch" */
398 b = 0; i++;
399 while (i < clen(rrdata)) {
400 /* make sure it matches switch */
401 if (c->swm[b] != rrdata->buf[i])
402 return 0;
403 b++; i++;
404 }
405 goto done_parsing_l;
406 }
407 /* fall through */
408 default:
409 /* invalid */
410 warning("invalid IPV4 address (%c, %d)", rrdata->buf[i], i);
411 return 0;
412 };
413
414 /* digit */
415 a *= 10; a += b;
416 }
417 done_parsing_l:
418 ip[j] = a;
419 bin_copy(retval, ip, 4);
420 return (char *)caddr(retval);
421 }
__parse_email(bin_t rrdata)422 static char inline *__parse_email(bin_t rrdata)
423 {
424 str_t tmp;
425 bin_t retval;
426
427 /* name is in ascii form.... convert to DNS */
428 bin_init(retval);
429 bin_copy(retval, caddr(rrdata), clen(rrdata));
430 bin_0(retval);
431 name_to_dns_fix(tmp, (char *)caddr(retval), 2);
432 bin_copy(retval, str(tmp), dns_domain_length(str(tmp)));
433
434 return (char *)caddr(retval);
435 }
__parse_txt(bin_t rrdata)436 static char inline *__parse_txt(bin_t rrdata)
437 {
438 str_t tmp;
439 bin_t retval;
440
441 /* don't dns-encode the TXT segment */
442 bin_init(retval);
443 bin_addch(retval, clen(rrdata));
444 bin_cat(retval, caddr(rrdata), clen(rrdata));
445 bin_0(retval);
446
447 return (char *)caddr(retval);
448 }
__parse_generic(bin_t rrdata)449 static char inline *__parse_generic(bin_t rrdata)
450 {
451 /* return MUST contain length:
452 * order: rr len data....
453 */
454 bin_t retval;
455 unsigned short n;
456
457 bin_init(retval);
458 bin_copy(retval, caddr(rrdata), 2);
459 /* n is in host-byte order */
460 n = clen(rrdata)-2;
461 bin_copy(retval, (char *)&n, 2);
462 bin_copy(retval, caddr(rrdata)+2, n);
463
464 return (char *)caddr(retval);
465 }
466
467 /* bind-style */
ldap_dnsrecord_rfc1279(dns_ctx * c,bin_t rrdata)468 static int inline ldap_dnsrecord_rfc1279(dns_ctx *c, bin_t rrdata)
469 {
470 register char *q;
471 register int len;
472 char rr[2];
473 bin_t tmp;
474 int r;
475
476 /* IN rr [str] */
477 if (clen(rrdata) < 4) return 0;
478 if (!(tolower((unsigned int)(caddr(rrdata)[0])) == 'i'
479 && tolower((unsigned int)(caddr(rrdata)[1])) == 'n')) {
480 return 0;
481 }
482
483 /* step over whitespace[s] */
484 q = caddr(rrdata) + 2; len = clen(rrdata) - 2;
485 while (len > 0 && (*q == ' ' || *q == '\t')) { q++; len--; }
486 if (len < 2) return 0;
487
488 /* parse word */
489 #define _setrr(x) do { rr[0] = x[0]; rr[1] = x[1]; } while (0)
490 q[0] = toupper(((unsigned int)q[0])); /* modifying rrdata! */
491 if (q[0] == 'A') {
492 /* modifying rrdata */
493 if (toupper(((unsigned int)q[1])) == 'A') {
494 /* AAAA: not supported (yet) */
495 return 0;
496 }
497 /* A: address record */
498 _setrr(DNS_T_A);
499 } else if (q[0] == 'C') {
500 /* CNAME: alias */
501 _setrr(DNS_T_CNAME);
502 } else if (q[0] == 'T') {
503 /* TXT: text record */
504 _setrr(DNS_T_TXT);
505 } else if (q[0] == 'P') {
506 /* PTR: pointer-name */
507 _setrr(DNS_T_PTR);
508 } else if (q[0] == 'M') {
509 /* MX: mail exchanger */
510 _setrr(DNS_T_MX);
511 } else if (q[0] == 'N') {
512 /* NS: name server */
513 _setrr(DNS_T_NS);
514 } else if (q[0] == 'S') {
515 /* SOA: start of authority */
516 _setrr(DNS_T_SOA);
517 }
518 #undef _setrr
519
520 /* parse RR -- pass everything but SOA to their ldapdns parser */
521 while (len > 0 && (*q != ' ' && *q != '\t')) { q++; len--; }
522 if (len < 2) return 0;
523
524 while (len > 0 && (*q == ' ' || *q == '\t')) { q++; len--; }
525 if (len < 2) return 0;
526
527 #define _eq4(x) (rr[0] == x[0] && rr[1] == x[1])
528 if (_eq4(DNS_T_SOA)) {
529 /* start of authority */
530 if (*q == '(') {
531 q++; len--;
532 if (len < 2) return 0;
533 while (len > 0 && (*q == ' ' || *q == '\t')) { q++; len--; }
534 if (len < 2) return 0;
535 }
536 for (r = 0; r < len; r++) {
537 if (q[r] == ')') {
538 r--;
539 while ((q[r] == ' ' || q[r] == '\t') && r > 0)
540 r--;
541 len = r;
542 break;
543 }
544 }
545 /* fall through */
546 }
547
548 bin_init(tmp);
549 bin_copy(tmp, q, len);
550 r = 1;
551 if (_eq4(DNS_T_A)) {
552 /* disables client differentiation */
553 list_push(&c->A, __parse_ipv4((dns_ctx *)0, tmp));
554 } else if (_eq4(DNS_T_PTR)) {
555 list_push(&c->PTR, __parse_name(c, tmp));
556 } else if (!c->subreq) {
557 if (_eq4(DNS_T_MX)) {
558 list_push(&c->MX, __parse_mx(c, tmp));
559 } else if (_eq4(DNS_T_CNAME)) {
560 list_push(&c->CNAME, __parse_name(c, tmp));
561 } else if (_eq4(DNS_T_NS)) {
562 list_push(&c->NS, __parse_name(c, tmp));
563 } else if (_eq4(DNS_T_TXT)) {
564 list_push(&c->TXT, __parse_txt(tmp));
565 } else if (_eq4(DNS_T_SOA)) {
566 r = __parse_soa(c, tmp, 0);
567 } else
568 r = 0;
569 } else
570 r = 0;
571 #undef _eq4
572 mem_free(caddr(tmp));
573 return r;
574 }
575 /* microsoft-style */
ldap_dnsrecord_msdns(dns_ctx * c,bin_t rrdata)576 static int inline ldap_dnsrecord_msdns(dns_ctx *c, bin_t rrdata)
577 {
578 register char *q;
579 bin_t retval;
580
581 if (clen(rrdata) < 24) return 0;
582
583 /* data is in a binary-packed format which i'm not 100% on:
584 * each two-character blob is a single octet. some things are
585 * in network byte-order, other things are NOT. this can be
586 * confusing quick...
587 *
588 * note that places where I've marked the field as 'xx' means i don't
589 * know what it is. 0x means that it's always 00 (in my tests)
590 * but that i still don't know what it is...
591 *
592 * HEADER:
593 *
594 * xx xx [0-1]
595 * RR RR 16-bit: resource record [2-3]
596 * xx xx 0x 0x xx xx 0x 0x [4-11]
597 * TT TT TT TT 32-bit: time to live [12-15]
598 * 0x 0x 0x 0x xx xx xx xx [16-23]
599 * -- last dword has significance for A-records
600 *
601 * what follows is RR-data [24]:
602 *
603 * SOA-RR:
604 * SS SS SS SS serial
605 * AA AA AA AA refresh
606 * BB BB BB BB retry
607 * CC CC CC CC expire
608 * DD DD DD DD minimum
609 *
610 * (44) ll el d.d.d length (ll), elements (el), dns-encoded NS1
611 * ll el d.d.d length (ll), elements (el), hostmaster
612 *
613 * NS-RR
614 * ll el d.d.d length (ll), elements (el), dns-encoded name
615 *
616 * A-RR
617 * a. b. c. d. ip address
618 *
619 * MX-RR
620 * pp pp preference
621 * ll el d.d.d length (ll), elements (el), mail server
622 *
623 * CNAME-RR
624 * (same as ns)
625 * PTR-RR
626 * (same as ns)
627 * TXT-RR
628 * (same as ns; BUT there's ALWAYS only 1 segment)
629 *
630 */
631 #define _eq3(a) (a[0] == (caddr(rrdata)[2]) && a[1] == (caddr(rrdata)[3]))
632 bin_init(retval);
633 if (_eq3(DNS_T_SOA)) {
634 /* Clib */
635 c->refresh = ntohl(*((unsigned long *)(caddr(rrdata)+12)));
636 c->serial = ntohl(*((unsigned long *)(caddr(rrdata)+24)));
637 c->retry = ntohl(*((unsigned long *)(caddr(rrdata)+32)));
638 c->expire = ntohl(*((unsigned long *)(caddr(rrdata)+36)));
639 c->minimum = ntohl(*((unsigned long *)(caddr(rrdata)+40)));
640 c->ttl = c->minimum;
641
642 q = caddr(rrdata) + 44;
643 q++; q++; q += dns_domain_length(q)+1;
644 q++; q++;
645 bin_copy(retval, q, dns_domain_length(q));
646 list_push(&c->ADM, caddr(retval));
647 } else if (_eq3(DNS_T_NS)) {
648 q = caddr(rrdata) + 26;
649 bin_copy(retval, q, dns_domain_length(q));
650 list_push(&c->NS, caddr(retval));
651 } else if (_eq3(DNS_T_A)) {
652 q = caddr(rrdata) + 24;
653 bin_copy(retval, q, 4);
654 list_push(&c->MX, caddr(retval));
655 } else if (_eq3(DNS_T_MX)) {
656 q = caddr(rrdata) + 24;
657 bin_copy(retval, q, 2);
658 q += 4; /* pref and ll,el */
659 bin_cat(retval, q, dns_domain_length(q));
660 list_push(&c->MX, caddr(retval));
661 } else if (_eq3(DNS_T_CNAME)) {
662 q = caddr(rrdata) + 26;
663 bin_copy(retval, q, dns_domain_length(q));
664 list_push(&c->CNAME, caddr(retval));
665 } else if (_eq3(DNS_T_PTR)) {
666 q = caddr(rrdata) + 26;
667 bin_copy(retval, q, dns_domain_length(q));
668 list_push(&c->PTR, caddr(retval));
669 } else if (_eq3(DNS_T_TXT)) {
670 q = caddr(rrdata) + 26;
671 bin_copy(retval, q, dns_domain_length(q));
672 list_push(&c->TXT, caddr(retval));
673 } else {
674 /* didn't really need it */
675 mem_free(caddr(retval));
676 return 0;
677 }
678
679 return 1;
680 }
681 /* me-style */
ldap_arecord(dns_ctx * c,bin_t rrdata)682 static int inline ldap_arecord(dns_ctx *c, bin_t rrdata)
683 {
684 list_push(&c->A, __parse_ipv4(c, rrdata));
685 return 1;
686 }
ldap_serial(dns_ctx * c,bin_t rrdata)687 static int inline ldap_serial(dns_ctx *c, bin_t rrdata)
688 {
689 register int i, ylen;
690 unsigned int Y,M,D, h,m,s;
691 struct tm tp;
692 time_t trymk;
693
694 if (c->soahack) return 1; /* skip */
695
696 /* this is NOT a linear number:
697 * it is a timestamp... and should be treated as such
698 */
699 if (clen(rrdata) < 15) return 0;
700
701 ylen = clen(rrdata) - 11;
702 for (i = Y = 0; i < ylen; i++) {
703 Y *= 10;
704 Y += str_chtoi(caddr(rrdata)[i]);
705 }
706 M = str_chtoi(caddr(rrdata)[i]) * 10; i++;
707 M += str_chtoi(caddr(rrdata)[i]); i++;
708 D = str_chtoi(caddr(rrdata)[i]) * 10; i++;
709 D += str_chtoi(caddr(rrdata)[i]); i++;
710
711 h = str_chtoi(caddr(rrdata)[i]) * 10; i++;
712 h += str_chtoi(caddr(rrdata)[i]); i++;
713 m = str_chtoi(caddr(rrdata)[i]) * 10; i++;
714 m += str_chtoi(caddr(rrdata)[i]); i++;
715 s = str_chtoi(caddr(rrdata)[i]) * 10; i++;
716 s += str_chtoi(caddr(rrdata)[i]); i++;
717
718 tp.tm_sec = s;
719 tp.tm_min = m;
720 tp.tm_hour = h;
721 tp.tm_mday = D;
722 tp.tm_mon = M-1;
723 tp.tm_year = Y-1900;
724 tp.tm_wday = tp.tm_yday = 0;
725 if (caddr(rrdata)[i] == 'z') {
726 tp.tm_isdst = 0;
727 c->serial = mktime(&tp);
728 } else {
729 tp.tm_isdst = 1;
730 trymk = mktime(&tp);
731 if (trymk == -1 || trymk == 11 || trymk == 1) {
732 /*
733 * it would not happen if the ldapserver was always
734 * using GMT....
735 */
736 tp.tm_isdst = 0;
737 trymk = mktime(&tp);
738 }
739 c->serial = trymk;
740 }
741
742 return 1;
743 }
ldap_mxrecord(dns_ctx * c,bin_t rrdata)744 static int inline ldap_mxrecord(dns_ctx *c, bin_t rrdata)
745 {
746 if (!c->subreq) {
747 list_push(&c->MX, __parse_mx(c, rrdata));
748 }
749 return 1;
750 }
ldap_mail(dns_ctx * c,bin_t rrdata)751 static int inline ldap_mail(dns_ctx *c, bin_t rrdata)
752 {
753 if (!c->subreq) {
754 list_push(&c->ADM, __parse_email(rrdata));
755 }
756 return 1;
757 }
ldap_cnamerecord(dns_ctx * c,bin_t rrdata)758 static int inline ldap_cnamerecord(dns_ctx *c, bin_t rrdata)
759 {
760 static char *inaddr_str = "\007in-addr\004arpa";
761 /* check to see if we're in in_addr space */
762 register char *q;
763
764 if (c->request_name) {
765 q = c->request_name + dns_domain_length(c->request_name);
766 q -= 14; /* in-addr.arpa. */
767
768 if (str_equal(q, inaddr_str)) {
769 /* yeehaw */
770 list_push(&c->PTR, __parse_name(c, rrdata));
771 return 1;
772 }
773 }
774 if (!c->subreq) {
775 /* ignore CNAME on subrequest */
776 list_push(&c->CNAME, __parse_name(c, rrdata));
777 }
778 return 1;
779 }
ldap_description(dns_ctx * c,bin_t rrdata)780 static int inline ldap_description(dns_ctx *c, bin_t rrdata)
781 {
782 if (!c->subreq) {
783 list_push(&c->TXT, __parse_txt(rrdata));
784 }
785 return 1;
786 }
ldap_photo(dns_ctx * c,bin_t rrdata)787 static int inline ldap_photo(dns_ctx *c, bin_t rrdata)
788 {
789 list_push(&c->Generic, __parse_generic(rrdata));
790 return 1;
791 }
ldap_nsrecord(dns_ctx * c,bin_t rrdata)792 static int inline ldap_nsrecord(dns_ctx *c, bin_t rrdata)
793 {
794 if (!c->subreq) {
795 list_push(&c->NS, __parse_name(c, rrdata));
796 } else {
797 c->subreq_valid++;
798 }
799 return 1;
800 }
ldap_seealso(dns_ctx * c,bin_t rrdata)801 static int inline ldap_seealso(dns_ctx *c, bin_t rrdata)
802 {
803 list_push(&c->PTR, __parse_name(c, rrdata));
804 return 1;
805 }
ldap_soarecord(dns_ctx * c,bin_t rrdata)806 static int inline ldap_soarecord(dns_ctx *c, bin_t rrdata)
807 {
808 if (!c->subreq) {
809 return __parse_soa(c, rrdata, 1);
810 }
811 return 0;
812 }
handle_ldap_rrdata(dns_ctx * c,char * attr,bin_t rrdata)813 static void inline handle_ldap_rrdata(dns_ctx *c, char *attr, bin_t rrdata)
814 {
815 switch (attr[0]) {
816 case 'a':
817 /* aRecord */
818 ldap_arecord(c, rrdata);
819 break;
820 case 'c': /* cNAMERecord */
821 ldap_cnamerecord(c, rrdata);
822 break;
823 case 'd':
824 if (attr[1] == 'n') {
825 if (attr[2] == 's') {
826 /* dnsRecord */
827 switch (ldapdns.dn_mode) {
828 case DN_MODE_RFC1279:
829 ldap_dnsrecord_rfc1279(c, rrdata);
830 break;
831 case DN_MODE_MSDNS:
832 ldap_dnsrecord_msdns(c, rrdata);
833 break;
834 };
835 }
836 } else {
837 /* description */
838 ldap_description(c, rrdata);
839 }
840 break;
841 case 'm':
842 if (attr[1] == 'o') {
843 break;
844
845 } else if (attr[1] == 'x') {
846 /* mXRecord */
847 ldap_mxrecord(c, rrdata);
848 } else {
849 /* mail */
850 ldap_mail(c, rrdata);
851 }
852 break;
853 case 'n':
854 /* nSRecord */
855 ldap_nsrecord(c, rrdata);
856 break;
857 case 'p': /* generic record (photo) */
858 ldap_photo(c, rrdata);
859 break;
860 case 's':
861 /* sOARecord */
862 if (attr[1] == 'e') {
863 /* seeAlso */
864 ldap_seealso(c, rrdata);
865 } else {
866 /* sOARecord */
867 ldap_soarecord(c, rrdata);
868 }
869 break;
870 };
871 }
ldap_load_dns_attributes(dns_ctx * c,char ** dn,int zonef)872 int ldap_load_dns_attributes(dns_ctx *c, char **dn, int zonef)
873 {
874 /* should be safe; barring any strangeness from ldap client lib */
875 BerElement *ber;
876 char *attr, *val;
877 struct berval **bvals;
878 bin_t rrdata;
879 int i, len;
880 LDAPMessage *m;
881
882 m = ldap_first_entry(c->c->ldap_con, c->message);
883 if (!m) {
884 return 0; /* out of entries */
885 }
886
887 if (dn) {
888 *dn = ldap_get_dn(c->c->ldap_con, m);
889 }
890
891 bin_init(rrdata);
892 attr = ldap_first_attribute(c->c->ldap_con, m, &ber);
893 while (attr) {
894 if (!m) break; /* weird */
895
896 bvals = ldap_get_values_len(c->c->ldap_con, m, attr);
897 if (!bvals) /* server problem could halt here */
898 break;
899
900 str_lc(attr);
901
902 for (i = 0; bvals[i]; i++) {
903 len = bvals[i]->bv_len;
904 if (len < 1)
905 continue;
906
907 val = bvals[i]->bv_val;
908 if (!val) /* should never happen */
909 continue;
910
911 if (attr[0] == 'a' && attr[1] == 's') {
912 /* associated Domain */
913 c->adlen = bvals[i]->bv_len;
914 continue;
915 }
916
917
918 /* convert to bin */
919 bin_copy(rrdata, val, bvals[i]->bv_len);
920
921 if (attr[0] == 'm' && attr[1] == 'o') {
922 /* modify timestamp */
923 if (zonef) ldap_serial(c, rrdata);
924 continue;
925 }
926
927 handle_ldap_rrdata(c, attr, rrdata);
928 }
929
930 ldap_value_free_len(bvals);
931 ldap_memfree(attr);
932
933 attr = ldap_next_attribute(c->c->ldap_con, m, ber);
934 }
935 ber_free(ber, 0);
936 mem_free(caddr(rrdata));
937 while (m) m = ldap_next_entry(c->c->ldap_con, m);
938 return 1;
939 }
940