xref: /freebsd/contrib/sendmail/src/domain.c (revision f374ba41f55c1a127303d92d830dd58eef2f5243)
1 /*
2  * Copyright (c) 1998-2004, 2006, 2010 Proofpoint, Inc. and its suppliers.
3  *	All rights reserved.
4  * Copyright (c) 1986, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13 
14 #include <sendmail.h>
15 #include "map.h"
16 #if USE_EAI
17 #include <unicode/uidna.h>
18 #endif
19 
20 #if NAMED_BIND
21 SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (with name server)")
22 #else
23 SM_RCSID("@(#)$Id: domain.c,v 8.205 2013-11-22 20:51:55 ca Exp $ (without name server)")
24 #endif
25 
26 #include <sm/sendmail.h>
27 
28 #if NAMED_BIND
29 # include <arpa/inet.h>
30 # include <sm_resolve.h>
31 # if DANE
32 #  include <tls.h>
33 #  ifndef SM_NEG_TTL
34 #   define SM_NEG_TTL 60 /* "negative" TTL */
35 #  endif
36 # endif
37 
38 
39 # ifndef MXHOSTBUFSIZE
40 #  define MXHOSTBUFSIZE	(128 * MAXMXHOSTS)
41 # endif
42 
43 static char	MXHostBuf[MXHOSTBUFSIZE];
44 # if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
45 	ERROR: _MXHOSTBUFSIZE is out of range
46 # endif
47 
48 # ifndef MAXDNSRCH
49 #  define MAXDNSRCH	6	/* number of possible domains to search */
50 # endif
51 
52 # ifndef RES_DNSRCH_VARIABLE
53 #  define RES_DNSRCH_VARIABLE	_res.dnsrch
54 # endif
55 
56 # ifndef NO_DATA
57 #  define NO_DATA	NO_ADDRESS
58 # endif
59 
60 # ifndef HFIXEDSZ
61 #  define HFIXEDSZ	12	/* sizeof(HEADER) */
62 # endif
63 
64 # define MAXCNAMEDEPTH	10	/* maximum depth of CNAME recursion */
65 
66 # if defined(__RES) && (__RES >= 19940415)
67 #  define RES_UNC_T	char *
68 # else
69 #  define RES_UNC_T	unsigned char *
70 # endif
71 
72 static int	mxrand __P((char *));
73 static int	fallbackmxrr __P((int, unsigned short *, char **));
74 
75 # if DANE
76 
77 /*
78 **  TLSAADD -- add TLSA records to dane_tlsa entry
79 **
80 **	Parameters:
81 **		name -- key for stab entry (for debugging output)
82 **		dr -- DNS reply
83 **		dane_tlsa -- dane_tlsa entry
84 **		dnsrc -- DNS lookup return code (h_errno)
85 **		n -- current number of TLSA records in dane_tlsa entry
86 **		pttl -- (pointer to) TTL (in/out)
87 **		level -- recursion level (CNAMEs)
88 **
89 **	Returns:
90 **		new number of TLSA records
91 */
92 
93 static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
94 			unsigned int *, int));
95 
96 static int
97 tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
98 	const char *name;
99 	DNS_REPLY_T *dr;
100 	dane_tlsa_P dane_tlsa;
101 	int dnsrc;
102 	int n;
103 	unsigned int *pttl;
104 	int level;
105 {
106 	RESOURCE_RECORD_T *rr;
107 	unsigned int ttl;
108 	int nprev;
109 
110 	if (dnsrc != 0)
111 	{
112 		if (tTd(8, 2))
113 			sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
114 				name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
115 
116 		/* check previous error and keep the "most important" one? */
117 		dane_tlsa->dane_tlsa_dnsrc = dnsrc;
118 #  if DNSSEC_TEST
119 		if (tTd(8, 110))
120 			*pttl = tTdlevel(8)-110; /* how to make this an option? */
121 		else
122 #  endif
123 		/* "else" in #if code above */
124 			*pttl = SM_NEG_TTL;
125 		return n;
126 	}
127 	if (dr == NULL)
128 		return n;
129 	if (dr->dns_r_h.ad != 1 && Dane == DANE_SECURE)	/* not secure? */
130 		return n;
131 	ttl = *pttl;
132 
133 	/* first: try to find TLSA records */
134 	nprev = n;
135 	for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR;
136 	     rr = rr->rr_next)
137 	{
138 		int tlsa_chk;
139 
140 		if (rr->rr_type != T_TLSA)
141 		{
142 			if (rr->rr_type != T_CNAME && tTd(8, 8))
143 				sm_dprintf("tlsaadd(%s), type=%s\n", name,
144 					dns_type_to_string(rr->rr_type));
145 			continue;
146 		}
147 		tlsa_chk = dane_tlsa_chk(rr->rr_u.rr_data, rr->rr_size, name,
148 					true);
149 		if (!TLSA_IS_VALID(tlsa_chk))
150 			continue;
151 
152 		/*
153 		**  To do: the RRs should be sorted (by "complexity") --
154 		**  when more than one type is supported.
155 		*/
156 
157 		dane_tlsa->dane_tlsa_rr[n] = rr->rr_u.rr_data;
158 		dane_tlsa->dane_tlsa_len[n] = rr->rr_size;
159 		if (tTd(8, 2))
160 		{
161 			unsigned char *p;
162 
163 			p = rr->rr_u.rr_data;
164 			sm_dprintf("tlsaadd(%s), n=%d, %d-%d-%d:%02x\n", name,
165 				n, (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
166 		}
167 
168 		/* require some minimum TTL? */
169 		if (ttl > rr->rr_ttl && rr->rr_ttl > 0)
170 			ttl = rr->rr_ttl;
171 
172 		/* hack: instead of copying the data, just "take it over" */
173 		rr->rr_u.rr_data = NULL;
174 		++n;
175 	}
176 
177 	/* second: check for CNAME records, but only if no TLSA RR was added */
178 	for (rr = dr->dns_r_head; rr != NULL && n < MAX_TLSA_RR && nprev == n;
179 	     rr = rr->rr_next)
180 	{
181 		DNS_REPLY_T *drc;
182 		int err, herr;
183 
184 		if (rr->rr_type != T_CNAME)
185 			continue;
186 		if (level > 1)
187 		{
188 			if (tTd(8, 2))
189 				sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d\n",
190 					name, rr->rr_u.rr_txt, level);
191 			continue;
192 		}
193 
194 		drc = dns_lookup_int(rr->rr_u.rr_txt, C_IN, T_TLSA, 0, 0,
195 			(Dane == DANE_SECURE &&
196 			 !TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX))
197 			? SM_RES_DNSSEC : 0,
198 			RR_RAW, &err, &herr);
199 
200 		if (tTd(8, 2))
201 			sm_dprintf("tlsaadd(%s), CNAME=%s, level=%d, dr=%p, ad=%d, err=%d, herr=%d\n",
202 				name, rr->rr_u.rr_txt, level,
203 				(void *)drc, drc != NULL ? drc->dns_r_h.ad : -1,
204 				err, herr);
205 		nprev = n = tlsaadd(name, drc, dane_tlsa, herr, n, pttl,
206 				level + 1);
207 		dns_free_data(drc);
208 		drc = NULL;
209 	}
210 
211 	*pttl = ttl;
212 	return n;
213 }
214 
215 /*
216 **  GETTLSA -- get TLSA records for named host using DNS
217 **
218 **	Parameters:
219 **		host -- host
220 **		name -- name for stab entry key (if NULL: host)
221 **		pste -- (pointer to) stab entry (output)
222 **		flags -- TLSAFL*
223 **		mxttl -- TTL of MX (or host)
224 **		port -- port
225 **
226 **	Returns:
227 **		The number of TLSA records found.
228 **		<0 if there is an internal failure.
229 **
230 **	Side effects:
231 **		Enters TLSA RRs into stab().
232 **		If the DNS lookup fails temporarily, an "empty" entry is
233 **		created with that DNS error code.
234 */
235 
236 int
237 gettlsa(host, name, pste, flags, mxttl, port)
238 	char *host;
239 	char *name;
240 	STAB **pste;
241 	unsigned long flags;
242 	unsigned int mxttl;
243 	unsigned int port;
244 {
245 	DNS_REPLY_T *dr;
246 	dane_tlsa_P dane_tlsa;
247 	STAB *ste;
248 	time_t now;
249 	unsigned int ttl;
250 	int n_rrs, len, err, herr;
251 	bool isrname;
252 	char nbuf[MAXDNAME];
253 	char key[MAXDNAME];
254 
255 	SM_REQUIRE(host != NULL);
256 	if (pste != NULL)
257 		*pste = NULL;
258 	if ('\0' == *host)
259 		return 0;
260 
261 	isrname = NULL == name;
262 	if (isrname)
263 		name = host;
264 	now = 0;
265 	n_rrs = 0;
266 	dr = NULL;
267 	dane_tlsa = NULL;
268 	len = strlen(name);
269 	if (len > 1 && name[len - 1] == '.')
270 	{
271 		len--;
272 		name[len] = '\0';
273 	}
274 	else
275 		len = -1;
276 	if (0 == port || tTd(66, 10))
277 		port = 25;
278 	(void) sm_snprintf(key, sizeof(key), "_%u..%s", port, name);
279 	ste = stab(key, ST_TLSA_RR, ST_FIND);
280 	if (tTd(8, 2))
281 		sm_dprintf("gettlsa(%s, %s, ste=%p, pste=%p, flags=%lX, port=%d)\n",
282 			host, isrname ? "" : name, (void *)ste, (void *)pste,
283 			flags, port);
284 
285 	if (ste != NULL)
286 	{
287 		dane_tlsa = ste->s_tlsa;
288 		if ((TLSAFLADMX & flags) != 0)
289 			TLSA_CLR_FL(ste->s_tlsa, TLSAFLNOADMX);
290 	}
291 
292 	/* Do not reload TLSA RRs if the MX RRs were not securely retrieved. */
293 	if (pste != NULL
294 	    && dane_tlsa != NULL && TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX)
295 	    && DANE_SECURE == Dane)
296 		goto end;
297 
298 	if (ste != NULL)
299 	{
300 		SM_ASSERT(dane_tlsa != NULL);
301 		now = curtime();
302 		if (dane_tlsa->dane_tlsa_exp <= now
303 		    && 0 == (TLSAFLNOEXP & flags))
304 			dane_tlsa_clr(dane_tlsa);
305 		else
306 		{
307 			n_rrs = dane_tlsa->dane_tlsa_n;
308 			goto end;
309 		}
310 	}
311 
312 	if (dane_tlsa == NULL)
313 	{
314 		dane_tlsa = (dane_tlsa_P) sm_malloc(sizeof(*dane_tlsa));
315 		if (dane_tlsa == NULL)
316 		{
317 			n_rrs = -ENOMEM;
318 			goto end;
319 		}
320 		memset(dane_tlsa, '\0', sizeof(*dane_tlsa));
321 	}
322 
323 	/* There are flags to store -- just set those, do nothing else. */
324 	if (TLSA_STORE_FL(flags))
325 	{
326 		dane_tlsa->dane_tlsa_flags = flags;
327 		ttl = mxttl > 0 ? mxttl: SM_DEFAULT_TTL;
328 		goto done;
329 	}
330 
331 	(void) sm_snprintf(nbuf, sizeof(nbuf), "_%u._tcp.%s", port, host);
332 	dr = dns_lookup_int(nbuf, C_IN, T_TLSA, 0, 0,
333 		TLSA_IS_FL(dane_tlsa, TLSAFLNOADMX) ? 0 : SM_RES_DNSSEC,
334 		RR_RAW, &err, &herr);
335 	if (tTd(8, 2))
336 		sm_dprintf("gettlsa(%s), dr=%p, ad=%d, err=%d, herr=%d\n", host,
337 			(void *)dr, dr != NULL ? dr->dns_r_h.ad : -1, err, herr);
338 	ttl = UINT_MAX;
339 	n_rrs = tlsaadd(key, dr, dane_tlsa, herr, n_rrs, &ttl, 0);
340 
341 	/* no valid entries found? */
342 	if (n_rrs == 0 && !TLSA_RR_TEMPFAIL(dane_tlsa))
343 	{
344 		if (tTd(8, 2))
345 			sm_dprintf("gettlsa(%s), n_rrs=%d, herr=%d, status=NOT_ADDED\n",
346 				host, n_rrs, dane_tlsa->dane_tlsa_dnsrc);
347 		goto cleanup;
348 	}
349 
350   done:
351 	dane_tlsa->dane_tlsa_n = n_rrs;
352 	if (!isrname)
353 	{
354 		SM_FREE(dane_tlsa->dane_tlsa_sni);
355 		dane_tlsa->dane_tlsa_sni = sm_strdup(host);
356 	}
357 	if (NULL == ste)
358 	{
359 		ste = stab(key, ST_TLSA_RR, ST_ENTER);
360 		if (NULL == ste)
361 			goto error;
362 	}
363 	ste->s_tlsa = dane_tlsa;
364 	if (now == 0)
365 		now = curtime();
366 	dane_tlsa->dane_tlsa_exp = now + SM_MIN(ttl, SM_DEFAULT_TTL);
367 	dns_free_data(dr);
368 	dr = NULL;
369 	goto end;
370 
371   error:
372 	if (tTd(8, 2))
373 		sm_dprintf("gettlsa(%s, %s), status=error\n", host, key);
374 	n_rrs = -1;
375   cleanup:
376 	if (NULL == ste)
377 		dane_tlsa_free(dane_tlsa);
378 	dns_free_data(dr);
379 	dr = NULL;
380 
381   end:
382 	if (pste != NULL && ste != NULL)
383 		*pste = ste;
384 	if (len > 0)
385 		host[len] = '.';
386 	return n_rrs;
387 }
388 # endif /* DANE */
389 
390 /*
391 **  GETFALLBACKMXRR -- get MX resource records for fallback MX host.
392 **
393 **	We have to initialize this once before doing anything else.
394 **	Moreover, we have to repeat this from time to time to avoid
395 **	stale data, e.g., in persistent queue runners.
396 **	This should be done in a parent process so the child
397 **	processes have the right data.
398 **
399 **	Parameters:
400 **		host -- the name of the fallback MX host.
401 **
402 **	Returns:
403 **		number of MX records.
404 **
405 **	Side Effects:
406 **		Populates NumFallbackMXHosts and fbhosts.
407 **		Sets renewal time (based on TTL).
408 */
409 
410 int NumFallbackMXHosts = 0;	/* Number of fallback MX hosts (after MX expansion) */
411 static char *fbhosts[MAXMXHOSTS + 1];
412 
413 int
414 getfallbackmxrr(host)
415 	char *host;
416 {
417 	int i, rcode;
418 	int ttl;
419 	static time_t renew = 0;
420 
421 # if 0
422 	/* This is currently done before this function is called. */
423 	if (SM_IS_EMPTY(host))
424 		return 0;
425 # endif /* 0 */
426 	if (NumFallbackMXHosts > 0 && renew > curtime())
427 		return NumFallbackMXHosts;
428 
429 	/* for DANE we need to invoke getmxrr() to get the TLSA RRs. */
430 # if !DANE
431 	if (host[0] == '[')
432 	{
433 		fbhosts[0] = host;
434 		NumFallbackMXHosts = 1;
435 	}
436 	else
437 # endif
438 	{
439 		/* free old data */
440 		for (i = 0; i < NumFallbackMXHosts; i++)
441 			sm_free(fbhosts[i]);
442 
443 		/*
444 		**  Get new data.
445 		**  Note: passing 0 as port is not correct but we cannot
446 		**  determine the port number as there is no mailer.
447 		*/
448 
449 		NumFallbackMXHosts = getmxrr(host, fbhosts, NULL,
450 # if DANE
451 					(DANE_SECURE == Dane) ?  ISAD :
452 # endif
453 					0,
454 					&rcode, &ttl, 0);
455 		renew = curtime() + ttl;
456 		for (i = 0; i < NumFallbackMXHosts; i++)
457 			fbhosts[i] = newstr(fbhosts[i]);
458 	}
459 	if (NumFallbackMXHosts == NULLMX)
460 		NumFallbackMXHosts = 0;
461 	return NumFallbackMXHosts;
462 }
463 
464 /*
465 **  FALLBACKMXRR -- add MX resource records for fallback MX host to list.
466 **
467 **	Parameters:
468 **		nmx -- current number of MX records.
469 **		prefs -- array of preferences.
470 **		mxhosts -- array of MX hosts (maximum size: MAXMXHOSTS)
471 **
472 **	Returns:
473 **		new number of MX records.
474 **
475 **	Side Effects:
476 **		If FallbackMX was set, it appends the MX records for
477 **		that host to mxhosts (and modifies prefs accordingly).
478 */
479 
480 static int
481 fallbackmxrr(nmx, prefs, mxhosts)
482 	int nmx;
483 	unsigned short *prefs;
484 	char **mxhosts;
485 {
486 	int i;
487 
488 	for (i = 0; i < NumFallbackMXHosts && nmx < MAXMXHOSTS; i++)
489 	{
490 		if (nmx > 0)
491 			prefs[nmx] = prefs[nmx - 1] + 1;
492 		else
493 			prefs[nmx] = 0;
494 		mxhosts[nmx++] = fbhosts[i];
495 	}
496 	return nmx;
497 }
498 
499 # if USE_EAI
500 
501 /*
502 **  HN2ALABEL -- convert hostname in U-label format to A-label format
503 **
504 **	Parameters:
505 **		hostname -- hostname in U-label format
506 **
507 **	Returns:
508 **		hostname in A-label format in a local static buffer.
509 **		It must be copied before the function is called again.
510 */
511 
512 const char *
513 hn2alabel(hostname)
514 	const char *hostname;
515 {
516 	UErrorCode error = U_ZERO_ERROR;
517 	UIDNAInfo info = UIDNA_INFO_INITIALIZER;
518 	UIDNA *idna;
519 	static char buf[MAXNAME_I];	/* XXX ??? */
520 
521 	if (addr_is_ascii(hostname))
522 		return hostname;
523 	idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
524 	(void) uidna_nameToASCII_UTF8(idna, hostname, strlen(hostname),
525 				     buf, sizeof(buf) - 1,
526 				     &info, &error);
527 	uidna_close(idna);
528 	return buf;
529 }
530 # endif /* USE_EAI */
531 
532 /*
533 **  GETMXRR -- get MX resource records for a domain
534 **
535 **	Parameters:
536 **		host -- the name of the host to MX [must be x]
537 **		mxhosts -- a pointer to a return buffer of MX records.
538 **		mxprefs -- a pointer to a return buffer of MX preferences.
539 **			If NULL, don't try to populate.
540 **		flags -- flags:
541 **			DROPLOCALHOSt -- If true, all MX records less preferred
542 **			than the local host (as determined by $=w) will
543 **			be discarded.
544 **			TRYFALLBACK -- add also fallback MX host?
545 **			ISAD -- host lookup was secure?
546 **		rcode -- a pointer to an EX_ status code.
547 **		pttl -- pointer to return TTL (can be NULL).
548 **
549 **	Returns:
550 **		The number of MX records found.
551 **		-1 if there is an internal failure.
552 **		If no MX records are found, mxhosts[0] is set to host
553 **			and 1 is returned.
554 **
555 **	Side Effects:
556 **		The entries made for mxhosts point to a static array
557 **		MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
558 **		if it must be preserved across calls to this function.
559 */
560 
561 int
562 getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
563 	char *host;
564 	char **mxhosts;
565 	unsigned short *mxprefs;
566 	unsigned int flags;
567 	int *rcode;
568 	int *pttl;
569 	int port;
570 {
571 	register unsigned char *eom, *cp;
572 	register int i, j, n;
573 	int nmx = 0;
574 	register char *bp;
575 	HEADER *hp;
576 	querybuf answer;
577 	int ancount, qdcount, buflen;
578 	bool seenlocal = false;
579 	unsigned short pref, type;
580 	unsigned short localpref = 256;
581 	char *fallbackMX = FallbackMX;
582 	bool trycanon = false;
583 	unsigned short *prefs;
584 	int (*resfunc) __P((const char *, int, int, u_char *, int));
585 	unsigned short prefer[MAXMXHOSTS];
586 	int weight[MAXMXHOSTS];
587 	int ttl = 0;
588 	bool ad;
589 	bool seennullmx = false;
590 	extern int res_query __P((const char *, int, int, u_char *, int));
591 	extern int res_search __P((const char *, int, int , u_char *, int));
592 # if DANE
593 	bool cname2mx;
594 	char qname[MAXNAME];	/* EAI: copy of host: ok? */
595 	unsigned long old_options = 0;
596 # endif
597 
598 	if (tTd(8, 2))
599 		sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
600 			   host, (flags & DROPLOCALHOST) != 0, flags, port);
601 	ad = (flags & ISAD) != 0;
602 	*rcode = EX_OK;
603 	if (pttl != NULL)
604 		*pttl = SM_DEFAULT_TTL;
605 	if (*host == '\0')
606 		return 0;
607 # if DANE
608 	cname2mx = false;
609 	qname[0] = '\0';
610 	old_options = _res.options;
611 	if (ad)
612 		_res.options |= SM_RES_DNSSEC;
613 # endif
614 
615 	if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
616 	     wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
617 	{
618 		/* don't use fallback for this pass */
619 		fallbackMX = NULL;
620 	}
621 
622 	if (mxprefs != NULL)
623 		prefs = mxprefs;
624 	else
625 		prefs = prefer;
626 
627 	/* efficiency hack -- numeric or non-MX lookups */
628 	if (host[0] == '[')
629 		goto punt;
630 
631 # if DANE
632 	/*
633 	**  NOTE: This only works if nocanonify is used,
634 	**  otherwise the name is already rewritten.
635 	*/
636 
637 	/* always or only when "needed"? */
638 	if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
639 		(void) sm_strlcpy(qname, host, sizeof(qname));
640 # endif /* DANE */
641 
642 # if USE_EAI
643 	if (!addr_is_ascii(host))
644 	{
645 		/* XXX memory leak? */
646 		host = sm_rpool_strdup_x(CurEnv->e_rpool, hn2alabel(host));
647 	}
648 # endif /* USE_EAI */
649 
650 	/*
651 	**  If we don't have MX records in our host switch, don't
652 	**  try for MX records.  Note that this really isn't "right",
653 	**  since we might be set up to try NIS first and then DNS;
654 	**  if the host is found in NIS we really shouldn't be doing
655 	**  MX lookups.  However, that should be a degenerate case.
656 	*/
657 
658 	if (!UseNameServer)
659 		goto punt;
660 	if (HasWildcardMX && ConfigLevel >= 6)
661 		resfunc = res_query;
662 	else
663 		resfunc = res_search;
664 # if DNSSEC_TEST
665 	if (tTd(8, 110))
666 		resfunc = tstdns_search;
667 # endif
668 
669 	errno = 0;
670 	hp = (HEADER *)&answer;
671 	n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
672 		       sizeof(answer));
673 	if (n < 0)
674 	{
675 		if (tTd(8, 1))
676 # if DNSSEC_TEST
677 			sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
678 				host, errno, strerror(errno),
679 				h_errno, herrno2txt(h_errno));
680 # else
681 			sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
682 				host, h_errno);
683 # endif
684 		switch (h_errno)
685 		{
686 		  case NO_DATA:
687 			trycanon = true;
688 			/* FALLTHROUGH */
689 
690 		  case NO_RECOVERY:
691 			/* no MX data on this host */
692 			goto punt;
693 
694 		  case HOST_NOT_FOUND:
695 # if BROKEN_RES_SEARCH
696 		  case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
697 # endif
698 			/* host doesn't exist in DNS; might be in /etc/hosts */
699 			trycanon = true;
700 			*rcode = EX_NOHOST;
701 			goto punt;
702 
703 		  case TRY_AGAIN:
704 		  case -1:
705 			/* couldn't connect to the name server */
706 			if (fallbackMX != NULL)
707 			{
708 				/* name server is hosed -- push to fallback */
709 				nmx = fallbackmxrr(nmx, prefs, mxhosts);
710 				goto done;
711 			}
712 			/* it might come up later; better queue it up */
713 			*rcode = EX_TEMPFAIL;
714 			break;
715 
716 		  default:
717 			syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
718 				host, h_errno);
719 			*rcode = EX_OSERR;
720 			break;
721 		}
722 
723 		/* irreconcilable differences */
724 		goto error;
725 	}
726 
727 	ad = ad && hp->ad;
728 	if (tTd(8, 2))
729 		sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
730 
731 	/* avoid problems after truncation in tcp packets */
732 	if (n > sizeof(answer))
733 		n = sizeof(answer);
734 
735 	/* find first satisfactory answer */
736 	cp = (unsigned char *)&answer + HFIXEDSZ;
737 	eom = (unsigned char *)&answer + n;
738 
739 	for (qdcount = ntohs((unsigned short) hp->qdcount);
740 	     qdcount--;
741 	     cp += n + QFIXEDSZ)
742 	{
743 		if ((n = dn_skipname(cp, eom)) < 0)
744 			goto punt;
745 	}
746 
747 	/* NOTE: see definition of MXHostBuf! */
748 	buflen = sizeof(MXHostBuf) - 1;
749 	SM_ASSERT(buflen > 0);
750 	bp = MXHostBuf;
751 	ancount = ntohs((unsigned short) hp->ancount);
752 
753 	/* See RFC 1035 for layout of RRs. */
754 	/* XXX leave room for FallbackMX ? */
755 	while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
756 	{
757 		if ((n = dn_expand((unsigned char *)&answer, eom, cp,
758 				   (RES_UNC_T) bp, buflen)) < 0)
759 			break;
760 		cp += n;
761 		GETSHORT(type, cp);
762 		cp += INT16SZ;		/* skip over class */
763 		GETLONG(ttl, cp);
764 		GETSHORT(n, cp);	/* rdlength */
765 # if DANE
766 		if (type == T_CNAME)
767 			cname2mx = true;
768 # endif
769 		if (type != T_MX)
770 		{
771 			if ((tTd(8, 8) || _res.options & RES_DEBUG)
772 # if DANE
773 			    && type != T_RRSIG
774 # endif
775 			    )
776 				sm_dprintf("unexpected answer type %s, size %d\n",
777 					dns_type_to_string(type), n);
778 			cp += n;
779 			continue;
780 		}
781 		GETSHORT(pref, cp);
782 		if ((n = dn_expand((unsigned char *)&answer, eom, cp,
783 				   (RES_UNC_T) bp, buflen)) < 0)
784 			break;
785 		cp += n;
786 		n = strlen(bp);
787 
788 		/* Support for RFC7505 "MX 0 ." */
789 		if (pref == 0 && *bp == '\0')
790 			seennullmx = true;
791 
792 		if (wordinclass(bp, 'w'))
793 		{
794 			if (tTd(8, 3))
795 				sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
796 					bp, pref);
797 			if ((flags & DROPLOCALHOST) != 0)
798 			{
799 				if (!seenlocal || pref < localpref)
800 					localpref = pref;
801 				seenlocal = true;
802 				continue;
803 			}
804 			weight[nmx] = 0;
805 		}
806 		else
807 			weight[nmx] = mxrand(bp);
808 		prefs[nmx] = pref;
809 		mxhosts[nmx++] = bp;
810 # if DANE
811 		if (CHK_DANE(Dane) && port >= 0)
812 		{
813 			int nrr;
814 			unsigned long flags;
815 
816 			flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
817 			nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
818 
819 			/* Only check qname if no TLSA RRs were found */
820 			if (0 == nrr && cname2mx && '\0' != qname[0] &&
821 			    strcmp(qname, bp))
822 				gettlsa(qname, bp, NULL, flags, ttl, port);
823 			/* XXX is this the right ad flag? */
824 		}
825 # endif
826 
827 		/*
828 		**  Note: n can be 0 for something like:
829 		**  host MX 0 .
830 		**  See RFC 7505
831 		*/
832 
833 		bp += n;
834 		if (0 == n || bp[-1] != '.')
835 		{
836 			*bp++ = '.';
837 			n++;
838 		}
839 		*bp++ = '\0';
840 		if (buflen < n + 1)
841 		{
842 			/* don't want to wrap buflen */
843 			break;
844 		}
845 		buflen -= n + 1;
846 	}
847 
848 	/* Support for RFC7505 "MX 0 ." */
849 	if (seennullmx && nmx == 1)
850 	{
851 		if (tTd(8, 4))
852 			sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
853 		*rcode = EX_UNAVAILABLE;
854 		return NULLMX;
855 	}
856 
857 	/* return only one TTL entry, that should be sufficient */
858 	if (ttl > 0 && pttl != NULL)
859 		*pttl = ttl;
860 
861 	/* sort the records */
862 	for (i = 0; i < nmx; i++)
863 	{
864 		for (j = i + 1; j < nmx; j++)
865 		{
866 			if (prefs[i] > prefs[j] ||
867 			    (prefs[i] == prefs[j] && weight[i] > weight[j]))
868 			{
869 				register int temp;
870 				register char *temp1;
871 
872 				temp = prefs[i];
873 				prefs[i] = prefs[j];
874 				prefs[j] = temp;
875 				temp1 = mxhosts[i];
876 				mxhosts[i] = mxhosts[j];
877 				mxhosts[j] = temp1;
878 				temp = weight[i];
879 				weight[i] = weight[j];
880 				weight[j] = temp;
881 			}
882 		}
883 		if (seenlocal && prefs[i] >= localpref)
884 		{
885 			/* truncate higher preference part of list */
886 			nmx = i;
887 		}
888 	}
889 
890 	/* delete duplicates from list (yes, some bozos have duplicates) */
891 	for (i = 0; i < nmx - 1; )
892 	{
893 		if (!SM_STRCASEEQ(mxhosts[i], mxhosts[i + 1]))
894 			i++;
895 		else
896 		{
897 			/* compress out duplicate */
898 			for (j = i + 1; j < nmx; j++)
899 			{
900 				mxhosts[j] = mxhosts[j + 1];
901 				prefs[j] = prefs[j + 1];
902 			}
903 			nmx--;
904 		}
905 	}
906 
907 	if (nmx == 0)
908 	{
909 punt:
910 		if (seenlocal)
911 		{
912 			struct hostent *h = NULL;
913 
914 			/*
915 			**  If we have deleted all MX entries, this is
916 			**  an error -- we should NEVER send to a host that
917 			**  has an MX, and this should have been caught
918 			**  earlier in the config file.
919 			**
920 			**  Some sites prefer to go ahead and try the
921 			**  A record anyway; that case is handled by
922 			**  setting TryNullMXList.  I believe this is a
923 			**  bad idea, but it's up to you....
924 			*/
925 
926 			if (TryNullMXList)
927 			{
928 				SM_SET_H_ERRNO(0);
929 				errno = 0;
930 				h = sm_gethostbyname(host, AF_INET);
931 				if (h == NULL)
932 				{
933 					if (errno == ETIMEDOUT ||
934 					    h_errno == TRY_AGAIN ||
935 					    (errno == ECONNREFUSED &&
936 					     UseNameServer))
937 					{
938 						*rcode = EX_TEMPFAIL;
939 						goto error;
940 					}
941 # if NETINET6
942 					SM_SET_H_ERRNO(0);
943 					errno = 0;
944 					h = sm_gethostbyname(host, AF_INET6);
945 					if (h == NULL &&
946 					    (errno == ETIMEDOUT ||
947 					     h_errno == TRY_AGAIN ||
948 					     (errno == ECONNREFUSED &&
949 					      UseNameServer)))
950 					{
951 						*rcode = EX_TEMPFAIL;
952 						goto error;
953 					}
954 # endif /* NETINET6 */
955 				}
956 			}
957 
958 			if (h == NULL)
959 			{
960 				*rcode = EX_CONFIG;
961 				syserr("MX list for %s points back to %s",
962 				       host, MyHostName);
963 				goto error;
964 			}
965 # if NETINET6
966 			freehostent(h);
967 			h = NULL;
968 # endif
969 		}
970 		if (strlen(host) >= sizeof(MXHostBuf))
971 		{
972 			*rcode = EX_CONFIG;
973 			syserr("Host name %s too long",
974 			       shortenstring(host, MAXSHORTSTR));
975 			goto error;
976 		}
977 		(void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
978 		mxhosts[0] = MXHostBuf;
979 		prefs[0] = 0;
980 		if (host[0] == '[')
981 		{
982 			register char *p;
983 # if NETINET6
984 			struct sockaddr_in6 tmp6;
985 # endif
986 
987 			/* this may be an MX suppression-style address */
988 			p = strchr(MXHostBuf, ']');
989 			if (p != NULL)
990 			{
991 				*p = '\0';
992 
993 				if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
994 				{
995 					nmx++;
996 					*p = ']';
997 				}
998 # if NETINET6
999 				else if (anynet_pton(AF_INET6, &MXHostBuf[1],
1000 						     &tmp6.sin6_addr) == 1)
1001 				{
1002 					nmx++;
1003 					*p = ']';
1004 				}
1005 # endif /* NETINET6 */
1006 				else
1007 				{
1008 # if USE_EAI
1009 					char *hn;
1010 
1011 					hn = MXHostBuf + 1;
1012 					if (!addr_is_ascii(hn))
1013 					{
1014 						const char *ahn;
1015 
1016 						ahn = hn2alabel(hn);
1017 						if (strlen(ahn) >= sizeof(MXHostBuf) - 1)
1018 						{
1019 							*rcode = EX_CONFIG;
1020 							syserr("Encoded host name %s too long",
1021 							       shortenstring(ahn, MAXSHORTSTR));
1022 							goto error;
1023 						}
1024 						(void) sm_strlcpy(hn, ahn, sizeof(MXHostBuf) - 1);
1025 					}
1026 # endif /* USE_EAI */
1027 					trycanon = true;
1028 					mxhosts[0]++;
1029 				}
1030 			}
1031 		}
1032 		if (trycanon &&
1033 		    (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
1034 				pttl)) != HOST_NOTFOUND)
1035 		{
1036 			/* XXX MXHostBuf == "" ?  is that possible? */
1037 			bp = &MXHostBuf[strlen(MXHostBuf)];
1038 			if (bp[-1] != '.')
1039 			{
1040 				*bp++ = '.';
1041 				*bp = '\0';
1042 			}
1043 			nmx = 1;
1044 # if DANE
1045 			if (tTd(8, 3))
1046 				sm_dprintf("getmxrr=%s, getcanonname=%d\n",
1047 					mxhosts[0], n);
1048 			if (CHK_DANE(Dane) && port >= 0)
1049 			{
1050 				int nrr;
1051 				unsigned long flags;
1052 				unsigned int cttl;
1053 
1054 				if (pttl != NULL)
1055 					cttl = *pttl;
1056 				else if (ttl > 0)
1057 					cttl = ttl;
1058 				else
1059 					cttl = SM_DEFAULT_TTL;
1060 
1061 				flags = (ad && n == HOST_SECURE)
1062 					? TLSAFLADMX : TLSAFLNOADMX;
1063 				nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
1064 						cttl, port);
1065 
1066 				/*
1067 				**  Only check qname if no TLSA RRs were found
1068 				**  XXX: what about (temp) DNS errors?
1069 				*/
1070 
1071 				if (0 == nrr && '\0' != qname[0] &&
1072 				    strcmp(qname, mxhosts[0]))
1073 					gettlsa(qname, mxhosts[0], NULL, flags,
1074 						cttl, port);
1075 				/* XXX is this the right ad flag? */
1076 			}
1077 # endif
1078 		}
1079 	}
1080 
1081 	/* if we have a default lowest preference, include that */
1082 	if (fallbackMX != NULL && !seenlocal)
1083 	{
1084 		/* TODO: DNSsec status of fallbacks */
1085 		nmx = fallbackmxrr(nmx, prefs, mxhosts);
1086 	}
1087     done:
1088 # if DANE
1089 	_res.options = old_options;
1090 # endif
1091 	return nmx;
1092 
1093    error:
1094 # if DANE
1095 	_res.options = old_options;
1096 # endif
1097 	return -1;
1098 }
1099 
1100 /*
1101 **  MXRAND -- create a randomizer for equal MX preferences
1102 **
1103 **	If two MX hosts have equal preferences we want to randomize
1104 **	the selection.  But in order for signatures to be the same,
1105 **	we need to randomize the same way each time.  This function
1106 **	computes a pseudo-random hash function from the host name.
1107 **
1108 **	Parameters:
1109 **		host -- the name of the host.
1110 **
1111 **	Returns:
1112 **		A random but repeatable value based on the host name.
1113 */
1114 
1115 static int
1116 mxrand(host)
1117 	register char *host;
1118 {
1119 	int hfunc;
1120 	static unsigned int seed;
1121 
1122 	if (seed == 0)
1123 	{
1124 		seed = (int) curtime() & 0xffff;
1125 		if (seed == 0)
1126 			seed++;
1127 	}
1128 
1129 	if (tTd(17, 9))
1130 		sm_dprintf("mxrand(%s)", host);
1131 
1132 	hfunc = seed;
1133 	while (*host != '\0')
1134 	{
1135 		int c = *host++;
1136 
1137 		if (isascii(c) && isupper(c))
1138 			c = tolower(c);
1139 		hfunc = ((hfunc << 1) ^ c) % 2003;
1140 	}
1141 
1142 	hfunc &= 0xff;
1143 	hfunc++;
1144 
1145 	if (tTd(17, 9))
1146 		sm_dprintf(" = %d\n", hfunc);
1147 	return hfunc;
1148 }
1149 /*
1150 **  BESTMX -- find the best MX for a name
1151 **
1152 **	This is really a hack, but I don't see any obvious way
1153 **	to generalize it at the moment.
1154 */
1155 
1156 /* ARGSUSED3 */
1157 char *
1158 bestmx_map_lookup(map, name, av, statp)
1159 	MAP *map;
1160 	char *name;
1161 	char **av;
1162 	int *statp;
1163 {
1164 	int nmx;
1165 	int saveopts = _res.options;
1166 	int i;
1167 	ssize_t len = 0;
1168 	char *result;
1169 	char *mxhosts[MAXMXHOSTS + 1];
1170 # if _FFR_BESTMX_BETTER_TRUNCATION
1171 	char *buf;
1172 # else
1173 	char *p;
1174 	char buf[PSBUFSIZE / 2];
1175 # endif
1176 
1177 	_res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
1178 	nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
1179 	_res.options = saveopts;
1180 	if (nmx <= 0)
1181 		return NULL;
1182 	if (bitset(MF_MATCHONLY, map->map_mflags))
1183 		return map_rewrite(map, name, strlen(name), NULL);
1184 	if ((map->map_coldelim == '\0') || (nmx == 1))
1185 		return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
1186 
1187 	/*
1188 	**  We were given a -z flag (return all MXs) and there are multiple
1189 	**  ones.  We need to build them all into a list.
1190 	*/
1191 
1192 # if _FFR_BESTMX_BETTER_TRUNCATION
1193 	for (i = 0; i < nmx; i++)
1194 	{
1195 		if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1196 		{
1197 			syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1198 			       mxhosts[i], map->map_coldelim);
1199 			return NULL;
1200 		}
1201 		len += strlen(mxhosts[i]) + 1;
1202 		if (len < 0)
1203 		{
1204 			len -= strlen(mxhosts[i]) + 1;
1205 			break;
1206 		}
1207 	}
1208 	buf = (char *) sm_malloc(len);
1209 	if (buf == NULL)
1210 	{
1211 		*statp = EX_UNAVAILABLE;
1212 		return NULL;
1213 	}
1214 	*buf = '\0';
1215 	for (i = 0; i < nmx; i++)
1216 	{
1217 		int end;
1218 
1219 		end = sm_strlcat(buf, mxhosts[i], len);
1220 		if (i != nmx && end + 1 < len)
1221 		{
1222 			buf[end] = map->map_coldelim;
1223 			buf[end + 1] = '\0';
1224 		}
1225 	}
1226 
1227 	/* Cleanly truncate for rulesets */
1228 	truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
1229 # else /* _FFR_BESTMX_BETTER_TRUNCATION */
1230 	p = buf;
1231 	for (i = 0; i < nmx; i++)
1232 	{
1233 		size_t slen;
1234 
1235 		if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1236 		{
1237 			syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1238 			       mxhosts[i], map->map_coldelim);
1239 			return NULL;
1240 		}
1241 		slen = strlen(mxhosts[i]);
1242 		if (len + slen + 2 > sizeof(buf))
1243 			break;
1244 		if (i > 0)
1245 		{
1246 			*p++ = map->map_coldelim;
1247 			len++;
1248 		}
1249 		(void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len);
1250 		p += slen;
1251 		len += slen;
1252 	}
1253 # endif /* _FFR_BESTMX_BETTER_TRUNCATION */
1254 
1255 	result = map_rewrite(map, buf, len, av);
1256 # if _FFR_BESTMX_BETTER_TRUNCATION
1257 	sm_free(buf);
1258 # endif
1259 	return result;
1260 }
1261 /*
1262 **  DNS_GETCANONNAME -- get the canonical name for named host using DNS
1263 **
1264 **	This algorithm tries to be smart about wildcard MX records.
1265 **	This is hard to do because DNS doesn't tell is if we matched
1266 **	against a wildcard or a specific MX.
1267 **
1268 **	We always prefer A & CNAME records, since these are presumed
1269 **	to be specific.
1270 **
1271 **	If we match an MX in one pass and lose it in the next, we use
1272 **	the old one.  For example, consider an MX matching *.FOO.BAR.COM.
1273 **	A hostname bletch.foo.bar.com will match against this MX, but
1274 **	will stop matching when we try bletch.bar.com -- so we know
1275 **	that bletch.foo.bar.com must have been right.  This fails if
1276 **	there was also an MX record matching *.BAR.COM, but there are
1277 **	some things that just can't be fixed.
1278 **
1279 **	Parameters:
1280 **		host -- a buffer containing the name of the host.
1281 **			This is a value-result parameter.
1282 **		hbsize -- the size of the host buffer.
1283 **		trymx -- if set, try MX records as well as A and CNAME.
1284 **		statp -- pointer to place to store status.
1285 **		pttl -- pointer to return TTL (can be NULL).
1286 **
1287 **	Returns:
1288 **		>0 -- if the host was found.
1289 **		0 -- otherwise.
1290 */
1291 
1292 int
1293 dns_getcanonname(host, hbsize, trymx, statp, pttl)
1294 	char *host;
1295 	int hbsize;
1296 	bool trymx;
1297 	int *statp;
1298 	int *pttl;
1299 {
1300 	register unsigned char *eom, *ap;
1301 	register char *cp;
1302 	register int n;
1303 	HEADER *hp;
1304 	querybuf answer;
1305 	int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
1306 	char **domain;
1307 	char *dp;
1308 	char *mxmatch;
1309 	bool amatch, gotmx, ad;
1310 	char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
1311 # if DNSSEC_TEST
1312 #  define ADDSL	1 /* NameSearchList may add another entry to searchlist! */
1313 # else
1314 #  define ADDSL	0
1315 # endif
1316 	char *searchlist[MAXDNSRCH + 2 + ADDSL];
1317 # define SLSIZE SM_ARRAY_SIZE(searchlist)
1318 	int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
1319 # if DANE
1320 	unsigned long old_options = 0;
1321 # endif
1322 
1323 	ttl = 0;
1324 	gotmx = false;
1325 	ad = true;
1326 	if (tTd(8, 2))
1327 		sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
1328 
1329 	if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1330 	{
1331 		*statp = EX_UNAVAILABLE;
1332 		return HOST_NOTFOUND;
1333 	}
1334 
1335 # if DANE
1336 	old_options = _res.options;
1337 	if (DANE_SECURE == Dane)
1338 		_res.options |= SM_RES_DNSSEC;
1339 # endif
1340 
1341 	*statp = EX_OK;
1342 	resqdomain = res_querydomain;
1343 # if DNSSEC_TEST
1344 	if (tTd(8, 110))
1345 		resqdomain = tstdns_querydomain;
1346 # endif
1347 
1348 	/*
1349 	**  Initialize domain search list.  If there is at least one
1350 	**  dot in the name, search the unmodified name first so we
1351 	**  find "vse.CS" in Czechoslovakia instead of in the local
1352 	**  domain (e.g., vse.CS.Berkeley.EDU).  Note that there is no
1353 	**  longer a country named Czechoslovakia but this type of problem
1354 	**  is still present.
1355 	**
1356 	**  Older versions of the resolver could create this
1357 	**  list by tearing apart the host name.
1358 	*/
1359 
1360 	loopcnt = 0;
1361 cnameloop:
1362 	/* Check for dots in the name */
1363 	for (cp = host, n = 0; *cp != '\0'; cp++)
1364 		if (*cp == '.')
1365 			n++;
1366 
1367 	/*
1368 	**  Build the search list.
1369 	**	If there is at least one dot in name, start with a null
1370 	**	domain to search the unmodified name first.
1371 	**	If name does not end with a dot and search up local domain
1372 	**	tree desired, append each local domain component to the
1373 	**	search list; if name contains no dots and default domain
1374 	**	name is desired, append default domain name to search list;
1375 	**	else if name ends in a dot, remove that dot.
1376 	*/
1377 
1378 	sli = 0;
1379 	if (n > 0)
1380 		searchlist[sli++] = "";
1381 # if DNSSEC_TEST
1382 	if (NameSearchList != NULL)
1383 	{
1384 		SM_ASSERT(sli < SLSIZE);
1385 		searchlist[sli++] = NameSearchList;
1386 	}
1387 # endif
1388 	if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
1389 	{
1390 		/* make sure there are less than MAXDNSRCH domains */
1391 		for (domain = RES_DNSRCH_VARIABLE, ret = 0;
1392 		     *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
1393 		     ret++)
1394 			searchlist[sli++] = *domain++;
1395 	}
1396 	else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
1397 	{
1398 		SM_ASSERT(sli < SLSIZE);
1399 		searchlist[sli++] = _res.defdname;
1400 	}
1401 	else if (*cp == '.')
1402 	{
1403 		*cp = '\0';
1404 	}
1405 	SM_ASSERT(sli < SLSIZE);
1406 	searchlist[sli] = NULL;
1407 
1408 	/*
1409 	**  Now loop through the search list, appending each domain in turn
1410 	**  name and searching for a match.
1411 	*/
1412 
1413 	mxmatch = NULL;
1414 	initial = T_A;
1415 # if NETINET6
1416 	if (InetMode == AF_INET6)
1417 		initial = T_AAAA;
1418 # endif
1419 	qtype = initial;
1420 
1421 	for (sli = 0; sli < SLSIZE; )
1422 	{
1423 		dp = searchlist[sli];
1424 		if (NULL == dp)
1425 			break;
1426 		if (qtype == initial)
1427 			gotmx = false;
1428 		if (tTd(8, 5))
1429 			sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
1430 				host, dp,
1431 # if NETINET6
1432 				qtype == T_AAAA ? "AAAA" :
1433 # endif
1434 				qtype == T_A ? "A" :
1435 				qtype == T_MX ? "MX" :
1436 				"???");
1437 		errno = 0;
1438 		hp = (HEADER *) &answer;
1439 		ret = (*resqdomain)(host, dp, C_IN, qtype,
1440 				      answer.qb2, sizeof(answer.qb2));
1441 		if (ret <= 0)
1442 		{
1443 			int save_errno = errno;
1444 
1445 			if (tTd(8, 7))
1446 				sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
1447 					   save_errno, h_errno);
1448 
1449 			if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
1450 			{
1451 				/*
1452 				**  the name server seems to be down or broken.
1453 				*/
1454 
1455 				SM_SET_H_ERRNO(TRY_AGAIN);
1456 				if (*dp == '\0')
1457 				{
1458 					if (*statp == EX_OK)
1459 						*statp = EX_TEMPFAIL;
1460 					goto nexttype;
1461 				}
1462 				*statp = EX_TEMPFAIL;
1463 
1464 				if (WorkAroundBrokenAAAA)
1465 				{
1466 					/*
1467 					**  Only return if not TRY_AGAIN as an
1468 					**  attempt with a different qtype may
1469 					**  succeed (res_querydomain() calls
1470 					**  res_query() calls res_send() which
1471 					**  sets errno to ETIMEDOUT if the
1472 					**  nameservers could be contacted but
1473 					**  didn't give an answer).
1474 					*/
1475 
1476 					if (save_errno != ETIMEDOUT)
1477 						goto error;
1478 				}
1479 				else
1480 					goto error;
1481 			}
1482 
1483 nexttype:
1484 			if (h_errno != HOST_NOT_FOUND)
1485 			{
1486 				/* might have another type of interest */
1487 # if NETINET6
1488 				if (qtype == T_AAAA)
1489 				{
1490 					qtype = T_A;
1491 					continue;
1492 				}
1493 				else
1494 # endif /* NETINET6 */
1495 				if (qtype == T_A && !gotmx &&
1496 				    (trymx || *dp == '\0'))
1497 				{
1498 					qtype = T_MX;
1499 					continue;
1500 				}
1501 			}
1502 
1503 			/* definite no -- try the next domain */
1504 			sli++;
1505 			qtype = initial;
1506 			continue;
1507 		}
1508 		else if (tTd(8, 7))
1509 			sm_dprintf("\tYES\n");
1510 
1511 		/* avoid problems after truncation in tcp packets */
1512 		if (ret > sizeof(answer))
1513 			ret = sizeof(answer);
1514 		SM_ASSERT(ret >= 0);
1515 
1516 		/*
1517 		**  Appear to have a match.  Confirm it by searching for A or
1518 		**  CNAME records.  If we don't have a local domain
1519 		**  wild card MX record, we will accept MX as well.
1520 		*/
1521 
1522 		ap = (unsigned char *) &answer + HFIXEDSZ;
1523 		eom = (unsigned char *) &answer + ret;
1524 
1525 		if (0 == hp->ad)
1526 			ad = false;
1527 
1528 		/* skip question part of response -- we know what we asked */
1529 		for (qdcount = ntohs((unsigned short) hp->qdcount);
1530 		     qdcount--;
1531 		     ap += ret + QFIXEDSZ)
1532 		{
1533 			if ((ret = dn_skipname(ap, eom)) < 0)
1534 			{
1535 				if (tTd(8, 20))
1536 					sm_dprintf("qdcount failure (%d)\n",
1537 						ntohs((unsigned short) hp->qdcount));
1538 				*statp = EX_SOFTWARE;
1539 				goto error;
1540 			}
1541 		}
1542 
1543 		amatch = false;
1544 		for (ancount = ntohs((unsigned short) hp->ancount);
1545 		     --ancount >= 0 && ap < eom;
1546 		     ap += n)
1547 		{
1548 			n = dn_expand((unsigned char *) &answer, eom, ap,
1549 				      (RES_UNC_T) nbuf, sizeof(nbuf));
1550 			if (n < 0)
1551 				break;
1552 			ap += n;
1553 			GETSHORT(type, ap);
1554 			ap += INT16SZ;		/* skip over class */
1555 			GETLONG(ttl, ap);
1556 			GETSHORT(n, ap);	/* rdlength */
1557 			switch (type)
1558 			{
1559 			  case T_MX:
1560 				gotmx = true;
1561 				if (*dp != '\0' && HasWildcardMX)
1562 				{
1563 					/*
1564 					**  If we are using MX matches and have
1565 					**  not yet gotten one, save this one
1566 					**  but keep searching for an A or
1567 					**  CNAME match.
1568 					*/
1569 
1570 					if (trymx && mxmatch == NULL)
1571 						mxmatch = dp;
1572 					continue;
1573 				}
1574 
1575 				/*
1576 				**  If we did not append a domain name, this
1577 				**  must have been a canonical name to start
1578 				**  with.  Even if we did append a domain name,
1579 				**  in the absence of a wildcard MX this must
1580 				**  still be a real MX match.
1581 				**  Such MX matches are as good as an A match,
1582 				**  fall through.
1583 				*/
1584 				/* FALLTHROUGH */
1585 
1586 # if NETINET6
1587 			  case T_AAAA:
1588 # endif
1589 			  case T_A:
1590 				/* Flag that a good match was found */
1591 				amatch = true;
1592 
1593 				/* continue in case a CNAME also exists */
1594 				continue;
1595 
1596 			  case T_CNAME:
1597 				if (DontExpandCnames)
1598 				{
1599 					/* got CNAME -- guaranteed canonical */
1600 					amatch = true;
1601 					break;
1602 				}
1603 
1604 				if (loopcnt++ > MAXCNAMEDEPTH)
1605 				{
1606 					/*XXX should notify postmaster XXX*/
1607 					message("DNS failure: CNAME loop for %s",
1608 						host);
1609 					if (CurEnv->e_message == NULL)
1610 					{
1611 						char ebuf[MAXLINE];
1612 
1613 						(void) sm_snprintf(ebuf,
1614 							sizeof(ebuf),
1615 							"Deferred: DNS failure: CNAME loop for %.100s",
1616 							host);
1617 						CurEnv->e_message =
1618 						    sm_rpool_strdup_x(
1619 							CurEnv->e_rpool, ebuf);
1620 					}
1621 					SM_SET_H_ERRNO(NO_RECOVERY);
1622 					*statp = EX_CONFIG;
1623 					goto error;
1624 				}
1625 
1626 				/* value points at name */
1627 				if ((ret = dn_expand((unsigned char *)&answer,
1628 						     eom, ap, (RES_UNC_T) nbuf,
1629 						     sizeof(nbuf))) < 0)
1630 					break;
1631 				(void) sm_strlcpy(host, nbuf, hbsize);
1632 
1633 				/*
1634 				**  RFC 1034 section 3.6 specifies that CNAME
1635 				**  should point at the canonical name -- but
1636 				**  urges software to try again anyway.
1637 				*/
1638 
1639 				goto cnameloop;
1640 
1641 			  default:
1642 				/* not a record of interest */
1643 				continue;
1644 			}
1645 		}
1646 
1647 		if (amatch)
1648 		{
1649 			/*
1650 			**  Got a good match -- either an A, CNAME, or an
1651 			**  exact MX record.  Save it and get out of here.
1652 			*/
1653 
1654 			mxmatch = dp;
1655 			break;
1656 		}
1657 
1658 		/*
1659 		**  Nothing definitive yet.
1660 		**	If this was a T_A query and we haven't yet found a MX
1661 		**		match, try T_MX if allowed to do so.
1662 		**	Otherwise, try the next domain.
1663 		*/
1664 
1665 # if NETINET6
1666 		if (qtype == T_AAAA)
1667 			qtype = T_A;
1668 		else
1669 # endif
1670 		if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
1671 			qtype = T_MX;
1672 		else
1673 		{
1674 			qtype = initial;
1675 			sli++;
1676 		}
1677 	}
1678 
1679 	/* if nothing was found, we are done */
1680 	if (mxmatch == NULL)
1681 	{
1682 		if (*statp == EX_OK)
1683 			*statp = EX_NOHOST;
1684 		goto error;
1685 	}
1686 
1687 	/*
1688 	**  Create canonical name and return.
1689 	**  If saved domain name is null, name was already canonical.
1690 	**  Otherwise append the saved domain name.
1691 	*/
1692 
1693 	(void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host,
1694 			   *mxmatch == '\0' ? "" : ".",
1695 			   MAXDNAME, mxmatch);
1696 	(void) sm_strlcpy(host, nbuf, hbsize);
1697 	if (tTd(8, 5))
1698 		sm_dprintf("dns_getcanonname: %s\n", host);
1699 	*statp = EX_OK;
1700 
1701 	/* return only one TTL entry, that should be sufficient */
1702 	if (ttl > 0 && pttl != NULL)
1703 		*pttl = ttl;
1704 # if DANE
1705 	_res.options = old_options;
1706 # endif
1707 	return ad ? HOST_SECURE : HOST_OK;
1708 
1709   error:
1710 # if DANE
1711 	_res.options = old_options;
1712 # endif
1713 	return HOST_NOTFOUND;
1714 }
1715 
1716 #endif /* NAMED_BIND */
1717