xref: /csrg-svn/usr.sbin/sendmail/src/domain.c (revision 33778)
129432Sbloom /*
2*33778Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*33778Sbostic  * All rights reserved.
4*33778Sbostic  *
5*33778Sbostic  * Redistribution and use in source and binary forms are permitted
6*33778Sbostic  * provided that this notice is preserved and that due credit is given
7*33778Sbostic  * to the University of California at Berkeley. The name of the University
8*33778Sbostic  * may not be used to endorse or promote products derived from this
9*33778Sbostic  * software without specific prior written permission. This software
10*33778Sbostic  * is provided ``as is'' without express or implied warranty.
11*33778Sbostic  *
12*33778Sbostic  *  Sendmail
13*33778Sbostic  *  Copyright (c) 1986  Eric P. Allman
14*33778Sbostic  *  Berkeley, California
15*33778Sbostic  */
1629432Sbloom 
1729660Sbloom #include "sendmail.h"
1829660Sbloom 
1929432Sbloom #ifndef lint
20*33778Sbostic #ifdef MXDOMAIN
21*33778Sbostic static char sccsid[] = "@(#)domain.c	5.10 (Berkeley) 03/24/88 (with MXDOMAIN)";
22*33778Sbostic #else
23*33778Sbostic static char sccsid[] = "@(#)domain.c	5.10 (Berkeley) 03/24/88 (without MXDOMAIN)";
24*33778Sbostic #endif
25*33778Sbostic #endif /* not lint */
2629432Sbloom 
27*33778Sbostic #ifdef MXDOMAIN
2829432Sbloom # include <sys/param.h>
2929432Sbloom # include <arpa/nameser.h>
3029432Sbloom # include <resolv.h>
3129432Sbloom # include <netdb.h>
3229432Sbloom 
3329432Sbloom typedef union {
3429432Sbloom 	HEADER qb1;
3529432Sbloom 	char qb2[PACKETSZ];
3629432Sbloom } querybuf;
3729432Sbloom 
3830448Seric static char	hostbuf[BUFSIZ];
3930448Seric int		h_errno;
4033777Sbostic extern u_short	_getshort();
4129432Sbloom 
4229551Sbloom getmxrr(host, mxhosts, maxmx, localhost)
4329432Sbloom 	char *host, **mxhosts;
4429432Sbloom 	int maxmx;
4529551Sbloom 	char *localhost;
4629432Sbloom {
4729432Sbloom 
4829432Sbloom 	HEADER *hp;
4929432Sbloom 	char *eom, *bp, *cp;
5029432Sbloom 	querybuf buf, answer;
5129432Sbloom 	int n, n1, i, j, nmx, ancount, qdcount, buflen;
5229551Sbloom 	int seenlocal;
5329432Sbloom 	u_short prefer[BUFSIZ];
5429551Sbloom 	u_short pref, localpref, type, class;
5529432Sbloom 
5629432Sbloom 	n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL,
5729432Sbloom 		(char *)&buf, sizeof(buf));
5829432Sbloom 	if (n < 0) {
5929432Sbloom #ifdef DEBUG
6029432Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
6129432Sbloom 			printf("res_mkquery failed\n");
6229432Sbloom #endif
6329551Sbloom 		h_errno = NO_RECOVERY;
6429551Sbloom 		return(-2);
6529432Sbloom 	}
6629432Sbloom 	n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
6729432Sbloom 	if (n < 0) {
6829432Sbloom #ifdef DEBUG
6929432Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
7029432Sbloom 			printf("res_send failed\n");
7129432Sbloom #endif
7229432Sbloom 		h_errno = TRY_AGAIN;
7329432Sbloom 		return (-1);
7429432Sbloom 	}
7529432Sbloom 	eom = (char *)&answer + n;
7629432Sbloom 	/*
7729432Sbloom 	 * find first satisfactory answer
7829432Sbloom 	 */
7929432Sbloom 	hp = (HEADER *) &answer;
8029432Sbloom 	ancount = ntohs(hp->ancount);
8129432Sbloom 	qdcount = ntohs(hp->qdcount);
8229432Sbloom 	if (hp->rcode != NOERROR || ancount == 0) {
8329432Sbloom #ifdef DEBUG
8429432Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
8529432Sbloom 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
8629432Sbloom #endif
8729432Sbloom 		switch (hp->rcode) {
8829432Sbloom 			case NXDOMAIN:
8929432Sbloom 				/* Check if it's an authoritive answer */
9029551Sbloom 				if (hp->aa) {
9129432Sbloom 					h_errno = HOST_NOT_FOUND;
9229551Sbloom 					return(-3);
9329551Sbloom 				} else {
9429432Sbloom 					h_errno = TRY_AGAIN;
9529551Sbloom 					return(-1);
9629551Sbloom 				}
9729432Sbloom 			case SERVFAIL:
9829432Sbloom 				h_errno = TRY_AGAIN;
9929551Sbloom 				return(-1);
10029653Sbloom #ifdef OLDJEEVES
10129653Sbloom 			/*
10229653Sbloom 			 * Jeeves (TOPS-20 server) still does not
10329653Sbloom 			 * support MX records.  For the time being,
10429653Sbloom 			 * we must accept FORMERRs as the same as
10529653Sbloom 			 * NOERROR.
10629653Sbloom 			 */
10729653Sbloom 			case FORMERR:
10829653Sbloom #endif OLDJEEVES
10929432Sbloom 			case NOERROR:
11029551Sbloom 				(void) strcpy(hostbuf, host);
11129551Sbloom 				mxhosts[0] = hostbuf;
11229551Sbloom 				return(1);
11329653Sbloom #ifndef OLDJEEVES
11429432Sbloom 			case FORMERR:
11529653Sbloom #endif OLDJEEVES
11629432Sbloom 			case NOTIMP:
11729432Sbloom 			case REFUSED:
11829432Sbloom 				h_errno = NO_RECOVERY;
11929551Sbloom 				return(-2);
12029432Sbloom 		}
12129432Sbloom 		return (-1);
12229432Sbloom 	}
12329432Sbloom 	bp = hostbuf;
12429432Sbloom 	nmx = 0;
12529551Sbloom 	seenlocal = 0;
12629432Sbloom 	buflen = sizeof(hostbuf);
12729432Sbloom 	cp = (char *)&answer + sizeof(HEADER);
12829432Sbloom 	if (qdcount) {
12932988Sbostic 		cp += dn_skipname(cp, eom) + QFIXEDSZ;
13029432Sbloom 		while (--qdcount > 0)
13132988Sbostic 			cp += dn_skipname(cp, eom) + QFIXEDSZ;
13229432Sbloom 	}
13329432Sbloom 	while (--ancount >= 0 && cp < eom && nmx < maxmx) {
13429432Sbloom 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
13529432Sbloom 			break;
13629432Sbloom 		cp += n;
13733777Sbostic 		type = _getshort(cp);
13829432Sbloom  		cp += sizeof(u_short);
13929551Sbloom 		/*
14033777Sbostic 		class = _getshort(cp);
14129551Sbloom 		*/
14229432Sbloom  		cp += sizeof(u_short) + sizeof(u_long);
14333777Sbostic 		n = _getshort(cp);
14429432Sbloom 		cp += sizeof(u_short);
14529432Sbloom 		if (type != T_MX)  {
14629432Sbloom #ifdef DEBUG
14729432Sbloom 			if (tTd(8, 1) || _res.options & RES_DEBUG)
14829432Sbloom 				printf("unexpected answer type %d, size %d\n",
14929432Sbloom 					type, n);
15029432Sbloom #endif
15129432Sbloom 			cp += n;
15229432Sbloom 			continue;
15329432Sbloom 		}
15433777Sbostic 		pref = _getshort(cp);
15529432Sbloom 		cp += sizeof(u_short);
15629432Sbloom 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
15729432Sbloom 			break;
15829551Sbloom 		cp += n;
15933725Sbostic 		if (!strcasecmp(bp, localhost))
16029551Sbloom 		{
16129551Sbloom 			seenlocal = 1;
16229551Sbloom 			localpref = pref;
16329551Sbloom 			continue;
16429551Sbloom 		}
16529432Sbloom 		prefer[nmx] = pref;
16629432Sbloom 		mxhosts[nmx++] = bp;
16729432Sbloom 		n1 = strlen(bp)+1;
16829432Sbloom 		bp += n1;
16929432Sbloom 		buflen -= n1;
17029432Sbloom 	}
17129551Sbloom 	if (nmx == 0) {
17229551Sbloom 		(void) strcpy(hostbuf, host);
17329551Sbloom 		mxhosts[0] = hostbuf;
17429551Sbloom 		return(1);
17529551Sbloom 	}
17629432Sbloom 	/* sort the records */
17729432Sbloom 	for (i = 0; i < nmx; i++) {
17829432Sbloom 		for (j = i + 1; j < nmx; j++) {
17929432Sbloom 			if (prefer[i] > prefer[j]) {
18029432Sbloom 				int temp;
18129432Sbloom 				char *temp1;
18229432Sbloom 
18329432Sbloom 				temp = prefer[i];
18429432Sbloom 				prefer[i] = prefer[j];
18529432Sbloom 				prefer[j] = temp;
18629432Sbloom 				temp1 = mxhosts[i];
18729432Sbloom 				mxhosts[i] = mxhosts[j];
18829432Sbloom 				mxhosts[j] = temp1;
18929432Sbloom 			}
19029432Sbloom 		}
19129551Sbloom 		if (seenlocal && (prefer[i] >= localpref))
19229551Sbloom 		{
19329551Sbloom 			nmx = i;
19429551Sbloom 			/*
19529551Sbloom 			 * We are the first MX, might as well try delivering
19629551Sbloom 			 * since nobody is supposed to have more info.
19729551Sbloom 			 */
19829551Sbloom 			if (nmx == 0)
19929551Sbloom 			{
20029551Sbloom 				(void) strcpy(hostbuf, host);
20129551Sbloom 				mxhosts[0] = hostbuf;
20229551Sbloom 				return(1);
20329551Sbloom 			}
20429551Sbloom 			break;
20529551Sbloom 		}
20629432Sbloom 	}
20729432Sbloom 	return(nmx);
20829432Sbloom }
20929653Sbloom 
21029653Sbloom 
21129653Sbloom getcanonname(host, hbsize)
21229653Sbloom 	char *host;
21329653Sbloom 	int hbsize;
21429653Sbloom {
21529653Sbloom 
21629653Sbloom 	HEADER *hp;
21729653Sbloom 	char *eom, *cp;
21829653Sbloom 	querybuf buf, answer;
21929653Sbloom 	int n, ancount, qdcount;
22029653Sbloom 	u_short type;
22129653Sbloom 	char nbuf[BUFSIZ];
22229653Sbloom 	int first;
22329653Sbloom 
22429653Sbloom 	n = res_mkquery(QUERY, host, C_IN, T_ANY, (char *)NULL, 0, NULL,
22529653Sbloom 		(char *)&buf, sizeof(buf));
22629653Sbloom 	if (n < 0) {
22729653Sbloom #ifdef DEBUG
22829653Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
22929653Sbloom 			printf("res_mkquery failed\n");
23029653Sbloom #endif
23129653Sbloom 		h_errno = NO_RECOVERY;
23229653Sbloom 		return;
23329653Sbloom 	}
23429653Sbloom 	n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
23529653Sbloom 	if (n < 0) {
23629653Sbloom #ifdef DEBUG
23729653Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
23829653Sbloom 			printf("res_send failed\n");
23929653Sbloom #endif
24029653Sbloom 		h_errno = TRY_AGAIN;
24129653Sbloom 		return;
24229653Sbloom 	}
24329653Sbloom 	eom = (char *)&answer + n;
24429653Sbloom 	/*
24529653Sbloom 	 * find first satisfactory answer
24629653Sbloom 	 */
24729653Sbloom 	hp = (HEADER *) &answer;
24829653Sbloom 	ancount = ntohs(hp->ancount);
24929653Sbloom 	qdcount = ntohs(hp->qdcount);
25029653Sbloom 	/*
25129653Sbloom 	 * We don't care about errors here, only if we got an answer
25229653Sbloom 	 */
25329653Sbloom 	if (ancount == 0) {
25429653Sbloom #ifdef DEBUG
25529653Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
25629653Sbloom 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
25729653Sbloom #endif
25829653Sbloom 		return;
25929653Sbloom 	}
26029653Sbloom 	cp = (char *)&answer + sizeof(HEADER);
26129653Sbloom 	if (qdcount) {
26232988Sbostic 		cp += dn_skipname(cp, eom) + QFIXEDSZ;
26329653Sbloom 		while (--qdcount > 0)
26432988Sbostic 			cp += dn_skipname(cp, eom) + QFIXEDSZ;
26529653Sbloom 	}
26629653Sbloom 	first = 1;
26729653Sbloom 	while (--ancount >= 0 && cp < eom) {
26829653Sbloom 		if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
26929653Sbloom 		    sizeof(nbuf))) < 0)
27029653Sbloom 			break;
27129653Sbloom 		if (first) {
27229653Sbloom 			(void)strncpy(host, nbuf, hbsize);
27329653Sbloom 			host[hbsize - 1] = '\0';
27429653Sbloom 			first = 0;
27529653Sbloom 		}
27629653Sbloom 		cp += n;
27733777Sbostic 		type = _getshort(cp);
27829653Sbloom  		cp += sizeof(u_short);
27929653Sbloom  		cp += sizeof(u_short) + sizeof(u_long);
28033777Sbostic 		n = _getshort(cp);
28129653Sbloom 		cp += sizeof(u_short);
28229653Sbloom 		if (type == T_CNAME)  {
28329653Sbloom 			/*
28429653Sbloom 			 * Assume that only one cname will be found.  More
28529653Sbloom 			 * than one is undefined.
28629653Sbloom 			 */
28729653Sbloom 			if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
28829653Sbloom 			    sizeof(nbuf))) < 0)
28929653Sbloom 				break;
29029653Sbloom 			(void)strncpy(host, nbuf, hbsize);
29129653Sbloom 			host[hbsize - 1] = '\0';
29229653Sbloom 			getcanonname(host, hbsize);
29329653Sbloom 			break;
29429653Sbloom 		}
29529653Sbloom 		cp += n;
29629653Sbloom 	}
29729653Sbloom 	return;
29829653Sbloom }
29929551Sbloom #endif MXDOMAIN
300