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 }