#include <sys_defs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
#include <myaddrinfo.h>
#include <sock_addr.h>
#include <inet_proto.h>
#include <split_at.h>
#include <mail_proto.h>
#include <valid_mailhost_addr.h>
#include <mail_params.h>
#include "qmqpd.h"
void qmqpd_peer_init(QMQPD_STATE *state)
{
const char *myname = "qmqpd_peer_init";
struct sockaddr_storage ss;
struct sockaddr *sa;
SOCKADDR_SIZE sa_length;
INET_PROTO_INFO *proto_info = inet_proto_info();
sa = (struct sockaddr *) & ss;
sa_length = sizeof(ss);
if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
errno = 0;
}
if (errno != 0 && errno != ENOTSOCK) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->addr_family = AF_UNSPEC;
state->port = mystrdup(CLIENT_PORT_UNKNOWN);
}
else if (errno == 0
&& (sa->sa_family == AF_INET
#ifdef AF_INET6
|| sa->sa_family == AF_INET6
#endif
)) {
MAI_HOSTNAME_STR client_name;
MAI_HOSTADDR_STR client_addr;
MAI_SERVPORT_STR client_port;
int aierr;
char *colonp;
if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
msg_fatal("cannot handle socket type %s with \"%s = %s\"",
#ifdef AF_INET6
sa->sa_family == AF_INET6 ? "AF_INET6" :
#endif
sa->sa_family == AF_INET ? "AF_INET" :
"other", VAR_INET_PROTOCOLS, var_inet_protocols);
if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
msg_error("incorrect QMQP server privileges: uid=%lu euid=%lu",
(unsigned long) getuid(), (unsigned long) geteuid());
msg_fatal("the Postfix QMQP server must run with $%s privileges",
VAR_MAIL_OWNER);
}
if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
&client_port, 0)) != 0)
msg_fatal("%s: cannot convert client address/port to string: %s",
myname, MAI_STRERROR(aierr));
state->port = mystrdup(client_port.buf);
#ifdef HAS_IPV6
(void) split_at(client_addr.buf, '%');
#endif
#ifdef HAS_IPV6
if (sa->sa_family == AF_INET6) {
if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
&& IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
&& (colonp = strrchr(client_addr.buf, ':')) != 0) {
struct addrinfo *res0;
if (msg_verbose > 1)
msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
myname, client_addr.buf, colonp + 1);
state->addr = mystrdup(colonp + 1);
state->rfc_addr = mystrdup(colonp + 1);
state->addr_family = AF_INET;
aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
if (aierr)
msg_fatal("%s: cannot convert %s from string to binary: %s",
myname, state->addr, MAI_STRERROR(aierr));
sa_length = res0->ai_addrlen;
if (sa_length > sizeof(ss))
sa_length = sizeof(ss);
memcpy((char *) sa, res0->ai_addr, sa_length);
freeaddrinfo(res0);
}
else {
state->addr = mystrdup(client_addr.buf);
state->rfc_addr =
concatenate(IPV6_COL, client_addr.buf, (char *) 0);
state->addr_family = sa->sa_family;
}
}
else
#endif
{
state->addr = mystrdup(client_addr.buf);
state->rfc_addr = mystrdup(client_addr.buf);
state->addr_family = sa->sa_family;
}
#define REJECT_PEER_NAME(state) { \
myfree(state->name); \
state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
}
if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
(MAI_SERVNAME_STR *) 0, 0)) != 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
} else {
struct addrinfo *res0;
struct addrinfo *res;
state->name = mystrdup(client_name.buf);
aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
(char *) 0, 0, &res0);
if (aierr) {
msg_warn("hostname %s does not resolve to address %s: %s",
state->name, state->addr, MAI_STRERROR(aierr));
REJECT_PEER_NAME(state);
} else {
for (res = res0; ; res = res->ai_next) {
if (res == 0) {
msg_warn("hostname %s does not resolve to address %s",
state->addr, state->name);
REJECT_PEER_NAME(state);
break;
}
if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
msg_info("skipping address family %d for host %s",
res->ai_family, state->name);
continue;
}
if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
break;
}
freeaddrinfo(res0);
}
}
}
else {
state->name = mystrdup("localhost");
state->addr = mystrdup("127.0.0.1");
state->rfc_addr = mystrdup("127.0.0.1");
state->addr_family = AF_UNSPEC;
state->port = mystrdup("0");
}
state->namaddr =
concatenate(state->name, "[", state->addr, "]",
var_qmqpd_client_port_log ? ":" : (char *) 0,
state->port, (char *) 0);
}
void qmqpd_peer_reset(QMQPD_STATE *state)
{
myfree(state->name);
myfree(state->addr);
myfree(state->namaddr);
myfree(state->rfc_addr);
myfree(state->port);
}