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