Download | Plain Text | No Line Numbers


  1. http://code.dogmap.org./qmail/#realrcptto
  2.  
  3. Changes in version 2006.12.10:
  4. - For QMAILRRTENYALL, use error code 554 after DATA, not 550. Thanks to
  5. ... sorry, I lost track of who found this.
  6. - Log stat() errors for .qmail files. Thanks to Chris Bensend for suggesting
  7. this.
  8.  
  9. Changes in version 2006.10.26:
  10. - Logging uses substdio_puts() and substdio_flush() instead of
  11. substdio_putsflush(). This makes log entries less likely to be
  12. interleaved. Thanks to Matthew Dempsky for finding this.
  13.  
  14. Changes in version 2004.09.14:
  15. - Strict syntax fix: a variable declaration was accidentally put among
  16. statements instead of at the beginning of the block.
  17.  
  18. Changes in version 2004.08.30:
  19. - Added QMAILRRTDENYALL.
  20. - Cleanup: missing "break" for some switch statements (no visible behavior
  21. changes AFAICT). Thanks to Markus Stumpf for finding these.
  22.  
  23. Changes in version 2004.02.05:
  24. - Short-circuit speedup when "dash" is empty.
  25. - Move duplicated code into realrcptto.c.
  26. - Add logging of rejected addresses.
  27. - Verified inter-patchability with netqmail-1.05 and Russell Nelson's
  28. qmail-smtpd-viruscan patch.
  29.  
  30. diff -Naur Makefile.orig Makefile
  31. --- Makefile.orig 1998-06-15 06:52:55.000000000 -0400
  32. +++ Makefile 2006-12-08 03:21:25.000000000 -0500
  33. @@ -1447,15 +1447,15 @@
  34. ./compile qmail-qmqpd.c
  35.  
  36. qmail-qmtpd: \
  37. -load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \
  38. +load qmail-qmtpd.o realrcptto.o rcpthosts.o control.o constmap.o received.o \
  39. date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a open.a \
  40. getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \
  41. -str.a fs.a auto_qmail.o dns.o ip.o ipalloc.o ipme.o byte_diff.o
  42. - ./load qmail-qmtpd rcpthosts.o control.o constmap.o \
  43. +str.a fs.a auto_qmail.o dns.o ip.o ipalloc.o ipme.o byte_diff.o auto_break.o auto_usera.o
  44. + ./load qmail-qmtpd realrcptto.o rcpthosts.o control.o constmap.o \
  45. received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
  46. datetime.a open.a getln.a sig.a case.a env.a stralloc.a \
  47. - alloc.a substdio.a error.a fs.a auto_qmail.o dns.o \
  48. + alloc.a substdio.a error.a fs.a auto_qmail.o dns.o auto_break.o auto_usera.o \
  49. `cat dns.lib` ip.o ipalloc.o ipme.o byte_diff.o str.a
  50.  
  51. qmail-qmtpd.0: \
  52. qmail-qmtpd.8
  53. @@ -1614,18 +1614,18 @@
  54. ./compile qmail-showctl.c
  55.  
  56. qmail-smtpd: \
  57. -load qmail-smtpd.o rcpthosts.o qregex.o commands.o timeoutread.o \
  58. +load qmail-smtpd.o realrcptto.o rcpthosts.o qregex.o commands.o timeoutread.o \
  59. timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
  60. date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
  61. open.a sig.a case.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \
  62. -fs.a auto_qmail.o base64.o qmail-spp.o socket.lib dns.o ip.o ipalloc.o
  63. - ./load qmail-smtpd qregex.o rcpthosts.o commands.o timeoutread.o \
  64. +fs.a auto_qmail.o base64.o qmail-spp.o auto_break.o auto_usera.o socket.lib dns.o ip.o ipalloc.o
  65. + ./load qmail-smtpd realrcptto.o qregex.o rcpthosts.o commands.o timeoutread.o \
  66. timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
  67. tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \
  68. received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
  69. datetime.a getln.a open.a sig.a case.a qmail-spp.o env.a stralloc.a \
  70. - alloc.a strerr.a substdio.a error.a fs.a auto_qmail.o base64.o `cat \
  71. - socket.lib` dns.o str.a `cat dns.lib`
  72. + alloc.a strerr.a substdio.a error.a fs.a auto_qmail.o base64.o auto_break.o \
  73. + auto_usera.o `cat socket.lib` dns.o str.a `cat dns.lib`
  74.  
  75. qmail-smtpd.0: \
  76. qmail-smtpd.8
  77. @@ -1774,6 +1774,11 @@
  78. auto_split.h
  79. ./compile readsubdir.c
  80.  
  81. +realrcptto.o: \
  82. +compile realrcptto.c auto_break.h auto_usera.h byte.h case.h cdb.h \
  83. +constmap.h error.h fmt.h open.h str.h stralloc.h uint32.h
  84. + ./compile realrcptto.c
  85. +
  86. received.o: \
  87. compile received.c fmt.h qmail.h substdio.h now.h datetime.h \
  88. datetime.h date822fmt.h received.h
  89. diff -Naur qmail-qmtpd.c.orig qmail-qmtpd.c
  90. --- qmail-qmtpd.c.orig 1998-06-15 06:52:55.000000000 -0400
  91. +++ qmail-qmtpd.c 2006-12-08 03:21:25.000000000 -0500
  92. @@ -14,6 +14,15 @@
  93.  
  94. void badproto() { _exit(100); }
  95. void resources() { _exit(111); }
  96. +void die_nomem() { resources(); }
  97. +void die_control() { resources(); }
  98. +void die_cdb() { resources(); }
  99. +void die_sys() { resources(); }
  100. +
  101. +extern void realrcptto_init();
  102. +extern void realrcptto_start();
  103. +extern int realrcptto();
  104. +extern int realrcptto_deny();
  105.  
  106. int safewrite(fd,buf,len) int fd; char *buf; int len;
  107. {
  108. @@ -98,6 +107,8 @@
  109. if (rcpthosts_init() == -1) resources();
  110. relayclient = env_get("RELAYCLIENT");
  111. relayclientlen = relayclient ? str_len(relayclient) : 0;
  112. +
  113. + realrcptto_init();
  114.  
  115. if (control_readint(&databytes,"control/databytes") == -1) resources();
  116. x = env_get("DATABYTES");
  117. @@ -114,6 +125,7 @@
  118. if (!local) local = "unknown";
  119.  
  120. for (;;) {
  121. + realrcptto_start();
  122. if (!stralloc_copys(&failure,"")) resources();
  123. flagsenderok = 1;
  124.  
  125. @@ -216,6 +228,10 @@
  126. case -1: resources();
  127. case 0: failure.s[failure.len - 1] = 'D';
  128. }
  129. +
  130. + if (!failure.s[failure.len - 1])
  131. + if (!realrcptto(buf))
  132. + failure.s[failure.len - 1] = 'D';
  133.  
  134. if (!failure.s[failure.len - 1]) {
  135. qmail_to(&qq,buf);
  136. @@ -231,6 +247,7 @@
  137. result = qmail_close(&qq);
  138. if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)";
  139. if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
  140. + if (!relayclient && realrcptto_deny()) result = "Dsorry, no mailbox here by that name. (#5.1.1)\r\n";
  141.  
  142. if (*result)
  143. len = str_len(result);
  144. diff -Naur qmail-smtpd.c.orig qmail-smtpd.c
  145. --- qmail-smtpd.c.orig 1998-06-15 06:52:55.000000000 -0400
  146. +++ qmail-smtpd.c 2006-12-09 04:02:00.000000000 -0500
  147. @@ -111,12 +111,24 @@
  148. void die_ipme()
  149. {
  150. enew(); eout("Unable to figure out my IP addresses!\n");
  151. out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush();
  152. eflush(); _exit(1);
  153. }
  154. +void die_cdb()
  155. +{
  156. + enew(); eout("Unable to read cdb user database!\n");
  157. + out("421 unable to read cdb user database (#4.3.0)\r\n"); flush();
  158. + eflush(); _exit(1);
  159. +}
  160. +void die_sys()
  161. +{
  162. + enew(); eout("Unable to read system user database!\n");
  163. + out("421 unable to read system user database (#4.3.0)\r\n"); flush();
  164. + eflush(); _exit(1);
  165. +}
  166. void straynewline()
  167. {
  168. enew(); eout("Stray newline from "); eout(remoteip); eout(".\n");
  169. out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush();
  170. eflush(); _exit(1);
  171. }
  172. @@ -161,6 +173,13 @@
  173. int err_wantstarttls() { out("530 Must issue a STARTTLS command first (#5.7.0)\r\n"); return -1; };
  174. void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
  175.  
  176. +extern void realrcptto_init();
  177. +extern void realrcptto_start();
  178. +extern int realrcptto();
  179. +extern int realrcptto_deny();
  180. +
  181. +int flagauth = 0;
  182. +
  183. stralloc greeting = {0};
  184.  
  185. void smtp_greet(code) char *code;
  186. @@ -259,7 +259,8 @@
  187. fdmbrt = open_read("control/morebadrcptto.cdb");
  188. if (fdmbrt == -1) if (errno != error_noent) die_control();
  189.  
  190.  
  191. + realrcptto_init();
  192.  
  193. if (control_readint(&databytes,"control/databytes") == -1) die_control();
  194. x = env_get("DATABYTES");
  195. @@ -635,7 +635,8 @@
  196. if (!stralloc_copys(&rcptto,"")) die_nomem();
  197. if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
  198. if (!stralloc_0(&mailfrom)) die_nomem();
  199. + realrcptto_start();
  200. recipcount = 0;
  201. out("250 ok\r\n");
  202. }
  203. void smtp_rcpt(arg) char *arg; {
  204. @@ -680,5 +701,9 @@
  205. flagbrt = 1;
  206. log_deny("BAD RCPT TO", mailfrom.s,addr.s);
  207. }
  208. + if (!flagauth && !relayclient && !realrcptto(addr.s)) {
  209. + out("554 sorry, no mailbox here by that name. (#5.1.1)\r\n");
  210. + return;
  211. + }
  212. if (!(spp_val = spp_rcpt(allowed))) return;
  213. if (!relayclient && spp_val == 1) {
  214. @@ -899,6 +899,7 @@
  215. if (mailfrom.len == 1 && recipcount > 1) { err_badbounce(); return; }
  216. if (flagbrt) { err_brt(); return; }
  217. if (!spp_data()) return;
  218. + if (!relayclient && realrcptto_deny()) { out("550 sorry, no mailbox here by that name. (#5.1.1)\r\n"); return; }
  219. seenmail = 0;
  220. if (databytes) bytestooverflow = databytes + 1;
  221. if (qmail_open(&qqt) == -1) { err_qqt(); return; }
  222. @@ -961,6 +961,5 @@
  223. static stralloc slop = {0}; /* b64 challenge */
  224. #endif
  225.  
  226. -int flagauth = 0;
  227. char **childargs;
  228. char ssauthbuf[512];
  229. diff -Naur realrcptto.c.orig realrcptto.c
  230. --- realrcptto.c.orig 1969-12-31 19:00:00.000000000 -0500
  231. +++ realrcptto.c 2006-12-09 18:33:04.000000000 -0500
  232. @@ -0,0 +1,343 @@
  233. +#include <sys/types.h>
  234. +#include <sys/stat.h>
  235. +#include <unistd.h>
  236. +#include <pwd.h>
  237. +#include "auto_break.h"
  238. +#include "auto_usera.h"
  239. +#include "byte.h"
  240. +#include "case.h"
  241. +#include "cdb.h"
  242. +#include "constmap.h"
  243. +#include "error.h"
  244. +#include "fmt.h"
  245. +#include "open.h"
  246. +#include "str.h"
  247. +#include "stralloc.h"
  248. +#include "uint32.h"
  249. +#include "substdio.h"
  250. +#include "env.h"
  251. +
  252. +extern void die_nomem();
  253. +extern void die_control();
  254. +extern void die_cdb();
  255. +extern void die_sys();
  256. +
  257. +static stralloc envnoathost = {0};
  258. +static stralloc percenthack = {0};
  259. +static stralloc locals = {0};
  260. +static stralloc vdoms = {0};
  261. +static struct constmap mappercenthack;
  262. +static struct constmap maplocals;
  263. +static struct constmap mapvdoms;
  264. +
  265. +static char *dash;
  266. +static char *extension;
  267. +static char *local;
  268. +static struct passwd *pw;
  269. +
  270. +static char errbuf[128];
  271. +static struct substdio sserr = SUBSTDIO_FDBUF(write,2,errbuf,sizeof errbuf);
  272. +
  273. +static char pidbuf[64];
  274. +static char remoteipbuf[64]=" ";
  275. +
  276. +static int flagdenyall;
  277. +static int flagdenyany;
  278. +
  279. +void realrcptto_init()
  280. +{
  281. + char *x;
  282. +
  283. + if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1)
  284. + die_control();
  285. +
  286. + if (control_readfile(&locals,"control/locals",1) != 1) die_control();
  287. + if (!constmap_init(&maplocals,locals.s,locals.len,0)) die_nomem();
  288. + switch(control_readfile(&percenthack,"control/percenthack",0)) {
  289. + case -1: die_control();
  290. + case 0: if (!constmap_init(&mappercenthack,"",0,0)) die_nomem();
  291. + case 1:
  292. + if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0))
  293. + die_nomem();
  294. + }
  295. + switch(control_readfile(&vdoms,"control/virtualdomains",0)) {
  296. + case -1: die_control();
  297. + case 0: if (!constmap_init(&mapvdoms,"",0,1)) die_nomem();
  298. + case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) die_nomem();
  299. + }
  300. +
  301. + str_copy(pidbuf + fmt_ulong(pidbuf,getpid())," ");
  302. + x=env_get("PROTO");
  303. + if (x) {
  304. + static char const remoteip[]="REMOTEIP";
  305. + unsigned int len = str_len(x);
  306. + if (len <= sizeof remoteipbuf - sizeof remoteip) {
  307. + byte_copy(remoteipbuf,len,x);
  308. + byte_copy(remoteipbuf + len,sizeof remoteip,remoteip);
  309. + x = env_get(remoteipbuf);
  310. + len = str_len(x);
  311. + if (len + 1 < sizeof remoteipbuf) {
  312. + byte_copy(remoteipbuf,len,x);
  313. + remoteipbuf[len]=' ';
  314. + remoteipbuf[len + 1]='\0';
  315. + }
  316. + }
  317. + }
  318. +
  319. + x = env_get("QMAILRRTDENYALL");
  320. + flagdenyall = (x && x[0]=='1' && x[1]=='\0');
  321. +}
  322. +
  323. +void realrcptto_start()
  324. +{
  325. + flagdenyany = 0;
  326. +}
  327. +
  328. +static int denyaddr(addr)
  329. +char *addr;
  330. +{
  331. + substdio_puts(&sserr,"realrcptto ");
  332. + substdio_puts(&sserr,pidbuf);
  333. + substdio_puts(&sserr,remoteipbuf);
  334. + substdio_puts(&sserr,addr);
  335. + substdio_puts(&sserr,"\n");
  336. + substdio_flush(&sserr);
  337. + flagdenyany = 1;
  338. + return flagdenyall;
  339. +}
  340. +
  341. +static void stat_error(path,error)
  342. +char* path;
  343. +int error;
  344. +{
  345. + substdio_puts(&sserr,"unable to stat ");
  346. + substdio_puts(&sserr,path);
  347. + substdio_puts(&sserr,": ");
  348. + substdio_puts(&sserr,error_str(error));
  349. + substdio_puts(&sserr,"\n");
  350. + substdio_flush(&sserr);
  351. +}
  352. +
  353. +#define GETPW_USERLEN 32
  354. +
  355. +static int userext()
  356. +{
  357. + char username[GETPW_USERLEN];
  358. + struct stat st;
  359. +
  360. + extension = local + str_len(local);
  361. + for (;;) {
  362. + if (extension - local < sizeof(username))
  363. + if (!*extension || (*extension == *auto_break)) {
  364. + byte_copy(username,extension - local,local);
  365. + username[extension - local] = 0;
  366. + case_lowers(username);
  367. + errno = 0;
  368. + pw = getpwnam(username);
  369. + if (errno == error_txtbsy) die_sys();
  370. + if (pw)
  371. + if (pw->pw_uid)
  372. + if (stat(pw->pw_dir,&st) == 0) {
  373. + if (st.st_uid == pw->pw_uid) {
  374. + dash = "";
  375. + if (*extension) { ++extension; dash = "-"; }
  376. + return 1;
  377. + }
  378. + }
  379. + else
  380. + if (error_temp(errno)) die_sys();
  381. + }
  382. + if (extension == local) return 0;
  383. + --extension;
  384. + }
  385. +}
  386. +
  387. +int realrcptto(addr)
  388. +char *addr;
  389. +{
  390. + char *homedir;
  391. + static stralloc localpart = {0};
  392. + static stralloc lower = {0};
  393. + static stralloc nughde = {0};
  394. + static stralloc wildchars = {0};
  395. + static stralloc safeext = {0};
  396. + static stralloc qme = {0};
  397. + unsigned int i,at;
  398. +
  399. + /* Short circuit, or full logging? Short circuit. */
  400. + if (flagdenyall && flagdenyany) return 1;
  401. +
  402. + /* qmail-send:rewrite */
  403. + if (!stralloc_copys(&localpart,addr)) die_nomem();
  404. + i = byte_rchr(localpart.s,localpart.len,'@');
  405. + if (i == localpart.len) {
  406. + if (!stralloc_cats(&localpart,"@")) die_nomem();
  407. + if (!stralloc_cat(&localpart,&envnoathost)) die_nomem();
  408. + }
  409. + while (constmap(&mappercenthack,localpart.s + i + 1,localpart.len - i - 1)) {
  410. + unsigned int j = byte_rchr(localpart.s,i,'%');
  411. + if (j == i) break;
  412. + localpart.len = i;
  413. + i = j;
  414. + localpart.s[i] = '@';
  415. + }
  416. + at = byte_rchr(localpart.s,localpart.len,'@');
  417. + if (constmap(&maplocals,localpart.s + at + 1,localpart.len - at - 1)) {
  418. + localpart.len = at;
  419. + localpart.s[at] = '\0';
  420. + } else {
  421. + unsigned int xlen,newlen;
  422. + char *x;
  423. + for (i = 0;;++i) {
  424. + if (i > localpart.len) return denyaddr(addr);
  425. + if (!i || (i == at + 1) || (i == localpart.len) ||
  426. + ((i > at) && (localpart.s[i] == '.'))) {
  427. + x = constmap(&mapvdoms,localpart.s + i,localpart.len - i);
  428. + if (x && i == at + 1) {
  429. + char *qmailqueue;
  430. + qmailqueue = env_get("QMAILQUEUE");
  431. + if (qmailqueue) {
  432. + if (!env_put("QMAILQUEUE=bin/qmail-queue")) die_nomem();
  433. + }
  434. + }
  435. + if (x) break;
  436. + }
  437. + }
  438. + if (!*x) return 1;
  439. + xlen = str_len(x) + 1; /* +1 for '-' */
  440. + newlen = xlen + at + 1; /* +1 for \0 */
  441. + if (xlen < 1 || newlen - 1 < xlen || newlen < 1 ||
  442. + !stralloc_ready(&localpart,newlen))
  443. + die_nomem();
  444. + localpart.s[newlen - 1] = '\0';
  445. + byte_copyr(localpart.s + xlen,at,localpart.s);
  446. + localpart.s[xlen - 1] = '-';
  447. + byte_copy(localpart.s,xlen - 1,x);
  448. + localpart.len = newlen;
  449. + }
  450. +
  451. + /* qmail-lspawn:nughde_get */
  452. + {
  453. + int r,fd,flagwild;
  454. + if (!stralloc_copys(&lower,"!")) die_nomem();
  455. + if (!stralloc_cats(&lower,localpart.s)) die_nomem();
  456. + if (!stralloc_0(&lower)) die_nomem();
  457. + case_lowerb(lower.s,lower.len);
  458. + if (!stralloc_copys(&nughde,"")) die_nomem();
  459. + fd = open_read("users/cdb");
  460. + if (fd == -1) {
  461. + if (errno != error_noent) die_cdb();
  462. + } else {
  463. + uint32 dlen;
  464. + r = cdb_seek(fd,"",0,&dlen);
  465. + if (r != 1) die_cdb();
  466. + if (!stralloc_ready(&wildchars,(unsigned int) dlen)) die_nomem();
  467. + wildchars.len = dlen;
  468. + if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) die_cdb();
  469. + i = lower.len;
  470. + flagwild = 0;
  471. + do { /* i > 0 */
  472. + if (!flagwild || (i == 1) ||
  473. + (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1])
  474. + < wildchars.len)) {
  475. + r = cdb_seek(fd,lower.s,i,&dlen);
  476. + if (r == -1) die_cdb();
  477. + if (r == 1) {
  478. + char *x;
  479. + if (!stralloc_ready(&nughde,(unsigned int) dlen)) die_nomem();
  480. + nughde.len = dlen;
  481. + if (cdb_bread(fd,nughde.s,nughde.len) == -1) die_cdb();
  482. + if (flagwild)
  483. + if (!stralloc_cats(&nughde,localpart.s + i - 1)) die_nomem();
  484. + if (!stralloc_0(&nughde)) die_nomem();
  485. + close(fd);
  486. + x=nughde.s;
  487. + /* skip username */
  488. + x += byte_chr(x,nughde.s + nughde.len - x,'\0');
  489. + if (x == nughde.s + nughde.len) return 1;
  490. + ++x;
  491. + /* skip uid */
  492. + x += byte_chr(x,nughde.s + nughde.len - x,'\0');
  493. + if (x == nughde.s + nughde.len) return 1;
  494. + ++x;
  495. + /* skip gid */
  496. + x += byte_chr(x,nughde.s + nughde.len - x,'\0');
  497. + if (x == nughde.s + nughde.len) return 1;
  498. + ++x;
  499. + /* skip homedir */
  500. + homedir=x;
  501. + x += byte_chr(x,nughde.s + nughde.len - x,'\0');
  502. + if (x == nughde.s + nughde.len) return 1;
  503. + ++x;
  504. + /* skip dash */
  505. + dash=x;
  506. + x += byte_chr(x,nughde.s + nughde.len - x,'\0');
  507. + if (x == nughde.s + nughde.len) return 1;
  508. + ++x;
  509. + extension=x;
  510. + goto got_nughde;
  511. + }
  512. + }
  513. + --i;
  514. + flagwild = 1;
  515. + } while (i);
  516. + close(fd);
  517. + }
  518. + }
  519. +
  520. + /* qmail-getpw */
  521. + local = localpart.s;
  522. + if (!userext()) {
  523. + extension = local;
  524. + dash = "-";
  525. + pw = getpwnam(auto_usera);
  526. + }
  527. + if (!pw) return denyaddr(addr);
  528. + if (!stralloc_copys(&nughde,pw->pw_dir)) die_nomem();
  529. + if (!stralloc_0(&nughde)) die_nomem();
  530. + homedir=nughde.s;
  531. +
  532. + got_nughde:
  533. +
  534. + /* qmail-local:qmesearch */
  535. + if (!*dash) return 1;
  536. + if (!stralloc_copys(&safeext,extension)) die_nomem();
  537. + case_lowerb(safeext.s,safeext.len);
  538. + for (i = 0;i < safeext.len;++i)
  539. + if (safeext.s[i] == '.')
  540. + safeext.s[i] = ':';
  541. + {
  542. + struct stat st;
  543. + int i;
  544. + if (!stralloc_copys(&qme,homedir)) die_nomem();
  545. + if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
  546. + if (!stralloc_cats(&qme,dash)) die_nomem();
  547. + if (!stralloc_cat(&qme,&safeext)) die_nomem();
  548. + if (!stralloc_0(&qme)) die_nomem();
  549. + if (stat(qme.s,&st) == 0) return 1;
  550. + if (errno != error_noent) {
  551. + stat_error(qme.s,errno);
  552. + return 1;
  553. + }
  554. + for (i = safeext.len;i >= 0;--i)
  555. + if (!i || (safeext.s[i - 1] == '-')) {
  556. + if (!stralloc_copys(&qme,homedir)) die_nomem();
  557. + if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
  558. + if (!stralloc_cats(&qme,dash)) die_nomem();
  559. + if (!stralloc_catb(&qme,safeext.s,i)) die_nomem();
  560. + if (!stralloc_cats(&qme,"default")) die_nomem();
  561. + if (!stralloc_0(&qme)) die_nomem();
  562. + if (stat(qme.s,&st) == 0) return 1;
  563. + if (errno != error_noent) {
  564. + stat_error(qme.s,errno);
  565. + return 1;
  566. + }
  567. + }
  568. + return denyaddr(addr);
  569. + }
  570. +}
  571. +
  572. +int realrcptto_deny()
  573. +{
  574. + return flagdenyall && flagdenyany;
  575. +}
  576.