1 /* 2 * Copyright (c) 1986 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms are permitted 7 * provided that the above copyright notice and this paragraph are 8 * duplicated in all such forms and that any documentation, 9 * advertising materials, and other materials related to such 10 * distribution and use acknowledge that the software was developed 11 * by the University of California, Berkeley. The name of the 12 * University may not be used to endorse or promote products derived 13 * from this software without specific prior written permission. 14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 */ 18 19 #ifndef lint 20 static char sccsid[] = "@(#)domain.c 5.15 (Berkeley) 06/30/88"; 21 #endif /* not lint */ 22 23 #include <sendmail.h> 24 #include <sys/param.h> 25 #include <arpa/nameser.h> 26 #include <resolv.h> 27 #include <netdb.h> 28 29 typedef union { 30 HEADER qb1; 31 char qb2[PACKETSZ]; 32 } querybuf; 33 34 static char hostbuf[MAXMXHOSTS*PACKETSZ]; 35 36 getmxrr(host, mxhosts, localhost, rcode) 37 char *host, **mxhosts, *localhost; 38 int *rcode; 39 { 40 extern int h_errno; 41 register u_char *eom, *cp; 42 register int i, j, n, nmx; 43 register char *bp; 44 HEADER *hp; 45 querybuf answer; 46 int ancount, qdcount, buflen, seenlocal; 47 u_short pref, localpref, type, prefer[MAXMXHOSTS]; 48 49 n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); 50 if (n < 0) { 51 #ifdef DEBUG 52 if (tTd(8, 1)) 53 printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", 54 errno, h_errno); 55 #endif 56 switch(h_errno) { 57 case NO_DATA: 58 case NO_RECOVERY: 59 goto punt; 60 case HOST_NOT_FOUND: 61 *rcode = EX_NOHOST; 62 break; 63 case TRY_AGAIN: 64 *rcode = EX_TEMPFAIL; 65 break; 66 } 67 return(-1); 68 } 69 70 /* find first satisfactory answer */ 71 hp = (HEADER *)&answer; 72 cp = (u_char *)&answer + sizeof(HEADER); 73 eom = (u_char *)&answer + n; 74 for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 75 if ((n = dn_skipname(cp, eom)) < 0) 76 goto punt; 77 nmx = 0; 78 seenlocal = 0; 79 buflen = sizeof(hostbuf); 80 bp = hostbuf; 81 ancount = ntohs(hp->ancount); 82 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { 83 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 84 break; 85 cp += n; 86 GETSHORT(type, cp); 87 cp += sizeof(u_short) + sizeof(u_long); 88 GETSHORT(n, cp); 89 if (type != T_MX) { 90 #ifdef DEBUG 91 if (tTd(8, 1) || _res.options & RES_DEBUG) 92 printf("unexpected answer type %d, size %d\n", 93 type, n); 94 #endif 95 cp += n; 96 continue; 97 } 98 GETSHORT(pref, cp); 99 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 100 break; 101 cp += n; 102 if (!strcasecmp(bp, localhost)) { 103 if (seenlocal == 0 || pref < localpref) 104 localpref = pref; 105 seenlocal = 1; 106 continue; 107 } 108 prefer[nmx] = pref; 109 mxhosts[nmx++] = bp; 110 n = strlen(bp) + 1; 111 bp += n; 112 buflen -= n; 113 } 114 if (nmx == 0) { 115 punt: mxhosts[0] = strcpy(hostbuf, host); 116 return(1); 117 } 118 119 /* sort the records */ 120 for (i = 0; i < nmx; i++) { 121 for (j = i + 1; j < nmx; j++) { 122 if (prefer[i] > prefer[j]) { 123 register int temp; 124 register char *temp1; 125 126 temp = prefer[i]; 127 prefer[i] = prefer[j]; 128 prefer[j] = temp; 129 temp1 = mxhosts[i]; 130 mxhosts[i] = mxhosts[j]; 131 mxhosts[j] = temp1; 132 } 133 } 134 if (seenlocal && prefer[i] >= localpref) { 135 /* 136 * truncate higher pref part of list; if we're 137 * the best choice left, we should have realized 138 * awhile ago that this was a local delivery. 139 */ 140 if (i == 0) { 141 *rcode = EX_CONFIG; 142 return(-1); 143 } 144 nmx = i; 145 break; 146 } 147 } 148 return(nmx); 149 } 150 151 getcanonname(host, hbsize) 152 char *host; 153 int hbsize; 154 { 155 register u_char *eom, *cp; 156 register int n; 157 HEADER *hp; 158 querybuf answer; 159 u_short type; 160 int first, ancount, qdcount, loopcnt; 161 char nbuf[PACKETSZ]; 162 163 loopcnt = 0; 164 loop: 165 n = res_search(host, C_IN, T_CNAME, (char *)&answer, sizeof(answer)); 166 if (n < 0) { 167 #ifdef DEBUG 168 if (tTd(8, 1)) 169 printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", 170 errno, h_errno); 171 #endif 172 return; 173 } 174 175 /* find first satisfactory answer */ 176 hp = (HEADER *)&answer; 177 ancount = ntohs(hp->ancount); 178 179 /* we don't care about errors here, only if we got an answer */ 180 if (ancount == 0) { 181 #ifdef DEBUG 182 if (tTd(8, 1)) 183 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 184 #endif 185 return; 186 } 187 cp = (u_char *)&answer + sizeof(HEADER); 188 eom = (u_char *)&answer + n; 189 for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 190 if ((n = dn_skipname(cp, eom)) < 0) 191 return; 192 193 /* 194 * just in case someone puts a CNAME record after another record, 195 * check all records for CNAME; otherwise, just take the first 196 * name found. 197 */ 198 for (first = 1; --ancount >= 0 && cp < eom; cp += n) { 199 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 200 sizeof(nbuf))) < 0) 201 break; 202 if (first) { /* XXX */ 203 (void)strncpy(host, nbuf, hbsize); 204 host[hbsize - 1] = '\0'; 205 first = 0; 206 } 207 cp += n; 208 GETSHORT(type, cp); 209 cp += sizeof(u_short) + sizeof(u_long); 210 GETSHORT(n, cp); 211 if (type == T_CNAME) { 212 /* 213 * assume that only one cname will be found. More 214 * than one is undefined. Copy so that if dn_expand 215 * fails, `host' is still okay. 216 */ 217 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 218 sizeof(nbuf))) < 0) 219 break; 220 (void)strncpy(host, nbuf, hbsize); /* XXX */ 221 host[hbsize - 1] = '\0'; 222 if (++loopcnt > 8) /* never be more than 1 */ 223 return; 224 goto loop; 225 } 226 } 227 } 228