1 /* $NetBSD: smtpd_peer.c,v 1.1.1.1 2009/06/23 10:08:56 tron 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 /* This module uses the local name service via getaddrinfo() 23 /* and getnameinfo(). It does not query the DNS directly. 24 /* 25 /* smtpd_peer_init() updates the following fields: 26 /* .IP name 27 /* The verified client hostname. This name is represented by 28 /* the string "unknown" when 1) the address->name lookup failed, 29 /* 2) the name->address mapping fails, or 3) the name->address 30 /* mapping does not produce the client IP address. 31 /* .IP reverse_name 32 /* The unverified client hostname as found with address->name 33 /* lookup; it is not verified for consistency with the client 34 /* IP address result from name->address lookup. 35 /* .IP forward_name 36 /* The unverified client hostname as found with address->name 37 /* lookup followed by name->address lookup; it is not verified 38 /* for consistency with the result from address->name lookup. 39 /* For example, when the address->name lookup produces as 40 /* hostname an alias, the name->address lookup will produce 41 /* as hostname the expansion of that alias, so that the two 42 /* lookups produce different names. 43 /* .IP addr 44 /* Printable representation of the client address. 45 /* .IP namaddr 46 /* String of the form: "name[addr]:port". 47 /* .IP rfc_addr 48 /* String of the form "ipv4addr" or "ipv6:ipv6addr" for use 49 /* in Received: message headers. 50 /* .IP name_status 51 /* The name_status result field specifies how the name 52 /* information should be interpreted: 53 /* .RS 54 /* .IP 2 55 /* The address->name lookup and name->address lookup produced 56 /* the client IP address. 57 /* .IP 4 58 /* The address->name lookup or name->address lookup failed 59 /* with a recoverable error. 60 /* .IP 5 61 /* The address->name lookup or name->address lookup failed 62 /* with an unrecoverable error, or the result did not match 63 /* the client IP address. 64 /* .RE 65 /* .IP reverse_name_status 66 /* The reverse_name_status result field specifies how the 67 /* reverse_name information should be interpreted: 68 /* .RS .IP 2 69 /* The address->name lookup succeeded. 70 /* .IP 4 71 /* The address->name lookup failed with a recoverable error. 72 /* .IP 5 73 /* The address->name lookup failed with an unrecoverable error. 74 /* .RE .IP forward_name_status 75 /* The forward_name_status result field specifies how the 76 /* forward_name information should be interpreted: 77 /* .RS .IP 2 78 /* The address->name and name->address lookup succeeded. 79 /* .IP 4 80 /* The address->name lookup or name->address failed with a 81 /* recoverable error. 82 /* .IP 5 83 /* The address->name lookup or name->address failed with an 84 /* unrecoverable error. 85 /* .RE 86 /* .PP 87 /* smtpd_peer_reset() releases memory allocated by smtpd_peer_init(). 88 /* LICENSE 89 /* .ad 90 /* .fi 91 /* The Secure Mailer license must be distributed with this software. 92 /* AUTHOR(S) 93 /* Wietse Venema 94 /* IBM T.J. Watson Research 95 /* P.O. Box 704 96 /* Yorktown Heights, NY 10598, USA 97 /*--*/ 98 99 /* System library. */ 100 101 #include <sys_defs.h> 102 #include <sys/socket.h> 103 #include <netinet/in.h> 104 #include <arpa/inet.h> 105 #include <stdio.h> /* strerror() */ 106 #include <errno.h> 107 #include <netdb.h> 108 #include <string.h> 109 110 /* Utility library. */ 111 112 #include <msg.h> 113 #include <mymalloc.h> 114 #include <stringops.h> 115 #include <myaddrinfo.h> 116 #include <sock_addr.h> 117 #include <inet_proto.h> 118 119 /* Global library. */ 120 121 #include <mail_proto.h> 122 #include <valid_mailhost_addr.h> 123 #include <mail_params.h> 124 125 /* Application-specific. */ 126 127 #include "smtpd.h" 128 129 /* smtpd_peer_init - initialize peer information */ 130 131 void smtpd_peer_init(SMTPD_STATE *state) 132 { 133 const char *myname = "smtpd_peer_init"; 134 SOCKADDR_SIZE sa_length; 135 struct sockaddr *sa; 136 INET_PROTO_INFO *proto_info = inet_proto_info(); 137 138 sa = (struct sockaddr *) & (state->sockaddr); 139 sa_length = sizeof(state->sockaddr); 140 141 /* 142 * Look up the peer address information. 143 * 144 * XXX If we make local endpoint (getsockname) information available to 145 * Milter applications as {if_name} and {if_addr}, then we also must be 146 * able to provide this via the XCLIENT command for Milter testing. 147 * 148 * XXX If we make local or remote port information available to policy 149 * servers or Milter applications, then we must also make this testable 150 * with the XCLIENT command, otherwise there will be confusion. 151 * 152 * XXX If we make local or remote port information available via logging, 153 * then we must also support these attributes with the XFORWARD command. 154 * 155 * XXX If support were to be added for Milter applications in down-stream 156 * MTAs, then consistency demands that we propagate a lot of Sendmail 157 * macro information via the XFORWARD command. Otherwise we could end up 158 * with a very confusing situation. 159 */ 160 if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) { 161 errno = 0; 162 } 163 164 /* 165 * If peer went away, give up. 166 */ 167 if (errno != 0 && errno != ENOTSOCK) { 168 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 169 state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); 170 state->addr = mystrdup(CLIENT_ADDR_UNKNOWN); 171 state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN); 172 state->addr_family = AF_UNSPEC; 173 state->name_status = SMTPD_PEER_CODE_PERM; 174 state->reverse_name_status = SMTPD_PEER_CODE_PERM; 175 state->port = mystrdup(CLIENT_PORT_UNKNOWN); 176 } 177 178 /* 179 * Convert the client address to printable address and hostname. 180 * 181 * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while 182 * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final 183 * else clause, pretend the origin is localhost[127.0.0.1], and become an 184 * open relay). 185 */ 186 else if (errno == 0 187 && (sa->sa_family == AF_INET 188 #ifdef AF_INET6 189 || sa->sa_family == AF_INET6 190 #endif 191 )) { 192 MAI_HOSTNAME_STR client_name; 193 MAI_HOSTADDR_STR client_addr; 194 MAI_SERVPORT_STR client_port; 195 int aierr; 196 char *colonp; 197 198 /* 199 * Sanity check: we can't use sockets that we're not configured for. 200 */ 201 if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0) 202 msg_fatal("cannot handle socket type %s with \"%s = %s\"", 203 #ifdef AF_INET6 204 sa->sa_family == AF_INET6 ? "AF_INET6" : 205 #endif 206 sa->sa_family == AF_INET ? "AF_INET" : 207 "other", VAR_INET_PROTOCOLS, var_inet_protocols); 208 209 /* 210 * Sorry, but there are some things that we just cannot do while 211 * connected to the network. 212 */ 213 if (geteuid() != var_owner_uid || getuid() != var_owner_uid) { 214 msg_error("incorrect SMTP server privileges: uid=%lu euid=%lu", 215 (unsigned long) getuid(), (unsigned long) geteuid()); 216 msg_fatal("the Postfix SMTP server must run with $%s privileges", 217 VAR_MAIL_OWNER); 218 } 219 220 /* 221 * Convert the client address to printable form. 222 */ 223 if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr, 224 &client_port, 0)) != 0) 225 msg_fatal("%s: cannot convert client address/port to string: %s", 226 myname, MAI_STRERROR(aierr)); 227 state->port = mystrdup(client_port.buf); 228 229 /* 230 * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on, 231 * but only if IPv4 support is enabled (why would anyone want to turn 232 * it off)? With IPv4 support enabled we have no need for the IPv6 233 * form in logging, hostname verification and access checks. 234 */ 235 #ifdef HAS_IPV6 236 if (sa->sa_family == AF_INET6) { 237 if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0 238 && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa)) 239 && (colonp = strrchr(client_addr.buf, ':')) != 0) { 240 struct addrinfo *res0; 241 242 if (msg_verbose > 1) 243 msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"", 244 myname, client_addr.buf, colonp + 1); 245 246 state->addr = mystrdup(colonp + 1); 247 state->rfc_addr = mystrdup(colonp + 1); 248 state->addr_family = AF_INET; 249 aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0); 250 if (aierr) 251 msg_fatal("%s: cannot convert %s from string to binary: %s", 252 myname, state->addr, MAI_STRERROR(aierr)); 253 sa_length = res0->ai_addrlen; 254 if (sa_length > sizeof(state->sockaddr)) 255 sa_length = sizeof(state->sockaddr); 256 memcpy((char *) sa, res0->ai_addr, sa_length); 257 freeaddrinfo(res0); /* 200412 */ 258 } 259 260 /* 261 * Following RFC 2821 section 4.1.3, an IPv6 address literal gets 262 * a prefix of 'IPv6:'. We do this consistently for all IPv6 263 * addresses that that appear in headers or envelopes. The fact 264 * that valid_mailhost_addr() enforces the form helps of course. 265 * We use the form without IPV6: prefix when doing access 266 * control, or when accessing the connection cache. 267 */ 268 else { 269 state->addr = mystrdup(client_addr.buf); 270 state->rfc_addr = 271 concatenate(IPV6_COL, client_addr.buf, (char *) 0); 272 state->addr_family = sa->sa_family; 273 } 274 } 275 276 /* 277 * An IPv4 address is in dotted quad decimal form. 278 */ 279 else 280 #endif 281 { 282 state->addr = mystrdup(client_addr.buf); 283 state->rfc_addr = mystrdup(client_addr.buf); 284 state->addr_family = sa->sa_family; 285 } 286 287 /* 288 * Look up and sanity check the client hostname. 289 * 290 * It is unsafe to allow numeric hostnames, especially because there 291 * exists pressure to turn off the name->addr double check. In that 292 * case an attacker could trivally bypass access restrictions. 293 * 294 * sockaddr_to_hostname() already rejects malformed or numeric names. 295 */ 296 #define TEMP_AI_ERROR(e) \ 297 ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM) 298 299 #define REJECT_PEER_NAME(state, code) { \ 300 myfree(state->name); \ 301 state->name = mystrdup(CLIENT_NAME_UNKNOWN); \ 302 state->name_status = code; \ 303 } 304 305 if (var_smtpd_peername_lookup == 0) { 306 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 307 state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); 308 state->name_status = SMTPD_PEER_CODE_PERM; 309 state->reverse_name_status = SMTPD_PEER_CODE_PERM; 310 } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name, 311 (MAI_SERVNAME_STR *) 0, 0)) != 0) { 312 state->name = mystrdup(CLIENT_NAME_UNKNOWN); 313 state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); 314 state->name_status = (TEMP_AI_ERROR(aierr) ? 315 SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); 316 state->reverse_name_status = (TEMP_AI_ERROR(aierr) ? 317 SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); 318 } else { 319 struct addrinfo *res0; 320 struct addrinfo *res; 321 322 state->name = mystrdup(client_name.buf); 323 state->reverse_name = mystrdup(client_name.buf); 324 state->name_status = SMTPD_PEER_CODE_OK; 325 state->reverse_name_status = SMTPD_PEER_CODE_OK; 326 327 /* 328 * Reject the hostname if it does not list the peer address. 329 * Without further validation or qualification, such information 330 * must not be allowed to enter the audit trail, as people would 331 * draw false conclusions. 332 */ 333 aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0); 334 if (aierr) { 335 msg_warn("%s: hostname %s verification failed: %s", 336 state->addr, state->name, MAI_STRERROR(aierr)); 337 REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ? 338 SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED)); 339 } else { 340 for (res = res0; /* void */ ; res = res->ai_next) { 341 if (res == 0) { 342 msg_warn("%s: address not listed for hostname %s", 343 state->addr, state->name); 344 REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED); 345 break; 346 } 347 if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { 348 msg_info("skipping address family %d for host %s", 349 res->ai_family, state->name); 350 continue; 351 } 352 if (sock_addr_cmp_addr(res->ai_addr, sa) == 0) 353 break; /* keep peer name */ 354 } 355 freeaddrinfo(res0); 356 } 357 } 358 } 359 360 /* 361 * If it's not Internet, assume the client is local, and avoid using the 362 * naming service because that can hang when the machine is disconnected. 363 */ 364 else { 365 state->name = mystrdup("localhost"); 366 state->reverse_name = mystrdup("localhost"); 367 state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */ 368 state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */ 369 state->addr_family = AF_UNSPEC; 370 state->name_status = SMTPD_PEER_CODE_OK; 371 state->reverse_name_status = SMTPD_PEER_CODE_OK; 372 state->port = mystrdup("0"); /* XXX bogus. */ 373 } 374 375 /* 376 * Do the name[addr]:port formatting for pretty reports. 377 */ 378 state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr, 379 state->port); 380 } 381 382 /* smtpd_peer_reset - destroy peer information */ 383 384 void smtpd_peer_reset(SMTPD_STATE *state) 385 { 386 myfree(state->name); 387 myfree(state->reverse_name); 388 myfree(state->addr); 389 myfree(state->namaddr); 390 myfree(state->rfc_addr); 391 myfree(state->port); 392 } 393