shell32: RunFileDlg: allow the user to cancel the Browse dialog, remove some unneeded...
[wine] / dlls / dnsapi / ns_name.c
1 /*
2  * Copyright (c) 1996,1999 by Internet Software Consortium.
3  *
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.
7  *
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.
16  */
17
18 #include "config.h"
19
20 #include <sys/types.h>
21
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
28
29 #include <ctype.h>
30 #include <errno.h>
31 #ifdef HAVE_RESOLV_H
32 # include <resolv.h>
33 #endif
34 #include <string.h>
35
36 /* Data. */
37
38 static const char       digits[] = "0123456789";
39
40 /* Forward. */
41
42 static int              special(int);
43 static int              printable(int);
44
45 /* Public. */
46
47 /*
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
55  */
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;
62
63         cp = src;
64         dn = dst;
65         eom = dst + dstsiz;
66
67         while ((n = *cp++) != 0) {
68                 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {
69                         /* Some kind of compression pointer. */
70                         return (-1);
71                 }
72                 if (dn != dst) {
73                         if (dn >= eom) {
74                                 return (-1);
75                         }
76                         *dn++ = '.';
77                 }
78
79                 if (n == 0x41) {
80                         n = *cp++ / 8;
81                         if (dn + n * 2 + 4 >= eom) {
82                                 return (-1);
83                         }
84                         *dn++ = '\\';
85                         *dn++ = '[';
86                         *dn++ = 'x';
87
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;
95                         }
96
97                         *dn++ = ']';
98                         continue;
99                 }
100
101                 if (dn + n >= eom) {
102                         return (-1);
103                 }
104                 for ((void)NULL; n > 0; n--) {
105                         c = *cp++;
106                         if (special(c)) {
107                                 if (dn + 1 >= eom) {
108                                         return (-1);
109                                 }
110                                 *dn++ = '\\';
111                                 *dn++ = (char)c;
112                         } else if (!printable(c)) {
113                                 if (dn + 3 >= eom) {
114                                         return (-1);
115                                 }
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);
123                                 }
124                                 *dn++ = (char)c;
125                         }
126                 }
127         }
128         if (dn == dst) {
129                 if (dn >= eom) {
130                         return (-1);
131                 }
132                 *dn++ = '.';
133         }
134         if (dn >= eom) {
135                 return (-1);
136         }
137         *dn++ = '\0';
138         return (dn - dst);
139 }
140
141 /*
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.
150  */
151
152 int
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;
157
158         escaped = 0;
159         bp = dst;
160         eom = dst + dstsiz;
161         label = bp++;
162
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);
170                                 }
171                                 n += (cp - digits) * 10;
172                                 if ((c = *src++) == 0 ||
173                                     (cp = strchr(digits, c)) == NULL) {
174                                         return (-1);
175                                 }
176                                 n += (cp - digits);
177                                 if (n > 255) {
178                                         return (-1);
179                                 }
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);
193                                         }
194                                         n <<= 4;
195                                         n += *src > '9' ? *src - 'a' + 10 : *src - '0';
196                                         if (bp + 1 >= eom) {
197                                                 return (-1);
198                                         }
199                                         *bp++ = n;
200                                         ++src;
201                                 }
202                                 *label = (bp - label - 1) * 8;
203                                 if (*src++ != ']' || *src++ != '.') {
204                                         return (-1);
205                                 }
206                                 escaped = 0;
207                                 label = bp++;
208                                 if (bp >= eom) {
209                                         return (-1);
210                                 }
211                                 continue;
212                         }
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);
221                         }
222                         if (label >= eom) {
223                                 return (-1);
224                         }
225                         *label = c;
226                         /* Fully qualified ? */
227                         if (*src == '\0') {
228                                 if (c != 0) {
229                                         if (bp >= eom) {
230                                                 return (-1);
231                                         }
232                                         *bp++ = '\0';
233                                 }
234                                 if ((bp - dst) > NS_MAXCDNAME) {
235                                         return (-1);
236                                 }
237                                 return (1);
238                         }
239                         if (c == 0 || *src == '.') {
240                                 return (-1);
241                         }
242                         label = bp++;
243                         continue;
244                 }
245                 if (bp >= eom) {
246                         return (-1);
247                 }
248                 *bp++ = (u_char)c;
249         }
250         c = (bp - label - 1);
251         if ((c & NS_CMPRSFLGS) != 0) {          /* Label too big. */
252                 return (-1);
253         }
254         if (label >= eom) {
255                 return (-1);
256         }
257         *label = c;
258         if (c != 0) {
259                 if (bp >= eom) {
260                         return (-1);
261                 }
262                 *bp++ = 0;
263         }
264         if ((bp - dst) > NS_MAXCDNAME) {        /* src too big */
265                 return (-1);
266         }
267         return (0);
268 }
269
270
271 /*
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.
276  */
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)
280 {
281         const u_char *srcp, *dstlim;
282         u_char *dstp;
283         int n, len, checked;
284
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);
292         }
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);
301                                 }
302                                 *dstp++ = 0x41;
303                                 n = *srcp++ / 8;
304                                 ++checked;
305                         } else {
306                                 return (-1);            /* flag error */
307                         }
308                         /* FALLTHROUGH */
309                 case 0:
310                         /* Limit checks. */
311                         if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
312                                 return (-1);
313                         }
314                         checked += n + 1;
315                         dstp = memcpy(dstp, srcp - 1, n + 1);
316                         dstp += n + 1;
317                         srcp += n;
318                         break;
319
320                 case NS_CMPRSFLGS:
321                         if (srcp >= eom) {
322                                 return (-1);
323                         }
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);
329                         }
330                         checked += 2;
331                         /*
332                          * Check for loops in the compressed name;
333                          * if we've looked at the whole message,
334                          * there must be a loop.
335                          */
336                         if (checked >= eom - msg) {
337                                 return (-1);
338                         }
339                         break;
340
341                 default:
342                         return (-1);                    /* flag error */
343                 }
344         }
345         *dstp = '\0';
346         if (len < 0)
347                 len = srcp - src;
348         return (len);
349 }
350
351
352 /*
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 "".
359  */
360 int
361 dns_ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
362                    char *dst, size_t dstsiz)
363 {
364         u_char tmp[NS_MAXCDNAME];
365         int n;
366
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);
372 }
373
374
375 /*
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.
380  */
381 int
382 dns_ns_name_skip(const u_char **ptrptr, const u_char *eom) {
383         const u_char *cp;
384         u_int n;
385
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);
398                 }
399                 break;
400         }
401         if (cp > eom) {
402                 return (-1);
403         }
404         *ptrptr = cp;
405         return (0);
406 }
407
408 /* Private. */
409
410 /*
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.
416  */
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);
430         }
431 }
432
433 /*
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.
439  */
440 static int
441 printable(int ch) {
442         return (ch > 0x20 && ch < 0x7f);
443 }