summaryrefslogtreecommitdiffstats
path: root/src/global/valid_mailhost_addr.c
blob: 79a7900185711d290fb569eda923e5349812e72f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*++
/* NAME
/*	valid_mailhost_addr 3
/* SUMMARY
/*	mailhost address syntax validation
/* SYNOPSIS
/*	#include <valid_mailhost_addr.h>
/*
/*	const char *valid_mailhost_addr(name, gripe)
/*	const char *name;
/*	int	gripe;
/*
/*	int	valid_mailhost_literal(addr, gripe)
/*	const char *addr;
/*	int	gripe;
/* DESCRIPTION
/*	valid_mailhost_addr() requires that the input is a valid
/*	RFC 2821 string representation of an IPv4 or IPv6 network
/*	address.  A valid IPv4 address is in dotted quad decimal
/*	form.  A valid IPv6 address includes the "IPV6:" prefix as
/*	required by RFC 2821, and is in valid hexadecimal form or
/*	in valid IPv4-in-IPv6 form.  The result value is the bare
/*	address in the input argument (i.e. text after "IPV6:"
/*	prefix, if any) in case of success, a null pointer in case
/*	of failure.
/*
/*	valid_mailhost_literal() requires an address enclosed in
/*	[].  The result is non-zero in case of success, zero in
/*	case of failure.
/*
/*	These routines operate silently unless the gripe parameter
/*	specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
/*	provide suitable constants.
/*
/*	The IPV6_COL macro defines the "IPv6:" prefix.
/* DIAGNOSTICS
/*	Warnings are logged with msg_warn().
/* SEE ALSO
/*	valid_hostname(3)
/*	RFC 952, RFC 1123, RFC 1035, RFC 2821
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <string.h>

#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif

/* Utility library. */

#include <msg.h>
#include <myaddrinfo.h>

/* Global library. */

#include <valid_mailhost_addr.h>

/* Application-specific. */

#define IPV6_COL_LEN       (sizeof(IPV6_COL) - 1)
#define HAS_IPV6_COL(str)  (strncasecmp((str), IPV6_COL, IPV6_COL_LEN) == 0)
#define SKIP_IPV6_COL(str) (HAS_IPV6_COL(str) ? (str) + IPV6_COL_LEN : (str))

/* valid_mailhost_addr - validate RFC 2821 numerical address form */

const char *valid_mailhost_addr(const char *addr, int gripe)
{
    const char *bare_addr;

    bare_addr = SKIP_IPV6_COL(addr);
    return ((bare_addr != addr ? valid_ipv6_hostaddr : valid_ipv4_hostaddr)
	    (bare_addr, gripe) ? bare_addr : 0);
}

/* valid_mailhost_literal - validate [RFC 2821 numerical address] form */

int     valid_mailhost_literal(const char *addr, int gripe)
{
    const char *myname = "valid_mailhost_literal";
    MAI_HOSTADDR_STR hostaddr;
    const char *last;
    size_t address_bytes;

    if (*addr != '[') {
	if (gripe)
	    msg_warn("%s: '[' expected at start: %.100s", myname, addr);
	return (0);
    }
    if ((last = strchr(addr, ']')) == 0) {
	if (gripe)
	    msg_warn("%s: ']' expected at end: %.100s", myname, addr);
	return (0);
    }
    if (last[1]) {
	if (gripe)
	    msg_warn("%s: unexpected text after ']': %.100s", myname, addr);
	return (0);
    }
    if ((address_bytes = last - addr - 1) >= sizeof(hostaddr.buf)) {
	if (gripe)
	    msg_warn("%s: too much text: %.100s", myname, addr);
	return (0);
    }
    strncpy(hostaddr.buf, addr + 1, address_bytes);
    hostaddr.buf[address_bytes] = 0;
    return (valid_mailhost_addr(hostaddr.buf, gripe) != 0);
}

#ifdef TEST

 /*
  * Test program - reads hostnames from stdin, reports invalid hostnames to
  * stderr.
  */
#include <stdlib.h>

#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <msg_vstream.h>

int     main(int unused_argc, char **argv)
{
    VSTRING *buffer = vstring_alloc(1);

    msg_vstream_init(argv[0], VSTREAM_ERR);
    msg_verbose = 1;

    while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
	msg_info("testing: \"%s\"", vstring_str(buffer));
	if (vstring_str(buffer)[0] == '[')
	    valid_mailhost_literal(vstring_str(buffer), DO_GRIPE);
	else
	    valid_mailhost_addr(vstring_str(buffer), DO_GRIPE);
    }
    exit(0);
}

#endif