source: trunk/third/sendmail/src/domain.c @ 12554

Revision 12554, 20.2 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1986, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#include "sendmail.h"
14
15#ifndef lint
16#if NAMED_BIND
17static char sccsid[] = "@(#)domain.c    8.81 (Berkeley) 1/21/1999 (with name server)";
18#else
19static char sccsid[] = "@(#)domain.c    8.81 (Berkeley) 1/21/1999 (without name server)";
20#endif
21#endif /* not lint */
22
23#if NAMED_BIND
24
25#include <errno.h>
26#include <resolv.h>
27#include <arpa/inet.h>
28
29/*
30**  The standard udp packet size PACKETSZ (512) is not sufficient for some
31**  nameserver answers containing very many resource records. The resolver
32**  may switch to tcp and retry if it detects udp packet overflow.
33**  Also note that the resolver routines res_query and res_search return
34**  the size of the *un*truncated answer in case the supplied answer buffer
35**  it not big enough to accommodate the entire answer.
36*/
37
38#ifndef MAXPACKET
39# define MAXPACKET 8192         /* max packet size used internally by BIND */
40#endif
41
42typedef union
43{
44        HEADER  qb1;
45        u_char  qb2[MAXPACKET];
46} querybuf;
47
48#ifndef MXHOSTBUFSIZE
49# define MXHOSTBUFSIZE  (128 * MAXMXHOSTS)
50#endif
51
52static char     MXHostBuf[MXHOSTBUFSIZE];
53
54#ifndef MAXDNSRCH
55# define MAXDNSRCH      6       /* number of possible domains to search */
56#endif
57
58#ifndef MAX
59# define MAX(a, b)      ((a) > (b) ? (a) : (b))
60#endif
61
62#ifndef NO_DATA
63# define NO_DATA        NO_ADDRESS
64#endif
65
66#ifndef HFIXEDSZ
67# define HFIXEDSZ       12      /* sizeof(HEADER) */
68#endif
69
70#define MAXCNAMEDEPTH   10      /* maximum depth of CNAME recursion */
71
72#if defined(__RES) && (__RES >= 19940415)
73# define RES_UNC_T      char *
74#else
75# define RES_UNC_T      u_char *
76#endif
77/*
78**  GETMXRR -- get MX resource records for a domain
79**
80**      Parameters:
81**              host -- the name of the host to MX.
82**              mxhosts -- a pointer to a return buffer of MX records.
83**              droplocalhost -- If TRUE, all MX records less preferred
84**                      than the local host (as determined by $=w) will
85**                      be discarded.
86**              rcode -- a pointer to an EX_ status code.
87**
88**      Returns:
89**              The number of MX records found.
90**              -1 if there is an internal failure.
91**              If no MX records are found, mxhosts[0] is set to host
92**                      and 1 is returned.
93*/
94
95int
96getmxrr(host, mxhosts, droplocalhost, rcode)
97        char *host;
98        char **mxhosts;
99        bool droplocalhost;
100        int *rcode;
101{
102        register u_char *eom, *cp;
103        register int i, j, n;
104        int nmx = 0;
105        register char *bp;
106        HEADER *hp;
107        querybuf answer;
108        int ancount, qdcount, buflen;
109        bool seenlocal = FALSE;
110        u_short pref, type;
111        u_short localpref = 256;
112        char *fallbackMX = FallBackMX;
113        bool trycanon = FALSE;
114        int (*resfunc)();
115        extern int res_query(), res_search();
116        u_short prefer[MAXMXHOSTS];
117        int weight[MAXMXHOSTS];
118        extern int mxrand __P((char *));
119
120        if (tTd(8, 2))
121                printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost);
122
123        if (fallbackMX != NULL && droplocalhost &&
124            wordinclass(fallbackMX, 'w'))
125        {
126                /* don't use fallback for this pass */
127                fallbackMX = NULL;
128        }
129
130        *rcode = EX_OK;
131
132        /* efficiency hack -- numeric or non-MX lookups */
133        if (host[0] == '[')
134                goto punt;
135
136        /*
137        **  If we don't have MX records in our host switch, don't
138        **  try for MX records.  Note that this really isn't "right",
139        **  since we might be set up to try NIS first and then DNS;
140        **  if the host is found in NIS we really shouldn't be doing
141        **  MX lookups.  However, that should be a degenerate case.
142        */
143
144        if (!UseNameServer)
145                goto punt;
146        if (HasWildcardMX && ConfigLevel >= 6)
147                resfunc = res_query;
148        else
149                resfunc = res_search;
150
151        errno = 0;
152        n = (*resfunc)(host, C_IN, T_MX, (u_char *) &answer, sizeof(answer));
153        if (n < 0)
154        {
155                if (tTd(8, 1))
156                        printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n",
157                            (host == NULL) ? "<NULL>" : host, errno, h_errno);
158                switch (h_errno)
159                {
160                  case NO_DATA:
161                        trycanon = TRUE;
162                        /* fall through */
163
164                  case NO_RECOVERY:
165                        /* no MX data on this host */
166                        goto punt;
167
168                  case HOST_NOT_FOUND:
169#if BROKEN_RES_SEARCH
170                  case 0:       /* Ultrix resolver retns failure w/ h_errno=0 */
171#endif
172                        /* host doesn't exist in DNS; might be in /etc/hosts */
173                        trycanon = TRUE;
174                        *rcode = EX_NOHOST;
175                        goto punt;
176
177                  case TRY_AGAIN:
178                  case -1:
179                        /* couldn't connect to the name server */
180                        if (fallbackMX != NULL)
181                        {
182                                /* name server is hosed -- push to fallback */
183                                mxhosts[nmx++] = fallbackMX;
184                                return nmx;
185                        }
186                        /* it might come up later; better queue it up */
187                        *rcode = EX_TEMPFAIL;
188                        break;
189
190                  default:
191                        syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n",
192                                host, h_errno);
193                        *rcode = EX_OSERR;
194                        break;
195                }
196
197                /* irreconcilable differences */
198                return (-1);
199        }
200
201        /* avoid problems after truncation in tcp packets */
202        if (n > sizeof(answer))
203                n = sizeof(answer);
204
205        /* find first satisfactory answer */
206        hp = (HEADER *)&answer;
207        cp = (u_char *)&answer + HFIXEDSZ;
208        eom = (u_char *)&answer + n;
209        for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
210                if ((n = dn_skipname(cp, eom)) < 0)
211                        goto punt;
212        buflen = sizeof(MXHostBuf) - 1;
213        bp = MXHostBuf;
214        ancount = ntohs(hp->ancount);
215        while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1)
216        {
217                if ((n = dn_expand((u_char *)&answer,
218                    eom, cp, (RES_UNC_T) bp, buflen)) < 0)
219                        break;
220                cp += n;
221                GETSHORT(type, cp);
222                cp += INT16SZ + INT32SZ;
223                GETSHORT(n, cp);
224                if (type != T_MX)
225                {
226                        if (tTd(8, 8) || _res.options & RES_DEBUG)
227                                printf("unexpected answer type %d, size %d\n",
228                                    type, n);
229                        cp += n;
230                        continue;
231                }
232                GETSHORT(pref, cp);
233                if ((n = dn_expand((u_char *)&answer, eom, cp,
234                                   (RES_UNC_T) bp, buflen)) < 0)
235                        break;
236                cp += n;
237                if (wordinclass(bp, 'w'))
238                {
239                        if (tTd(8, 3))
240                                printf("found localhost (%s) in MX list, pref=%d\n",
241                                        bp, pref);
242                        if (droplocalhost)
243                        {
244                                if (!seenlocal || pref < localpref)
245                                        localpref = pref;
246                                seenlocal = TRUE;
247                                continue;
248                        }
249                        weight[nmx] = 0;
250                }
251                else
252                        weight[nmx] = mxrand(bp);
253                prefer[nmx] = pref;
254                mxhosts[nmx++] = bp;
255                n = strlen(bp);
256                bp += n;
257                if (bp[-1] != '.')
258                {
259                        *bp++ = '.';
260                        n++;
261                }
262                *bp++ = '\0';
263                buflen -= n + 1;
264        }
265
266        /* sort the records */
267        for (i = 0; i < nmx; i++)
268        {
269                for (j = i + 1; j < nmx; j++)
270                {
271                        if (prefer[i] > prefer[j] ||
272                            (prefer[i] == prefer[j] && weight[i] > weight[j]))
273                        {
274                                register int temp;
275                                register char *temp1;
276
277                                temp = prefer[i];
278                                prefer[i] = prefer[j];
279                                prefer[j] = temp;
280                                temp1 = mxhosts[i];
281                                mxhosts[i] = mxhosts[j];
282                                mxhosts[j] = temp1;
283                                temp = weight[i];
284                                weight[i] = weight[j];
285                                weight[j] = temp;
286                        }
287                }
288                if (seenlocal && prefer[i] >= localpref)
289                {
290                        /* truncate higher preference part of list */
291                        nmx = i;
292                }
293        }
294
295        /* delete duplicates from list (yes, some bozos have duplicates) */
296        for (i = 0; i < nmx - 1; )
297        {
298                if (strcasecmp(mxhosts[i], mxhosts[i + 1]) != 0)
299                        i++;
300                else
301                {
302                        /* compress out duplicate */
303                        for (j = i + 1; j < nmx; j++)
304                                mxhosts[j] = mxhosts[j + 1];
305                        nmx--;
306                }
307        }
308
309        if (nmx == 0)
310        {
311punt:
312                if (seenlocal &&
313                    (!TryNullMXList || sm_gethostbyname(host) == NULL))
314                {
315                        /*
316                        **  If we have deleted all MX entries, this is
317                        **  an error -- we should NEVER send to a host that
318                        **  has an MX, and this should have been caught
319                        **  earlier in the config file.
320                        **
321                        **  Some sites prefer to go ahead and try the
322                        **  A record anyway; that case is handled by
323                        **  setting TryNullMXList.  I believe this is a
324                        **  bad idea, but it's up to you....
325                        */
326
327                        *rcode = EX_CONFIG;
328                        syserr("MX list for %s points back to %s",
329                                host, MyHostName);
330                        return -1;
331                }
332                if (strlen(host) >= (SIZE_T) sizeof MXHostBuf)
333                {
334                        *rcode = EX_CONFIG;
335                        syserr("Host name %s too long",
336                               shortenstring(host, MAXSHORTSTR));
337                        return -1;
338                }
339                snprintf(MXHostBuf, sizeof MXHostBuf, "%s", host);
340                mxhosts[0] = MXHostBuf;
341                if (host[0] == '[')
342                {
343                        register char *p;
344
345                        /* this may be an MX suppression-style address */
346                        p = strchr(MXHostBuf, ']');
347                        if (p != NULL)
348                        {
349                                *p = '\0';
350                                if (inet_addr(&MXHostBuf[1]) != INADDR_NONE)
351                                {
352                                        nmx++;
353                                        *p = ']';
354                                }
355                                else
356                                {
357                                        trycanon = TRUE;
358                                        mxhosts[0]++;
359                                }
360                        }
361                }
362                if (trycanon &&
363                    getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE))
364                {
365                        bp = &MXHostBuf[strlen(MXHostBuf)];
366                        if (bp[-1] != '.')
367                        {
368                                *bp++ = '.';
369                                *bp = '\0';
370                        }
371                        nmx = 1;
372                }
373        }
374
375        /* if we have a default lowest preference, include that */
376        if (fallbackMX != NULL && !seenlocal)
377                mxhosts[nmx++] = fallbackMX;
378
379        return (nmx);
380}
381/*
382**  MXRAND -- create a randomizer for equal MX preferences
383**
384**      If two MX hosts have equal preferences we want to randomize
385**      the selection.  But in order for signatures to be the same,
386**      we need to randomize the same way each time.  This function
387**      computes a pseudo-random hash function from the host name.
388**
389**      Parameters:
390**              host -- the name of the host.
391**
392**      Returns:
393**              A random but repeatable value based on the host name.
394**
395**      Side Effects:
396**              none.
397*/
398
399int
400mxrand(host)
401        register char *host;
402{
403        int hfunc;
404        static unsigned int seed;
405
406        if (seed == 0)
407        {
408                seed = (int) curtime() & 0xffff;
409                if (seed == 0)
410                        seed++;
411        }
412
413        if (tTd(17, 9))
414                printf("mxrand(%s)", host);
415
416        hfunc = seed;
417        while (*host != '\0')
418        {
419                int c = *host++;
420
421                if (isascii(c) && isupper(c))
422                        c = tolower(c);
423                hfunc = ((hfunc << 1) ^ c) % 2003;
424        }
425
426        hfunc &= 0xff;
427        hfunc++;
428
429        if (tTd(17, 9))
430                printf(" = %d\n", hfunc);
431        return hfunc;
432}
433/*
434**  BESTMX -- find the best MX for a name
435**
436**      This is really a hack, but I don't see any obvious way
437**      to generalize it at the moment.
438*/
439
440/* ARGSUSED3 */
441char *
442bestmx_map_lookup(map, name, av, statp)
443        MAP *map;
444        char *name;
445        char **av;
446        int *statp;
447{
448        int nmx;
449        int saveopts = _res.options;
450        int i, len = 0;
451        char *p;
452        char *mxhosts[MAXMXHOSTS + 1];
453        char buf[PSBUFSIZE / 2];
454
455        _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
456        nmx = getmxrr(name, mxhosts, FALSE, statp);
457        _res.options = saveopts;
458        if (nmx <= 0)
459                return NULL;
460        if (bitset(MF_MATCHONLY, map->map_mflags))
461                return map_rewrite(map, name, strlen(name), NULL);
462        if ((map->map_coldelim == '\0') || (nmx == 1))
463                return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
464
465        /*
466        **  We were given a -z flag (return all MXs) and there are multiple
467        **  ones.  We need to build them all into a list.
468        */
469        p = buf;
470        for (i = 0; i < nmx; i++)
471        {
472                int slen;
473               
474                if (strchr(mxhosts[i], map->map_coldelim) != NULL)
475                {
476                        syserr("bestmx_map_lookup: MX host %.64s includes map delimiter character 0x%02X",
477                               mxhosts[i], map->map_coldelim);
478                        return NULL;
479                }
480                slen = strlen(mxhosts[i]);
481                if (len + slen + 2 > sizeof buf)
482                        break;
483                if (i > 0)
484                {
485                        *p++ = map->map_coldelim;
486                        len++;
487                }
488                strcpy(p, mxhosts[i]);
489                p += slen;
490                len += slen;
491        }
492        return map_rewrite(map, buf, len, av);
493}
494/*
495**  DNS_GETCANONNAME -- get the canonical name for named host using DNS
496**
497**      This algorithm tries to be smart about wildcard MX records.
498**      This is hard to do because DNS doesn't tell is if we matched
499**      against a wildcard or a specific MX.
500**     
501**      We always prefer A & CNAME records, since these are presumed
502**      to be specific.
503**
504**      If we match an MX in one pass and lose it in the next, we use
505**      the old one.  For example, consider an MX matching *.FOO.BAR.COM.
506**      A hostname bletch.foo.bar.com will match against this MX, but
507**      will stop matching when we try bletch.bar.com -- so we know
508**      that bletch.foo.bar.com must have been right.  This fails if
509**      there was also an MX record matching *.BAR.COM, but there are
510**      some things that just can't be fixed.
511**
512**      Parameters:
513**              host -- a buffer containing the name of the host.
514**                      This is a value-result parameter.
515**              hbsize -- the size of the host buffer.
516**              trymx -- if set, try MX records as well as A and CNAME.
517**              statp -- pointer to place to store status.
518**
519**      Returns:
520**              TRUE -- if the host matched.
521**              FALSE -- otherwise.
522*/
523
524bool
525dns_getcanonname(host, hbsize, trymx, statp)
526        char *host;
527        int hbsize;
528        bool trymx;
529        int *statp;
530{
531        register u_char *eom, *ap;
532        register char *cp;
533        register int n;
534        HEADER *hp;
535        querybuf answer;
536        int ancount, qdcount;
537        int ret;
538        char **domain;
539        int type;
540        char **dp;
541        char *mxmatch;
542        bool amatch;
543        bool gotmx = FALSE;
544        int qtype;
545        int loopcnt;
546        char *xp;
547        char nbuf[MAX(MAXPACKET, MAXDNAME*2+2)];
548        char *searchlist[MAXDNSRCH+2];
549        extern char *gethostalias __P((char *));
550
551        if (tTd(8, 2))
552                printf("dns_getcanonname(%s, trymx=%d)\n", host, trymx);
553
554        if ((_res.options & RES_INIT) == 0 && res_init() == -1)
555        {
556                *statp = EX_UNAVAILABLE;
557                return FALSE;
558        }
559
560        /*
561        **  Initialize domain search list.  If there is at least one
562        **  dot in the name, search the unmodified name first so we
563        **  find "vse.CS" in Czechoslovakia instead of in the local
564        **  domain (e.g., vse.CS.Berkeley.EDU).
565        **
566        **  Older versions of the resolver could create this
567        **  list by tearing apart the host name.
568        */
569
570        loopcnt = 0;
571cnameloop:
572        /* Check for dots in the name */
573        for (cp = host, n = 0; *cp != '\0'; cp++)
574                if (*cp == '.')
575                        n++;
576
577        /*
578        **  If this is a simple name, determine whether it matches an
579        **  alias in the file defined by the environment variable HOSTALIASES.
580        */
581        if (n == 0 && (xp = gethostalias(host)) != NULL)
582        {
583                if (loopcnt++ > MAXCNAMEDEPTH)
584                {
585                        syserr("loop in ${HOSTALIASES} file");
586                }
587                else
588                {
589                        strncpy(host, xp, hbsize);
590                        host[hbsize - 1] = '\0';
591                        goto cnameloop;
592                }
593        }
594
595        /*
596        **  Build the search list. 
597        **      If there is at least one dot in name, start with a null
598        **      domain to search the unmodified name first.
599        **      If name does not end with a dot and search up local domain
600        **      tree desired, append each local domain component to the
601        **      search list; if name contains no dots and default domain
602        **      name is desired, append default domain name to search list;
603        **      else if name ends in a dot, remove that dot.
604        */
605
606        dp = searchlist;
607        if (n > 0)
608                *dp++ = "";
609        if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options))
610        {
611                for (domain = _res.dnsrch; *domain != NULL; )
612                        *dp++ = *domain++;
613        }
614        else if (n == 0 && bitset(RES_DEFNAMES, _res.options))
615        {
616                *dp++ = _res.defdname;
617        }
618        else if (*cp == '.')
619        {
620                *cp = '\0';
621        }
622        *dp = NULL;
623
624        /*
625        **  Now loop through the search list, appending each domain in turn
626        **  name and searching for a match.
627        */
628
629        mxmatch = NULL;
630        qtype = T_ANY;
631
632        for (dp = searchlist; *dp != NULL; )
633        {
634                if (qtype == T_ANY)
635                        gotmx = FALSE;
636                if (tTd(8, 5))
637                        printf("dns_getcanonname: trying %s.%s (%s)\n",
638                                host, *dp,
639                                qtype == T_ANY ? "ANY" : qtype == T_A ? "A" :
640                                qtype == T_MX ? "MX" : "???");
641                ret = res_querydomain(host, *dp, C_IN, qtype,
642                                      answer.qb2, sizeof(answer.qb2));
643                if (ret <= 0)
644                {
645                        if (tTd(8, 7))
646                                printf("\tNO: errno=%d, h_errno=%d\n",
647                                        errno, h_errno);
648
649                        if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
650                        {
651                                /* the name server seems to be down */
652                                h_errno = TRY_AGAIN;
653                                *statp = EX_TEMPFAIL;
654                                return FALSE;
655                        }
656
657                        if (h_errno != HOST_NOT_FOUND)
658                        {
659                                /* might have another type of interest */
660                                if (qtype == T_ANY)
661                                {
662                                        qtype = T_A;
663                                        continue;
664                                }
665                                else if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
666                                {
667                                        qtype = T_MX;
668                                        continue;
669                                }
670                        }
671
672                        /* definite no -- try the next domain */
673                        dp++;
674                        qtype = T_ANY;
675                        continue;
676                }
677                else if (tTd(8, 7))
678                        printf("\tYES\n");
679
680                /* avoid problems after truncation in tcp packets */
681                if (ret > sizeof(answer))
682                        ret = sizeof(answer);
683
684                /*
685                **  Appear to have a match.  Confirm it by searching for A or
686                **  CNAME records.  If we don't have a local domain
687                **  wild card MX record, we will accept MX as well.
688                */
689
690                hp = (HEADER *) &answer;
691                ap = (u_char *) &answer + HFIXEDSZ;
692                eom = (u_char *) &answer + ret;
693
694                /* skip question part of response -- we know what we asked */
695                for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ)
696                {
697                        if ((ret = dn_skipname(ap, eom)) < 0)
698                        {
699                                if (tTd(8, 20))
700                                        printf("qdcount failure (%d)\n",
701                                                ntohs(hp->qdcount));
702                                *statp = EX_SOFTWARE;
703                                return FALSE;           /* ???XXX??? */
704                        }
705                }
706
707                amatch = FALSE;
708                for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom;
709                                                                        ap += n)
710                {
711                        n = dn_expand((u_char *) &answer, eom, ap,
712                                      (RES_UNC_T) nbuf, sizeof nbuf);
713                        if (n < 0)
714                                break;
715                        ap += n;
716                        GETSHORT(type, ap);
717                        ap += INT16SZ + INT32SZ;
718                        GETSHORT(n, ap);
719                        switch (type)
720                        {
721                          case T_MX:
722                                gotmx = TRUE;
723                                if (**dp != '\0' && HasWildcardMX)
724                                {
725                                        /*
726                                        **  If we are using MX matches and have
727                                        **  not yet gotten one, save this one
728                                        **  but keep searching for an A or
729                                        **  CNAME match.
730                                        */
731
732                                        if (trymx && mxmatch == NULL)
733                                                mxmatch = *dp;
734                                        continue;
735                                }
736
737                                /*
738                                **  If we did not append a domain name, this
739                                **  must have been a canonical name to start
740                                **  with.  Even if we did append a domain name,
741                                **  in the absence of a wildcard MX this must
742                                **  still be a real MX match.
743                                **  Such MX matches are as good as an A match,
744                                **  fall through.
745                                */
746
747                          case T_A:
748                                /* Flag that a good match was found */
749                                amatch = TRUE;
750
751                                /* continue in case a CNAME also exists */
752                                continue;
753
754                          case T_CNAME:
755                                if (DontExpandCnames)
756                                {
757                                        /* got CNAME -- guaranteed canonical */
758                                        amatch = TRUE;
759                                        break;
760                                }
761
762                                if (loopcnt++ > MAXCNAMEDEPTH)
763                                {
764                                        /*XXX should notify postmaster XXX*/
765                                        message("DNS failure: CNAME loop for %s",
766                                                host);
767                                        if (CurEnv->e_message == NULL)
768                                        {
769                                                char ebuf[MAXLINE];
770
771                                                snprintf(ebuf, sizeof ebuf,
772                                                        "Deferred: DNS failure: CNAME loop for %.100s",
773                                                        host);
774                                                CurEnv->e_message = newstr(ebuf);
775                                        }
776                                        h_errno = NO_RECOVERY;
777                                        *statp = EX_CONFIG;
778                                        return FALSE;
779                                }
780
781                                /* value points at name */
782                                if ((ret = dn_expand((u_char *)&answer,
783                                    eom, ap, (RES_UNC_T) nbuf, sizeof(nbuf))) < 0)
784                                        break;
785                                (void)strncpy(host, nbuf, hbsize); /* XXX */
786                                host[hbsize - 1] = '\0';
787
788                                /*
789                                **  RFC 1034 section 3.6 specifies that CNAME
790                                **  should point at the canonical name -- but
791                                **  urges software to try again anyway.
792                                */
793
794                                goto cnameloop;
795
796                          default:
797                                /* not a record of interest */
798                                continue;
799                        }
800                }
801
802                if (amatch)
803                {
804                        /*
805                        **  Got a good match -- either an A, CNAME, or an
806                        **  exact MX record.  Save it and get out of here.
807                        */
808
809                        mxmatch = *dp;
810                        break;
811                }
812
813                /*
814                **  Nothing definitive yet.
815                **      If this was a T_ANY query, we don't really know what
816                **              was returned -- it might have been a T_NS,
817                **              for example.  Try T_A to be more specific
818                **              during the next pass.
819                **      If this was a T_A query and we haven't yet found a MX
820                **              match, try T_MX if allowed to do so.
821                **      Otherwise, try the next domain.
822                */
823
824                if (qtype == T_ANY)
825                        qtype = T_A;
826                else if (qtype == T_A && !gotmx && (trymx || **dp == '\0'))
827                        qtype = T_MX;
828                else
829                {
830                        qtype = T_ANY;
831                        dp++;
832                }
833        }
834
835        /* if nothing was found, we are done */
836        if (mxmatch == NULL)
837        {
838                *statp = EX_NOHOST;
839                return FALSE;
840        }
841
842        /*
843        **  Create canonical name and return.
844        **  If saved domain name is null, name was already canonical.
845        **  Otherwise append the saved domain name.
846        */
847
848        (void) snprintf(nbuf, sizeof nbuf, "%.*s%s%.*s", MAXDNAME, host,
849                        *mxmatch == '\0' ? "" : ".",
850                        MAXDNAME, mxmatch);
851        strncpy(host, nbuf, hbsize);
852        host[hbsize - 1] = '\0';
853        if (tTd(8, 5))
854                printf("dns_getcanonname: %s\n", host);
855        *statp = EX_OK;
856        return TRUE;
857}
858
859
860
861char *
862gethostalias(host)
863        char *host;
864{
865        char *fname;
866        FILE *fp;
867        register char *p = NULL;
868        int sff = SFF_REGONLY;
869        char buf[MAXLINE];
870        static char hbuf[MAXDNAME];
871
872        if (DontLockReadFiles)
873                sff |= SFF_NOLOCK;
874        fname = getenv("HOSTALIASES");
875        if (fname == NULL ||
876            (fp = safefopen(fname, O_RDONLY, 0, sff)) == NULL)
877                return NULL;
878        while (fgets(buf, sizeof buf, fp) != NULL)
879        {
880                for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++)
881                        continue;
882                if (*p == 0)
883                {
884                        /* syntax error */
885                        continue;
886                }
887                *p++ = '\0';
888                if (strcasecmp(buf, host) == 0)
889                        break;
890        }
891
892        if (feof(fp))
893        {
894                /* no match */
895                fclose(fp);
896                return NULL;
897        }
898        fclose(fp);
899
900        /* got a match; extract the equivalent name */
901        while (*p != '\0' && isascii(*p) && isspace(*p))
902                p++;
903        host = p;
904        while (*p != '\0' && !(isascii(*p) && isspace(*p)))
905                p++;
906        *p = '\0';
907        strncpy(hbuf, host, sizeof hbuf - 1);
908        hbuf[sizeof hbuf - 1] = '\0';
909        return hbuf;
910}
911
912#endif /* NAMED_BIND */
Note: See TracBrowser for help on using the repository browser.