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