1 /* dns stringing functions */
2 #include <errno.h>
3 #include "ldapdns.h"
4 #include "mem.h"
5 
name_to_dns_fix(str_t retbuf,char * name,int splithow)6 void name_to_dns_fix(str_t retbuf, char *name, int splithow)
7 {
8 	register int ch;
9 
10 	ch = (splithow ? '|' : '.');
11 	if (splithow == 2) ch = '@';
12 
13 	/* safe if name is truly ASCIIZ */
14 	while (*name == ch)
15 		++name;
16 
17 	str_init(retbuf);
18 	while (*name) {
19 		register char *start = name;
20 		register unsigned length;
21 		register int tmp;
22 
23 		while (*name && *name != ch)
24 			++name;
25 		length = name - start;
26 		if (length >= 127 && !splithow) {
27 			warning("name-segment too long: %s", name);
28 			return; /* invalid */
29 		}
30 
31 		while (length) {
32 			/* tmp is a function of length, and length must be >0 */
33 			str_addch(retbuf, tmp = length > 127 ? 127 : length);
34 			str_catb(retbuf, start, tmp);
35 			length -= tmp;
36 			start += tmp;
37 		}
38 		while (*name == ch)
39 			++name;
40 		if (splithow == 2) {
41 			splithow = 0;
42 			ch = '.';
43 		}
44 	}
45 }
46 
dns_to_name(str_t retbuf,char * dns,int joinhow)47 void dns_to_name(str_t retbuf, char *dns, int joinhow)
48 {
49 	const char *ch = ".|@";
50 
51 	str_init(retbuf);
52 	while (*dns) {
53 		str_catb(retbuf, dns+1, dns[0]);
54 		str_addch(retbuf, ch[joinhow]);
55 		if (joinhow == 2) joinhow = 0;
56 		dns += (dns[0]+1);
57 	}
58 	/* will have two dots... */
59 	str_chop(retbuf);
60 }
61 
62 /* these lists are built BACKWARDS so that we can just pop() off the first
63  * entries easily when searching for wildcards
64  */
join_name_parts(str_t retbuf,list_t p)65 void join_name_parts(str_t retbuf, list_t p)
66 {
67 	str_init(retbuf);
68 	while (p) {
69 		str_cat(retbuf, p->str);
70 		str_addch(retbuf, '.');
71 		p = p->next;
72 	}
73 	str_chop(retbuf);
74 }
join_dns_parts(str_t retbuf,list_t p)75 void join_dns_parts(str_t retbuf, list_t p)
76 {
77 	str_init(retbuf);
78 	while (p) {
79 		str_addch(retbuf, __str_clen(p->str));
80 		str_cat(retbuf, p->str);
81 
82 		p = p->next;
83 	}
84 	str_chop(retbuf);
85 }
split_name_parts(char * name)86 list_t split_name_parts(char *name)
87 {
88 	/* name is modified by this routine! */
89 	list_t p = 0;
90 	register char *start = name;
91 
92 	while (*start == '.') start++;
93 	while (*start) {
94 		while (*start && *start != '.') start++;
95 		if (*start) {
96 			*start = 0;
97 			start++;
98 			while (*start == '.') start++;
99 		}
100 
101 		list_push(&p, name);
102 		name = start;
103 	}
104 
105 	/* list is in reverse */
106 	list_reverse(&p);
107 
108 	return p;
109 }
split_dns_parts(char * name)110 list_t split_dns_parts(char *name)
111 {
112 	/* name is modified by this routine! */
113 	list_t p = 0;
114 	register unsigned int length, nl;
115 
116 	while (*name) {
117 		length = *name;
118 		if (length == 0)
119 			break;
120 		nl = name[length+1];
121 		name[length+1] = 0;
122 		list_push(&p, name+1);
123 		name += length;
124 	}
125 
126 	/* list is in reverse */
127 	list_reverse(&p);
128 
129 	return p;
130 }
131 
132 /* packet related */
dns_packet_copy(dns_ctx * c,char * out,unsigned int outlen)133 unsigned int dns_packet_copy(dns_ctx *c, char *out,unsigned int outlen)
134 {
135 	while (outlen) {
136 		if (c->request_pos >= c->request_len) {
137 			errno = EBADMSG;
138 			return 0;
139 		}
140 		*out = c->request_buf[c->request_pos++];
141 		++out; --outlen;
142 	}
143 	return c->request_pos;
144 }
145 
dns_packet_skipname(dns_ctx * c)146 unsigned int dns_packet_skipname(dns_ctx *c)
147 {
148 	unsigned char ch;
149 
150 	for (;;) { /* should be safe because it is bounded and breaks on non-movement */
151 		if (c->request_pos >= c->request_len)
152 			break;
153 		ch = c->request_buf[c->request_pos++];
154 		if (ch >= 192) { c->request_pos++; return c->request_pos; }
155 		if (ch >= 64) break;
156 		if (!ch) return c->request_pos;
157 		c->request_pos += ch;
158 	}
159 
160 	errno = EBADMSG;
161 	return 0;
162 }
163 
dns_packet_getname(dns_ctx * c,char ** d)164 unsigned int dns_packet_getname(dns_ctx *c, char **d)
165 {
166 	unsigned int loop = 0;
167 	unsigned int state = 0;
168 	unsigned int firstcompress = 0;
169 	unsigned int where;
170 	unsigned char ch;
171 	char name[255];
172 	unsigned int namelen = 0;
173 
174 	for (;;) { /* should be safe: breaks on non-movement;
175 		      OR after 1000 iterations */
176 		if (c->request_pos >= c->request_len) goto PROTO;
177 		ch = c->request_buf[c->request_pos++];
178 		if (++loop >= 1000) goto PROTO;
179 
180 		if (state) {
181 			if (namelen + 1 > sizeof name) goto PROTO;
182 			name[namelen++] = ch;
183 			--state;
184 		} else {
185 			while (ch >= 192) {
186 				where = ch; where -= 192; where <<= 8;
187 				if (c->request_pos >= c->request_len)
188 					goto PROTO;
189 				ch = c->request_buf[c->request_pos++];
190 				if (!firstcompress)
191 					firstcompress = c->request_pos;
192 				c->request_pos = where + ch;
193 				if (c->request_pos >= c->request_len)
194 					goto PROTO;
195 				ch = c->request_buf[c->request_pos++];
196 				if (++loop >= 1000) goto PROTO;
197 			}
198 			if (ch >= 64) goto PROTO;
199 			if (namelen + 1 > sizeof name) goto PROTO;
200 			name[namelen++] = ch;
201 			if (!ch) break;
202 			state = ch;
203 		}
204 	}
205 
206 	if (!dns_domain_copy(d,name)) return 0;
207 
208 	if (firstcompress) c->request_pos = firstcompress;
209 	return c->request_pos;
210 
211 PROTO:
212 	errno = EBADMSG;
213 	return 0;
214 }
dns_domain_length(const char * dn)215 unsigned int dns_domain_length(const char *dn)
216 {
217 	const char *x;
218 	unsigned char c;
219 
220 	x = dn;
221 	while ((c = *x++)) /* should be safe if dn is a valid dns-encoded */
222 		x += (unsigned int) c;
223 	return x - dn;
224 }
dns_domain_lower(char * dn)225 void dns_domain_lower(char *dn)
226 {
227 	char *x;
228 	int i;
229 
230 	x = dn;
231 	while (*x) { /* should be safe if dn is a valid dns-encoded */
232 		for (i = 1; i <= *x; i++) {
233 			/* Clib */
234 			dn[i] = tolower(dn[i]);
235 		}
236 		dn += *x;
237 		dn++;
238 		x = dn;
239 	}
240 }
dns_domain_copy(char ** out,char * in)241 int dns_domain_copy(char **out, char *in)
242 {
243 	bin_t retval;
244 	unsigned int len;
245 
246 	len = dns_domain_length(in);
247 	bin_init(retval);
248 	bin_copy(retval, in, len);
249 	if (*out) mem_free(*out);
250 	*out = caddr(retval);
251 
252 	return 1;
253 }
254 
255