#include "recipients.h" #include #include "buffer.h" #include "byte.h" #include "case.h" #include "cdbread.h" #include "constmap.h" #include "fd.h" #include "open.h" #include "sig.h" #include "str.h" #include "stralloc.h" #include "wait.h" #include "auto_break.h" #include "control.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)); static 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); } static 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; }