name.c revision 218384
1135446Strhodes/*
2218384Sdougb * Copyright (C) 2004-2008, 2010  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1998-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18218384Sdougb/* $Id: name.c,v 1.165.120.3 2010-07-09 05:15:05 each Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <ctype.h>
25170222Sdougb#include <stdlib.h>
26135446Strhodes
27135446Strhodes#include <isc/buffer.h>
28135446Strhodes#include <isc/hash.h>
29135446Strhodes#include <isc/mem.h>
30170222Sdougb#include <isc/once.h>
31135446Strhodes#include <isc/print.h>
32135446Strhodes#include <isc/string.h>
33170222Sdougb#include <isc/thread.h>
34135446Strhodes#include <isc/util.h>
35135446Strhodes
36135446Strhodes#include <dns/compress.h>
37135446Strhodes#include <dns/name.h>
38135446Strhodes#include <dns/result.h>
39135446Strhodes
40135446Strhodes#define VALID_NAME(n)	ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
41135446Strhodes
42135446Strhodestypedef enum {
43135446Strhodes	ft_init = 0,
44135446Strhodes	ft_start,
45135446Strhodes	ft_ordinary,
46135446Strhodes	ft_initialescape,
47135446Strhodes	ft_escape,
48135446Strhodes	ft_escdecimal,
49135446Strhodes	ft_at
50135446Strhodes} ft_state;
51135446Strhodes
52135446Strhodestypedef enum {
53135446Strhodes	fw_start = 0,
54135446Strhodes	fw_ordinary,
55135446Strhodes	fw_copy,
56135446Strhodes	fw_newcurrent
57135446Strhodes} fw_state;
58135446Strhodes
59135446Strhodesstatic char digitvalue[256] = {
60135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	/*16*/
61135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
62135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
63135446Strhodes	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
64135446Strhodes	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
65135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
66135446Strhodes	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
67135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
68135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
69135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
70135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
72135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
76135446Strhodes};
77135446Strhodes
78135446Strhodesstatic unsigned char maptolower[] = {
79135446Strhodes	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
80135446Strhodes	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
81135446Strhodes	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
82135446Strhodes	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
83135446Strhodes	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
84135446Strhodes	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
85135446Strhodes	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
86135446Strhodes	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
87135446Strhodes	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
88135446Strhodes	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
89135446Strhodes	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
90135446Strhodes	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
91135446Strhodes	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
92135446Strhodes	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
93135446Strhodes	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
94135446Strhodes	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
95135446Strhodes	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
96135446Strhodes	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
97135446Strhodes	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
98135446Strhodes	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
99135446Strhodes	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
100135446Strhodes	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
101135446Strhodes	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
102135446Strhodes	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
103135446Strhodes	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
104135446Strhodes	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
105135446Strhodes	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
106135446Strhodes	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
107135446Strhodes	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
108135446Strhodes	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
109135446Strhodes	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
110135446Strhodes	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
111135446Strhodes};
112135446Strhodes
113135446Strhodes#define CONVERTTOASCII(c)
114135446Strhodes#define CONVERTFROMASCII(c)
115135446Strhodes
116135446Strhodes#define INIT_OFFSETS(name, var, default) \
117135446Strhodes	if (name->offsets != NULL) \
118135446Strhodes		var = name->offsets; \
119135446Strhodes	else \
120135446Strhodes		var = default;
121135446Strhodes
122135446Strhodes#define SETUP_OFFSETS(name, var, default) \
123135446Strhodes	if (name->offsets != NULL) \
124135446Strhodes		var = name->offsets; \
125135446Strhodes	else { \
126135446Strhodes		var = default; \
127135446Strhodes		set_offsets(name, var, NULL); \
128135446Strhodes	}
129135446Strhodes
130170222Sdougb/*%
131135446Strhodes * Note:  If additional attributes are added that should not be set for
132135446Strhodes *	  empty names, MAKE_EMPTY() must be changed so it clears them.
133135446Strhodes */
134135446Strhodes#define MAKE_EMPTY(name) \
135135446Strhodesdo { \
136135446Strhodes	name->ndata = NULL; \
137135446Strhodes	name->length = 0; \
138135446Strhodes	name->labels = 0; \
139135446Strhodes	name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
140135446Strhodes} while (0);
141135446Strhodes
142170222Sdougb/*%
143135446Strhodes * A name is "bindable" if it can be set to point to a new value, i.e.
144135446Strhodes * name->ndata and name->length may be changed.
145135446Strhodes */
146135446Strhodes#define BINDABLE(name) \
147135446Strhodes	((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
148135446Strhodes	 == 0)
149135446Strhodes
150170222Sdougb/*%
151135446Strhodes * Note that the name data must be a char array, not a string
152135446Strhodes * literal, to avoid compiler warnings about discarding
153135446Strhodes * the const attribute of a string.
154135446Strhodes */
155135446Strhodesstatic unsigned char root_ndata[] = { '\0' };
156135446Strhodesstatic unsigned char root_offsets[] = { 0 };
157135446Strhodes
158193149Sdougbstatic dns_name_t root =
159135446Strhodes{
160135446Strhodes	DNS_NAME_MAGIC,
161135446Strhodes	root_ndata, 1, 1,
162135446Strhodes	DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
163135446Strhodes	root_offsets, NULL,
164135446Strhodes	{(void *)-1, (void *)-1},
165135446Strhodes	{NULL, NULL}
166135446Strhodes};
167135446Strhodes
168135446Strhodes/* XXXDCL make const? */
169135446StrhodesLIBDNS_EXTERNAL_DATA dns_name_t *dns_rootname = &root;
170135446Strhodes
171135446Strhodesstatic unsigned char wild_ndata[] = { '\001', '*' };
172135446Strhodesstatic unsigned char wild_offsets[] = { 0 };
173135446Strhodes
174135446Strhodesstatic dns_name_t wild =
175135446Strhodes{
176135446Strhodes	DNS_NAME_MAGIC,
177135446Strhodes	wild_ndata, 2, 1,
178135446Strhodes	DNS_NAMEATTR_READONLY,
179135446Strhodes	wild_offsets, NULL,
180135446Strhodes	{(void *)-1, (void *)-1},
181135446Strhodes	{NULL, NULL}
182135446Strhodes};
183135446Strhodes
184135446Strhodes/* XXXDCL make const? */
185135446StrhodesLIBDNS_EXTERNAL_DATA dns_name_t *dns_wildcardname = &wild;
186135446Strhodes
187135446Strhodesunsigned int
188135446Strhodesdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive);
189135446Strhodes
190170222Sdougb/*
191170222Sdougb * dns_name_t to text post-conversion procedure.
192170222Sdougb */
193170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
194170222Sdougbstatic int thread_key_initialized = 0;
195170222Sdougbstatic isc_mutex_t thread_key_mutex;
196170222Sdougbstatic isc_mem_t *thread_key_mctx = NULL;
197170222Sdougbstatic isc_thread_key_t totext_filter_proc_key;
198170222Sdougbstatic isc_once_t once = ISC_ONCE_INIT;
199170222Sdougb#else
200170222Sdougbstatic dns_name_totextfilter_t totext_filter_proc = NULL;
201170222Sdougb#endif
202170222Sdougb
203135446Strhodesstatic void
204135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets,
205135446Strhodes	    dns_name_t *set_name);
206135446Strhodes
207135446Strhodesvoid
208135446Strhodesdns_name_init(dns_name_t *name, unsigned char *offsets) {
209135446Strhodes	/*
210135446Strhodes	 * Initialize 'name'.
211135446Strhodes	 */
212135446Strhodes	DNS_NAME_INIT(name, offsets);
213135446Strhodes}
214135446Strhodes
215135446Strhodesvoid
216135446Strhodesdns_name_reset(dns_name_t *name) {
217135446Strhodes	REQUIRE(VALID_NAME(name));
218135446Strhodes	REQUIRE(BINDABLE(name));
219135446Strhodes
220135446Strhodes	DNS_NAME_RESET(name);
221135446Strhodes}
222135446Strhodes
223135446Strhodesvoid
224135446Strhodesdns_name_invalidate(dns_name_t *name) {
225135446Strhodes	/*
226135446Strhodes	 * Make 'name' invalid.
227135446Strhodes	 */
228135446Strhodes
229135446Strhodes	REQUIRE(VALID_NAME(name));
230135446Strhodes
231135446Strhodes	name->magic = 0;
232135446Strhodes	name->ndata = NULL;
233135446Strhodes	name->length = 0;
234135446Strhodes	name->labels = 0;
235135446Strhodes	name->attributes = 0;
236135446Strhodes	name->offsets = NULL;
237135446Strhodes	name->buffer = NULL;
238135446Strhodes	ISC_LINK_INIT(name, link);
239135446Strhodes}
240135446Strhodes
241135446Strhodesvoid
242135446Strhodesdns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
243135446Strhodes	/*
244135446Strhodes	 * Dedicate a buffer for use with 'name'.
245135446Strhodes	 */
246135446Strhodes
247135446Strhodes	REQUIRE(VALID_NAME(name));
248135446Strhodes	REQUIRE((buffer != NULL && name->buffer == NULL) ||
249135446Strhodes		(buffer == NULL));
250135446Strhodes
251135446Strhodes	name->buffer = buffer;
252135446Strhodes}
253135446Strhodes
254135446Strhodesisc_boolean_t
255135446Strhodesdns_name_hasbuffer(const dns_name_t *name) {
256135446Strhodes	/*
257135446Strhodes	 * Does 'name' have a dedicated buffer?
258135446Strhodes	 */
259135446Strhodes
260135446Strhodes	REQUIRE(VALID_NAME(name));
261135446Strhodes
262135446Strhodes	if (name->buffer != NULL)
263135446Strhodes		return (ISC_TRUE);
264135446Strhodes
265135446Strhodes	return (ISC_FALSE);
266135446Strhodes}
267135446Strhodes
268135446Strhodesisc_boolean_t
269135446Strhodesdns_name_isabsolute(const dns_name_t *name) {
270135446Strhodes
271135446Strhodes	/*
272135446Strhodes	 * Does 'name' end in the root label?
273135446Strhodes	 */
274135446Strhodes
275135446Strhodes	REQUIRE(VALID_NAME(name));
276135446Strhodes
277135446Strhodes	if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
278135446Strhodes		return (ISC_TRUE);
279135446Strhodes	return (ISC_FALSE);
280135446Strhodes}
281135446Strhodes
282135446Strhodes#define hyphenchar(c) ((c) == 0x2d)
283135446Strhodes#define asterchar(c) ((c) == 0x2a)
284135446Strhodes#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
285135446Strhodes		      || ((c) >= 0x61 && (c) <= 0x7a))
286135446Strhodes#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
287135446Strhodes#define borderchar(c) (alphachar(c) || digitchar(c))
288135446Strhodes#define middlechar(c) (borderchar(c) || hyphenchar(c))
289135446Strhodes#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
290135446Strhodes
291135446Strhodesisc_boolean_t
292135446Strhodesdns_name_ismailbox(const dns_name_t *name) {
293135446Strhodes	unsigned char *ndata, ch;
294135446Strhodes	unsigned int n;
295135446Strhodes	isc_boolean_t first;
296135446Strhodes
297135446Strhodes	REQUIRE(VALID_NAME(name));
298135446Strhodes	REQUIRE(name->labels > 0);
299135446Strhodes	REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
300135446Strhodes
301193149Sdougb	/*
302135446Strhodes	 * Root label.
303135446Strhodes	 */
304135446Strhodes	if (name->length == 1)
305135446Strhodes		return (ISC_TRUE);
306135446Strhodes
307135446Strhodes	ndata = name->ndata;
308135446Strhodes	n = *ndata++;
309135446Strhodes	INSIST(n <= 63);
310135446Strhodes	while (n--) {
311135446Strhodes		ch = *ndata++;
312135446Strhodes		if (!domainchar(ch))
313135446Strhodes			return (ISC_FALSE);
314135446Strhodes	}
315193149Sdougb
316135446Strhodes	if (ndata == name->ndata + name->length)
317135446Strhodes		return (ISC_FALSE);
318135446Strhodes
319135446Strhodes	/*
320135446Strhodes	 * RFC292/RFC1123 hostname.
321135446Strhodes	 */
322135446Strhodes	while (ndata < (name->ndata + name->length)) {
323135446Strhodes		n = *ndata++;
324135446Strhodes		INSIST(n <= 63);
325135446Strhodes		first = ISC_TRUE;
326135446Strhodes		while (n--) {
327135446Strhodes			ch = *ndata++;
328135446Strhodes			if (first || n == 0) {
329135446Strhodes				if (!borderchar(ch))
330135446Strhodes					return (ISC_FALSE);
331135446Strhodes			} else {
332135446Strhodes				if (!middlechar(ch))
333135446Strhodes					return (ISC_FALSE);
334135446Strhodes			}
335135446Strhodes			first = ISC_FALSE;
336135446Strhodes		}
337135446Strhodes	}
338135446Strhodes	return (ISC_TRUE);
339135446Strhodes}
340135446Strhodes
341135446Strhodesisc_boolean_t
342135446Strhodesdns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) {
343135446Strhodes	unsigned char *ndata, ch;
344135446Strhodes	unsigned int n;
345135446Strhodes	isc_boolean_t first;
346135446Strhodes
347135446Strhodes	REQUIRE(VALID_NAME(name));
348135446Strhodes	REQUIRE(name->labels > 0);
349135446Strhodes	REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
350193149Sdougb
351193149Sdougb	/*
352135446Strhodes	 * Root label.
353135446Strhodes	 */
354135446Strhodes	if (name->length == 1)
355135446Strhodes		return (ISC_TRUE);
356135446Strhodes
357135446Strhodes	/*
358135446Strhodes	 * Skip wildcard if this is a ownername.
359135446Strhodes	 */
360135446Strhodes	ndata = name->ndata;
361135446Strhodes	if (wildcard && ndata[0] == 1 && ndata[1] == '*')
362135446Strhodes		ndata += 2;
363135446Strhodes
364135446Strhodes	/*
365135446Strhodes	 * RFC292/RFC1123 hostname.
366135446Strhodes	 */
367135446Strhodes	while (ndata < (name->ndata + name->length)) {
368135446Strhodes		n = *ndata++;
369135446Strhodes		INSIST(n <= 63);
370135446Strhodes		first = ISC_TRUE;
371135446Strhodes		while (n--) {
372135446Strhodes			ch = *ndata++;
373135446Strhodes			if (first || n == 0) {
374135446Strhodes				if (!borderchar(ch))
375135446Strhodes					return (ISC_FALSE);
376135446Strhodes			} else {
377135446Strhodes				if (!middlechar(ch))
378135446Strhodes					return (ISC_FALSE);
379135446Strhodes			}
380135446Strhodes			first = ISC_FALSE;
381135446Strhodes		}
382135446Strhodes	}
383135446Strhodes	return (ISC_TRUE);
384135446Strhodes}
385135446Strhodes
386135446Strhodesisc_boolean_t
387135446Strhodesdns_name_iswildcard(const dns_name_t *name) {
388135446Strhodes	unsigned char *ndata;
389135446Strhodes
390135446Strhodes	/*
391135446Strhodes	 * Is 'name' a wildcard name?
392135446Strhodes	 */
393135446Strhodes
394135446Strhodes	REQUIRE(VALID_NAME(name));
395135446Strhodes	REQUIRE(name->labels > 0);
396135446Strhodes
397135446Strhodes	if (name->length >= 2) {
398135446Strhodes		ndata = name->ndata;
399135446Strhodes		if (ndata[0] == 1 && ndata[1] == '*')
400135446Strhodes			return (ISC_TRUE);
401135446Strhodes	}
402135446Strhodes
403135446Strhodes	return (ISC_FALSE);
404135446Strhodes}
405135446Strhodes
406170222Sdougbisc_boolean_t
407170222Sdougbdns_name_internalwildcard(const dns_name_t *name) {
408170222Sdougb	unsigned char *ndata;
409170222Sdougb	unsigned int count;
410170222Sdougb	unsigned int label;
411170222Sdougb
412170222Sdougb	/*
413170222Sdougb	 * Does 'name' contain a internal wildcard?
414170222Sdougb	 */
415170222Sdougb
416170222Sdougb	REQUIRE(VALID_NAME(name));
417170222Sdougb	REQUIRE(name->labels > 0);
418170222Sdougb
419170222Sdougb	/*
420170222Sdougb	 * Skip first label.
421170222Sdougb	 */
422170222Sdougb	ndata = name->ndata;
423170222Sdougb	count = *ndata++;
424170222Sdougb	INSIST(count <= 63);
425170222Sdougb	ndata += count;
426170222Sdougb	label = 1;
427170222Sdougb	/*
428170222Sdougb	 * Check all but the last of the remaining labels.
429170222Sdougb	 */
430170222Sdougb	while (label + 1 < name->labels) {
431170222Sdougb		count = *ndata++;
432170222Sdougb		INSIST(count <= 63);
433170222Sdougb		if (count == 1 && *ndata == '*')
434170222Sdougb			return (ISC_TRUE);
435170222Sdougb		ndata += count;
436170222Sdougb		label++;
437170222Sdougb	}
438170222Sdougb	return (ISC_FALSE);
439170222Sdougb}
440170222Sdougb
441135446Strhodesstatic inline unsigned int
442135446Strhodesname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
443135446Strhodes	unsigned int length;
444135446Strhodes	const unsigned char *s;
445135446Strhodes	unsigned int h = 0;
446135446Strhodes	unsigned char c;
447135446Strhodes
448135446Strhodes	length = name->length;
449135446Strhodes	if (length > 16)
450135446Strhodes		length = 16;
451135446Strhodes
452135446Strhodes	/*
453135446Strhodes	 * This hash function is similar to the one Ousterhout
454135446Strhodes	 * uses in Tcl.
455135446Strhodes	 */
456135446Strhodes	s = name->ndata;
457135446Strhodes	if (case_sensitive) {
458135446Strhodes		while (length > 0) {
459135446Strhodes			h += ( h << 3 ) + *s;
460135446Strhodes			s++;
461135446Strhodes			length--;
462135446Strhodes		}
463135446Strhodes	} else {
464135446Strhodes		while (length > 0) {
465135446Strhodes			c = maptolower[*s];
466135446Strhodes			h += ( h << 3 ) + c;
467135446Strhodes			s++;
468135446Strhodes			length--;
469135446Strhodes		}
470135446Strhodes	}
471135446Strhodes
472135446Strhodes	return (h);
473135446Strhodes}
474135446Strhodes
475135446Strhodesunsigned int
476135446Strhodesdns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
477135446Strhodes	/*
478135446Strhodes	 * Provide a hash value for 'name'.
479135446Strhodes	 */
480135446Strhodes	REQUIRE(VALID_NAME(name));
481135446Strhodes
482135446Strhodes	if (name->labels == 0)
483135446Strhodes		return (0);
484135446Strhodes
485135446Strhodes	return (name_hash(name, case_sensitive));
486135446Strhodes}
487135446Strhodes
488135446Strhodesunsigned int
489135446Strhodesdns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive) {
490135446Strhodes	/*
491135446Strhodes	 * Provide a hash value for 'name'.
492135446Strhodes	 */
493135446Strhodes	REQUIRE(VALID_NAME(name));
494135446Strhodes
495135446Strhodes	if (name->labels == 0)
496135446Strhodes		return (0);
497135446Strhodes
498135446Strhodes	return (isc_hash_calc((const unsigned char *)name->ndata,
499135446Strhodes			      name->length, case_sensitive));
500135446Strhodes}
501135446Strhodes
502135446Strhodesunsigned int
503135446Strhodesdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
504135446Strhodes	/*
505135446Strhodes	 * This function was deprecated due to the breakage of the name space
506135446Strhodes	 * convention.  We only keep this internally to provide binary backward
507135446Strhodes	 * compatibility.
508135446Strhodes	 */
509135446Strhodes	REQUIRE(VALID_NAME(name));
510135446Strhodes
511135446Strhodes	return (dns_name_fullhash(name, case_sensitive));
512135446Strhodes}
513135446Strhodes
514135446Strhodesunsigned int
515135446Strhodesdns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) {
516135446Strhodes	unsigned char *offsets;
517135446Strhodes	dns_offsets_t odata;
518135446Strhodes	dns_name_t tname;
519135446Strhodes	unsigned int h = 0;
520135446Strhodes	unsigned int i;
521135446Strhodes
522135446Strhodes	/*
523135446Strhodes	 * Provide a hash value for 'name'.
524135446Strhodes	 */
525135446Strhodes	REQUIRE(VALID_NAME(name));
526135446Strhodes
527135446Strhodes	if (name->labels == 0)
528135446Strhodes		return (0);
529135446Strhodes	else if (name->labels == 1)
530135446Strhodes		return (name_hash(name, case_sensitive));
531135446Strhodes
532135446Strhodes	SETUP_OFFSETS(name, offsets, odata);
533135446Strhodes	DNS_NAME_INIT(&tname, NULL);
534135446Strhodes	tname.labels = 1;
535135446Strhodes	h = 0;
536135446Strhodes	for (i = 0; i < name->labels; i++) {
537135446Strhodes		tname.ndata = name->ndata + offsets[i];
538135446Strhodes		if (i == name->labels - 1)
539135446Strhodes			tname.length = name->length - offsets[i];
540135446Strhodes		else
541135446Strhodes			tname.length = offsets[i + 1] - offsets[i];
542135446Strhodes		h += name_hash(&tname, case_sensitive);
543135446Strhodes	}
544135446Strhodes
545135446Strhodes	return (h);
546135446Strhodes}
547135446Strhodes
548135446Strhodesdns_namereln_t
549135446Strhodesdns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
550135446Strhodes		     int *orderp, unsigned int *nlabelsp)
551135446Strhodes{
552135446Strhodes	unsigned int l1, l2, l, count1, count2, count, nlabels;
553135446Strhodes	int cdiff, ldiff, chdiff;
554135446Strhodes	unsigned char *label1, *label2;
555135446Strhodes	unsigned char *offsets1, *offsets2;
556135446Strhodes	dns_offsets_t odata1, odata2;
557135446Strhodes	dns_namereln_t namereln = dns_namereln_none;
558135446Strhodes
559135446Strhodes	/*
560135446Strhodes	 * Determine the relative ordering under the DNSSEC order relation of
561135446Strhodes	 * 'name1' and 'name2', and also determine the hierarchical
562135446Strhodes	 * relationship of the names.
563135446Strhodes	 *
564135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
565135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
566135446Strhodes	 * compared the caller must ensure that they are both relative to the
567135446Strhodes	 * same domain.
568135446Strhodes	 */
569135446Strhodes
570135446Strhodes	REQUIRE(VALID_NAME(name1));
571135446Strhodes	REQUIRE(VALID_NAME(name2));
572135446Strhodes	REQUIRE(orderp != NULL);
573135446Strhodes	REQUIRE(nlabelsp != NULL);
574135446Strhodes	/*
575135446Strhodes	 * Either name1 is absolute and name2 is absolute, or neither is.
576135446Strhodes	 */
577135446Strhodes	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
578135446Strhodes		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
579135446Strhodes
580135446Strhodes	SETUP_OFFSETS(name1, offsets1, odata1);
581135446Strhodes	SETUP_OFFSETS(name2, offsets2, odata2);
582135446Strhodes
583135446Strhodes	nlabels = 0;
584135446Strhodes	l1 = name1->labels;
585135446Strhodes	l2 = name2->labels;
586135446Strhodes	ldiff = (int)l1 - (int)l2;
587135446Strhodes	if (ldiff < 0)
588135446Strhodes		l = l1;
589135446Strhodes	else
590135446Strhodes		l = l2;
591135446Strhodes
592135446Strhodes	while (l > 0) {
593135446Strhodes		l--;
594135446Strhodes		l1--;
595135446Strhodes		l2--;
596135446Strhodes		label1 = &name1->ndata[offsets1[l1]];
597135446Strhodes		label2 = &name2->ndata[offsets2[l2]];
598135446Strhodes		count1 = *label1++;
599135446Strhodes		count2 = *label2++;
600135446Strhodes
601135446Strhodes		/*
602135446Strhodes		 * We dropped bitstring labels, and we don't support any
603135446Strhodes		 * other extended label types.
604135446Strhodes		 */
605135446Strhodes		INSIST(count1 <= 63 && count2 <= 63);
606135446Strhodes
607135446Strhodes		cdiff = (int)count1 - (int)count2;
608135446Strhodes		if (cdiff < 0)
609135446Strhodes			count = count1;
610135446Strhodes		else
611135446Strhodes			count = count2;
612135446Strhodes
613135446Strhodes		while (count > 0) {
614135446Strhodes			chdiff = (int)maptolower[*label1] -
615135446Strhodes			    (int)maptolower[*label2];
616135446Strhodes			if (chdiff != 0) {
617135446Strhodes				*orderp = chdiff;
618135446Strhodes				goto done;
619135446Strhodes			}
620135446Strhodes			count--;
621135446Strhodes			label1++;
622135446Strhodes			label2++;
623135446Strhodes		}
624135446Strhodes		if (cdiff != 0) {
625135446Strhodes			*orderp = cdiff;
626135446Strhodes			goto done;
627135446Strhodes		}
628135446Strhodes		nlabels++;
629135446Strhodes	}
630135446Strhodes
631135446Strhodes	*orderp = ldiff;
632135446Strhodes	if (ldiff < 0)
633135446Strhodes		namereln = dns_namereln_contains;
634135446Strhodes	else if (ldiff > 0)
635135446Strhodes		namereln = dns_namereln_subdomain;
636135446Strhodes	else
637135446Strhodes		namereln = dns_namereln_equal;
638135446Strhodes
639135446Strhodes done:
640135446Strhodes	*nlabelsp = nlabels;
641135446Strhodes
642135446Strhodes	if (nlabels > 0 && namereln == dns_namereln_none)
643135446Strhodes		namereln = dns_namereln_commonancestor;
644135446Strhodes
645135446Strhodes	return (namereln);
646135446Strhodes}
647135446Strhodes
648135446Strhodesint
649135446Strhodesdns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
650135446Strhodes	int order;
651135446Strhodes	unsigned int nlabels;
652135446Strhodes
653135446Strhodes	/*
654135446Strhodes	 * Determine the relative ordering under the DNSSEC order relation of
655135446Strhodes	 * 'name1' and 'name2'.
656135446Strhodes	 *
657135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
658135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
659135446Strhodes	 * compared the caller must ensure that they are both relative to the
660135446Strhodes	 * same domain.
661135446Strhodes	 */
662135446Strhodes
663135446Strhodes	(void)dns_name_fullcompare(name1, name2, &order, &nlabels);
664135446Strhodes
665135446Strhodes	return (order);
666135446Strhodes}
667135446Strhodes
668135446Strhodesisc_boolean_t
669135446Strhodesdns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
670135446Strhodes	unsigned int l, count;
671135446Strhodes	unsigned char c;
672135446Strhodes	unsigned char *label1, *label2;
673135446Strhodes
674135446Strhodes	/*
675135446Strhodes	 * Are 'name1' and 'name2' equal?
676135446Strhodes	 *
677135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
678135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
679135446Strhodes	 * compared the caller must ensure that they are both relative to the
680135446Strhodes	 * same domain.
681135446Strhodes	 */
682135446Strhodes
683135446Strhodes	REQUIRE(VALID_NAME(name1));
684135446Strhodes	REQUIRE(VALID_NAME(name2));
685135446Strhodes	/*
686135446Strhodes	 * Either name1 is absolute and name2 is absolute, or neither is.
687135446Strhodes	 */
688135446Strhodes	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
689135446Strhodes		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
690135446Strhodes
691135446Strhodes	if (name1->length != name2->length)
692135446Strhodes		return (ISC_FALSE);
693135446Strhodes
694135446Strhodes	l = name1->labels;
695135446Strhodes
696135446Strhodes	if (l != name2->labels)
697135446Strhodes		return (ISC_FALSE);
698135446Strhodes
699135446Strhodes	label1 = name1->ndata;
700135446Strhodes	label2 = name2->ndata;
701135446Strhodes	while (l > 0) {
702135446Strhodes		l--;
703135446Strhodes		count = *label1++;
704135446Strhodes		if (count != *label2++)
705135446Strhodes			return (ISC_FALSE);
706135446Strhodes
707135446Strhodes		INSIST(count <= 63); /* no bitstring support */
708135446Strhodes
709135446Strhodes		while (count > 0) {
710135446Strhodes			count--;
711135446Strhodes			c = maptolower[*label1++];
712135446Strhodes			if (c != maptolower[*label2++])
713135446Strhodes				return (ISC_FALSE);
714135446Strhodes		}
715135446Strhodes	}
716135446Strhodes
717135446Strhodes	return (ISC_TRUE);
718135446Strhodes}
719135446Strhodes
720170222Sdougbisc_boolean_t
721170222Sdougbdns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
722170222Sdougb
723170222Sdougb	/*
724170222Sdougb	 * Are 'name1' and 'name2' equal?
725170222Sdougb	 *
726170222Sdougb	 * Note: It makes no sense for one of the names to be relative and the
727170222Sdougb	 * other absolute.  If both names are relative, then to be meaningfully
728170222Sdougb	 * compared the caller must ensure that they are both relative to the
729170222Sdougb	 * same domain.
730170222Sdougb	 */
731170222Sdougb
732170222Sdougb	REQUIRE(VALID_NAME(name1));
733170222Sdougb	REQUIRE(VALID_NAME(name2));
734170222Sdougb	/*
735170222Sdougb	 * Either name1 is absolute and name2 is absolute, or neither is.
736170222Sdougb	 */
737170222Sdougb	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
738170222Sdougb		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
739170222Sdougb
740170222Sdougb	if (name1->length != name2->length)
741170222Sdougb		return (ISC_FALSE);
742170222Sdougb
743170222Sdougb	if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
744170222Sdougb		return (ISC_FALSE);
745170222Sdougb
746170222Sdougb	return (ISC_TRUE);
747170222Sdougb}
748170222Sdougb
749135446Strhodesint
750135446Strhodesdns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
751135446Strhodes	unsigned int l1, l2, l, count1, count2, count;
752135446Strhodes	unsigned char c1, c2;
753135446Strhodes	unsigned char *label1, *label2;
754135446Strhodes
755135446Strhodes	/*
756135446Strhodes	 * Compare two absolute names as rdata.
757135446Strhodes	 */
758135446Strhodes
759135446Strhodes	REQUIRE(VALID_NAME(name1));
760135446Strhodes	REQUIRE(name1->labels > 0);
761135446Strhodes	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
762135446Strhodes	REQUIRE(VALID_NAME(name2));
763135446Strhodes	REQUIRE(name2->labels > 0);
764135446Strhodes	REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
765135446Strhodes
766135446Strhodes	l1 = name1->labels;
767135446Strhodes	l2 = name2->labels;
768135446Strhodes
769135446Strhodes	l = (l1 < l2) ? l1 : l2;
770135446Strhodes
771135446Strhodes	label1 = name1->ndata;
772135446Strhodes	label2 = name2->ndata;
773135446Strhodes	while (l > 0) {
774135446Strhodes		l--;
775135446Strhodes		count1 = *label1++;
776135446Strhodes		count2 = *label2++;
777135446Strhodes
778135446Strhodes		/* no bitstring support */
779135446Strhodes		INSIST(count1 <= 63 && count2 <= 63);
780135446Strhodes
781135446Strhodes		if (count1 != count2)
782135446Strhodes			return ((count1 < count2) ? -1 : 1);
783135446Strhodes		count = count1;
784135446Strhodes		while (count > 0) {
785135446Strhodes			count--;
786135446Strhodes			c1 = maptolower[*label1++];
787135446Strhodes			c2 = maptolower[*label2++];
788135446Strhodes			if (c1 < c2)
789135446Strhodes				return (-1);
790135446Strhodes			else if (c1 > c2)
791135446Strhodes				return (1);
792135446Strhodes		}
793135446Strhodes	}
794135446Strhodes
795135446Strhodes	/*
796135446Strhodes	 * If one name had more labels than the other, their common
797135446Strhodes	 * prefix must have been different because the shorter name
798135446Strhodes	 * ended with the root label and the longer one can't have
799135446Strhodes	 * a root label in the middle of it.  Therefore, if we get
800135446Strhodes	 * to this point, the lengths must be equal.
801135446Strhodes	 */
802135446Strhodes	INSIST(l1 == l2);
803135446Strhodes
804135446Strhodes	return (0);
805135446Strhodes}
806135446Strhodes
807135446Strhodesisc_boolean_t
808135446Strhodesdns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
809135446Strhodes	int order;
810135446Strhodes	unsigned int nlabels;
811135446Strhodes	dns_namereln_t namereln;
812135446Strhodes
813135446Strhodes	/*
814135446Strhodes	 * Is 'name1' a subdomain of 'name2'?
815135446Strhodes	 *
816135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
817135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
818135446Strhodes	 * compared the caller must ensure that they are both relative to the
819135446Strhodes	 * same domain.
820135446Strhodes	 */
821135446Strhodes
822135446Strhodes	namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
823135446Strhodes	if (namereln == dns_namereln_subdomain ||
824135446Strhodes	    namereln == dns_namereln_equal)
825135446Strhodes		return (ISC_TRUE);
826135446Strhodes
827135446Strhodes	return (ISC_FALSE);
828135446Strhodes}
829135446Strhodes
830135446Strhodesisc_boolean_t
831135446Strhodesdns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
832135446Strhodes	int order;
833135446Strhodes	unsigned int nlabels, labels;
834135446Strhodes	dns_name_t tname;
835135446Strhodes
836135446Strhodes	REQUIRE(VALID_NAME(name));
837135446Strhodes	REQUIRE(name->labels > 0);
838135446Strhodes	REQUIRE(VALID_NAME(wname));
839135446Strhodes	labels = wname->labels;
840135446Strhodes	REQUIRE(labels > 0);
841135446Strhodes	REQUIRE(dns_name_iswildcard(wname));
842135446Strhodes
843135446Strhodes	DNS_NAME_INIT(&tname, NULL);
844135446Strhodes	dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
845135446Strhodes	if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
846135446Strhodes	    dns_namereln_subdomain)
847135446Strhodes		return (ISC_TRUE);
848135446Strhodes	return (ISC_FALSE);
849135446Strhodes}
850135446Strhodes
851135446Strhodesunsigned int
852135446Strhodesdns_name_countlabels(const dns_name_t *name) {
853135446Strhodes	/*
854135446Strhodes	 * How many labels does 'name' have?
855135446Strhodes	 */
856135446Strhodes
857135446Strhodes	REQUIRE(VALID_NAME(name));
858135446Strhodes
859135446Strhodes	ENSURE(name->labels <= 128);
860135446Strhodes
861135446Strhodes	return (name->labels);
862135446Strhodes}
863135446Strhodes
864135446Strhodesvoid
865135446Strhodesdns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
866135446Strhodes	unsigned char *offsets;
867135446Strhodes	dns_offsets_t odata;
868135446Strhodes
869135446Strhodes	/*
870135446Strhodes	 * Make 'label' refer to the 'n'th least significant label of 'name'.
871135446Strhodes	 */
872135446Strhodes
873135446Strhodes	REQUIRE(VALID_NAME(name));
874135446Strhodes	REQUIRE(name->labels > 0);
875135446Strhodes	REQUIRE(n < name->labels);
876135446Strhodes	REQUIRE(label != NULL);
877135446Strhodes
878135446Strhodes	SETUP_OFFSETS(name, offsets, odata);
879135446Strhodes
880135446Strhodes	label->base = &name->ndata[offsets[n]];
881135446Strhodes	if (n == name->labels - 1)
882135446Strhodes		label->length = name->length - offsets[n];
883135446Strhodes	else
884135446Strhodes		label->length = offsets[n + 1] - offsets[n];
885135446Strhodes}
886135446Strhodes
887135446Strhodesvoid
888135446Strhodesdns_name_getlabelsequence(const dns_name_t *source,
889135446Strhodes			  unsigned int first, unsigned int n,
890135446Strhodes			  dns_name_t *target)
891135446Strhodes{
892135446Strhodes	unsigned char *offsets;
893135446Strhodes	dns_offsets_t odata;
894135446Strhodes	unsigned int firstoffset, endoffset;
895135446Strhodes
896135446Strhodes	/*
897135446Strhodes	 * Make 'target' refer to the 'n' labels including and following
898135446Strhodes	 * 'first' in 'source'.
899135446Strhodes	 */
900135446Strhodes
901135446Strhodes	REQUIRE(VALID_NAME(source));
902135446Strhodes	REQUIRE(VALID_NAME(target));
903135446Strhodes	REQUIRE(first <= source->labels);
904218384Sdougb	REQUIRE(n <= source->labels - first); /* note first+n could overflow */
905135446Strhodes	REQUIRE(BINDABLE(target));
906135446Strhodes
907135446Strhodes	SETUP_OFFSETS(source, offsets, odata);
908135446Strhodes
909135446Strhodes	if (first == source->labels)
910135446Strhodes		firstoffset = source->length;
911135446Strhodes	else
912135446Strhodes		firstoffset = offsets[first];
913135446Strhodes
914135446Strhodes	if (first + n == source->labels)
915135446Strhodes		endoffset = source->length;
916135446Strhodes	else
917135446Strhodes		endoffset = offsets[first + n];
918135446Strhodes
919135446Strhodes	target->ndata = &source->ndata[firstoffset];
920135446Strhodes	target->length = endoffset - firstoffset;
921193149Sdougb
922135446Strhodes	if (first + n == source->labels && n > 0 &&
923135446Strhodes	    (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
924135446Strhodes		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
925135446Strhodes	else
926135446Strhodes		target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
927135446Strhodes
928135446Strhodes	target->labels = n;
929135446Strhodes
930135446Strhodes	/*
931135446Strhodes	 * If source and target are the same, and we're making target
932135446Strhodes	 * a prefix of source, the offsets table is correct already
933135446Strhodes	 * so we don't need to call set_offsets().
934135446Strhodes	 */
935135446Strhodes	if (target->offsets != NULL &&
936135446Strhodes	    (target != source || first != 0))
937135446Strhodes		set_offsets(target, target->offsets, NULL);
938135446Strhodes}
939135446Strhodes
940135446Strhodesvoid
941165071Sdougbdns_name_clone(const dns_name_t *source, dns_name_t *target) {
942135446Strhodes
943135446Strhodes	/*
944135446Strhodes	 * Make 'target' refer to the same name as 'source'.
945135446Strhodes	 */
946135446Strhodes
947135446Strhodes	REQUIRE(VALID_NAME(source));
948135446Strhodes	REQUIRE(VALID_NAME(target));
949135446Strhodes	REQUIRE(BINDABLE(target));
950135446Strhodes
951135446Strhodes	target->ndata = source->ndata;
952135446Strhodes	target->length = source->length;
953135446Strhodes	target->labels = source->labels;
954135446Strhodes	target->attributes = source->attributes &
955135446Strhodes		(unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
956135446Strhodes				DNS_NAMEATTR_DYNOFFSETS);
957135446Strhodes	if (target->offsets != NULL && source->labels > 0) {
958135446Strhodes		if (source->offsets != NULL)
959135446Strhodes			memcpy(target->offsets, source->offsets,
960135446Strhodes			       source->labels);
961135446Strhodes		else
962135446Strhodes			set_offsets(target, target->offsets, NULL);
963135446Strhodes	}
964135446Strhodes}
965135446Strhodes
966135446Strhodesvoid
967135446Strhodesdns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
968135446Strhodes	unsigned char *offsets;
969135446Strhodes	dns_offsets_t odata;
970135446Strhodes	unsigned int len;
971135446Strhodes	isc_region_t r2;
972135446Strhodes
973135446Strhodes	/*
974135446Strhodes	 * Make 'name' refer to region 'r'.
975135446Strhodes	 */
976135446Strhodes
977135446Strhodes	REQUIRE(VALID_NAME(name));
978135446Strhodes	REQUIRE(r != NULL);
979135446Strhodes	REQUIRE(BINDABLE(name));
980135446Strhodes
981135446Strhodes	INIT_OFFSETS(name, offsets, odata);
982135446Strhodes
983135446Strhodes	if (name->buffer != NULL) {
984135446Strhodes		isc_buffer_clear(name->buffer);
985135446Strhodes		isc_buffer_availableregion(name->buffer, &r2);
986135446Strhodes		len = (r->length < r2.length) ? r->length : r2.length;
987135446Strhodes		if (len > DNS_NAME_MAXWIRE)
988135446Strhodes			len = DNS_NAME_MAXWIRE;
989135446Strhodes		memcpy(r2.base, r->base, len);
990135446Strhodes		name->ndata = r2.base;
991135446Strhodes		name->length = len;
992135446Strhodes	} else {
993135446Strhodes		name->ndata = r->base;
994193149Sdougb		name->length = (r->length <= DNS_NAME_MAXWIRE) ?
995135446Strhodes			r->length : DNS_NAME_MAXWIRE;
996135446Strhodes	}
997135446Strhodes
998135446Strhodes	if (r->length > 0)
999135446Strhodes		set_offsets(name, offsets, name);
1000135446Strhodes	else {
1001135446Strhodes		name->labels = 0;
1002135446Strhodes		name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1003135446Strhodes	}
1004135446Strhodes
1005135446Strhodes	if (name->buffer != NULL)
1006135446Strhodes		isc_buffer_add(name->buffer, name->length);
1007135446Strhodes}
1008135446Strhodes
1009135446Strhodesvoid
1010135446Strhodesdns_name_toregion(dns_name_t *name, isc_region_t *r) {
1011135446Strhodes	/*
1012135446Strhodes	 * Make 'r' refer to 'name'.
1013135446Strhodes	 */
1014135446Strhodes
1015135446Strhodes	REQUIRE(VALID_NAME(name));
1016135446Strhodes	REQUIRE(r != NULL);
1017135446Strhodes
1018135446Strhodes	DNS_NAME_TOREGION(name, r);
1019135446Strhodes}
1020135446Strhodes
1021135446Strhodes
1022135446Strhodesisc_result_t
1023135446Strhodesdns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
1024135446Strhodes		  dns_name_t *origin, unsigned int options,
1025135446Strhodes		  isc_buffer_t *target)
1026135446Strhodes{
1027135446Strhodes	unsigned char *ndata, *label;
1028135446Strhodes	char *tdata;
1029135446Strhodes	char c;
1030153816Sdougb	ft_state state;
1031153816Sdougb	unsigned int value, count;
1032153816Sdougb	unsigned int n1, n2, tlen, nrem, nused, digits, labels, tused;
1033135446Strhodes	isc_boolean_t done;
1034135446Strhodes	unsigned char *offsets;
1035135446Strhodes	dns_offsets_t odata;
1036135446Strhodes	isc_boolean_t downcase;
1037135446Strhodes
1038135446Strhodes	/*
1039135446Strhodes	 * Convert the textual representation of a DNS name at source
1040135446Strhodes	 * into uncompressed wire form stored in target.
1041135446Strhodes	 *
1042135446Strhodes	 * Notes:
1043135446Strhodes	 *	Relative domain names will have 'origin' appended to them
1044135446Strhodes	 *	unless 'origin' is NULL, in which case relative domain names
1045135446Strhodes	 *	will remain relative.
1046135446Strhodes	 */
1047135446Strhodes
1048135446Strhodes	REQUIRE(VALID_NAME(name));
1049135446Strhodes	REQUIRE(ISC_BUFFER_VALID(source));
1050135446Strhodes	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1051135446Strhodes		(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1052193149Sdougb
1053135446Strhodes	downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1054135446Strhodes
1055135446Strhodes	if (target == NULL && name->buffer != NULL) {
1056135446Strhodes		target = name->buffer;
1057135446Strhodes		isc_buffer_clear(target);
1058135446Strhodes	}
1059135446Strhodes
1060135446Strhodes	REQUIRE(BINDABLE(name));
1061135446Strhodes
1062135446Strhodes	INIT_OFFSETS(name, offsets, odata);
1063135446Strhodes	offsets[0] = 0;
1064135446Strhodes
1065135446Strhodes	/*
1066135446Strhodes	 * Initialize things to make the compiler happy; they're not required.
1067135446Strhodes	 */
1068135446Strhodes	n1 = 0;
1069135446Strhodes	n2 = 0;
1070135446Strhodes	label = NULL;
1071135446Strhodes	digits = 0;
1072135446Strhodes	value = 0;
1073135446Strhodes	count = 0;
1074135446Strhodes
1075135446Strhodes	/*
1076135446Strhodes	 * Make 'name' empty in case of failure.
1077135446Strhodes	 */
1078135446Strhodes	MAKE_EMPTY(name);
1079135446Strhodes
1080135446Strhodes	/*
1081135446Strhodes	 * Set up the state machine.
1082135446Strhodes	 */
1083135446Strhodes	tdata = (char *)source->base + source->current;
1084135446Strhodes	tlen = isc_buffer_remaininglength(source);
1085135446Strhodes	tused = 0;
1086135446Strhodes	ndata = isc_buffer_used(target);
1087135446Strhodes	nrem = isc_buffer_availablelength(target);
1088135446Strhodes	if (nrem > 255)
1089135446Strhodes		nrem = 255;
1090135446Strhodes	nused = 0;
1091135446Strhodes	labels = 0;
1092135446Strhodes	done = ISC_FALSE;
1093135446Strhodes	state = ft_init;
1094135446Strhodes
1095135446Strhodes	while (nrem > 0 && tlen > 0 && !done) {
1096135446Strhodes		c = *tdata++;
1097135446Strhodes		tlen--;
1098135446Strhodes		tused++;
1099135446Strhodes
1100135446Strhodes		switch (state) {
1101135446Strhodes		case ft_init:
1102135446Strhodes			/*
1103135446Strhodes			 * Is this the root name?
1104135446Strhodes			 */
1105135446Strhodes			if (c == '.') {
1106135446Strhodes				if (tlen != 0)
1107135446Strhodes					return (DNS_R_EMPTYLABEL);
1108135446Strhodes				labels++;
1109135446Strhodes				*ndata++ = 0;
1110135446Strhodes				nrem--;
1111135446Strhodes				nused++;
1112135446Strhodes				done = ISC_TRUE;
1113135446Strhodes				break;
1114135446Strhodes			}
1115135446Strhodes			if (c == '@' && tlen == 0) {
1116135446Strhodes				state = ft_at;
1117135446Strhodes				break;
1118135446Strhodes			}
1119135446Strhodes
1120135446Strhodes			/* FALLTHROUGH */
1121135446Strhodes		case ft_start:
1122135446Strhodes			label = ndata;
1123135446Strhodes			ndata++;
1124135446Strhodes			nrem--;
1125135446Strhodes			nused++;
1126135446Strhodes			count = 0;
1127135446Strhodes			if (c == '\\') {
1128135446Strhodes				state = ft_initialescape;
1129135446Strhodes				break;
1130135446Strhodes			}
1131135446Strhodes			state = ft_ordinary;
1132135446Strhodes			if (nrem == 0)
1133135446Strhodes				return (ISC_R_NOSPACE);
1134135446Strhodes			/* FALLTHROUGH */
1135135446Strhodes		case ft_ordinary:
1136135446Strhodes			if (c == '.') {
1137135446Strhodes				if (count == 0)
1138135446Strhodes					return (DNS_R_EMPTYLABEL);
1139135446Strhodes				*label = count;
1140135446Strhodes				labels++;
1141135446Strhodes				INSIST(labels <= 127);
1142135446Strhodes				offsets[labels] = nused;
1143135446Strhodes				if (tlen == 0) {
1144135446Strhodes					labels++;
1145135446Strhodes					*ndata++ = 0;
1146135446Strhodes					nrem--;
1147135446Strhodes					nused++;
1148135446Strhodes					done = ISC_TRUE;
1149135446Strhodes				}
1150135446Strhodes				state = ft_start;
1151135446Strhodes			} else if (c == '\\') {
1152135446Strhodes				state = ft_escape;
1153135446Strhodes			} else {
1154135446Strhodes				if (count >= 63)
1155135446Strhodes					return (DNS_R_LABELTOOLONG);
1156135446Strhodes				count++;
1157135446Strhodes				CONVERTTOASCII(c);
1158135446Strhodes				if (downcase)
1159135446Strhodes					c = maptolower[(int)c];
1160135446Strhodes				*ndata++ = c;
1161135446Strhodes				nrem--;
1162135446Strhodes				nused++;
1163135446Strhodes			}
1164135446Strhodes			break;
1165135446Strhodes		case ft_initialescape:
1166135446Strhodes			if (c == '[') {
1167135446Strhodes				/*
1168135446Strhodes				 * This looks like a bitstring label, which
1169135446Strhodes				 * was deprecated.  Intentionally drop it.
1170135446Strhodes				 */
1171135446Strhodes				return (DNS_R_BADLABELTYPE);
1172135446Strhodes			}
1173135446Strhodes			state = ft_escape;
1174135446Strhodes			/* FALLTHROUGH */
1175135446Strhodes		case ft_escape:
1176135446Strhodes			if (!isdigit(c & 0xff)) {
1177135446Strhodes				if (count >= 63)
1178135446Strhodes					return (DNS_R_LABELTOOLONG);
1179135446Strhodes				count++;
1180135446Strhodes				CONVERTTOASCII(c);
1181135446Strhodes				if (downcase)
1182135446Strhodes					c = maptolower[(int)c];
1183135446Strhodes				*ndata++ = c;
1184135446Strhodes				nrem--;
1185135446Strhodes				nused++;
1186135446Strhodes				state = ft_ordinary;
1187135446Strhodes				break;
1188135446Strhodes			}
1189135446Strhodes			digits = 0;
1190135446Strhodes			value = 0;
1191135446Strhodes			state = ft_escdecimal;
1192135446Strhodes			/* FALLTHROUGH */
1193135446Strhodes		case ft_escdecimal:
1194135446Strhodes			if (!isdigit(c & 0xff))
1195135446Strhodes				return (DNS_R_BADESCAPE);
1196135446Strhodes			value *= 10;
1197135446Strhodes			value += digitvalue[(int)c];
1198135446Strhodes			digits++;
1199135446Strhodes			if (digits == 3) {
1200135446Strhodes				if (value > 255)
1201135446Strhodes					return (DNS_R_BADESCAPE);
1202135446Strhodes				if (count >= 63)
1203135446Strhodes					return (DNS_R_LABELTOOLONG);
1204135446Strhodes				count++;
1205135446Strhodes				if (downcase)
1206135446Strhodes					value = maptolower[value];
1207135446Strhodes				*ndata++ = value;
1208135446Strhodes				nrem--;
1209135446Strhodes				nused++;
1210135446Strhodes				state = ft_ordinary;
1211135446Strhodes			}
1212135446Strhodes			break;
1213135446Strhodes		default:
1214135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1215135446Strhodes				    "Unexpected state %d", state);
1216135446Strhodes			/* Does not return. */
1217135446Strhodes		}
1218135446Strhodes	}
1219135446Strhodes
1220135446Strhodes	if (!done) {
1221135446Strhodes		if (nrem == 0)
1222135446Strhodes			return (ISC_R_NOSPACE);
1223135446Strhodes		INSIST(tlen == 0);
1224135446Strhodes		if (state != ft_ordinary && state != ft_at)
1225135446Strhodes			return (ISC_R_UNEXPECTEDEND);
1226135446Strhodes		if (state == ft_ordinary) {
1227135446Strhodes			INSIST(count != 0);
1228135446Strhodes			*label = count;
1229135446Strhodes			labels++;
1230135446Strhodes			INSIST(labels <= 127);
1231135446Strhodes			offsets[labels] = nused;
1232135446Strhodes		}
1233135446Strhodes		if (origin != NULL) {
1234135446Strhodes			if (nrem < origin->length)
1235135446Strhodes				return (ISC_R_NOSPACE);
1236135446Strhodes			label = origin->ndata;
1237135446Strhodes			n1 = origin->length;
1238135446Strhodes			nrem -= n1;
1239135446Strhodes			while (n1 > 0) {
1240135446Strhodes				n2 = *label++;
1241135446Strhodes				INSIST(n2 <= 63); /* no bitstring support */
1242135446Strhodes				*ndata++ = n2;
1243135446Strhodes				n1 -= n2 + 1;
1244135446Strhodes				nused += n2 + 1;
1245135446Strhodes				while (n2 > 0) {
1246135446Strhodes					c = *label++;
1247135446Strhodes					if (downcase)
1248135446Strhodes						c = maptolower[(int)c];
1249135446Strhodes					*ndata++ = c;
1250135446Strhodes					n2--;
1251135446Strhodes				}
1252135446Strhodes				labels++;
1253135446Strhodes				if (n1 > 0) {
1254135446Strhodes					INSIST(labels <= 127);
1255135446Strhodes					offsets[labels] = nused;
1256135446Strhodes				}
1257135446Strhodes			}
1258135446Strhodes			if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1259135446Strhodes				name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1260135446Strhodes		}
1261135446Strhodes	} else
1262135446Strhodes		name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1263135446Strhodes
1264135446Strhodes	name->ndata = (unsigned char *)target->base + target->used;
1265135446Strhodes	name->labels = labels;
1266135446Strhodes	name->length = nused;
1267135446Strhodes
1268135446Strhodes	isc_buffer_forward(source, tused);
1269135446Strhodes	isc_buffer_add(target, name->length);
1270135446Strhodes
1271135446Strhodes	return (ISC_R_SUCCESS);
1272135446Strhodes}
1273135446Strhodes
1274170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1275170222Sdougbstatic void
1276170222Sdougbfree_specific(void *arg) {
1277170222Sdougb	dns_name_totextfilter_t *mem = arg;
1278170222Sdougb	isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
1279170222Sdougb	/* Stop use being called again. */
1280170222Sdougb	(void)isc_thread_key_setspecific(totext_filter_proc_key, NULL);
1281170222Sdougb}
1282170222Sdougb
1283170222Sdougbstatic void
1284170222Sdougbthread_key_mutex_init(void) {
1285170222Sdougb	RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS);
1286170222Sdougb}
1287170222Sdougb
1288170222Sdougbstatic isc_result_t
1289170222Sdougbtotext_filter_proc_key_init(void) {
1290170222Sdougb	isc_result_t result;
1291170222Sdougb
1292170222Sdougb	/*
1293170222Sdougb	 * We need the call to isc_once_do() to support profiled mutex
1294170222Sdougb	 * otherwise thread_key_mutex could be initialized at compile time.
1295170222Sdougb	 */
1296170222Sdougb	result = isc_once_do(&once, thread_key_mutex_init);
1297170222Sdougb	if (result != ISC_R_SUCCESS)
1298170222Sdougb		return (result);
1299170222Sdougb
1300193149Sdougb	if (!thread_key_initialized) {
1301170222Sdougb		LOCK(&thread_key_mutex);
1302170222Sdougb		if (thread_key_mctx == NULL)
1303170222Sdougb			result = isc_mem_create2(0, 0, &thread_key_mctx, 0);
1304170222Sdougb		if (result != ISC_R_SUCCESS)
1305170222Sdougb			goto unlock;
1306193149Sdougb		isc_mem_setname(thread_key_mctx, "threadkey", NULL);
1307170222Sdougb		isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE);
1308193149Sdougb
1309170222Sdougb		if (!thread_key_initialized &&
1310170222Sdougb		     isc_thread_key_create(&totext_filter_proc_key,
1311193149Sdougb					   free_specific) != 0) {
1312170222Sdougb			result = ISC_R_FAILURE;
1313170222Sdougb			isc_mem_detach(&thread_key_mctx);
1314170222Sdougb		} else
1315170222Sdougb			thread_key_initialized = 1;
1316170222Sdougb unlock:
1317170222Sdougb		UNLOCK(&thread_key_mutex);
1318193149Sdougb	}
1319170222Sdougb	return (result);
1320170222Sdougb}
1321170222Sdougb#endif
1322170222Sdougb
1323135446Strhodesisc_result_t
1324135446Strhodesdns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
1325135446Strhodes		isc_buffer_t *target)
1326135446Strhodes{
1327218384Sdougb	unsigned int options = DNS_NAME_MASTERFILE;
1328218384Sdougb
1329218384Sdougb	if (omit_final_dot)
1330218384Sdougb		options |= DNS_NAME_OMITFINALDOT;
1331218384Sdougb	return (dns_name_totext2(name, options, target));
1332218384Sdougb}
1333218384Sdougb
1334218384Sdougbisc_result_t
1335218384Sdougbdns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) {
1336218384Sdougb	return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target));
1337218384Sdougb}
1338218384Sdougb
1339218384Sdougbisc_result_t
1340218384Sdougbdns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
1341218384Sdougb{
1342135446Strhodes	unsigned char *ndata;
1343135446Strhodes	char *tdata;
1344135446Strhodes	unsigned int nlen, tlen;
1345135446Strhodes	unsigned char c;
1346135446Strhodes	unsigned int trem, count;
1347135446Strhodes	unsigned int labels;
1348135446Strhodes	isc_boolean_t saw_root = ISC_FALSE;
1349170222Sdougb	unsigned int oused = target->used;
1350170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1351170222Sdougb	dns_name_totextfilter_t *mem;
1352170222Sdougb	dns_name_totextfilter_t totext_filter_proc = NULL;
1353170222Sdougb	isc_result_t result;
1354170222Sdougb#endif
1355218384Sdougb	isc_boolean_t omit_final_dot =
1356218384Sdougb		ISC_TF(options & DNS_NAME_OMITFINALDOT);
1357135446Strhodes
1358135446Strhodes	/*
1359135446Strhodes	 * This function assumes the name is in proper uncompressed
1360135446Strhodes	 * wire format.
1361135446Strhodes	 */
1362135446Strhodes	REQUIRE(VALID_NAME(name));
1363135446Strhodes	REQUIRE(ISC_BUFFER_VALID(target));
1364135446Strhodes
1365170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1366170222Sdougb	result = totext_filter_proc_key_init();
1367170222Sdougb	if (result != ISC_R_SUCCESS)
1368170222Sdougb		return (result);
1369170222Sdougb#endif
1370135446Strhodes	ndata = name->ndata;
1371135446Strhodes	nlen = name->length;
1372135446Strhodes	labels = name->labels;
1373135446Strhodes	tdata = isc_buffer_used(target);
1374135446Strhodes	tlen = isc_buffer_availablelength(target);
1375135446Strhodes
1376135446Strhodes	trem = tlen;
1377135446Strhodes
1378135446Strhodes	if (labels == 0 && nlen == 0) {
1379135446Strhodes		/*
1380135446Strhodes		 * Special handling for an empty name.
1381135446Strhodes		 */
1382135446Strhodes		if (trem == 0)
1383135446Strhodes			return (ISC_R_NOSPACE);
1384135446Strhodes
1385135446Strhodes		/*
1386135446Strhodes		 * The names of these booleans are misleading in this case.
1387135446Strhodes		 * This empty name is not necessarily from the root node of
1388135446Strhodes		 * the DNS root zone, nor is a final dot going to be included.
1389135446Strhodes		 * They need to be set this way, though, to keep the "@"
1390135446Strhodes		 * from being trounced.
1391135446Strhodes		 */
1392135446Strhodes		saw_root = ISC_TRUE;
1393135446Strhodes		omit_final_dot = ISC_FALSE;
1394135446Strhodes		*tdata++ = '@';
1395135446Strhodes		trem--;
1396135446Strhodes
1397135446Strhodes		/*
1398135446Strhodes		 * Skip the while() loop.
1399135446Strhodes		 */
1400135446Strhodes		nlen = 0;
1401135446Strhodes	} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
1402135446Strhodes		/*
1403135446Strhodes		 * Special handling for the root label.
1404135446Strhodes		 */
1405135446Strhodes		if (trem == 0)
1406135446Strhodes			return (ISC_R_NOSPACE);
1407135446Strhodes
1408135446Strhodes		saw_root = ISC_TRUE;
1409135446Strhodes		omit_final_dot = ISC_FALSE;
1410135446Strhodes		*tdata++ = '.';
1411135446Strhodes		trem--;
1412135446Strhodes
1413135446Strhodes		/*
1414135446Strhodes		 * Skip the while() loop.
1415135446Strhodes		 */
1416135446Strhodes		nlen = 0;
1417135446Strhodes	}
1418135446Strhodes
1419135446Strhodes	while (labels > 0 && nlen > 0 && trem > 0) {
1420135446Strhodes		labels--;
1421135446Strhodes		count = *ndata++;
1422135446Strhodes		nlen--;
1423135446Strhodes		if (count == 0) {
1424135446Strhodes			saw_root = ISC_TRUE;
1425135446Strhodes			break;
1426135446Strhodes		}
1427135446Strhodes		if (count < 64) {
1428135446Strhodes			INSIST(nlen >= count);
1429135446Strhodes			while (count > 0) {
1430135446Strhodes				c = *ndata;
1431135446Strhodes				switch (c) {
1432218384Sdougb				/* Special modifiers in zone files. */
1433218384Sdougb				case 0x40: /* '@' */
1434218384Sdougb				case 0x24: /* '$' */
1435218384Sdougb					if ((options & DNS_NAME_MASTERFILE) == 0)
1436218384Sdougb						goto no_escape;
1437135446Strhodes				case 0x22: /* '"' */
1438135446Strhodes				case 0x28: /* '(' */
1439135446Strhodes				case 0x29: /* ')' */
1440135446Strhodes				case 0x2E: /* '.' */
1441135446Strhodes				case 0x3B: /* ';' */
1442135446Strhodes				case 0x5C: /* '\\' */
1443135446Strhodes					if (trem < 2)
1444135446Strhodes						return (ISC_R_NOSPACE);
1445135446Strhodes					*tdata++ = '\\';
1446135446Strhodes					CONVERTFROMASCII(c);
1447135446Strhodes					*tdata++ = c;
1448135446Strhodes					ndata++;
1449135446Strhodes					trem -= 2;
1450135446Strhodes					nlen--;
1451135446Strhodes					break;
1452218384Sdougb				no_escape:
1453135446Strhodes				default:
1454135446Strhodes					if (c > 0x20 && c < 0x7f) {
1455135446Strhodes						if (trem == 0)
1456135446Strhodes							return (ISC_R_NOSPACE);
1457135446Strhodes						CONVERTFROMASCII(c);
1458135446Strhodes						*tdata++ = c;
1459135446Strhodes						ndata++;
1460135446Strhodes						trem--;
1461135446Strhodes						nlen--;
1462135446Strhodes					} else {
1463135446Strhodes						if (trem < 4)
1464135446Strhodes							return (ISC_R_NOSPACE);
1465153816Sdougb						*tdata++ = 0x5c;
1466153816Sdougb						*tdata++ = 0x30 +
1467153816Sdougb							   ((c / 100) % 10);
1468153816Sdougb						*tdata++ = 0x30 +
1469153816Sdougb							   ((c / 10) % 10);
1470153816Sdougb						*tdata++ = 0x30 + (c % 10);
1471135446Strhodes						trem -= 4;
1472135446Strhodes						ndata++;
1473135446Strhodes						nlen--;
1474135446Strhodes					}
1475135446Strhodes				}
1476135446Strhodes				count--;
1477135446Strhodes			}
1478135446Strhodes		} else {
1479135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1480135446Strhodes				    "Unexpected label type %02x", count);
1481135446Strhodes			/* NOTREACHED */
1482135446Strhodes		}
1483135446Strhodes
1484135446Strhodes		/*
1485135446Strhodes		 * The following assumes names are absolute.  If not, we
1486135446Strhodes		 * fix things up later.  Note that this means that in some
1487135446Strhodes		 * cases one more byte of text buffer is required than is
1488135446Strhodes		 * needed in the final output.
1489135446Strhodes		 */
1490135446Strhodes		if (trem == 0)
1491135446Strhodes			return (ISC_R_NOSPACE);
1492135446Strhodes		*tdata++ = '.';
1493135446Strhodes		trem--;
1494135446Strhodes	}
1495135446Strhodes
1496135446Strhodes	if (nlen != 0 && trem == 0)
1497135446Strhodes		return (ISC_R_NOSPACE);
1498135446Strhodes
1499135446Strhodes	if (!saw_root || omit_final_dot)
1500135446Strhodes		trem++;
1501135446Strhodes
1502135446Strhodes	isc_buffer_add(target, tlen - trem);
1503135446Strhodes
1504170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1505170222Sdougb	mem = isc_thread_key_getspecific(totext_filter_proc_key);
1506170222Sdougb	if (mem != NULL)
1507170222Sdougb		totext_filter_proc = *mem;
1508170222Sdougb#endif
1509170222Sdougb	if (totext_filter_proc != NULL)
1510170222Sdougb		return ((*totext_filter_proc)(target, oused, saw_root));
1511170222Sdougb
1512135446Strhodes	return (ISC_R_SUCCESS);
1513135446Strhodes}
1514135446Strhodes
1515135446Strhodesisc_result_t
1516135446Strhodesdns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
1517135446Strhodes			isc_buffer_t *target)
1518135446Strhodes{
1519135446Strhodes	unsigned char *ndata;
1520135446Strhodes	char *tdata;
1521135446Strhodes	unsigned int nlen, tlen;
1522135446Strhodes	unsigned char c;
1523135446Strhodes	unsigned int trem, count;
1524135446Strhodes	unsigned int labels;
1525135446Strhodes
1526135446Strhodes	/*
1527135446Strhodes	 * This function assumes the name is in proper uncompressed
1528135446Strhodes	 * wire format.
1529135446Strhodes	 */
1530135446Strhodes	REQUIRE(VALID_NAME(name));
1531135446Strhodes	REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
1532135446Strhodes	REQUIRE(ISC_BUFFER_VALID(target));
1533135446Strhodes
1534135446Strhodes	ndata = name->ndata;
1535135446Strhodes	nlen = name->length;
1536135446Strhodes	labels = name->labels;
1537135446Strhodes	tdata = isc_buffer_used(target);
1538135446Strhodes	tlen = isc_buffer_availablelength(target);
1539135446Strhodes
1540135446Strhodes	trem = tlen;
1541135446Strhodes
1542135446Strhodes	if (nlen == 1 && labels == 1 && *ndata == '\0') {
1543135446Strhodes		/*
1544135446Strhodes		 * Special handling for the root label.
1545135446Strhodes		 */
1546135446Strhodes		if (trem == 0)
1547135446Strhodes			return (ISC_R_NOSPACE);
1548135446Strhodes
1549135446Strhodes		omit_final_dot = ISC_FALSE;
1550135446Strhodes		*tdata++ = '.';
1551135446Strhodes		trem--;
1552135446Strhodes
1553135446Strhodes		/*
1554135446Strhodes		 * Skip the while() loop.
1555135446Strhodes		 */
1556135446Strhodes		nlen = 0;
1557135446Strhodes	}
1558135446Strhodes
1559135446Strhodes	while (labels > 0 && nlen > 0 && trem > 0) {
1560135446Strhodes		labels--;
1561135446Strhodes		count = *ndata++;
1562135446Strhodes		nlen--;
1563135446Strhodes		if (count == 0)
1564135446Strhodes			break;
1565135446Strhodes		if (count < 64) {
1566135446Strhodes			INSIST(nlen >= count);
1567135446Strhodes			while (count > 0) {
1568135446Strhodes				c = *ndata;
1569135446Strhodes				if ((c >= 0x30 && c <= 0x39) || /* digit */
1570135446Strhodes				    (c >= 0x41 && c <= 0x5A) ||	/* uppercase */
1571135446Strhodes				    (c >= 0x61 && c <= 0x7A) || /* lowercase */
1572135446Strhodes				    c == 0x2D ||		/* hyphen */
1573135446Strhodes				    c == 0x5F)			/* underscore */
1574135446Strhodes				{
1575135446Strhodes					if (trem == 0)
1576135446Strhodes						return (ISC_R_NOSPACE);
1577135446Strhodes					/* downcase */
1578135446Strhodes					if (c >= 0x41 && c <= 0x5A)
1579135446Strhodes						c += 0x20;
1580135446Strhodes					CONVERTFROMASCII(c);
1581135446Strhodes					*tdata++ = c;
1582135446Strhodes					ndata++;
1583135446Strhodes					trem--;
1584135446Strhodes					nlen--;
1585135446Strhodes				} else {
1586135446Strhodes					if (trem < 3)
1587135446Strhodes						return (ISC_R_NOSPACE);
1588135446Strhodes					sprintf(tdata, "%%%02X", c);
1589135446Strhodes					tdata += 3;
1590135446Strhodes					trem -= 3;
1591135446Strhodes					ndata++;
1592135446Strhodes					nlen--;
1593135446Strhodes				}
1594135446Strhodes				count--;
1595135446Strhodes			}
1596135446Strhodes		} else {
1597135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1598135446Strhodes				    "Unexpected label type %02x", count);
1599135446Strhodes			/* NOTREACHED */
1600135446Strhodes		}
1601135446Strhodes
1602135446Strhodes		/*
1603135446Strhodes		 * The following assumes names are absolute.  If not, we
1604135446Strhodes		 * fix things up later.  Note that this means that in some
1605135446Strhodes		 * cases one more byte of text buffer is required than is
1606135446Strhodes		 * needed in the final output.
1607135446Strhodes		 */
1608135446Strhodes		if (trem == 0)
1609135446Strhodes			return (ISC_R_NOSPACE);
1610135446Strhodes		*tdata++ = '.';
1611135446Strhodes		trem--;
1612135446Strhodes	}
1613135446Strhodes
1614135446Strhodes	if (nlen != 0 && trem == 0)
1615135446Strhodes		return (ISC_R_NOSPACE);
1616135446Strhodes
1617135446Strhodes	if (omit_final_dot)
1618135446Strhodes		trem++;
1619135446Strhodes
1620135446Strhodes	isc_buffer_add(target, tlen - trem);
1621135446Strhodes
1622135446Strhodes	return (ISC_R_SUCCESS);
1623135446Strhodes}
1624135446Strhodes
1625135446Strhodesisc_result_t
1626135446Strhodesdns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
1627135446Strhodes	unsigned char *sndata, *ndata;
1628135446Strhodes	unsigned int nlen, count, labels;
1629135446Strhodes	isc_buffer_t buffer;
1630135446Strhodes
1631135446Strhodes	/*
1632135446Strhodes	 * Downcase 'source'.
1633135446Strhodes	 */
1634135446Strhodes
1635135446Strhodes	REQUIRE(VALID_NAME(source));
1636135446Strhodes	REQUIRE(VALID_NAME(name));
1637135446Strhodes	if (source == name) {
1638135446Strhodes		REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1639135446Strhodes		isc_buffer_init(&buffer, source->ndata, source->length);
1640135446Strhodes		target = &buffer;
1641135446Strhodes		ndata = source->ndata;
1642135446Strhodes	} else {
1643135446Strhodes		REQUIRE(BINDABLE(name));
1644135446Strhodes		REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1645135446Strhodes			(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1646135446Strhodes		if (target == NULL) {
1647135446Strhodes			target = name->buffer;
1648135446Strhodes			isc_buffer_clear(name->buffer);
1649135446Strhodes		}
1650135446Strhodes		ndata = (unsigned char *)target->base + target->used;
1651135446Strhodes		name->ndata = ndata;
1652135446Strhodes	}
1653135446Strhodes
1654135446Strhodes	sndata = source->ndata;
1655135446Strhodes	nlen = source->length;
1656135446Strhodes	labels = source->labels;
1657135446Strhodes
1658135446Strhodes	if (nlen > (target->length - target->used)) {
1659135446Strhodes		MAKE_EMPTY(name);
1660135446Strhodes		return (ISC_R_NOSPACE);
1661135446Strhodes	}
1662135446Strhodes
1663135446Strhodes	while (labels > 0 && nlen > 0) {
1664135446Strhodes		labels--;
1665135446Strhodes		count = *sndata++;
1666135446Strhodes		*ndata++ = count;
1667135446Strhodes		nlen--;
1668135446Strhodes		if (count < 64) {
1669135446Strhodes			INSIST(nlen >= count);
1670135446Strhodes			while (count > 0) {
1671135446Strhodes				*ndata++ = maptolower[(*sndata++)];
1672135446Strhodes				nlen--;
1673135446Strhodes				count--;
1674135446Strhodes			}
1675135446Strhodes		} else {
1676135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1677135446Strhodes				    "Unexpected label type %02x", count);
1678135446Strhodes			/* Does not return. */
1679135446Strhodes		}
1680135446Strhodes	}
1681135446Strhodes
1682135446Strhodes	if (source != name) {
1683135446Strhodes		name->labels = source->labels;
1684135446Strhodes		name->length = source->length;
1685135446Strhodes		if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1686135446Strhodes			name->attributes = DNS_NAMEATTR_ABSOLUTE;
1687135446Strhodes		else
1688135446Strhodes			name->attributes = 0;
1689135446Strhodes		if (name->labels > 0 && name->offsets != NULL)
1690135446Strhodes			set_offsets(name, name->offsets, NULL);
1691135446Strhodes	}
1692135446Strhodes
1693135446Strhodes	isc_buffer_add(target, name->length);
1694135446Strhodes
1695135446Strhodes	return (ISC_R_SUCCESS);
1696135446Strhodes}
1697135446Strhodes
1698135446Strhodesstatic void
1699135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets,
1700135446Strhodes	    dns_name_t *set_name)
1701135446Strhodes{
1702135446Strhodes	unsigned int offset, count, length, nlabels;
1703135446Strhodes	unsigned char *ndata;
1704135446Strhodes	isc_boolean_t absolute;
1705135446Strhodes
1706135446Strhodes	ndata = name->ndata;
1707135446Strhodes	length = name->length;
1708135446Strhodes	offset = 0;
1709135446Strhodes	nlabels = 0;
1710135446Strhodes	absolute = ISC_FALSE;
1711135446Strhodes	while (offset != length) {
1712135446Strhodes		INSIST(nlabels < 128);
1713135446Strhodes		offsets[nlabels++] = offset;
1714135446Strhodes		count = *ndata++;
1715135446Strhodes		offset++;
1716135446Strhodes		INSIST(count <= 63);
1717135446Strhodes		offset += count;
1718135446Strhodes		ndata += count;
1719135446Strhodes		INSIST(offset <= length);
1720135446Strhodes		if (count == 0) {
1721135446Strhodes			absolute = ISC_TRUE;
1722135446Strhodes			break;
1723135446Strhodes		}
1724135446Strhodes	}
1725135446Strhodes	if (set_name != NULL) {
1726135446Strhodes		INSIST(set_name == name);
1727135446Strhodes
1728135446Strhodes		set_name->labels = nlabels;
1729135446Strhodes		set_name->length = offset;
1730135446Strhodes		if (absolute)
1731135446Strhodes			set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1732135446Strhodes		else
1733135446Strhodes			set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1734135446Strhodes	}
1735135446Strhodes	INSIST(nlabels == name->labels);
1736135446Strhodes	INSIST(offset == name->length);
1737135446Strhodes}
1738135446Strhodes
1739135446Strhodesisc_result_t
1740135446Strhodesdns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1741135446Strhodes		  dns_decompress_t *dctx, unsigned int options,
1742135446Strhodes		  isc_buffer_t *target)
1743135446Strhodes{
1744135446Strhodes	unsigned char *cdata, *ndata;
1745135446Strhodes	unsigned int cused; /* Bytes of compressed name data used */
1746170222Sdougb	unsigned int nused, labels, n, nmax;
1747135446Strhodes	unsigned int current, new_current, biggest_pointer;
1748135446Strhodes	isc_boolean_t done;
1749135446Strhodes	fw_state state = fw_start;
1750135446Strhodes	unsigned int c;
1751135446Strhodes	unsigned char *offsets;
1752135446Strhodes	dns_offsets_t odata;
1753135446Strhodes	isc_boolean_t downcase;
1754170222Sdougb	isc_boolean_t seen_pointer;
1755135446Strhodes
1756135446Strhodes	/*
1757135446Strhodes	 * Copy the possibly-compressed name at source into target,
1758170222Sdougb	 * decompressing it.  Loop prevention is performed by checking
1759170222Sdougb	 * the new pointer against biggest_pointer.
1760135446Strhodes	 */
1761135446Strhodes
1762135446Strhodes	REQUIRE(VALID_NAME(name));
1763135446Strhodes	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1764135446Strhodes		(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1765135446Strhodes
1766135446Strhodes	downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1767135446Strhodes
1768135446Strhodes	if (target == NULL && name->buffer != NULL) {
1769135446Strhodes		target = name->buffer;
1770135446Strhodes		isc_buffer_clear(target);
1771135446Strhodes	}
1772135446Strhodes
1773135446Strhodes	REQUIRE(dctx != NULL);
1774135446Strhodes	REQUIRE(BINDABLE(name));
1775135446Strhodes
1776135446Strhodes	INIT_OFFSETS(name, offsets, odata);
1777135446Strhodes
1778135446Strhodes	/*
1779135446Strhodes	 * Make 'name' empty in case of failure.
1780135446Strhodes	 */
1781135446Strhodes	MAKE_EMPTY(name);
1782135446Strhodes
1783135446Strhodes	/*
1784135446Strhodes	 * Initialize things to make the compiler happy; they're not required.
1785135446Strhodes	 */
1786135446Strhodes	n = 0;
1787135446Strhodes	new_current = 0;
1788135446Strhodes
1789135446Strhodes	/*
1790135446Strhodes	 * Set up.
1791135446Strhodes	 */
1792135446Strhodes	labels = 0;
1793135446Strhodes	done = ISC_FALSE;
1794135446Strhodes
1795135446Strhodes	ndata = isc_buffer_used(target);
1796135446Strhodes	nused = 0;
1797170222Sdougb	seen_pointer = ISC_FALSE;
1798135446Strhodes
1799135446Strhodes	/*
1800135446Strhodes	 * Find the maximum number of uncompressed target name
1801135446Strhodes	 * bytes we are willing to generate.  This is the smaller
1802135446Strhodes	 * of the available target buffer length and the
1803135446Strhodes	 * maximum legal domain name length (255).
1804135446Strhodes	 */
1805135446Strhodes	nmax = isc_buffer_availablelength(target);
1806135446Strhodes	if (nmax > DNS_NAME_MAXWIRE)
1807135446Strhodes		nmax = DNS_NAME_MAXWIRE;
1808135446Strhodes
1809135446Strhodes	cdata = isc_buffer_current(source);
1810135446Strhodes	cused = 0;
1811135446Strhodes
1812135446Strhodes	current = source->current;
1813135446Strhodes	biggest_pointer = current;
1814135446Strhodes
1815135446Strhodes	/*
1816135446Strhodes	 * Note:  The following code is not optimized for speed, but
1817135446Strhodes	 * rather for correctness.  Speed will be addressed in the future.
1818135446Strhodes	 */
1819135446Strhodes
1820135446Strhodes	while (current < source->active && !done) {
1821135446Strhodes		c = *cdata++;
1822135446Strhodes		current++;
1823170222Sdougb		if (!seen_pointer)
1824135446Strhodes			cused++;
1825135446Strhodes
1826135446Strhodes		switch (state) {
1827135446Strhodes		case fw_start:
1828135446Strhodes			if (c < 64) {
1829135446Strhodes				offsets[labels] = nused;
1830135446Strhodes				labels++;
1831135446Strhodes				if (nused + c + 1 > nmax)
1832135446Strhodes					goto full;
1833135446Strhodes				nused += c + 1;
1834135446Strhodes				*ndata++ = c;
1835135446Strhodes				if (c == 0)
1836135446Strhodes					done = ISC_TRUE;
1837135446Strhodes				n = c;
1838135446Strhodes				state = fw_ordinary;
1839135446Strhodes			} else if (c >= 128 && c < 192) {
1840135446Strhodes				/*
1841135446Strhodes				 * 14 bit local compression pointer.
1842135446Strhodes				 * Local compression is no longer an
1843135446Strhodes				 * IETF draft.
1844135446Strhodes				 */
1845135446Strhodes				return (DNS_R_BADLABELTYPE);
1846135446Strhodes			} else if (c >= 192) {
1847135446Strhodes				/*
1848135446Strhodes				 * Ordinary 14-bit pointer.
1849135446Strhodes				 */
1850135446Strhodes				if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1851135446Strhodes				    0)
1852135446Strhodes					return (DNS_R_DISALLOWED);
1853135446Strhodes				new_current = c & 0x3F;
1854135446Strhodes				n = 1;
1855135446Strhodes				state = fw_newcurrent;
1856135446Strhodes			} else
1857135446Strhodes				return (DNS_R_BADLABELTYPE);
1858135446Strhodes			break;
1859135446Strhodes		case fw_ordinary:
1860135446Strhodes			if (downcase)
1861135446Strhodes				c = maptolower[c];
1862135446Strhodes			/* FALLTHROUGH */
1863135446Strhodes		case fw_copy:
1864135446Strhodes			*ndata++ = c;
1865135446Strhodes			n--;
1866135446Strhodes			if (n == 0)
1867135446Strhodes				state = fw_start;
1868135446Strhodes			break;
1869135446Strhodes		case fw_newcurrent:
1870135446Strhodes			new_current *= 256;
1871135446Strhodes			new_current += c;
1872135446Strhodes			n--;
1873135446Strhodes			if (n != 0)
1874135446Strhodes				break;
1875135446Strhodes			if (new_current >= biggest_pointer)
1876135446Strhodes				return (DNS_R_BADPOINTER);
1877135446Strhodes			biggest_pointer = new_current;
1878135446Strhodes			current = new_current;
1879170222Sdougb			cdata = (unsigned char *)source->base + current;
1880170222Sdougb			seen_pointer = ISC_TRUE;
1881135446Strhodes			state = fw_start;
1882135446Strhodes			break;
1883135446Strhodes		default:
1884135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1885135446Strhodes				    "Unknown state %d", state);
1886135446Strhodes			/* Does not return. */
1887135446Strhodes		}
1888135446Strhodes	}
1889135446Strhodes
1890135446Strhodes	if (!done)
1891135446Strhodes		return (ISC_R_UNEXPECTEDEND);
1892135446Strhodes
1893135446Strhodes	name->ndata = (unsigned char *)target->base + target->used;
1894135446Strhodes	name->labels = labels;
1895135446Strhodes	name->length = nused;
1896135446Strhodes	name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1897135446Strhodes
1898135446Strhodes	isc_buffer_forward(source, cused);
1899135446Strhodes	isc_buffer_add(target, name->length);
1900135446Strhodes
1901135446Strhodes	return (ISC_R_SUCCESS);
1902135446Strhodes
1903135446Strhodes full:
1904135446Strhodes	if (nmax == DNS_NAME_MAXWIRE)
1905135446Strhodes		/*
1906135446Strhodes		 * The name did not fit even though we had a buffer
1907135446Strhodes		 * big enough to fit a maximum-length name.
1908135446Strhodes		 */
1909135446Strhodes		return (DNS_R_NAMETOOLONG);
1910135446Strhodes	else
1911135446Strhodes		/*
1912135446Strhodes		 * The name might fit if only the caller could give us a
1913135446Strhodes		 * big enough buffer.
1914135446Strhodes		 */
1915135446Strhodes		return (ISC_R_NOSPACE);
1916135446Strhodes}
1917135446Strhodes
1918135446Strhodesisc_result_t
1919165071Sdougbdns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
1920165071Sdougb		isc_buffer_t *target)
1921165071Sdougb{
1922135446Strhodes	unsigned int methods;
1923135446Strhodes	isc_uint16_t offset;
1924135446Strhodes	dns_name_t gp;	/* Global compression prefix */
1925135446Strhodes	isc_boolean_t gf;	/* Global compression target found */
1926135446Strhodes	isc_uint16_t go;	/* Global compression offset */
1927135446Strhodes	dns_offsets_t clo;
1928135446Strhodes	dns_name_t clname;
1929135446Strhodes
1930135446Strhodes	/*
1931135446Strhodes	 * Convert 'name' into wire format, compressing it as specified by the
1932135446Strhodes	 * compression context 'cctx', and storing the result in 'target'.
1933135446Strhodes	 */
1934135446Strhodes
1935135446Strhodes	REQUIRE(VALID_NAME(name));
1936135446Strhodes	REQUIRE(cctx != NULL);
1937135446Strhodes	REQUIRE(ISC_BUFFER_VALID(target));
1938135446Strhodes
1939135446Strhodes	/*
1940135446Strhodes	 * If 'name' doesn't have an offsets table, make a clone which
1941135446Strhodes	 * has one.
1942135446Strhodes	 */
1943135446Strhodes	if (name->offsets == NULL) {
1944135446Strhodes		DNS_NAME_INIT(&clname, clo);
1945135446Strhodes		dns_name_clone(name, &clname);
1946135446Strhodes		name = &clname;
1947135446Strhodes	}
1948135446Strhodes	DNS_NAME_INIT(&gp, NULL);
1949135446Strhodes
1950135446Strhodes	offset = target->used;	/*XXX*/
1951135446Strhodes
1952135446Strhodes	methods = dns_compress_getmethods(cctx);
1953135446Strhodes
1954193149Sdougb	if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
1955193149Sdougb	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
1956135446Strhodes		gf = dns_compress_findglobal(cctx, name, &gp, &go);
1957135446Strhodes	else
1958135446Strhodes		gf = ISC_FALSE;
1959135446Strhodes
1960135446Strhodes	/*
1961135446Strhodes	 * If the offset is too high for 14 bit global compression, we're
1962135446Strhodes	 * out of luck.
1963135446Strhodes	 */
1964135446Strhodes	if (gf && go >= 0x4000)
1965135446Strhodes		gf = ISC_FALSE;
1966135446Strhodes
1967135446Strhodes	/*
1968135446Strhodes	 * Will the compression pointer reduce the message size?
1969135446Strhodes	 */
1970135446Strhodes	if (gf && (gp.length + 2) >= name->length)
1971135446Strhodes		gf = ISC_FALSE;
1972135446Strhodes
1973135446Strhodes	if (gf) {
1974135446Strhodes		if (target->length - target->used < gp.length)
1975135446Strhodes			return (ISC_R_NOSPACE);
1976135446Strhodes		(void)memcpy((unsigned char *)target->base + target->used,
1977135446Strhodes			     gp.ndata, (size_t)gp.length);
1978135446Strhodes		isc_buffer_add(target, gp.length);
1979135446Strhodes		go |= 0xc000;
1980135446Strhodes		if (target->length - target->used < 2)
1981135446Strhodes			return (ISC_R_NOSPACE);
1982135446Strhodes		isc_buffer_putuint16(target, go);
1983135446Strhodes		if (gp.length != 0)
1984135446Strhodes			dns_compress_add(cctx, name, &gp, offset);
1985135446Strhodes	} else {
1986135446Strhodes		if (target->length - target->used < name->length)
1987135446Strhodes			return (ISC_R_NOSPACE);
1988135446Strhodes		(void)memcpy((unsigned char *)target->base + target->used,
1989135446Strhodes			     name->ndata, (size_t)name->length);
1990135446Strhodes		isc_buffer_add(target, name->length);
1991135446Strhodes		dns_compress_add(cctx, name, name, offset);
1992135446Strhodes	}
1993135446Strhodes	return (ISC_R_SUCCESS);
1994135446Strhodes}
1995135446Strhodes
1996135446Strhodesisc_result_t
1997135446Strhodesdns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
1998135446Strhodes		     isc_buffer_t *target)
1999135446Strhodes{
2000135446Strhodes	unsigned char *ndata, *offsets;
2001135446Strhodes	unsigned int nrem, labels, prefix_length, length;
2002135446Strhodes	isc_boolean_t copy_prefix = ISC_TRUE;
2003135446Strhodes	isc_boolean_t copy_suffix = ISC_TRUE;
2004135446Strhodes	isc_boolean_t absolute = ISC_FALSE;
2005135446Strhodes	dns_name_t tmp_name;
2006135446Strhodes	dns_offsets_t odata;
2007135446Strhodes
2008135446Strhodes	/*
2009135446Strhodes	 * Concatenate 'prefix' and 'suffix'.
2010135446Strhodes	 */
2011135446Strhodes
2012135446Strhodes	REQUIRE(prefix == NULL || VALID_NAME(prefix));
2013135446Strhodes	REQUIRE(suffix == NULL || VALID_NAME(suffix));
2014135446Strhodes	REQUIRE(name == NULL || VALID_NAME(name));
2015135446Strhodes	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
2016135446Strhodes		(target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer)));
2017135446Strhodes	if (prefix == NULL || prefix->labels == 0)
2018135446Strhodes		copy_prefix = ISC_FALSE;
2019135446Strhodes	if (suffix == NULL || suffix->labels == 0)
2020135446Strhodes		copy_suffix = ISC_FALSE;
2021135446Strhodes	if (copy_prefix &&
2022135446Strhodes	    (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2023135446Strhodes		absolute = ISC_TRUE;
2024135446Strhodes		REQUIRE(!copy_suffix);
2025135446Strhodes	}
2026135446Strhodes	if (name == NULL) {
2027135446Strhodes		DNS_NAME_INIT(&tmp_name, odata);
2028135446Strhodes		name = &tmp_name;
2029135446Strhodes	}
2030135446Strhodes	if (target == NULL) {
2031135446Strhodes		INSIST(name->buffer != NULL);
2032135446Strhodes		target = name->buffer;
2033135446Strhodes		isc_buffer_clear(name->buffer);
2034135446Strhodes	}
2035135446Strhodes
2036135446Strhodes	REQUIRE(BINDABLE(name));
2037135446Strhodes
2038135446Strhodes	/*
2039135446Strhodes	 * Set up.
2040135446Strhodes	 */
2041135446Strhodes	nrem = target->length - target->used;
2042135446Strhodes	ndata = (unsigned char *)target->base + target->used;
2043135446Strhodes	if (nrem > DNS_NAME_MAXWIRE)
2044135446Strhodes		nrem = DNS_NAME_MAXWIRE;
2045135446Strhodes	length = 0;
2046135446Strhodes	prefix_length = 0;
2047135446Strhodes	labels = 0;
2048135446Strhodes	if (copy_prefix) {
2049135446Strhodes		prefix_length = prefix->length;
2050135446Strhodes		length += prefix_length;
2051135446Strhodes		labels += prefix->labels;
2052135446Strhodes	}
2053135446Strhodes	if (copy_suffix) {
2054135446Strhodes		length += suffix->length;
2055135446Strhodes		labels += suffix->labels;
2056135446Strhodes	}
2057135446Strhodes	if (length > DNS_NAME_MAXWIRE) {
2058135446Strhodes		MAKE_EMPTY(name);
2059135446Strhodes		return (DNS_R_NAMETOOLONG);
2060135446Strhodes	}
2061135446Strhodes	if (length > nrem) {
2062135446Strhodes		MAKE_EMPTY(name);
2063135446Strhodes		return (ISC_R_NOSPACE);
2064135446Strhodes	}
2065135446Strhodes
2066135446Strhodes	if (copy_suffix) {
2067135446Strhodes		if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2068135446Strhodes			absolute = ISC_TRUE;
2069135446Strhodes		if (suffix == name && suffix->buffer == target)
2070135446Strhodes			memmove(ndata + prefix_length, suffix->ndata,
2071135446Strhodes				suffix->length);
2072135446Strhodes		else
2073135446Strhodes			memcpy(ndata + prefix_length, suffix->ndata,
2074135446Strhodes			       suffix->length);
2075135446Strhodes	}
2076135446Strhodes
2077135446Strhodes	/*
2078135446Strhodes	 * If 'prefix' and 'name' are the same object, and the object has
2079135446Strhodes	 * a dedicated buffer, and we're using it, then we don't have to
2080135446Strhodes	 * copy anything.
2081135446Strhodes	 */
2082135446Strhodes	if (copy_prefix && (prefix != name || prefix->buffer != target))
2083135446Strhodes		memcpy(ndata, prefix->ndata, prefix_length);
2084135446Strhodes
2085135446Strhodes	name->ndata = ndata;
2086135446Strhodes	name->labels = labels;
2087135446Strhodes	name->length = length;
2088135446Strhodes	if (absolute)
2089135446Strhodes		name->attributes = DNS_NAMEATTR_ABSOLUTE;
2090135446Strhodes	else
2091135446Strhodes		name->attributes = 0;
2092135446Strhodes
2093135446Strhodes	if (name->labels > 0 && name->offsets != NULL) {
2094135446Strhodes		INIT_OFFSETS(name, offsets, odata);
2095135446Strhodes		set_offsets(name, offsets, NULL);
2096135446Strhodes	}
2097135446Strhodes
2098135446Strhodes	isc_buffer_add(target, name->length);
2099135446Strhodes
2100135446Strhodes	return (ISC_R_SUCCESS);
2101135446Strhodes}
2102135446Strhodes
2103135446Strhodesvoid
2104135446Strhodesdns_name_split(dns_name_t *name, unsigned int suffixlabels,
2105135446Strhodes	       dns_name_t *prefix, dns_name_t *suffix)
2106135446Strhodes
2107135446Strhodes{
2108135446Strhodes	unsigned int splitlabel;
2109135446Strhodes
2110135446Strhodes	REQUIRE(VALID_NAME(name));
2111135446Strhodes	REQUIRE(suffixlabels > 0);
2112135446Strhodes	REQUIRE(suffixlabels < name->labels);
2113135446Strhodes	REQUIRE(prefix != NULL || suffix != NULL);
2114135446Strhodes	REQUIRE(prefix == NULL ||
2115135446Strhodes		(VALID_NAME(prefix) &&
2116135446Strhodes		 prefix->buffer != NULL &&
2117135446Strhodes		 BINDABLE(prefix)));
2118135446Strhodes	REQUIRE(suffix == NULL ||
2119135446Strhodes		(VALID_NAME(suffix) &&
2120135446Strhodes		 suffix->buffer != NULL &&
2121135446Strhodes		 BINDABLE(suffix)));
2122135446Strhodes
2123135446Strhodes	splitlabel = name->labels - suffixlabels;
2124135446Strhodes
2125135446Strhodes	if (prefix != NULL)
2126135446Strhodes		dns_name_getlabelsequence(name, 0, splitlabel, prefix);
2127135446Strhodes
2128135446Strhodes	if (suffix != NULL)
2129135446Strhodes		dns_name_getlabelsequence(name, splitlabel,
2130135446Strhodes					  suffixlabels, suffix);
2131135446Strhodes
2132135446Strhodes	return;
2133135446Strhodes}
2134135446Strhodes
2135135446Strhodesisc_result_t
2136165071Sdougbdns_name_dup(const dns_name_t *source, isc_mem_t *mctx,
2137165071Sdougb	     dns_name_t *target)
2138165071Sdougb{
2139135446Strhodes	/*
2140135446Strhodes	 * Make 'target' a dynamically allocated copy of 'source'.
2141135446Strhodes	 */
2142135446Strhodes
2143135446Strhodes	REQUIRE(VALID_NAME(source));
2144135446Strhodes	REQUIRE(source->length > 0);
2145135446Strhodes	REQUIRE(VALID_NAME(target));
2146135446Strhodes	REQUIRE(BINDABLE(target));
2147135446Strhodes
2148135446Strhodes	/*
2149135446Strhodes	 * Make 'target' empty in case of failure.
2150135446Strhodes	 */
2151135446Strhodes	MAKE_EMPTY(target);
2152135446Strhodes
2153135446Strhodes	target->ndata = isc_mem_get(mctx, source->length);
2154135446Strhodes	if (target->ndata == NULL)
2155135446Strhodes		return (ISC_R_NOMEMORY);
2156135446Strhodes
2157135446Strhodes	memcpy(target->ndata, source->ndata, source->length);
2158135446Strhodes
2159135446Strhodes	target->length = source->length;
2160135446Strhodes	target->labels = source->labels;
2161135446Strhodes	target->attributes = DNS_NAMEATTR_DYNAMIC;
2162135446Strhodes	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2163135446Strhodes		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
2164135446Strhodes	if (target->offsets != NULL) {
2165135446Strhodes		if (source->offsets != NULL)
2166135446Strhodes			memcpy(target->offsets, source->offsets,
2167135446Strhodes			       source->labels);
2168135446Strhodes		else
2169135446Strhodes			set_offsets(target, target->offsets, NULL);
2170135446Strhodes	}
2171135446Strhodes
2172135446Strhodes	return (ISC_R_SUCCESS);
2173135446Strhodes}
2174135446Strhodes
2175135446Strhodesisc_result_t
2176135446Strhodesdns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
2177135446Strhodes			dns_name_t *target)
2178135446Strhodes{
2179135446Strhodes	/*
2180135446Strhodes	 * Make 'target' a read-only dynamically allocated copy of 'source'.
2181135446Strhodes	 * 'target' will also have a dynamically allocated offsets table.
2182135446Strhodes	 */
2183135446Strhodes
2184135446Strhodes	REQUIRE(VALID_NAME(source));
2185135446Strhodes	REQUIRE(source->length > 0);
2186135446Strhodes	REQUIRE(VALID_NAME(target));
2187135446Strhodes	REQUIRE(BINDABLE(target));
2188135446Strhodes	REQUIRE(target->offsets == NULL);
2189135446Strhodes
2190135446Strhodes	/*
2191135446Strhodes	 * Make 'target' empty in case of failure.
2192135446Strhodes	 */
2193135446Strhodes	MAKE_EMPTY(target);
2194135446Strhodes
2195135446Strhodes	target->ndata = isc_mem_get(mctx, source->length + source->labels);
2196135446Strhodes	if (target->ndata == NULL)
2197135446Strhodes		return (ISC_R_NOMEMORY);
2198135446Strhodes
2199135446Strhodes	memcpy(target->ndata, source->ndata, source->length);
2200135446Strhodes
2201135446Strhodes	target->length = source->length;
2202135446Strhodes	target->labels = source->labels;
2203135446Strhodes	target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
2204135446Strhodes		DNS_NAMEATTR_READONLY;
2205135446Strhodes	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2206135446Strhodes		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
2207135446Strhodes	target->offsets = target->ndata + source->length;
2208135446Strhodes	if (source->offsets != NULL)
2209135446Strhodes		memcpy(target->offsets, source->offsets, source->labels);
2210135446Strhodes	else
2211135446Strhodes		set_offsets(target, target->offsets, NULL);
2212135446Strhodes
2213135446Strhodes	return (ISC_R_SUCCESS);
2214135446Strhodes}
2215135446Strhodes
2216135446Strhodesvoid
2217135446Strhodesdns_name_free(dns_name_t *name, isc_mem_t *mctx) {
2218135446Strhodes	size_t size;
2219135446Strhodes
2220135446Strhodes	/*
2221135446Strhodes	 * Free 'name'.
2222135446Strhodes	 */
2223135446Strhodes
2224135446Strhodes	REQUIRE(VALID_NAME(name));
2225135446Strhodes	REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
2226135446Strhodes
2227135446Strhodes	size = name->length;
2228135446Strhodes	if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0)
2229135446Strhodes		size += name->labels;
2230135446Strhodes	isc_mem_put(mctx, name->ndata, size);
2231135446Strhodes	dns_name_invalidate(name);
2232135446Strhodes}
2233135446Strhodes
2234135446Strhodesisc_result_t
2235135446Strhodesdns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) {
2236135446Strhodes	dns_name_t downname;
2237135446Strhodes	unsigned char data[256];
2238135446Strhodes	isc_buffer_t buffer;
2239135446Strhodes	isc_result_t result;
2240135446Strhodes	isc_region_t r;
2241135446Strhodes
2242135446Strhodes	/*
2243135446Strhodes	 * Send 'name' in DNSSEC canonical form to 'digest'.
2244135446Strhodes	 */
2245135446Strhodes
2246135446Strhodes	REQUIRE(VALID_NAME(name));
2247135446Strhodes	REQUIRE(digest != NULL);
2248135446Strhodes
2249135446Strhodes	DNS_NAME_INIT(&downname, NULL);
2250135446Strhodes	isc_buffer_init(&buffer, data, sizeof(data));
2251135446Strhodes
2252135446Strhodes	result = dns_name_downcase(name, &downname, &buffer);
2253135446Strhodes	if (result != ISC_R_SUCCESS)
2254135446Strhodes		return (result);
2255135446Strhodes
2256135446Strhodes	isc_buffer_usedregion(&buffer, &r);
2257135446Strhodes
2258135446Strhodes	return ((digest)(arg, &r));
2259135446Strhodes}
2260135446Strhodes
2261135446Strhodesisc_boolean_t
2262135446Strhodesdns_name_dynamic(dns_name_t *name) {
2263135446Strhodes	REQUIRE(VALID_NAME(name));
2264135446Strhodes
2265135446Strhodes	/*
2266135446Strhodes	 * Returns whether there is dynamic memory associated with this name.
2267135446Strhodes	 */
2268135446Strhodes
2269135446Strhodes	return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
2270135446Strhodes		ISC_TRUE : ISC_FALSE);
2271135446Strhodes}
2272135446Strhodes
2273135446Strhodesisc_result_t
2274135446Strhodesdns_name_print(dns_name_t *name, FILE *stream) {
2275135446Strhodes	isc_result_t result;
2276135446Strhodes	isc_buffer_t b;
2277135446Strhodes	isc_region_t r;
2278135446Strhodes	char t[1024];
2279135446Strhodes
2280135446Strhodes	/*
2281135446Strhodes	 * Print 'name' on 'stream'.
2282135446Strhodes	 */
2283135446Strhodes
2284135446Strhodes	REQUIRE(VALID_NAME(name));
2285135446Strhodes
2286135446Strhodes	isc_buffer_init(&b, t, sizeof(t));
2287135446Strhodes	result = dns_name_totext(name, ISC_FALSE, &b);
2288135446Strhodes	if (result != ISC_R_SUCCESS)
2289135446Strhodes		return (result);
2290135446Strhodes	isc_buffer_usedregion(&b, &r);
2291135446Strhodes	fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
2292135446Strhodes
2293135446Strhodes	return (ISC_R_SUCCESS);
2294135446Strhodes}
2295135446Strhodes
2296170222Sdougbisc_result_t
2297170222Sdougbdns_name_settotextfilter(dns_name_totextfilter_t proc) {
2298170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
2299170222Sdougb	isc_result_t result;
2300170222Sdougb	dns_name_totextfilter_t *mem;
2301170222Sdougb	int res;
2302170222Sdougb
2303170222Sdougb	result = totext_filter_proc_key_init();
2304170222Sdougb	if (result != ISC_R_SUCCESS)
2305170222Sdougb		return (result);
2306170222Sdougb
2307170222Sdougb	/*
2308170222Sdougb	 * If we already have been here set / clear as appropriate.
2309170222Sdougb	 * Otherwise allocate memory.
2310170222Sdougb	 */
2311170222Sdougb	mem = isc_thread_key_getspecific(totext_filter_proc_key);
2312170222Sdougb	if (mem != NULL && proc != NULL) {
2313170222Sdougb		*mem = proc;
2314170222Sdougb		return (ISC_R_SUCCESS);
2315170222Sdougb	}
2316170222Sdougb	if (proc == NULL) {
2317170222Sdougb		isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
2318170222Sdougb		res = isc_thread_key_setspecific(totext_filter_proc_key, NULL);
2319170222Sdougb		if (res != 0)
2320170222Sdougb			result = ISC_R_UNEXPECTED;
2321170222Sdougb		return (result);
2322170222Sdougb	}
2323193149Sdougb
2324170222Sdougb	mem = isc_mem_get(thread_key_mctx, sizeof(*mem));
2325170222Sdougb	if (mem == NULL)
2326170222Sdougb		return (ISC_R_NOMEMORY);
2327170222Sdougb	*mem = proc;
2328170222Sdougb	if (isc_thread_key_setspecific(totext_filter_proc_key, mem) != 0) {
2329170222Sdougb		isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
2330170222Sdougb		result = ISC_R_UNEXPECTED;
2331170222Sdougb	}
2332170222Sdougb	return (result);
2333170222Sdougb#else
2334170222Sdougb	totext_filter_proc = proc;
2335170222Sdougb	return (ISC_R_SUCCESS);
2336170222Sdougb#endif
2337170222Sdougb}
2338170222Sdougb
2339135446Strhodesvoid
2340135446Strhodesdns_name_format(dns_name_t *name, char *cp, unsigned int size) {
2341135446Strhodes	isc_result_t result;
2342135446Strhodes	isc_buffer_t buf;
2343135446Strhodes
2344135446Strhodes	REQUIRE(size > 0);
2345135446Strhodes
2346135446Strhodes	/*
2347135446Strhodes	 * Leave room for null termination after buffer.
2348135446Strhodes	 */
2349135446Strhodes	isc_buffer_init(&buf, cp, size - 1);
2350135446Strhodes	result = dns_name_totext(name, ISC_TRUE, &buf);
2351135446Strhodes	if (result == ISC_R_SUCCESS) {
2352135446Strhodes		/*
2353135446Strhodes		 * Null terminate.
2354135446Strhodes		 */
2355135446Strhodes		isc_region_t r;
2356135446Strhodes		isc_buffer_usedregion(&buf, &r);
2357135446Strhodes		((char *) r.base)[r.length] = '\0';
2358135446Strhodes
2359135446Strhodes	} else
2360135446Strhodes		snprintf(cp, size, "<unknown>");
2361135446Strhodes}
2362135446Strhodes
2363135446Strhodesisc_result_t
2364135446Strhodesdns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
2365135446Strhodes	unsigned char *ndata;
2366135446Strhodes
2367135446Strhodes	/*
2368135446Strhodes	 * Make dest a copy of source.
2369135446Strhodes	 */
2370135446Strhodes
2371135446Strhodes	REQUIRE(VALID_NAME(source));
2372135446Strhodes	REQUIRE(VALID_NAME(dest));
2373135446Strhodes	REQUIRE(target != NULL || dest->buffer != NULL);
2374135446Strhodes
2375135446Strhodes	if (target == NULL) {
2376135446Strhodes		target = dest->buffer;
2377135446Strhodes		isc_buffer_clear(dest->buffer);
2378135446Strhodes	}
2379135446Strhodes
2380135446Strhodes	REQUIRE(BINDABLE(dest));
2381135446Strhodes
2382135446Strhodes	/*
2383135446Strhodes	 * Set up.
2384135446Strhodes	 */
2385135446Strhodes	if (target->length - target->used < source->length)
2386135446Strhodes		return (ISC_R_NOSPACE);
2387135446Strhodes
2388135446Strhodes	ndata = (unsigned char *)target->base + target->used;
2389135446Strhodes	dest->ndata = target->base;
2390135446Strhodes
2391135446Strhodes	memcpy(ndata, source->ndata, source->length);
2392135446Strhodes
2393135446Strhodes	dest->ndata = ndata;
2394135446Strhodes	dest->labels = source->labels;
2395135446Strhodes	dest->length = source->length;
2396135446Strhodes	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2397135446Strhodes		dest->attributes = DNS_NAMEATTR_ABSOLUTE;
2398135446Strhodes	else
2399135446Strhodes		dest->attributes = 0;
2400135446Strhodes
2401135446Strhodes	if (dest->labels > 0 && dest->offsets != NULL) {
2402135446Strhodes		if (source->offsets != NULL)
2403135446Strhodes			memcpy(dest->offsets, source->offsets, source->labels);
2404135446Strhodes		else
2405135446Strhodes			set_offsets(dest, dest->offsets, NULL);
2406135446Strhodes	}
2407135446Strhodes
2408135446Strhodes	isc_buffer_add(target, dest->length);
2409135446Strhodes
2410135446Strhodes	return (ISC_R_SUCCESS);
2411135446Strhodes}
2412135446Strhodes
2413170222Sdougbvoid
2414170222Sdougbdns_name_destroy(void) {
2415170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
2416170222Sdougb	RUNTIME_CHECK(isc_once_do(&once, thread_key_mutex_init)
2417170222Sdougb				  == ISC_R_SUCCESS);
2418170222Sdougb
2419170222Sdougb	LOCK(&thread_key_mutex);
2420170222Sdougb	if (thread_key_initialized) {
2421170222Sdougb		isc_mem_detach(&thread_key_mctx);
2422170222Sdougb		isc_thread_key_delete(totext_filter_proc_key);
2423170222Sdougb		thread_key_initialized = 0;
2424170222Sdougb	}
2425170222Sdougb	UNLOCK(&thread_key_mutex);
2426170222Sdougb
2427170222Sdougb#endif
2428170222Sdougb}
2429