diff options
Diffstat (limited to 'src/qmail-lspawn.c')
-rw-r--r-- | src/qmail-lspawn.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/qmail-lspawn.c b/src/qmail-lspawn.c new file mode 100644 index 0000000..fed5c4c --- /dev/null +++ b/src/qmail-lspawn.c @@ -0,0 +1,241 @@ +#include <unistd.h> +#include "fd.h" +#include "wait.h" +#include "prot.h" +#include "buffer.h" +#include "stralloc.h" +#include "scan.h" +#include "exit.h" +#include "cdbread.h" +#include "case.h" +#include "readclose.h" +#include "auto_qmail.h" +#include "auto_uids.h" +#include "qlx.h" +#include "error.h" +#include "open.h" +#include "byte.h" + +char *aliasempty; + +void initialize(int argc,char **argv) +{ + aliasempty = argv[1]; + if (!aliasempty) _exit(100); +} + +int truncreport = 3000; + +void report(buffer *log,int wstat,char *s,int len) +{ + int i; + if (wait_crashed(wstat)) { buffer_putsflush(log,"Zqmail-lspawn: qmail-local crashed.\n"); return; } + + switch (wait_exitcode(wstat)) { + case QLX_CDB: + buffer_putsflush(log,"Zqmail-lspawn: Trouble reading users/assign.cdb.\n"); return; + case QLX_NOMEM: + buffer_putsflush(log,"Zqmail-lspawn: Out of memory.\n"); return; + case QLX_SYS: + buffer_putsflush(log,"Zqmail-lspawn: Temporary failure.\n"); return; + case QLX_NOALIAS: + buffer_putsflush(log,"Zqmail-lspawn: Unable to find alias user!\n"); return; + case QLX_ROOT: + buffer_putsflush(log,"Zqmail-spawn: Not allowed to perform deliveries as root.\n"); return; + case QLX_USAGE: + buffer_putsflush(log,"Zqmail-spawn: Internal bug.\n"); return; + case QLX_NFS: + buffer_putsflush(log,"Zqmail-spawn: NFS failure in qmail-local.\n"); return; + case QLX_EXECHARD: + buffer_putsflush(log,"Dqmail-spawn: Unable to run qmail-local.\n"); return; + case QLX_EXECSOFT: + buffer_putsflush(log,"Zqmail-spawn: Unable to run qmail-local.\n"); return; + case QLX_EXECPW: + buffer_putsflush(log,"Zqmail-spawn: Unable to run qmail-getpw.\n"); return; + case 111: case 71: case 74: case 75: + buffer_put(log,"Z",1); break; + case 0: + buffer_put(log,"K",1); break; + case 100: + default: + buffer_put(log,"D",1); break; + } + + for (i = 0; i < len; ++i) + if (!s[i]) break; + + buffer_put(log,s,i); +} + +stralloc lower = {0}; +stralloc nughde = {0}; +stralloc wildchars = {0}; + +static struct cdb c; + +void nughde_get(char *local) +{ + char *(args[3]); + int pi[2]; + int gpwpid; + int gpwstat; + int r; + int fd; + int flagwild; + + if (!stralloc_copys(&lower,"!")) _exit(QLX_NOMEM); + if (!stralloc_cats(&lower,local)) _exit(QLX_NOMEM); + if (!stralloc_0(&lower)) _exit(QLX_NOMEM); + case_lowerb(lower.s,lower.len); + + if (!stralloc_copys(&nughde,"")) _exit(QLX_NOMEM); + + fd = open_read("users/assign.cdb"); + if (fd == -1) + if (errno != ENOENT) + _exit(QLX_CDB); + + if (fd != -1) { + unsigned int i; + + cdb_init(&c,fd); + r = cdb_find(&c,"",0); + if (r != 1) _exit(QLX_CDB); + if (!stralloc_ready(&wildchars,cdb_datalen(&c))) _exit(QLX_NOMEM); + wildchars.len = cdb_datalen(&c); + if (cdb_read(&c,wildchars.s,wildchars.len,cdb_datapos(&c)) == -1) _exit(QLX_CDB); + + i = lower.len; + flagwild = 0; + + do { + /* i > 0 */ + if (!flagwild || (i == 1) || (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1]) < wildchars.len)) { + r = cdb_find(&c,lower.s,i); + if (r == -1) _exit(QLX_CDB); + if (r == 1) { + if (!stralloc_ready(&nughde,cdb_datalen(&c))) _exit(QLX_NOMEM); + nughde.len = cdb_datalen(&c); + if (cdb_read(&c,nughde.s,nughde.len,cdb_datapos(&c)) == -1) _exit(QLX_CDB); + if (flagwild) + if (!stralloc_cats(&nughde,local + i - 1)) _exit(QLX_NOMEM); + if (!stralloc_0(&nughde)) _exit(QLX_NOMEM); + close(fd); + return; + } + } + --i; + flagwild = 1; + } while (i); + + close(fd); + } + + if (pipe(pi) == -1) _exit(QLX_SYS); + + args[0] = "bin/qmail-getpw"; + args[1] = local; + args[2] = 0; + switch (gpwpid = fork()) { + case -1: + _exit(QLX_SYS); + case 0: + if (prot_gid(auto_gidn) == -1) _exit(QLX_USAGE); + if (prot_uid(auto_uidp) == -1) _exit(QLX_USAGE); + close(pi[0]); + if (fd_move(1,pi[1]) == -1) _exit(QLX_SYS); + execv(*args,args); + _exit(QLX_EXECPW); + } + close(pi[1]); + + if (readclose_append(pi[0],&nughde,128) == -1) _exit(QLX_SYS); + + if (wait_pid(&gpwstat,gpwpid) != -1) { + if (wait_crashed(gpwstat)) _exit(QLX_SYS); + if (wait_exitcode(gpwstat) != 0) _exit(wait_exitcode(gpwstat)); + } +} + +int spawn(int fdmess,int fdout,const char *s,char *r,const int at) +{ + int f; + + if (!(f = fork())) { + char *(args[11]); + unsigned long u; + int n; + int uid; + int gid; + char *x; + unsigned int xlen; + + r[at] = 0; + if (!r[0]) _exit(0); /* <> */ + + if (chdir(auto_qmail) == -1) _exit(QLX_USAGE); + + nughde_get(r); + + x = nughde.s; + xlen = nughde.len; + + args[0] = "bin/qmail-local"; + args[1] = "--"; + args[2] = x; + n = byte_chr(x,xlen,0); + if (n++ == xlen) _exit(QLX_USAGE); + x += n; + xlen -= n; + + scan_ulong(x,&u); + uid = u; + n = byte_chr(x,xlen,0); + if (n++ == xlen) _exit(QLX_USAGE); + x += n; + xlen -= n; + + scan_ulong(x,&u); + gid = u; + n = byte_chr(x,xlen,0); + if (n++ == xlen) _exit(QLX_USAGE); + x += n; + xlen -= n; + + args[3] = x; + n = byte_chr(x,xlen,0); + if (n++ == xlen) _exit(QLX_USAGE); + x += n; + xlen -= n; + + args[4] = r; + args[5] = x; + n = byte_chr(x,xlen,0); + if (n++ == xlen) _exit(QLX_USAGE); + x += n; + xlen -= n; + + args[6] = x; + n = byte_chr(x,xlen,0); + if (n++ == xlen) _exit(QLX_USAGE); + x += n; + xlen -= n; + + args[7] = r + at + 1; + args[8] = s; + args[9] = aliasempty; + args[10] = 0; + + if (fd_move(0,fdmess) == -1) _exit(QLX_SYS); + if (fd_move(1,fdout) == -1) _exit(QLX_SYS); + if (fd_copy(2,1) == -1) _exit(QLX_SYS); + if (prot_gid(gid) == -1) _exit(QLX_USAGE); + if (prot_uid(uid) == -1) _exit(QLX_USAGE); + if (!getuid()) _exit(QLX_ROOT); + + execv(*args,args); + if (errno) _exit(QLX_EXECSOFT); + _exit(QLX_EXECHARD); + } + return f; +} |