xref: /csrg-svn/usr.sbin/sendmail/src/domain.c (revision 29660)
129432Sbloom /*
229432Sbloom **  Sendmail
329432Sbloom **  Copyright (c) 1986  Eric P. Allman
429432Sbloom **  Berkeley, California
529432Sbloom **
629432Sbloom **  Copyright (c) 1986 Regents of the University of California.
729432Sbloom **  All rights reserved.  The Berkeley software License Agreement
829432Sbloom **  specifies the terms and conditions for redistribution.
929432Sbloom */
1029432Sbloom 
11*29660Sbloom #include "sendmail.h"
12*29660Sbloom 
1329551Sbloom #ifndef MXDOMAIN
1429432Sbloom #ifndef lint
15*29660Sbloom static char	SccsId[] = "@(#)domain.c	5.4 (Berkeley) 07/25/86 (no MXDOMAIN)";
1629432Sbloom #endif not lint
1729551Sbloom #else MXDOMAIN
1829432Sbloom 
1929551Sbloom #ifndef lint
20*29660Sbloom static char	SccsId[] = "@(#)domain.c	5.4 (Berkeley) 07/25/86";
2129551Sbloom #endif not lint
2229551Sbloom 
2329432Sbloom # include <sys/param.h>
2429432Sbloom # include <arpa/nameser.h>
2529432Sbloom # include <resolv.h>
2629432Sbloom # include <netdb.h>
2729432Sbloom 
2829432Sbloom typedef union {
2929432Sbloom 	HEADER qb1;
3029432Sbloom 	char qb2[PACKETSZ];
3129432Sbloom } querybuf;
3229432Sbloom 
3329432Sbloom static char hostbuf[BUFSIZ];
3429432Sbloom 
3529432Sbloom int h_errno;
3629432Sbloom 
3729551Sbloom getmxrr(host, mxhosts, maxmx, localhost)
3829432Sbloom 	char *host, **mxhosts;
3929432Sbloom 	int maxmx;
4029551Sbloom 	char *localhost;
4129432Sbloom {
4229432Sbloom 
4329432Sbloom 	HEADER *hp;
4429432Sbloom 	char *eom, *bp, *cp;
4529432Sbloom 	querybuf buf, answer;
4629432Sbloom 	int n, n1, i, j, nmx, ancount, qdcount, buflen;
4729551Sbloom 	int seenlocal;
4829432Sbloom 	u_short prefer[BUFSIZ];
4929551Sbloom 	u_short pref, localpref, type, class;
5029432Sbloom 
5129432Sbloom 	n = res_mkquery(QUERY, host, C_IN, T_MX, (char *)NULL, 0, NULL,
5229432Sbloom 		(char *)&buf, sizeof(buf));
5329432Sbloom 	if (n < 0) {
5429432Sbloom #ifdef DEBUG
5529432Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
5629432Sbloom 			printf("res_mkquery failed\n");
5729432Sbloom #endif
5829551Sbloom 		h_errno = NO_RECOVERY;
5929551Sbloom 		return(-2);
6029432Sbloom 	}
6129432Sbloom 	n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
6229432Sbloom 	if (n < 0) {
6329432Sbloom #ifdef DEBUG
6429432Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
6529432Sbloom 			printf("res_send failed\n");
6629432Sbloom #endif
6729432Sbloom 		h_errno = TRY_AGAIN;
6829432Sbloom 		return (-1);
6929432Sbloom 	}
7029432Sbloom 	eom = (char *)&answer + n;
7129432Sbloom 	/*
7229432Sbloom 	 * find first satisfactory answer
7329432Sbloom 	 */
7429432Sbloom 	hp = (HEADER *) &answer;
7529432Sbloom 	ancount = ntohs(hp->ancount);
7629432Sbloom 	qdcount = ntohs(hp->qdcount);
7729432Sbloom 	if (hp->rcode != NOERROR || ancount == 0) {
7829432Sbloom #ifdef DEBUG
7929432Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
8029432Sbloom 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
8129432Sbloom #endif
8229432Sbloom 		switch (hp->rcode) {
8329432Sbloom 			case NXDOMAIN:
8429432Sbloom 				/* Check if it's an authoritive answer */
8529551Sbloom 				if (hp->aa) {
8629432Sbloom 					h_errno = HOST_NOT_FOUND;
8729551Sbloom 					return(-3);
8829551Sbloom 				} else {
8929432Sbloom 					h_errno = TRY_AGAIN;
9029551Sbloom 					return(-1);
9129551Sbloom 				}
9229432Sbloom 			case SERVFAIL:
9329432Sbloom 				h_errno = TRY_AGAIN;
9429551Sbloom 				return(-1);
9529653Sbloom #ifdef OLDJEEVES
9629653Sbloom 			/*
9729653Sbloom 			 * Jeeves (TOPS-20 server) still does not
9829653Sbloom 			 * support MX records.  For the time being,
9929653Sbloom 			 * we must accept FORMERRs as the same as
10029653Sbloom 			 * NOERROR.
10129653Sbloom 			 */
10229653Sbloom 			case FORMERR:
10329653Sbloom #endif OLDJEEVES
10429432Sbloom 			case NOERROR:
10529551Sbloom 				(void) strcpy(hostbuf, host);
10629551Sbloom 				mxhosts[0] = hostbuf;
10729551Sbloom 				return(1);
10829653Sbloom #ifndef OLDJEEVES
10929432Sbloom 			case FORMERR:
11029653Sbloom #endif OLDJEEVES
11129432Sbloom 			case NOTIMP:
11229432Sbloom 			case REFUSED:
11329432Sbloom 				h_errno = NO_RECOVERY;
11429551Sbloom 				return(-2);
11529432Sbloom 		}
11629432Sbloom 		return (-1);
11729432Sbloom 	}
11829432Sbloom 	bp = hostbuf;
11929432Sbloom 	nmx = 0;
12029551Sbloom 	seenlocal = 0;
12129432Sbloom 	buflen = sizeof(hostbuf);
12229432Sbloom 	cp = (char *)&answer + sizeof(HEADER);
12329432Sbloom 	if (qdcount) {
12429432Sbloom 		cp += dn_skip(cp) + QFIXEDSZ;
12529432Sbloom 		while (--qdcount > 0)
12629432Sbloom 			cp += dn_skip(cp) + QFIXEDSZ;
12729432Sbloom 	}
12829432Sbloom 	while (--ancount >= 0 && cp < eom && nmx < maxmx) {
12929432Sbloom 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
13029432Sbloom 			break;
13129432Sbloom 		cp += n;
13229432Sbloom 		type = getshort(cp);
13329432Sbloom  		cp += sizeof(u_short);
13429551Sbloom 		/*
13529432Sbloom 		class = getshort(cp);
13629551Sbloom 		*/
13729432Sbloom  		cp += sizeof(u_short) + sizeof(u_long);
13829432Sbloom 		n = getshort(cp);
13929432Sbloom 		cp += sizeof(u_short);
14029432Sbloom 		if (type != T_MX)  {
14129432Sbloom #ifdef DEBUG
14229432Sbloom 			if (tTd(8, 1) || _res.options & RES_DEBUG)
14329432Sbloom 				printf("unexpected answer type %d, size %d\n",
14429432Sbloom 					type, n);
14529432Sbloom #endif
14629432Sbloom 			cp += n;
14729432Sbloom 			continue;
14829432Sbloom 		}
14929432Sbloom 		pref = getshort(cp);
15029432Sbloom 		cp += sizeof(u_short);
15129432Sbloom 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
15229432Sbloom 			break;
15329551Sbloom 		cp += n;
15429551Sbloom 		if (sameword(bp, localhost))
15529551Sbloom 		{
15629551Sbloom 			seenlocal = 1;
15729551Sbloom 			localpref = pref;
15829551Sbloom 			continue;
15929551Sbloom 		}
16029432Sbloom 		prefer[nmx] = pref;
16129432Sbloom 		mxhosts[nmx++] = bp;
16229432Sbloom 		n1 = strlen(bp)+1;
16329432Sbloom 		bp += n1;
16429432Sbloom 		buflen -= n1;
16529432Sbloom 	}
16629551Sbloom 	if (nmx == 0) {
16729551Sbloom 		(void) strcpy(hostbuf, host);
16829551Sbloom 		mxhosts[0] = hostbuf;
16929551Sbloom 		return(1);
17029551Sbloom 	}
17129432Sbloom 	/* sort the records */
17229432Sbloom 	for (i = 0; i < nmx; i++) {
17329432Sbloom 		for (j = i + 1; j < nmx; j++) {
17429432Sbloom 			if (prefer[i] > prefer[j]) {
17529432Sbloom 				int temp;
17629432Sbloom 				char *temp1;
17729432Sbloom 
17829432Sbloom 				temp = prefer[i];
17929432Sbloom 				prefer[i] = prefer[j];
18029432Sbloom 				prefer[j] = temp;
18129432Sbloom 				temp1 = mxhosts[i];
18229432Sbloom 				mxhosts[i] = mxhosts[j];
18329432Sbloom 				mxhosts[j] = temp1;
18429432Sbloom 			}
18529432Sbloom 		}
18629551Sbloom 		if (seenlocal && (prefer[i] >= localpref))
18729551Sbloom 		{
18829551Sbloom 			nmx = i;
18929551Sbloom 			/*
19029551Sbloom 			 * We are the first MX, might as well try delivering
19129551Sbloom 			 * since nobody is supposed to have more info.
19229551Sbloom 			 */
19329551Sbloom 			if (nmx == 0)
19429551Sbloom 			{
19529551Sbloom 				(void) strcpy(hostbuf, host);
19629551Sbloom 				mxhosts[0] = hostbuf;
19729551Sbloom 				return(1);
19829551Sbloom 			}
19929551Sbloom 			break;
20029551Sbloom 		}
20129432Sbloom 	}
20229432Sbloom 	return(nmx);
20329432Sbloom }
20429653Sbloom 
20529653Sbloom 
20629653Sbloom getcanonname(host, hbsize)
20729653Sbloom 	char *host;
20829653Sbloom 	int hbsize;
20929653Sbloom {
21029653Sbloom 
21129653Sbloom 	HEADER *hp;
21229653Sbloom 	char *eom, *cp;
21329653Sbloom 	querybuf buf, answer;
21429653Sbloom 	int n, ancount, qdcount;
21529653Sbloom 	u_short type;
21629653Sbloom 	char nbuf[BUFSIZ];
21729653Sbloom 	int first;
21829653Sbloom 
21929653Sbloom 	n = res_mkquery(QUERY, host, C_IN, T_ANY, (char *)NULL, 0, NULL,
22029653Sbloom 		(char *)&buf, sizeof(buf));
22129653Sbloom 	if (n < 0) {
22229653Sbloom #ifdef DEBUG
22329653Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
22429653Sbloom 			printf("res_mkquery failed\n");
22529653Sbloom #endif
22629653Sbloom 		h_errno = NO_RECOVERY;
22729653Sbloom 		return;
22829653Sbloom 	}
22929653Sbloom 	n = res_send((char *)&buf, n, (char *)&answer, sizeof(answer));
23029653Sbloom 	if (n < 0) {
23129653Sbloom #ifdef DEBUG
23229653Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
23329653Sbloom 			printf("res_send failed\n");
23429653Sbloom #endif
23529653Sbloom 		h_errno = TRY_AGAIN;
23629653Sbloom 		return;
23729653Sbloom 	}
23829653Sbloom 	eom = (char *)&answer + n;
23929653Sbloom 	/*
24029653Sbloom 	 * find first satisfactory answer
24129653Sbloom 	 */
24229653Sbloom 	hp = (HEADER *) &answer;
24329653Sbloom 	ancount = ntohs(hp->ancount);
24429653Sbloom 	qdcount = ntohs(hp->qdcount);
24529653Sbloom 	/*
24629653Sbloom 	 * We don't care about errors here, only if we got an answer
24729653Sbloom 	 */
24829653Sbloom 	if (ancount == 0) {
24929653Sbloom #ifdef DEBUG
25029653Sbloom 		if (tTd(8, 1) || _res.options & RES_DEBUG)
25129653Sbloom 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
25229653Sbloom #endif
25329653Sbloom 		return;
25429653Sbloom 	}
25529653Sbloom 	cp = (char *)&answer + sizeof(HEADER);
25629653Sbloom 	if (qdcount) {
25729653Sbloom 		cp += dn_skip(cp) + QFIXEDSZ;
25829653Sbloom 		while (--qdcount > 0)
25929653Sbloom 			cp += dn_skip(cp) + QFIXEDSZ;
26029653Sbloom 	}
26129653Sbloom 	first = 1;
26229653Sbloom 	while (--ancount >= 0 && cp < eom) {
26329653Sbloom 		if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
26429653Sbloom 		    sizeof(nbuf))) < 0)
26529653Sbloom 			break;
26629653Sbloom 		if (first) {
26729653Sbloom 			(void)strncpy(host, nbuf, hbsize);
26829653Sbloom 			host[hbsize - 1] = '\0';
26929653Sbloom 			first = 0;
27029653Sbloom 		}
27129653Sbloom 		cp += n;
27229653Sbloom 		type = getshort(cp);
27329653Sbloom  		cp += sizeof(u_short);
27429653Sbloom  		cp += sizeof(u_short) + sizeof(u_long);
27529653Sbloom 		n = getshort(cp);
27629653Sbloom 		cp += sizeof(u_short);
27729653Sbloom 		if (type == T_CNAME)  {
27829653Sbloom 			/*
27929653Sbloom 			 * Assume that only one cname will be found.  More
28029653Sbloom 			 * than one is undefined.
28129653Sbloom 			 */
28229653Sbloom 			if ((n = dn_expand((char *)&answer, eom, cp, nbuf,
28329653Sbloom 			    sizeof(nbuf))) < 0)
28429653Sbloom 				break;
28529653Sbloom 			(void)strncpy(host, nbuf, hbsize);
28629653Sbloom 			host[hbsize - 1] = '\0';
28729653Sbloom 			getcanonname(host, hbsize);
28829653Sbloom 			break;
28929653Sbloom 		}
29029653Sbloom 		cp += n;
29129653Sbloom 	}
29229653Sbloom 	return;
29329653Sbloom }
29429551Sbloom #endif MXDOMAIN
295