Formerly ../hurd/hurdpid.c.~9~
[kopensolaris-gnu/glibc.git] / resolv / res_comp.c
1 /*
2  * ++Copyright++ 1985
3  * -
4  * Copyright (c) 1985 Regents of the University of California.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  * -
35  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36  * 
37  * Permission to use, copy, modify, and distribute this software for any
38  * purpose with or without fee is hereby granted, provided that the above
39  * copyright notice and this permission notice appear in all copies, and that
40  * the name of Digital Equipment Corporation not be used in advertising or
41  * publicity pertaining to distribution of the document or software without
42  * specific, written prior permission.
43  * 
44  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51  * SOFTWARE.
52  * -
53  * --Copyright--
54  */
55
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)res_comp.c  6.22 (Berkeley) 3/19/91";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <arpa/nameser.h>
63 #include <netinet/in.h>
64 #include <resolv.h>
65 #include <stdio.h>
66 #include "../conf/portability.h"
67
68 static int dn_find();
69
70 /*
71  * Expand compressed domain name 'comp_dn' to full domain name.
72  * 'msg' is a pointer to the begining of the message,
73  * 'eomorig' points to the first location after the message,
74  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
75  * Return size of compressed name or -1 if there was an error.
76  */
77 dn_expand(msg, eomorig, comp_dn, exp_dn, length)
78         const u_char *msg, *eomorig, *comp_dn;
79         u_char *exp_dn;
80         int length;
81 {
82         register u_char *cp, *dn;
83         register int n, c;
84         u_char *eom;
85         int len = -1, checked = 0;
86
87         dn = exp_dn;
88         cp = (u_char *)comp_dn;
89         eom = exp_dn + length;
90         /*
91          * fetch next label in domain name
92          */
93         while (n = *cp++) {
94                 /*
95                  * Check for indirection
96                  */
97                 switch (n & INDIR_MASK) {
98                 case 0:
99                         if (dn != exp_dn) {
100                                 if (dn >= eom)
101                                         return (-1);
102                                 *dn++ = '.';
103                         }
104                         if (dn+n >= eom)
105                                 return (-1);
106                         checked += n + 1;
107                         while (--n >= 0) {
108                                 if ((c = *cp++) == '.') {
109                                         if (dn + n + 2 >= eom)
110                                                 return (-1);
111                                         *dn++ = '\\';
112                                 }
113                                 *dn++ = c;
114                                 if (cp >= eomorig)      /* out of range */
115                                         return(-1);
116                         }
117                         break;
118
119                 case INDIR_MASK:
120                         if (len < 0)
121                                 len = cp - comp_dn + 1;
122                         cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
123                         if (cp < msg || cp >= eomorig)  /* out of range */
124                                 return(-1);
125                         checked += 2;
126                         /*
127                          * Check for loops in the compressed name;
128                          * if we've looked at the whole message,
129                          * there must be a loop.
130                          */
131                         if (checked >= eomorig - msg)
132                                 return (-1);
133                         break;
134
135                 default:
136                         return (-1);                    /* flag error */
137                 }
138         }
139         *dn = '\0';
140         if (len < 0)
141                 len = cp - comp_dn;
142         return (len);
143 }
144
145 /*
146  * Compress domain name 'exp_dn' into 'comp_dn'.
147  * Return the size of the compressed name or -1.
148  * 'length' is the size of the array pointed to by 'comp_dn'.
149  * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
150  * is a pointer to the beginning of the message. The list ends with NULL.
151  * 'lastdnptr' is a pointer to the end of the arrary pointed to
152  * by 'dnptrs'. Side effect is to update the list of pointers for
153  * labels inserted into the message as we compress the name.
154  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
155  * is NULL, we don't update the list.
156  */
157 dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
158         const u_char *exp_dn;
159         u_char *comp_dn, **dnptrs, **lastdnptr;
160         int length;
161 {
162         register u_char *cp, *dn;
163         register int c, l;
164         u_char **cpp, **lpp, *sp, *eob;
165         u_char *msg;
166
167         dn = (u_char *)exp_dn;
168         cp = comp_dn;
169         eob = cp + length;
170         if (dnptrs != NULL) {
171                 if ((msg = *dnptrs++) != NULL) {
172                         for (cpp = dnptrs; *cpp != NULL; cpp++)
173                                 ;
174                         lpp = cpp;      /* end of list to search */
175                 }
176         } else
177                 msg = NULL;
178         for (c = *dn++; c != '\0'; ) {
179                 /* look to see if we can use pointers */
180                 if (msg != NULL) {
181                         if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
182                                 if (cp+1 >= eob)
183                                         return (-1);
184                                 *cp++ = (l >> 8) | INDIR_MASK;
185                                 *cp++ = l % 256;
186                                 return (cp - comp_dn);
187                         }
188                         /* not found, save it */
189                         if (lastdnptr != NULL && cpp < lastdnptr-1) {
190                                 *cpp++ = cp;
191                                 *cpp = NULL;
192                         }
193                 }
194                 sp = cp++;      /* save ptr to length byte */
195                 do {
196                         if (c == '.') {
197                                 c = *dn++;
198                                 break;
199                         }
200                         if (c == '\\') {
201                                 if ((c = *dn++) == '\0')
202                                         break;
203                         }
204                         if (cp >= eob) {
205                                 if (msg != NULL)
206                                         *lpp = NULL;
207                                 return (-1);
208                         }
209                         *cp++ = c;
210                 } while ((c = *dn++) != '\0');
211                 /* catch trailing '.'s but not '..' */
212                 if ((l = cp - sp - 1) == 0 && c == '\0') {
213                         cp--;
214                         break;
215                 }
216                 if (l <= 0 || l > MAXLABEL) {
217                         if (msg != NULL)
218                                 *lpp = NULL;
219                         return (-1);
220                 }
221                 *sp = l;
222         }
223         if (cp >= eob) {
224                 if (msg != NULL)
225                         *lpp = NULL;
226                 return (-1);
227         }
228         *cp++ = '\0';
229         return (cp - comp_dn);
230 }
231
232 /*
233  * Skip over a compressed domain name. Return the size or -1.
234  */
235 __dn_skipname(comp_dn, eom)
236         const u_char *comp_dn, *eom;
237 {
238         register u_char *cp;
239         register int n;
240
241         cp = (u_char *)comp_dn;
242         while (cp < eom && (n = *cp++)) {
243                 /*
244                  * check for indirection
245                  */
246                 switch (n & INDIR_MASK) {
247                 case 0:         /* normal case, n == len */
248                         cp += n;
249                         continue;
250                 default:        /* illegal type */
251                         return (-1);
252                 case INDIR_MASK:        /* indirection */
253                         cp++;
254                 }
255                 break;
256         }
257         return (cp - comp_dn);
258 }
259
260 /*
261  * Search for expanded name from a list of previously compressed names.
262  * Return the offset from msg if found or -1.
263  * dnptrs is the pointer to the first name on the list,
264  * not the pointer to the start of the message.
265  */
266 static int
267 dn_find(exp_dn, msg, dnptrs, lastdnptr)
268         u_char *exp_dn, *msg;
269         u_char **dnptrs, **lastdnptr;
270 {
271         register u_char *dn, *cp, **cpp;
272         register int n;
273         u_char *sp;
274
275         for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
276                 dn = exp_dn;
277                 sp = cp = *cpp;
278                 while (n = *cp++) {
279                         /*
280                          * check for indirection
281                          */
282                         switch (n & INDIR_MASK) {
283                         case 0:         /* normal case, n == len */
284                                 while (--n >= 0) {
285                                         if (*dn == '.')
286                                                 goto next;
287                                         if (*dn == '\\')
288                                                 dn++;
289                                         if (*dn++ != *cp++)
290                                                 goto next;
291                                 }
292                                 if ((n = *dn++) == '\0' && *cp == '\0')
293                                         return (sp - msg);
294                                 if (n == '.')
295                                         continue;
296                                 goto next;
297
298                         default:        /* illegal type */
299                                 return (-1);
300
301                         case INDIR_MASK:        /* indirection */
302                                 cp = msg + (((n & 0x3f) << 8) | *cp);
303                         }
304                 }
305                 if (*dn == '\0')
306                         return (sp - msg);
307         next:   ;
308         }
309         return (-1);
310 }
311
312 /*
313  * Routines to insert/extract short/long's. Must account for byte
314  * order and non-alignment problems. This code at least has the
315  * advantage of being portable.
316  *
317  * used by sendmail.
318  */
319
320 u_short
321 _getshort(msgp)
322         register u_char *msgp;
323 {
324         register u_short u;
325
326         GETSHORT(u, msgp);
327         return u;
328 }
329
330 u_int32_t
331 _getlong(msgp)
332         register u_char *msgp;
333 {
334         register u_int32_t u;
335
336         GETLONG(u, msgp);
337         return u;
338 }
339
340 void
341 #if defined(__STDC__) || defined(__cplusplus)
342 __putshort(register u_short s, register u_char *msgp)
343 #else
344 __putshort(s, msgp)
345         register u_short s;
346         register u_char *msgp;
347 #endif
348 {
349         PUTSHORT(s, msgp);
350 }
351
352 void
353 __putlong(l, msgp)
354         register u_int32_t l;
355         register u_char *msgp;
356 {
357         PUTLONG(l, msgp);
358 }