xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtpd/smtpd_peer.c (revision 2d48ac808c43ea6701ba8f33cfc3645685301f79)
1 /*	$NetBSD: smtpd_peer.c,v 1.1.1.1 2009/06/23 10:08:56 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	smtpd_peer 3
6 /* SUMMARY
7 /*	look up peer name/address information
8 /* SYNOPSIS
9 /*	#include "smtpd.h"
10 /*
11 /*	void	smtpd_peer_init(state)
12 /*	SMTPD_STATE *state;
13 /*
14 /*	void	smtpd_peer_reset(state)
15 /*	SMTPD_STATE *state;
16 /* DESCRIPTION
17 /*	The smtpd_peer_init() routine attempts to produce a printable
18 /*	version of the peer name and address of the specified socket.
19 /*	Where information is unavailable, the name and/or address
20 /*	are set to "unknown".
21 /*
22 /*	This module uses the local name service via getaddrinfo()
23 /*	and getnameinfo(). It does not query the DNS directly.
24 /*
25 /*	smtpd_peer_init() updates the following fields:
26 /* .IP name
27 /*	The verified client hostname. This name is represented by
28 /*	the string "unknown" when 1) the address->name lookup failed,
29 /*	2) the name->address mapping fails, or 3) the name->address
30 /*	mapping does not produce the client IP address.
31 /* .IP reverse_name
32 /*	The unverified client hostname as found with address->name
33 /*	lookup; it is not verified for consistency with the client
34 /*	IP address result from name->address lookup.
35 /* .IP forward_name
36 /*	The unverified client hostname as found with address->name
37 /*	lookup followed by name->address lookup; it is not verified
38 /*	for consistency with the result from address->name lookup.
39 /*	For example, when the address->name lookup produces as
40 /*	hostname an alias, the name->address lookup will produce
41 /*	as hostname the expansion of that alias, so that the two
42 /*	lookups produce different names.
43 /* .IP addr
44 /*	Printable representation of the client address.
45 /* .IP namaddr
46 /*	String of the form: "name[addr]:port".
47 /* .IP rfc_addr
48 /*      String of the form "ipv4addr" or "ipv6:ipv6addr" for use
49 /*	in Received: message headers.
50 /* .IP name_status
51 /*	The name_status result field specifies how the name
52 /*	information should be interpreted:
53 /* .RS
54 /* .IP 2
55 /*	The address->name lookup and name->address lookup produced
56 /*	the client IP address.
57 /* .IP 4
58 /*	The address->name lookup or name->address lookup failed
59 /*	with a recoverable error.
60 /* .IP 5
61 /*	The address->name lookup or name->address lookup failed
62 /*	with an unrecoverable error, or the result did not match
63 /*	the client IP address.
64 /* .RE
65 /* .IP reverse_name_status
66 /*	The reverse_name_status result field specifies how the
67 /*	reverse_name information should be interpreted:
68 /* .RS .IP 2
69 /*	The address->name lookup succeeded.
70 /* .IP 4
71 /*	The address->name lookup failed with a recoverable error.
72 /* .IP 5
73 /*	The address->name lookup failed with an unrecoverable error.
74 /* .RE .IP forward_name_status
75 /*	The forward_name_status result field specifies how the
76 /*	forward_name information should be interpreted:
77 /* .RS .IP 2
78 /*	The address->name and name->address lookup succeeded.
79 /* .IP 4
80 /*	The address->name lookup or name->address failed with a
81 /*	recoverable error.
82 /* .IP 5
83 /*	The address->name lookup or name->address failed with an
84 /*	unrecoverable error.
85 /* .RE
86 /* .PP
87 /*	smtpd_peer_reset() releases memory allocated by smtpd_peer_init().
88 /* LICENSE
89 /* .ad
90 /* .fi
91 /*	The Secure Mailer license must be distributed with this software.
92 /* AUTHOR(S)
93 /*	Wietse Venema
94 /*	IBM T.J. Watson Research
95 /*	P.O. Box 704
96 /*	Yorktown Heights, NY 10598, USA
97 /*--*/
98 
99 /* System library. */
100 
101 #include <sys_defs.h>
102 #include <sys/socket.h>
103 #include <netinet/in.h>
104 #include <arpa/inet.h>
105 #include <stdio.h>			/* strerror() */
106 #include <errno.h>
107 #include <netdb.h>
108 #include <string.h>
109 
110 /* Utility library. */
111 
112 #include <msg.h>
113 #include <mymalloc.h>
114 #include <stringops.h>
115 #include <myaddrinfo.h>
116 #include <sock_addr.h>
117 #include <inet_proto.h>
118 
119 /* Global library. */
120 
121 #include <mail_proto.h>
122 #include <valid_mailhost_addr.h>
123 #include <mail_params.h>
124 
125 /* Application-specific. */
126 
127 #include "smtpd.h"
128 
129 /* smtpd_peer_init - initialize peer information */
130 
131 void    smtpd_peer_init(SMTPD_STATE *state)
132 {
133     const char *myname = "smtpd_peer_init";
134     SOCKADDR_SIZE sa_length;
135     struct sockaddr *sa;
136     INET_PROTO_INFO *proto_info = inet_proto_info();
137 
138     sa = (struct sockaddr *) & (state->sockaddr);
139     sa_length = sizeof(state->sockaddr);
140 
141     /*
142      * Look up the peer address information.
143      *
144      * XXX If we make local endpoint (getsockname) information available to
145      * Milter applications as {if_name} and {if_addr}, then we also must be
146      * able to provide this via the XCLIENT command for Milter testing.
147      *
148      * XXX If we make local or remote port information available to policy
149      * servers or Milter applications, then we must also make this testable
150      * with the XCLIENT command, otherwise there will be confusion.
151      *
152      * XXX If we make local or remote port information available via logging,
153      * then we must also support these attributes with the XFORWARD command.
154      *
155      * XXX If support were to be added for Milter applications in down-stream
156      * MTAs, then consistency demands that we propagate a lot of Sendmail
157      * macro information via the XFORWARD command. Otherwise we could end up
158      * with a very confusing situation.
159      */
160     if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
161 	errno = 0;
162     }
163 
164     /*
165      * If peer went away, give up.
166      */
167     if (errno != 0 && errno != ENOTSOCK) {
168 	state->name = mystrdup(CLIENT_NAME_UNKNOWN);
169 	state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
170 	state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
171 	state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
172 	state->addr_family = AF_UNSPEC;
173 	state->name_status = SMTPD_PEER_CODE_PERM;
174 	state->reverse_name_status = SMTPD_PEER_CODE_PERM;
175 	state->port = mystrdup(CLIENT_PORT_UNKNOWN);
176     }
177 
178     /*
179      * Convert the client address to printable address and hostname.
180      *
181      * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
182      * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
183      * else clause, pretend the origin is localhost[127.0.0.1], and become an
184      * open relay).
185      */
186     else if (errno == 0
187 	     && (sa->sa_family == AF_INET
188 #ifdef AF_INET6
189 		 || sa->sa_family == AF_INET6
190 #endif
191 		 )) {
192 	MAI_HOSTNAME_STR client_name;
193 	MAI_HOSTADDR_STR client_addr;
194 	MAI_SERVPORT_STR client_port;
195 	int     aierr;
196 	char   *colonp;
197 
198 	/*
199 	 * Sanity check: we can't use sockets that we're not configured for.
200 	 */
201 	if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
202 	    msg_fatal("cannot handle socket type %s with \"%s = %s\"",
203 #ifdef AF_INET6
204 		      sa->sa_family == AF_INET6 ? "AF_INET6" :
205 #endif
206 		      sa->sa_family == AF_INET ? "AF_INET" :
207 		      "other", VAR_INET_PROTOCOLS, var_inet_protocols);
208 
209 	/*
210 	 * Sorry, but there are some things that we just cannot do while
211 	 * connected to the network.
212 	 */
213 	if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
214 	    msg_error("incorrect SMTP server privileges: uid=%lu euid=%lu",
215 		      (unsigned long) getuid(), (unsigned long) geteuid());
216 	    msg_fatal("the Postfix SMTP server must run with $%s privileges",
217 		      VAR_MAIL_OWNER);
218 	}
219 
220 	/*
221 	 * Convert the client address to printable form.
222 	 */
223 	if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
224 					  &client_port, 0)) != 0)
225 	    msg_fatal("%s: cannot convert client address/port to string: %s",
226 		      myname, MAI_STRERROR(aierr));
227 	state->port = mystrdup(client_port.buf);
228 
229 	/*
230 	 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
231 	 * but only if IPv4 support is enabled (why would anyone want to turn
232 	 * it off)? With IPv4 support enabled we have no need for the IPv6
233 	 * form in logging, hostname verification and access checks.
234 	 */
235 #ifdef HAS_IPV6
236 	if (sa->sa_family == AF_INET6) {
237 	    if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
238 		&& IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
239 		&& (colonp = strrchr(client_addr.buf, ':')) != 0) {
240 		struct addrinfo *res0;
241 
242 		if (msg_verbose > 1)
243 		    msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
244 			     myname, client_addr.buf, colonp + 1);
245 
246 		state->addr = mystrdup(colonp + 1);
247 		state->rfc_addr = mystrdup(colonp + 1);
248 		state->addr_family = AF_INET;
249 		aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
250 		if (aierr)
251 		    msg_fatal("%s: cannot convert %s from string to binary: %s",
252 			      myname, state->addr, MAI_STRERROR(aierr));
253 		sa_length = res0->ai_addrlen;
254 		if (sa_length > sizeof(state->sockaddr))
255 		    sa_length = sizeof(state->sockaddr);
256 		memcpy((char *) sa, res0->ai_addr, sa_length);
257 		freeaddrinfo(res0);		/* 200412 */
258 	    }
259 
260 	    /*
261 	     * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
262 	     * a prefix of 'IPv6:'. We do this consistently for all IPv6
263 	     * addresses that that appear in headers or envelopes. The fact
264 	     * that valid_mailhost_addr() enforces the form helps of course.
265 	     * We use the form without IPV6: prefix when doing access
266 	     * control, or when accessing the connection cache.
267 	     */
268 	    else {
269 		state->addr = mystrdup(client_addr.buf);
270 		state->rfc_addr =
271 		    concatenate(IPV6_COL, client_addr.buf, (char *) 0);
272 		state->addr_family = sa->sa_family;
273 	    }
274 	}
275 
276 	/*
277 	 * An IPv4 address is in dotted quad decimal form.
278 	 */
279 	else
280 #endif
281 	{
282 	    state->addr = mystrdup(client_addr.buf);
283 	    state->rfc_addr = mystrdup(client_addr.buf);
284 	    state->addr_family = sa->sa_family;
285 	}
286 
287 	/*
288 	 * Look up and sanity check the client hostname.
289 	 *
290 	 * It is unsafe to allow numeric hostnames, especially because there
291 	 * exists pressure to turn off the name->addr double check. In that
292 	 * case an attacker could trivally bypass access restrictions.
293 	 *
294 	 * sockaddr_to_hostname() already rejects malformed or numeric names.
295 	 */
296 #define TEMP_AI_ERROR(e) \
297 	((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
298 
299 #define REJECT_PEER_NAME(state, code) { \
300 	myfree(state->name); \
301 	state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
302 	state->name_status = code; \
303     }
304 
305 	if (var_smtpd_peername_lookup == 0) {
306 	    state->name = mystrdup(CLIENT_NAME_UNKNOWN);
307 	    state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
308 	    state->name_status = SMTPD_PEER_CODE_PERM;
309 	    state->reverse_name_status = SMTPD_PEER_CODE_PERM;
310 	} else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
311 					 (MAI_SERVNAME_STR *) 0, 0)) != 0) {
312 	    state->name = mystrdup(CLIENT_NAME_UNKNOWN);
313 	    state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
314 	    state->name_status = (TEMP_AI_ERROR(aierr) ?
315 			       SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
316 	    state->reverse_name_status = (TEMP_AI_ERROR(aierr) ?
317 			       SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
318 	} else {
319 	    struct addrinfo *res0;
320 	    struct addrinfo *res;
321 
322 	    state->name = mystrdup(client_name.buf);
323 	    state->reverse_name = mystrdup(client_name.buf);
324 	    state->name_status = SMTPD_PEER_CODE_OK;
325 	    state->reverse_name_status = SMTPD_PEER_CODE_OK;
326 
327 	    /*
328 	     * Reject the hostname if it does not list the peer address.
329 	     * Without further validation or qualification, such information
330 	     * must not be allowed to enter the audit trail, as people would
331 	     * draw false conclusions.
332 	     */
333 	    aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0);
334 	    if (aierr) {
335 		msg_warn("%s: hostname %s verification failed: %s",
336 			 state->addr, state->name, MAI_STRERROR(aierr));
337 		REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
338 			    SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED));
339 	    } else {
340 		for (res = res0; /* void */ ; res = res->ai_next) {
341 		    if (res == 0) {
342 			msg_warn("%s: address not listed for hostname %s",
343 				 state->addr, state->name);
344 			REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED);
345 			break;
346 		    }
347 		    if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
348 			msg_info("skipping address family %d for host %s",
349 				 res->ai_family, state->name);
350 			continue;
351 		    }
352 		    if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
353 			break;			/* keep peer name */
354 		}
355 		freeaddrinfo(res0);
356 	    }
357 	}
358     }
359 
360     /*
361      * If it's not Internet, assume the client is local, and avoid using the
362      * naming service because that can hang when the machine is disconnected.
363      */
364     else {
365 	state->name = mystrdup("localhost");
366 	state->reverse_name = mystrdup("localhost");
367 	state->addr = mystrdup("127.0.0.1");	/* XXX bogus. */
368 	state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
369 	state->addr_family = AF_UNSPEC;
370 	state->name_status = SMTPD_PEER_CODE_OK;
371 	state->reverse_name_status = SMTPD_PEER_CODE_OK;
372 	state->port = mystrdup("0");		/* XXX bogus. */
373     }
374 
375     /*
376      * Do the name[addr]:port formatting for pretty reports.
377      */
378     state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
379 					     state->port);
380 }
381 
382 /* smtpd_peer_reset - destroy peer information */
383 
384 void    smtpd_peer_reset(SMTPD_STATE *state)
385 {
386     myfree(state->name);
387     myfree(state->reverse_name);
388     myfree(state->addr);
389     myfree(state->namaddr);
390     myfree(state->rfc_addr);
391     myfree(state->port);
392 }
393