1 /* $NetBSD: smtpd_peer.c,v 1.2 2017/02/14 01:16:48 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* smtpd_peer 3 6 /* SUMMARY 7 /* look up peer name/address information 8 /* SYNOPSIS 9 /* #include "smtpd.h" 10 /* 11 /* void smtpd_peer_init(state) 12 /* SMTPD_STATE *state; 13 /* 14 /* void smtpd_peer_reset(state) 15 /* SMTPD_STATE *state; 16 /* DESCRIPTION 17 /* The smtpd_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 /* Alternatively, the peer address and port may be obtained 23 /* from a proxy server. 24 /* 25 /* This module uses the local name service via getaddrinfo() 26 /* and getnameinfo(). It does not query the DNS directly. 27 /* 28 /* smtpd_peer_init() updates the following fields: 29 /* .IP name 30 /* The verified client hostname. This name is represented by 31 /* the string "unknown" when 1) the address->name lookup failed, 32 /* 2) the name->address mapping fails, or 3) the name->address 33 /* mapping does not produce the client IP address. 34 /* .IP reverse_name 35 /* The unverified client hostname as found with address->name 36 /* lookup; it is not verified for consistency with the client 37 /* IP address result from name->address lookup. 38 /* .IP forward_name 39 /* The unverified client hostname as found with address->name 40 /* lookup followed by name->address lookup; it is not verified 41 /* for consistency with the result from address->name lookup. 42 /* For example, when the address->name lookup produces as 43 /* hostname an alias, the name->address lookup will produce 44 /* as hostname the expansion of that alias, so that the two 45 /* lookups produce different names. 46 /* .IP addr 47 /* Printable representation of the client address. 48 /* .IP namaddr 49 /* String of the form: "name[addr]:port". 50 /* .IP rfc_addr 51 /* String of the form "ipv4addr" or "ipv6:ipv6addr" for use 52 /* in Received: message headers. 53 /* .IP dest_addr 54 /* Server address, used by the Dovecot authentication server. 55 /* .IP name_status 56 /* The name_status result field specifies how the name 57 /* information should be interpreted: 58 /* .RS 59 /* .IP 2 60 /* The address->name lookup and name->address lookup produced 61 /* the client IP address. 62 /* .IP 4 63 /* The address->name lookup or name->address lookup failed 64 /* with a recoverable error. 65 /* .IP 5 66 /* The address->name lookup or name->address lookup failed 67 /* with an unrecoverable error, or the result did not match 68 /* the client IP address. 69 /* .RE 70 /* .IP reverse_name_status 71 /* The reverse_name_status result field specifies how the 72 /* reverse_name information should be interpreted: 73 /* .RS .IP 2 74 /* The address->name lookup succeeded. 75 /* .IP 4 76 /* The address->name lookup failed with a recoverable error. 77 /* .IP 5 78 /* The address->name lookup failed with an unrecoverable error. 79 /* .RE .IP forward_name_status 80 /* The forward_name_status result field specifies how the 81 /* forward_name information should be interpreted: 82 /* .RS .IP 2 83 /* The address->name and name->address lookup succeeded. 84 /* .IP 4 85 /* The address->name lookup or name->address failed with a 86 /* recoverable error. 87 /* .IP 5 88 /* The address->name lookup or name->address failed with an 89 /* unrecoverable error. 90 /* .RE 91 /* .PP 92 /* smtpd_peer_reset() releases memory allocated by smtpd_peer_init(). 93 /* LICENSE 94 /* .ad 95 /* .fi 96 /* The Secure Mailer license must be distributed with this software. 97 /* AUTHOR(S) 98 /* Wietse Venema 99 /* IBM T.J. Watson Research 100 /* P.O. Box 704 101 /* Yorktown Heights, NY 10598, USA 102 /*--*/ 103 104 /* System library. */ 105 106 #include <sys_defs.h> 107 #include <sys/socket.h> 108 #include <netinet/in.h> 109 #include <arpa/inet.h> 110 #include <stdio.h> /* strerror() */ 111 #include <errno.h> 112 #include <netdb.h> 113 #include <string.h> 114 #include <htable.h> 115 116 /* Utility library. */ 117 118 #include <msg.h> 119 #include <mymalloc.h> 120 #include <stringops.h> 121 #include <myaddrinfo.h> 122 #include <sock_addr.h> 123 #include <inet_proto.h> 124 #include <split_at.h> 125 126 /* Global library. */ 127 128 #include <mail_proto.h> 129 #include <valid_mailhost_addr.h> 130 #include <mail_params.h> 131 #include <haproxy_srvr.h> 132 133 /* Application-specific. */ 134 135 #include "smtpd.h" 136 137 static INET_PROTO_INFO *proto_info; 138 139 /* 140 * XXX If we make local endpoint (getsockname) information available to 141 * Milter applications as {if_name} and {if_addr}, then we also must be able 142 * to provide this via the XCLIENT command for Milter testing. 143 * 144 * XXX If we make local port information available to policy servers or Milter 145 * applications, then we must also make this testable with the XCLIENT 146 * command, otherwise there will be confusion. 147 * 148 * XXX If we make local port information available via logging, then we must 149 * also support these attributes with the XFORWARD command. 150 * 151 * XXX If support were to be added for Milter applications in down-stream MTAs, 152 * then consistency demands that we propagate a lot of Sendmail macro 153 * information via the XFORWARD command. Otherwise we could end up with a 154 * very confusing situation. 155 */ 156 157 /* smtpd_peer_sockaddr_to_hostaddr - client address/port to printable form */ 158 159 static int smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE *state) 160 { 161 const char *myname = "smtpd_peer_sockaddr_to_hostaddr"; 162 struct sockaddr *sa = (struct sockaddr *) &(state->sockaddr); 163 SOCKADDR_SIZE sa_length = state->sockaddr_len; 164 165 /* 166 * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, 167 * while Postfix IPv6 (or IPv4) support is turned off, don't (skip to the 168 * final else clause, pretend the origin is localhost[127.0.0.1], and 169 * become an open relay). 170 */ 171 if (sa->sa_family == AF_INET 172 #ifdef AF_INET6 173 || sa->sa_family == AF_INET6 174 #endif 175 ) { 176 MAI_HOSTADDR_STR client_addr; 177 MAI_SERVPORT_STR client_port; 178 int aierr; 179 char *colonp; 180 181 /* 182 * Sanity check: we can't use sockets that we're not configured for. 183 */ 184 if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0) 185 msg_fatal("cannot handle socket type %s with \"%s = %s\"", 186 #ifdef AF_INET6 187 sa->sa_family == AF_INET6 ? "AF_INET6" : 188 #endif 189 sa->sa_family == AF_INET ? "AF_INET" : 190 "other", VAR_INET_PROTOCOLS, var_inet_protocols); 191 192 /* 193 * Sorry, but there are some things that we just cannot do while 194 * connected to the network. 195 */ 196 if (geteuid() != var_owner_uid || getuid() != var_owner_uid) { 197 msg_error("incorrect SMTP server privileges: uid=%lu euid=%lu", 198 (unsigned long) getuid(), (unsigned long) geteuid()); 199 msg_fatal("the Postfix SMTP server must run with $%s privileges", 200 VAR_MAIL_OWNER); 201 } 202 203 /* 204 * Convert the client address to printable form. 205 */ 206 if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr, 207 &client_port, 0)) != 0) 208 msg_fatal("%s: cannot convert client address/port to string: %s", 209 myname, MAI_STRERROR(aierr)); 210 state->port = mystrdup(client_port.buf); 211 212 /* 213 * XXX Require that the infrastructure strips off the IPv6 datalink 214 * suffix to avoid false alarms with strict address syntax checks. 215 */ 216 #ifdef HAS_IPV6 217 if (strchr(client_addr.buf, '%') != 0) 218 msg_panic("%s: address %s has datalink suffix", 219 myname, client_addr.buf); 220 #endif 221 222 /* 223 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on, 224 * but only if IPv4 support is enabled (why would anyone want to turn 225 * it off)? With IPv4 support enabled we have no need for the IPv6 226 * form in logging, hostname verification and access checks. 227 */ 228 #ifdef HAS_IPV6 229 if (sa->sa_family == AF_INET6) { 230 if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0 231 && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa)) 232 && (colonp = strrchr(client_addr.buf, ':')) != 0) { 233 struct addrinfo *res0; 234 235 if (msg_verbose > 1) 236 msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"", 237 myname, client_addr.buf, colonp + 1); 238 239 state->addr = mystrdup(colonp + 1); 240 state->rfc_addr = mystrdup(colonp + 1); 241 state->addr_family = AF_INET; 242 aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0); 243 if (aierr) 244 msg_fatal("%s: cannot convert %s from string to binary: %s", 245 myname, state->addr, MAI_STRERROR(aierr)); 246 sa_length = res0->ai_addrlen; 247 if (sa_length > sizeof(state->sockaddr)) 248 sa_length = sizeof(state->sockaddr); 249 memcpy((void *) sa, res0->ai_addr, sa_length); 250 freeaddrinfo(res0); /* 200412 */ 251 } 252 253 /* 254 * Following RFC 2821 section 4.1.3, an IPv6 address literal gets 255 * a prefix of 'IPv6:'. We do this consistently for all IPv6 256 * addresses that that appear in headers or envelopes. The fact 257 * that valid_mailhost_addr() enforces the form helps of course. 258 * We use the form without IPV6: prefix when doing access 259 * control, or when accessing the connection cache. 260 */ 261 else { 262 state->addr = mystrdup(client_addr.buf); 263 state->rfc_addr = 264 concatenate(IPV6_COL, client_addr.buf, (char *) 0); 265 state->addr_family = sa->sa_family; 266 } 267 } 268 269 /* 270 * An IPv4 address is in dotted quad decimal form. 271 */ 272 else 273 #endif 274 { 275 state->addr = mystrdup(client_addr.buf); 276 state->rfc_addr = mystrdup(client_addr.buf); 277 state->addr_family = sa->sa_family; 278 } 279 return (0); 280 } 281 282 /* 283 * It's not Internet. 284 */ 285 else { 286 return (-1); 287 } 288 } 289 290 /* smtpd_peer_sockaddr_to_hostname - client hostname lookup */ 291 292 static void smtpd_peer_sockaddr_to_hostname(SMTPD_STATE *state) 293 { 294 struct sockaddr *sa = (struct sockaddr *) &(state->sockaddr); 295 SOCKADDR_SIZE sa_length = state->sockaddr_len; 296 MAI_HOSTNAME_STR client_name; 297 int aierr; 298 299 /* 300 * Look up and sanity check the client hostname. 301 * 302 * It is unsafe to allow numeric hostnames, especially because there exists 303 * pressure to turn off the name->addr double check. In that case an 304 * attacker could trivally bypass access restrictions. 305 * 306 * sockaddr_to_hostname() already rejects malformed or numeric names. 307 */ 308 #define TEMP_AI_ERROR(e) \ 309 ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM) 310 311 #define REJECT_PEER_NAME(state, code) { \ 312 myfree(state->name); \ 313 state->name = mystrdup(CLIENT_NAME_UNKNOWN); \ 314 state->name_status = code; \ 315 } 316 317 if (var_smtpd_peername_lookup == 0) { 318 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 319 state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); 320 state->name_status = SMTPD_PEER_CODE_PERM; 321 state->reverse_name_status = SMTPD_PEER_CODE_PERM; 322 } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name, 323 (MAI_SERVNAME_STR *) 0, 0)) != 0) { 324 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 325 state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); 326 state->name_status = (TEMP_AI_ERROR(aierr) ? 327 SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); 328 state->reverse_name_status = (TEMP_AI_ERROR(aierr) ? 329 SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); 330 } else { 331 struct addrinfo *res0; 332 struct addrinfo *res; 333 334 state->name = mystrdup(client_name.buf); 335 state->reverse_name = mystrdup(client_name.buf); 336 state->name_status = SMTPD_PEER_CODE_OK; 337 state->reverse_name_status = SMTPD_PEER_CODE_OK; 338 339 /* 340 * Reject the hostname if it does not list the peer address. Without 341 * further validation or qualification, such information must not be 342 * allowed to enter the audit trail, as people would draw false 343 * conclusions. 344 */ 345 aierr = hostname_to_sockaddr_pf(state->name, state->addr_family, 346 (char *) 0, 0, &res0); 347 if (aierr) { 348 msg_warn("hostname %s does not resolve to address %s: %s", 349 state->name, state->addr, MAI_STRERROR(aierr)); 350 REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ? 351 SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED)); 352 } else { 353 for (res = res0; /* void */ ; res = res->ai_next) { 354 if (res == 0) { 355 msg_warn("hostname %s does not resolve to address %s", 356 state->name, state->addr); 357 REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED); 358 break; 359 } 360 if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { 361 msg_info("skipping address family %d for host %s", 362 res->ai_family, state->name); 363 continue; 364 } 365 if (sock_addr_cmp_addr(res->ai_addr, sa) == 0) 366 break; /* keep peer name */ 367 } 368 freeaddrinfo(res0); 369 } 370 } 371 } 372 373 /* smtpd_peer_hostaddr_to_sockaddr - convert numeric string to binary */ 374 375 static void smtpd_peer_hostaddr_to_sockaddr(SMTPD_STATE *state) 376 { 377 const char *myname = "smtpd_peer_hostaddr_to_sockaddr"; 378 struct addrinfo *res; 379 int aierr; 380 381 if ((aierr = hostaddr_to_sockaddr(state->addr, state->port, 382 SOCK_STREAM, &res)) != 0) 383 msg_fatal("%s: cannot convert client address/port to string: %s", 384 myname, MAI_STRERROR(aierr)); 385 if (res->ai_addrlen > sizeof(state->sockaddr)) 386 msg_panic("%s: address length > struct sockaddr_storage", myname); 387 memcpy((void *) &(state->sockaddr), res->ai_addr, res->ai_addrlen); 388 state->sockaddr_len = res->ai_addrlen; 389 freeaddrinfo(res); 390 } 391 392 /* smtpd_peer_not_inet - non-socket or non-Internet endpoint */ 393 394 static void smtpd_peer_not_inet(SMTPD_STATE *state) 395 { 396 397 /* 398 * If it's not Internet, assume the client is local, and avoid using the 399 * naming service because that can hang when the machine is disconnected. 400 */ 401 state->name = mystrdup("localhost"); 402 state->reverse_name = mystrdup("localhost"); 403 #ifdef AF_INET6 404 if (proto_info->sa_family_list[0] == PF_INET6) { 405 state->addr = mystrdup("::1"); /* XXX bogus. */ 406 state->rfc_addr = mystrdup(IPV6_COL "::1"); /* XXX bogus. */ 407 } else 408 #endif 409 { 410 state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */ 411 state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */ 412 } 413 state->addr_family = AF_UNSPEC; 414 state->name_status = SMTPD_PEER_CODE_OK; 415 state->reverse_name_status = SMTPD_PEER_CODE_OK; 416 state->port = mystrdup("0"); /* XXX bogus. */ 417 } 418 419 /* smtpd_peer_no_client - peer went away, or peer info unavailable */ 420 421 static void smtpd_peer_no_client(SMTPD_STATE *state) 422 { 423 smtpd_peer_reset(state); 424 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 425 state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); 426 state->addr = mystrdup(CLIENT_ADDR_UNKNOWN); 427 state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN); 428 state->addr_family = AF_UNSPEC; 429 state->name_status = SMTPD_PEER_CODE_PERM; 430 state->reverse_name_status = SMTPD_PEER_CODE_PERM; 431 state->port = mystrdup(CLIENT_PORT_UNKNOWN); 432 } 433 434 /* smtpd_peer_from_pass_attr - initialize from attribute hash */ 435 436 static void smtpd_peer_from_pass_attr(SMTPD_STATE *state) 437 { 438 HTABLE *attr = (HTABLE *) vstream_context(state->client); 439 const char *cp; 440 441 /* 442 * Extract the client endpoint information from the attribute hash. 443 */ 444 if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_ADDR)) == 0) 445 msg_fatal("missing client address from proxy"); 446 if (strrchr(cp, ':') != 0) { 447 if (valid_ipv6_hostaddr(cp, DO_GRIPE) == 0) 448 msg_fatal("bad IPv6 client address syntax from proxy: %s", cp); 449 state->addr = mystrdup(cp); 450 state->rfc_addr = concatenate(IPV6_COL, cp, (char *) 0); 451 state->addr_family = AF_INET6; 452 } else { 453 if (valid_ipv4_hostaddr(cp, DO_GRIPE) == 0) 454 msg_fatal("bad IPv4 client address syntax from proxy: %s", cp); 455 state->addr = mystrdup(cp); 456 state->rfc_addr = mystrdup(cp); 457 state->addr_family = AF_INET; 458 } 459 if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_PORT)) == 0) 460 msg_fatal("missing client port from proxy"); 461 if (valid_hostport(cp, DO_GRIPE) == 0) 462 msg_fatal("bad TCP client port number syntax from proxy: %s", cp); 463 state->port = mystrdup(cp); 464 465 /* 466 * Avoid surprises in the Dovecot authentication server. 467 */ 468 if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_ADDR)) == 0) 469 msg_fatal("missing server address from proxy"); 470 if (valid_hostaddr(cp, DO_GRIPE) == 0) 471 msg_fatal("bad IPv6 client address syntax from proxy: %s", cp); 472 state->dest_addr = mystrdup(cp); 473 474 /* 475 * Convert the client address from string to binary form. 476 */ 477 smtpd_peer_hostaddr_to_sockaddr(state); 478 } 479 480 /* smtpd_peer_from_default - try to initialize peer information from socket */ 481 482 static void smtpd_peer_from_default(SMTPD_STATE *state) 483 { 484 SOCKADDR_SIZE sa_length = sizeof(state->sockaddr); 485 struct sockaddr *sa = (struct sockaddr *) &(state->sockaddr); 486 487 /* 488 * The "no client" routine provides surrogate information so that the 489 * application can produce sensible logging when a client disconnects 490 * before the server wakes up. The "not inet" routine provides surrogate 491 * state for (presumably) local IPC channels. 492 */ 493 if (getpeername(vstream_fileno(state->client), sa, &sa_length) < 0) { 494 if (errno == ENOTSOCK) 495 smtpd_peer_not_inet(state); 496 else 497 smtpd_peer_no_client(state); 498 } else { 499 state->sockaddr_len = sa_length; 500 if (smtpd_peer_sockaddr_to_hostaddr(state) < 0) 501 smtpd_peer_not_inet(state); 502 } 503 } 504 505 /* smtpd_peer_from_proxy - get endpoint info from proxy agent */ 506 507 static void smtpd_peer_from_proxy(SMTPD_STATE *state) 508 { 509 typedef struct { 510 const char *name; 511 int (*endpt_lookup) (SMTPD_STATE *); 512 } SMTPD_ENDPT_LOOKUP_INFO; 513 static const SMTPD_ENDPT_LOOKUP_INFO smtpd_endpt_lookup_info[] = { 514 HAPROXY_PROTO_NAME, smtpd_peer_from_haproxy, 515 0, 516 }; 517 const SMTPD_ENDPT_LOOKUP_INFO *pp; 518 519 /* 520 * When the proxy information is unavailable, we can't maintain an audit 521 * trail or enforce access control, therefore we forcibly hang up. 522 */ 523 for (pp = smtpd_endpt_lookup_info; /* see below */ ; pp++) { 524 if (pp->name == 0) 525 msg_fatal("unsupported %s value: %s", 526 VAR_SMTPD_UPROXY_PROTO, var_smtpd_uproxy_proto); 527 if (strcmp(var_smtpd_uproxy_proto, pp->name) == 0) 528 break; 529 } 530 if (pp->endpt_lookup(state) < 0) { 531 smtpd_peer_no_client(state); 532 state->flags |= SMTPD_FLAG_HANGUP; 533 } else { 534 smtpd_peer_hostaddr_to_sockaddr(state); 535 } 536 } 537 538 /* smtpd_peer_init - initialize peer information */ 539 540 void smtpd_peer_init(SMTPD_STATE *state) 541 { 542 543 /* 544 * Initialize. 545 */ 546 if (proto_info == 0) 547 proto_info = inet_proto_info(); 548 549 /* 550 * Prepare for partial initialization after error. 551 */ 552 memset((void *) &(state->sockaddr), 0, sizeof(state->sockaddr)); 553 state->sockaddr_len = 0; 554 state->name = 0; 555 state->reverse_name = 0; 556 state->addr = 0; 557 state->namaddr = 0; 558 state->rfc_addr = 0; 559 state->port = 0; 560 state->dest_addr = 0; 561 562 /* 563 * Determine the remote SMTP client address and port. 564 * 565 * XXX In stand-alone mode, don't assume that the peer will be a local 566 * process. That could introduce a gaping hole when the SMTP daemon is 567 * hooked up to the network via inetd or some other super-server. 568 */ 569 if (vstream_context(state->client) != 0) { 570 smtpd_peer_from_pass_attr(state); 571 if (*var_smtpd_uproxy_proto != 0) 572 msg_warn("ignoring non-empty %s setting behind postscreen", 573 VAR_SMTPD_UPROXY_PROTO); 574 } else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) { 575 smtpd_peer_from_default(state); 576 } else { 577 smtpd_peer_from_proxy(state); 578 } 579 580 /* 581 * Determine the remote SMTP client hostname. Note: some of the handlers 582 * above provide surrogate endpoint information in case of error. In that 583 * case, leave the surrogate information alone. 584 */ 585 if (state->name == 0) 586 smtpd_peer_sockaddr_to_hostname(state); 587 588 /* 589 * Do the name[addr]:port formatting for pretty reports. 590 */ 591 state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr, 592 state->port); 593 } 594 595 /* smtpd_peer_reset - destroy peer information */ 596 597 void smtpd_peer_reset(SMTPD_STATE *state) 598 { 599 if (state->name) 600 myfree(state->name); 601 if (state->reverse_name) 602 myfree(state->reverse_name); 603 if (state->addr) 604 myfree(state->addr); 605 if (state->namaddr) 606 myfree(state->namaddr); 607 if (state->rfc_addr) 608 myfree(state->rfc_addr); 609 if (state->port) 610 myfree(state->port); 611 if (state->dest_addr) 612 myfree(state->dest_addr); 613 } 614