/* dns stringing functions */ #include #include "ldapdns.h" #include "mem.h" void name_to_dns_fix(str_t retbuf, char *name, int splithow) { register int ch; ch = (splithow ? '|' : '.'); if (splithow == 2) ch = '@'; /* safe if name is truly ASCIIZ */ while (*name == ch) ++name; str_init(retbuf); while (*name) { register char *start = name; register unsigned length; register int tmp; while (*name && *name != ch) ++name; length = name - start; if (length >= 127 && !splithow) { warning("name-segment too long: %s", name); return; /* invalid */ } while (length) { /* tmp is a function of length, and length must be >0 */ str_addch(retbuf, tmp = length > 127 ? 127 : length); str_catb(retbuf, start, tmp); length -= tmp; start += tmp; } while (*name == ch) ++name; if (splithow == 2) { splithow = 0; ch = '.'; } } } void dns_to_name(str_t retbuf, char *dns, int joinhow) { const char *ch = ".|@"; str_init(retbuf); while (*dns) { str_catb(retbuf, dns+1, dns[0]); str_addch(retbuf, ch[joinhow]); if (joinhow == 2) joinhow = 0; dns += (dns[0]+1); } /* will have two dots... */ str_chop(retbuf); } /* these lists are built BACKWARDS so that we can just pop() off the first * entries easily when searching for wildcards */ void join_name_parts(str_t retbuf, list_t p) { str_init(retbuf); while (p) { str_cat(retbuf, p->str); str_addch(retbuf, '.'); p = p->next; } str_chop(retbuf); } void join_dns_parts(str_t retbuf, list_t p) { str_init(retbuf); while (p) { str_addch(retbuf, __str_clen(p->str)); str_cat(retbuf, p->str); p = p->next; } str_chop(retbuf); } list_t split_name_parts(char *name) { /* name is modified by this routine! */ list_t p = 0; register char *start = name; while (*start == '.') start++; while (*start) { while (*start && *start != '.') start++; if (*start) { *start = 0; start++; while (*start == '.') start++; } list_push(&p, name); name = start; } /* list is in reverse */ list_reverse(&p); return p; } list_t split_dns_parts(char *name) { /* name is modified by this routine! */ list_t p = 0; register unsigned int length, nl; while (*name) { length = *name; if (length == 0) break; nl = name[length+1]; name[length+1] = 0; list_push(&p, name+1); name += length; } /* list is in reverse */ list_reverse(&p); return p; } /* packet related */ unsigned int dns_packet_copy(dns_ctx *c, char *out,unsigned int outlen) { while (outlen) { if (c->request_pos >= c->request_len) { errno = EBADMSG; return 0; } *out = c->request_buf[c->request_pos++]; ++out; --outlen; } return c->request_pos; } unsigned int dns_packet_skipname(dns_ctx *c) { unsigned char ch; for (;;) { /* should be safe because it is bounded and breaks on non-movement */ if (c->request_pos >= c->request_len) break; ch = c->request_buf[c->request_pos++]; if (ch >= 192) { c->request_pos++; return c->request_pos; } if (ch >= 64) break; if (!ch) return c->request_pos; c->request_pos += ch; } errno = EBADMSG; return 0; } unsigned int dns_packet_getname(dns_ctx *c, char **d) { unsigned int loop = 0; unsigned int state = 0; unsigned int firstcompress = 0; unsigned int where; unsigned char ch; char name[255]; unsigned int namelen = 0; for (;;) { /* should be safe: breaks on non-movement; OR after 1000 iterations */ if (c->request_pos >= c->request_len) goto PROTO; ch = c->request_buf[c->request_pos++]; if (++loop >= 1000) goto PROTO; if (state) { if (namelen + 1 > sizeof name) goto PROTO; name[namelen++] = ch; --state; } else { while (ch >= 192) { where = ch; where -= 192; where <<= 8; if (c->request_pos >= c->request_len) goto PROTO; ch = c->request_buf[c->request_pos++]; if (!firstcompress) firstcompress = c->request_pos; c->request_pos = where + ch; if (c->request_pos >= c->request_len) goto PROTO; ch = c->request_buf[c->request_pos++]; if (++loop >= 1000) goto PROTO; } if (ch >= 64) goto PROTO; if (namelen + 1 > sizeof name) goto PROTO; name[namelen++] = ch; if (!ch) break; state = ch; } } if (!dns_domain_copy(d,name)) return 0; if (firstcompress) c->request_pos = firstcompress; return c->request_pos; PROTO: errno = EBADMSG; return 0; } unsigned int dns_domain_length(const char *dn) { const char *x; unsigned char c; x = dn; while ((c = *x++)) /* should be safe if dn is a valid dns-encoded */ x += (unsigned int) c; return x - dn; } void dns_domain_lower(char *dn) { char *x; int i; x = dn; while (*x) { /* should be safe if dn is a valid dns-encoded */ for (i = 1; i <= *x; i++) { /* Clib */ dn[i] = tolower(dn[i]); } dn += *x; dn++; x = dn; } } int dns_domain_copy(char **out, char *in) { bin_t retval; unsigned int len; len = dns_domain_length(in); bin_init(retval); bin_copy(retval, in, len); if (*out) mem_free(*out); *out = caddr(retval); return 1; }