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