7 /* look up peer name/address information
11 /* void qmqpd_peer_init(state)
12 /* QMQPD_STATE *state;
14 /* void qmqpd_peer_reset(state)
15 /* QMQPD_STATE *state;
17 /* The qmqpd_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".
22 /* qmqpd_peer_init() updates the following fields:
24 /* The client hostname. An unknown name is represented by the
27 /* Printable representation of the client address.
29 /* String of the form: "name[addr]:port".
31 /* qmqpd_peer_reset() releases memory allocated by qmqpd_peer_init().
35 /* The Secure Mailer license must be distributed with this software.
38 /* IBM T.J. Watson Research
40 /* Yorktown Heights, NY 10598, USA
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <stdio.h> /* strerror() */
54 /* Utility library. */
58 #include <stringops.h>
59 #include <myaddrinfo.h>
60 #include <sock_addr.h>
61 #include <inet_proto.h>
65 #include <mail_proto.h>
66 #include <valid_mailhost_addr.h>
67 #include <mail_params.h>
69 /* Application-specific. */
73 /* qmqpd_peer_init - initialize peer information */
75 void qmqpd_peer_init(QMQPD_STATE
*state
)
77 const char *myname
= "qmqpd_peer_init";
78 struct sockaddr_storage ss
;
80 SOCKADDR_SIZE sa_length
;
81 INET_PROTO_INFO
*proto_info
= inet_proto_info();
83 sa
= (struct sockaddr
*) & ss
;
84 sa_length
= sizeof(ss
);
87 * Look up the peer address information.
89 if (getpeername(vstream_fileno(state
->client
), sa
, &sa_length
) >= 0) {
94 * If peer went away, give up.
96 if (errno
!= 0 && errno
!= ENOTSOCK
) {
97 state
->name
= mystrdup(CLIENT_NAME_UNKNOWN
);
98 state
->addr
= mystrdup(CLIENT_ADDR_UNKNOWN
);
99 state
->rfc_addr
= mystrdup(CLIENT_ADDR_UNKNOWN
);
100 state
->addr_family
= AF_UNSPEC
;
101 state
->port
= mystrdup(CLIENT_PORT_UNKNOWN
);
105 * Convert the client address to printable address and hostname.
107 * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
108 * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
109 * else clause, pretend the origin is localhost[127.0.0.1], and become an
113 && (sa
->sa_family
== AF_INET
115 || sa
->sa_family
== AF_INET6
118 MAI_HOSTNAME_STR client_name
;
119 MAI_HOSTADDR_STR client_addr
;
120 MAI_SERVPORT_STR client_port
;
125 * Sanity check: we can't use sockets that we're not configured for.
127 if (strchr((char *) proto_info
->sa_family_list
, sa
->sa_family
) == 0)
128 msg_fatal("cannot handle socket type %s with \"%s = %s\"",
130 sa
->sa_family
== AF_INET6
? "AF_INET6" :
132 sa
->sa_family
== AF_INET
? "AF_INET" :
133 "other", VAR_INET_PROTOCOLS
, var_inet_protocols
);
136 * Sorry, but there are some things that we just cannot do while
137 * connected to the network.
139 if (geteuid() != var_owner_uid
|| getuid() != var_owner_uid
) {
140 msg_error("incorrect QMQP server privileges: uid=%lu euid=%lu",
141 (unsigned long) getuid(), (unsigned long) geteuid());
142 msg_fatal("the Postfix QMQP server must run with $%s privileges",
147 * Convert the client address to printable form.
149 if ((aierr
= sockaddr_to_hostaddr(sa
, sa_length
, &client_addr
,
150 &client_port
, 0)) != 0)
151 msg_fatal("%s: cannot convert client address/port to string: %s",
152 myname
, MAI_STRERROR(aierr
));
153 state
->port
= mystrdup(client_port
.buf
);
156 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
157 * but only if IPv4 support is enabled (why would anyone want to turn
158 * it off)? With IPv4 support enabled we have no need for the IPv6
159 * form in logging, hostname verification and access checks.
162 if (sa
->sa_family
== AF_INET6
) {
163 if (strchr((char *) proto_info
->sa_family_list
, AF_INET
) != 0
164 && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa
))
165 && (colonp
= strrchr(client_addr
.buf
, ':')) != 0) {
166 struct addrinfo
*res0
;
169 msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
170 myname
, client_addr
.buf
, colonp
+ 1);
172 state
->addr
= mystrdup(colonp
+ 1);
173 state
->rfc_addr
= mystrdup(colonp
+ 1);
174 state
->addr_family
= AF_INET
;
175 aierr
= hostaddr_to_sockaddr(state
->addr
, (char *) 0, 0, &res0
);
177 msg_fatal("%s: cannot convert %s from string to binary: %s",
178 myname
, state
->addr
, MAI_STRERROR(aierr
));
179 sa_length
= res0
->ai_addrlen
;
180 if (sa_length
> sizeof(ss
))
181 sa_length
= sizeof(ss
);
182 memcpy((char *) sa
, res0
->ai_addr
, sa_length
);
187 * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
188 * a prefix of 'IPv6:'. We do this consistently for all IPv6
189 * addresses that that appear in headers or envelopes. The fact
190 * that valid_mailhost_addr() enforces the form helps of course.
191 * We use the form without IPV6: prefix when doing access
192 * control, or when accessing the connection cache.
195 state
->addr
= mystrdup(client_addr
.buf
);
197 concatenate(IPV6_COL
, client_addr
.buf
, (char *) 0);
198 state
->addr_family
= sa
->sa_family
;
203 * An IPv4 address is in dotted quad decimal form.
208 state
->addr
= mystrdup(client_addr
.buf
);
209 state
->rfc_addr
= mystrdup(client_addr
.buf
);
210 state
->addr_family
= sa
->sa_family
;
214 * Look up and sanity check the client hostname.
216 * It is unsafe to allow numeric hostnames, especially because there
217 * exists pressure to turn off the name->addr double check. In that
218 * case an attacker could trivally bypass access restrictions.
220 * sockaddr_to_hostname() already rejects malformed or numeric names.
222 #define REJECT_PEER_NAME(state) { \
223 myfree(state->name); \
224 state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
227 if ((aierr
= sockaddr_to_hostname(sa
, sa_length
, &client_name
,
228 (MAI_SERVNAME_STR
*) 0, 0)) != 0) {
229 state
->name
= mystrdup(CLIENT_NAME_UNKNOWN
);
231 struct addrinfo
*res0
;
232 struct addrinfo
*res
;
234 state
->name
= mystrdup(client_name
.buf
);
237 * Reject the hostname if it does not list the peer address.
239 aierr
= hostname_to_sockaddr(state
->name
, (char *) 0, 0, &res0
);
241 msg_warn("%s: hostname %s verification failed: %s",
242 state
->addr
, state
->name
, MAI_STRERROR(aierr
));
243 REJECT_PEER_NAME(state
);
245 for (res
= res0
; /* void */ ; res
= res
->ai_next
) {
247 msg_warn("%s: address not listed for hostname %s",
248 state
->addr
, state
->name
);
249 REJECT_PEER_NAME(state
);
252 if (strchr((char *) proto_info
->sa_family_list
, res
->ai_family
) == 0) {
253 msg_info("skipping address family %d for host %s",
254 res
->ai_family
, state
->name
);
257 if (sock_addr_cmp_addr(res
->ai_addr
, sa
) == 0)
258 break; /* keep peer name */
266 * If it's not Internet, assume the client is local, and avoid using the
267 * naming service because that can hang when the machine is disconnected.
270 state
->name
= mystrdup("localhost");
271 state
->addr
= mystrdup("127.0.0.1"); /* XXX bogus. */
272 state
->rfc_addr
= mystrdup("127.0.0.1");/* XXX bogus. */
273 state
->addr_family
= AF_UNSPEC
;
274 state
->port
= mystrdup("0"); /* XXX bogus. */
278 * Do the name[addr]:port formatting for pretty reports.
281 concatenate(state
->name
, "[", state
->addr
, "]",
282 var_qmqpd_client_port_log
? ":" : (char *) 0,
283 state
->port
, (char *) 0);
286 /* qmqpd_peer_reset - destroy peer information */
288 void qmqpd_peer_reset(QMQPD_STATE
*state
)
292 myfree(state
->namaddr
);
293 myfree(state
->rfc_addr
);