129432Sbloom /* 234921Sbostic * Copyright (c) 1986 Eric P. Allman 362524Sbostic * Copyright (c) 1988, 1993 462524Sbostic * The Regents of the University of California. All rights reserved. 533778Sbostic * 642826Sbostic * %sccs.include.redist.c% 733778Sbostic */ 829432Sbloom 940961Sbostic #include "sendmail.h" 1035653Seric 1129432Sbloom #ifndef lint 1266334Seric #if NAMED_BIND 13*68495Seric static char sccsid[] = "@(#)domain.c 8.19.1.1 (Berkeley) 03/06/95 (with name server)"; 1435653Seric #else 15*68495Seric static char sccsid[] = "@(#)domain.c 8.19.1.1 (Berkeley) 03/06/95 (without name server)"; 1635653Seric #endif 1733778Sbostic #endif /* not lint */ 1829432Sbloom 1966334Seric #if NAMED_BIND 2035653Seric 2135653Seric #include <errno.h> 22*68495Seric #include <arpa/nameser.h> 2333929Sbostic #include <resolv.h> 2433929Sbostic #include <netdb.h> 2529432Sbloom 2657454Seric typedef union 2757454Seric { 2857454Seric HEADER qb1; 29*68495Seric char qb2[PACKETSZ]; 3029432Sbloom } querybuf; 3129432Sbloom 3259075Seric static char MXHostBuf[MAXMXHOSTS*PACKETSZ]; 3329432Sbloom 3457943Seric #ifndef MAXDNSRCH 3557943Seric #define MAXDNSRCH 6 /* number of possible domains to search */ 3657943Seric #endif 3757943Seric 3858010Seric #ifndef MAX 3958010Seric #define MAX(a, b) ((a) > (b) ? (a) : (b)) 4058010Seric #endif 4158010Seric 4263969Seric #ifndef NO_DATA 4363969Seric # define NO_DATA NO_ADDRESS 4463969Seric #endif 4563969Seric 46*68495Seric #ifndef HEADERSZ 47*68495Seric # define HEADERSZ sizeof(HEADER) 4865751Seric #endif 4965751Seric 50*68495Seric /* don't use sizeof because sizeof(long) is different on 64-bit machines */ 51*68495Seric #define SHORTSIZE 2 /* size of a short (really, must be 2) */ 52*68495Seric #define LONGSIZE 4 /* size of a long (really, must be 4) */ 53*68495Seric 5462524Sbostic #define MAXCNAMEDEPTH 10 /* maximum depth of CNAME recursion */ 5558248Seric /* 5658248Seric ** GETMXRR -- get MX resource records for a domain 5758248Seric ** 5858248Seric ** Parameters: 5958248Seric ** host -- the name of the host to MX. 6058248Seric ** mxhosts -- a pointer to a return buffer of MX records. 6159273Seric ** droplocalhost -- If TRUE, all MX records less preferred 6259273Seric ** than the local host (as determined by $=w) will 6359273Seric ** be discarded. 6458248Seric ** rcode -- a pointer to an EX_ status code. 6558248Seric ** 6658248Seric ** Returns: 6758248Seric ** The number of MX records found. 6858248Seric ** -1 if there is an internal failure. 6958248Seric ** If no MX records are found, mxhosts[0] is set to host 7058248Seric ** and 1 is returned. 7158248Seric */ 7258248Seric 7359273Seric getmxrr(host, mxhosts, droplocalhost, rcode) 7459075Seric char *host; 7559075Seric char **mxhosts; 7659273Seric bool droplocalhost; 7733929Sbostic int *rcode; 7829432Sbloom { 7933929Sbostic extern int h_errno; 8033929Sbostic register u_char *eom, *cp; 8163840Seric register int i, j, n; 8263840Seric int nmx = 0; 8333929Sbostic register char *bp; 8429432Sbloom HEADER *hp; 8533929Sbostic querybuf answer; 8658857Seric int ancount, qdcount, buflen; 8763840Seric bool seenlocal = FALSE; 88*68495Seric u_short pref, localpref, type; 8958891Seric char *fallbackMX = FallBackMX; 9058891Seric static bool firsttime = TRUE; 91*68495Seric STAB *st; 9264015Seric bool trycanon = FALSE; 9358891Seric u_short prefer[MAXMXHOSTS]; 9457454Seric int weight[MAXMXHOSTS]; 9563840Seric extern bool getcanonname(); 9629432Sbloom 9766145Seric if (tTd(8, 2)) 9866145Seric printf("getmxrr(%s, droplocalhost=%d)\n", host, droplocalhost); 9966145Seric 10058891Seric if (fallbackMX != NULL) 10158891Seric { 102*68495Seric if (firsttime && res_query(FallBackMX, C_IN, T_A, 103*68495Seric (char *) &answer, sizeof answer) < 0) 10458891Seric { 10558891Seric /* this entry is bogus */ 10658891Seric fallbackMX = FallBackMX = NULL; 10758891Seric } 108*68495Seric else if (droplocalhost && 109*68495Seric (st = stab(fallbackMX, ST_CLASS, ST_FIND)) != NULL && 110*68495Seric bitnset('w', st->s_class)) 11158891Seric { 11258891Seric /* don't use fallback for this pass */ 11358891Seric fallbackMX = NULL; 11458891Seric } 11558891Seric firsttime = FALSE; 11658891Seric } 11758891Seric 11864676Seric /* efficiency hack -- numeric or non-MX lookups */ 11964676Seric if (host[0] == '[') 12064676Seric goto punt; 12164676Seric 12236483Sbostic errno = 0; 123*68495Seric n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); 12435653Seric if (n < 0) 12535653Seric { 12633929Sbostic if (tTd(8, 1)) 12752852Seric printf("getmxrr: res_search(%s) failed (errno=%d, h_errno=%d)\n", 12852852Seric (host == NULL) ? "<NULL>" : host, errno, h_errno); 12935653Seric switch (h_errno) 13035653Seric { 13135653Seric case NO_DATA: 13264015Seric trycanon = TRUE; 13364015Seric /* fall through */ 13464015Seric 13535653Seric case NO_RECOVERY: 13635653Seric /* no MX data on this host */ 13733929Sbostic goto punt; 13835653Seric 13935653Seric case HOST_NOT_FOUND: 14066318Seric #ifdef BROKEN_RES_SEARCH 141*68495Seric /* Ultrix resolver returns failure w/ h_errno=0 */ 142*68495Seric case 0: 14366318Seric #endif 144*68495Seric /* the host just doesn't exist */ 14533929Sbostic *rcode = EX_NOHOST; 14664950Seric 147*68495Seric if (!UseNameServer) 148*68495Seric { 149*68495Seric /* might exist in /etc/hosts */ 150*68495Seric goto punt; 151*68495Seric } 152*68495Seric break; 153*68495Seric 15435653Seric case TRY_AGAIN: 15535653Seric /* couldn't connect to the name server */ 156*68495Seric if (!UseNameServer && errno == ECONNREFUSED) 157*68495Seric goto punt; 158*68495Seric 15935653Seric /* it might come up later; better queue it up */ 16033929Sbostic *rcode = EX_TEMPFAIL; 16133929Sbostic break; 16266253Seric 16366253Seric default: 16466253Seric syserr("getmxrr: res_search (%s) failed with impossible h_errno (%d)\n", 16566253Seric host, h_errno); 16666253Seric *rcode = EX_OSERR; 16766253Seric break; 16829432Sbloom } 16935653Seric 17035653Seric /* irreconcilable differences */ 17135653Seric return (-1); 17229432Sbloom } 17333929Sbostic 17433929Sbostic /* find first satisfactory answer */ 17533929Sbostic hp = (HEADER *)&answer; 176*68495Seric cp = (u_char *)&answer + HEADERSZ; 17733929Sbostic eom = (u_char *)&answer + n; 17833929Sbostic for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 17950957Skarels if ((n = dn_skipname(cp, eom)) < 0) 18033929Sbostic goto punt; 18159075Seric buflen = sizeof(MXHostBuf) - 1; 18259075Seric bp = MXHostBuf; 18333929Sbostic ancount = ntohs(hp->ancount); 18458848Seric while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS - 1) 18556336Seric { 18646928Sbostic if ((n = dn_expand((u_char *)&answer, 187*68495Seric eom, cp, (u_char *)bp, buflen)) < 0) 18829432Sbloom break; 18929432Sbloom cp += n; 19033929Sbostic GETSHORT(type, cp); 191*68495Seric cp += SHORTSIZE + LONGSIZE; 19233929Sbostic GETSHORT(n, cp); 19356336Seric if (type != T_MX) 19456336Seric { 19557943Seric if (tTd(8, 8) || _res.options & RES_DEBUG) 19629432Sbloom printf("unexpected answer type %d, size %d\n", 19733929Sbostic type, n); 19829432Sbloom cp += n; 19929432Sbloom continue; 20029432Sbloom } 20133929Sbostic GETSHORT(pref, cp); 20256336Seric if ((n = dn_expand((u_char *)&answer, eom, cp, 203*68495Seric (u_char *)bp, buflen)) < 0) 20429432Sbloom break; 20529551Sbloom cp += n; 206*68495Seric if (droplocalhost && 207*68495Seric (st = stab(bp, ST_CLASS, ST_FIND)) != NULL && 208*68495Seric bitnset('w', st->s_class)) 20956336Seric { 21066145Seric if (tTd(8, 3)) 21166145Seric printf("found localhost (%s) in MX list, pref=%d\n", 21266145Seric bp, pref); 21358857Seric if (!seenlocal || pref < localpref) 21433929Sbostic localpref = pref; 21558857Seric seenlocal = TRUE; 21629551Sbloom continue; 21729551Sbloom } 21857454Seric weight[nmx] = mxrand(bp); 21929432Sbloom prefer[nmx] = pref; 22029432Sbloom mxhosts[nmx++] = bp; 22156336Seric n = strlen(bp); 22233929Sbostic bp += n; 22356336Seric if (bp[-1] != '.') 22456336Seric { 22556336Seric *bp++ = '.'; 22656336Seric n++; 22756336Seric } 22856336Seric *bp++ = '\0'; 22956336Seric buflen -= n + 1; 23029432Sbloom } 23163840Seric 23263840Seric /* sort the records */ 23363840Seric for (i = 0; i < nmx; i++) 23457454Seric { 23563840Seric for (j = i + 1; j < nmx; j++) 23658668Seric { 23763840Seric if (prefer[i] > prefer[j] || 23863840Seric (prefer[i] == prefer[j] && weight[i] > weight[j])) 23963840Seric { 24063840Seric register int temp; 24163840Seric register char *temp1; 24263840Seric 24363840Seric temp = prefer[i]; 24463840Seric prefer[i] = prefer[j]; 24563840Seric prefer[j] = temp; 24663840Seric temp1 = mxhosts[i]; 24763840Seric mxhosts[i] = mxhosts[j]; 24863840Seric mxhosts[j] = temp1; 24963840Seric temp = weight[i]; 25063840Seric weight[i] = weight[j]; 25163840Seric weight[j] = temp; 25263840Seric } 25358668Seric } 25463840Seric if (seenlocal && prefer[i] >= localpref) 25563840Seric { 25663840Seric /* truncate higher preference part of list */ 25763840Seric nmx = i; 25863840Seric } 25929551Sbloom } 26063840Seric 26163840Seric if (nmx == 0) 26257454Seric { 26363840Seric punt: 26463840Seric if (seenlocal && 26563840Seric (!TryNullMXList || gethostbyname(host) == NULL)) 26657454Seric { 26763840Seric /* 26863840Seric ** If we have deleted all MX entries, this is 26963840Seric ** an error -- we should NEVER send to a host that 27063840Seric ** has an MX, and this should have been caught 27163840Seric ** earlier in the config file. 27263840Seric ** 27363840Seric ** Some sites prefer to go ahead and try the 27463840Seric ** A record anyway; that case is handled by 27563840Seric ** setting TryNullMXList. I believe this is a 27663840Seric ** bad idea, but it's up to you.... 27763840Seric */ 27829432Sbloom 27963840Seric *rcode = EX_CONFIG; 28066256Seric syserr("MX list for %s points back to %s", 28166256Seric host, MyHostName); 28263840Seric return -1; 28363840Seric } 28464676Seric strcpy(MXHostBuf, host); 28564676Seric mxhosts[0] = MXHostBuf; 28664676Seric if (host[0] == '[') 28764676Seric { 28864676Seric register char *p; 28964676Seric 29064676Seric /* this may be an MX suppression-style address */ 29164676Seric p = strchr(MXHostBuf, ']'); 29264676Seric if (p != NULL) 29364676Seric { 29464676Seric *p = '\0'; 29564676Seric if (inet_addr(&MXHostBuf[1]) != -1) 29664676Seric *p = ']'; 29764676Seric else 29864677Seric { 29964677Seric trycanon = TRUE; 30064676Seric mxhosts[0]++; 30164677Seric } 30264676Seric } 30364676Seric } 30464677Seric if (trycanon && 30564677Seric getcanonname(mxhosts[0], sizeof MXHostBuf - 2, FALSE)) 30663840Seric { 30764950Seric bp = &MXHostBuf[strlen(MXHostBuf)]; 30863840Seric if (bp[-1] != '.') 30957454Seric { 31063840Seric *bp++ = '.'; 31163840Seric *bp = '\0'; 31229551Sbloom } 31329551Sbloom } 31463840Seric nmx = 1; 31529432Sbloom } 31658848Seric 31758848Seric /* if we have a default lowest preference, include that */ 31864950Seric if (fallbackMX != NULL && !seenlocal) 31964950Seric mxhosts[nmx++] = fallbackMX; 32058848Seric 32157454Seric return (nmx); 32229432Sbloom } 32357135Seric /* 32457454Seric ** MXRAND -- create a randomizer for equal MX preferences 32557454Seric ** 32657454Seric ** If two MX hosts have equal preferences we want to randomize 32757454Seric ** the selection. But in order for signatures to be the same, 32857454Seric ** we need to randomize the same way each time. This function 32957454Seric ** computes a pseudo-random hash function from the host name. 33057454Seric ** 33157454Seric ** Parameters: 33257454Seric ** host -- the name of the host. 33357454Seric ** 33457454Seric ** Returns: 33557454Seric ** A random but repeatable value based on the host name. 33657454Seric ** 33757454Seric ** Side Effects: 33857454Seric ** none. 33957454Seric */ 34057454Seric 34157454Seric mxrand(host) 34257454Seric register char *host; 34357454Seric { 34457454Seric int hfunc; 34557454Seric static unsigned int seed; 34657454Seric 34757454Seric if (seed == 0) 34857454Seric { 34957454Seric seed = (int) curtime() & 0xffff; 35057454Seric if (seed == 0) 35157454Seric seed++; 35257454Seric } 35357454Seric 35457454Seric if (tTd(17, 9)) 35557454Seric printf("mxrand(%s)", host); 35657454Seric 35757454Seric hfunc = seed; 35857454Seric while (*host != '\0') 35957454Seric { 36057454Seric int c = *host++; 36157454Seric 36257454Seric if (isascii(c) && isupper(c)) 36357454Seric c = tolower(c); 36465952Seric hfunc = ((hfunc << 1) ^ c) % 2003; 36557454Seric } 36657454Seric 36757454Seric hfunc &= 0xff; 36857454Seric 36957454Seric if (tTd(17, 9)) 37057454Seric printf(" = %d\n", hfunc); 37157454Seric return hfunc; 37257454Seric } 37357454Seric /* 37457135Seric ** GETCANONNAME -- get the canonical name for named host 37557135Seric ** 37657943Seric ** This algorithm tries to be smart about wildcard MX records. 37757943Seric ** This is hard to do because DNS doesn't tell is if we matched 37857943Seric ** against a wildcard or a specific MX. 37957943Seric ** 38057943Seric ** We always prefer A & CNAME records, since these are presumed 38157943Seric ** to be specific. 38257943Seric ** 38357943Seric ** If we match an MX in one pass and lose it in the next, we use 38457943Seric ** the old one. For example, consider an MX matching *.FOO.BAR.COM. 38557943Seric ** A hostname bletch.foo.bar.com will match against this MX, but 38657943Seric ** will stop matching when we try bletch.bar.com -- so we know 38757943Seric ** that bletch.foo.bar.com must have been right. This fails if 38857943Seric ** there was also an MX record matching *.BAR.COM, but there are 38957943Seric ** some things that just can't be fixed. 39057943Seric ** 39157135Seric ** Parameters: 39257135Seric ** host -- a buffer containing the name of the host. 39357135Seric ** This is a value-result parameter. 39457135Seric ** hbsize -- the size of the host buffer. 39563840Seric ** trymx -- if set, try MX records as well as A and CNAME. 39657135Seric ** 39757135Seric ** Returns: 39857135Seric ** TRUE -- if the host matched. 39957135Seric ** FALSE -- otherwise. 40057135Seric */ 40129653Sbloom 40251314Seric bool 40363840Seric getcanonname(host, hbsize, trymx) 40429653Sbloom char *host; 40529653Sbloom int hbsize; 40663840Seric bool trymx; 40729653Sbloom { 40840277Sbostic extern int h_errno; 40951324Seric register u_char *eom, *ap; 41051324Seric register char *cp; 41133929Sbostic register int n; 41229653Sbloom HEADER *hp; 41333929Sbostic querybuf answer; 41461707Seric int ancount, qdcount; 41551324Seric int ret; 41651324Seric char **domain; 41751324Seric int type; 41857943Seric char **dp; 41957943Seric char *mxmatch; 42057943Seric bool amatch; 421*68495Seric bool gotmx; 42258404Seric int qtype; 42362524Sbostic int loopcnt; 42465193Seric char *xp; 42558010Seric char nbuf[MAX(PACKETSZ, MAXDNAME*2+2)]; 42658039Seric char *searchlist[MAXDNSRCH+2]; 42765193Seric extern char *gethostalias(); 42829653Sbloom 42951324Seric if (tTd(8, 2)) 43051324Seric printf("getcanonname(%s)\n", host); 43151324Seric 43251324Seric if ((_res.options & RES_INIT) == 0 && res_init() == -1) 43351324Seric return (FALSE); 43451324Seric 43536483Sbostic /* 43657943Seric ** Initialize domain search list. If there is at least one 43757943Seric ** dot in the name, search the unmodified name first so we 43857943Seric ** find "vse.CS" in Czechoslovakia instead of in the local 43957943Seric ** domain (e.g., vse.CS.Berkeley.EDU). 44057943Seric ** 44157943Seric ** Older versions of the resolver could create this 44257943Seric ** list by tearing apart the host name. 44357205Seric */ 44457205Seric 44562524Sbostic loopcnt = 0; 44659268Seric cnameloop: 44759268Seric for (cp = host, n = 0; *cp; cp++) 44859268Seric if (*cp == '.') 44959268Seric n++; 45059268Seric 45165193Seric if (n == 0 && (xp = gethostalias(host)) != NULL) 45265193Seric { 45365193Seric if (loopcnt++ > MAXCNAMEDEPTH) 45465193Seric { 45565193Seric syserr("loop in ${HOSTALIASES} file"); 45665193Seric } 45765193Seric else 45865193Seric { 45965193Seric strncpy(host, xp, hbsize); 46065193Seric host[hbsize - 1] = '\0'; 46165193Seric goto cnameloop; 46265193Seric } 46365193Seric } 46465193Seric 46557943Seric dp = searchlist; 46657943Seric if (n > 0) 46757943Seric *dp++ = ""; 46858411Seric if (n >= 0 && *--cp != '.' && bitset(RES_DNSRCH, _res.options)) 46951324Seric { 47057943Seric for (domain = _res.dnsrch; *domain != NULL; ) 47157943Seric *dp++ = *domain++; 47257205Seric } 47358411Seric else if (n == 0 && bitset(RES_DEFNAMES, _res.options)) 47458411Seric { 47558411Seric *dp++ = _res.defdname; 47658411Seric } 47766040Seric else if (*cp == '.') 47866040Seric { 47966040Seric *cp = '\0'; 48066040Seric } 48157943Seric *dp = NULL; 48257205Seric 48357205Seric /* 48457943Seric ** Now run through the search list for the name in question. 48557205Seric */ 48657205Seric 48757943Seric mxmatch = NULL; 48858404Seric qtype = T_ANY; 48957943Seric 49058404Seric for (dp = searchlist; *dp != NULL; ) 49157205Seric { 49258411Seric if (qtype == T_ANY) 49358411Seric gotmx = FALSE; 49457943Seric if (tTd(8, 5)) 49558508Seric printf("getcanonname: trying %s.%s (%s)\n", host, *dp, 49658508Seric qtype == T_ANY ? "ANY" : qtype == T_A ? "A" : 49758508Seric qtype == T_MX ? "MX" : "???"); 49858404Seric ret = res_querydomain(host, *dp, C_IN, qtype, 499*68495Seric &answer, sizeof(answer)); 50057943Seric if (ret <= 0) 50151324Seric { 50258796Seric if (tTd(8, 7)) 50358082Seric printf("\tNO: errno=%d, h_errno=%d\n", 50458082Seric errno, h_errno); 50551324Seric 50658082Seric if (errno == ECONNREFUSED || h_errno == TRY_AGAIN) 50757205Seric { 50857943Seric /* the name server seems to be down */ 50951324Seric h_errno = TRY_AGAIN; 51051910Seric return FALSE; 51151324Seric } 51257943Seric 51358501Seric if (h_errno != HOST_NOT_FOUND) 51458404Seric { 51558501Seric /* might have another type of interest */ 51658501Seric if (qtype == T_ANY) 51758501Seric { 51858501Seric qtype = T_A; 51958501Seric continue; 52058501Seric } 52163840Seric else if (qtype == T_A && !gotmx && trymx) 52258501Seric { 52358501Seric qtype = T_MX; 52458501Seric continue; 52558501Seric } 52658404Seric } 52758404Seric 52857943Seric if (mxmatch != NULL) 52951324Seric { 53057943Seric /* we matched before -- use that one */ 53151324Seric break; 53251324Seric } 53358501Seric 53458501Seric /* otherwise, try the next name */ 53558501Seric dp++; 53658501Seric qtype = T_ANY; 53757943Seric continue; 53851324Seric } 53958796Seric else if (tTd(8, 7)) 54057943Seric printf("\tYES\n"); 54157943Seric 54251910Seric /* 54357943Seric ** This might be a bogus match. Search for A or 54457943Seric ** CNAME records. If we don't have a matching 54557943Seric ** wild card MX record, we will accept MX as well. 54651910Seric */ 54751910Seric 54857943Seric hp = (HEADER *) &answer; 549*68495Seric ap = (u_char *) &answer + HEADERSZ; 55057943Seric eom = (u_char *) &answer + ret; 55157943Seric 55257943Seric /* skip question part of response -- we know what we asked */ 55357943Seric for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ) 55451324Seric { 55557943Seric if ((ret = dn_skipname(ap, eom)) < 0) 55657943Seric { 55757943Seric if (tTd(8, 20)) 55857943Seric printf("qdcount failure (%d)\n", 55957943Seric ntohs(hp->qdcount)); 56057943Seric return FALSE; /* ???XXX??? */ 56157943Seric } 56251324Seric } 56357943Seric 56457943Seric amatch = FALSE; 56557943Seric for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n) 56651324Seric { 56757943Seric n = dn_expand((u_char *) &answer, eom, ap, 568*68495Seric (u_char *) nbuf, sizeof nbuf); 56957943Seric if (n < 0) 57057943Seric break; 57157943Seric ap += n; 57257943Seric GETSHORT(type, ap); 573*68495Seric ap += SHORTSIZE + LONGSIZE; 57457943Seric GETSHORT(n, ap); 57557943Seric switch (type) 57657943Seric { 57757943Seric case T_MX: 57858411Seric gotmx = TRUE; 57964030Seric if (**dp != '\0') 58057943Seric { 58157943Seric /* got a match -- save that info */ 58264030Seric if (trymx && mxmatch == NULL) 58357943Seric mxmatch = *dp; 58457943Seric continue; 58557943Seric } 58633929Sbostic 58757943Seric /* exact MX matches are as good as an A match */ 58857943Seric /* fall through */ 58957205Seric 59057943Seric case T_A: 59157943Seric /* good show */ 59257943Seric amatch = TRUE; 59333929Sbostic 59457943Seric /* continue in case a CNAME also exists */ 59557943Seric continue; 59657943Seric 59757943Seric case T_CNAME: 59862524Sbostic if (loopcnt++ > MAXCNAMEDEPTH) 59962524Sbostic { 60066323Seric /*XXX should notify postmaster XXX*/ 60166323Seric message("DNS failure: CNAME loop for %s", 60262524Sbostic host); 60366323Seric if (CurEnv->e_message == NULL) 60466323Seric { 60566323Seric char ebuf[MAXLINE]; 60666323Seric 60766323Seric sprintf(ebuf, "Deferred: DNS failure: CNAME loop for %s", 60866323Seric host); 60966323Seric CurEnv->e_message = newstr(ebuf); 61066323Seric } 61166323Seric h_errno = NO_RECOVERY; 61266323Seric return FALSE; 61362524Sbostic } 61462524Sbostic 61557943Seric /* value points at name */ 61657943Seric if ((ret = dn_expand((u_char *)&answer, 617*68495Seric eom, ap, (u_char *)nbuf, sizeof(nbuf))) < 0) 61857943Seric break; 61957943Seric (void)strncpy(host, nbuf, hbsize); /* XXX */ 62057943Seric host[hbsize - 1] = '\0'; 62157943Seric 62258844Seric /* 62358844Seric ** RFC 1034 section 3.6 specifies that CNAME 62458844Seric ** should point at the canonical name -- but 62558844Seric ** urges software to try again anyway. 62658844Seric */ 62758844Seric 62858844Seric goto cnameloop; 62958844Seric 63057943Seric default: 63157943Seric /* not a record of interest */ 63257943Seric continue; 63357943Seric } 63451324Seric } 63533929Sbostic 63657943Seric if (amatch) 63757943Seric { 63857943Seric /* got an A record and no CNAME */ 63957943Seric mxmatch = *dp; 64029653Sbloom break; 64129653Sbloom } 64258404Seric 64358404Seric /* 64458404Seric ** If this was a T_ANY query, we may have the info but 64558404Seric ** need an explicit query. Try T_A, then T_MX. 64658404Seric */ 64758404Seric 64858404Seric if (qtype == T_ANY) 64958404Seric qtype = T_A; 65063840Seric else if (qtype == T_A && !gotmx && trymx) 65158404Seric qtype = T_MX; 65258404Seric else 65358404Seric { 65458404Seric /* really nothing in this domain; try the next */ 65558404Seric qtype = T_ANY; 65658404Seric dp++; 65758404Seric } 65829653Sbloom } 65957943Seric 66057943Seric if (mxmatch == NULL) 66157943Seric return FALSE; 66257943Seric 66357943Seric /* create matching name and return */ 66457943Seric (void) sprintf(nbuf, "%.*s%s%.*s", MAXDNAME, host, 66557943Seric *mxmatch == '\0' ? "" : ".", 66657943Seric MAXDNAME, mxmatch); 66757943Seric strncpy(host, nbuf, hbsize); 66857943Seric host[hbsize - 1] = '\0'; 66957943Seric return TRUE; 67029653Sbloom } 67135653Seric 67265193Seric 67365193Seric char * 67465193Seric gethostalias(host) 67565193Seric char *host; 67665193Seric { 67765193Seric char *fname; 67865193Seric FILE *fp; 679*68495Seric register char *p; 68065193Seric char buf[MAXLINE]; 68165193Seric static char hbuf[MAXDNAME]; 68265193Seric 68365193Seric fname = getenv("HOSTALIASES"); 684*68495Seric if (fname == NULL || (fp = fopen(fname, "r")) == NULL) 68565193Seric return NULL; 686*68495Seric setbuf(fp, NULL); 68765193Seric while (fgets(buf, sizeof buf, fp) != NULL) 68865193Seric { 68965193Seric for (p = buf; p != '\0' && !(isascii(*p) && isspace(*p)); p++) 69065193Seric continue; 69165193Seric if (*p == 0) 69265193Seric { 69365193Seric /* syntax error */ 69465193Seric continue; 69565193Seric } 69665193Seric *p++ = '\0'; 69765193Seric if (strcasecmp(buf, host) == 0) 69865193Seric break; 69965193Seric } 70065193Seric 70165193Seric if (feof(fp)) 70265193Seric { 70365193Seric /* no match */ 70465193Seric fclose(fp); 70565193Seric return NULL; 70665193Seric } 70765193Seric 70865193Seric /* got a match; extract the equivalent name */ 70965193Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 71065193Seric p++; 71165193Seric host = p; 71265193Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 71365193Seric p++; 71465193Seric *p = '\0'; 71565193Seric strncpy(hbuf, host, sizeof hbuf - 1); 71665193Seric hbuf[sizeof hbuf - 1] = '\0'; 71765193Seric return hbuf; 71865193Seric } 71965193Seric 72065193Seric 72136494Sphil #else /* not NAMED_BIND */ 72236494Sphil 72336494Sphil #include <netdb.h> 72436494Sphil 72551314Seric bool 72663840Seric getcanonname(host, hbsize, trymx) 72736494Sphil char *host; 72836494Sphil int hbsize; 72963840Seric bool trymx; 73036494Sphil { 73136494Sphil struct hostent *hp; 73236494Sphil 73336494Sphil hp = gethostbyname(host); 73436494Sphil if (hp == NULL) 73551314Seric return (FALSE); 73636494Sphil 737*68495Seric if (strlen(hp->h_name) >= hbsize) 73851314Seric return (FALSE); 73936494Sphil 740*68495Seric (void) strcpy(host, hp->h_name); 74151314Seric return (TRUE); 74236494Sphil } 74336494Sphil 74436494Sphil #endif /* not NAMED_BIND */ 745