summaryrefslogtreecommitdiffstats
path: root/src/postscreen/postscreen_endpt.c
blob: 57655ac6a4d8dbcbb924b1543e2a6fab234c8989 (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*++
/* NAME
/*	postscreen_endpt 3
/* SUMMARY
/*	look up connection endpoint information
/* SYNOPSIS
/*	#include <postscreen.h>
/*
/*	void	psc_endpt_lookup(smtp_client_stream, lookup_done)
/*	VSTREAM	*smtp_client_stream;
/*	void	(*lookup_done)(status, smtp_client_stream,
/*				smtp_client_addr, smtp_client_port,
/*				smtp_server_addr, smtp_server_port)
/*	int	status;
/*	MAI_HOSTADDR_STR *smtp_client_addr;
/*	MAI_SERVPORT_STR *smtp_client_port;
/*	MAI_HOSTADDR_STR *smtp_server_addr;
/*	MAI_SERVPORT_STR *smtp_server_port;
/* DESCRIPTION
/*	psc_endpt_lookup() looks up remote and local connection
/*	endpoint information, either through local system calls,
/*	or through an adapter for an up-stream proxy protocol.
/*
/*	The following summarizes what the postscreen(8) server
/*	expects from a proxy protocol adapter routine.
/* .IP \(bu
/*	Accept the same arguments as psc_endpt_lookup().
/* .IP \(bu
/*	Validate protocol, address and port syntax. Permit only
/*	protocols that are configured with the main.cf:inet_protocols
/*	setting.
/* .IP \(bu
/*	Convert IPv4-in-IPv6 address syntax to IPv4 syntax when
/*	both IPv6 and IPv4 support are enabled with main.cf:inet_protocols.
/* .IP \(bu
/*	Log a clear warning message that explains why a request
/*	fails.
/* .IP \(bu
/*	Never talk to the remote SMTP client.
/* .PP
/*	Arguments:
/* .IP client_stream
/*	A brand-new stream that is connected to the remote client.
/* .IP lookup
/*	Call-back routine that reports the result status, address
/*	and port information. The result status is -1 in case of
/*	error, 0 in case of success.
/* 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>
#include <vstream.h>
#include <inet_proto.h>

/* Global library. */

#include <mail_params.h>
#include <haproxy_srvr.h>

/* Application-specific. */

#include <postscreen.h>
#include <postscreen_haproxy.h>

static INET_PROTO_INFO *proto_info;

/* psc_sockaddr_to_hostaddr - transform endpoint address and port to string */

static int psc_sockaddr_to_hostaddr(struct sockaddr *addr_storage,
				            SOCKADDR_SIZE addr_storage_len,
				            MAI_HOSTADDR_STR *addr_buf,
				            MAI_SERVPORT_STR *port_buf,
				            int socktype)
{
    int     aierr;

    if ((aierr = sockaddr_to_hostaddr(addr_storage, addr_storage_len,
				      addr_buf, port_buf, socktype)) == 0
	&& strncasecmp("::ffff:", addr_buf->buf, 7) == 0
	&& strchr((char *) proto_info->sa_family_list, AF_INET) != 0)
	memmove(addr_buf->buf, addr_buf->buf + 7,
		sizeof(addr_buf->buf) - 7);
    return (aierr);
}

/* psc_endpt_local_lookup - look up local system connection information */

static void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
				           PSC_ENDPT_LOOKUP_FN lookup_done)
{
    struct sockaddr_storage addr_storage;
    SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
    int     status;
    MAI_HOSTADDR_STR smtp_client_addr;
    MAI_SERVPORT_STR smtp_client_port;
    MAI_HOSTADDR_STR smtp_server_addr;
    MAI_SERVPORT_STR smtp_server_port;
    int     aierr;

    /*
     * Look up the remote SMTP client address and port.
     */
    if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
		    &addr_storage, &addr_storage_len) < 0) {
	msg_warn("getpeername: %m -- dropping this connection");
	status = -1;
    }

    /*
     * Convert the remote SMTP client address and port to printable form for
     * logging and access control.
     */
    else if ((aierr = psc_sockaddr_to_hostaddr(
					  (struct sockaddr *) &addr_storage,
					addr_storage_len, &smtp_client_addr,
				    &smtp_client_port, SOCK_STREAM)) != 0) {
	msg_warn("cannot convert client address/port to string: %s"
		 " -- dropping this connection",
		 MAI_STRERROR(aierr));
	status = -1;
    }

    /*
     * Look up the local SMTP server address and port.
     */
    else if (getsockname(vstream_fileno(smtp_client_stream),
			 (struct sockaddr *) &addr_storage,
			 &addr_storage_len) < 0) {
	msg_warn("getsockname: %m -- dropping this connection");
	status = -1;
    }

    /*
     * Convert the local SMTP server address and port to printable form for
     * logging.
     */
    else if ((aierr = psc_sockaddr_to_hostaddr(
					  (struct sockaddr *) &addr_storage,
					addr_storage_len, &smtp_server_addr,
				    &smtp_server_port, SOCK_STREAM)) != 0) {
	msg_warn("cannot convert server address/port to string: %s"
		 " -- dropping this connection",
		 MAI_STRERROR(aierr));
	status = -1;
    } else {
	status = 0;
    }
    lookup_done(status, smtp_client_stream,
		&smtp_client_addr, &smtp_client_port,
		&smtp_server_addr, &smtp_server_port);
}

 /*
  * Lookup table for available proxy protocols.
  */
typedef struct {
    const char *name;
    void    (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN);
} PSC_ENDPT_LOOKUP_INFO;

static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = {
    NOPROXY_PROTO_NAME, psc_endpt_local_lookup,
    HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup,
    0,
};

/* psc_endpt_lookup - look up connection endpoint information */

void    psc_endpt_lookup(VSTREAM *smtp_client_stream,
			         PSC_ENDPT_LOOKUP_FN notify)
{
    const PSC_ENDPT_LOOKUP_INFO *pp;

    if (proto_info == 0)
	proto_info = inet_proto_info();

    for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) {
	if (pp->name == 0)
	    msg_fatal("unsupported %s value: %s",
		      VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto);
	if (strcmp(var_psc_uproxy_proto, pp->name) == 0) {
	    pp->endpt_lookup(smtp_client_stream, notify);
	    return;
	}
    }
}