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 74void qmqpd_peer_init(QMQPD_STATE *state) 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) { 96 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 97 state->addr = mystrdup(CLIENT_ADDR_UNKNOWN); 98 state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN); 99 state->addr_family = AF_UNSPEC; 100 state->port = mystrdup(CLIENT_PORT_UNKNOWN); 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" : 132 "other", VAR_INET_PROTOCOLS, var_inet_protocols); 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", 142 VAR_MAIL_OWNER); 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((char *) 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) { 238 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 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 298void qmqpd_peer_reset(QMQPD_STATE *state) 299{ 300 myfree(state->name); 301 myfree(state->addr); 302 myfree(state->namaddr); 303 myfree(state->rfc_addr); 304 myfree(state->port); 305} 306