res_comp.c revision 1219:f89f56c2d9ac
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41#pragma ident	"%Z%%M%	%I%	%E% SMI"
42
43#include "c_synonyms.h"
44#include <sys/types.h>
45#include <stdio.h>
46#include <arpa/nameser.h>
47
48static int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs,
49	u_char **lastdnptr);
50
51
52/*
53 * Expand compressed domain name 'comp_dn' to full domain name.
54 * 'msg' is a pointer to the begining of the message,
55 * 'eomorig' points to the first location after the message,
56 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
57 * Return size of compressed name or -1 if there was an error.
58 */
59int
60dn_expand(msg, eomorig, comp_dn, exp_dn, length)
61	u_char *msg, *eomorig, *comp_dn, *exp_dn;
62	int length;
63{
64	register u_char *cp, *dn;
65	register int n, c;
66	u_char *eom;
67	int len = -1, checked = 0;
68
69	dn = exp_dn;
70	cp = comp_dn;
71	eom = exp_dn + length;
72	/*
73	 * fetch next label in domain name
74	 */
75	while (n = *cp++) {
76		/*
77		 * Check for indirection
78		 */
79		switch (n & INDIR_MASK) {
80		case 0:
81			if (dn != exp_dn) {
82				if (dn >= eom)
83					return (-1);
84				*dn++ = '.';
85			}
86			if (dn+n >= eom)
87				return (-1);
88			checked += n + 1;
89			while (--n >= 0) {
90				if ((c = *cp++) == '.') {
91					if (dn + n + 2 >= eom)
92						return (-1);
93					*dn++ = '\\';
94				}
95				*dn++ = c;
96				if (cp >= eomorig)	/* out of range */
97					return (-1);
98			}
99			break;
100
101		case INDIR_MASK:
102			if (len < 0)
103				len = cp - comp_dn + 1;
104			cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
105			if (cp < msg || cp >= eomorig)	/* out of range */
106				return (-1);
107			checked += 2;
108			/*
109			 * Check for loops in the compressed name;
110			 * if we've looked at the whole message,
111			 * there must be a loop.
112			 */
113			if (checked >= eomorig - msg)
114				return (-1);
115			break;
116
117		default:
118			return (-1);			/* flag error */
119		}
120	}
121	*dn = '\0';
122	if (len < 0)
123		len = cp - comp_dn;
124	return (len);
125}
126
127/*
128 * Compress domain name 'exp_dn' into 'comp_dn'.
129 * Return the size of the compressed name or -1.
130 * 'length' is the size of the array pointed to by 'comp_dn'.
131 * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
132 * is a pointer to the beginning of the message. The list ends with NULL.
133 * 'lastdnptr' is a pointer to the end of the arrary pointed to
134 * by 'dnptrs'. Side effect is to update the list of pointers for
135 * labels inserted into the message as we compress the name.
136 * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
137 * is NULL, we don't update the list.
138 */
139int
140dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
141	u_char *exp_dn, *comp_dn;
142	int length;
143	u_char **dnptrs, **lastdnptr;
144{
145	register u_char *cp, *dn;
146	register int c, l;
147	u_char **cpp, **lpp, *sp, *eob;
148	u_char *msg;
149
150	dn = exp_dn;
151	cp = comp_dn;
152	eob = cp + length;
153	if (dnptrs != NULL) {
154		if ((msg = *dnptrs++) != NULL) {
155			for (cpp = dnptrs; *cpp != NULL; cpp++)
156				;
157			lpp = cpp;	/* end of list to search */
158		}
159	} else
160		msg = NULL;
161	for (c = *dn++; c != '\0'; /*EMPTY*/) {
162		/* look to see if we can use pointers */
163		if (msg != NULL) {
164			if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
165				if (cp+1 >= eob)
166					return (-1);
167				*cp++ = (l >> 8) | INDIR_MASK;
168				*cp++ = l % 256;
169				return (cp - comp_dn);
170			}
171			/* not found, save it */
172			if (lastdnptr != NULL && cpp < lastdnptr-1) {
173				*cpp++ = cp;
174				*cpp = NULL;
175			}
176		}
177		sp = cp++;	/* save ptr to length byte */
178		do {
179			if (c == '.') {
180				c = *dn++;
181				break;
182			}
183			if (c == '\\') {
184				if ((c = *dn++) == '\0')
185					break;
186			}
187			if (cp >= eob) {
188				if (msg != NULL)
189					*lpp = NULL;
190				return (-1);
191			}
192			*cp++ = c;
193		} while ((c = *dn++) != '\0');
194		/* catch trailing '.'s but not '..' */
195		if ((l = cp - sp - 1) == 0 && c == '\0') {
196			cp--;
197			break;
198		}
199		if (l <= 0 || l > MAXLABEL) {
200			if (msg != NULL)
201				*lpp = NULL;
202			return (-1);
203		}
204		*sp = l;
205	}
206	if (cp >= eob) {
207		if (msg != NULL)
208			*lpp = NULL;
209		return (-1);
210	}
211	*cp++ = '\0';
212	return (cp - comp_dn);
213}
214
215/*
216 * Skip over a compressed domain name. Return the size or -1.
217 */
218int
219dn_skipname(comp_dn, eom)
220	u_char *comp_dn, *eom;
221{
222	register u_char *cp;
223	register int n;
224
225	cp = comp_dn;
226	while (cp < eom && (n = *cp++)) {
227		/*
228		 * check for indirection
229		 */
230		switch (n & INDIR_MASK) {
231		case 0:		/* normal case, n == len */
232			cp += n;
233			continue;
234		default:	/* illegal type */
235			return (-1);
236		case INDIR_MASK:	/* indirection */
237			cp++;
238		}
239		break;
240	}
241	return (cp - comp_dn);
242}
243
244/*
245 * Search for expanded name from a list of previously compressed names.
246 * Return the offset from msg if found or -1.
247 * dnptrs is the pointer to the first name on the list,
248 * not the pointer to the start of the message.
249 */
250static int
251dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr)
252{
253	register u_char *dn, *cp, **cpp;
254	register int n;
255	u_char *sp;
256
257	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
258		dn = exp_dn;
259		sp = cp = *cpp;
260		while (n = *cp++) {
261			/*
262			 * check for indirection
263			 */
264			switch (n & INDIR_MASK) {
265			case 0:		/* normal case, n == len */
266				while (--n >= 0) {
267					if (*dn == '.')
268						goto next;
269					if (*dn == '\\')
270						dn++;
271					if (*dn++ != *cp++)
272						goto next;
273				}
274				if ((n = *dn++) == '\0' && *cp == '\0')
275					return (sp - msg);
276				if (n == '.')
277					continue;
278				goto next;
279
280			default:	/* illegal type */
281				return (-1);
282
283			case INDIR_MASK:	/* indirection */
284				cp = msg + (((n & 0x3f) << 8) | *cp);
285			}
286		}
287		if (*dn == '\0')
288			return (sp - msg);
289	next:	/*EMPTY*/;
290	}
291	return (-1);
292}
293
294/*
295 * Routines to insert/extract short/long's. Must account for byte
296 * order and non-alignment problems. This code at least has the
297 * advantage of being portable.
298 *
299 * used by sendmail.
300 */
301
302u_short
303_getshort(msgp)
304	u_char *msgp;
305{
306	register u_char *p = (u_char *) msgp;
307#ifdef vax
308	/*
309	 * vax compiler doesn't put shorts in registers
310	 */
311	register u_long u;
312#else
313	register u_short u;
314#endif
315
316	u = *p++ << 8;
317	return ((u_short)(u | *p));
318}
319
320u_long
321_getlong(msgp)
322	u_char *msgp;
323{
324	register u_char *p = (u_char *) msgp;
325	register u_long u;
326
327	u = *p++; u <<= 8;
328	u |= *p++; u <<= 8;
329	u |= *p++; u <<= 8;
330	return (u | *p);
331}
332
333void
334putshort(s, msgp)
335	register u_short s;
336	register u_char *msgp;
337{
338
339	msgp[1] = s;
340	msgp[0] = s >> 8;
341}
342
343void
344putlong(l, msgp)
345	register u_long l;
346	register u_char *msgp;
347{
348
349	msgp[3] = l;
350	msgp[2] = (l >>= 8);
351	msgp[1] = (l >>= 8);
352	msgp[0] = l >> 8;
353}
354