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