summaryrefslogtreecommitdiff
path: root/src/srsreverse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/srsreverse.c')
-rw-r--r--src/srsreverse.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/srsreverse.c b/src/srsreverse.c
new file mode 100644
index 0000000..d9b57db
--- /dev/null
+++ b/src/srsreverse.c
@@ -0,0 +1,172 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include "control.h"
+#include "sig.h"
+#include "constmap.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "env.h"
+#include "qmail.h"
+#include "auto_qmail.h"
+#include "auto_break.h"
+#include "buffer.h"
+#include "case.h"
+#include "str.h"
+#include "fmt.h"
+#include "stralloc.h"
+#include "logmsg.h"
+#include "srs2.h"
+
+#define WHO "srsreverse"
+
+void die_nomem() { logmsg(WHO,111,FATAL,"out of memory"); }
+void die_control() { logmsg(WHO,110,FATAL,"Unable to read control files"); }
+
+struct qmail qqt;
+char *vdomainuser = 0;
+stralloc vdomains = {0};
+struct constmap mapvdomains;
+char *srsdomaininfo = 0;
+stralloc srsdomains = {0};
+struct constmap mapsrsdomains;
+stralloc srserror = {0};
+stralloc srshost = {0};
+
+/** @file srsreverse.c
+ @brief forwarding bounces with SRS enhanced addresss
+ @return 0 on success (forwarded or not)
+ -3 SRS error with error output
+ 111 no memory / processing error
+ 110 control file not readable
+*/
+
+static int srserror_str(int code) {
+ if (!stralloc_copys(&srserror,"SRS: ")) die_nomem();
+ if (!stralloc_cats(&srserror,srs_strerror(code))) die_nomem();
+ if (!stralloc_0(&srserror)) die_nomem();
+ return -3;
+}
+
+ssize_t mywrite(int fd,char *buf,int len)
+{
+ qmail_put(&qqt,buf,len);
+ return len;
+}
+
+char inbuf[BUFSIZE_LINE];
+char outbuf[BUFSIZE_LINE];
+buffer bi = BUFFER_INIT(read,0,inbuf,sizeof(inbuf));
+buffer bo = BUFFER_INIT(mywrite,-1,outbuf,sizeof(outbuf));
+
+char num[FMT_ULONG];
+
+int main()
+{
+ int i, j, r;
+ char *recipient;
+ char *dtline;
+ char *qqx;
+ srs_t *srs;
+ stralloc cookie = {0};
+ char separator = '=';
+ char srsrecipient[512];
+ char *host = 0;
+
+ sig_pipeignore();
+
+ recipient = env_get("RECIPIENT");
+ if (!recipient)
+ logmsg(WHO,100,FATAL,"RECIPIENT not set");
+ dtline = env_get("DTLINE");
+ if (!dtline)
+ logmsg(WHO,100,FATAL,"DTLINE not set");
+ host = env_get("HOST");
+ if (!host)
+ logmsg(WHO,100,FATAL,"HOST not set");
+
+ if (chdir(auto_qmail) == -1)
+ logmsg(WHO,111,FATAL,B("unable to chdir to: ",auto_qmail));
+
+ /* Check for particular virtual SRS domain user */
+
+ switch (control_readfile(&vdomains,"control/virtualdomains",0)) {
+ case -1: die_control();
+ case 0: if (!constmap_init(&mapvdomains,"",0,1)) die_nomem(); break;
+ case 1: if (!constmap_init(&mapvdomains,vdomains.s,vdomains.len,1)) die_nomem(); break;
+ }
+
+ j = str_len(host);
+ for (i = 0; i <= j; ++i)
+ if ((i == 0) || (host[i] == '.')) {
+ if (!stralloc_copys(&srshost,"")) die_nomem();
+ if (!stralloc_catb(&srshost,host + i,j - i)) die_nomem();
+ if ((srsdomaininfo = constmap(&mapvdomains,srshost.s,srshost.len)) != 0) goto SRSDOMAINS;
+ }
+ if (!stralloc_copys(&srshost,host)) die_nomem();
+
+ SRSDOMAINS:
+
+ switch (control_readfile(&srsdomains,"control/srsdomains",0)) {
+ case -1: die_control();
+ case 0: if (!constmap_init(&mapsrsdomains,"",0,1)) die_nomem(); break;
+ case 1: if (!constmap_init(&mapsrsdomains,srsdomains.s,srsdomains.len,1)) die_nomem(); break;
+ }
+ if ((srsdomaininfo = constmap(&mapsrsdomains,srshost.s,srshost.len)) == 0)
+ if ((srsdomaininfo = constmap(&mapsrsdomains,"*",1)) == 0) return 0;
+
+ if (*srsdomaininfo) {
+ i = str_chr(srsdomaininfo,'|'); // multiple cookies; separated by ' '
+ if (srsdomaininfo[i] == '|') {
+ srsdomaininfo[i] = 0;
+ separator = srsdomaininfo[i+1];
+ }
+ if (!stralloc_copys(&cookie,srsdomaininfo)) die_nomem();
+ if (!stralloc_0(&cookie)) die_nomem();
+ }
+
+ /* strip virtual user from recipient */
+
+ if ((vdomainuser = constmap(&mapvdomains,host,j))) {
+ i = str_chr(recipient,*auto_break);
+ if (!case_diffb(recipient,i - 1,vdomainuser)) recipient += i + 1;
+ }
+
+ /* Let's go SRS reverse */
+
+ srs = srs_new();
+
+ if (separator == '-' || separator == '+' || separator == '=') { // '=' is default
+ r = srs_set_separator(srs,separator);
+ if (r != SRS_SUCCESS) return srserror_str(r);
+ }
+
+ for (j = 0, i = 0; j < cookie.len; j++) {
+ if (cookie.s[j] == ' ' || cookie.s[j] == '\0' ) {
+ cookie.s[j] = '\0';
+ r = srs_add_secret(srs,cookie.s + i);
+ if (r != SRS_SUCCESS) return srserror_str(r);
+ i = j + 1;
+ if (cookie.s[i] == ' ') { j++; continue; }
+ }
+ }
+
+ if ((r = srs_reverse(srs,srsrecipient,sizeof(srsrecipient),recipient)) != SRS_SUCCESS) {
+ logmsg(WHO,100,FATAL,B("unable to reverse: ",recipient," ",srs_strerror(r)));
+ }
+
+ if (qmail_open(&qqt) == -1)
+ logmsg(WHO,111,FATAL,"unable to fork: ");
+ qmail_puts(&qqt,dtline);
+ if (buffer_copy(&bo,&bi) != 0)
+ logmsg(WHO,111,FATAL,"unable to read message: ");
+ buffer_flush(&bo);
+
+ num[fmt_ulong(num,qmail_qp(&qqt))] = 0;
+
+ qmail_from(&qqt,"");
+ qmail_to(&qqt,srsrecipient);
+ qqx = qmail_close(&qqt);
+ if (*qqx) logmsg(WHO,*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
+ logmsg(WHO,0,LOG,B(srsrecipient,": qp ",num));
+
+}