msi: Only copy the resulting string if the RegistryValue call succeeded.
[wine/multimedia.git] / dlls / dnsapi / ns_name.c
bloba108c563cfb33f4faceca011b63500f91f93ebc7
1 /*
2 * Copyright (c) 1996,1999 by Internet Software Consortium.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
18 #include "config.h"
20 #include <sys/types.h>
22 #ifdef HAVE_NETINET_IN_H
23 # include <netinet/in.h>
24 #endif
25 #ifdef HAVE_ARPA_NAMESER_H
26 # include <arpa/nameser.h>
27 #endif
29 #include <ctype.h>
30 #include <errno.h>
31 #ifdef HAVE_RESOLV_H
32 # include <resolv.h>
33 #endif
34 #include <string.h>
36 /* Data. */
38 static const char digits[] = "0123456789";
40 /* Forward. */
42 static int special(int);
43 static int printable(int);
45 /* Public. */
48 * dns_ns_name_ntop(src, dst, dstsiz)
49 * Convert an encoded domain name to printable ascii as per RFC1035.
50 * return:
51 * Number of bytes written to buffer, or -1 (with errno set)
52 * notes:
53 * The root is returned as "."
54 * All other domains are returned in non absolute form
56 static int
57 dns_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
58 const u_char *cp;
59 char *dn, *eom;
60 u_char c;
61 u_int n;
63 cp = src;
64 dn = dst;
65 eom = dst + dstsiz;
67 while ((n = *cp++) != 0) {
68 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {
69 /* Some kind of compression pointer. */
70 return (-1);
72 if (dn != dst) {
73 if (dn >= eom) {
74 return (-1);
76 *dn++ = '.';
79 if (n == 0x41) {
80 n = *cp++ / 8;
81 if (dn + n * 2 + 4 >= eom) {
82 return (-1);
84 *dn++ = '\\';
85 *dn++ = '[';
86 *dn++ = 'x';
88 while (n-- > 0) {
89 unsigned u;
90 c = *cp++;
91 u = c >> 4;
92 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
93 u = c & 0xf;
94 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
97 *dn++ = ']';
98 continue;
101 if (dn + n >= eom) {
102 return (-1);
104 for ((void)NULL; n > 0; n--) {
105 c = *cp++;
106 if (special(c)) {
107 if (dn + 1 >= eom) {
108 return (-1);
110 *dn++ = '\\';
111 *dn++ = (char)c;
112 } else if (!printable(c)) {
113 if (dn + 3 >= eom) {
114 return (-1);
116 *dn++ = '\\';
117 *dn++ = digits[c / 100];
118 *dn++ = digits[(c % 100) / 10];
119 *dn++ = digits[c % 10];
120 } else {
121 if (dn >= eom) {
122 return (-1);
124 *dn++ = (char)c;
128 if (dn == dst) {
129 if (dn >= eom) {
130 return (-1);
132 *dn++ = '.';
134 if (dn >= eom) {
135 return (-1);
137 *dn++ = '\0';
138 return (dn - dst);
142 * dns_ns_name_pton(src, dst, dstsiz)
143 * Convert a ascii string into an encoded domain name as per RFC1035.
144 * return:
145 * -1 if it fails
146 * 1 if string was fully qualified
147 * 0 is string was not fully qualified
148 * notes:
149 * Enforces label and domain length limits.
153 dns_ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
154 u_char *label, *bp, *eom;
155 int c, n, escaped;
156 char *cp;
158 escaped = 0;
159 bp = dst;
160 eom = dst + dstsiz;
161 label = bp++;
163 while ((c = *src++) != 0) {
164 if (escaped) {
165 if ((cp = strchr(digits, c)) != NULL) {
166 n = (cp - digits) * 100;
167 if ((c = *src++) == 0 ||
168 (cp = strchr(digits, c)) == NULL) {
169 return (-1);
171 n += (cp - digits) * 10;
172 if ((c = *src++) == 0 ||
173 (cp = strchr(digits, c)) == NULL) {
174 return (-1);
176 n += (cp - digits);
177 if (n > 255) {
178 return (-1);
180 c = n;
181 } else if (c == '[' && label == bp - 1 && *src == 'x') {
182 /* Theoretically we would have to handle \[o
183 as well but we do not since we do not need
184 it internally. */
185 *label = 0x41;
186 label = bp++;
187 ++src;
188 while (isxdigit (*src)) {
189 n = *src > '9' ? *src - 'a' + 10 : *src - '0';
190 ++src;
191 if (! isxdigit(*src)) {
192 return (-1);
194 n <<= 4;
195 n += *src > '9' ? *src - 'a' + 10 : *src - '0';
196 if (bp + 1 >= eom) {
197 return (-1);
199 *bp++ = n;
200 ++src;
202 *label = (bp - label - 1) * 8;
203 if (*src++ != ']' || *src++ != '.') {
204 return (-1);
206 escaped = 0;
207 label = bp++;
208 if (bp >= eom) {
209 return (-1);
211 continue;
213 escaped = 0;
214 } else if (c == '\\') {
215 escaped = 1;
216 continue;
217 } else if (c == '.') {
218 c = (bp - label - 1);
219 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
220 return (-1);
222 if (label >= eom) {
223 return (-1);
225 *label = c;
226 /* Fully qualified ? */
227 if (*src == '\0') {
228 if (c != 0) {
229 if (bp >= eom) {
230 return (-1);
232 *bp++ = '\0';
234 if ((bp - dst) > NS_MAXCDNAME) {
235 return (-1);
237 return (1);
239 if (c == 0 || *src == '.') {
240 return (-1);
242 label = bp++;
243 continue;
245 if (bp >= eom) {
246 return (-1);
248 *bp++ = (u_char)c;
250 c = (bp - label - 1);
251 if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
252 return (-1);
254 if (label >= eom) {
255 return (-1);
257 *label = c;
258 if (c != 0) {
259 if (bp >= eom) {
260 return (-1);
262 *bp++ = 0;
264 if ((bp - dst) > NS_MAXCDNAME) { /* src too big */
265 return (-1);
267 return (0);
272 * dns_ns_name_unpack(msg, eom, src, dst, dstsiz)
273 * Unpack a domain name from a message, source may be compressed.
274 * return:
275 * -1 if it fails, or consumed octets if it succeeds.
277 static int
278 dns_ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
279 u_char *dst, size_t dstsiz)
281 const u_char *srcp, *dstlim;
282 u_char *dstp;
283 int n, len, checked;
285 len = -1;
286 checked = 0;
287 dstp = dst;
288 srcp = src;
289 dstlim = dst + dstsiz;
290 if (srcp < msg || srcp >= eom) {
291 return (-1);
293 /* Fetch next label in domain name. */
294 while ((n = *srcp++) != 0) {
295 /* Check for indirection. */
296 switch (n & NS_CMPRSFLGS) {
297 case 0x40:
298 if (n == 0x41) {
299 if (dstp + 1 >= dstlim) {
300 return (-1);
302 *dstp++ = 0x41;
303 n = *srcp++ / 8;
304 ++checked;
305 } else {
306 return (-1); /* flag error */
308 /* FALLTHROUGH */
309 case 0:
310 /* Limit checks. */
311 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
312 return (-1);
314 checked += n + 1;
315 dstp = memcpy(dstp, srcp - 1, n + 1);
316 dstp += n + 1;
317 srcp += n;
318 break;
320 case NS_CMPRSFLGS:
321 if (srcp >= eom) {
322 return (-1);
324 if (len < 0)
325 len = srcp - src + 1;
326 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
327 if (srcp < msg || srcp >= eom) { /* Out of range. */
328 return (-1);
330 checked += 2;
332 * Check for loops in the compressed name;
333 * if we've looked at the whole message,
334 * there must be a loop.
336 if (checked >= eom - msg) {
337 return (-1);
339 break;
341 default:
342 return (-1); /* flag error */
345 *dstp = '\0';
346 if (len < 0)
347 len = srcp - src;
348 return (len);
353 * dns_ns_name_uncompress(msg, eom, src, dst, dstsiz)
354 * Expand compressed domain name to presentation format.
355 * return:
356 * Number of bytes read out of `src', or -1 (with errno set).
357 * note:
358 * Root domain returns as "." not "".
361 dns_ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
362 char *dst, size_t dstsiz)
364 u_char tmp[NS_MAXCDNAME];
365 int n;
367 if ((n = dns_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
368 return (-1);
369 if (dns_ns_name_ntop(tmp, dst, dstsiz) == -1)
370 return (-1);
371 return (n);
376 * dns_ns_name_skip(ptrptr, eom)
377 * Advance *ptrptr to skip over the compressed name it points at.
378 * return:
379 * 0 on success, -1 (with errno set) on failure.
382 dns_ns_name_skip(const u_char **ptrptr, const u_char *eom) {
383 const u_char *cp;
384 u_int n;
386 cp = *ptrptr;
387 while (cp < eom && (n = *cp++) != 0) {
388 /* Check for indirection. */
389 switch (n & NS_CMPRSFLGS) {
390 case 0: /* normal case, n == len */
391 cp += n;
392 continue;
393 case NS_CMPRSFLGS: /* indirection */
394 cp++;
395 break;
396 default: /* illegal type */
397 return (-1);
399 break;
401 if (cp > eom) {
402 return (-1);
404 *ptrptr = cp;
405 return (0);
408 /* Private. */
411 * special(ch)
412 * Thinking in noninternationalized USASCII (per the DNS spec),
413 * is this character special ("in need of quoting") ?
414 * return:
415 * boolean.
417 static int
418 special(int ch) {
419 switch (ch) {
420 case 0x22: /* '"' */
421 case 0x2E: /* '.' */
422 case 0x3B: /* ';' */
423 case 0x5C: /* '\\' */
424 /* Special modifiers in zone files. */
425 case 0x40: /* '@' */
426 case 0x24: /* '$' */
427 return (1);
428 default:
429 return (0);
434 * printable(ch)
435 * Thinking in noninternationalized USASCII (per the DNS spec),
436 * is this character visible and not a space when printed ?
437 * return:
438 * boolean.
440 static int
441 printable(int ch) {
442 return (ch > 0x20 && ch < 0x7f);