free(c->rdata.s);
bzero(&c->rdata, sizeof(c->rdata));
}
- module_resetconn(c);
+ module_close(c);
if (pthread_mutex_lock(&cp.cpmtx)) assert(0);
cp.count --;
STAILQ_INSERT_HEAD(&cp.c_pool, c, c_list);
struct sockaddr_in addr;
int addrlen, fd;
struct linger l = {1,0};
+ int ret;
struct conn *c;
c->peer = addr;
c->fd = fd;
io_initconn(c);
- module_initconn(c);
- greeting(c);
- c->state = SMTP_GREET;
+ ret = module_connect(c);
+ if (SSM_ACCEPTED(ret))
+ c->state = SMTP_GREET;
+ else
+ c->state = SMTP_CLOSED;
+
+ if (!SSM_RESPONDED(ret)) {
+ if (SSM_ACCEPTED(ret)) greeting(c);
+ else respond(c, "421 connection rejected\r\n");
+ }
if (c->wdata.s) {
c->event = EV_WRITE;
} else {
if (!mod)
errx(1, "module %s invalid: %s\n", file, dlerror());
- mod->mod_index = nmod;
- mod->module_init(t);
+ mod->ssm_module_index = nmod;
+ if (mod->ssm_module_init) mod->ssm_module_init(t);
modlist = realloc(modlist, nmod + 1);
if (!modlist)
}
void
-module_hup(void)
+module_reload(void)
{
int i;
for (i = 0; i < nmod; i++)
- if (modlist[i]->module_hup)
- modlist[i]->module_hup();
+ if (modlist[i]->ssm_module_reload)
+ modlist[i]->ssm_module_reload();
}
-void
-module_initconn(struct conn *c)
-{
+
+int
+module_connect(struct conn *c) {
+ int i, ret;
if (!c->priv_data) {
c->priv_data = calloc(1, nmod * sizeof(void *));
+ if (!c->priv_data) {
+ respond(c, "451 out of memory\r\n");
+ return SSM_REJECT;
+ }
+
+ }
+ for (i = 0; i < nmod; i++) {
+ if (modlist[i]->ssm_connect) {
+ ret = modlist[i]->ssm_connect(c);
+ if ((ret & 0x0F) != SSM_PASS) return ret;
+ }
}
+ return SSM_ACCEPT;
}
-void
-module_resetconn(struct conn *c)
-{
- int i;
- for (i = 0; i < nmod; i++)
- if (modlist[i]->reset_cdata)
- modlist[i]->reset_cdata(c);
-}
int
module_helo(struct conn *c, char *cmd, int len, int argoff)
{
int i, ret;
for (i = 0; i < nmod; i++) {
- if (modlist[i]->hook_helo) {
- ret = modlist[i]->hook_helo(c,cmd,len,argoff);
+ if (modlist[i]->ssm_helo) {
+ ret = modlist[i]->ssm_helo(c,cmd,len,argoff);
if ((ret & 0x0F) != SSM_PASS) return ret;
}
}
{
int i, ret;
for (i = 0; i < nmod; i++) {
- if (modlist[i]->hook_mail) {
- ret = modlist[i]->hook_mail(c,cmd,len,argoff);
+ if (modlist[i]->ssm_mail) {
+ ret = modlist[i]->ssm_mail(c,cmd,len,argoff);
if ((ret & 0x0F) != SSM_PASS) return ret;
}
}
{
int i, ret;
for (i = 0; i < nmod; i++) {
- if (modlist[i]->hook_rcpt) {
- ret = modlist[i]->hook_rcpt(c,cmd,len,argoff);
+ if (modlist[i]->ssm_rcpt) {
+ ret = modlist[i]->ssm_rcpt(c,cmd,len,argoff);
+ if ((ret & 0x0F) != SSM_PASS) return ret;
+ }
+ }
+ return SSM_ACCEPT;
+}
+
+int
+module_data(struct conn *c, char *cmd, int len, int argoff)
+{
+ int i, ret;
+ for (i = 0; i < nmod; i++) {
+ if (modlist[i]->ssm_enddata) {
+ ret = modlist[i]->ssm_data(c, cmd, len, argoff);
if ((ret & 0x0F) != SSM_PASS) return ret;
}
}
}
void
-module_data(struct conn *c, char *data, int len)
+module_body(struct conn *c, char *data, int len)
{
int i;
for (i = 0; i < nmod; i++) {
- if (modlist[i]->hook_enddata) {
- modlist[i]->hook_data(c, data, len);
+ if (modlist[i]->ssm_body) {
+ modlist[i]->ssm_body(c, data, len);
}
}
}
+
int
module_enddata(struct conn *c)
{
int i, ret;
for (i = 0; i < nmod; i++) {
- if (modlist[i]->hook_enddata) {
- ret = modlist[i]->hook_enddata(c);
+ if (modlist[i]->ssm_enddata) {
+ ret = modlist[i]->ssm_enddata(c);
if ((ret & 0x0F) != SSM_PASS) return ret;
}
}
return SSM_ACCEPT;
}
+void
+module_abort(struct conn *c)
+{
+ int i;
+ for (i = 0; i < nmod; i++)
+ if (modlist[i]->ssm_abort)
+ modlist[i]->ssm_abort(c);
+}
+
+void
+module_close(struct conn *c)
+{
+ int i;
+ for (i = 0; i < nmod; i++)
+ if (modlist[i]->ssm_close)
+ modlist[i]->ssm_close(c);
+}
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
ssm_getpriv(struct smtpsink_module *m, struct conn *c)
{
assert(c->priv_data);
- return c->priv_data[m->mod_index];
+ return c->priv_data[m->ssm_module_index];
}
void
ssm_setpriv(struct smtpsink_module *m, struct conn *c, void *data)
{
assert(c->priv_data);
- c->priv_data[m->mod_index] = data;
+ c->priv_data[m->ssm_module_index] = data;
}
/* DATA command */
static char *data_ok = "354 go ahead\r\n";
+static char *data_reject = "554 data command rejected\r\n";
/* End of DATA (timestamp, random integer) */
static char *enddata_ok = "250 ok %d qp %d\r\n";
smtpd_rcpt(struct conn *c, char *cmd, int len, int argoff)
{
int ret;
- if (c->state == SMTP_MAIL || c->state == SMTP_RCPT) {
- ret = module_rcpt(c, cmd, len, argoff);
+ char *resp = rcpt_ok;
+ if (c->state != SMTP_MAIL && c->state != SMTP_RCPT)
+ return respond(c, err_wantmail);
+
+ ret = module_rcpt(c, cmd, len, argoff);
+ if (SSM_ACCEPTED(ret))
c->state = SMTP_RCPT;
- return respond(c, rcpt_ok);
+ else
+ resp = rcpt_reject;
+
+ if (SSM_RESPONDED(ret)) {
+ if (c->wdata.s) return 0;
+ return 1;
}
- return respond(c, err_wantmail);
+ return respond(c, resp);
}
static int
smtpd_data(struct conn *c, char *cmd, int len, int argoff)
{
+ int ret;
+ char *resp = data_ok;
if (c->state != SMTP_RCPT)
return respond(c, err_wantrcpt);
- c->state = SMTP_DATA;
- c->dstate = 2;
- return respond(c, data_ok);
+ ret = module_data(c, cmd, len, argoff);
+ if (SSM_ACCEPTED(ret)) {
+ c->state = SMTP_DATA;
+ c->dstate = 2;
+ } else
+ resp = data_reject;
+
+ if (SSM_RESPONDED(ret)) {
+ if (c->wdata.s) return 0;
+ return 1;
+ }
+ return respond(c, resp);
}
static int
smtpd_rset(struct conn *c, char *cmd, int len, int argoff)
{
c->state = SMTP_RSET;
+ module_abort(c);
return respond(c, rset_ok);
}
}
break;
}
- module_data(c, *buf, s - *buf);
+ module_body(c, *buf, s - *buf);
*len -= s - *buf;
*buf = s;
if (c->dstate == 5) return smtpd_enddata(c);
/* module hooks */
extern void module_init(char *);
-extern void module_hup(void);
-extern void module_initconn(struct conn *);
-extern void module_resetconn(struct conn *);
+extern void module_reload(void);
+extern int module_connect(struct conn *);
extern int module_helo(struct conn *, char *, int, int);
extern int module_mail(struct conn *, char *, int, int);
extern int module_rcpt(struct conn *, char *, int, int);
-extern void module_data(struct conn *, char *, int);
+extern int module_data(struct conn *, char *, int, int);
+extern void module_body(struct conn *, char *, int);
extern int module_enddata(struct conn *);
+extern void module_abort(struct conn *);
+extern void module_close(struct conn *);
exit(0);
}
+static void
+sigev_reload(int fd, short event, void *arg)
+{
+ module_reload();
+}
+
static void *
sigloop(void *data)
{
struct event_base *base = (struct event_base *)data;
- struct event sigterm, sigint;
+ struct event sigterm, sigint, sighup;
signal_set(&sigint, SIGINT, sigev_exit, 0);
event_base_set(base, &sigint);
signal_set(&sigterm, SIGTERM, sigev_exit, 0);
event_base_set(base, &sigint);
+ signal_set(&sighup, SIGHUP, sigev_reload, 0);
+ event_base_set(base, &sighup);
signal_add(&sigint, 0);
signal_add(&sigterm, 0);
+ signal_add(&sighup, 0);
event_base_dispatch(base);
return (void *)base;
}
#define SSM_RESPONDED(x) (x & 0x100)
struct smtpsink_module {
- void (*module_init)(char *);
- void (*module_hup)(void);
+ unsigned ssm_module_index;
- /* manage connection private data */
- void (*reset_cdata)(struct conn *);
+ void (*ssm_module_init)(char *);
+ void (*ssm_module_reload)(void);
- /* smtp command hooks */
- int (*hook_helo)(struct conn *, char *, int, int);
- int (*hook_mail)(struct conn *, char *, int, int);
- int (*hook_rcpt)(struct conn *, char *, int, int);
-
- /* data processing hooks */
- void (*hook_data)(struct conn *, char *, int);
- int (*hook_enddata)(struct conn *);
-
- /* module index (filled in by module_init) */
- unsigned mod_index;
+ int (*ssm_connect)(struct conn *);
+ int (*ssm_helo)(struct conn *, char *, int, int);
+ int (*ssm_mail)(struct conn *, char *, int, int);
+ int (*ssm_rcpt)(struct conn *, char *, int, int);
+ int (*ssm_data)(struct conn *, char *, int, int);
+ void (*ssm_body)(struct conn *, char *, int);
+ int (*ssm_enddata)(struct conn *);
+ void (*ssm_abort)(struct conn *);
+ void (*ssm_close)(struct conn *);
};
void *ssm_getpriv(struct smtpsink_module *, struct conn *);