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