ole32: Implement MkParseDisplayName.
[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 #include <ctype.h>
36
37 /* Data. */
38
39 static const char       digits[] = "0123456789";
40
41 /* Forward. */
42
43 static int              special(int);
44 static int              printable(int);
45
46 /* Public. */
47
48 /*
49  * dns_ns_name_ntop(src, dst, dstsiz)
50  *      Convert an encoded domain name to printable ascii as per RFC1035.
51  * return:
52  *      Number of bytes written to buffer, or -1 (with errno set)
53  * notes:
54  *      The root is returned as "."
55  *      All other domains are returned in non absolute form
56  */
57 static int
58 dns_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
59         const u_char *cp;
60         char *dn, *eom;
61         u_char c;
62         u_int n;
63
64         cp = src;
65         dn = dst;
66         eom = dst + dstsiz;
67
68         while ((n = *cp++) != 0) {
69                 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {
70                         /* Some kind of compression pointer. */
71                         return (-1);
72                 }
73                 if (dn != dst) {
74                         if (dn >= eom) {
75                                 return (-1);
76                         }
77                         *dn++ = '.';
78                 }
79
80                 if (n == 0x41) {
81                         n = *cp++ / 8;
82                         if (dn + n * 2 + 4 >= eom) {
83                                 return (-1);
84                         }
85                         *dn++ = '\\';
86                         *dn++ = '[';
87                         *dn++ = 'x';
88
89                         while (n-- > 0) {
90                 unsigned u;
91                                 c = *cp++;
92                                 u = c >> 4;
93                                 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
94                                 u = c & 0xf;
95                                 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
96                         }
97
98                         *dn++ = ']';
99                         continue;
100                 }
101
102                 if (dn + n >= eom) {
103                         return (-1);
104                 }
105                 for ((void)NULL; n > 0; n--) {
106                         c = *cp++;
107                         if (special(c)) {
108                                 if (dn + 1 >= eom) {
109                                         return (-1);
110                                 }
111                                 *dn++ = '\\';
112                                 *dn++ = (char)c;
113                         } else if (!printable(c)) {
114                                 if (dn + 3 >= eom) {
115                                         return (-1);
116                                 }
117                                 *dn++ = '\\';
118                                 *dn++ = digits[c / 100];
119                                 *dn++ = digits[(c % 100) / 10];
120                                 *dn++ = digits[c % 10];
121                         } else {
122                                 if (dn >= eom) {
123                                         return (-1);
124                                 }
125                                 *dn++ = (char)c;
126                         }
127                 }
128         }
129         if (dn == dst) {
130                 if (dn >= eom) {
131                         return (-1);
132                 }
133                 *dn++ = '.';
134         }
135         if (dn >= eom) {
136                 return (-1);
137         }
138         *dn++ = '\0';
139         return (dn - dst);
140 }
141
142 /*
143  * dns_ns_name_pton(src, dst, dstsiz)
144  *      Convert a ascii string into an encoded domain name as per RFC1035.
145  * return:
146  *      -1 if it fails
147  *      1 if string was fully qualified
148  *      0 is string was not fully qualified
149  * notes:
150  *      Enforces label and domain length limits.
151  */
152
153 int
154 dns_ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
155         u_char *label, *bp, *eom;
156         int c, n, escaped;
157         char *cp;
158
159         escaped = 0;
160         bp = dst;
161         eom = dst + dstsiz;
162         label = bp++;
163
164         while ((c = *src++) != 0) {
165                 if (escaped) {
166                         if ((cp = strchr(digits, c)) != NULL) {
167                                 n = (cp - digits) * 100;
168                                 if ((c = *src++) == 0 ||
169                                     (cp = strchr(digits, c)) == NULL) {
170                                         return (-1);
171                                 }
172                                 n += (cp - digits) * 10;
173                                 if ((c = *src++) == 0 ||
174                                     (cp = strchr(digits, c)) == NULL) {
175                                         return (-1);
176                                 }
177                                 n += (cp - digits);
178                                 if (n > 255) {
179                                         return (-1);
180                                 }
181                                 c = n;
182                         } else if (c == '[' && label == bp - 1 && *src == 'x') {
183                                 /* Theoretically we would have to handle \[o
184                                    as well but we do not since we do not need
185                                    it internally.  */
186                                 *label = 0x41;
187                                 label = bp++;
188                                 ++src;
189                                 while (isxdigit (*src)) {
190                                         n = *src > '9' ? *src - 'a' + 10 : *src - '0';
191                                         ++src;
192                                         if (! isxdigit(*src)) {
193                                                 return (-1);
194                                         }
195                                         n <<= 4;
196                                         n += *src > '9' ? *src - 'a' + 10 : *src - '0';
197                                         if (bp + 1 >= eom) {
198                                                 return (-1);
199                                         }
200                                         *bp++ = n;
201                                         ++src;
202                                 }
203                                 *label = (bp - label - 1) * 8;
204                                 if (*src++ != ']' || *src++ != '.') {
205                                         return (-1);
206                                 }
207                                 escaped = 0;
208                                 label = bp++;
209                                 if (bp >= eom) {
210                                         return (-1);
211                                 }
212                                 continue;
213                         }
214                         escaped = 0;
215                 } else if (c == '\\') {
216                         escaped = 1;
217                         continue;
218                 } else if (c == '.') {
219                         c = (bp - label - 1);
220                         if ((c & NS_CMPRSFLGS) != 0) {  /* Label too big. */
221                                 return (-1);
222                         }
223                         if (label >= eom) {
224                                 return (-1);
225                         }
226                         *label = c;
227                         /* Fully qualified ? */
228                         if (*src == '\0') {
229                                 if (c != 0) {
230                                         if (bp >= eom) {
231                                                 return (-1);
232                                         }
233                                         *bp++ = '\0';
234                                 }
235                                 if ((bp - dst) > NS_MAXCDNAME) {
236                                         return (-1);
237                                 }
238                                 return (1);
239                         }
240                         if (c == 0 || *src == '.') {
241                                 return (-1);
242                         }
243                         label = bp++;
244                         continue;
245                 }
246                 if (bp >= eom) {
247                         return (-1);
248                 }
249                 *bp++ = (u_char)c;
250         }
251         c = (bp - label - 1);
252         if ((c & NS_CMPRSFLGS) != 0) {          /* Label too big. */
253                 return (-1);
254         }
255         if (label >= eom) {
256                 return (-1);
257         }
258         *label = c;
259         if (c != 0) {
260                 if (bp >= eom) {
261                         return (-1);
262                 }
263                 *bp++ = 0;
264         }
265         if ((bp - dst) > NS_MAXCDNAME) {        /* src too big */
266                 return (-1);
267         }
268         return (0);
269 }
270
271
272 /*
273  * dns_ns_name_unpack(msg, eom, src, dst, dstsiz)
274  *      Unpack a domain name from a message, source may be compressed.
275  * return:
276  *      -1 if it fails, or consumed octets if it succeeds.
277  */
278 static int
279 dns_ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
280                u_char *dst, size_t dstsiz)
281 {
282         const u_char *srcp, *dstlim;
283         u_char *dstp;
284         int n, len, checked;
285
286         len = -1;
287         checked = 0;
288         dstp = dst;
289         srcp = src;
290         dstlim = dst + dstsiz;
291         if (srcp < msg || srcp >= eom) {
292                 return (-1);
293         }
294         /* Fetch next label in domain name. */
295         while ((n = *srcp++) != 0) {
296                 /* Check for indirection. */
297                 switch (n & NS_CMPRSFLGS) {
298                 case 0x40:
299                         if (n == 0x41) {
300                                 if (dstp + 1 >= dstlim) {
301                                         return (-1);
302                                 }
303                                 *dstp++ = 0x41;
304                                 n = *srcp++ / 8;
305                                 ++checked;
306                         } else {
307                                 return (-1);            /* flag error */
308                         }
309                         /* FALLTHROUGH */
310                 case 0:
311                         /* Limit checks. */
312                         if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
313                                 return (-1);
314                         }
315                         checked += n + 1;
316                         dstp = memcpy(dstp, srcp - 1, n + 1);
317                         dstp += n + 1;
318                         srcp += n;
319                         break;
320
321                 case NS_CMPRSFLGS:
322                         if (srcp >= eom) {
323                                 return (-1);
324                         }
325                         if (len < 0)
326                                 len = srcp - src + 1;
327                         srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
328                         if (srcp < msg || srcp >= eom) {  /* Out of range. */
329                                 return (-1);
330                         }
331                         checked += 2;
332                         /*
333                          * Check for loops in the compressed name;
334                          * if we've looked at the whole message,
335                          * there must be a loop.
336                          */
337                         if (checked >= eom - msg) {
338                                 return (-1);
339                         }
340                         break;
341
342                 default:
343                         return (-1);                    /* flag error */
344                 }
345         }
346         *dstp = '\0';
347         if (len < 0)
348                 len = srcp - src;
349         return (len);
350 }
351
352
353 /*
354  * dns_ns_name_uncompress(msg, eom, src, dst, dstsiz)
355  *      Expand compressed domain name to presentation format.
356  * return:
357  *      Number of bytes read out of `src', or -1 (with errno set).
358  * note:
359  *      Root domain returns as "." not "".
360  */
361 int
362 dns_ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
363                    char *dst, size_t dstsiz)
364 {
365         u_char tmp[NS_MAXCDNAME];
366         int n;
367
368         if ((n = dns_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
369                 return (-1);
370         if (dns_ns_name_ntop(tmp, dst, dstsiz) == -1)
371                 return (-1);
372         return (n);
373 }
374
375
376 /*
377  * dns_ns_name_skip(ptrptr, eom)
378  *      Advance *ptrptr to skip over the compressed name it points at.
379  * return:
380  *      0 on success, -1 (with errno set) on failure.
381  */
382 int
383 dns_ns_name_skip(const u_char **ptrptr, const u_char *eom) {
384         const u_char *cp;
385         u_int n;
386
387         cp = *ptrptr;
388         while (cp < eom && (n = *cp++) != 0) {
389                 /* Check for indirection. */
390                 switch (n & NS_CMPRSFLGS) {
391                 case 0:                 /* normal case, n == len */
392                         cp += n;
393                         continue;
394                 case NS_CMPRSFLGS:      /* indirection */
395                         cp++;
396                         break;
397                 default:                /* illegal type */
398                         return (-1);
399                 }
400                 break;
401         }
402         if (cp > eom) {
403                 return (-1);
404         }
405         *ptrptr = cp;
406         return (0);
407 }
408
409 /* Private. */
410
411 /*
412  * special(ch)
413  *      Thinking in noninternationalized USASCII (per the DNS spec),
414  *      is this characted special ("in need of quoting") ?
415  * return:
416  *      boolean.
417  */
418 static int
419 special(int ch) {
420         switch (ch) {
421         case 0x22: /* '"' */
422         case 0x2E: /* '.' */
423         case 0x3B: /* ';' */
424         case 0x5C: /* '\\' */
425         /* Special modifiers in zone files. */
426         case 0x40: /* '@' */
427         case 0x24: /* '$' */
428                 return (1);
429         default:
430                 return (0);
431         }
432 }
433
434 /*
435  * printable(ch)
436  *      Thinking in noninternationalized USASCII (per the DNS spec),
437  *      is this character visible and not a space when printed ?
438  * return:
439  *      boolean.
440  */
441 static int
442 printable(int ch) {
443         return (ch > 0x20 && ch < 0x7f);
444 }