kernel32: Added support for ctrl-home (aka clear from beginning of line) in line...
[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 #ifdef HAVE_RESOLV
21
22 #include <sys/types.h>
23
24 #ifdef HAVE_NETINET_IN_H
25 # include <netinet/in.h>
26 #endif
27 #ifdef HAVE_ARPA_NAMESER_H
28 # include <arpa/nameser.h>
29 #endif
30
31 #include <ctype.h>
32 #include <errno.h>
33 #ifdef HAVE_RESOLV_H
34 # include <resolv.h>
35 #endif
36 #include <string.h>
37
38 /* Data. */
39
40 static const char       digits[] = "0123456789";
41
42 /* Private. */
43
44 /*
45  * special(ch)
46  *      Thinking in noninternationalized USASCII (per the DNS spec),
47  *      is this character special ("in need of quoting") ?
48  * return:
49  *      boolean.
50  */
51 static int
52 special(int ch) {
53         switch (ch) {
54         case 0x22: /* '"' */
55         case 0x2E: /* '.' */
56         case 0x3B: /* ';' */
57         case 0x5C: /* '\\' */
58         /* Special modifiers in zone files. */
59         case 0x40: /* '@' */
60         case 0x24: /* '$' */
61                 return (1);
62         default:
63                 return (0);
64         }
65 }
66
67 /*
68  * printable(ch)
69  *      Thinking in noninternationalized USASCII (per the DNS spec),
70  *      is this character visible and not a space when printed ?
71  * return:
72  *      boolean.
73  */
74 static int
75 printable(int ch) {
76         return (ch > 0x20 && ch < 0x7f);
77 }
78
79 /* Public. */
80
81 /*
82  * dns_ns_name_ntop(src, dst, dstsiz)
83  *      Convert an encoded domain name to printable ascii as per RFC1035.
84  * return:
85  *      Number of bytes written to buffer, or -1 (with errno set)
86  * notes:
87  *      The root is returned as "."
88  *      All other domains are returned in non absolute form
89  */
90 static int
91 dns_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
92         const u_char *cp;
93         char *dn, *eom;
94         u_char c;
95         u_int n;
96
97         cp = src;
98         dn = dst;
99         eom = dst + dstsiz;
100
101         while ((n = *cp++) != 0) {
102                 if ((n & NS_CMPRSFLGS) != 0 && n != 0x41) {
103                         /* Some kind of compression pointer. */
104                         return (-1);
105                 }
106                 if (dn != dst) {
107                         if (dn >= eom) {
108                                 return (-1);
109                         }
110                         *dn++ = '.';
111                 }
112
113                 if (n == 0x41) {
114                         n = *cp++ / 8;
115                         if (dn + n * 2 + 4 >= eom) {
116                                 return (-1);
117                         }
118                         *dn++ = '\\';
119                         *dn++ = '[';
120                         *dn++ = 'x';
121
122                         while (n-- > 0) {
123                 unsigned u;
124                                 c = *cp++;
125                                 u = c >> 4;
126                                 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
127                                 u = c & 0xf;
128                                 *dn++ = u > 9 ? 'a' + u - 10 : '0' + u;
129                         }
130
131                         *dn++ = ']';
132                         continue;
133                 }
134
135                 if (dn + n >= eom) {
136                         return (-1);
137                 }
138                 while (n-- > 0) {
139                         c = *cp++;
140                         if (special(c)) {
141                                 if (dn + 1 >= eom) {
142                                         return (-1);
143                                 }
144                                 *dn++ = '\\';
145                                 *dn++ = (char)c;
146                         } else if (!printable(c)) {
147                                 if (dn + 3 >= eom) {
148                                         return (-1);
149                                 }
150                                 *dn++ = '\\';
151                                 *dn++ = digits[c / 100];
152                                 *dn++ = digits[(c % 100) / 10];
153                                 *dn++ = digits[c % 10];
154                         } else {
155                                 if (dn >= eom) {
156                                         return (-1);
157                                 }
158                                 *dn++ = (char)c;
159                         }
160                 }
161         }
162         if (dn == dst) {
163                 if (dn >= eom) {
164                         return (-1);
165                 }
166                 *dn++ = '.';
167         }
168         if (dn >= eom) {
169                 return (-1);
170         }
171         *dn++ = '\0';
172         return (dn - dst);
173 }
174
175
176 /*
177  * dns_ns_name_unpack(msg, eom, src, dst, dstsiz)
178  *      Unpack a domain name from a message, source may be compressed.
179  * return:
180  *      -1 if it fails, or consumed octets if it succeeds.
181  */
182 static int
183 dns_ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
184                u_char *dst, size_t dstsiz)
185 {
186         const u_char *srcp, *dstlim;
187         u_char *dstp;
188         int n, len, checked;
189
190         len = -1;
191         checked = 0;
192         dstp = dst;
193         srcp = src;
194         dstlim = dst + dstsiz;
195         if (srcp < msg || srcp >= eom) {
196                 return (-1);
197         }
198         /* Fetch next label in domain name. */
199         while ((n = *srcp++) != 0) {
200                 /* Check for indirection. */
201                 switch (n & NS_CMPRSFLGS) {
202                 case 0x40:
203                         if (n == 0x41) {
204                                 if (dstp + 1 >= dstlim) {
205                                         return (-1);
206                                 }
207                                 *dstp++ = 0x41;
208                                 n = *srcp++ / 8;
209                                 ++checked;
210                         } else {
211                                 return (-1);            /* flag error */
212                         }
213                         /* FALLTHROUGH */
214                 case 0:
215                         /* Limit checks. */
216                         if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
217                                 return (-1);
218                         }
219                         checked += n + 1;
220                         dstp = memcpy(dstp, srcp - 1, n + 1);
221                         dstp += n + 1;
222                         srcp += n;
223                         break;
224
225                 case NS_CMPRSFLGS:
226                         if (srcp >= eom) {
227                                 return (-1);
228                         }
229                         if (len < 0)
230                                 len = srcp - src + 1;
231                         srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
232                         if (srcp < msg || srcp >= eom) {  /* Out of range. */
233                                 return (-1);
234                         }
235                         checked += 2;
236                         /*
237                          * Check for loops in the compressed name;
238                          * if we've looked at the whole message,
239                          * there must be a loop.
240                          */
241                         if (checked >= eom - msg) {
242                                 return (-1);
243                         }
244                         break;
245
246                 default:
247                         return (-1);                    /* flag error */
248                 }
249         }
250         *dstp = '\0';
251         if (len < 0)
252                 len = srcp - src;
253         return (len);
254 }
255
256
257 /*
258  * dns_ns_name_uncompress(msg, eom, src, dst, dstsiz)
259  *      Expand compressed domain name to presentation format.
260  * return:
261  *      Number of bytes read out of `src', or -1 (with errno set).
262  * note:
263  *      Root domain returns as "." not "".
264  */
265 int
266 dns_ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
267                    char *dst, size_t dstsiz)
268 {
269         u_char tmp[NS_MAXCDNAME];
270         int n;
271
272         if ((n = dns_ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
273                 return (-1);
274         if (dns_ns_name_ntop(tmp, dst, dstsiz) == -1)
275                 return (-1);
276         return (n);
277 }
278
279
280 /*
281  * dns_ns_name_skip(ptrptr, eom)
282  *      Advance *ptrptr to skip over the compressed name it points at.
283  * return:
284  *      0 on success, -1 (with errno set) on failure.
285  */
286 int
287 dns_ns_name_skip(const u_char **ptrptr, const u_char *eom) {
288         const u_char *cp;
289         u_int n;
290
291         cp = *ptrptr;
292         while (cp < eom && (n = *cp++) != 0) {
293                 /* Check for indirection. */
294                 switch (n & NS_CMPRSFLGS) {
295                 case 0:                 /* normal case, n == len */
296                         cp += n;
297                         continue;
298                 case NS_CMPRSFLGS:      /* indirection */
299                         cp++;
300                         break;
301                 default:                /* illegal type */
302                         return (-1);
303                 }
304                 break;
305         }
306         if (cp > eom) {
307                 return (-1);
308         }
309         *ptrptr = cp;
310         return (0);
311 }
312
313 #endif  /* HAVE_RESOLV */