chiark / gitweb /
Merge branches 'idx/verh' and 'idx/qmqpc'
[qmail] / qmail-lspawn.c
1 #include "fd.h"
2 #include "wait.h"
3 #include "prot.h"
4 #include "substdio.h"
5 #include "stralloc.h"
6 #include "scan.h"
7 #include "exit.h"
8 #include "fork.h"
9 #include "error.h"
10 #include "cdb.h"
11 #include "case.h"
12 #include "slurpclose.h"
13 #include "auto_qmail.h"
14 #include "auto_uids.h"
15 #include "qlx.h"
16
17 char *aliasempty;
18
19 void initialize(argc,argv)
20 int argc;
21 char **argv;
22 {
23   aliasempty = argv[1];
24   if (!aliasempty) _exit(100);
25 }
26
27 int truncreport = 3000;
28
29 void report(ss,wstat,s,len)
30 substdio *ss;
31 int wstat;
32 char *s;
33 int len;
34 {
35  int i;
36  if (wait_crashed(wstat))
37   { substdio_puts(ss,"Zqmail-local crashed.\n"); return; }
38  switch(wait_exitcode(wstat))
39   {
40    case QLX_CDB:
41      substdio_puts(ss,"ZTrouble reading users/cdb in qmail-lspawn.\n"); return;
42    case QLX_NOMEM:
43      substdio_puts(ss,"ZOut of memory in qmail-lspawn.\n"); return;
44    case QLX_SYS:
45      substdio_puts(ss,"ZTemporary failure in qmail-lspawn.\n"); return;
46    case QLX_NOALIAS:
47      substdio_puts(ss,"ZUnable to find alias user!\n"); return;
48    case QLX_ROOT:
49      substdio_puts(ss,"ZNot allowed to perform deliveries as root.\n"); return;
50    case QLX_USAGE:
51      substdio_puts(ss,"ZInternal qmail-lspawn bug.\n"); return;
52    case QLX_NFS:
53      substdio_puts(ss,"ZNFS failure in qmail-local.\n"); return;
54    case QLX_EXECHARD:
55      substdio_puts(ss,"DUnable to run qmail-local.\n"); return;
56    case QLX_EXECSOFT:
57      substdio_puts(ss,"ZUnable to run qmail-local.\n"); return;
58    case QLX_EXECPW:
59      substdio_puts(ss,"ZUnable to run qmail-getpw.\n"); return;
60    case 111: case 71: case 74: case 75:
61      substdio_put(ss,"Z",1); break;
62    case 0:
63      substdio_put(ss,"K",1); break;
64    case 100:
65    default:
66      substdio_put(ss,"D",1); break;
67   }
68
69  for (i = 0;i < len;++i) if (!s[i]) break;
70  substdio_put(ss,s,i);
71 }
72
73 stralloc lower = {0};
74 stralloc nughde = {0};
75 stralloc wildchars = {0};
76
77 void nughde_get(local)
78 char *local;
79 {
80  char *(args[3]);
81  int pi[2];
82  int gpwpid;
83  int gpwstat;
84  int r;
85  int fd;
86  int flagwild;
87
88  if (!stralloc_copys(&lower,"!")) _exit(QLX_NOMEM);
89  if (!stralloc_cats(&lower,local)) _exit(QLX_NOMEM);
90  if (!stralloc_0(&lower)) _exit(QLX_NOMEM);
91  case_lowerb(lower.s,lower.len);
92
93  if (!stralloc_copys(&nughde,"")) _exit(QLX_NOMEM);
94
95  fd = open_read("users/cdb");
96  if (fd == -1)
97    if (errno != error_noent)
98      _exit(QLX_CDB);
99
100  if (fd != -1)
101   {
102    uint32 dlen;
103    unsigned int i;
104
105    r = cdb_seek(fd,"",0,&dlen);
106    if (r != 1) _exit(QLX_CDB);
107    if (!stralloc_ready(&wildchars,(unsigned int) dlen)) _exit(QLX_NOMEM);
108    wildchars.len = dlen;
109    if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) _exit(QLX_CDB);
110
111    i = lower.len;
112    flagwild = 0;
113
114    do
115     {
116      /* i > 0 */
117      if (!flagwild || (i == 1) || (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1]) < wildchars.len))
118       {
119        r = cdb_seek(fd,lower.s,i,&dlen);
120        if (r == -1) _exit(QLX_CDB);
121        if (r == 1)
122         {
123          if (!stralloc_ready(&nughde,(unsigned int) dlen)) _exit(QLX_NOMEM);
124          nughde.len = dlen;
125          if (cdb_bread(fd,nughde.s,nughde.len) == -1) _exit(QLX_CDB);
126          if (flagwild)
127            if (!stralloc_cats(&nughde,local + i - 1)) _exit(QLX_NOMEM);
128          if (!stralloc_0(&nughde)) _exit(QLX_NOMEM);
129          close(fd);
130          return;
131         }
132       }
133      --i;
134      flagwild = 1;
135     }
136    while (i);
137
138    close(fd);
139   }
140
141  if (pipe(pi) == -1) _exit(QLX_SYS);
142  args[0] = "/usr/sbin/qmail-getpw";
143  args[1] = local;
144  args[2] = 0;
145  switch(gpwpid = vfork())
146   {
147    case -1:
148      _exit(QLX_SYS);
149    case 0:
150      if (prot_gid(auto_gidn) == -1) _exit(QLX_USAGE);
151      if (prot_uid(auto_uidp) == -1) _exit(QLX_USAGE);
152      close(pi[0]);
153      if (fd_move(1,pi[1]) == -1) _exit(QLX_SYS);
154      execv(*args,args);
155      _exit(QLX_EXECPW);
156   }
157  close(pi[1]);
158
159  if (slurpclose(pi[0],&nughde,128) == -1) _exit(QLX_SYS);
160
161  if (wait_pid(&gpwstat,gpwpid) != -1)
162   {
163    if (wait_crashed(gpwstat)) _exit(QLX_SYS);
164    if (wait_exitcode(gpwstat) != 0) _exit(wait_exitcode(gpwstat));
165   }
166 }
167
168 int spawn(fdmess,fdout,s,r,at)
169 int fdmess; int fdout;
170 char *s; char *r; int at;
171 {
172  int f;
173
174  if (!(f = fork()))
175   {
176    char *(args[11]);
177    unsigned long u;
178    int n;
179    int uid;
180    int gid;
181    char *x;
182    unsigned int xlen;
183    
184    r[at] = 0;
185    if (!r[0]) _exit(0); /* <> */
186
187    if (chdir(auto_qmail) == -1) _exit(QLX_USAGE);
188
189    nughde_get(r);
190
191    x = nughde.s;
192    xlen = nughde.len;
193
194    args[0] = "/usr/sbin/qmail-local";
195    args[1] = "--";
196    args[2] = x;
197    n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
198
199    scan_ulong(x,&u);
200    uid = u;
201    n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
202
203    scan_ulong(x,&u);
204    gid = u;
205    n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
206
207    args[3] = x;
208    n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
209
210    args[4] = r;
211    args[5] = x;
212    n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
213
214    args[6] = x;
215    n = byte_chr(x,xlen,0); if (n++ == xlen) _exit(QLX_USAGE); x += n; xlen -= n;
216
217    args[7] = r + at + 1;
218    args[8] = s;
219    args[9] = aliasempty;
220    args[10] = 0;
221
222    if (fd_move(0,fdmess) == -1) _exit(QLX_SYS);
223    if (fd_move(1,fdout) == -1) _exit(QLX_SYS);
224    if (fd_copy(2,1) == -1) _exit(QLX_SYS);
225    if (prot_gid(gid) == -1) _exit(QLX_USAGE);
226    if (prot_uid(uid) == -1) _exit(QLX_USAGE);
227    if (!getuid()) _exit(QLX_ROOT);
228
229    execv(*args,args);
230    if (error_temp(errno)) _exit(QLX_EXECSOFT);
231    _exit(QLX_EXECHARD);
232   }
233  return f;
234 }