1/*	$NetBSD$	*/
2
3/*++
4/* NAME
5/*	valid_mailhost_addr 3
6/* SUMMARY
7/*	mailhost address syntax validation
8/* SYNOPSIS
9/*	#include <valid_mailhost_addr.h>
10/*
11/*	const char *valid_mailhost_addr(name, gripe)
12/*	const char *name;
13/*	int	gripe;
14/*
15/*	int	valid_mailhost_literal(addr, gripe)
16/*	const char *addr;
17/*	int	gripe;
18/* DESCRIPTION
19/*	valid_mailhost_addr() requires that the input is a valid
20/*	RFC 2821 string representation of an IPv4 or IPv6 network
21/*	address.  A valid IPv4 address is in dotted quad decimal
22/*	form.  A valid IPv6 address includes the "IPV6:" prefix as
23/*	required by RFC 2821, and is in valid hexadecimal form or
24/*	in valid IPv4-in-IPv6 form.  The result value is the bare
25/*	address in the input argument (i.e. text after "IPV6:"
26/*	prefix, if any) in case of success, a null pointer in case
27/*	of failure.
28/*
29/*	valid_mailhost_literal() requires an address enclosed in
30/*	[].  The result is non-zero in case of success, zero in
31/*	case of failure.
32/*
33/*	These routines operate silently unless the gripe parameter
34/*	specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
35/*	provide suitable constants.
36/*
37/*	The IPV6_COL macro defines the "IPv6:" prefix.
38/* DIAGNOSTICS
39/*	Warnings are logged with msg_warn().
40/* SEE ALSO
41/*	valid_hostname(3)
42/*	RFC 952, RFC 1123, RFC 1035, RFC 2821
43/* LICENSE
44/* .ad
45/* .fi
46/*	The Secure Mailer license must be distributed with this software.
47/* AUTHOR(S)
48/*	Wietse Venema
49/*	IBM T.J. Watson Research
50/*	P.O. Box 704
51/*	Yorktown Heights, NY 10598, USA
52/*--*/
53
54
55/* System library. */
56
57#include <sys_defs.h>
58#include <string.h>
59
60#ifdef STRCASECMP_IN_STRINGS_H
61#include <strings.h>
62#endif
63
64/* Utility library. */
65
66#include <msg.h>
67#include <myaddrinfo.h>
68
69/* Global library. */
70
71#include <valid_mailhost_addr.h>
72
73/* Application-specific. */
74
75#define IPV6_COL_LEN       (sizeof(IPV6_COL) - 1)
76#define HAS_IPV6_COL(str)  (strncasecmp((str), IPV6_COL, IPV6_COL_LEN) == 0)
77#define SKIP_IPV6_COL(str) (HAS_IPV6_COL(str) ? (str) + IPV6_COL_LEN : (str))
78
79/* valid_mailhost_addr - validate RFC 2821 numerical address form */
80
81const char *valid_mailhost_addr(const char *addr, int gripe)
82{
83    const char *bare_addr;
84
85    bare_addr = SKIP_IPV6_COL(addr);
86    return ((bare_addr != addr ? valid_ipv6_hostaddr : valid_ipv4_hostaddr)
87	    (bare_addr, gripe) ? bare_addr : 0);
88}
89
90/* valid_mailhost_literal - validate [RFC 2821 numerical address] form */
91
92int     valid_mailhost_literal(const char *addr, int gripe)
93{
94    const char *myname = "valid_mailhost_literal";
95    MAI_HOSTADDR_STR hostaddr;
96    const char *last;
97    size_t address_bytes;
98
99    if (*addr != '[') {
100	if (gripe)
101	    msg_warn("%s: '[' expected at start: %.100s", myname, addr);
102	return (0);
103    }
104    if ((last = strchr(addr, ']')) == 0) {
105	if (gripe)
106	    msg_warn("%s: ']' expected at end: %.100s", myname, addr);
107	return (0);
108    }
109    if (last[1]) {
110	if (gripe)
111	    msg_warn("%s: unexpected text after ']': %.100s", myname, addr);
112	return (0);
113    }
114    if ((address_bytes = last - addr - 1) >= sizeof(hostaddr.buf)) {
115	if (gripe)
116	    msg_warn("%s: too much text: %.100s", myname, addr);
117	return (0);
118    }
119    strncpy(hostaddr.buf, addr + 1, address_bytes);
120    hostaddr.buf[address_bytes] = 0;
121    return (valid_mailhost_addr(hostaddr.buf, gripe) != 0);
122}
123
124#ifdef TEST
125
126 /*
127  * Test program - reads hostnames from stdin, reports invalid hostnames to
128  * stderr.
129  */
130#include <stdlib.h>
131
132#include <vstring.h>
133#include <vstream.h>
134#include <vstring_vstream.h>
135#include <msg_vstream.h>
136
137int     main(int unused_argc, char **argv)
138{
139    VSTRING *buffer = vstring_alloc(1);
140
141    msg_vstream_init(argv[0], VSTREAM_ERR);
142    msg_verbose = 1;
143
144    while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
145	msg_info("testing: \"%s\"", vstring_str(buffer));
146	if (vstring_str(buffer)[0] == '[')
147	    valid_mailhost_literal(vstring_str(buffer), DO_GRIPE);
148	else
149	    valid_mailhost_addr(vstring_str(buffer), DO_GRIPE);
150    }
151    exit(0);
152}
153
154#endif
155