/*
 * Copyright (c) 2004 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: nameok.c,v 1.5 2006/12/27 23:41:09 ca Exp $")
#include "sm/types.h"
#include "sm/error.h"
#include "sm/mta.h"	/* MAXDOMAINLEN */
#include "nameok.h"

#define PERIOD 0x2e
#define ishyphenchar(c) ((c) == 0x2d)
#define isunderscorechar(c) ((c) == 0x5f)
#define isbslashchar(c) ((c) == 0x5c)
#define isperiodchar(c) ((c) == PERIOD)
#define isasterchar(c) ((c) == 0x2a)
#define ISALPHACHAR(c) (((c) >= 0x41 && (c) <= 0x5a) \
		   || ((c) >= 0x61 && (c) <= 0x7a))
#define ISDIGITCHAR(c) ((c) >= 0x30 && (c) <= 0x39)

#define ISBORDERCHAR(c) (ISALPHACHAR(c) || ISDIGITCHAR(c))
#define ISMIDDLECHAR(c) (ISBORDERCHAR(c) || hyphenchar(c))
#define ISDOMAINCHAR(c) ((c) > 0x20 && (c) < 0x7f)

/*
**  VALIDDNSDOMAIN -- check whether a dns domain is syntactically valid
**
**	Parameters:
**		dn -- domain
**		flags -- flags
**
**	Returns:
**		true iff domain is syntactically valid
*/

bool
validdnsdomain(const uchar *dn, uint flags)
{
	uchar ch, pch;
	uint tl, ll, lp;

	if (dn == NULL || *dn == '\0')
		return false;
	pch = ch = '\0';
	tl = 0;

	/*
	**  Grammar:
	**  domain ::= label ['.' domain ] ['.']
	**  label ::= alnum [ ['-'] alnum ]*
	**  Note: this grammar doesn't allow adjacent '-'.
	**  That's ok for RFC 2821 addresses but RFC 952 allows it.
	*/

	if (SM_IS_FLAG(flags, DNS_DOT) && '.' == *dn && '\0' == *(dn + 1))
		return true;

#define MaxLL	64	/* Maximum label length */

	do {
		ll = 0;
		do {
			lp = 0;
			pch = ch;
			ch = *dn++;
			while (ISBORDERCHAR(ch)
			       || (SM_IS_FLAG(flags, DNS__OK) && isunderscorechar(ch))
			       || (SM_IS_FLAG(flags, DNS_HYPHENS) && ishyphenchar(ch) && lp > 0
				  )
			       )
			{
				pch = ch;
				ch = *dn++;
				++tl;
				++ll;
				++lp;
			}
		} while (ishyphenchar(ch) && lp > 0 && ll <= MaxLL);

		/* last character must not be '-' */
		if (SM_IS_FLAG(flags, DNS_HYPHENS) && ishyphenchar(pch))
			return false;

		/* allow trailing dot */
		if (lp == 0 && isperiodchar(pch) && ch == '\0')
			return true;
		if (lp == 0 || ll > MaxLL || ll == 0)
			return false;
	} while (isperiodchar(ch) && ll > 0 && ll <= MaxLL);
	if (tl > MAXDOMAINLEN)
		return false;
	return ('\0' == ch);
}
#if 0

BIND 9.x code; slightly modified:
	int ch, pch, nch;

	pch = '\0';
	ch = *dn++;
	while (ch != '\0')
	{
		nch = *dn++;
		if (isperiodchar(ch))
		{
			if (!isborderchar(pch))
				return false;
		}
		else if (isperiodchar(pch))
		{
			if (!isborderchar(ch))
				return false;
		}
		else if (isperiodchar(nch) || nch == '\0')
		{
			if (!isborderchar(ch))
				return false;
		}
		else
		{
			if (!ismiddlechar(ch))
				return false;
		}
		ppch = pch, pch = ch, ch = nch;
	}
	return true;
}
#endif /* 0 */


syntax highlighted by Code2HTML, v. 0.9.1