129432Sbloom /* 2*34921Sbostic * Copyright (c) 1986 Eric P. Allman 333778Sbostic * Copyright (c) 1988 Regents of the University of California. 433778Sbostic * All rights reserved. 533778Sbostic * 633778Sbostic * Redistribution and use in source and binary forms are permitted 7*34921Sbostic * provided that the above copyright notice and this paragraph are 8*34921Sbostic * duplicated in all such forms and that any documentation, 9*34921Sbostic * advertising materials, and other materials related to such 10*34921Sbostic * distribution and use acknowledge that the software was developed 11*34921Sbostic * by the University of California, Berkeley. The name of the 12*34921Sbostic * University may not be used to endorse or promote products derived 13*34921Sbostic * from this software without specific prior written permission. 14*34921Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15*34921Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16*34921Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1733778Sbostic */ 1829432Sbloom 1929432Sbloom #ifndef lint 20*34921Sbostic static char sccsid[] = "@(#)domain.c 5.15 (Berkeley) 06/30/88"; 2133778Sbostic #endif /* not lint */ 2229432Sbloom 23*34921Sbostic #include <sendmail.h> 2433929Sbostic #include <sys/param.h> 2533929Sbostic #include <arpa/nameser.h> 2633929Sbostic #include <resolv.h> 2733929Sbostic #include <netdb.h> 2829432Sbloom 2929432Sbloom typedef union { 3029432Sbloom HEADER qb1; 3129432Sbloom char qb2[PACKETSZ]; 3229432Sbloom } querybuf; 3329432Sbloom 3433929Sbostic static char hostbuf[MAXMXHOSTS*PACKETSZ]; 3529432Sbloom 3633929Sbostic getmxrr(host, mxhosts, localhost, rcode) 3733929Sbostic char *host, **mxhosts, *localhost; 3833929Sbostic int *rcode; 3929432Sbloom { 4033929Sbostic extern int h_errno; 4133929Sbostic register u_char *eom, *cp; 4233929Sbostic register int i, j, n, nmx; 4333929Sbostic register char *bp; 4429432Sbloom HEADER *hp; 4533929Sbostic querybuf answer; 4633929Sbostic int ancount, qdcount, buflen, seenlocal; 4733929Sbostic u_short pref, localpref, type, prefer[MAXMXHOSTS]; 4829432Sbloom 4933929Sbostic n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); 5029432Sbloom if (n < 0) { 5129432Sbloom #ifdef DEBUG 5233929Sbostic if (tTd(8, 1)) 5333929Sbostic printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", 5433929Sbostic errno, h_errno); 5529432Sbloom #endif 5633929Sbostic switch(h_errno) { 5734021Sbostic case NO_DATA: 5833929Sbostic case NO_RECOVERY: 5933929Sbostic goto punt; 6033929Sbostic case HOST_NOT_FOUND: 6133929Sbostic *rcode = EX_NOHOST; 6233929Sbostic break; 6333929Sbostic case TRY_AGAIN: 6433929Sbostic *rcode = EX_TEMPFAIL; 6533929Sbostic break; 6629432Sbloom } 6733929Sbostic return(-1); 6829432Sbloom } 6933929Sbostic 7033929Sbostic /* find first satisfactory answer */ 7133929Sbostic hp = (HEADER *)&answer; 7233929Sbostic cp = (u_char *)&answer + sizeof(HEADER); 7333929Sbostic eom = (u_char *)&answer + n; 7433929Sbostic for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 7533929Sbostic if ((n = dn_skipname(cp, eom)) < 0) 7633929Sbostic goto punt; 7729432Sbloom nmx = 0; 7829551Sbloom seenlocal = 0; 7929432Sbloom buflen = sizeof(hostbuf); 8033929Sbostic bp = hostbuf; 8133929Sbostic ancount = ntohs(hp->ancount); 8233929Sbostic while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { 8329432Sbloom if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 8429432Sbloom break; 8529432Sbloom cp += n; 8633929Sbostic GETSHORT(type, cp); 8729432Sbloom cp += sizeof(u_short) + sizeof(u_long); 8833929Sbostic GETSHORT(n, cp); 8929432Sbloom if (type != T_MX) { 9029432Sbloom #ifdef DEBUG 9129432Sbloom if (tTd(8, 1) || _res.options & RES_DEBUG) 9229432Sbloom printf("unexpected answer type %d, size %d\n", 9333929Sbostic type, n); 9429432Sbloom #endif 9529432Sbloom cp += n; 9629432Sbloom continue; 9729432Sbloom } 9833929Sbostic GETSHORT(pref, cp); 9929432Sbloom if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 10029432Sbloom break; 10129551Sbloom cp += n; 10233929Sbostic if (!strcasecmp(bp, localhost)) { 10333929Sbostic if (seenlocal == 0 || pref < localpref) 10433929Sbostic localpref = pref; 10529551Sbloom seenlocal = 1; 10629551Sbloom continue; 10729551Sbloom } 10829432Sbloom prefer[nmx] = pref; 10929432Sbloom mxhosts[nmx++] = bp; 11033929Sbostic n = strlen(bp) + 1; 11133929Sbostic bp += n; 11233929Sbostic buflen -= n; 11329432Sbloom } 11429551Sbloom if (nmx == 0) { 11533929Sbostic punt: mxhosts[0] = strcpy(hostbuf, host); 11629551Sbloom return(1); 11729551Sbloom } 11833929Sbostic 11929432Sbloom /* sort the records */ 12029432Sbloom for (i = 0; i < nmx; i++) { 12129432Sbloom for (j = i + 1; j < nmx; j++) { 12229432Sbloom if (prefer[i] > prefer[j]) { 12333929Sbostic register int temp; 12433929Sbostic register char *temp1; 12529432Sbloom 12629432Sbloom temp = prefer[i]; 12729432Sbloom prefer[i] = prefer[j]; 12829432Sbloom prefer[j] = temp; 12929432Sbloom temp1 = mxhosts[i]; 13029432Sbloom mxhosts[i] = mxhosts[j]; 13129432Sbloom mxhosts[j] = temp1; 13229432Sbloom } 13329432Sbloom } 13433929Sbostic if (seenlocal && prefer[i] >= localpref) { 13529551Sbloom /* 13633929Sbostic * truncate higher pref part of list; if we're 13733929Sbostic * the best choice left, we should have realized 13833929Sbostic * awhile ago that this was a local delivery. 13929551Sbloom */ 14033929Sbostic if (i == 0) { 14133929Sbostic *rcode = EX_CONFIG; 14233929Sbostic return(-1); 14329551Sbloom } 14433929Sbostic nmx = i; 14529551Sbloom break; 14629551Sbloom } 14729432Sbloom } 14829432Sbloom return(nmx); 14929432Sbloom } 15029653Sbloom 15129653Sbloom getcanonname(host, hbsize) 15229653Sbloom char *host; 15329653Sbloom int hbsize; 15429653Sbloom { 15533929Sbostic register u_char *eom, *cp; 15633929Sbostic register int n; 15729653Sbloom HEADER *hp; 15833929Sbostic querybuf answer; 15929653Sbloom u_short type; 16033929Sbostic int first, ancount, qdcount, loopcnt; 16133929Sbostic char nbuf[PACKETSZ]; 16229653Sbloom 16333929Sbostic loopcnt = 0; 16433929Sbostic loop: 16534158Sbostic n = res_search(host, C_IN, T_CNAME, (char *)&answer, sizeof(answer)); 16629653Sbloom if (n < 0) { 16729653Sbloom #ifdef DEBUG 16833929Sbostic if (tTd(8, 1)) 16933929Sbostic printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", 17033929Sbostic errno, h_errno); 17129653Sbloom #endif 17229653Sbloom return; 17329653Sbloom } 17433929Sbostic 17533929Sbostic /* find first satisfactory answer */ 17633929Sbostic hp = (HEADER *)&answer; 17729653Sbloom ancount = ntohs(hp->ancount); 17833929Sbostic 17933929Sbostic /* we don't care about errors here, only if we got an answer */ 18029653Sbloom if (ancount == 0) { 18129653Sbloom #ifdef DEBUG 18233929Sbostic if (tTd(8, 1)) 18329653Sbloom printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 18429653Sbloom #endif 18529653Sbloom return; 18629653Sbloom } 18733929Sbostic cp = (u_char *)&answer + sizeof(HEADER); 18833929Sbostic eom = (u_char *)&answer + n; 18933929Sbostic for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 19033929Sbostic if ((n = dn_skipname(cp, eom)) < 0) 19133929Sbostic return; 19233929Sbostic 19333929Sbostic /* 19433929Sbostic * just in case someone puts a CNAME record after another record, 19533929Sbostic * check all records for CNAME; otherwise, just take the first 19633929Sbostic * name found. 19733929Sbostic */ 19833929Sbostic for (first = 1; --ancount >= 0 && cp < eom; cp += n) { 19929653Sbloom if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 20029653Sbloom sizeof(nbuf))) < 0) 20129653Sbloom break; 20233929Sbostic if (first) { /* XXX */ 20329653Sbloom (void)strncpy(host, nbuf, hbsize); 20429653Sbloom host[hbsize - 1] = '\0'; 20529653Sbloom first = 0; 20629653Sbloom } 20729653Sbloom cp += n; 20833929Sbostic GETSHORT(type, cp); 20929653Sbloom cp += sizeof(u_short) + sizeof(u_long); 21033929Sbostic GETSHORT(n, cp); 21129653Sbloom if (type == T_CNAME) { 21229653Sbloom /* 21333929Sbostic * assume that only one cname will be found. More 21433929Sbostic * than one is undefined. Copy so that if dn_expand 21533929Sbostic * fails, `host' is still okay. 21629653Sbloom */ 21729653Sbloom if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 21829653Sbloom sizeof(nbuf))) < 0) 21929653Sbloom break; 22033929Sbostic (void)strncpy(host, nbuf, hbsize); /* XXX */ 22129653Sbloom host[hbsize - 1] = '\0'; 22233929Sbostic if (++loopcnt > 8) /* never be more than 1 */ 22333929Sbostic return; 22433929Sbostic goto loop; 22529653Sbloom } 22629653Sbloom } 22729653Sbloom } 228