xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtpd/smtpd_peer.c (revision c48c605c14fd8622b523d1d6a3f0c0bad133ea89)
1 /*	$NetBSD: smtpd_peer.c,v 1.5 2023/12/23 20:30:45 christos 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 /* AUXILIARY METHODS
17 /*	void	smtpd_peer_from_default(state)
18 /*	SMTPD_STATE *state;
19 /* DESCRIPTION
20 /*	The smtpd_peer_init() routine attempts to produce a printable
21 /*	version of the peer name and address of the specified socket.
22 /*	Where information is unavailable, the name and/or address
23 /*	are set to "unknown".
24 /*
25 /*	Alternatively, the peer address and port may be obtained
26 /*	from a proxy server.
27 /*
28 /*	This module uses the local name service via getaddrinfo()
29 /*	and getnameinfo(). It does not query the DNS directly.
30 /*
31 /*	smtpd_peer_init() updates the following fields:
32 /* .IP name
33 /*	The verified client hostname. This name is represented by
34 /*	the string "unknown" when 1) the address->name lookup failed,
35 /*	2) the name->address mapping fails, or 3) the name->address
36 /*	mapping does not produce the client IP address.
37 /* .IP reverse_name
38 /*	The unverified client hostname as found with address->name
39 /*	lookup; it is not verified for consistency with the client
40 /*	IP address result from name->address lookup.
41 /* .IP forward_name
42 /*	The unverified client hostname as found with address->name
43 /*	lookup followed by name->address lookup; it is not verified
44 /*	for consistency with the result from address->name lookup.
45 /*	For example, when the address->name lookup produces as
46 /*	hostname an alias, the name->address lookup will produce
47 /*	as hostname the expansion of that alias, so that the two
48 /*	lookups produce different names.
49 /* .IP addr
50 /*	Printable representation of the client address.
51 /* .IP namaddr
52 /*	String of the form: "name[addr]:port".
53 /* .IP rfc_addr
54 /*	String of the form "ipv4addr" or "ipv6:ipv6addr" for use
55 /*	in Received: message headers.
56 /* .IP dest_addr
57 /*	Server address, used by the Dovecot authentication server,
58 /*	available as Milter {daemon_addr} macro, and as server_address
59 /*	policy delegation attribute.
60 /* .IP dest_port
61 /*	Server port, available as Milter {daemon_port} macro, and
62 /*	as server_port policy delegation attribute.
63 /* .IP name_status
64 /*	The name_status result field specifies how the name
65 /*	information should be interpreted:
66 /* .RS
67 /* .IP 2
68 /*	The address->name lookup and name->address lookup produced
69 /*	the client IP address.
70 /* .IP 4
71 /*	The address->name lookup or name->address lookup failed
72 /*	with a recoverable error.
73 /* .IP 5
74 /*	The address->name lookup or name->address lookup failed
75 /*	with an unrecoverable error, or the result did not match
76 /*	the client IP address.
77 /* .RE
78 /* .IP reverse_name_status
79 /*	The reverse_name_status result field specifies how the
80 /*	reverse_name information should be interpreted:
81 /* .RS
82 /* .IP 2
83 /*	The address->name lookup succeeded.
84 /* .IP 4
85 /*	The address->name lookup failed with a recoverable error.
86 /* .IP 5
87 /*	The address->name lookup failed with an unrecoverable error.
88 /* .RE
89 /* .IP forward_name_status
90 /*	The forward_name_status result field specifies how the
91 /*	forward_name information should be interpreted:
92 /* .RS
93 /* .IP 2
94 /*	The address->name and name->address lookup succeeded.
95 /* .IP 4
96 /*	The address->name lookup or name->address failed with a
97 /*	recoverable error.
98 /* .IP 5
99 /*	The address->name lookup or name->address failed with an
100 /*	unrecoverable error.
101 /* .RE
102 /* .PP
103 /*	smtpd_peer_reset() releases memory allocated by smtpd_peer_init().
104 /*
105 /*	smtpd_peer_from_default() looks up connection information
106 /*	when an up-stream proxy indicates that a connection is not
107 /*	proxied.
108 /* LICENSE
109 /* .ad
110 /* .fi
111 /*	The Secure Mailer license must be distributed with this software.
112 /* AUTHOR(S)
113 /*	Wietse Venema
114 /*	IBM T.J. Watson Research
115 /*	P.O. Box 704
116 /*	Yorktown Heights, NY 10598, USA
117 /*
118 /*	Wietse Venema
119 /*	Google, Inc.
120 /*	111 8th Avenue
121 /*	New York, NY 10011, USA
122 /*--*/
123 
124 /* System library. */
125 
126 #include <sys_defs.h>
127 #include <sys/socket.h>
128 #include <netinet/in.h>
129 #include <arpa/inet.h>
130 #include <errno.h>
131 #include <netdb.h>
132 #include <string.h>
133 #include <htable.h>
134 
135 /* Utility library. */
136 
137 #include <msg.h>
138 #include <mymalloc.h>
139 #include <stringops.h>
140 #include <myaddrinfo.h>
141 #include <sock_addr.h>
142 #include <inet_proto.h>
143 #include <split_at.h>
144 #include <inet_prefix_top.h>
145 
146 /* Global library. */
147 
148 #include <mail_proto.h>
149 #include <valid_mailhost_addr.h>
150 #include <mail_params.h>
151 #include <haproxy_srvr.h>
152 
153 /* Application-specific. */
154 
155 #include "smtpd.h"
156 
157 static const INET_PROTO_INFO *proto_info;
158 
159  /*
160   * XXX If we make local port information available via logging, then we must
161   * also support these attributes with the XFORWARD command.
162   *
163   * XXX If support were to be added for Milter applications in down-stream MTAs,
164   * then consistency demands that we propagate a lot of Sendmail macro
165   * information via the XFORWARD command. Otherwise we could end up with a
166   * very confusing situation.
167   */
168 
169 /* smtpd_peer_sockaddr_to_hostaddr - client address/port to printable form */
170 
smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE * state)171 static int smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE *state)
172 {
173     const char *myname = "smtpd_peer_sockaddr_to_hostaddr";
174     struct sockaddr *sa = (struct sockaddr *) &(state->sockaddr);
175     SOCKADDR_SIZE sa_length = state->sockaddr_len;
176 
177     /*
178      * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd,
179      * while Postfix IPv6 (or IPv4) support is turned off, don't (skip to the
180      * final else clause, pretend the origin is localhost[127.0.0.1], and
181      * become an open relay).
182      */
183     if (sa->sa_family == AF_INET
184 #ifdef AF_INET6
185 	|| sa->sa_family == AF_INET6
186 #endif
187 	) {
188 	MAI_HOSTADDR_STR client_addr;
189 	MAI_SERVPORT_STR client_port;
190 	MAI_HOSTADDR_STR server_addr;
191 	MAI_SERVPORT_STR server_port;
192 	int     aierr;
193 	char   *colonp;
194 
195 	/*
196 	 * Sanity check: we can't use sockets that we're not configured for.
197 	 */
198 	if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
199 	    msg_fatal("cannot handle socket type %s with \"%s = %s\"",
200 #ifdef AF_INET6
201 		      sa->sa_family == AF_INET6 ? "AF_INET6" :
202 #endif
203 		      sa->sa_family == AF_INET ? "AF_INET" :
204 		      "other", VAR_INET_PROTOCOLS, var_inet_protocols);
205 
206 	/*
207 	 * Sorry, but there are some things that we just cannot do while
208 	 * connected to the network.
209 	 */
210 	if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
211 	    msg_error("incorrect SMTP server privileges: uid=%lu euid=%lu",
212 		      (unsigned long) getuid(), (unsigned long) geteuid());
213 	    msg_fatal("the Postfix SMTP server must run with $%s privileges",
214 		      VAR_MAIL_OWNER);
215 	}
216 
217 	/*
218 	 * Convert the client address to printable form.
219 	 */
220 	if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
221 					  &client_port, 0)) != 0)
222 	    msg_fatal("%s: cannot convert client address/port to string: %s",
223 		      myname, MAI_STRERROR(aierr));
224 	state->port = mystrdup(client_port.buf);
225 
226 	/*
227 	 * XXX Require that the infrastructure strips off the IPv6 datalink
228 	 * suffix to avoid false alarms with strict address syntax checks.
229 	 */
230 #ifdef HAS_IPV6
231 	if (strchr(client_addr.buf, '%') != 0)
232 	    msg_panic("%s: address %s has datalink suffix",
233 		      myname, client_addr.buf);
234 #endif
235 
236 	/*
237 	 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
238 	 * but only if IPv4 support is enabled (why would anyone want to turn
239 	 * it off)? With IPv4 support enabled we have no need for the IPv6
240 	 * form in logging, hostname verification and access checks.
241 	 */
242 #ifdef HAS_IPV6
243 	if (sa->sa_family == AF_INET6) {
244 	    if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
245 		&& IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
246 		&& (colonp = strrchr(client_addr.buf, ':')) != 0) {
247 		struct addrinfo *res0;
248 
249 		if (msg_verbose > 1)
250 		    msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
251 			     myname, client_addr.buf, colonp + 1);
252 
253 		state->addr = mystrdup(colonp + 1);
254 		state->rfc_addr = mystrdup(colonp + 1);
255 		state->addr_family = AF_INET;
256 		aierr =
257 		    hostaddr_to_sockaddr(state->addr, state->port, 0, &res0);
258 		if (aierr)
259 		    msg_fatal("%s: cannot convert [%s]:%s to binary: %s",
260 			      myname, state->addr, state->port,
261 			      MAI_STRERROR(aierr));
262 		sa_length = res0->ai_addrlen;
263 		if (sa_length > sizeof(state->sockaddr))
264 		    sa_length = sizeof(state->sockaddr);
265 		memcpy((void *) sa, res0->ai_addr, sa_length);
266 		freeaddrinfo(res0);		/* 200412 */
267 	    }
268 
269 	    /*
270 	     * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
271 	     * a prefix of 'IPv6:'. We do this consistently for all IPv6
272 	     * addresses that appear in headers or envelopes. The fact that
273 	     * valid_mailhost_addr() enforces the form helps of course. We
274 	     * use the form without IPV6: prefix when doing access control,
275 	     * or when accessing the connection cache.
276 	     */
277 	    else {
278 		state->addr = mystrdup(client_addr.buf);
279 		state->rfc_addr =
280 		    concatenate(IPV6_COL, client_addr.buf, (char *) 0);
281 		state->addr_family = sa->sa_family;
282 	    }
283 	}
284 
285 	/*
286 	 * An IPv4 address is in dotted quad decimal form.
287 	 */
288 	else
289 #endif
290 	{
291 	    state->addr = mystrdup(client_addr.buf);
292 	    state->rfc_addr = mystrdup(client_addr.buf);
293 	    state->addr_family = sa->sa_family;
294 	}
295 
296 	/*
297 	 * Convert the server address/port to printable form.
298 	 */
299 	if ((aierr = sockaddr_to_hostaddr((struct sockaddr *)
300 					  &state->dest_sockaddr,
301 					  state->dest_sockaddr_len,
302 					  &server_addr,
303 					  &server_port, 0)) != 0)
304 	    msg_fatal("%s: cannot convert server address/port to string: %s",
305 		      myname, MAI_STRERROR(aierr));
306 	/* TODO: convert IPv4-in-IPv6 to IPv4 form. */
307 	state->dest_addr = mystrdup(server_addr.buf);
308 	state->dest_port = mystrdup(server_port.buf);
309 
310 	return (0);
311     }
312 
313     /*
314      * It's not Internet.
315      */
316     else {
317 	return (-1);
318     }
319 }
320 
321 /* smtpd_peer_sockaddr_to_hostname - client hostname lookup */
322 
smtpd_peer_sockaddr_to_hostname(SMTPD_STATE * state)323 static void smtpd_peer_sockaddr_to_hostname(SMTPD_STATE *state)
324 {
325     struct sockaddr *sa = (struct sockaddr *) &(state->sockaddr);
326     SOCKADDR_SIZE sa_length = state->sockaddr_len;
327     MAI_HOSTNAME_STR client_name;
328     int     aierr;
329 
330     /*
331      * Look up and sanity check the client hostname.
332      *
333      * It is unsafe to allow numeric hostnames, especially because there exists
334      * pressure to turn off the name->addr double check. In that case an
335      * attacker could trivally bypass access restrictions.
336      *
337      * sockaddr_to_hostname() already rejects malformed or numeric names.
338      */
339 #define TEMP_AI_ERROR(e) \
340 	((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
341 
342 #define REJECT_PEER_NAME(state, code) { \
343 	myfree(state->name); \
344 	state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
345 	state->name_status = code; \
346     }
347 
348     if (var_smtpd_peername_lookup == 0) {
349 	state->name = mystrdup(CLIENT_NAME_UNKNOWN);
350 	state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
351 	state->name_status = SMTPD_PEER_CODE_PERM;
352 	state->reverse_name_status = SMTPD_PEER_CODE_PERM;
353     } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
354 					 (MAI_SERVNAME_STR *) 0, 0)) != 0) {
355 	state->name = mystrdup(CLIENT_NAME_UNKNOWN);
356 	state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
357 	state->name_status = (TEMP_AI_ERROR(aierr) ?
358 			      SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
359 	state->reverse_name_status = (TEMP_AI_ERROR(aierr) ?
360 			       SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
361     } else {
362 	struct addrinfo *res0;
363 	struct addrinfo *res;
364 
365 	state->name = mystrdup(client_name.buf);
366 	state->reverse_name = mystrdup(client_name.buf);
367 	state->name_status = SMTPD_PEER_CODE_OK;
368 	state->reverse_name_status = SMTPD_PEER_CODE_OK;
369 
370 	/*
371 	 * Reject the hostname if it does not list the peer address. Without
372 	 * further validation or qualification, such information must not be
373 	 * allowed to enter the audit trail, as people would draw false
374 	 * conclusions.
375 	 */
376 	aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
377 					(char *) 0, 0, &res0);
378 	if (aierr) {
379 	    msg_warn("hostname %s does not resolve to address %s: %s",
380 		     state->name, state->addr, MAI_STRERROR(aierr));
381 	    REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
382 			    SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED));
383 	} else {
384 	    for (res = res0; /* void */ ; res = res->ai_next) {
385 		if (res == 0) {
386 		    msg_warn("hostname %s does not resolve to address %s",
387 			     state->name, state->addr);
388 		    REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED);
389 		    break;
390 		}
391 		if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
392 		    msg_info("skipping address family %d for host %s",
393 			     res->ai_family, state->name);
394 		    continue;
395 		}
396 		if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
397 		    break;			/* keep peer name */
398 	    }
399 	    freeaddrinfo(res0);
400 	}
401     }
402 }
403 
404 /* smtpd_peer_hostaddr_to_sockaddr - convert numeric string to binary */
405 
smtpd_peer_hostaddr_to_sockaddr(SMTPD_STATE * state)406 static void smtpd_peer_hostaddr_to_sockaddr(SMTPD_STATE *state)
407 {
408     const char *myname = "smtpd_peer_hostaddr_to_sockaddr";
409     struct addrinfo *res;
410     int     aierr;
411 
412     if ((aierr = hostaddr_to_sockaddr(state->addr, state->port,
413 				      SOCK_STREAM, &res)) != 0)
414 	msg_fatal("%s: cannot convert client address/port to string: %s",
415 		  myname, MAI_STRERROR(aierr));
416     if (res->ai_addrlen > sizeof(state->sockaddr))
417 	msg_panic("%s: address length > struct sockaddr_storage", myname);
418     memcpy((void *) &(state->sockaddr), res->ai_addr, res->ai_addrlen);
419     state->sockaddr_len = res->ai_addrlen;
420     freeaddrinfo(res);
421 }
422 
423 /* smtpd_peer_not_inet - non-socket or non-Internet endpoint */
424 
smtpd_peer_not_inet(SMTPD_STATE * state)425 static void smtpd_peer_not_inet(SMTPD_STATE *state)
426 {
427 
428     /*
429      * If it's not Internet, assume the client is local, and avoid using the
430      * naming service because that can hang when the machine is disconnected.
431      */
432     state->name = mystrdup("localhost");
433     state->reverse_name = mystrdup("localhost");
434 #ifdef AF_INET6
435     if (proto_info->sa_family_list[0] == PF_INET6) {
436 	state->addr = mystrdup("::1");		/* XXX bogus. */
437 	state->rfc_addr = mystrdup(IPV6_COL "::1");	/* XXX bogus. */
438     } else
439 #endif
440     {
441 	state->addr = mystrdup("127.0.0.1");	/* XXX bogus. */
442 	state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
443     }
444     state->addr_family = AF_UNSPEC;
445     state->name_status = SMTPD_PEER_CODE_OK;
446     state->reverse_name_status = SMTPD_PEER_CODE_OK;
447     state->port = mystrdup("0");		/* XXX bogus. */
448 
449     state->dest_addr = mystrdup(state->addr);	/* XXX bogus. */
450     state->dest_port = mystrdup(state->port);	/* XXX bogus. */
451 }
452 
453 /* smtpd_peer_no_client - peer went away, or peer info unavailable */
454 
smtpd_peer_no_client(SMTPD_STATE * state)455 static void smtpd_peer_no_client(SMTPD_STATE *state)
456 {
457     smtpd_peer_reset(state);
458     state->name = mystrdup(CLIENT_NAME_UNKNOWN);
459     state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
460     state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
461     state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
462     state->addr_family = AF_UNSPEC;
463     state->name_status = SMTPD_PEER_CODE_PERM;
464     state->reverse_name_status = SMTPD_PEER_CODE_PERM;
465     state->port = mystrdup(CLIENT_PORT_UNKNOWN);
466 
467     state->dest_addr = mystrdup(SERVER_ADDR_UNKNOWN);
468     state->dest_port = mystrdup(SERVER_PORT_UNKNOWN);
469 }
470 
471 /* smtpd_peer_from_pass_attr - initialize from attribute hash */
472 
smtpd_peer_from_pass_attr(SMTPD_STATE * state)473 static void smtpd_peer_from_pass_attr(SMTPD_STATE *state)
474 {
475     HTABLE *attr = (HTABLE *) vstream_context(state->client);
476     const char *cp;
477 
478     /*
479      * Extract the client endpoint information from the attribute hash.
480      */
481     if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_ADDR)) == 0)
482 	msg_fatal("missing client address from proxy");
483     if (strrchr(cp, ':') != 0) {
484 	if (valid_ipv6_hostaddr(cp, DO_GRIPE) == 0)
485 	    msg_fatal("bad IPv6 client address syntax from proxy: %s", cp);
486 	state->addr = mystrdup(cp);
487 	state->rfc_addr = concatenate(IPV6_COL, cp, (char *) 0);
488 	state->addr_family = AF_INET6;
489     } else {
490 	if (valid_ipv4_hostaddr(cp, DO_GRIPE) == 0)
491 	    msg_fatal("bad IPv4 client address syntax from proxy: %s", cp);
492 	state->addr = mystrdup(cp);
493 	state->rfc_addr = mystrdup(cp);
494 	state->addr_family = AF_INET;
495     }
496     if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_PORT)) == 0)
497 	msg_fatal("missing client port from proxy");
498     if (valid_hostport(cp, DO_GRIPE) == 0)
499 	msg_fatal("bad TCP client port number syntax from proxy: %s", cp);
500     state->port = mystrdup(cp);
501 
502     /*
503      * The Dovecot authentication server needs the server IP address.
504      */
505     if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_ADDR)) == 0)
506 	msg_fatal("missing server address from proxy");
507     if (valid_hostaddr(cp, DO_GRIPE) == 0)
508 	msg_fatal("bad IPv6 server address syntax from proxy: %s", cp);
509     state->dest_addr = mystrdup(cp);
510 
511     if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_PORT)) == 0)
512 	msg_fatal("missing server port from proxy");
513     if (valid_hostport(cp, DO_GRIPE) == 0)
514 	msg_fatal("bad TCP server port number syntax from proxy: %s", cp);
515     state->dest_port = mystrdup(cp);
516 
517     /*
518      * Convert the client address from string to binary form.
519      */
520     smtpd_peer_hostaddr_to_sockaddr(state);
521 }
522 
523 /* smtpd_peer_from_default - try to initialize peer information from socket */
524 
smtpd_peer_from_default(SMTPD_STATE * state)525 void    smtpd_peer_from_default(SMTPD_STATE *state)
526 {
527 
528     /*
529      * The "no client" routine provides surrogate information so that the
530      * application can produce sensible logging when a client disconnects
531      * before the server wakes up. The "not inet" routine provides surrogate
532      * state for (presumably) local IPC channels.
533      */
534     state->sockaddr_len = sizeof(state->sockaddr);
535     state->dest_sockaddr_len = sizeof(state->dest_sockaddr);
536     if (getpeername(vstream_fileno(state->client),
537 		    (struct sockaddr *) &state->sockaddr,
538 		    &state->sockaddr_len) <0
539 	|| getsockname(vstream_fileno(state->client),
540 		       (struct sockaddr *) &state->dest_sockaddr,
541 		       &state->dest_sockaddr_len) < 0) {
542 	if (errno == ENOTSOCK)
543 	    smtpd_peer_not_inet(state);
544 	else
545 	    smtpd_peer_no_client(state);
546     } else {
547 	if (smtpd_peer_sockaddr_to_hostaddr(state) < 0)
548 	    smtpd_peer_not_inet(state);
549     }
550 }
551 
552 /* smtpd_peer_from_proxy - get endpoint info from proxy agent */
553 
smtpd_peer_from_proxy(SMTPD_STATE * state)554 static void smtpd_peer_from_proxy(SMTPD_STATE *state)
555 {
556     typedef struct {
557 	const char *name;
558 	int     (*endpt_lookup) (SMTPD_STATE *);
559     } SMTPD_ENDPT_LOOKUP_INFO;
560     static const SMTPD_ENDPT_LOOKUP_INFO smtpd_endpt_lookup_info[] = {
561 	HAPROXY_PROTO_NAME, smtpd_peer_from_haproxy,
562 	0,
563     };
564     const SMTPD_ENDPT_LOOKUP_INFO *pp;
565 
566     /*
567      * When the proxy information is unavailable, we can't maintain an audit
568      * trail or enforce access control, therefore we forcibly hang up.
569      */
570     for (pp = smtpd_endpt_lookup_info; /* see below */ ; pp++) {
571 	if (pp->name == 0)
572 	    msg_fatal("unsupported %s value: %s",
573 		      VAR_SMTPD_UPROXY_PROTO, var_smtpd_uproxy_proto);
574 	if (strcmp(var_smtpd_uproxy_proto, pp->name) == 0)
575 	    break;
576     }
577     if (pp->endpt_lookup(state) < 0) {
578 	smtpd_peer_from_default(state);
579 	state->flags |= SMTPD_FLAG_HANGUP;
580     } else {
581 	smtpd_peer_hostaddr_to_sockaddr(state);
582     }
583 }
584 
585 /* smtpd_peer_init - initialize peer information */
586 
smtpd_peer_init(SMTPD_STATE * state)587 void    smtpd_peer_init(SMTPD_STATE *state)
588 {
589     int     af;
590 
591     /*
592      * Initialize.
593      */
594     if (proto_info == 0)
595 	proto_info = inet_proto_info();
596 
597     /*
598      * Prepare for partial initialization after error.
599      */
600     memset((void *) &(state->sockaddr), 0, sizeof(state->sockaddr));
601     state->sockaddr_len = 0;
602     state->name = 0;
603     state->reverse_name = 0;
604     state->addr = 0;
605     state->namaddr = 0;
606     state->rfc_addr = 0;
607     state->port = 0;
608     state->anvil_range = 0;
609     state->dest_addr = 0;
610     state->dest_port = 0;
611 
612     /*
613      * Determine the remote SMTP client address and port.
614      *
615      * XXX In stand-alone mode, don't assume that the peer will be a local
616      * process. That could introduce a gaping hole when the SMTP daemon is
617      * hooked up to the network via inetd or some other super-server.
618      */
619     if (vstream_context(state->client) != 0) {
620 	smtpd_peer_from_pass_attr(state);
621 	if (*var_smtpd_uproxy_proto != 0)
622 	    msg_warn("ignoring non-empty %s setting behind postscreen",
623 		     VAR_SMTPD_UPROXY_PROTO);
624     } else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) {
625 	smtpd_peer_from_default(state);
626     } else {
627 	smtpd_peer_from_proxy(state);
628     }
629 
630     /*
631      * Determine the remote SMTP client hostname. Note: some of the handlers
632      * above provide surrogate endpoint information in case of error. In that
633      * case, leave the surrogate information alone.
634      */
635     if (state->name == 0)
636 	smtpd_peer_sockaddr_to_hostname(state);
637 
638     /*
639      * Do the name[addr]:port formatting for pretty reports.
640      */
641     state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
642 					     state->port);
643 
644     /*
645      * Generate 'address' or 'net/mask' index for anvil event aggregation.
646      * Don't do this for non-socket input. See smtpd_peer_not_inet().
647      */
648     if (state->addr_family != AF_UNSPEC) {
649 	af = SOCK_ADDR_FAMILY(&(state->sockaddr));
650 	state->anvil_range = inet_prefix_top(af,
651 					SOCK_ADDR_ADDRP(&(state->sockaddr)),
652 					     af == AF_INET ?
653 					     var_smtpd_cipv4_prefix :
654 					     var_smtpd_cipv6_prefix);
655     }
656 }
657 
658 /* smtpd_peer_reset - destroy peer information */
659 
smtpd_peer_reset(SMTPD_STATE * state)660 void    smtpd_peer_reset(SMTPD_STATE *state)
661 {
662     if (state->name)
663 	myfree(state->name);
664     if (state->reverse_name)
665 	myfree(state->reverse_name);
666     if (state->addr)
667 	myfree(state->addr);
668     if (state->namaddr)
669 	myfree(state->namaddr);
670     if (state->rfc_addr)
671 	myfree(state->rfc_addr);
672     if (state->port)
673 	myfree(state->port);
674     if (state->dest_addr)
675 	myfree(state->dest_addr);
676     if (state->dest_port)
677 	myfree(state->dest_port);
678     if (state->anvil_range)
679 	myfree(state->anvil_range);
680 }
681