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 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 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