1 /* $NetBSD: qmqpd_peer.c,v 1.1.1.1 2009/06/23 10:08:53 tron 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 43 /* System library. */ 44 45 #include <sys_defs.h> 46 #include <sys/socket.h> 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 #include <stdio.h> /* strerror() */ 50 #include <errno.h> 51 #include <netdb.h> 52 #include <string.h> 53 54 /* Utility library. */ 55 56 #include <msg.h> 57 #include <mymalloc.h> 58 #include <stringops.h> 59 #include <myaddrinfo.h> 60 #include <sock_addr.h> 61 #include <inet_proto.h> 62 63 /* Global library. */ 64 65 #include <mail_proto.h> 66 #include <valid_mailhost_addr.h> 67 #include <mail_params.h> 68 69 /* Application-specific. */ 70 71 #include "qmqpd.h" 72 73 /* qmqpd_peer_init - initialize peer information */ 74 75 void qmqpd_peer_init(QMQPD_STATE *state) 76 { 77 const char *myname = "qmqpd_peer_init"; 78 struct sockaddr_storage ss; 79 struct sockaddr *sa; 80 SOCKADDR_SIZE sa_length; 81 INET_PROTO_INFO *proto_info = inet_proto_info(); 82 83 sa = (struct sockaddr *) & ss; 84 sa_length = sizeof(ss); 85 86 /* 87 * Look up the peer address information. 88 */ 89 if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) { 90 errno = 0; 91 } 92 93 /* 94 * If peer went away, give up. 95 */ 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); 102 } 103 104 /* 105 * Convert the client address to printable address and hostname. 106 * 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 110 * open relay). 111 */ 112 else if (errno == 0 113 && (sa->sa_family == AF_INET 114 #ifdef AF_INET6 115 || sa->sa_family == AF_INET6 116 #endif 117 )) { 118 MAI_HOSTNAME_STR client_name; 119 MAI_HOSTADDR_STR client_addr; 120 MAI_SERVPORT_STR client_port; 121 int aierr; 122 char *colonp; 123 124 /* 125 * Sanity check: we can't use sockets that we're not configured for. 126 */ 127 if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0) 128 msg_fatal("cannot handle socket type %s with \"%s = %s\"", 129 #ifdef AF_INET6 130 sa->sa_family == AF_INET6 ? "AF_INET6" : 131 #endif 132 sa->sa_family == AF_INET ? "AF_INET" : 133 "other", VAR_INET_PROTOCOLS, var_inet_protocols); 134 135 /* 136 * Sorry, but there are some things that we just cannot do while 137 * connected to the network. 138 */ 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", 143 VAR_MAIL_OWNER); 144 } 145 146 /* 147 * Convert the client address to printable form. 148 */ 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); 154 155 /* 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. 160 */ 161 #ifdef HAS_IPV6 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; 167 168 if (msg_verbose > 1) 169 msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"", 170 myname, client_addr.buf, colonp + 1); 171 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); 176 if (aierr) 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); 183 freeaddrinfo(res0); 184 } 185 186 /* 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. 193 */ 194 else { 195 state->addr = mystrdup(client_addr.buf); 196 state->rfc_addr = 197 concatenate(IPV6_COL, client_addr.buf, (char *) 0); 198 state->addr_family = sa->sa_family; 199 } 200 } 201 202 /* 203 * An IPv4 address is in dotted quad decimal form. 204 */ 205 else 206 #endif 207 { 208 state->addr = mystrdup(client_addr.buf); 209 state->rfc_addr = mystrdup(client_addr.buf); 210 state->addr_family = sa->sa_family; 211 } 212 213 /* 214 * Look up and sanity check the client hostname. 215 * 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. 219 * 220 * sockaddr_to_hostname() already rejects malformed or numeric names. 221 */ 222 #define REJECT_PEER_NAME(state) { \ 223 myfree(state->name); \ 224 state->name = mystrdup(CLIENT_NAME_UNKNOWN); \ 225 } 226 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); 230 } else { 231 struct addrinfo *res0; 232 struct addrinfo *res; 233 234 state->name = mystrdup(client_name.buf); 235 236 /* 237 * Reject the hostname if it does not list the peer address. 238 */ 239 aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0); 240 if (aierr) { 241 msg_warn("%s: hostname %s verification failed: %s", 242 state->addr, state->name, MAI_STRERROR(aierr)); 243 REJECT_PEER_NAME(state); 244 } else { 245 for (res = res0; /* void */ ; res = res->ai_next) { 246 if (res == 0) { 247 msg_warn("%s: address not listed for hostname %s", 248 state->addr, state->name); 249 REJECT_PEER_NAME(state); 250 break; 251 } 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); 255 continue; 256 } 257 if (sock_addr_cmp_addr(res->ai_addr, sa) == 0) 258 break; /* keep peer name */ 259 } 260 freeaddrinfo(res0); 261 } 262 } 263 } 264 265 /* 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. 268 */ 269 else { 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. */ 275 } 276 277 /* 278 * Do the name[addr]:port formatting for pretty reports. 279 */ 280 state->namaddr = 281 concatenate(state->name, "[", state->addr, "]", 282 var_qmqpd_client_port_log ? ":" : (char *) 0, 283 state->port, (char *) 0); 284 } 285 286 /* qmqpd_peer_reset - destroy peer information */ 287 288 void qmqpd_peer_reset(QMQPD_STATE *state) 289 { 290 myfree(state->name); 291 myfree(state->addr); 292 myfree(state->namaddr); 293 myfree(state->rfc_addr); 294 myfree(state->port); 295 } 296