1/*++
2/* NAME
3/*	qmqpd_peer 3
4/* SUMMARY
5/*	look up peer name/address information
6/* SYNOPSIS
7/*	#include "qmqpd.h"
8/*
9/*	void	qmqpd_peer_init(state)
10/*	QMQPD_STATE *state;
11/*
12/*	void	qmqpd_peer_reset(state)
13/*	QMQPD_STATE *state;
14/* DESCRIPTION
15/*	The qmqpd_peer_init() routine attempts to produce a printable
16/*	version of the peer name and address of the specified socket.
17/*	Where information is unavailable, the name and/or address
18/*	are set to "unknown".
19/*
20/*	qmqpd_peer_init() updates the following fields:
21/* .IP name
22/*	The client hostname. An unknown name is represented by the
23/*	string "unknown".
24/* .IP addr
25/*	Printable representation of the client address.
26/* .IP namaddr
27/*	String of the form: "name[addr]:port".
28/* .PP
29/*	qmqpd_peer_reset() releases memory allocated by qmqpd_peer_init().
30/* LICENSE
31/* .ad
32/* .fi
33/*	The Secure Mailer license must be distributed with this software.
34/* AUTHOR(S)
35/*	Wietse Venema
36/*	IBM T.J. Watson Research
37/*	P.O. Box 704
38/*	Yorktown Heights, NY 10598, USA
39/*--*/
40
41/* System library. */
42
43#include <sys_defs.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <stdio.h>			/* strerror() */
48#include <errno.h>
49#include <netdb.h>
50#include <string.h>
51
52/* Utility library. */
53
54#include <msg.h>
55#include <mymalloc.h>
56#include <stringops.h>
57#include <myaddrinfo.h>
58#include <sock_addr.h>
59#include <inet_proto.h>
60#include <split_at.h>
61
62/* Global library. */
63
64#include <mail_proto.h>
65#include <valid_mailhost_addr.h>
66#include <mail_params.h>
67
68/* Application-specific. */
69
70#include "qmqpd.h"
71
72/* qmqpd_peer_init - initialize peer information */
73
74void    qmqpd_peer_init(QMQPD_STATE *state)
75{
76    const char *myname = "qmqpd_peer_init";
77    struct sockaddr_storage ss;
78    struct sockaddr *sa;
79    SOCKADDR_SIZE sa_length;
80    INET_PROTO_INFO *proto_info = inet_proto_info();
81
82    sa = (struct sockaddr *) & ss;
83    sa_length = sizeof(ss);
84
85    /*
86     * Look up the peer address information.
87     */
88    if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
89	errno = 0;
90    }
91
92    /*
93     * If peer went away, give up.
94     */
95    if (errno != 0 && errno != ENOTSOCK) {
96	state->name = mystrdup(CLIENT_NAME_UNKNOWN);
97	state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
98	state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
99	state->addr_family = AF_UNSPEC;
100	state->port = mystrdup(CLIENT_PORT_UNKNOWN);
101    }
102
103    /*
104     * Convert the client address to printable address and hostname.
105     *
106     * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
107     * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
108     * else clause, pretend the origin is localhost[127.0.0.1], and become an
109     * open relay).
110     */
111    else if (errno == 0
112	     && (sa->sa_family == AF_INET
113#ifdef AF_INET6
114		 || sa->sa_family == AF_INET6
115#endif
116		 )) {
117	MAI_HOSTNAME_STR client_name;
118	MAI_HOSTADDR_STR client_addr;
119	MAI_SERVPORT_STR client_port;
120	int     aierr;
121	char   *colonp;
122
123	/*
124	 * Sanity check: we can't use sockets that we're not configured for.
125	 */
126	if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
127	    msg_fatal("cannot handle socket type %s with \"%s = %s\"",
128#ifdef AF_INET6
129		      sa->sa_family == AF_INET6 ? "AF_INET6" :
130#endif
131		      sa->sa_family == AF_INET ? "AF_INET" :
132		      "other", VAR_INET_PROTOCOLS, var_inet_protocols);
133
134	/*
135	 * Sorry, but there are some things that we just cannot do while
136	 * connected to the network.
137	 */
138	if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
139	    msg_error("incorrect QMQP server privileges: uid=%lu euid=%lu",
140		      (unsigned long) getuid(), (unsigned long) geteuid());
141	    msg_fatal("the Postfix QMQP server must run with $%s privileges",
142		      VAR_MAIL_OWNER);
143	}
144
145	/*
146	 * Convert the client address to printable form.
147	 */
148	if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
149					  &client_port, 0)) != 0)
150	    msg_fatal("%s: cannot convert client address/port to string: %s",
151		      myname, MAI_STRERROR(aierr));
152	state->port = mystrdup(client_port.buf);
153
154	/*
155	 * XXX Require that the infrastructure strips off the IPv6 datalink
156	 * suffix to avoid false alarms with strict address syntax checks.
157	 */
158#ifdef HAS_IPV6
159	if (strchr(client_addr.buf, '%') != 0)
160	    msg_panic("%s: address %s has datalink suffix",
161		      myname, client_addr.buf);
162#endif
163
164	/*
165	 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
166	 * but only if IPv4 support is enabled (why would anyone want to turn
167	 * it off)? With IPv4 support enabled we have no need for the IPv6
168	 * form in logging, hostname verification and access checks.
169	 */
170#ifdef HAS_IPV6
171	if (sa->sa_family == AF_INET6) {
172	    if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
173		&& IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
174		&& (colonp = strrchr(client_addr.buf, ':')) != 0) {
175		struct addrinfo *res0;
176
177		if (msg_verbose > 1)
178		    msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
179			     myname, client_addr.buf, colonp + 1);
180
181		state->addr = mystrdup(colonp + 1);
182		state->rfc_addr = mystrdup(colonp + 1);
183		state->addr_family = AF_INET;
184		aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
185		if (aierr)
186		    msg_fatal("%s: cannot convert %s from string to binary: %s",
187			      myname, state->addr, MAI_STRERROR(aierr));
188		sa_length = res0->ai_addrlen;
189		if (sa_length > sizeof(ss))
190		    sa_length = sizeof(ss);
191		memcpy((char *) sa, res0->ai_addr, sa_length);
192		freeaddrinfo(res0);
193	    }
194
195	    /*
196	     * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
197	     * a prefix of 'IPv6:'. We do this consistently for all IPv6
198	     * addresses that that appear in headers or envelopes. The fact
199	     * that valid_mailhost_addr() enforces the form helps of course.
200	     * We use the form without IPV6: prefix when doing access
201	     * control, or when accessing the connection cache.
202	     */
203	    else {
204		state->addr = mystrdup(client_addr.buf);
205		state->rfc_addr =
206		    concatenate(IPV6_COL, client_addr.buf, (char *) 0);
207		state->addr_family = sa->sa_family;
208	    }
209	}
210
211	/*
212	 * An IPv4 address is in dotted quad decimal form.
213	 */
214	else
215#endif
216	{
217	    state->addr = mystrdup(client_addr.buf);
218	    state->rfc_addr = mystrdup(client_addr.buf);
219	    state->addr_family = sa->sa_family;
220	}
221
222	/*
223	 * Look up and sanity check the client hostname.
224	 *
225	 * It is unsafe to allow numeric hostnames, especially because there
226	 * exists pressure to turn off the name->addr double check. In that
227	 * case an attacker could trivally bypass access restrictions.
228	 *
229	 * sockaddr_to_hostname() already rejects malformed or numeric names.
230	 */
231#define REJECT_PEER_NAME(state) { \
232	myfree(state->name); \
233	state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
234    }
235
236	if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
237					  (MAI_SERVNAME_STR *) 0, 0)) != 0) {
238	    state->name = mystrdup(CLIENT_NAME_UNKNOWN);
239	} else {
240	    struct addrinfo *res0;
241	    struct addrinfo *res;
242
243	    state->name = mystrdup(client_name.buf);
244
245	    /*
246	     * Reject the hostname if it does not list the peer address.
247	     */
248	    aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
249					    (char *) 0, 0, &res0);
250	    if (aierr) {
251		msg_warn("hostname %s does not resolve to address %s: %s",
252			 state->name, state->addr, MAI_STRERROR(aierr));
253		REJECT_PEER_NAME(state);
254	    } else {
255		for (res = res0; /* void */ ; res = res->ai_next) {
256		    if (res == 0) {
257			msg_warn("hostname %s does not resolve to address %s",
258				 state->addr, state->name);
259			REJECT_PEER_NAME(state);
260			break;
261		    }
262		    if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
263			msg_info("skipping address family %d for host %s",
264				 res->ai_family, state->name);
265			continue;
266		    }
267		    if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
268			break;			/* keep peer name */
269		}
270		freeaddrinfo(res0);
271	    }
272	}
273    }
274
275    /*
276     * If it's not Internet, assume the client is local, and avoid using the
277     * naming service because that can hang when the machine is disconnected.
278     */
279    else {
280	state->name = mystrdup("localhost");
281	state->addr = mystrdup("127.0.0.1");	/* XXX bogus. */
282	state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
283	state->addr_family = AF_UNSPEC;
284	state->port = mystrdup("0");		/* XXX bogus. */
285    }
286
287    /*
288     * Do the name[addr]:port formatting for pretty reports.
289     */
290    state->namaddr =
291	concatenate(state->name, "[", state->addr, "]",
292		    var_qmqpd_client_port_log ? ":" : (char *) 0,
293		    state->port, (char *) 0);
294}
295
296/* qmqpd_peer_reset - destroy peer information */
297
298void    qmqpd_peer_reset(QMQPD_STATE *state)
299{
300    myfree(state->name);
301    myfree(state->addr);
302    myfree(state->namaddr);
303    myfree(state->rfc_addr);
304    myfree(state->port);
305}
306