From: chris mikkelson Date: Fri, 27 Mar 2009 01:59:50 +0000 (-0500) Subject: First cut at module loading system. Still need to make a usable X-Git-Url: https://git.mikk.net/?a=commitdiff_plain;h=40e8fb2936e70d9d059ab764f1839556bd3ac4d3;p=smtpsink First cut at module loading system. Still need to make a usable API for module developers. (get/set private data, respond, etc.) --- diff --git a/Makefile b/Makefile index d7e6048..3bccc70 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-g -Wall -I/usr/local/include -SMTPSINK_OBJS=conn_pool.o conn_queue.o io.o smtp.o smtpsink.o +SMTPSINK_OBJS=conn_pool.o conn_queue.o io.o smtp.o module.o smtpsink.o default: smtpsink @@ -19,6 +19,9 @@ io.o: io.c smtpsink.h conn_queue.h smtpsink-int.h smtp.o: smtp.c smtpsink.h conn_queue.h smtpsink-int.h responses.inc cc $(CFLAGS) -c smtp.c +module.o: module.c smtpsink.h + cc $(CFLAGS) -c module.c + smtpsink.o: smtpsink.c smtpsink.h conn_queue.h smtpsink-int.h clean: diff --git a/conn_pool.c b/conn_pool.c index 3a44436..824f022 100644 --- a/conn_pool.c +++ b/conn_pool.c @@ -120,6 +120,7 @@ listener_loop(void *data) c->peer = addr; c->fd = fd; io_initconn(c); + module_initconn(c); greeting(c); c->state = SMTP_GREET; if (c->wdata.s) { diff --git a/module.c b/module.c new file mode 100644 index 0000000..d7d3b1b --- /dev/null +++ b/module.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include + +#include +#include +#include +#include "smtpsink.h" + +static int nmod = 0; +static struct smtpsink_module **modlist = 0; + +/* modulespec is a string formatted as: + + "/path/to/module,options" + + parsing of "options" is module dependent +*/ +void +module_init(char *modulespec) +{ + char modpath[1024]; + char *file, *t; + struct smtpsink_module *mod; + void *dlmod; + + t = strchr(modulespec, ','); + if (!t) file = modulespec; + else { + if (t-modulespec - 1 > sizeof(modpath)) + errx(1, "module path too long: %s\n", modulespec); + strncpy(modpath, modulespec, t - modulespec); + file = modpath; + t++; + } + + dlmod = dlopen(file, RTLD_NOW); + if (!dlmod) + errx(1, "could not load %s: %s\n", file, dlerror()); + + mod = (void *)dlsym(dlmod, "ss_module"); + if (!mod) + errx(1, "module %s invalid: %s\n", file, dlerror()); + + mod->mod_index = nmod; + mod->module_init(t); + + modlist = realloc(modlist, nmod + 1); + if (!modlist) + errx(1, "out of memory\n"); + + modlist[nmod++] = mod; +} + +void +module_hup(void) +{ + int i; + for (i = 0; i < nmod; i++) + if (modlist[i]->module_hup) + modlist[i]->module_hup(); +} + +void +module_initconn(struct conn *c) +{ + if (!c->priv_data) { + c->priv_data = calloc(1, nmod * sizeof(void *)); + } +} + +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 ((ret & 0x0F) != SSM_PASS) return ret; + } + } + return SSM_ACCEPT; +} + + +int +module_mail(struct conn *c, char *cmd, int len, int argoff) +{ + int i, ret; + for (i = 0; i < nmod; i++) { + if (modlist[i]->hook_mail) { + ret = modlist[i]->hook_mail(c,cmd,len,argoff); + if ((ret & 0x0F) != SSM_PASS) return ret; + } + } + return SSM_ACCEPT; +} + +int +module_rcpt(struct conn *c, char *cmd, int len, int argoff) +{ + int i, ret; + for (i = 0; i < nmod; i++) { + if (modlist[i]->hook_rcpt) { + ret = modlist[i]->hook_rcpt(c,cmd,len,argoff); + if ((ret & 0x0F) != SSM_PASS) return ret; + } + } + return SSM_ACCEPT; +} + +void +module_data(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); + } + } +} + +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 ((ret & 0x0F) != SSM_PASS) return ret; + } + } + return SSM_ACCEPT; +} + diff --git a/modules.c b/modules.c new file mode 100644 index 0000000..3fb4f3f --- /dev/null +++ b/modules.c @@ -0,0 +1,47 @@ +#include +#include +#include + +static int nmod = 0; +static smtpsink_module **modlist = 0; + +/* modulespec is a string formatted as: + + "/path/to/module,options" + + parsing of "options" is module dependent +*/ +void +module_init(char *modulespec) +{ + char modpath[1024]; + char *file, *t; + smtpsink_module *mod; + void *dlmod; + + t = strchr(modulespec, ','); + if (!t) file = modulespec; + else { + if (t-modulespec - 1 > sizeof(modpath)) + errx(1, "module path too long: %s\n", modulespec); + strncpy(modpath, modulespec, t - modulespec); + file = modpath; + } + + dlmod = dlopen(file, RTLD_NOW); + if (!dlmod) + errx(1, "could not load %s: %s\n", file, dlerror()); + + mod = (void *)dlsym(dlmod, "smtpsink_module"); + if (!mod) + errx(1, "module %s invalid: %s\n", file, dlerror()); + + mod->module_init(); + + modlist = realloc(modlist, nmod + 1); + if (!modlist) + errx(1, "out of memory\n"); + + modlist[nmod++] = mod; +} + diff --git a/smtpsink-int.h b/smtpsink-int.h index 5e87033..8cd64a4 100644 --- a/smtpsink-int.h +++ b/smtpsink-int.h @@ -18,3 +18,14 @@ extern int read_timeout(struct conn *); extern struct conn_queue io_queue, smtp_queue; extern char *banner_hostname; + +/* 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 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_enddata(struct conn *); diff --git a/smtpsink.c b/smtpsink.c index 5e836a9..3bbd394 100644 --- a/smtpsink.c +++ b/smtpsink.c @@ -70,7 +70,7 @@ main(int argc, char **argv) pthread_t sl; int tstart = 1; - while ((c=getopt(argc, argv, "fp:c:l:u:g:j:h:")) != -1) { + while ((c=getopt(argc, argv, "fp:c:l:u:g:j:h:M:")) != -1) { switch(c) { case 'f': daemonize = 0; break; case 'p': pidfd = open(optarg, O_CREAT|O_TRUNC|O_WRONLY, 0600); @@ -108,7 +108,8 @@ main(int argc, char **argv) break; case 'h': banner_hostname = optarg; break; case 'M': - /* WRITEME: module init */ + module_init(optarg); + break; case '?': default: usage(argv[0]); diff --git a/smtpsink.h b/smtpsink.h index 3c6d3ee..c67eb23 100644 --- a/smtpsink.h +++ b/smtpsink.h @@ -29,8 +29,39 @@ struct conn { } rdata, wdata; short event; struct event re, we; - void *priv_data; + void **priv_data; STAILQ_ENTRY(conn) c_list; }; int respond(struct conn *, const char *, ...); + +/* return values for module methods */ +/* SSM_PASS: move on to next module */ +/* SSM_ACCEPT: stop processing, accept command */ +/* SSM_REJECT: stop processing, reject command */ +/* SSM_MSG | SSM_ACCEPT: stop processing, accept command, module responded */ +/* SSM_MSG | SSM_REJECT: stop processing, reject command, module responded */ +#define SSM_PASS 0 +#define SSM_ACCEPT 1 +#define SSM_REJECT 2 +#define SSM_MSG (1 << 8) + +struct smtpsink_module { + void (*module_init)(char *); + void (*module_hup)(void); + + /* manage connection private data */ + void (*reset_cdata)(struct conn *); + + /* 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; +};