/* this file contains information for navigating the various LDAP schema */
#include "ldapdns.h"
#include "config.h"
#include "dns.h"
#include "ip.h"
#include <time.h>
void inline ldapdns_list_unique(list_t *p)
{
list_t x = 0;
list_t seen = 0;
list_t lp, sp;
for (lp = (*p); lp; lp = lp->next) {
for (sp = seen; sp; sp = sp->next) {
if (str_equal(sp->str, lp->str)) {
goto HIT;
}
}
list_push(&x, lp->str);
list_push(&seen, lp->str);
HIT:
continue;
}
lp = *p;
while (list_pop(&lp));
while (list_pop(&seen));
*p = x;
}
static void inline ldap_escape(str_t retbuf, char *s)
{
while (*s) {
if (*s == ',') {
str_addch(retbuf, '\\');
}
str_addch(retbuf, *s);
s++;
}
}
void name_to_ldap(str_t retbuf, char *name)
{
list_t p = 0;
char *x;
int i;
str_init(retbuf);
switch (ldapdns.dn_mode) {
case DN_MODE_COSINE:
case DN_MODE_LDAPDNS: /* dc=www, dc=example, dc=com */
case DN_MODE_RFC1279: /* dc=www, dc=example, dc=com */
p = split_name_parts(name);
i = 0; while ((x = list_pop(&p))) {
str_cat(retbuf, "dc=");
ldap_escape(retbuf, x);
str_cat(retbuf, ", ");
i++;
}
if (i) str_chopn(retbuf, 2);
break;
case DN_MODE_MSDNS: /* dc=www.example.com */
str_cat(retbuf, "dc=");
ldap_escape(retbuf, x);
break;
};
}
list_t ldap_into_parts(char *dn)
{
/* safe if dn is infact an asciiZ string */
list_t p = 0;
register char *x = dn, *y;
str_t s;
/* split into parts */
str_init(s);
while (*x == ' ' || *x == ',') x++; /* mostly safe :) */
while (*x) {
/* looking for: \s*,\s* but !~ \\. */
if (*x == '\\') {
x++;
str_addch(s, *x);
x++;
} else if (*x == ',') {
/* pull off excess whitespace from previous */
y = strchr(str(s), '\0');
if (y) {
y--;
while (*y == ' ') y--;
if (*y) y++;
if (*y) *y = 0;
}
list_push(&p, str(s));
str_init(s);
while (*x == ',' || *x == ' ') x++;
} else {
str_addch(s, *x);
x++;
}
}
return p;
}
void ldap_to_name(str_t retbuf, char *dn)
{
/* safe if dn is asciiz */
list_t z, b, p = ldap_into_parts(dn);
char *x, *y, *q;
/* we need the suffix here in order to pull it off */
if (ldapdns.ldap_suffix && *ldapdns.ldap_suffix) {
b = ldap_into_parts(ldapdns.ldap_suffix);
for (z = b; z; z = z->next) {
if (str_diffi(z->str, p->str)) {
break;
} else {
q = list_pop(&p);
mem_free(q);
}
}
while ((x = list_pop(&b))) {
if (str_diffi(x, p->str)) {
mem_free(x);
while ((x = list_pop(&b)))
mem_free(x);
break;
}
q = list_pop(&p);
mem_free(q);
mem_free(x);
}
}
/* flip p around; we have to have this in it's own list */
list_reverse(&p);
str_init(retbuf);
while ((x = list_pop(&p))) {
if (str_start(x, "dc=")) {
y = x + 3;
while (*y == ' ') y++;
if (*y != ',') {
str_cat(retbuf, y);
str_addch(retbuf, '.');
}
}
mem_free(x);
}
str_chop(retbuf);
}
static int inline __parse_soa(dns_ctx *c, bin_t rrdata, int flag)
{
register unsigned int i, j;
unsigned long ar[5];
register char *q;
str_t tmp, tmp2;
q = caddr(rrdata);
if (flag) {
if (clen(rrdata) >= 1 && *q == '*') {
c->wantdie=1;
return 0;
}
/* don't want anything else */
if (clen(rrdata) == 1)
return 0;
}
if (c->soahack) return 1; /* skip */
/* remainder is of the format is serial [ttl retry expire minimum] */
for (j = i = 0; j < 5; j++) { /* safe: bounded */
if (!(i < clen(rrdata))) break;
while (isspace(((unsigned int)q[i])) && i < clen(rrdata)) i++;
if (!(i < clen(rrdata))) break;
ar[j] = 0;
while (isdigit(((unsigned int)q[i])) && i < clen(rrdata)) {
ar[j] *= 10;
switch (q[i]) {
case '0': ar[j] += 0; break;
case '1': ar[j] += 1; break;
case '2': ar[j] += 2; break;
case '3': ar[j] += 3; break;
case '4': ar[j] += 4; break;
case '5': ar[j] += 5; break;
case '6': ar[j] += 6; break;
case '7': ar[j] += 7; break;
case '8': ar[j] += 8; break;
case '9': ar[j] += 9; break;
};
i++;
}
}
if (j < 4 || ar[4] == 0) {
/* if j == 1 then... */
switch (j) {
case 2: c->refresh = ar[1];
case 1: if (ar[0]) c->serial = ar[0];
};
return 0;
}
/* these are kept in host-endian form (for now) */
if (ar[0]) c->serial = ar[0];
c->refresh = ar[1];
c->retry = ar[2];
c->expire = ar[3];
c->minimum = ar[4];
c->ttl = c->minimum;
if (i < clen(rrdata)) {
/* grap ADM as well */
str_init(tmp);
str_catb(tmp, caddr(rrdata)+i, clen(rrdata)-i);
name_to_dns_fix(tmp2, str(tmp), 2); /* email address? */
list_push(&c->ADM, str(tmp2));
mem_free(str(tmp));
}
c->soahack = 1;
return 1;
}
static char inline *__parse_name(dns_ctx *c, bin_t rrdata)
{
str_t tmp;
bin_t retval;
int addzone;
/* name is in ascii form.... convert to DNS */
bin_init(retval);
bin_copy(retval, caddr(rrdata), clen(rrdata));
addzone = 0;
if (ldapdns.relative_names) {
/* if . is the last character... */
if (clen(retval) && caddr(retval)[clen(retval)-1] != '.') {
addzone = 1;
}
}
bin_0(retval);
name_to_dns(tmp, (char *)caddr(retval));
if (addzone && c->request_name_zone) {
/* add the zone to the end */
str_cat(tmp, c->request_name_zone);
}
bin_copy(retval, str(tmp), dns_domain_length(str(tmp)));
return (char *)caddr(retval);
}
static char inline *__parse_mx(dns_ctx *c, bin_t rrdata)
{
str_t tmp;
bin_t retval;
unsigned short pref;
char *q;
register int b, len;
int addzone;
/* name is in ascii form.... convert to DNS */
bin_init(retval);
q = (char *)caddr(rrdata);
len = clen(rrdata);
pref = 0;
while (len > 0 && *q) {
switch (*q) {
case '0': b = 0; break;
case '1': b = 1; break;
case '2': b = 2; break;
case '3': b = 3; break;
case '4': b = 4; break;
case '5': b = 5; break;
case '6': b = 6; break;
case '7': b = 7; break;
case '8': b = 8; break;
case '9': b = 9; break;
default: b = -1; break;
};
if (b == -1) break;
pref *= 10;
pref += b;
q++; len--;
}
while (len > 0 && *q == ' ') { q++; len--; }
bin_copy(retval, q, len);
addzone = 0;
if (ldapdns.relative_names) {
/* if . is the last character... */
if (caddr(retval)[clen(retval)-1] != '.') {
addzone = 1;
}
}
bin_0(retval);
name_to_dns(tmp, (char *)caddr(retval));
if (addzone && c->request_name_zone) {
/* add the zone to the end */
str_cat(tmp, c->request_name_zone);
}
/* Clib */
pref = htons(pref);
bin_copy(retval, (char *)&pref, 2);
bin_cat(retval, str(tmp), dns_domain_length(str(tmp)));
mem_free(str(tmp));
return (char *)caddr(retval);
}
static char inline *__parse_ipv4(dns_ctx *c, bin_t rrdata)
{
/* rrdata is in the form of A.B.C.D; so length bind it... */
unsigned char ip[8];
register int i, j, a, b, r;
bin_t retval;
int cflag;
bin_init(retval);
ip[4] = ip[5] = ip[6] = ip[7] = 0;
for (i = j = a = cflag = 0; (cflag || j < 4) && i < clen(rrdata); i++) {
switch (rrdata->buf[i]) {
case '0': b = 0; break;
case '1': b = 1; break;
case '2': b = 2; break;
case '3': b = 3; break;
case '4': b = 4; break;
case '5': b = 5; break;
case '6': b = 6; break;
case '7': b = 7; break;
case '8': b = 8; break;
case '9': b = 9; break;
case '.': ip[j] = a; a = 0; j++; continue;
case '/': /* i think we're making a subnet-switch */
if (!c) /* fail early */
return 0;
ip[j] = a;
j = 4;
a = 0;
cflag = 1;
continue;
case '=':
if (!c) /* fail early */
return 0;
ip[j] = a;
if (j == 0) {
ip[4] = 0xff;
ip[5] = ip[6] = ip[7] = 0;
} else if (j == 1) {
ip[4] = ip[5] = 0xff;
ip[6] = ip[7] = 0;
} else if (j == 2) {
ip[4] = ip[5] = ip[6] = 0xff;
ip[7] = 0;
} else if (j == 3) {
ip[4] = ip[5] = ip[6] = ip[7] = 0xff;
} else if (j == 4) {
if (ip[4] == 0) {
/* exact match */
ip[4] = ip[5] = ip[6] = ip[7] = 255;
} else if (ip[4] == 255) {
/* 255.0.0.0 */
ip[4] = 255;
ip[5] = ip[6] = ip[7] = 0;
} else {
/* okay /CIDR notation */
r = ip[4];
ip[4] = ip[5] = ip[6] = ip[7] = 255;
if (r < 8) {
ip[4] = (255 << (8 - r));
ip[5] = ip[6] = ip[7] = 0;
} else if (r < 16) {
ip[5] = (255 << (16 - r));
ip[6] = ip[7] = 0;
} else if (r < 24) {
ip[6] = (255 << (24 - r));
ip[7] = 0;
} else {
ip[7] = (255 << (32 - r));
}
}
}
if (ipv4_in_subnet(ip, c->ip)) {
/* reset and start over */
j = b = a = 0;
cflag = 0;
/* note, we also blop
* 'c' so we can't do this again */
c = (dns_ctx *)0;
continue;
}
return 0; /* don't return anything */
case '%':
if (c && j == 3) {
if (!c->swm) return 0;
/* next chars are "switch" */
b = 0; i++;
while (i < clen(rrdata)) {
/* make sure it matches switch */
if (c->swm[b] != rrdata->buf[i])
return 0;
b++; i++;
}
goto done_parsing_l;
}
/* fall through */
default:
/* invalid */
warning("invalid IPV4 address (%c, %d)", rrdata->buf[i], i);
return 0;
};
/* digit */
a *= 10; a += b;
}
done_parsing_l:
ip[j] = a;
bin_copy(retval, ip, 4);
return (char *)caddr(retval);
}
static char inline *__parse_email(bin_t rrdata)
{
str_t tmp;
bin_t retval;
/* name is in ascii form.... convert to DNS */
bin_init(retval);
bin_copy(retval, caddr(rrdata), clen(rrdata));
bin_0(retval);
name_to_dns_fix(tmp, (char *)caddr(retval), 2);
bin_copy(retval, str(tmp), dns_domain_length(str(tmp)));
return (char *)caddr(retval);
}
static char inline *__parse_txt(bin_t rrdata)
{
str_t tmp;
bin_t retval;
/* don't dns-encode the TXT segment */
bin_init(retval);
bin_addch(retval, clen(rrdata));
bin_cat(retval, caddr(rrdata), clen(rrdata));
bin_0(retval);
return (char *)caddr(retval);
}
static char inline *__parse_generic(bin_t rrdata)
{
/* return MUST contain length:
* order: rr len data....
*/
bin_t retval;
unsigned short n;
bin_init(retval);
bin_copy(retval, caddr(rrdata), 2);
/* n is in host-byte order */
n = clen(rrdata)-2;
bin_copy(retval, (char *)&n, 2);
bin_copy(retval, caddr(rrdata)+2, n);
return (char *)caddr(retval);
}
/* bind-style */
static int inline ldap_dnsrecord_rfc1279(dns_ctx *c, bin_t rrdata)
{
register char *q;
register int len;
char rr[2];
bin_t tmp;
int r;
/* IN rr [str] */
if (clen(rrdata) < 4) return 0;
if (!(tolower((unsigned int)(caddr(rrdata)[0])) == 'i'
&& tolower((unsigned int)(caddr(rrdata)[1])) == 'n')) {
return 0;
}
/* step over whitespace[s] */
q = caddr(rrdata) + 2; len = clen(rrdata) - 2;
while (len > 0 && (*q == ' ' || *q == '\t')) { q++; len--; }
if (len < 2) return 0;
/* parse word */
#define _setrr(x) do { rr[0] = x[0]; rr[1] = x[1]; } while (0)
q[0] = toupper(((unsigned int)q[0])); /* modifying rrdata! */
if (q[0] == 'A') {
/* modifying rrdata */
if (toupper(((unsigned int)q[1])) == 'A') {
/* AAAA: not supported (yet) */
return 0;
}
/* A: address record */
_setrr(DNS_T_A);
} else if (q[0] == 'C') {
/* CNAME: alias */
_setrr(DNS_T_CNAME);
} else if (q[0] == 'T') {
/* TXT: text record */
_setrr(DNS_T_TXT);
} else if (q[0] == 'P') {
/* PTR: pointer-name */
_setrr(DNS_T_PTR);
} else if (q[0] == 'M') {
/* MX: mail exchanger */
_setrr(DNS_T_MX);
} else if (q[0] == 'N') {
/* NS: name server */
_setrr(DNS_T_NS);
} else if (q[0] == 'S') {
/* SOA: start of authority */
_setrr(DNS_T_SOA);
}
#undef _setrr
/* parse RR -- pass everything but SOA to their ldapdns parser */
while (len > 0 && (*q != ' ' && *q != '\t')) { q++; len--; }
if (len < 2) return 0;
while (len > 0 && (*q == ' ' || *q == '\t')) { q++; len--; }
if (len < 2) return 0;
#define _eq4(x) (rr[0] == x[0] && rr[1] == x[1])
if (_eq4(DNS_T_SOA)) {
/* start of authority */
if (*q == '(') {
q++; len--;
if (len < 2) return 0;
while (len > 0 && (*q == ' ' || *q == '\t')) { q++; len--; }
if (len < 2) return 0;
}
for (r = 0; r < len; r++) {
if (q[r] == ')') {
r--;
while ((q[r] == ' ' || q[r] == '\t') && r > 0)
r--;
len = r;
break;
}
}
/* fall through */
}
bin_init(tmp);
bin_copy(tmp, q, len);
r = 1;
if (_eq4(DNS_T_A)) {
/* disables client differentiation */
list_push(&c->A, __parse_ipv4((dns_ctx *)0, tmp));
} else if (_eq4(DNS_T_PTR)) {
list_push(&c->PTR, __parse_name(c, tmp));
} else if (!c->subreq) {
if (_eq4(DNS_T_MX)) {
list_push(&c->MX, __parse_mx(c, tmp));
} else if (_eq4(DNS_T_CNAME)) {
list_push(&c->CNAME, __parse_name(c, tmp));
} else if (_eq4(DNS_T_NS)) {
list_push(&c->NS, __parse_name(c, tmp));
} else if (_eq4(DNS_T_TXT)) {
list_push(&c->TXT, __parse_txt(tmp));
} else if (_eq4(DNS_T_SOA)) {
r = __parse_soa(c, tmp, 0);
} else
r = 0;
} else
r = 0;
#undef _eq4
mem_free(caddr(tmp));
return r;
}
/* microsoft-style */
static int inline ldap_dnsrecord_msdns(dns_ctx *c, bin_t rrdata)
{
register char *q;
bin_t retval;
if (clen(rrdata) < 24) return 0;
/* data is in a binary-packed format which i'm not 100% on:
* each two-character blob is a single octet. some things are
* in network byte-order, other things are NOT. this can be
* confusing quick...
*
* note that places where I've marked the field as 'xx' means i don't
* know what it is. 0x means that it's always 00 (in my tests)
* but that i still don't know what it is...
*
* HEADER:
*
* xx xx [0-1]
* RR RR 16-bit: resource record [2-3]
* xx xx 0x 0x xx xx 0x 0x [4-11]
* TT TT TT TT 32-bit: time to live [12-15]
* 0x 0x 0x 0x xx xx xx xx [16-23]
* -- last dword has significance for A-records
*
* what follows is RR-data [24]:
*
* SOA-RR:
* SS SS SS SS serial
* AA AA AA AA refresh
* BB BB BB BB retry
* CC CC CC CC expire
* DD DD DD DD minimum
*
* (44) ll el d.d.d length (ll), elements (el), dns-encoded NS1
* ll el d.d.d length (ll), elements (el), hostmaster
*
* NS-RR
* ll el d.d.d length (ll), elements (el), dns-encoded name
*
* A-RR
* a. b. c. d. ip address
*
* MX-RR
* pp pp preference
* ll el d.d.d length (ll), elements (el), mail server
*
* CNAME-RR
* (same as ns)
* PTR-RR
* (same as ns)
* TXT-RR
* (same as ns; BUT there's ALWAYS only 1 segment)
*
*/
#define _eq3(a) (a[0] == (caddr(rrdata)[2]) && a[1] == (caddr(rrdata)[3]))
bin_init(retval);
if (_eq3(DNS_T_SOA)) {
/* Clib */
c->refresh = ntohl(*((unsigned long *)(caddr(rrdata)+12)));
c->serial = ntohl(*((unsigned long *)(caddr(rrdata)+24)));
c->retry = ntohl(*((unsigned long *)(caddr(rrdata)+32)));
c->expire = ntohl(*((unsigned long *)(caddr(rrdata)+36)));
c->minimum = ntohl(*((unsigned long *)(caddr(rrdata)+40)));
c->ttl = c->minimum;
q = caddr(rrdata) + 44;
q++; q++; q += dns_domain_length(q)+1;
q++; q++;
bin_copy(retval, q, dns_domain_length(q));
list_push(&c->ADM, caddr(retval));
} else if (_eq3(DNS_T_NS)) {
q = caddr(rrdata) + 26;
bin_copy(retval, q, dns_domain_length(q));
list_push(&c->NS, caddr(retval));
} else if (_eq3(DNS_T_A)) {
q = caddr(rrdata) + 24;
bin_copy(retval, q, 4);
list_push(&c->MX, caddr(retval));
} else if (_eq3(DNS_T_MX)) {
q = caddr(rrdata) + 24;
bin_copy(retval, q, 2);
q += 4; /* pref and ll,el */
bin_cat(retval, q, dns_domain_length(q));
list_push(&c->MX, caddr(retval));
} else if (_eq3(DNS_T_CNAME)) {
q = caddr(rrdata) + 26;
bin_copy(retval, q, dns_domain_length(q));
list_push(&c->CNAME, caddr(retval));
} else if (_eq3(DNS_T_PTR)) {
q = caddr(rrdata) + 26;
bin_copy(retval, q, dns_domain_length(q));
list_push(&c->PTR, caddr(retval));
} else if (_eq3(DNS_T_TXT)) {
q = caddr(rrdata) + 26;
bin_copy(retval, q, dns_domain_length(q));
list_push(&c->TXT, caddr(retval));
} else {
/* didn't really need it */
mem_free(caddr(retval));
return 0;
}
return 1;
}
/* me-style */
static int inline ldap_arecord(dns_ctx *c, bin_t rrdata)
{
list_push(&c->A, __parse_ipv4(c, rrdata));
return 1;
}
static int inline ldap_serial(dns_ctx *c, bin_t rrdata)
{
register int i, ylen;
unsigned int Y,M,D, h,m,s;
struct tm tp;
time_t trymk;
if (c->soahack) return 1; /* skip */
/* this is NOT a linear number:
* it is a timestamp... and should be treated as such
*/
if (clen(rrdata) < 15) return 0;
ylen = clen(rrdata) - 11;
for (i = Y = 0; i < ylen; i++) {
Y *= 10;
Y += str_chtoi(caddr(rrdata)[i]);
}
M = str_chtoi(caddr(rrdata)[i]) * 10; i++;
M += str_chtoi(caddr(rrdata)[i]); i++;
D = str_chtoi(caddr(rrdata)[i]) * 10; i++;
D += str_chtoi(caddr(rrdata)[i]); i++;
h = str_chtoi(caddr(rrdata)[i]) * 10; i++;
h += str_chtoi(caddr(rrdata)[i]); i++;
m = str_chtoi(caddr(rrdata)[i]) * 10; i++;
m += str_chtoi(caddr(rrdata)[i]); i++;
s = str_chtoi(caddr(rrdata)[i]) * 10; i++;
s += str_chtoi(caddr(rrdata)[i]); i++;
tp.tm_sec = s;
tp.tm_min = m;
tp.tm_hour = h;
tp.tm_mday = D;
tp.tm_mon = M-1;
tp.tm_year = Y-1900;
tp.tm_wday = tp.tm_yday = 0;
if (caddr(rrdata)[i] == 'z') {
tp.tm_isdst = 0;
c->serial = mktime(&tp);
} else {
tp.tm_isdst = 1;
trymk = mktime(&tp);
if (trymk == -1 || trymk == 11 || trymk == 1) {
/*
* it would not happen if the ldapserver was always
* using GMT....
*/
tp.tm_isdst = 0;
trymk = mktime(&tp);
}
c->serial = trymk;
}
return 1;
}
static int inline ldap_mxrecord(dns_ctx *c, bin_t rrdata)
{
if (!c->subreq) {
list_push(&c->MX, __parse_mx(c, rrdata));
}
return 1;
}
static int inline ldap_mail(dns_ctx *c, bin_t rrdata)
{
if (!c->subreq) {
list_push(&c->ADM, __parse_email(rrdata));
}
return 1;
}
static int inline ldap_cnamerecord(dns_ctx *c, bin_t rrdata)
{
static char *inaddr_str = "\007in-addr\004arpa";
/* check to see if we're in in_addr space */
register char *q;
if (c->request_name) {
q = c->request_name + dns_domain_length(c->request_name);
q -= 14; /* in-addr.arpa. */
if (str_equal(q, inaddr_str)) {
/* yeehaw */
list_push(&c->PTR, __parse_name(c, rrdata));
return 1;
}
}
if (!c->subreq) {
/* ignore CNAME on subrequest */
list_push(&c->CNAME, __parse_name(c, rrdata));
}
return 1;
}
static int inline ldap_description(dns_ctx *c, bin_t rrdata)
{
if (!c->subreq) {
list_push(&c->TXT, __parse_txt(rrdata));
}
return 1;
}
static int inline ldap_photo(dns_ctx *c, bin_t rrdata)
{
list_push(&c->Generic, __parse_generic(rrdata));
return 1;
}
static int inline ldap_nsrecord(dns_ctx *c, bin_t rrdata)
{
if (!c->subreq) {
list_push(&c->NS, __parse_name(c, rrdata));
} else {
c->subreq_valid++;
}
return 1;
}
static int inline ldap_seealso(dns_ctx *c, bin_t rrdata)
{
list_push(&c->PTR, __parse_name(c, rrdata));
return 1;
}
static int inline ldap_soarecord(dns_ctx *c, bin_t rrdata)
{
if (!c->subreq) {
return __parse_soa(c, rrdata, 1);
}
return 0;
}
static void inline handle_ldap_rrdata(dns_ctx *c, char *attr, bin_t rrdata)
{
switch (attr[0]) {
case 'a':
/* aRecord */
ldap_arecord(c, rrdata);
break;
case 'c': /* cNAMERecord */
ldap_cnamerecord(c, rrdata);
break;
case 'd':
if (attr[1] == 'n') {
if (attr[2] == 's') {
/* dnsRecord */
switch (ldapdns.dn_mode) {
case DN_MODE_RFC1279:
ldap_dnsrecord_rfc1279(c, rrdata);
break;
case DN_MODE_MSDNS:
ldap_dnsrecord_msdns(c, rrdata);
break;
};
}
} else {
/* description */
ldap_description(c, rrdata);
}
break;
case 'm':
if (attr[1] == 'o') {
break;
} else if (attr[1] == 'x') {
/* mXRecord */
ldap_mxrecord(c, rrdata);
} else {
/* mail */
ldap_mail(c, rrdata);
}
break;
case 'n':
/* nSRecord */
ldap_nsrecord(c, rrdata);
break;
case 'p': /* generic record (photo) */
ldap_photo(c, rrdata);
break;
case 's':
/* sOARecord */
if (attr[1] == 'e') {
/* seeAlso */
ldap_seealso(c, rrdata);
} else {
/* sOARecord */
ldap_soarecord(c, rrdata);
}
break;
};
}
int ldap_load_dns_attributes(dns_ctx *c, char **dn, int zonef)
{
/* should be safe; barring any strangeness from ldap client lib */
BerElement *ber;
char *attr, *val;
struct berval **bvals;
bin_t rrdata;
int i, len;
LDAPMessage *m;
m = ldap_first_entry(c->c->ldap_con, c->message);
if (!m) {
return 0; /* out of entries */
}
if (dn) {
*dn = ldap_get_dn(c->c->ldap_con, m);
}
bin_init(rrdata);
attr = ldap_first_attribute(c->c->ldap_con, m, &ber);
while (attr) {
if (!m) break; /* weird */
bvals = ldap_get_values_len(c->c->ldap_con, m, attr);
if (!bvals) /* server problem could halt here */
break;
str_lc(attr);
for (i = 0; bvals[i]; i++) {
len = bvals[i]->bv_len;
if (len < 1)
continue;
val = bvals[i]->bv_val;
if (!val) /* should never happen */
continue;
if (attr[0] == 'a' && attr[1] == 's') {
/* associated Domain */
c->adlen = bvals[i]->bv_len;
continue;
}
/* convert to bin */
bin_copy(rrdata, val, bvals[i]->bv_len);
if (attr[0] == 'm' && attr[1] == 'o') {
/* modify timestamp */
if (zonef) ldap_serial(c, rrdata);
continue;
}
handle_ldap_rrdata(c, attr, rrdata);
}
ldap_value_free_len(bvals);
ldap_memfree(attr);
attr = ldap_next_attribute(c->c->ldap_con, m, ber);
}
ber_free(ber, 0);
mem_free(caddr(rrdata));
while (m) m = ldap_next_entry(c->c->ldap_con, m);
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1