summaryrefslogtreecommitdiff
path: root/src/recipients.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/recipients.c')
-rw-r--r--src/recipients.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/recipients.c b/src/recipients.c
new file mode 100644
index 0000000..ce29e19
--- /dev/null
+++ b/src/recipients.c
@@ -0,0 +1,290 @@
+#include <unistd.h>
+#include "cdbread.h"
+#include "byte.h"
+#include "open.h"
+#include "control.h"
+#include "constmap.h"
+#include "stralloc.h"
+#include "recipients.h"
+#include "wait.h"
+#include "str.h"
+#include "fd.h"
+#include "sig.h"
+#include "case.h"
+#include "buffer.h"
+#include "auto_break.h"
+#include "qmail.h"
+
+#define FDAUTH 3
+
+static stralloc key = {0};
+static stralloc domain = {0};
+static stralloc wildhost = {0};
+static stralloc address = {0};
+static stralloc rcptline = {0};
+static stralloc vkey = {0};
+static stralloc verp = {0};
+static stralloc user = {0};
+static stralloc ukey = {0};
+static int flagrcpts = 0;
+static int fdrcps;
+static struct cdb cdb;
+
+/** @file recipients.c
+ @brief functions recipients_init, recipients, recipients_parse, callapam
+ @param pointer to address, length of address
+ @return -3: problem with PAM
+ -2: out of memory
+ -1: error reading control file
+ 0: address not found; unsuccessful
+ 1: CDB lookup; successful
+ 2: PAM lookup; successful
+ 3: USERS lookup; successful
+ 4: Wildcarded domain; successful
+ 5: Pass-thru; neutral
+ 10: none existing control file; pass-thru
+*/
+
+int recipients_init()
+{
+ flagrcpts = control_readfile(&rcptline,"control/recipients",0);
+ if (flagrcpts != 1) return flagrcpts;
+ return 0;
+}
+
+char rcptbuf[512];
+buffer br = BUFFER_INIT(safewrite,FDAUTH,rcptbuf,sizeof(rcptbuf));
+
+int callapam(char *pam,char *addr)
+{
+ int i;
+ int j=0;
+ int wstat;
+ int pi[2];
+ int child;
+ char ch;
+ static stralloc mailaddress = {0};
+
+ char *childargs[7] = {0, 0, 0, 0, 0, 0, 0};
+ stralloc pamarg = {0};
+ stralloc pamname = {0};
+ stralloc pamarg1 = {0};
+ stralloc pamarg2 = {0};
+ stralloc pamarg3 = {0};
+ stralloc pamarg4 = {0};
+ stralloc pamarg5 = {0};
+
+ for (i = 0; (ch = pam[i]); i++) {
+ if (j < 6) {
+ if (ch != ' ')
+ if (!stralloc_append(&pamarg,&ch)) return -2;
+ if (ch == ' ' || ch == '\n' || i == str_len(pam) - 1) {
+ if (!stralloc_0(&pamarg)) return -2;
+ switch (j) {
+ case 0:
+ if (!stralloc_copy(&pamname,&pamarg)) return -2;
+ childargs[0] = pamname.s;
+ case 1:
+ if (!stralloc_copy(&pamarg1,&pamarg)) return -2;
+ childargs[1] = pamarg1.s;
+ case 2:
+ if (!stralloc_copy(&pamarg2,&pamarg)) return -2;
+ childargs[2] = pamarg2.s;
+ case 3:
+ if (!stralloc_copy(&pamarg3,&pamarg)) return -2;
+ childargs[3] = pamarg3.s;
+ case 4:
+ if (!stralloc_copy(&pamarg4,&pamarg)) return -2;
+ childargs[4] = pamarg4.s;
+ case 5:
+ if (!stralloc_copy(&pamarg5,&pamarg)) return -2;
+ childargs[5] = pamarg5.s;
+ }
+ j++;
+ if (!stralloc_copys(&pamarg,"")) return -2;
+ }
+ }
+ }
+ childargs[j] = 0;
+
+ close(FDAUTH);
+ if (pipe(pi) == -1) return -3;
+ if (pi[0] != FDAUTH) return -3;
+
+ switch (child = fork()) {
+ case -1:
+ return -3;
+ case 0:
+ close(pi[1]);
+ if (fd_copy(FDAUTH,pi[0]) == -1) return -3;
+ sig_pipedefault();
+ execvp(childargs[0],childargs);
+ return 111;
+ }
+ close(pi[0]);
+
+/* checkpassword compliant form: address\0\0\0 */
+
+ if (!stralloc_copys(&mailaddress,addr)) return -2;
+ if (!stralloc_0(&mailaddress)) return -2;
+ if (!stralloc_0(&mailaddress)) return -2;
+ if (!stralloc_0(&mailaddress)) return -2;
+
+ buffer_init(&br,write,pi[1],rcptbuf,sizeof(rcptbuf));
+ if (buffer_put(&br,mailaddress.s,mailaddress.len) == -1) return -3;
+ if (buffer_flush(&br) == -1) return -3;
+ close(pi[1]);
+
+ if (wait_pid(&wstat,child) == -1) return -3;
+ if (wait_crashed(wstat)) return -3;
+ return wait_exitcode(wstat);
+}
+
+int recipients_parse(char *rhost,int rlen,char *addr,char *rkey,int klen,char *vaddr,char *vkey,int vlen,char *ukey,int ulen)
+{
+ int i;
+ int r;
+ int j = 0;
+ int k = 0;
+ int u = 0;
+ static stralloc line = {0};
+ int seenhost = 0;
+
+ if (!stralloc_copys(&line,"")) return -2;
+ if (!stralloc_copys(&wildhost,"!")) return -2;
+ if (!stralloc_cats(&wildhost,rhost)) return -2;
+ if (!stralloc_0(&wildhost)) return -2;
+
+ for (i = 0; i < rcptline.len; ++i) {
+ if (!stralloc_append(&line,&rcptline.s[i])) return -2;
+
+ if (rcptline.s[i] == '\0') {
+ if (!stralloc_0(&line)) return -2;
+
+ j = byte_chr(line.s,line.len,':'); /* cdb */
+ k = byte_chr(line.s,line.len,'|'); /* pam */
+ u = byte_chr(line.s,line.len,'='); /* assign users */
+
+ if (!str_diffn(line.s,wildhost.s,wildhost.len - 1)) return 4; /* wilddomain */
+ if ((j && j < line.len) || (k && k < line.len) || (u && u < line.len))
+ if (!str_diffn(line.s,"@",1)) /* exact */
+ if (!str_diffn(line.s + 1,rhost,rlen - 1)) seenhost = 1;
+
+ if (!seenhost) { /* domain */
+ if (j && rlen >= j)
+ if (!str_diffn(line.s,rhost + rlen - j - 1,j - 1)) seenhost = 2;
+ if (k && rlen >= k)
+ if (!str_diffn(line.s,rhost + rlen - k - 1,k - 1)) seenhost = 3;
+ if (u && rlen >= u)
+ if (!str_diffn(line.s,rhost + rlen - u - 1,u - 1)) seenhost = 4;
+ }
+ if (!seenhost) /* pass-thru */
+ if (!str_diffn(line.s,"!*",2)) return 5;
+
+ if (k && k < line.len) /* pam */
+ if (seenhost || !str_diffn(line.s,"*",1)) {
+ r = callapam(line.s + k + 1,addr);
+ if (vlen > 0 && r != 0)
+ r = callapam(line.s + k + 1,vaddr);
+ if (r == 0) return 2;
+ if (r == 111) return r;
+ }
+
+ if (u && u < line.len) /* qmail-users */
+ if (seenhost || !str_diffn(line.s,"*",1)) {
+ fdrcps = open_read("users/assign.cdb");
+ if (fdrcps != -1) {
+ cdb_init(&cdb,fdrcps);
+ r = cdb_find(&cdb,ukey,ulen - 1);
+ cdb_free(&cdb);
+ close(fdrcps);
+ if (r) return 3;
+ }
+ }
+
+ if (j && j < line.len) /* cdb */
+ if (seenhost || !str_diffn(line.s,"*",1)) {
+ fdrcps = open_read(line.s + j + 1);
+ if (fdrcps != -1) {
+ cdb_init(&cdb,fdrcps);
+ r = cdb_find(&cdb,rkey,klen - 2);
+ if (vlen > 0 && r == 0)
+ r = cdb_find(&cdb,vkey,vlen - 2);
+ cdb_free(&cdb);
+ close(fdrcps);
+ if (r) return 1;
+ }
+ }
+
+ if (!seenhost) {
+ fdrcps = open_read(line.s); /* legacy cdb */
+ if (fdrcps != -1) {
+ cdb_init(&cdb,fdrcps);
+ r = cdb_find(&cdb,rkey,klen - 2);
+ if (vlen > 0 && r == 0)
+ r = cdb_find(&cdb,vkey,vlen - 2);
+ cdb_free(&cdb);
+ close(fdrcps);
+ if (r) return 1;
+ }
+ }
+
+ if (!stralloc_copys(&line,"")) return -2;
+ }
+ }
+ return 0;
+}
+
+int recipients(char *buf,int len)
+{
+ int at;
+ int i;
+ int r;
+
+ if (flagrcpts != 1) return 10;
+
+ at = byte_rchr(buf,len,'@');
+ if (at && at < len) {
+ if (!stralloc_copyb(&domain,buf + at + 1,len - at - 1)) return -2;
+ if (!stralloc_copyb(&address,buf,len)) return -2;
+ } else {
+ if (!stralloc_copyb(&address,buf,len)) return -2;
+ if (!stralloc_append(&address,"@")) return -2;
+ if (!stralloc_copys(&domain,"localhost")) return -2;
+ if (!stralloc_cat(&address,&domain)) return -2;
+ }
+ if (!stralloc_copyb(&user,buf,at - 1)) return -2;
+
+ if (!stralloc_0(&user)) return -2;
+ if (!stralloc_0(&address)) return -2;
+ if (!stralloc_0(&domain)) return -2;
+
+ if (!stralloc_copys(&key,":")) return -2;
+ if (!stralloc_cat(&key,&address)) return -2;
+ if (!stralloc_0(&key)) return -2; /* \0\0 terminated */
+ case_lowerb(key.s,key.len);
+ case_lowerb(domain.s,domain.len);
+
+ if (!stralloc_copys(&ukey,"!")) return -2;
+ if (!stralloc_cat(&ukey,&user)) return -2;
+ if (!stralloc_0(&ukey)) return -2; /* \0 terminated */
+ case_lowerb(ukey.s,ukey.len);
+
+
+ for (i = 0; i < at; i++) { /* VERP addresses */
+ if (buf[i] == *auto_break || buf[i] == '=' || buf[i] == '+') { /* SRS delimiter */
+ if (!stralloc_copyb(&verp,buf,i + 1)) return -2;
+ if (!stralloc_append(&verp,"@")) return -2;
+ if (!stralloc_cat(&verp,&domain)) return -2;
+ if (!stralloc_copys(&vkey,":")) return -2;
+ if (!stralloc_cat(&vkey,&verp)) return -2;
+ if (!stralloc_0(&vkey)) return -2; /* \0\0 terminated */
+ case_lowerb(vkey.s,vkey.len);
+ break;
+ }
+ }
+
+ r = recipients_parse(domain.s,domain.len,address.s,key.s,key.len,verp.s,vkey.s,vkey.len,ukey.s,ukey.len);
+ if (r) return r;
+ return 0;
+}