]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/domain.c
Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for details
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / domain.c
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 _FFR_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 #if NAMED_BIND
27
28 # include <arpa/inet.h>
29 # include <sm_resolve.h>
30 # if DANE
31 #  include <tls.h>
32 #  ifndef SM_NEG_TTL
33 #   define SM_NEG_TTL 60 /* "negative" TTL */
34 #  endif
35 # endif
36
37
38 # ifndef MXHOSTBUFSIZE
39 #  define MXHOSTBUFSIZE (128 * MAXMXHOSTS)
40 # endif
41
42 static char     MXHostBuf[MXHOSTBUFSIZE];
43 # if (MXHOSTBUFSIZE < 2) || (MXHOSTBUFSIZE >= INT_MAX/2)
44         ERROR: _MXHOSTBUFSIZE is out of range
45 # endif
46
47 # ifndef MAXDNSRCH
48 #  define MAXDNSRCH     6       /* number of possible domains to search */
49 # endif
50
51 # ifndef RES_DNSRCH_VARIABLE
52 #  define RES_DNSRCH_VARIABLE   _res.dnsrch
53 # endif
54
55 # ifndef NO_DATA
56 #  define NO_DATA       NO_ADDRESS
57 # endif
58
59 # ifndef HFIXEDSZ
60 #  define HFIXEDSZ      12      /* sizeof(HEADER) */
61 # endif
62
63 # define MAXCNAMEDEPTH  10      /* maximum depth of CNAME recursion */
64
65 # if defined(__RES) && (__RES >= 19940415)
66 #  define RES_UNC_T     char *
67 # else
68 #  define RES_UNC_T     unsigned char *
69 # endif
70
71 static int      mxrand __P((char *));
72 static int      fallbackmxrr __P((int, unsigned short *, char **));
73
74 # if DANE
75
76 /*
77 **  TLSAADD -- add TLSA records to dane_tlsa entry
78 **
79 **      Parameters:
80 **              name -- key for stab entry (for debugging output)
81 **              dr -- DNS reply
82 **              dane_tlsa -- dane_tlsa entry
83 **              dnsrc -- DNS lookup return code (h_errno)
84 **              n -- current number of TLSA records in dane_tlsa entry
85 **              pttl -- (pointer to) TTL (in/out)
86 **              level -- recursion level (CNAMEs)
87 **
88 **      Returns:
89 **              new number of TLSA records
90 */
91
92 static int tlsaadd __P((const char *, DNS_REPLY_T *, dane_tlsa_P, int, int,
93                         unsigned int *, int));
94
95 static int
96 tlsaadd(name, dr, dane_tlsa, dnsrc, n, pttl, level)
97         const char *name;
98         DNS_REPLY_T *dr;
99         dane_tlsa_P dane_tlsa;
100         int dnsrc;
101         int n;
102         unsigned int *pttl;
103         int level;
104 {
105         RESOURCE_RECORD_T *rr;
106         unsigned int ttl;
107         int nprev;
108
109         if (dnsrc != 0)
110         {
111                 if (tTd(8, 2))
112                         sm_dprintf("tlsaadd(%s), prev=%d, dnsrc=%d\n",
113                                 name, dane_tlsa->dane_tlsa_dnsrc, dnsrc);
114
115                 /* check previous error and keep the "most important" one? */
116                 dane_tlsa->dane_tlsa_dnsrc = dnsrc;
117 # if DNSSEC_TEST
118                 if (tTd(8, 110))
119                         *pttl = tTdlevel(8)-110;        /* how to make this an option? */
120                 else
121 # else
122                         *pttl = SM_NEG_TTL;
123 # endif
124
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 (host == NULL || *host == '\0')
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 /*
500 **  GETMXRR -- get MX resource records for a domain
501 **
502 **      Parameters:
503 **              host -- the name of the host to MX.
504 **              mxhosts -- a pointer to a return buffer of MX records.
505 **              mxprefs -- a pointer to a return buffer of MX preferences.
506 **                      If NULL, don't try to populate.
507 **              flags -- flags:
508 **                      DROPLOCALHOSt -- If true, all MX records less preferred
509 **                      than the local host (as determined by $=w) will
510 **                      be discarded.
511 **                      TRYFALLBACK -- add also fallback MX host?
512 **                      ISAD -- host lookup was secure?
513 **              rcode -- a pointer to an EX_ status code.
514 **              pttl -- pointer to return TTL (can be NULL).
515 **
516 **      Returns:
517 **              The number of MX records found.
518 **              -1 if there is an internal failure.
519 **              If no MX records are found, mxhosts[0] is set to host
520 **                      and 1 is returned.
521 **
522 **      Side Effects:
523 **              The entries made for mxhosts point to a static array
524 **              MXHostBuf[MXHOSTBUFSIZE], so the data needs to be copied,
525 **              if it must be preserved across calls to this function.
526 */
527
528 int
529 getmxrr(host, mxhosts, mxprefs, flags, rcode, pttl, port)
530         char *host;
531         char **mxhosts;
532         unsigned short *mxprefs;
533         unsigned int flags;
534         int *rcode;
535         int *pttl;
536         int port;
537 {
538         register unsigned char *eom, *cp;
539         register int i, j, n;
540         int nmx = 0;
541         register char *bp;
542         HEADER *hp;
543         querybuf answer;
544         int ancount, qdcount, buflen;
545         bool seenlocal = false;
546         unsigned short pref, type;
547         unsigned short localpref = 256;
548         char *fallbackMX = FallbackMX;
549         bool trycanon = false;
550         unsigned short *prefs;
551         int (*resfunc) __P((const char *, int, int, u_char *, int));
552         unsigned short prefer[MAXMXHOSTS];
553         int weight[MAXMXHOSTS];
554         int ttl = 0;
555         bool ad;
556         bool seennullmx = false;
557         extern int res_query(), res_search();
558 # if DANE
559         bool cname2mx;
560         char qname[MAXNAME];
561         unsigned long old_options = 0;
562 # endif
563
564         if (tTd(8, 2))
565                 sm_dprintf("getmxrr(%s, droplocalhost=%d, flags=%X, port=%d)\n",
566                            host, (flags & DROPLOCALHOST) != 0, flags, port);
567         ad = (flags & ISAD) != 0;
568         *rcode = EX_OK;
569         if (pttl != NULL)
570                 *pttl = SM_DEFAULT_TTL;
571         if (*host == '\0')
572                 return 0;
573 # if DANE
574         cname2mx = false;
575         qname[0] = '\0';
576         old_options = _res.options;
577         if (ad)
578                 _res.options |= SM_RES_DNSSEC;
579 # endif
580
581         if ((fallbackMX != NULL && (flags & DROPLOCALHOST) != 0 &&
582              wordinclass(fallbackMX, 'w')) || (flags & TRYFALLBACK) == 0)
583         {
584                 /* don't use fallback for this pass */
585                 fallbackMX = NULL;
586         }
587
588         if (mxprefs != NULL)
589                 prefs = mxprefs;
590         else
591                 prefs = prefer;
592
593         /* efficiency hack -- numeric or non-MX lookups */
594         if (host[0] == '[')
595                 goto punt;
596
597 # if DANE
598         /*
599         **  NOTE: This only works if nocanonify is used,
600         **  otherwise the name is already rewritten.
601         */
602
603         /* always or only when "needed"? */
604         if (DANE_ALWAYS == Dane || (ad && DANE_SECURE == Dane))
605                 (void) sm_strlcpy(qname, host, sizeof(qname));
606 # endif /* DANE */
607
608 # if _FFR_EAI
609         if (!addr_is_ascii(host))
610         {
611                 char buf[1024];
612                 UErrorCode error = U_ZERO_ERROR;
613                 UIDNAInfo info = UIDNA_INFO_INITIALIZER;
614                 UIDNA *idna;
615
616                 idna = uidna_openUTS46(UIDNA_NONTRANSITIONAL_TO_ASCII, &error);
617                 (void) uidna_nameToASCII_UTF8(idna, host, strlen(host),
618                                              buf, sizeof(buf) - 1,
619                                              &info, &error);
620                 uidna_close(idna);
621                 host = sm_rpool_strdup_x(CurEnv->e_rpool, buf);
622         }
623 # endif /* _FFR_EAI */
624
625         /*
626         **  If we don't have MX records in our host switch, don't
627         **  try for MX records.  Note that this really isn't "right",
628         **  since we might be set up to try NIS first and then DNS;
629         **  if the host is found in NIS we really shouldn't be doing
630         **  MX lookups.  However, that should be a degenerate case.
631         */
632
633         if (!UseNameServer)
634                 goto punt;
635         if (HasWildcardMX && ConfigLevel >= 6)
636                 resfunc = res_query;
637         else
638                 resfunc = res_search;
639 # if DNSSEC_TEST
640         if (tTd(8, 110))
641                 resfunc = tstdns_search;
642 # endif
643
644         errno = 0;
645         hp = (HEADER *)&answer;
646         n = (*resfunc)(host, C_IN, T_MX, (unsigned char *) &answer,
647                        sizeof(answer));
648         if (n < 0)
649         {
650                 if (tTd(8, 1))
651 # if DNSSEC_TEST
652                         sm_dprintf("getmxrr: res_search(%s) failed (errno=%d (%s), h_errno=%d (%s))\n",
653                                 host, errno, strerror(errno),
654                                 h_errno, herrno2txt(h_errno));
655 # else
656                         sm_dprintf("getmxrr: res_search(%s) failed, h_errno=%d\n",
657                                 host, h_errno);
658 # endif
659                 switch (h_errno)
660                 {
661                   case NO_DATA:
662                         trycanon = true;
663                         /* FALLTHROUGH */
664
665                   case NO_RECOVERY:
666                         /* no MX data on this host */
667                         goto punt;
668
669                   case HOST_NOT_FOUND:
670 # if BROKEN_RES_SEARCH
671                   case 0: /* Ultrix resolver returns failure w/ h_errno=0 */
672 # endif
673                         /* host doesn't exist in DNS; might be in /etc/hosts */
674                         trycanon = true;
675                         *rcode = EX_NOHOST;
676                         goto punt;
677
678                   case TRY_AGAIN:
679                   case -1:
680                         /* couldn't connect to the name server */
681                         if (fallbackMX != NULL)
682                         {
683                                 /* name server is hosed -- push to fallback */
684                                 nmx = fallbackmxrr(nmx, prefs, mxhosts);
685                                 goto done;
686                         }
687                         /* it might come up later; better queue it up */
688                         *rcode = EX_TEMPFAIL;
689                         break;
690
691                   default:
692                         syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)",
693                                 host, h_errno);
694                         *rcode = EX_OSERR;
695                         break;
696                 }
697
698                 /* irreconcilable differences */
699                 goto error;
700         }
701
702         ad = ad && hp->ad;
703         if (tTd(8, 2))
704                 sm_dprintf("getmxrr(%s), hp=%p, ad=%d\n", host, (void*)hp, ad);
705
706         /* avoid problems after truncation in tcp packets */
707         if (n > sizeof(answer))
708                 n = sizeof(answer);
709
710         /* find first satisfactory answer */
711         cp = (unsigned char *)&answer + HFIXEDSZ;
712         eom = (unsigned char *)&answer + n;
713
714         for (qdcount = ntohs((unsigned short) hp->qdcount);
715              qdcount--;
716              cp += n + QFIXEDSZ)
717         {
718                 if ((n = dn_skipname(cp, eom)) < 0)
719                         goto punt;
720         }
721
722         /* NOTE: see definition of MXHostBuf! */
723         buflen = sizeof(MXHostBuf) - 1;
724         SM_ASSERT(buflen > 0);
725         bp = MXHostBuf;
726         ancount = ntohs((unsigned short) hp->ancount);
727
728         /* See RFC 1035 for layout of RRs. */
729         /* XXX leave room for FallbackMX ? */
730         while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
731         {
732                 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
733                                    (RES_UNC_T) bp, buflen)) < 0)
734                         break;
735                 cp += n;
736                 GETSHORT(type, cp);
737                 cp += INT16SZ;          /* skip over class */
738                 GETLONG(ttl, cp);
739                 GETSHORT(n, cp);        /* rdlength */
740 # if DANE
741                 if (type == T_CNAME)
742                         cname2mx = true;
743 # endif
744                 if (type != T_MX)
745                 {
746                         if ((tTd(8, 8) || _res.options & RES_DEBUG)
747 # if DANE
748                             && type != T_RRSIG
749 # endif
750                             )
751                                 sm_dprintf("unexpected answer type %s, size %d\n",
752                                         dns_type_to_string(type), n);
753                         cp += n;
754                         continue;
755                 }
756                 GETSHORT(pref, cp);
757                 if ((n = dn_expand((unsigned char *)&answer, eom, cp,
758                                    (RES_UNC_T) bp, buflen)) < 0)
759                         break;
760                 cp += n;
761                 n = strlen(bp);
762
763                 /* Support for RFC7505 "MX 0 ." */
764                 if (pref == 0 && *bp == '\0')
765                         seennullmx = true;
766
767                 if (wordinclass(bp, 'w'))
768                 {
769                         if (tTd(8, 3))
770                                 sm_dprintf("found localhost (%s) in MX list, pref=%d\n",
771                                         bp, pref);
772                         if ((flags & DROPLOCALHOST) != 0)
773                         {
774                                 if (!seenlocal || pref < localpref)
775                                         localpref = pref;
776                                 seenlocal = true;
777                                 continue;
778                         }
779                         weight[nmx] = 0;
780                 }
781                 else
782                         weight[nmx] = mxrand(bp);
783                 prefs[nmx] = pref;
784                 mxhosts[nmx++] = bp;
785 # if DANE
786                 if (CHK_DANE(Dane) && port >= 0)
787                 {
788                         int nrr;
789                         unsigned long flags;
790
791                         flags = ad ? TLSAFLADMX : TLSAFLNOADMX;
792                         nrr = gettlsa(bp, NULL, NULL, flags, ttl, port);
793
794                         /* Only check qname if no TLSA RRs were found */
795                         if (0 == nrr && cname2mx && '\0' != qname[0] &&
796                             strcmp(qname, bp))
797                                 gettlsa(qname, bp, NULL, flags, ttl, port);
798                         /* XXX is this the right ad flag? */
799                 }
800 # endif
801
802                 /*
803                 **  Note: n can be 0 for something like:
804                 **  host MX 0 .
805                 **  See RFC 7505
806                 */
807
808                 bp += n;
809                 if (0 == n || bp[-1] != '.')
810                 {
811                         *bp++ = '.';
812                         n++;
813                 }
814                 *bp++ = '\0';
815                 if (buflen < n + 1)
816                 {
817                         /* don't want to wrap buflen */
818                         break;
819                 }
820                 buflen -= n + 1;
821         }
822
823         /* Support for RFC7505 "MX 0 ." */
824         if (seennullmx && nmx == 1)
825         {
826                 if (tTd(8, 4))
827                         sm_dprintf("getmxrr: Null MX record found, domain doesn't accept mail (RFC7505)\n");
828                 *rcode = EX_UNAVAILABLE;
829                 return NULLMX;
830         }
831
832         /* return only one TTL entry, that should be sufficient */
833         if (ttl > 0 && pttl != NULL)
834                 *pttl = ttl;
835
836         /* sort the records */
837         for (i = 0; i < nmx; i++)
838         {
839                 for (j = i + 1; j < nmx; j++)
840                 {
841                         if (prefs[i] > prefs[j] ||
842                             (prefs[i] == prefs[j] && weight[i] > weight[j]))
843                         {
844                                 register int temp;
845                                 register char *temp1;
846
847                                 temp = prefs[i];
848                                 prefs[i] = prefs[j];
849                                 prefs[j] = temp;
850                                 temp1 = mxhosts[i];
851                                 mxhosts[i] = mxhosts[j];
852                                 mxhosts[j] = temp1;
853                                 temp = weight[i];
854                                 weight[i] = weight[j];
855                                 weight[j] = temp;
856                         }
857                 }
858                 if (seenlocal && prefs[i] >= localpref)
859                 {
860                         /* truncate higher preference part of list */
861                         nmx = i;
862                 }
863         }
864
865         /* delete duplicates from list (yes, some bozos have duplicates) */
866         for (i = 0; i < nmx - 1; )
867         {
868                 if (sm_strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
869                         i++;
870                 else
871                 {
872                         /* compress out duplicate */
873                         for (j = i + 1; j < nmx; j++)
874                         {
875                                 mxhosts[j] = mxhosts[j + 1];
876                                 prefs[j] = prefs[j + 1];
877                         }
878                         nmx--;
879                 }
880         }
881
882         if (nmx == 0)
883         {
884 punt:
885                 if (seenlocal)
886                 {
887                         struct hostent *h = NULL;
888
889                         /*
890                         **  If we have deleted all MX entries, this is
891                         **  an error -- we should NEVER send to a host that
892                         **  has an MX, and this should have been caught
893                         **  earlier in the config file.
894                         **
895                         **  Some sites prefer to go ahead and try the
896                         **  A record anyway; that case is handled by
897                         **  setting TryNullMXList.  I believe this is a
898                         **  bad idea, but it's up to you....
899                         */
900
901                         if (TryNullMXList)
902                         {
903                                 SM_SET_H_ERRNO(0);
904                                 errno = 0;
905                                 h = sm_gethostbyname(host, AF_INET);
906                                 if (h == NULL)
907                                 {
908                                         if (errno == ETIMEDOUT ||
909                                             h_errno == TRY_AGAIN ||
910                                             (errno == ECONNREFUSED &&
911                                              UseNameServer))
912                                         {
913                                                 *rcode = EX_TEMPFAIL;
914                                                 goto error;
915                                         }
916 # if NETINET6
917                                         SM_SET_H_ERRNO(0);
918                                         errno = 0;
919                                         h = sm_gethostbyname(host, AF_INET6);
920                                         if (h == NULL &&
921                                             (errno == ETIMEDOUT ||
922                                              h_errno == TRY_AGAIN ||
923                                              (errno == ECONNREFUSED &&
924                                               UseNameServer)))
925                                         {
926                                                 *rcode = EX_TEMPFAIL;
927                                                 goto error;
928                                         }
929 # endif /* NETINET6 */
930                                 }
931                         }
932
933                         if (h == NULL)
934                         {
935                                 *rcode = EX_CONFIG;
936                                 syserr("MX list for %s points back to %s",
937                                        host, MyHostName);
938                                 goto error;
939                         }
940 # if NETINET6
941                         freehostent(h);
942                         h = NULL;
943 # endif
944                 }
945                 if (strlen(host) >= sizeof(MXHostBuf))
946                 {
947                         *rcode = EX_CONFIG;
948                         syserr("Host name %s too long",
949                                shortenstring(host, MAXSHORTSTR));
950                         goto error;
951                 }
952                 (void) sm_strlcpy(MXHostBuf, host, sizeof(MXHostBuf));
953                 mxhosts[0] = MXHostBuf;
954                 prefs[0] = 0;
955                 if (host[0] == '[')
956                 {
957                         register char *p;
958 # if NETINET6
959                         struct sockaddr_in6 tmp6;
960 # endif
961
962                         /* this may be an MX suppression-style address */
963                         p = strchr(MXHostBuf, ']');
964                         if (p != NULL)
965                         {
966                                 *p = '\0';
967
968                                 if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
969                                 {
970                                         nmx++;
971                                         *p = ']';
972                                 }
973 # if NETINET6
974                                 else if (anynet_pton(AF_INET6, &MXHostBuf[1],
975                                                      &tmp6.sin6_addr) == 1)
976                                 {
977                                         nmx++;
978                                         *p = ']';
979                                 }
980 # endif /* NETINET6 */
981                                 else
982                                 {
983                                         trycanon = true;
984                                         mxhosts[0]++;
985                                 }
986                         }
987                 }
988                 if (trycanon &&
989                     (n = getcanonname(mxhosts[0], sizeof(MXHostBuf) - 2, false,
990                                 pttl)) != HOST_NOTFOUND)
991                 {
992                         /* XXX MXHostBuf == "" ?  is that possible? */
993                         bp = &MXHostBuf[strlen(MXHostBuf)];
994                         if (bp[-1] != '.')
995                         {
996                                 *bp++ = '.';
997                                 *bp = '\0';
998                         }
999                         nmx = 1;
1000 # if DANE
1001                         if (tTd(8, 3))
1002                                 sm_dprintf("getmxrr=%s, getcanonname=%d\n",
1003                                         mxhosts[0], n);
1004                         if (CHK_DANE(Dane) && port >= 0)
1005                         {
1006                                 int nrr;
1007                                 unsigned long flags;
1008                                 unsigned int cttl;
1009
1010                                 if (pttl != NULL)
1011                                         cttl = *pttl;
1012                                 else if (ttl > 0)
1013                                         cttl = ttl;
1014                                 else
1015                                         cttl = SM_DEFAULT_TTL;
1016
1017                                 flags = (ad && n == HOST_SECURE)
1018                                         ? TLSAFLADMX : TLSAFLNOADMX;
1019                                 nrr = gettlsa(mxhosts[0], NULL, NULL, flags,
1020                                                 cttl, port);
1021
1022                                 /*
1023                                 **  Only check qname if no TLSA RRs were found
1024                                 **  XXX: what about (temp) DNS errors?
1025                                 */
1026
1027                                 if (0 == nrr && '\0' != qname[0] &&
1028                                     strcmp(qname, mxhosts[0]))
1029                                         gettlsa(qname, mxhosts[0], NULL, flags,
1030                                                 cttl, port);
1031                                 /* XXX is this the right ad flag? */
1032                         }
1033 # endif
1034                 }
1035         }
1036
1037         /* if we have a default lowest preference, include that */
1038         if (fallbackMX != NULL && !seenlocal)
1039         {
1040                 /* TODO: DNSsec status of fallbacks */
1041                 nmx = fallbackmxrr(nmx, prefs, mxhosts);
1042         }
1043     done:
1044 # if DANE
1045         _res.options = old_options;
1046 # endif
1047         return nmx;
1048
1049    error:
1050 # if DANE
1051         _res.options = old_options;
1052 # endif
1053         return -1;
1054 }
1055
1056 /*
1057 **  MXRAND -- create a randomizer for equal MX preferences
1058 **
1059 **      If two MX hosts have equal preferences we want to randomize
1060 **      the selection.  But in order for signatures to be the same,
1061 **      we need to randomize the same way each time.  This function
1062 **      computes a pseudo-random hash function from the host name.
1063 **
1064 **      Parameters:
1065 **              host -- the name of the host.
1066 **
1067 **      Returns:
1068 **              A random but repeatable value based on the host name.
1069 */
1070
1071 static int
1072 mxrand(host)
1073         register char *host;
1074 {
1075         int hfunc;
1076         static unsigned int seed;
1077
1078         if (seed == 0)
1079         {
1080                 seed = (int) curtime() & 0xffff;
1081                 if (seed == 0)
1082                         seed++;
1083         }
1084
1085         if (tTd(17, 9))
1086                 sm_dprintf("mxrand(%s)", host);
1087
1088         hfunc = seed;
1089         while (*host != '\0')
1090         {
1091                 int c = *host++;
1092
1093                 if (isascii(c) && isupper(c))
1094                         c = tolower(c);
1095                 hfunc = ((hfunc << 1) ^ c) % 2003;
1096         }
1097
1098         hfunc &= 0xff;
1099         hfunc++;
1100
1101         if (tTd(17, 9))
1102                 sm_dprintf(" = %d\n", hfunc);
1103         return hfunc;
1104 }
1105 /*
1106 **  BESTMX -- find the best MX for a name
1107 **
1108 **      This is really a hack, but I don't see any obvious way
1109 **      to generalize it at the moment.
1110 */
1111
1112 /* ARGSUSED3 */
1113 char *
1114 bestmx_map_lookup(map, name, av, statp)
1115         MAP *map;
1116         char *name;
1117         char **av;
1118         int *statp;
1119 {
1120         int nmx;
1121         int saveopts = _res.options;
1122         int i;
1123         ssize_t len = 0;
1124         char *result;
1125         char *mxhosts[MAXMXHOSTS + 1];
1126 # if _FFR_BESTMX_BETTER_TRUNCATION
1127         char *buf;
1128 # else
1129         char *p;
1130         char buf[PSBUFSIZE / 2];
1131 # endif
1132
1133         _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
1134         nmx = getmxrr(name, mxhosts, NULL, 0, statp, NULL, -1);
1135         _res.options = saveopts;
1136         if (nmx <= 0)
1137                 return NULL;
1138         if (bitset(MF_MATCHONLY, map->map_mflags))
1139                 return map_rewrite(map, name, strlen(name), NULL);
1140         if ((map->map_coldelim == '\0') || (nmx == 1))
1141                 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
1142
1143         /*
1144         **  We were given a -z flag (return all MXs) and there are multiple
1145         **  ones.  We need to build them all into a list.
1146         */
1147
1148 # if _FFR_BESTMX_BETTER_TRUNCATION
1149         for (i = 0; i < nmx; i++)
1150         {
1151                 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1152                 {
1153                         syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1154                                mxhosts[i], map->map_coldelim);
1155                         return NULL;
1156                 }
1157                 len += strlen(mxhosts[i]) + 1;
1158                 if (len < 0)
1159                 {
1160                         len -= strlen(mxhosts[i]) + 1;
1161                         break;
1162                 }
1163         }
1164         buf = (char *) sm_malloc(len);
1165         if (buf == NULL)
1166         {
1167                 *statp = EX_UNAVAILABLE;
1168                 return NULL;
1169         }
1170         *buf = '\0';
1171         for (i = 0; i < nmx; i++)
1172         {
1173                 int end;
1174
1175                 end = sm_strlcat(buf, mxhosts[i], len);
1176                 if (i != nmx && end + 1 < len)
1177                 {
1178                         buf[end] = map->map_coldelim;
1179                         buf[end + 1] = '\0';
1180                 }
1181         }
1182
1183         /* Cleanly truncate for rulesets */
1184         truncate_at_delim(buf, PSBUFSIZE / 2, map->map_coldelim);
1185 # else /* _FFR_BESTMX_BETTER_TRUNCATION */
1186         p = buf;
1187         for (i = 0; i < nmx; i++)
1188         {
1189                 size_t slen;
1190
1191                 if (strchr(mxhosts[i], map->map_coldelim) != NULL)
1192                 {
1193                         syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
1194                                mxhosts[i], map->map_coldelim);
1195                         return NULL;
1196                 }
1197                 slen = strlen(mxhosts[i]);
1198                 if (len + slen + 2 > sizeof(buf))
1199                         break;
1200                 if (i > 0)
1201                 {
1202                         *p++ = map->map_coldelim;
1203                         len++;
1204                 }
1205                 (void) sm_strlcpy(p, mxhosts[i], sizeof(buf) - len);
1206                 p += slen;
1207                 len += slen;
1208         }
1209 # endif /* _FFR_BESTMX_BETTER_TRUNCATION */
1210
1211         result = map_rewrite(map, buf, len, av);
1212 # if _FFR_BESTMX_BETTER_TRUNCATION
1213         sm_free(buf);
1214 # endif
1215         return result;
1216 }
1217 /*
1218 **  DNS_GETCANONNAME -- get the canonical name for named host using DNS
1219 **
1220 **      This algorithm tries to be smart about wildcard MX records.
1221 **      This is hard to do because DNS doesn't tell is if we matched
1222 **      against a wildcard or a specific MX.
1223 **
1224 **      We always prefer A & CNAME records, since these are presumed
1225 **      to be specific.
1226 **
1227 **      If we match an MX in one pass and lose it in the next, we use
1228 **      the old one.  For example, consider an MX matching *.FOO.BAR.COM.
1229 **      A hostname bletch.foo.bar.com will match against this MX, but
1230 **      will stop matching when we try bletch.bar.com -- so we know
1231 **      that bletch.foo.bar.com must have been right.  This fails if
1232 **      there was also an MX record matching *.BAR.COM, but there are
1233 **      some things that just can't be fixed.
1234 **
1235 **      Parameters:
1236 **              host -- a buffer containing the name of the host.
1237 **                      This is a value-result parameter.
1238 **              hbsize -- the size of the host buffer.
1239 **              trymx -- if set, try MX records as well as A and CNAME.
1240 **              statp -- pointer to place to store status.
1241 **              pttl -- pointer to return TTL (can be NULL).
1242 **
1243 **      Returns:
1244 **              >0 -- if the host was found.
1245 **              0 -- otherwise.
1246 */
1247
1248 int
1249 dns_getcanonname(host, hbsize, trymx, statp, pttl)
1250         char *host;
1251         int hbsize;
1252         bool trymx;
1253         int *statp;
1254         int *pttl;
1255 {
1256         register unsigned char *eom, *ap;
1257         register char *cp;
1258         register int n;
1259         HEADER *hp;
1260         querybuf answer;
1261         int ancount, qdcount, ret, type, qtype, initial, loopcnt, ttl, sli;
1262         char **domain;
1263         char *dp;
1264         char *mxmatch;
1265         bool amatch, gotmx, ad;
1266         char nbuf[SM_MAX(MAXPACKET, MAXDNAME*2+2)];
1267 # if DNSSEC_TEST
1268 #  define ADDSL 1 /* NameSearchList may add another entry to searchlist! */
1269 # else
1270 #  define ADDSL 0
1271 # endif
1272         char *searchlist[MAXDNSRCH + 2 + ADDSL];
1273 # define SLSIZE SM_ARRAY_SIZE(searchlist)
1274         int (*resqdomain) __P((const char *, const char *, int, int, unsigned char *, int));
1275 # if DANE
1276         unsigned long old_options = 0;
1277 # endif
1278
1279         ttl = 0;
1280         gotmx = false;
1281         ad = true;
1282         if (tTd(8, 2))
1283                 sm_dprintf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
1284
1285         if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1286         {
1287                 *statp = EX_UNAVAILABLE;
1288                 return HOST_NOTFOUND;
1289         }
1290
1291 # if DANE
1292         old_options = _res.options;
1293         if (DANE_SECURE == Dane)
1294                 _res.options |= SM_RES_DNSSEC;
1295 # endif
1296
1297         *statp = EX_OK;
1298         resqdomain = res_querydomain;
1299 # if DNSSEC_TEST
1300         if (tTd(8, 110))
1301                 resqdomain = tstdns_querydomain;
1302 # endif
1303
1304         /*
1305         **  Initialize domain search list.  If there is at least one
1306         **  dot in the name, search the unmodified name first so we
1307         **  find "vse.CS" in Czechoslovakia instead of in the local
1308         **  domain (e.g., vse.CS.Berkeley.EDU).  Note that there is no
1309         **  longer a country named Czechoslovakia but this type of problem
1310         **  is still present.
1311         **
1312         **  Older versions of the resolver could create this
1313         **  list by tearing apart the host name.
1314         */
1315
1316         loopcnt = 0;
1317 cnameloop:
1318         /* Check for dots in the name */
1319         for (cp = host, n = 0; *cp != '\0'; cp++)
1320                 if (*cp == '.')
1321                         n++;
1322
1323         /*
1324         **  Build the search list.
1325         **      If there is at least one dot in name, start with a null
1326         **      domain to search the unmodified name first.
1327         **      If name does not end with a dot and search up local domain
1328         **      tree desired, append each local domain component to the
1329         **      search list; if name contains no dots and default domain
1330         **      name is desired, append default domain name to search list;
1331         **      else if name ends in a dot, remove that dot.
1332         */
1333
1334         sli = 0;
1335         if (n > 0)
1336                 searchlist[sli++] = "";
1337 # if DNSSEC_TEST
1338         if (NameSearchList != NULL)
1339         {
1340                 SM_ASSERT(sli < SLSIZE);
1341                 searchlist[sli++] = NameSearchList;
1342         }
1343 # endif
1344         if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
1345         {
1346                 /* make sure there are less than MAXDNSRCH domains */
1347                 for (domain = RES_DNSRCH_VARIABLE, ret = 0;
1348                      *domain != NULL && ret < MAXDNSRCH && sli < SLSIZE;
1349                      ret++)
1350                         searchlist[sli++] = *domain++;
1351         }
1352         else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
1353         {
1354                 SM_ASSERT(sli < SLSIZE);
1355                 searchlist[sli++] = _res.defdname;
1356         }
1357         else if (*cp == '.')
1358         {
1359                 *cp = '\0';
1360         }
1361         SM_ASSERT(sli < SLSIZE);
1362         searchlist[sli] = NULL;
1363
1364         /*
1365         **  Now loop through the search list, appending each domain in turn
1366         **  name and searching for a match.
1367         */
1368
1369         mxmatch = NULL;
1370         initial = T_A;
1371 # if NETINET6
1372         if (InetMode == AF_INET6)
1373                 initial = T_AAAA;
1374 # endif
1375         qtype = initial;
1376
1377         for (sli = 0; sli < SLSIZE; )
1378         {
1379                 dp = searchlist[sli];
1380                 if (NULL == dp)
1381                         break;
1382                 if (qtype == initial)
1383                         gotmx = false;
1384                 if (tTd(8, 5))
1385                         sm_dprintf("dns_getcanonname: trying %s.%s (%s)\n",
1386                                 host, dp,
1387 # if NETINET6
1388                                 qtype == T_AAAA ? "AAAA" :
1389 # endif
1390                                 qtype == T_A ? "A" :
1391                                 qtype == T_MX ? "MX" :
1392                                 "???");
1393                 errno = 0;
1394                 hp = (HEADER *) &answer;
1395                 ret = (*resqdomain)(host, dp, C_IN, qtype,
1396                                       answer.qb2, sizeof(answer.qb2));
1397                 if (ret <= 0)
1398                 {
1399                         int save_errno = errno;
1400
1401                         if (tTd(8, 7))
1402                                 sm_dprintf("\tNO: errno=%d, h_errno=%d\n",
1403                                            save_errno, h_errno);
1404
1405                         if (save_errno == ECONNREFUSED || h_errno == TRY_AGAIN)
1406                         {
1407                                 /*
1408                                 **  the name server seems to be down or broken.
1409                                 */
1410
1411                                 SM_SET_H_ERRNO(TRY_AGAIN);
1412                                 if (*dp == '\0')
1413                                 {
1414                                         if (*statp == EX_OK)
1415                                                 *statp = EX_TEMPFAIL;
1416                                         goto nexttype;
1417                                 }
1418                                 *statp = EX_TEMPFAIL;
1419
1420                                 if (WorkAroundBrokenAAAA)
1421                                 {
1422                                         /*
1423                                         **  Only return if not TRY_AGAIN as an
1424                                         **  attempt with a different qtype may
1425                                         **  succeed (res_querydomain() calls
1426                                         **  res_query() calls res_send() which
1427                                         **  sets errno to ETIMEDOUT if the
1428                                         **  nameservers could be contacted but
1429                                         **  didn't give an answer).
1430                                         */
1431
1432                                         if (save_errno != ETIMEDOUT)
1433                                                 goto error;
1434                                 }
1435                                 else
1436                                         goto error;
1437                         }
1438
1439 nexttype:
1440                         if (h_errno != HOST_NOT_FOUND)
1441                         {
1442                                 /* might have another type of interest */
1443 # if NETINET6
1444                                 if (qtype == T_AAAA)
1445                                 {
1446                                         qtype = T_A;
1447                                         continue;
1448                                 }
1449                                 else
1450 # endif /* NETINET6 */
1451                                 if (qtype == T_A && !gotmx &&
1452                                     (trymx || *dp == '\0'))
1453                                 {
1454                                         qtype = T_MX;
1455                                         continue;
1456                                 }
1457                         }
1458
1459                         /* definite no -- try the next domain */
1460                         sli++;
1461                         qtype = initial;
1462                         continue;
1463                 }
1464                 else if (tTd(8, 7))
1465                         sm_dprintf("\tYES\n");
1466
1467                 /* avoid problems after truncation in tcp packets */
1468                 if (ret > sizeof(answer))
1469                         ret = sizeof(answer);
1470                 SM_ASSERT(ret >= 0);
1471
1472                 /*
1473                 **  Appear to have a match.  Confirm it by searching for A or
1474                 **  CNAME records.  If we don't have a local domain
1475                 **  wild card MX record, we will accept MX as well.
1476                 */
1477
1478                 ap = (unsigned char *) &answer + HFIXEDSZ;
1479                 eom = (unsigned char *) &answer + ret;
1480
1481                 if (0 == hp->ad)
1482                         ad = false;
1483
1484                 /* skip question part of response -- we know what we asked */
1485                 for (qdcount = ntohs((unsigned short) hp->qdcount);
1486                      qdcount--;
1487                      ap += ret + QFIXEDSZ)
1488                 {
1489                         if ((ret = dn_skipname(ap, eom)) < 0)
1490                         {
1491                                 if (tTd(8, 20))
1492                                         sm_dprintf("qdcount failure (%d)\n",
1493                                                 ntohs((unsigned short) hp->qdcount));
1494                                 *statp = EX_SOFTWARE;
1495                                 goto error;
1496                         }
1497                 }
1498
1499                 amatch = false;
1500                 for (ancount = ntohs((unsigned short) hp->ancount);
1501                      --ancount >= 0 && ap < eom;
1502                      ap += n)
1503                 {
1504                         n = dn_expand((unsigned char *) &answer, eom, ap,
1505                                       (RES_UNC_T) nbuf, sizeof(nbuf));
1506                         if (n < 0)
1507                                 break;
1508                         ap += n;
1509                         GETSHORT(type, ap);
1510                         ap += INT16SZ;          /* skip over class */
1511                         GETLONG(ttl, ap);
1512                         GETSHORT(n, ap);        /* rdlength */
1513                         switch (type)
1514                         {
1515                           case T_MX:
1516                                 gotmx = true;
1517                                 if (*dp != '\0' && HasWildcardMX)
1518                                 {
1519                                         /*
1520                                         **  If we are using MX matches and have
1521                                         **  not yet gotten one, save this one
1522                                         **  but keep searching for an A or
1523                                         **  CNAME match.
1524                                         */
1525
1526                                         if (trymx && mxmatch == NULL)
1527                                                 mxmatch = dp;
1528                                         continue;
1529                                 }
1530
1531                                 /*
1532                                 **  If we did not append a domain name, this
1533                                 **  must have been a canonical name to start
1534                                 **  with.  Even if we did append a domain name,
1535                                 **  in the absence of a wildcard MX this must
1536                                 **  still be a real MX match.
1537                                 **  Such MX matches are as good as an A match,
1538                                 **  fall through.
1539                                 */
1540                                 /* FALLTHROUGH */
1541
1542 # if NETINET6
1543                           case T_AAAA:
1544 # endif
1545                           case T_A:
1546                                 /* Flag that a good match was found */
1547                                 amatch = true;
1548
1549                                 /* continue in case a CNAME also exists */
1550                                 continue;
1551
1552                           case T_CNAME:
1553                                 if (DontExpandCnames)
1554                                 {
1555                                         /* got CNAME -- guaranteed canonical */
1556                                         amatch = true;
1557                                         break;
1558                                 }
1559
1560                                 if (loopcnt++ > MAXCNAMEDEPTH)
1561                                 {
1562                                         /*XXX should notify postmaster XXX*/
1563                                         message("DNS failure: CNAME loop for %s",
1564                                                 host);
1565                                         if (CurEnv->e_message == NULL)
1566                                         {
1567                                                 char ebuf[MAXLINE];
1568
1569                                                 (void) sm_snprintf(ebuf,
1570                                                         sizeof(ebuf),
1571                                                         "Deferred: DNS failure: CNAME loop for %.100s",
1572                                                         host);
1573                                                 CurEnv->e_message =
1574                                                     sm_rpool_strdup_x(
1575                                                         CurEnv->e_rpool, ebuf);
1576                                         }
1577                                         SM_SET_H_ERRNO(NO_RECOVERY);
1578                                         *statp = EX_CONFIG;
1579                                         goto error;
1580                                 }
1581
1582                                 /* value points at name */
1583                                 if ((ret = dn_expand((unsigned char *)&answer,
1584                                                      eom, ap, (RES_UNC_T) nbuf,
1585                                                      sizeof(nbuf))) < 0)
1586                                         break;
1587                                 (void) sm_strlcpy(host, nbuf, hbsize);
1588
1589                                 /*
1590                                 **  RFC 1034 section 3.6 specifies that CNAME
1591                                 **  should point at the canonical name -- but
1592                                 **  urges software to try again anyway.
1593                                 */
1594
1595                                 goto cnameloop;
1596
1597                           default:
1598                                 /* not a record of interest */
1599                                 continue;
1600                         }
1601                 }
1602
1603                 if (amatch)
1604                 {
1605                         /*
1606                         **  Got a good match -- either an A, CNAME, or an
1607                         **  exact MX record.  Save it and get out of here.
1608                         */
1609
1610                         mxmatch = dp;
1611                         break;
1612                 }
1613
1614                 /*
1615                 **  Nothing definitive yet.
1616                 **      If this was a T_A query and we haven't yet found a MX
1617                 **              match, try T_MX if allowed to do so.
1618                 **      Otherwise, try the next domain.
1619                 */
1620
1621 # if NETINET6
1622                 if (qtype == T_AAAA)
1623                         qtype = T_A;
1624                 else
1625 # endif
1626                 if (qtype == T_A && !gotmx && (trymx || *dp == '\0'))
1627                         qtype = T_MX;
1628                 else
1629                 {
1630                         qtype = initial;
1631                         sli++;
1632                 }
1633         }
1634
1635         /* if nothing was found, we are done */
1636         if (mxmatch == NULL)
1637         {
1638                 if (*statp == EX_OK)
1639                         *statp = EX_NOHOST;
1640                 goto error;
1641         }
1642
1643         /*
1644         **  Create canonical name and return.
1645         **  If saved domain name is null, name was already canonical.
1646         **  Otherwise append the saved domain name.
1647         */
1648
1649         (void) sm_snprintf(nbuf, sizeof(nbuf), "%.*s%s%.*s", MAXDNAME, host,
1650                            *mxmatch == '\0' ? "" : ".",
1651                            MAXDNAME, mxmatch);
1652         (void) sm_strlcpy(host, nbuf, hbsize);
1653         if (tTd(8, 5))
1654                 sm_dprintf("dns_getcanonname: %s\n", host);
1655         *statp = EX_OK;
1656
1657         /* return only one TTL entry, that should be sufficient */
1658         if (ttl > 0 && pttl != NULL)
1659                 *pttl = ttl;
1660 # if DANE
1661         _res.options = old_options;
1662 # endif
1663         return ad ? HOST_SECURE : HOST_OK;
1664
1665   error:
1666 # if DANE
1667         _res.options = old_options;
1668 # endif
1669         return HOST_NOTFOUND;
1670 }
1671
1672 #endif /* NAMED_BIND */