Include <signal.h> in sysdeps/nptl/allocrtsig.c
[platform/upstream/glibc.git] / resolv / ns_name.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1996,1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #if !defined(_LIBC) && !defined(lint)
19 static const char rcsid[] = "$BINDId: ns_name.c,v 8.15 2000/03/30 22:53:46 vixie Exp $";
20 #endif
21
22 #include <sys/types.h>
23
24 #include <netinet/in.h>
25 #include <arpa/nameser.h>
26
27 #include <errno.h>
28 #include <resolv.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <limits.h>
33
34 # define SPRINTF(x) ((size_t)sprintf x)
35
36 #define NS_TYPE_ELT                     0x40 /*%< EDNS0 extended label type */
37 #define DNS_LABELTYPE_BITSTRING         0x41
38
39 /* Data. */
40
41 static const char       digits[] = "0123456789";
42
43 static const char digitvalue[256] = {
44         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
45         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
46         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
47          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
48         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
49         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
50         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
51         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
52         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
55         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
56         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
57         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
58         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
59         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
60 };
61
62 /* Forward. */
63
64 static int              special(int);
65 static int              printable(int);
66 static int              dn_find(const u_char *, const u_char *,
67                                 const u_char * const *,
68                                 const u_char * const *);
69 static int              encode_bitstring(const char **, const char *,
70                                          unsigned char **, unsigned char **,
71                                          unsigned const char *);
72 static int              labellen(const u_char *);
73 static int              decode_bitstring(const unsigned char **,
74                                          char *, const char *);
75
76 /* Public. */
77
78 /*%
79  *      Convert an encoded domain name to printable ascii as per RFC1035.
80
81  * return:
82  *\li   Number of bytes written to buffer, or -1 (with errno set)
83  *
84  * notes:
85  *\li   The root is returned as "."
86  *\li   All other domains are returned in non absolute form
87  */
88 int
89 ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
90 {
91         const u_char *cp;
92         char *dn, *eom;
93         u_char c;
94         u_int n;
95         int l;
96
97         cp = src;
98         dn = dst;
99         eom = dst + dstsiz;
100
101         while ((n = *cp++) != 0) {
102                 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
103                         /* Some kind of compression pointer. */
104                         __set_errno (EMSGSIZE);
105                         return (-1);
106                 }
107                 if (dn != dst) {
108                         if (dn >= eom) {
109                                 __set_errno (EMSGSIZE);
110                                 return (-1);
111                         }
112                         *dn++ = '.';
113                 }
114                 if ((l = labellen(cp - 1)) < 0) {
115                         __set_errno (EMSGSIZE);
116                         return(-1);
117                 }
118                 if (dn + l >= eom) {
119                         __set_errno (EMSGSIZE);
120                         return (-1);
121                 }
122                 if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
123                         int m;
124
125                         if (n != DNS_LABELTYPE_BITSTRING) {
126                                 /* XXX: labellen should reject this case */
127                                 __set_errno (EINVAL);
128                                 return(-1);
129                         }
130                         if ((m = decode_bitstring(&cp, dn, eom)) < 0)
131                         {
132                                 __set_errno (EMSGSIZE);
133                                 return(-1);
134                         }
135                         dn += m;
136                         continue;
137                 }
138                 for ((void)NULL; l > 0; l--) {
139                         c = *cp++;
140                         if (special(c)) {
141                                 if (dn + 1 >= eom) {
142                                         __set_errno (EMSGSIZE);
143                                         return (-1);
144                                 }
145                                 *dn++ = '\\';
146                                 *dn++ = (char)c;
147                         } else if (!printable(c)) {
148                                 if (dn + 3 >= eom) {
149                                         __set_errno (EMSGSIZE);
150                                         return (-1);
151                                 }
152                                 *dn++ = '\\';
153                                 *dn++ = digits[c / 100];
154                                 *dn++ = digits[(c % 100) / 10];
155                                 *dn++ = digits[c % 10];
156                         } else {
157                                 if (dn >= eom) {
158                                         __set_errno (EMSGSIZE);
159                                         return (-1);
160                                 }
161                                 *dn++ = (char)c;
162                         }
163                 }
164         }
165         if (dn == dst) {
166                 if (dn >= eom) {
167                         __set_errno (EMSGSIZE);
168                         return (-1);
169                 }
170                 *dn++ = '.';
171         }
172         if (dn >= eom) {
173                 __set_errno (EMSGSIZE);
174                 return (-1);
175         }
176         *dn++ = '\0';
177         return (dn - dst);
178 }
179 libresolv_hidden_def (ns_name_ntop)
180 strong_alias (ns_name_ntop, __ns_name_ntop)
181
182 /*%
183  *      Convert an ascii string into an encoded domain name as per RFC1035.
184  *
185  * return:
186  *
187  *\li   -1 if it fails
188  *\li   1 if string was fully qualified
189  *\li   0 is string was not fully qualified
190  *
191  * notes:
192  *\li   Enforces label and domain length limits.
193  */
194
195 int
196 ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
197 {
198         u_char *label, *bp, *eom;
199         int c, n, escaped, e = 0;
200         char *cp;
201
202         escaped = 0;
203         bp = dst;
204         eom = dst + dstsiz;
205         label = bp++;
206
207         while ((c = *src++) != 0) {
208                 if (escaped) {
209                         if (c == '[') { /*%< start a bit string label */
210                                 if ((cp = strchr(src, ']')) == NULL) {
211                                         __set_errno (EINVAL);
212                                         return(-1);
213                                 }
214                                 if ((e = encode_bitstring(&src, cp + 2,
215                                                           &label, &bp, eom))
216                                     != 0) {
217                                         __set_errno (e);
218                                         return(-1);
219                                 }
220                                 escaped = 0;
221                                 label = bp++;
222                                 if ((c = *src++) == 0)
223                                         goto done;
224                                 else if (c != '.') {
225                                         __set_errno (EINVAL);
226                                         return(-1);
227                                 }
228                                 continue;
229                         }
230                         else if ((cp = strchr(digits, c)) != NULL) {
231                                 n = (cp - digits) * 100;
232                                 if ((c = *src++) == 0 ||
233                                     (cp = strchr(digits, c)) == NULL) {
234                                         __set_errno (EMSGSIZE);
235                                         return (-1);
236                                 }
237                                 n += (cp - digits) * 10;
238                                 if ((c = *src++) == 0 ||
239                                     (cp = strchr(digits, c)) == NULL) {
240                                         __set_errno (EMSGSIZE);
241                                         return (-1);
242                                 }
243                                 n += (cp - digits);
244                                 if (n > 255) {
245                                         __set_errno (EMSGSIZE);
246                                         return (-1);
247                                 }
248                                 c = n;
249                         }
250                         escaped = 0;
251                 } else if (c == '\\') {
252                         escaped = 1;
253                         continue;
254                 } else if (c == '.') {
255                         c = (bp - label - 1);
256                         if ((c & NS_CMPRSFLGS) != 0) {  /*%< Label too big. */
257                                 __set_errno (EMSGSIZE);
258                                 return (-1);
259                         }
260                         if (label >= eom) {
261                                 __set_errno (EMSGSIZE);
262                                 return (-1);
263                         }
264                         *label = c;
265                         /* Fully qualified ? */
266                         if (*src == '\0') {
267                                 if (c != 0) {
268                                         if (bp >= eom) {
269                                                 __set_errno (EMSGSIZE);
270                                                 return (-1);
271                                         }
272                                         *bp++ = '\0';
273                                 }
274                                 if ((bp - dst) > MAXCDNAME) {
275                                         __set_errno (EMSGSIZE);
276                                         return (-1);
277                                 }
278                                 return (1);
279                         }
280                         if (c == 0 || *src == '.') {
281                                 __set_errno (EMSGSIZE);
282                                 return (-1);
283                         }
284                         label = bp++;
285                         continue;
286                 }
287                 if (bp >= eom) {
288                         __set_errno (EMSGSIZE);
289                         return (-1);
290                 }
291                 *bp++ = (u_char)c;
292         }
293         c = (bp - label - 1);
294         if ((c & NS_CMPRSFLGS) != 0) {          /*%< Label too big. */
295                 __set_errno (EMSGSIZE);
296                 return (-1);
297         }
298   done:
299         if (label >= eom) {
300                 __set_errno (EMSGSIZE);
301                 return (-1);
302         }
303         *label = c;
304         if (c != 0) {
305                 if (bp >= eom) {
306                         __set_errno (EMSGSIZE);
307                         return (-1);
308                 }
309                 *bp++ = 0;
310         }
311         if ((bp - dst) > MAXCDNAME) {   /*%< src too big */
312                 __set_errno (EMSGSIZE);
313                 return (-1);
314         }
315         return (0);
316 }
317 libresolv_hidden_def (ns_name_pton)
318
319 /*%
320  *      Convert a network strings labels into all lowercase.
321  *
322  * return:
323  *\li   Number of bytes written to buffer, or -1 (with errno set)
324  *
325  * notes:
326  *\li   Enforces label and domain length limits.
327  */
328
329 int
330 ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
331 {
332         const u_char *cp;
333         u_char *dn, *eom;
334         u_char c;
335         u_int n;
336         int l;
337
338         cp = src;
339         dn = dst;
340         eom = dst + dstsiz;
341
342         if (dn >= eom) {
343                 __set_errno (EMSGSIZE);
344                 return (-1);
345         }
346         while ((n = *cp++) != 0) {
347                 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
348                         /* Some kind of compression pointer. */
349                         __set_errno (EMSGSIZE);
350                         return (-1);
351                 }
352                 *dn++ = n;
353                 if ((l = labellen(cp - 1)) < 0) {
354                         __set_errno (EMSGSIZE);
355                         return (-1);
356                 }
357                 if (dn + l >= eom) {
358                         __set_errno (EMSGSIZE);
359                         return (-1);
360                 }
361                 for ((void)NULL; l > 0; l--) {
362                         c = *cp++;
363                         if (isupper(c))
364                                 *dn++ = tolower(c);
365                         else
366                                 *dn++ = c;
367                 }
368         }
369         *dn++ = '\0';
370         return (dn - dst);
371 }
372
373 /*%
374  *      Unpack a domain name from a message, source may be compressed.
375  *
376  * return:
377  *\li   -1 if it fails, or consumed octets if it succeeds.
378  */
379 int
380 ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
381                u_char *dst, size_t dstsiz)
382 {
383         const u_char *srcp, *dstlim;
384         u_char *dstp;
385         int n, len, checked, l;
386
387         len = -1;
388         checked = 0;
389         dstp = dst;
390         srcp = src;
391         dstlim = dst + dstsiz;
392         if (srcp < msg || srcp >= eom) {
393                 __set_errno (EMSGSIZE);
394                 return (-1);
395         }
396         /* Fetch next label in domain name. */
397         while ((n = *srcp++) != 0) {
398                 /* Check for indirection. */
399                 switch (n & NS_CMPRSFLGS) {
400                 case 0:
401                 case NS_TYPE_ELT:
402                         /* Limit checks. */
403                         if ((l = labellen(srcp - 1)) < 0) {
404                                 __set_errno (EMSGSIZE);
405                                 return(-1);
406                         }
407                         if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
408                                 __set_errno (EMSGSIZE);
409                                 return (-1);
410                         }
411                         checked += l + 1;
412                         *dstp++ = n;
413                         memcpy(dstp, srcp, l);
414                         dstp += l;
415                         srcp += l;
416                         break;
417
418                 case NS_CMPRSFLGS:
419                         if (srcp >= eom) {
420                                 __set_errno (EMSGSIZE);
421                                 return (-1);
422                         }
423                         if (len < 0)
424                                 len = srcp - src + 1;
425                         srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
426                         if (srcp < msg || srcp >= eom) {  /*%< Out of range. */
427                                 __set_errno (EMSGSIZE);
428                                 return (-1);
429                         }
430                         checked += 2;
431                         /*
432                          * Check for loops in the compressed name;
433                          * if we've looked at the whole message,
434                          * there must be a loop.
435                          */
436                         if (checked >= eom - msg) {
437                                 __set_errno (EMSGSIZE);
438                                 return (-1);
439                         }
440                         break;
441
442                 default:
443                         __set_errno (EMSGSIZE);
444                         return (-1);                    /*%< flag error */
445                 }
446         }
447         *dstp = '\0';
448         if (len < 0)
449                 len = srcp - src;
450         return (len);
451 }
452 libresolv_hidden_def (ns_name_unpack)
453 strong_alias (ns_name_unpack, __ns_name_unpack)
454
455 /*%
456  *      Pack domain name 'domain' into 'comp_dn'.
457  *
458  * return:
459  *\li   Size of the compressed name, or -1.
460  *
461  * notes:
462  *\li   'dnptrs' is an array of pointers to previous compressed names.
463  *\li   dnptrs[0] is a pointer to the beginning of the message. The array
464  *      ends with NULL.
465  *\li   'lastdnptr' is a pointer to the end of the array pointed to
466  *      by 'dnptrs'.
467  *
468  * Side effects:
469  *\li   The list of pointers in dnptrs is updated for labels inserted into
470  *      the message as we compress the name.  If 'dnptr' is NULL, we don't
471  *      try to compress names. If 'lastdnptr' is NULL, we don't update the
472  *      list.
473  */
474 int
475 ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
476              const u_char **dnptrs, const u_char **lastdnptr)
477 {
478         u_char *dstp;
479         const u_char **cpp, **lpp, *eob, *msg;
480         const u_char *srcp;
481         int n, l, first = 1;
482
483         srcp = src;
484         dstp = dst;
485         eob = dstp + dstsiz;
486         lpp = cpp = NULL;
487         if (dnptrs != NULL) {
488                 if ((msg = *dnptrs++) != NULL) {
489                         for (cpp = dnptrs; *cpp != NULL; cpp++)
490                                 (void)NULL;
491                         lpp = cpp;      /*%< end of list to search */
492                 }
493         } else
494                 msg = NULL;
495
496         /* make sure the domain we are about to add is legal */
497         l = 0;
498         do {
499                 int l0;
500
501                 n = *srcp;
502                 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
503                         __set_errno (EMSGSIZE);
504                         return (-1);
505                 }
506                 if ((l0 = labellen(srcp)) < 0) {
507                         __set_errno (EINVAL);
508                         return(-1);
509                 }
510                 l += l0 + 1;
511                 if (l > MAXCDNAME) {
512                         __set_errno (EMSGSIZE);
513                         return (-1);
514                 }
515                 srcp += l0 + 1;
516         } while (n != 0);
517
518         /* from here on we need to reset compression pointer array on error */
519         srcp = src;
520         do {
521                 /* Look to see if we can use pointers. */
522                 n = *srcp;
523                 if (n != 0 && msg != NULL) {
524                         l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
525                                     (const u_char * const *)lpp);
526                         if (l >= 0) {
527                                 if (dstp + 1 >= eob) {
528                                         goto cleanup;
529                                 }
530                                 *dstp++ = (l >> 8) | NS_CMPRSFLGS;
531                                 *dstp++ = l % 256;
532                                 return (dstp - dst);
533                         }
534                         /* Not found, save it. */
535                         if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
536                             (dstp - msg) < 0x4000 && first) {
537                                 *cpp++ = dstp;
538                                 *cpp = NULL;
539                                 first = 0;
540                         }
541                 }
542                 /* copy label to buffer */
543                 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
544                         /* Should not happen. */
545                         goto cleanup;
546                 }
547                 n = labellen(srcp);
548                 if (dstp + 1 + n >= eob) {
549                         goto cleanup;
550                 }
551                 memcpy(dstp, srcp, n + 1);
552                 srcp += n + 1;
553                 dstp += n + 1;
554         } while (n != 0);
555
556         if (dstp > eob) {
557 cleanup:
558                 if (msg != NULL)
559                         *lpp = NULL;
560                 __set_errno (EMSGSIZE);
561                 return (-1);
562         }
563         return (dstp - dst);
564 }
565 libresolv_hidden_def (ns_name_pack)
566
567 /*%
568  *      Expand compressed domain name to presentation format.
569  *
570  * return:
571  *\li   Number of bytes read out of `src', or -1 (with errno set).
572  *
573  * note:
574  *\li   Root domain returns as "." not "".
575  */
576 int
577 ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
578                    char *dst, size_t dstsiz)
579 {
580         u_char tmp[NS_MAXCDNAME];
581         int n;
582
583         if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
584                 return (-1);
585         if (ns_name_ntop(tmp, dst, dstsiz) == -1)
586                 return (-1);
587         return (n);
588 }
589 libresolv_hidden_def (ns_name_uncompress)
590
591 /*%
592  *      Compress a domain name into wire format, using compression pointers.
593  *
594  * return:
595  *\li   Number of bytes consumed in `dst' or -1 (with errno set).
596  *
597  * notes:
598  *\li   'dnptrs' is an array of pointers to previous compressed names.
599  *\li   dnptrs[0] is a pointer to the beginning of the message.
600  *\li   The list ends with NULL.  'lastdnptr' is a pointer to the end of the
601  *      array pointed to by 'dnptrs'. Side effect is to update the list of
602  *      pointers for labels inserted into the message as we compress the name.
603  *\li   If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
604  *      is NULL, we don't update the list.
605  */
606 int
607 ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
608                  const u_char **dnptrs, const u_char **lastdnptr)
609 {
610         u_char tmp[NS_MAXCDNAME];
611
612         if (ns_name_pton(src, tmp, sizeof tmp) == -1)
613                 return (-1);
614         return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
615 }
616 libresolv_hidden_def (ns_name_compress)
617
618 /*%
619  * Reset dnptrs so that there are no active references to pointers at or
620  * after src.
621  */
622 void
623 ns_name_rollback(const u_char *src, const u_char **dnptrs,
624                  const u_char **lastdnptr)
625 {
626         while (dnptrs < lastdnptr && *dnptrs != NULL) {
627                 if (*dnptrs >= src) {
628                         *dnptrs = NULL;
629                         break;
630                 }
631                 dnptrs++;
632         }
633 }
634
635 /*%
636  *      Advance *ptrptr to skip over the compressed name it points at.
637  *
638  * return:
639  *\li   0 on success, -1 (with errno set) on failure.
640  */
641 int
642 ns_name_skip(const u_char **ptrptr, const u_char *eom)
643 {
644         const u_char *cp;
645         u_int n;
646         int l;
647
648         cp = *ptrptr;
649         while (cp < eom && (n = *cp++) != 0) {
650                 /* Check for indirection. */
651                 switch (n & NS_CMPRSFLGS) {
652                 case 0:                 /*%< normal case, n == len */
653                         cp += n;
654                         continue;
655                 case NS_TYPE_ELT: /*%< EDNS0 extended label */
656                         if ((l = labellen(cp - 1)) < 0) {
657                                 __set_errno (EMSGSIZE);
658                                 return(-1);
659                         }
660                         cp += l;
661                         continue;
662                 case NS_CMPRSFLGS:      /*%< indirection */
663                         cp++;
664                         break;
665                 default:                /*%< illegal type */
666                         __set_errno (EMSGSIZE);
667                         return (-1);
668                 }
669                 break;
670         }
671         if (cp > eom) {
672                 __set_errno (EMSGSIZE);
673                 return (-1);
674         }
675         *ptrptr = cp;
676         return (0);
677 }
678 libresolv_hidden_def (ns_name_skip)
679
680 /* Private. */
681
682 /*%
683  *      Thinking in noninternationalized USASCII (per the DNS spec),
684  *      is this character special ("in need of quoting") ?
685  *
686  * return:
687  *\li   boolean.
688  */
689 static int
690 special(int ch) {
691         switch (ch) {
692         case 0x22: /*%< '"' */
693         case 0x2E: /*%< '.' */
694         case 0x3B: /*%< ';' */
695         case 0x5C: /*%< '\\' */
696         case 0x28: /*%< '(' */
697         case 0x29: /*%< ')' */
698         /* Special modifiers in zone files. */
699         case 0x40: /*%< '@' */
700         case 0x24: /*%< '$' */
701                 return (1);
702         default:
703                 return (0);
704         }
705 }
706
707 /*%
708  *      Thinking in noninternationalized USASCII (per the DNS spec),
709  *      is this character visible and not a space when printed ?
710  *
711  * return:
712  *\li   boolean.
713  */
714 static int
715 printable(int ch) {
716         return (ch > 0x20 && ch < 0x7f);
717 }
718
719 /*%
720  *      Thinking in noninternationalized USASCII (per the DNS spec),
721  *      convert this character to lower case if it's upper case.
722  */
723 static int
724 mklower(int ch) {
725         if (ch >= 0x41 && ch <= 0x5A)
726                 return (ch + 0x20);
727         return (ch);
728 }
729
730 /*%
731  *      Search for the counted-label name in an array of compressed names.
732  *
733  * return:
734  *\li   offset from msg if found, or -1.
735  *
736  * notes:
737  *\li   dnptrs is the pointer to the first name on the list,
738  *\li   not the pointer to the start of the message.
739  */
740 static int
741 dn_find(const u_char *domain, const u_char *msg,
742         const u_char * const *dnptrs,
743         const u_char * const *lastdnptr)
744 {
745         const u_char *dn, *cp, *sp;
746         const u_char * const *cpp;
747         u_int n;
748
749         for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
750                 sp = *cpp;
751                 /*
752                  * terminate search on:
753                  * root label
754                  * compression pointer
755                  * unusable offset
756                  */
757                 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
758                        (sp - msg) < 0x4000) {
759                         dn = domain;
760                         cp = sp;
761                         while ((n = *cp++) != 0) {
762                                 /*
763                                  * check for indirection
764                                  */
765                                 switch (n & NS_CMPRSFLGS) {
766                                 case 0:         /*%< normal case, n == len */
767                                         n = labellen(cp - 1); /*%< XXX */
768                                         if (n != *dn++)
769                                                 goto next;
770
771                                         for ((void)NULL; n > 0; n--)
772                                                 if (mklower(*dn++) !=
773                                                     mklower(*cp++))
774                                                         goto next;
775                                         /* Is next root for both ? */
776                                         if (*dn == '\0' && *cp == '\0')
777                                                 return (sp - msg);
778                                         if (*dn)
779                                                 continue;
780                                         goto next;
781                                 case NS_CMPRSFLGS:      /*%< indirection */
782                                         cp = msg + (((n & 0x3f) << 8) | *cp);
783                                         break;
784
785                                 default:        /*%< illegal type */
786                                         __set_errno (EMSGSIZE);
787                                         return (-1);
788                                 }
789                         }
790   next: ;
791                         sp += *sp + 1;
792                 }
793         }
794         __set_errno (ENOENT);
795         return (-1);
796 }
797
798 static int
799 decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
800 {
801         const unsigned char *cp = *cpp;
802         char *beg = dn, tc;
803         int b, blen, plen, i;
804
805         if ((blen = (*cp & 0xff)) == 0)
806                 blen = 256;
807         plen = (blen + 3) / 4;
808         plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
809         if (dn + plen >= eom)
810                 return(-1);
811
812         cp++;
813         i = SPRINTF((dn, "\\[x"));
814         if (i < 0)
815                 return (-1);
816         dn += i;
817         for (b = blen; b > 7; b -= 8, cp++) {
818                 i = SPRINTF((dn, "%02x", *cp & 0xff));
819                 if (i < 0)
820                         return (-1);
821                 dn += i;
822         }
823         if (b > 4) {
824                 tc = *cp++;
825                 i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
826                 if (i < 0)
827                         return (-1);
828                 dn += i;
829         } else if (b > 0) {
830                 tc = *cp++;
831                 i = SPRINTF((dn, "%1x",
832                                ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
833                 if (i < 0)
834                         return (-1);
835                 dn += i;
836         }
837         i = SPRINTF((dn, "/%d]", blen));
838         if (i < 0)
839                 return (-1);
840         dn += i;
841
842         *cpp = cp;
843         return(dn - beg);
844 }
845
846 static int
847 encode_bitstring(const char **bp, const char *end, unsigned char **labelp,
848                  unsigned char ** dst, unsigned const char *eom)
849 {
850         int afterslash = 0;
851         const char *cp = *bp;
852         unsigned char *tp;
853         char c;
854         const char *beg_blen;
855         char *end_blen = NULL;
856         int value = 0, count = 0, tbcount = 0, blen = 0;
857
858         beg_blen = end_blen = NULL;
859
860         /* a bitstring must contain at least 2 characters */
861         if (end - cp < 2)
862                 return(EINVAL);
863
864         /* XXX: currently, only hex strings are supported */
865         if (*cp++ != 'x')
866                 return(EINVAL);
867         if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
868                 return(EINVAL);
869
870         for (tp = *dst + 1; cp < end && tp < eom; cp++) {
871                 switch((c = *cp)) {
872                 case ']':       /*%< end of the bitstring */
873                         if (afterslash) {
874                                 if (beg_blen == NULL)
875                                         return(EINVAL);
876                                 blen = (int)strtol(beg_blen, &end_blen, 10);
877                                 if (*end_blen != ']')
878                                         return(EINVAL);
879                         }
880                         if (count)
881                                 *tp++ = ((value << 4) & 0xff);
882                         cp++;   /*%< skip ']' */
883                         goto done;
884                 case '/':
885                         afterslash = 1;
886                         break;
887                 default:
888                         if (afterslash) {
889                                 if (!isdigit(c&0xff))
890                                         return(EINVAL);
891                                 if (beg_blen == NULL) {
892
893                                         if (c == '0') {
894                                                 /* blen never begings with 0 */
895                                                 return(EINVAL);
896                                         }
897                                         beg_blen = cp;
898                                 }
899                         } else {
900                                 if (!isxdigit(c&0xff))
901                                         return(EINVAL);
902                                 value <<= 4;
903                                 value += digitvalue[(int)c];
904                                 count += 4;
905                                 tbcount += 4;
906                                 if (tbcount > 256)
907                                         return(EINVAL);
908                                 if (count == 8) {
909                                         *tp++ = value;
910                                         count = 0;
911                                 }
912                         }
913                         break;
914                 }
915         }
916   done:
917         if (cp >= end || tp >= eom)
918                 return(EMSGSIZE);
919
920         /*
921          * bit length validation:
922          * If a <length> is present, the number of digits in the <bit-data>
923          * MUST be just sufficient to contain the number of bits specified
924          * by the <length>. If there are insignificant bits in a final
925          * hexadecimal or octal digit, they MUST be zero.
926          * RFC2673, Section 3.2.
927          */
928         if (blen > 0) {
929                 int traillen;
930
931                 if (((blen + 3) & ~3) != tbcount)
932                         return(EINVAL);
933                 traillen = tbcount - blen; /*%< between 0 and 3 */
934                 if (((value << (8 - traillen)) & 0xff) != 0)
935                         return(EINVAL);
936         }
937         else
938                 blen = tbcount;
939         if (blen == 256)
940                 blen = 0;
941
942         /* encode the type and the significant bit fields */
943         **labelp = DNS_LABELTYPE_BITSTRING;
944         **dst = blen;
945
946         *bp = cp;
947         *dst = tp;
948
949         return(0);
950 }
951
952 static int
953 labellen(const u_char *lp)
954 {
955         int bitlen;
956         u_char l = *lp;
957
958         if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
959                 /* should be avoided by the caller */
960                 return(-1);
961         }
962
963         if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
964                 if (l == DNS_LABELTYPE_BITSTRING) {
965                         if ((bitlen = *(lp + 1)) == 0)
966                                 bitlen = 256;
967                         return((bitlen + 7 ) / 8 + 1);
968                 }
969                 return(-1);     /*%< unknwon ELT */
970         }
971         return(l);
972 }
973
974 /*! \file */