1 /* $NetBSD: qmqpd_peer.c,v 1.3 2022/10/08 16:12:48 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* qmqpd_peer 3
6 /* SUMMARY
7 /* look up peer name/address information
8 /* SYNOPSIS
9 /* #include "qmqpd.h"
10 /*
11 /* void qmqpd_peer_init(state)
12 /* QMQPD_STATE *state;
13 /*
14 /* void qmqpd_peer_reset(state)
15 /* QMQPD_STATE *state;
16 /* DESCRIPTION
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".
21 /*
22 /* qmqpd_peer_init() updates the following fields:
23 /* .IP name
24 /* The client hostname. An unknown name is represented by the
25 /* string "unknown".
26 /* .IP addr
27 /* Printable representation of the client address.
28 /* .IP namaddr
29 /* String of the form: "name[addr]:port".
30 /* .PP
31 /* qmqpd_peer_reset() releases memory allocated by qmqpd_peer_init().
32 /* LICENSE
33 /* .ad
34 /* .fi
35 /* The Secure Mailer license must be distributed with this software.
36 /* AUTHOR(S)
37 /* Wietse Venema
38 /* IBM T.J. Watson Research
39 /* P.O. Box 704
40 /* Yorktown Heights, NY 10598, USA
41 /*
42 /* Wietse Venema
43 /* Google, Inc.
44 /* 111 8th Avenue
45 /* New York, NY 10011, USA
46 /*--*/
47
48 /* System library. */
49
50 #include <sys_defs.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <errno.h>
55 #include <netdb.h>
56 #include <string.h>
57
58 /* Utility library. */
59
60 #include <msg.h>
61 #include <mymalloc.h>
62 #include <stringops.h>
63 #include <myaddrinfo.h>
64 #include <sock_addr.h>
65 #include <inet_proto.h>
66 #include <split_at.h>
67
68 /* Global library. */
69
70 #include <mail_proto.h>
71 #include <valid_mailhost_addr.h>
72 #include <mail_params.h>
73
74 /* Application-specific. */
75
76 #include "qmqpd.h"
77
78 /* qmqpd_peer_init - initialize peer information */
79
qmqpd_peer_init(QMQPD_STATE * state)80 void qmqpd_peer_init(QMQPD_STATE *state)
81 {
82 const char *myname = "qmqpd_peer_init";
83 struct sockaddr_storage ss;
84 struct sockaddr *sa;
85 SOCKADDR_SIZE sa_length;
86 const INET_PROTO_INFO *proto_info = inet_proto_info();
87
88 sa = (struct sockaddr *) &ss;
89 sa_length = sizeof(ss);
90
91 /*
92 * Look up the peer address information.
93 */
94 if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
95 errno = 0;
96 }
97
98 /*
99 * If peer went away, give up.
100 */
101 if (errno != 0 && errno != ENOTSOCK) {
102 state->name = mystrdup(CLIENT_NAME_UNKNOWN);
103 state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
104 state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
105 state->addr_family = AF_UNSPEC;
106 state->port = mystrdup(CLIENT_PORT_UNKNOWN);
107 }
108
109 /*
110 * Convert the client address to printable address and hostname.
111 *
112 * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
113 * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
114 * else clause, pretend the origin is localhost[127.0.0.1], and become an
115 * open relay).
116 */
117 else if (errno == 0
118 && (sa->sa_family == AF_INET
119 #ifdef AF_INET6
120 || sa->sa_family == AF_INET6
121 #endif
122 )) {
123 MAI_HOSTNAME_STR client_name;
124 MAI_HOSTADDR_STR client_addr;
125 MAI_SERVPORT_STR client_port;
126 int aierr;
127 char *colonp;
128
129 /*
130 * Sanity check: we can't use sockets that we're not configured for.
131 */
132 if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
133 msg_fatal("cannot handle socket type %s with \"%s = %s\"",
134 #ifdef AF_INET6
135 sa->sa_family == AF_INET6 ? "AF_INET6" :
136 #endif
137 sa->sa_family == AF_INET ? "AF_INET" :
138 "other", VAR_INET_PROTOCOLS, var_inet_protocols);
139
140 /*
141 * Sorry, but there are some things that we just cannot do while
142 * connected to the network.
143 */
144 if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
145 msg_error("incorrect QMQP server privileges: uid=%lu euid=%lu",
146 (unsigned long) getuid(), (unsigned long) geteuid());
147 msg_fatal("the Postfix QMQP server must run with $%s privileges",
148 VAR_MAIL_OWNER);
149 }
150
151 /*
152 * Convert the client address to printable form.
153 */
154 if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
155 &client_port, 0)) != 0)
156 msg_fatal("%s: cannot convert client address/port to string: %s",
157 myname, MAI_STRERROR(aierr));
158 state->port = mystrdup(client_port.buf);
159
160 /*
161 * XXX Require that the infrastructure strips off the IPv6 datalink
162 * suffix to avoid false alarms with strict address syntax checks.
163 */
164 #ifdef HAS_IPV6
165 if (strchr(client_addr.buf, '%') != 0)
166 msg_panic("%s: address %s has datalink suffix",
167 myname, client_addr.buf);
168 #endif
169
170 /*
171 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
172 * but only if IPv4 support is enabled (why would anyone want to turn
173 * it off)? With IPv4 support enabled we have no need for the IPv6
174 * form in logging, hostname verification and access checks.
175 */
176 #ifdef HAS_IPV6
177 if (sa->sa_family == AF_INET6) {
178 if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
179 && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
180 && (colonp = strrchr(client_addr.buf, ':')) != 0) {
181 struct addrinfo *res0;
182
183 if (msg_verbose > 1)
184 msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
185 myname, client_addr.buf, colonp + 1);
186
187 state->addr = mystrdup(colonp + 1);
188 state->rfc_addr = mystrdup(colonp + 1);
189 state->addr_family = AF_INET;
190 aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
191 if (aierr)
192 msg_fatal("%s: cannot convert %s from string to binary: %s",
193 myname, state->addr, MAI_STRERROR(aierr));
194 sa_length = res0->ai_addrlen;
195 if (sa_length > sizeof(ss))
196 sa_length = sizeof(ss);
197 memcpy((void *) sa, res0->ai_addr, sa_length);
198 freeaddrinfo(res0);
199 }
200
201 /*
202 * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
203 * a prefix of 'IPv6:'. We do this consistently for all IPv6
204 * addresses that appear in headers or envelopes. The fact
205 * that valid_mailhost_addr() enforces the form helps of course.
206 * We use the form without IPV6: prefix when doing access
207 * control, or when accessing the connection cache.
208 */
209 else {
210 state->addr = mystrdup(client_addr.buf);
211 state->rfc_addr =
212 concatenate(IPV6_COL, client_addr.buf, (char *) 0);
213 state->addr_family = sa->sa_family;
214 }
215 }
216
217 /*
218 * An IPv4 address is in dotted quad decimal form.
219 */
220 else
221 #endif
222 {
223 state->addr = mystrdup(client_addr.buf);
224 state->rfc_addr = mystrdup(client_addr.buf);
225 state->addr_family = sa->sa_family;
226 }
227
228 /*
229 * Look up and sanity check the client hostname.
230 *
231 * It is unsafe to allow numeric hostnames, especially because there
232 * exists pressure to turn off the name->addr double check. In that
233 * case an attacker could trivally bypass access restrictions.
234 *
235 * sockaddr_to_hostname() already rejects malformed or numeric names.
236 */
237 #define REJECT_PEER_NAME(state) { \
238 myfree(state->name); \
239 state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
240 }
241
242 if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
243 (MAI_SERVNAME_STR *) 0, 0)) != 0) {
244 state->name = mystrdup(CLIENT_NAME_UNKNOWN);
245 } else {
246 struct addrinfo *res0;
247 struct addrinfo *res;
248
249 state->name = mystrdup(client_name.buf);
250
251 /*
252 * Reject the hostname if it does not list the peer address.
253 */
254 aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
255 (char *) 0, 0, &res0);
256 if (aierr) {
257 msg_warn("hostname %s does not resolve to address %s: %s",
258 state->name, state->addr, MAI_STRERROR(aierr));
259 REJECT_PEER_NAME(state);
260 } else {
261 for (res = res0; /* void */ ; res = res->ai_next) {
262 if (res == 0) {
263 msg_warn("hostname %s does not resolve to address %s",
264 state->addr, state->name);
265 REJECT_PEER_NAME(state);
266 break;
267 }
268 if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
269 msg_info("skipping address family %d for host %s",
270 res->ai_family, state->name);
271 continue;
272 }
273 if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
274 break; /* keep peer name */
275 }
276 freeaddrinfo(res0);
277 }
278 }
279 }
280
281 /*
282 * If it's not Internet, assume the client is local, and avoid using the
283 * naming service because that can hang when the machine is disconnected.
284 */
285 else {
286 state->name = mystrdup("localhost");
287 state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
288 state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
289 state->addr_family = AF_UNSPEC;
290 state->port = mystrdup("0"); /* XXX bogus. */
291 }
292
293 /*
294 * Do the name[addr]:port formatting for pretty reports.
295 */
296 state->namaddr =
297 concatenate(state->name, "[", state->addr, "]",
298 var_qmqpd_client_port_log ? ":" : (char *) 0,
299 state->port, (char *) 0);
300 }
301
302 /* qmqpd_peer_reset - destroy peer information */
303
qmqpd_peer_reset(QMQPD_STATE * state)304 void qmqpd_peer_reset(QMQPD_STATE *state)
305 {
306 myfree(state->name);
307 myfree(state->addr);
308 myfree(state->namaddr);
309 myfree(state->rfc_addr);
310 myfree(state->port);
311 }
312