diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clamsmtpd.c | 111 | ||||
-rw-r--r-- | src/sock_any.c | 52 | ||||
-rw-r--r-- | src/sock_any.h | 22 | ||||
-rw-r--r-- | src/util.c | 7 |
4 files changed, 140 insertions, 52 deletions
diff --git a/src/clamsmtpd.c b/src/clamsmtpd.c index b93b636..d32248a 100644 --- a/src/clamsmtpd.c +++ b/src/clamsmtpd.c @@ -113,14 +113,12 @@ clamsmtp_thread_t; * Default Settings */ -#define DEFAULT_SOCKET "0.0.0.0:10025" -#define DEFAULT_PORT 10025 +#define DEFAULT_SOCKET "10025" #define DEFAULT_CLAMAV "/var/run/clamav/clamd" #define DEFAULT_MAXTHREADS 64 #define DEFAULT_TIMEOUT 180 #define DEFAULT_HEADER "X-AV-Checked: ClamAV using ClamSMTP\r\n" - /* ----------------------------------------------------------------------- * Globals */ @@ -265,11 +263,11 @@ int main(int argc, char* argv[]) messagex(NULL, LOG_DEBUG, "starting up..."); /* Parse all the addresses */ - if(sock_any_pton(listensock, &addr, DEFAULT_PORT) == -1) + if(sock_any_pton(listensock, &addr, SANY_OPT_DEFANY) == -1) errx(1, "invalid listen socket name or ip: %s", listensock); - if(sock_any_pton(g_outname, &g_outaddr, 25) == -1) + if(sock_any_pton(g_outname, &g_outaddr, SANY_OPT_DEFPORT(25)) == -1) errx(1, "invalid connect socket name or ip: %s", g_outname); - if(sock_any_pton(g_clamname, &g_clamaddr, 0) == -1) + if(sock_any_pton(g_clamname, &g_clamaddr, SANY_OPT_DEFLOCAL) == -1) errx(1, "invalid clam socket name: %s", g_clamname); if(daemonize) @@ -492,10 +490,12 @@ static void pid_file(const char* pidfile, int write) static void* thread_main(void* arg) { clamsmtp_thread_t* thread = (clamsmtp_thread_t*)arg; - char peername[MAXPATHLEN]; struct sockaddr_any addr; + struct sockaddr_any* outaddr; + const char* outname; + char buf[MAXPATHLEN]; clamsmtp_context_t ctx; - int r; + int ret = 0; ASSERT(thread); @@ -504,43 +504,88 @@ static void* thread_main(void* arg) memset(&ctx, 0, sizeof(ctx)); - plock(); - ctx.client = thread->fd; - punlock(); + /* Assign a unique id to the connection */ + ctx.id = g_unique_id++; ctx.server = -1; ctx.clam = -1; - ASSERT(ctx.client != -1); + plock(); + ctx.client = thread->fd; + punlock(); - /* Assign a unique id to the connection */ - ctx.id = g_unique_id++; + ASSERT(ctx.client != -1); memset(&addr, 0, sizeof(addr)); SANY_LEN(addr) = sizeof(addr); /* Get the peer name */ if(getpeername(ctx.client, &SANY_ADDR(addr), &SANY_LEN(addr)) == -1 || - sock_any_ntop(&addr, peername, MAXPATHLEN) == -1) + sock_any_ntop(&addr, buf, MAXPATHLEN, SANY_OPT_NOPORT) == -1) message(&ctx, LOG_WARNING, "couldn't get peer address"); else - messagex(&ctx, LOG_INFO, "accepted connection from: %s", peername); + messagex(&ctx, LOG_INFO, "accepted connection from: %s", buf); + + + /* Create the server connection address */ + outaddr = &g_outaddr; + outname = g_outname; + + if(SANY_TYPE(*outaddr) == AF_INET && + outaddr->s.in.sin_addr.s_addr == 0) + { + /* Use the incoming IP as the default */ + in_addr_t in = addr.s.in.sin_addr.s_addr; + memcpy(&addr, &g_outaddr, sizeof(addr)); + addr.s.in.sin_addr.s_addr = in; + + outaddr = &addr; + + if(sock_any_ntop(outaddr, buf, MAXPATHLEN, 0) != -1) + outname = buf; + } + + + /* Connect to the server */ + if((ctx.server = socket(SANY_TYPE(*outaddr), SOCK_STREAM, 0)) < 0 || + connect(ctx.server, &SANY_ADDR(*outaddr), SANY_LEN(*outaddr)) < 0) + { + message(&ctx, LOG_ERR, "couldn't connect to %s", outname); + RETURN(-1); + } + + messagex(&ctx, LOG_DEBUG, "connected to server: %s", outname); + + + if(connect_clam(&ctx) == -1) + RETURN(-1); + /* call the processor */ - r = smtp_passthru(&ctx); + ret = smtp_passthru(&ctx); + +cleanup: + + disconnect_clam(&ctx); - /* Close the incoming connection if neccessary */ if(ctx.client != -1) + { shutdown(ctx.client, SHUT_RDWR); + messagex(&ctx, LOG_NOTICE, "closed client connection"); + } - messagex(&ctx, LOG_NOTICE, "closed client connection"); + if(ctx.server != -1) + { + shutdown(ctx.server, SHUT_RDWR); + messagex(&ctx, LOG_DEBUG, "closed server connection"); + } /* mark this as done */ plock(); thread->fd = -1; punlock(); - return (void*)(r == 0 ? 0 : 1); + return (void*)(ret == 0 ? 0 : 1); } static int smtp_passthru(clamsmtp_context_t* ctx) @@ -550,19 +595,7 @@ static int smtp_passthru(clamsmtp_context_t* ctx) int r, ret = 0; fd_set mask; - ASSERT(ctx->server == -1); - - if((ctx->server = socket(SANY_TYPE(g_outaddr), SOCK_STREAM, 0)) < 0 || - connect(ctx->server, &SANY_ADDR(g_outaddr), SANY_LEN(g_outaddr)) < 0) - { - message(ctx, LOG_ERR, "couldn't connect to %s", g_outname); - RETURN(-1); - } - - messagex(ctx, LOG_DEBUG, "connected to server: %s", g_outname); - - if(connect_clam(ctx) == -1) - RETURN(-1); + ASSERT(ctx->clam != -1 && ctx->server != -1); /* This changes the error code sent to the client when an * error occurs. See cleanup below */ @@ -683,20 +716,12 @@ static int smtp_passthru(clamsmtp_context_t* ctx) cleanup: - disconnect_clam(ctx); - if(ret == -1 && ctx->client != -1) { write_data(ctx, &(ctx->client), processing ? SMTP_FAILED : SMTP_STARTFAILED); } - if(ctx->server != -1) - { - shutdown(ctx->server, SHUT_RDWR); - messagex(ctx, LOG_DEBUG, "closed server connection"); - } - return ret; } @@ -771,7 +796,7 @@ cleanup: if(ctx->clam != -1) { shutdown(ctx->clam, SHUT_RDWR); - ctx->clam == -1; + ctx->clam = -1; } } @@ -786,8 +811,8 @@ static int disconnect_clam(clamsmtp_context_t* ctx) if(write_data(ctx, &(ctx->clam), CLAM_DISCONNECT) != -1) read_junk(ctx, ctx->clam); - messagex(ctx, LOG_DEBUG, "disconnected from clamd"); shutdown(ctx->clam, SHUT_RDWR); + messagex(ctx, LOG_DEBUG, "disconnected from clamd"); ctx->clam = -1; return 0; } diff --git a/src/sock_any.c b/src/sock_any.c index 49e0390..0018318 100644 --- a/src/sock_any.c +++ b/src/sock_any.c @@ -47,12 +47,15 @@ #include <arpa/inet.h> -int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) +#define LOCALHOST_ADDR 0x7F000001 + +int sock_any_pton(const char* addr, struct sockaddr_any* any, int opts) { size_t l; char buf[256]; char* t; char* t2; + int defport = (opts & 0xFFFF); memset(any, 0, sizeof(*any)); @@ -69,13 +72,35 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) if(l < PORT_MIN || l > PORT_MAX || addr[l] != 0) break; - port = strtol(t, &t2, 10); + port = strtol(addr, &t2, 10); if(*t2 || port <= 0 || port >= 65536) break; - any->s.in.sin_family = AF_INET; - any->s.in.sin_port = htons((unsigned short)(port <= 0 ? defport : port)); - any->s.in.sin_addr.s_addr = 0; + any->s.in.sin_port = htons(port); + + /* Fill in the type based on defaults */ +#ifdef HAVE_INET6 + if(opts & SANY_OPT_DEFINET6) + any->s.in.sin_family = AF_INET6; + else +#endif + any->s.in.sin_family = AF_INET; + + /* Fill in the address based on defaults */ + if(opts & SANY_OPT_DEFLOCAL) + { +#ifdef HAVE_INET6 + if(opts & SANY_OPT_DEFINET6) + memcpy(&(any->s.in.sin6_addr), &in6addr_loopback, sizeof(struct in6_addr)); + else +#endif + any->s.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + /* + * Note the 'any' option is the default since we zero out + * the entire structure above. + */ any->namelen = sizeof(any->s.in); return AF_INET; @@ -274,9 +299,10 @@ int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport) return -1; } -int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen) +int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen, int opts) { int len = 0; + int port = 0; switch(any->s.a.sa_family) { @@ -294,12 +320,14 @@ int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen) case AF_INET: if(inet_ntop(any->s.a.sa_family, &(any->s.in.sin_addr), addr, addrlen) == NULL) return -1; + port = ntohs(any->s.in.sin_port); break; #ifdef HAVE_INET6 case AF_INET6: if(inet_ntop(any->s.a.sa_family, &(any->s.in6.sin6_addr), addr, addrlen) == NULL) return -1; + port = ntohs(any->s.in6.sin6_port); break; #endif @@ -308,5 +336,17 @@ int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen) return -1; } + if(!(opts & SANY_OPT_NOPORT) && port != 0) + { + strncat(addr, ":", addrlen); + addr[addrlen - 1] = 0; + + len = strlen(addr); + addr += len; + addrlen -= len; + + snprintf(addr, addrlen, "%d", port); + } + return 0; } diff --git a/src/sock_any.h b/src/sock_any.h index 924bf09..0b492b4 100644 --- a/src/sock_any.h +++ b/src/sock_any.h @@ -64,7 +64,25 @@ struct sockaddr_any #define SANY_LEN(any) ((any).namelen) #define SANY_TYPE(any) ((any).s.a.sa_family) -int sock_any_pton(const char* addr, struct sockaddr_any* any, int defport); -int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen); +int sock_any_pton(const char* addr, struct sockaddr_any* any, int opts); + +/* The default port to fill in when no IP/IPv6 port specified */ +#define SANY_OPT_DEFPORT(p) (int)((p) & 0xFFFF) + +/* When only port specified default to IPANY */ +#define SANY_OPT_DEFANY 0x00000000 + +/* When only port specified default to LOCALHOST */ +#define SANY_OPT_DEFLOCAL 0x00100000 + +/* When only port specified default to IPv6 */ +#ifdef HAVE_INET6 +#define SANY_OPT_DEFINET6 0x00200000 +#endif + +int sock_any_ntop(struct sockaddr_any* any, char* addr, size_t addrlen, int opts); + +/* Don't print the port */ +#define SANY_OPT_NOPORT 0x01000000 #endif /* __SOCK_ANY_H__ */ @@ -62,6 +62,7 @@ static void vmessage(clamsmtp_context_t* ctx, int level, int err, size_t len; char* m; int e = errno; + int x; if(g_daemonized) { @@ -87,7 +88,11 @@ static void vmessage(clamsmtp_context_t* ctx, int level, int err, snprintf(m, len, "%s%s", msg, err ? ": " : ""); if(err) - strerror_r(e, m + strlen(m), MAX_MSGLEN); + { + /* TODO: strerror_r doesn't want to work for us + strerror(e, m + strlen(m), MAX_MSGLEN); */ + strncat(m, strerror(e), len); + } m[len - 1] = 0; msg = m; |