1 /* 2 * Copyright (c) 1986 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #include "sendmail.h" 10 11 #ifndef lint 12 #ifdef NAMED_BIND 13 static char sccsid[] = "@(#)domain.c 5.22 (Berkeley) 06/01/90 (with name server)"; 14 #else 15 static char sccsid[] = "@(#)domain.c 5.22 (Berkeley) 06/01/90 (without name server)"; 16 #endif 17 #endif /* not lint */ 18 19 #ifdef NAMED_BIND 20 21 #include <sys/param.h> 22 #include <errno.h> 23 #include <arpa/nameser.h> 24 #include <resolv.h> 25 #include <netdb.h> 26 27 typedef union { 28 HEADER qb1; 29 char qb2[PACKETSZ]; 30 } querybuf; 31 32 static char hostbuf[MAXMXHOSTS*PACKETSZ]; 33 34 getmxrr(host, mxhosts, localhost, rcode) 35 char *host, **mxhosts, *localhost; 36 int *rcode; 37 { 38 extern int h_errno; 39 register u_char *eom, *cp; 40 register int i, j, n, nmx; 41 register char *bp; 42 HEADER *hp; 43 querybuf answer; 44 int ancount, qdcount, buflen, seenlocal; 45 u_short pref, localpref, type, prefer[MAXMXHOSTS]; 46 47 errno = 0; 48 n = res_search(host, C_IN, T_MX, (char *)&answer, sizeof(answer)); 49 if (n < 0) 50 { 51 if (tTd(8, 1)) 52 printf("getmxrr: res_search failed (errno=%d, h_errno=%d)\n", 53 errno, h_errno); 54 switch (h_errno) 55 { 56 case NO_DATA: 57 case NO_RECOVERY: 58 /* no MX data on this host */ 59 goto punt; 60 61 case HOST_NOT_FOUND: 62 /* the host just doesn't exist */ 63 *rcode = EX_NOHOST; 64 break; 65 66 case TRY_AGAIN: 67 /* couldn't connect to the name server */ 68 if (!UseNameServer && errno == ECONNREFUSED) 69 goto punt; 70 71 /* it might come up later; better queue it up */ 72 *rcode = EX_TEMPFAIL; 73 break; 74 } 75 76 /* irreconcilable differences */ 77 return (-1); 78 } 79 80 /* find first satisfactory answer */ 81 hp = (HEADER *)&answer; 82 cp = (u_char *)&answer + sizeof(HEADER); 83 eom = (u_char *)&answer + n; 84 for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 85 if ((n = dn_skipname(cp, eom)) < 0) 86 goto punt; 87 nmx = 0; 88 seenlocal = 0; 89 buflen = sizeof(hostbuf); 90 bp = hostbuf; 91 ancount = ntohs(hp->ancount); 92 while (--ancount >= 0 && cp < eom && nmx < MAXMXHOSTS) { 93 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 94 break; 95 cp += n; 96 GETSHORT(type, cp); 97 cp += sizeof(u_short) + sizeof(u_long); 98 GETSHORT(n, cp); 99 if (type != T_MX) { 100 if (tTd(8, 1) || _res.options & RES_DEBUG) 101 printf("unexpected answer type %d, size %d\n", 102 type, n); 103 cp += n; 104 continue; 105 } 106 GETSHORT(pref, cp); 107 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 108 break; 109 cp += n; 110 if (!strcasecmp(bp, localhost)) { 111 if (seenlocal == 0 || pref < localpref) 112 localpref = pref; 113 seenlocal = 1; 114 continue; 115 } 116 prefer[nmx] = pref; 117 mxhosts[nmx++] = bp; 118 n = strlen(bp) + 1; 119 bp += n; 120 buflen -= n; 121 } 122 if (nmx == 0) { 123 punt: mxhosts[0] = strcpy(hostbuf, host); 124 return(1); 125 } 126 127 /* sort the records */ 128 for (i = 0; i < nmx; i++) { 129 for (j = i + 1; j < nmx; j++) { 130 if (prefer[i] > prefer[j] || 131 (prefer[i] == prefer[j] && rand() % 1 == 0)) { 132 register int temp; 133 register char *temp1; 134 135 temp = prefer[i]; 136 prefer[i] = prefer[j]; 137 prefer[j] = temp; 138 temp1 = mxhosts[i]; 139 mxhosts[i] = mxhosts[j]; 140 mxhosts[j] = temp1; 141 } 142 } 143 if (seenlocal && prefer[i] >= localpref) { 144 /* 145 * truncate higher pref part of list; if we're 146 * the best choice left, we should have realized 147 * awhile ago that this was a local delivery. 148 */ 149 if (i == 0) { 150 *rcode = EX_CONFIG; 151 return(-1); 152 } 153 nmx = i; 154 break; 155 } 156 } 157 return(nmx); 158 } 159 160 getcanonname(host, hbsize) 161 char *host; 162 int hbsize; 163 { 164 extern int h_errno; 165 register u_char *eom, *cp; 166 register int n; 167 HEADER *hp; 168 querybuf answer; 169 u_short type; 170 int first, ancount, qdcount, loopcnt; 171 char nbuf[PACKETSZ]; 172 173 loopcnt = 0; 174 loop: 175 /* 176 * Use query type of ANY if possible (NO_WILDCARD_MX), which will 177 * find types CNAME, A, and MX, and will cause all existing records 178 * to be cached by our local server. If there is (might be) a 179 * wildcard MX record in the local domain or its parents that are 180 * searched, we can't use ANY; it would cause fully-qualified names 181 * to match as names in a local domain. 182 */ 183 # ifdef NO_WILDCARD_MX 184 n = res_search(host, C_IN, T_ANY, (char *)&answer, sizeof(answer)); 185 # else 186 n = res_search(host, C_IN, T_CNAME, (char *)&answer, sizeof(answer)); 187 # endif 188 if (n < 0) { 189 if (tTd(8, 1)) 190 printf("getcanonname: res_search failed (errno=%d, h_errno=%d)\n", 191 errno, h_errno); 192 return; 193 } 194 195 /* find first satisfactory answer */ 196 hp = (HEADER *)&answer; 197 ancount = ntohs(hp->ancount); 198 199 /* we don't care about errors here, only if we got an answer */ 200 if (ancount == 0) { 201 if (tTd(8, 1)) 202 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 203 return; 204 } 205 cp = (u_char *)&answer + sizeof(HEADER); 206 eom = (u_char *)&answer + n; 207 for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ) 208 if ((n = dn_skipname(cp, eom)) < 0) 209 return; 210 211 /* 212 * just in case someone puts a CNAME record after another record, 213 * check all records for CNAME; otherwise, just take the first 214 * name found. 215 */ 216 for (first = 1; --ancount >= 0 && cp < eom; cp += n) { 217 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 218 sizeof(nbuf))) < 0) 219 break; 220 if (first) { /* XXX */ 221 (void)strncpy(host, nbuf, hbsize); 222 host[hbsize - 1] = '\0'; 223 first = 0; 224 } 225 cp += n; 226 GETSHORT(type, cp); 227 cp += sizeof(u_short) + sizeof(u_long); 228 GETSHORT(n, cp); 229 if (type == T_CNAME) { 230 /* 231 * assume that only one cname will be found. More 232 * than one is undefined. Copy so that if dn_expand 233 * fails, `host' is still okay. 234 */ 235 if ((n = dn_expand((char *)&answer, eom, cp, nbuf, 236 sizeof(nbuf))) < 0) 237 break; 238 (void)strncpy(host, nbuf, hbsize); /* XXX */ 239 host[hbsize - 1] = '\0'; 240 if (++loopcnt > 8) /* never be more than 1 */ 241 return; 242 goto loop; 243 } 244 } 245 } 246 247 #else /* not NAMED_BIND */ 248 249 #include <netdb.h> 250 251 getcanonname(host, hbsize) 252 char *host; 253 int hbsize; 254 { 255 struct hostent *hp; 256 257 hp = gethostbyname(host); 258 if (hp == NULL) 259 return; 260 261 if (strlen(hp->h_name) >= hbsize) 262 return; 263 264 (void) strcpy(host, hp->h_name); 265 } 266 267 #endif /* not NAMED_BIND */ 268