nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

qmail-lspawn.c (5757B)


      1 #include "fd.h"
      2 #include "spawn.h"
      3 #include "wait.h"
      4 #include "prot.h"
      5 #include "substdio.h"
      6 #include "stralloc.h"
      7 #include "scan.h"
      8 #include "exit.h"
      9 #include "fork.h"
     10 #include "error.h"
     11 #include "byte.h"
     12 #include "cdb.h"
     13 #include "case.h"
     14 #include "open.h"
     15 #include "slurpclose.h"
     16 #include "uidgid.h"
     17 #include "auto_qmail.h"
     18 #include "auto_uids.h"
     19 #include "auto_users.h"
     20 #include "qlx.h"
     21 
     22 char *aliasempty;
     23 
     24 uid_t auto_uidp;
     25 
     26 gid_t auto_gidn;
     27 
     28 void
     29 initialize(int argc, char **argv)
     30 {
     31 	aliasempty = argv[1];
     32 	if (!aliasempty)
     33 		_exit(100);
     34 
     35 	auto_uidp = inituid(auto_userp);
     36 	auto_uidq = inituid(auto_userq);
     37 
     38 	auto_gidn = initgid(auto_groupn);
     39 }
     40 
     41 int truncreport = 3000;
     42 
     43 void
     44 report(substdio * ss, int wstat, char *s, int len)
     45 {
     46 	int i;
     47 	if (wait_crashed(wstat)) {
     48 		substdio_puts(ss, "Zqmail-local crashed.\n");
     49 		return;
     50 	}
     51 	switch (wait_exitcode(wstat)) {
     52 	case QLX_CDB:
     53 		substdio_puts(ss, "ZTrouble reading users/cdb in qmail-lspawn.\n");
     54 		return;
     55 	case QLX_NOMEM:
     56 		substdio_puts(ss, "ZOut of memory in qmail-lspawn.\n");
     57 		return;
     58 	case QLX_SYS:
     59 		substdio_puts(ss, "ZTemporary failure in qmail-lspawn.\n");
     60 		return;
     61 	case QLX_NOALIAS:
     62 		substdio_puts(ss, "ZUnable to find alias user!\n");
     63 		return;
     64 	case QLX_ROOT:
     65 		substdio_puts(ss, "ZNot allowed to perform deliveries as root.\n");
     66 		return;
     67 	case QLX_USAGE:
     68 		substdio_puts(ss, "ZInternal qmail-lspawn bug.\n");
     69 		return;
     70 	case QLX_NFS:
     71 		substdio_puts(ss, "ZNFS failure in qmail-local.\n");
     72 		return;
     73 	case QLX_EXECHARD:
     74 		substdio_puts(ss, "DUnable to run qmail-local.\n");
     75 		return;
     76 	case QLX_EXECSOFT:
     77 		substdio_puts(ss, "ZUnable to run qmail-local.\n");
     78 		return;
     79 	case QLX_EXECPW:
     80 		substdio_puts(ss, "ZUnable to run qmail-getpw.\n");
     81 		return;
     82 	case 111:
     83 	case 71:
     84 	case 74:
     85 	case 75:
     86 		substdio_put(ss, "Z", 1);
     87 		break;
     88 	case 0:
     89 		substdio_put(ss, "K", 1);
     90 		break;
     91 	case 100:
     92 	default:
     93 		substdio_put(ss, "D", 1);
     94 		break;
     95 	}
     96 
     97 	for (i = 0; i < len; ++i)
     98 		if (!s[i])
     99 			break;
    100 	substdio_put(ss, s, i);
    101 }
    102 
    103 stralloc lower = {0};
    104 stralloc nughde = {0};
    105 stralloc wildchars = {0};
    106 
    107 void
    108 nughde_get(char *local)
    109 {
    110 	char *(args[3]);
    111 	int pi[2];
    112 	int gpwpid;
    113 	int gpwstat;
    114 	int r;
    115 	int fd;
    116 	int flagwild;
    117 
    118 	if (!stralloc_copys(&lower, "!"))
    119 		_exit(QLX_NOMEM);
    120 	if (!stralloc_cats(&lower, local))
    121 		_exit(QLX_NOMEM);
    122 	if (!stralloc_0(&lower))
    123 		_exit(QLX_NOMEM);
    124 	case_lowerb(lower.s, lower.len);
    125 
    126 	if (!stralloc_copys(&nughde, ""))
    127 		_exit(QLX_NOMEM);
    128 
    129 	fd = open_read("users/cdb");
    130 	if (fd == -1)
    131 		if (errno != error_noent)
    132 			_exit(QLX_CDB);
    133 
    134 	if (fd != -1) {
    135 		uint32 dlen;
    136 		unsigned int i;
    137 
    138 		r = cdb_seek(fd, "", 0, &dlen);
    139 		if (r != 1)
    140 			_exit(QLX_CDB);
    141 		if (!stralloc_ready(&wildchars, (unsigned int)dlen))
    142 			_exit(QLX_NOMEM);
    143 		wildchars.len = dlen;
    144 		if (cdb_bread(fd, wildchars.s, wildchars.len) == -1)
    145 			_exit(QLX_CDB);
    146 
    147 		i = lower.len;
    148 		flagwild = 0;
    149 
    150 		do {
    151 			/* i > 0 */
    152 			if (!flagwild || (i == 1) || (byte_chr(wildchars.s, wildchars.len, lower.s[i - 1]) < wildchars.len)) {
    153 				r = cdb_seek(fd, lower.s, i, &dlen);
    154 				if (r == -1)
    155 					_exit(QLX_CDB);
    156 				if (r == 1) {
    157 					if (!stralloc_ready(&nughde, (unsigned int)dlen))
    158 						_exit(QLX_NOMEM);
    159 					nughde.len = dlen;
    160 					if (cdb_bread(fd, nughde.s, nughde.len) == -1)
    161 						_exit(QLX_CDB);
    162 					if (flagwild)
    163 						if (!stralloc_cats(&nughde, local + i - 1))
    164 							_exit(QLX_NOMEM);
    165 					if (!stralloc_0(&nughde))
    166 						_exit(QLX_NOMEM);
    167 					close(fd);
    168 					return;
    169 				}
    170 			}
    171 			--i;
    172 			flagwild = 1;
    173 		}
    174 		while (i);
    175 
    176 		close(fd);
    177 	}
    178 
    179 	if (pipe(pi) == -1)
    180 		_exit(QLX_SYS);
    181 	args[0] = "bin/qmail-getpw";
    182 	args[1] = local;
    183 	args[2] = 0;
    184 	switch (gpwpid = fork()) {
    185 	case -1:
    186 		_exit(QLX_SYS);
    187 	case 0:
    188 		if (prot_gid(auto_gidn) == -1)
    189 			_exit(QLX_USAGE);
    190 		if (prot_uid(auto_uidp) == -1)
    191 			_exit(QLX_USAGE);
    192 		close(pi[0]);
    193 		if (fd_move(1, pi[1]) == -1)
    194 			_exit(QLX_SYS);
    195 		execv(*args, args);
    196 		_exit(QLX_EXECPW);
    197 	}
    198 	close(pi[1]);
    199 
    200 	if (slurpclose(pi[0], &nughde, 128) == -1)
    201 		_exit(QLX_SYS);
    202 
    203 	if (wait_pid(&gpwstat, gpwpid) != -1) {
    204 		if (wait_crashed(gpwstat))
    205 			_exit(QLX_SYS);
    206 		if (wait_exitcode(gpwstat) != 0)
    207 			_exit(wait_exitcode(gpwstat));
    208 	}
    209 }
    210 
    211 int
    212 spawn(int fdmess, int fdout, char *s, char *r, int at)
    213 {
    214 	int f;
    215 
    216 	if (!(f = fork())) {
    217 		char *(args[11]);
    218 		unsigned long u;
    219 		int n;
    220 		uid_t uid;
    221 		gid_t gid;
    222 		char *x;
    223 		unsigned int xlen;
    224 
    225 		r[at] = 0;
    226 		if (!r[0])
    227 			_exit(0);	/* <> */
    228 
    229 		if (chdir(auto_qmail) == -1)
    230 			_exit(QLX_USAGE);
    231 
    232 		nughde_get(r);
    233 
    234 		x = nughde.s;
    235 		xlen = nughde.len;
    236 
    237 		args[0] = "bin/qmail-local";
    238 		args[1] = "--";
    239 		args[2] = x;
    240 		n = byte_chr(x, xlen, 0);
    241 		if (n++ == xlen)
    242 			_exit(QLX_USAGE);
    243 		x += n;
    244 		xlen -= n;
    245 
    246 		scan_ulong(x, &u);
    247 		uid = u;
    248 		n = byte_chr(x, xlen, 0);
    249 		if (n++ == xlen)
    250 			_exit(QLX_USAGE);
    251 		x += n;
    252 		xlen -= n;
    253 
    254 		scan_ulong(x, &u);
    255 		gid = u;
    256 		n = byte_chr(x, xlen, 0);
    257 		if (n++ == xlen)
    258 			_exit(QLX_USAGE);
    259 		x += n;
    260 		xlen -= n;
    261 
    262 		args[3] = x;
    263 		n = byte_chr(x, xlen, 0);
    264 		if (n++ == xlen)
    265 			_exit(QLX_USAGE);
    266 		x += n;
    267 		xlen -= n;
    268 
    269 		args[4] = r;
    270 		args[5] = x;
    271 		n = byte_chr(x, xlen, 0);
    272 		if (n++ == xlen)
    273 			_exit(QLX_USAGE);
    274 		x += n;
    275 		xlen -= n;
    276 
    277 		args[6] = x;
    278 		n = byte_chr(x, xlen, 0);
    279 		if (n++ == xlen)
    280 			_exit(QLX_USAGE);
    281 		x += n;
    282 		xlen -= n;
    283 
    284 		args[7] = r + at + 1;
    285 		args[8] = s;
    286 		args[9] = aliasempty;
    287 		args[10] = 0; /* Would need one additional arg to add an lda-prepend file */
    288 
    289 		if (fd_move(0, fdmess) == -1)
    290 			_exit(QLX_SYS);
    291 		if (fd_move(1, fdout) == -1)
    292 			_exit(QLX_SYS);
    293 		if (fd_copy(2, 1) == -1)
    294 			_exit(QLX_SYS);
    295 		if (prot_gid(gid) == -1)
    296 			_exit(QLX_USAGE);
    297 		if (prot_uid(uid) == -1)
    298 			_exit(QLX_USAGE);
    299 		if (!getuid())
    300 			_exit(QLX_ROOT);
    301 
    302 		execv(*args, args);
    303 		if (error_temp(errno))
    304 			_exit(QLX_EXECSOFT);
    305 		_exit(QLX_EXECHARD);
    306 	}
    307 	return f;
    308 }