#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>
#ifdef NO_HERRNO
static int h_errno = TRY_AGAIN;
#define HSTRERROR(err) "Host not found"
#else
#define HSTRERROR(err) (\
err == TRY_AGAIN ? "Host not found, try again" : \
err == HOST_NOT_FOUND ? "Host not found" : \
err == NO_DATA ? "Host name has no address" : \
err == NO_RECOVERY ? "Name server failure" : \
strerror(errno) \
)
#endif
#include <msg.h>
#include <mymalloc.h>
#include <valid_hostname.h>
#include <stringops.h>
#include <mail_proto.h>
#include "smtpd.h"
void smtpd_peer_init(SMTPD_STATE *state)
{
struct sockaddr_in sin;
SOCKADDR_SIZE len = sizeof(sin);
struct hostent *hp;
int i;
memset((char *) &sin, 0, len);
if (getpeername(vstream_fileno(state->client),
(struct sockaddr *) & sin, &len) >= 0) {
errno = 0;
}
if (errno == ECONNRESET || errno == ECONNABORTED) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->peer_code = SMTPD_PEER_CODE_PERM;
}
else if (errno == 0 && sin.sin_family == AF_INET) {
state->addr = mystrdup(inet_ntoa(sin.sin_addr));
hp = gethostbyaddr((char *) &(sin.sin_addr),
sizeof(sin.sin_addr), AF_INET);
if (hp == 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->peer_code = (h_errno == TRY_AGAIN ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
} else if (valid_hostaddr(hp->h_name, DONT_GRIPE)) {
msg_warn("numeric result %s in address->name lookup for %s",
hp->h_name, state->addr);
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->peer_code = SMTPD_PEER_CODE_PERM;
} else if (!valid_hostname(hp->h_name, DONT_GRIPE)) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->peer_code = SMTPD_PEER_CODE_PERM;
} else {
state->name = mystrdup(hp->h_name);
state->peer_code = SMTPD_PEER_CODE_OK;
#define REJECT_PEER_NAME(state, code) { \
myfree(state->name); \
state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
state->peer_code = code; \
}
hp = gethostbyname(state->name);
if (hp == 0) {
msg_warn("%s: hostname %s verification failed: %s",
state->addr, state->name, HSTRERROR(h_errno));
REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM));
} else if (hp->h_length != sizeof(sin.sin_addr)) {
msg_warn("%s: hostname %s verification failed: bad address size %d",
state->addr, state->name, hp->h_length);
REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM);
} else {
for (i = 0; ; i++) {
if (hp->h_addr_list[i] == 0) {
msg_warn("%s: address not listed for hostname %s",
state->addr, state->name);
REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM);
break;
}
if (memcmp(hp->h_addr_list[i],
(char *) &sin.sin_addr,
sizeof(sin.sin_addr)) == 0)
break;
}
}
}
}
else {
state->name = mystrdup("localhost");
state->addr = mystrdup("127.0.0.1");
state->peer_code = SMTPD_PEER_CODE_OK;
}
state->namaddr =
concatenate(state->name, "[", state->addr, "]", (char *) 0);
}
void smtpd_peer_reset(SMTPD_STATE *state)
{
myfree(state->name);
myfree(state->addr);
myfree(state->namaddr);
}