]> git.mikk.net Git - smtpsink/commitdiff
First cut at module loading system. Still need to make a usable
authorchris mikkelson <chris@mikk.net>
Fri, 27 Mar 2009 01:59:50 +0000 (20:59 -0500)
committerchris mikkelson <chris@mikk.net>
Fri, 27 Mar 2009 03:46:48 +0000 (22:46 -0500)
API for module developers.  (get/set private data, respond, etc.)

Makefile
conn_pool.c
module.c [new file with mode: 0644]
modules.c [new file with mode: 0644]
smtpsink-int.h
smtpsink.c
smtpsink.h

index d7e6048bda3a0f08a9d27433d1ded89eeccf2bf6..3bccc70d8869a67843aa6574cc12da28943cc58b 100644 (file)
--- 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:
index 3a44436d0409860d281d10ef9d618822f2f089b0..824f022ba5ac738b6c2a762a14de9b29394ff26e 100644 (file)
@@ -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 (file)
index 0000000..d7d3b1b
--- /dev/null
+++ b/module.c
@@ -0,0 +1,145 @@
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <err.h>
+
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <event.h>
+#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 (file)
index 0000000..3fb4f3f
--- /dev/null
+++ b/modules.c
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+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;
+}
+
index 5e87033da561b90657b61fa227cebe30b90becea..8cd64a403b2b908bcf25d01e1a3d5f963524d641 100644 (file)
@@ -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 *);
index 5e836a9bdbfbb4419ad94320be52b7743464158b..3bbd394fd3325a9c4838752ce0b88435cf7c5b27 100644 (file)
@@ -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]);
index 3c6d3ee8b90acbf2cb23eaff79ee8641b70c7e69..c67eb23bc816119158f78f5c3bb52d546c3e98d6 100644 (file)
@@ -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;
+};