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