Download | Plain Text | No Line Numbers


  1. qregex-starttls-2way-auth-20060423.patch
  2.  
  3. This patch is a combination of five patches that together provide the
  4. following features:
  5. secure SMTP communication using starttls
  6. authenticated SMTP for both the server and client side of connections
  7. SMTP connection filtering by pattern matching of envelope senders and recipients
  8. logging of canonicalised recipients by qmail-remote
  9.  
  10. The five patches are:
  11. netqmail-1.05-tls-20070408 <http://inoa.net/qmail-tls/>
  12. qmail-smtpd-auth-057 <http://www.fehcom.de/qmail/smtpauth.html>
  13. qmail-remote_authenticated_smtp <http://www.ornl.gov/lists/mailing-lists/qmail/2002/03/msg00091.html>
  14. qregex-20060423 <http://www.arda.homeunix.net/store/qmail/>
  15. canonicalised-recipient-logging <http://romana.now.ie/#rcpt-logging>
  16.  
  17. The version of qmail-remote_authenticated_smtp patch used here is the one
  18. modified by Robert Sander. Qmail-remote does the base64 encoding so the
  19. username and password appear as clear text in control/smtproutes.
  20.  
  21. The version of qregex used here ignores empty envelope senders
  22. ('mail from' command). Empty envelope senders will not be compared to any
  23. regular expressions in the badmailfrom control file and will always be accepted
  24. by qregex.
  25.  
  26. I've made the following changes to the patches:
  27. * The files README.auth, README.remote-auth, and README.starttls are copied to
  28. the qmail/doc directory when qmail is installed.
  29. * I've changed the way that the qmail-remote_authenticated_smtp patch logs
  30. notifications that authentication isn't being used. The way the patch was
  31. doing it originally could result in lost mail or non-delivery
  32. notifications not being sent under certain circumstances.
  33. * I've added two lines to qmail-remote.c to fix another problem with the
  34. qmail-remote_authenticated_smtp patch. These two lines set the auth_status
  35. stralloc when remote authentication is used.
  36. * I've removed two lines from qmail-smtpd.c put there by the qmail-smtpd-auth
  37. patch. This was necessary to let the patch work with the starttls patch.
  38. As a consequence, TLS will not be reported in Received headers when
  39. ESMTPA is used.
  40.  
  41. This patch applies cleanly to the following:
  42. netqmail-1.05
  43.  
  44. To apply the patch, unpack the package, run the collate.sh script, and then cd
  45. into the netqmail-1.05 source tree.
  46. Run this command:
  47.  
  48. patch < /path/to/patchfile
  49.  
  50. To apply the patch to qmail-1.03 or netqmail-1.04, you need to increase patch's fuzz factor.
  51. This works for me.
  52.  
  53. patch -F 3 < /path/to/patchfile
  54.  
  55. Enjoy!
  56.  
  57. This combination patch was prepared by:
  58. Andrew St. Jean <andrew@arda.homeunix.net>
  59. <http://www.arda.homeunix.net/store/qmail/>
  60.  
  61. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/base64.c ./netqmail-1.05/netqmail-1.05/base64.c
  62. --- ./netqmail-1.05.orig/netqmail-1.05/base64.c 1969-12-31 19:00:00.000000000 -0500
  63. +++ ./netqmail-1.05/netqmail-1.05/base64.c 2006-05-10 19:28:51.219866097 -0400
  64. @@ -0,0 +1,122 @@
  65. +#include "base64.h"
  66. +#include "stralloc.h"
  67. +#include "substdio.h"
  68. +#include "str.h"
  69. +
  70. +static char *b64alpha =
  71. + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  72. +#define B64PAD '='
  73. +
  74. +/* returns 0 ok, 1 illegal, -1 problem */
  75. +
  76. +int b64decode(in,l,out)
  77. +const unsigned char *in;
  78. +int l;
  79. +stralloc *out; /* not null terminated */
  80. +{
  81. + int p = 0;
  82. + int n;
  83. + unsigned int x;
  84. + int i, j;
  85. + char *s;
  86. + unsigned char b[3];
  87. +
  88. + if (l == 0)
  89. + {
  90. + if (!stralloc_copys(out,"")) return -1;
  91. + return 0;
  92. + }
  93. +
  94. + while(in[l-1] == B64PAD) {
  95. + p ++;
  96. + l--;
  97. + }
  98. +
  99. + n = (l + p) / 4;
  100. + out->len = (n * 3) - p;
  101. + if (!stralloc_ready(out,out->len)) return -1;
  102. + s = out->s;
  103. +
  104. + for(i = 0; i < n - 1 ; i++) {
  105. + x = 0;
  106. + for(j = 0; j < 4; j++) {
  107. + if(in[j] >= 'A' && in[j] <= 'Z')
  108. + x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
  109. + else if(in[j] >= 'a' && in[j] <= 'z')
  110. + x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
  111. + else if(in[j] >= '0' && in[j] <= '9')
  112. + x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
  113. + else if(in[j] == '+')
  114. + x = (x << 6) + 62;
  115. + else if(in[j] == '/')
  116. + x = (x << 6) + 63;
  117. + else if(in[j] == '=')
  118. + x = (x << 6);
  119. + }
  120. +
  121. + s[2] = (unsigned char)(x & 255); x >>= 8;
  122. + s[1] = (unsigned char)(x & 255); x >>= 8;
  123. + s[0] = (unsigned char)(x & 255); x >>= 8;
  124. + s += 3; in += 4;
  125. + }
  126. +
  127. + x = 0;
  128. + for(j = 0; j < 4; j++) {
  129. + if(in[j] >= 'A' && in[j] <= 'Z')
  130. + x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
  131. + else if(in[j] >= 'a' && in[j] <= 'z')
  132. + x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
  133. + else if(in[j] >= '0' && in[j] <= '9')
  134. + x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
  135. + else if(in[j] == '+')
  136. + x = (x << 6) + 62;
  137. + else if(in[j] == '/')
  138. + x = (x << 6) + 63;
  139. + else if(in[j] == '=')
  140. + x = (x << 6);
  141. + }
  142. +
  143. + b[2] = (unsigned char)(x & 255); x >>= 8;
  144. + b[1] = (unsigned char)(x & 255); x >>= 8;
  145. + b[0] = (unsigned char)(x & 255); x >>= 8;
  146. +
  147. + for(i = 0; i < 3 - p; i++)
  148. + s[i] = b[i];
  149. +
  150. + return 0;
  151. +}
  152. +
  153. +int b64encode(in,out)
  154. +stralloc *in;
  155. +stralloc *out; /* not null terminated */
  156. +{
  157. + unsigned char a, b, c;
  158. + int i;
  159. + char *s;
  160. +
  161. + if (in->len == 0)
  162. + {
  163. + if (!stralloc_copys(out,"")) return -1;
  164. + return 0;
  165. + }
  166. +
  167. + if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1;
  168. + s = out->s;
  169. +
  170. + for (i = 0;i < in->len;i += 3) {
  171. + a = in->s[i];
  172. + b = i + 1 < in->len ? in->s[i + 1] : 0;
  173. + c = i + 2 < in->len ? in->s[i + 2] : 0;
  174. +
  175. + *s++ = b64alpha[a >> 2];
  176. + *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)];
  177. +
  178. + if (i + 1 >= in->len) *s++ = B64PAD;
  179. + else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)];
  180. +
  181. + if (i + 2 >= in->len) *s++ = B64PAD;
  182. + else *s++ = b64alpha[c & 63];
  183. + }
  184. + out->len = s - out->s;
  185. + return 0;
  186. +}
  187. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/base64.h ./netqmail-1.05/netqmail-1.05/base64.h
  188. --- ./netqmail-1.05.orig/netqmail-1.05/base64.h 1969-12-31 19:00:00.000000000 -0500
  189. +++ ./netqmail-1.05/netqmail-1.05/base64.h 2006-05-10 19:28:51.219866097 -0400
  190. @@ -0,0 +1,7 @@
  191. +#ifndef BASE64_H
  192. +#define BASE64_H
  193. +
  194. +extern int b64decode();
  195. +extern int b64encode();
  196. +
  197. +#endif
  198. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/case_startb.c ./netqmail-1.05/netqmail-1.05/case_startb.c
  199. --- ./netqmail-1.05.orig/netqmail-1.05/case_startb.c 1969-12-31 19:00:00.000000000 -0500
  200. +++ ./netqmail-1.05/netqmail-1.05/case_startb.c 2006-05-10 19:28:51.219866097 -0400
  201. @@ -0,0 +1,21 @@
  202. +#include "case.h"
  203. +
  204. +int case_startb(s,len,t)
  205. +register char *s;
  206. +unsigned int len;
  207. +register char *t;
  208. +{
  209. + register unsigned char x;
  210. + register unsigned char y;
  211. +
  212. + for (;;) {
  213. + y = *t++ - 'A';
  214. + if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
  215. + if (!y) return 1;
  216. + if (!len) return 0;
  217. + --len;
  218. + x = *s++ - 'A';
  219. + if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
  220. + if (x != y) return 0;
  221. + }
  222. +}
  223. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/conf-cc ./netqmail-1.05/netqmail-1.05/conf-cc
  224. --- ./netqmail-1.05.orig/netqmail-1.05/conf-cc 1998-06-15 06:53:16.000000000 -0400
  225. +++ ./netqmail-1.05/netqmail-1.05/conf-cc 2006-05-10 19:28:51.220865921 -0400
  226. @@ -1,3 +1,3 @@
  227. -cc -O2
  228. +cc -O2 -DTLS=20070408 -I/usr/local/ssl/include
  229.  
  230. This will be used to compile .c files.
  231. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/dns.c ./netqmail-1.05/netqmail-1.05/dns.c
  232. --- ./netqmail-1.05.orig/netqmail-1.05/dns.c 2004-06-04 21:51:58.000000000 -0400
  233. +++ ./netqmail-1.05/netqmail-1.05/dns.c 2006-05-10 19:28:51.220865921 -0400
  234. @@ -267,12 +267,11 @@
  235. int pref;
  236. {
  237. int r;
  238. - struct ip_mx ix;
  239. + struct ip_mx ix = {0};
  240.  
  241. if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  242. if (!stralloc_0(&glue)) return DNS_MEM;
  243. if (glue.s[0]) {
  244. - ix.pref = 0;
  245. if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
  246. {
  247. if (!ipalloc_append(ia,&ix)) return DNS_MEM;
  248. @@ -291,9 +290,16 @@
  249. ix.ip = ip;
  250. ix.pref = pref;
  251. if (r == DNS_SOFT) return DNS_SOFT;
  252. - if (r == 1)
  253. + if (r == 1) {
  254. +#ifdef IX_FQDN
  255. + ix.fqdn = glue.s;
  256. +#endif
  257. if (!ipalloc_append(ia,&ix)) return DNS_MEM;
  258. }
  259. + }
  260. +#ifdef IX_FQDN
  261. + glue.s = 0;
  262. +#endif
  263. return 0;
  264. }
  265.  
  266. @@ -313,7 +319,7 @@
  267. {
  268. int r;
  269. struct mx { stralloc sa; unsigned short p; } *mx;
  270. - struct ip_mx ix;
  271. + struct ip_mx ix = {0};
  272. int nummx;
  273. int i;
  274. int j;
  275. @@ -325,7 +331,6 @@
  276. if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  277. if (!stralloc_0(&glue)) return DNS_MEM;
  278. if (glue.s[0]) {
  279. - ix.pref = 0;
  280. if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
  281. {
  282. if (!ipalloc_append(ia,&ix)) return DNS_MEM;
  283. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/hier.c ./netqmail-1.05/netqmail-1.05/hier.c
  284. --- ./netqmail-1.05.orig/netqmail-1.05/hier.c 1998-06-15 06:53:16.000000000 -0400
  285. +++ ./netqmail-1.05/netqmail-1.05/hier.c 2006-05-10 20:09:44.858547363 -0400
  286. @@ -76,6 +76,10 @@
  287. c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
  288.  
  289. c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
  290. + c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
  291. + c(auto_qmail,"doc","README.auth",auto_uido,auto_gidq,0644);
  292. + c(auto_qmail,"doc","README.remote-auth",auto_uido,auto_gidq,0644);
  293. + c(auto_qmail,"doc","README.starttls",auto_uido,auto_gidq,0644);
  294. c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
  295. c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
  296. c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
  297. @@ -143,6 +147,9 @@
  298. c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755);
  299. c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755);
  300. c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
  301. +#ifdef TLS
  302. + c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755);
  303. +#endif
  304.  
  305. c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
  306. c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
  307. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/install-big.c ./netqmail-1.05/netqmail-1.05/install-big.c
  308. --- ./netqmail-1.05.orig/netqmail-1.05/install-big.c 1998-06-15 06:53:16.000000000 -0400
  309. +++ ./netqmail-1.05/netqmail-1.05/install-big.c 2006-05-10 20:10:18.298648290 -0400
  310. @@ -76,6 +76,10 @@
  311. c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
  312.  
  313. c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
  314. + c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
  315. + c(auto_qmail,"doc","README.auth",auto_uido,auto_gidq,0644);
  316. + c(auto_qmail,"doc","README.remote-auth",auto_uido,auto_gidq,0644);
  317. + c(auto_qmail,"doc","README.starttls",auto_uido,auto_gidq,0644);
  318. c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
  319. c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
  320. c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
  321. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/ipalloc.h ./netqmail-1.05/netqmail-1.05/ipalloc.h
  322. --- ./netqmail-1.05.orig/netqmail-1.05/ipalloc.h 1998-06-15 06:53:16.000000000 -0400
  323. +++ ./netqmail-1.05/netqmail-1.05/ipalloc.h 2006-05-10 19:28:51.222865569 -0400
  324. @@ -3,7 +3,15 @@
  325.  
  326. #include "ip.h"
  327.  
  328. +#ifdef TLS
  329. +# define IX_FQDN 1
  330. +#endif
  331. +
  332. +#ifdef IX_FQDN
  333. +struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
  334. +#else
  335. struct ip_mx { struct ip_address ip; int pref; } ;
  336. +#endif
  337.  
  338. #include "gen_alloc.h"
  339.  
  340. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/Makefile ./netqmail-1.05/netqmail-1.05/Makefile
  341. --- ./netqmail-1.05.orig/netqmail-1.05/Makefile 2004-06-04 21:51:58.000000000 -0400
  342. +++ ./netqmail-1.05/netqmail-1.05/Makefile 2006-05-10 20:12:41.649359367 -0400
  343. @@ -136,6 +136,10 @@
  344. compile auto_usera.c
  345. ./compile auto_usera.c
  346.  
  347. +base64.o: \
  348. +compile base64.c base64.h stralloc.h substdio.h str.h
  349. + ./compile base64.c
  350. +
  351. binm1: \
  352. binm1.sh conf-qmail
  353. cat binm1.sh \
  354. @@ -808,7 +812,7 @@
  355. forward preline condredirect bouncesaying except maildirmake \
  356. maildir2mbox maildirwatch qail elq pinq idedit install-big install \
  357. instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
  358. -binm3 binm3+df
  359. +binm3 binm3+df update_tmprsadh
  360.  
  361. load: \
  362. make-load warn-auto.sh systype
  363. @@ -1441,12 +1445,13 @@
  364. load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
  365. timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
  366. ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
  367. -substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
  368. +substdio.a error.a str.a fs.a auto_qmail.o base64.o dns.lib socket.lib
  369. ./load qmail-remote control.o constmap.o timeoutread.o \
  370. timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
  371. + tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \
  372. ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
  373. lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
  374. - str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
  375. + str.a fs.a auto_qmail.o base64.o `cat dns.lib` `cat socket.lib`
  376.  
  377. qmail-remote.0: \
  378. qmail-remote.8
  379. @@ -1532,16 +1537,17 @@
  380. ./compile qmail-showctl.c
  381.  
  382. qmail-smtpd: \
  383. -load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
  384. +load qmail-smtpd.o rcpthosts.o qregex.o commands.o timeoutread.o \
  385. timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
  386. date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
  387. -open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
  388. -fs.a auto_qmail.o socket.lib
  389. - ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
  390. +open.a sig.a case.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \
  391. +fs.a auto_qmail.o base64.o socket.lib
  392. + ./load qmail-smtpd qregex.o rcpthosts.o commands.o timeoutread.o \
  393. timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
  394. + tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \
  395. received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
  396. datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
  397. - alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \
  398. + alloc.a strerr.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \
  399. socket.lib`
  400.  
  401. qmail-smtpd.0: \
  402. @@ -1553,7 +1559,7 @@
  403. substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \
  404. error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \
  405. substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \
  406. -exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h
  407. +exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h
  408. ./compile qmail-smtpd.c
  409.  
  410. qmail-start: \
  411. @@ -1681,6 +1687,10 @@
  412. constmap.h stralloc.h gen_alloc.h rcpthosts.h
  413. ./compile rcpthosts.c
  414.  
  415. +qregex.o: \
  416. +compile qregex.c qregex.h
  417. + ./compile qregex.c
  418. +
  419. readsubdir.o: \
  420. compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \
  421. auto_split.h
  422. @@ -1827,7 +1837,8 @@
  423. ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
  424. ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \
  425. prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \
  426. -maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c
  427. +maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c \
  428. +update_tmprsadh
  429. shar -m `cat FILES` > shar
  430. chmod 400 shar
  431.  
  432. @@ -2108,6 +2119,19 @@
  433. compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
  434. ./compile timeoutwrite.c
  435.  
  436. +qmail-smtpd: tls.o ssl_timeoutio.o ndelay.a
  437. +qmail-remote: tls.o ssl_timeoutio.o
  438. +qmail-smtpd.o: tls.h ssl_timeoutio.h
  439. +qmail-remote.o: tls.h ssl_timeoutio.h
  440. +
  441. +tls.o: \
  442. +compile tls.c exit.h error.h
  443. + ./compile tls.c
  444. +
  445. +ssl_timeoutio.o: \
  446. +compile ssl_timeoutio.c ssl_timeoutio.h select.h error.h ndelay.h
  447. + ./compile ssl_timeoutio.c
  448. +
  449. token822.o: \
  450. compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
  451. gen_alloc.h gen_allocdefs.h
  452. @@ -2139,3 +2163,26 @@
  453. wait_pid.o: \
  454. compile wait_pid.c error.h haswaitp.h
  455. ./compile wait_pid.c
  456. +
  457. +cert cert-req: \
  458. +Makefile-cert
  459. + @$(MAKE) -sf $< $@
  460. +
  461. +Makefile-cert: \
  462. +conf-qmail conf-users conf-groups Makefile-cert.mk
  463. + @cat Makefile-cert.mk \
  464. + | sed s}QMAIL}"`head -1 conf-qmail`"}g \
  465. + > $@
  466. +
  467. +update_tmprsadh: \
  468. +conf-qmail conf-users conf-groups update_tmprsadh.sh
  469. + @cat update_tmprsadh.sh\
  470. + | sed s}UGQMAILD}"`head -2 conf-users|tail -1`:`head -1 conf-groups`"}g \
  471. + | sed s}QMAIL}"`head -1 conf-qmail`"}g \
  472. + > $@
  473. + chmod 755 update_tmprsadh
  474. +
  475. +tmprsadh: \
  476. +update_tmprsadh
  477. + echo "Creating new temporary RSA and DH parameters"
  478. + ./update_tmprsadh
  479. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/Makefile-cert.mk ./netqmail-1.05/netqmail-1.05/Makefile-cert.mk
  480. --- ./netqmail-1.05.orig/netqmail-1.05/Makefile-cert.mk 1969-12-31 19:00:00.000000000 -0500
  481. +++ ./netqmail-1.05/netqmail-1.05/Makefile-cert.mk 2006-05-10 19:28:51.225865040 -0400
  482. @@ -0,0 +1,21 @@
  483. +cert-req: req.pem
  484. +cert cert-req: QMAIL/control/clientcert.pem
  485. + @:
  486. +
  487. +QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem
  488. + ln -s $< $@
  489. +
  490. +QMAIL/control/servercert.pem:
  491. + PATH=$$PATH:/usr/local/ssl/bin \
  492. + openssl req -new -x509 -nodes -days 366 -out $@ -keyout $@
  493. + chmod 640 $@
  494. + chown `head -2 conf-users | tail -1`:`head -1 conf-groups` $@
  495. +
  496. +req.pem:
  497. + PATH=$$PATH:/usr/local/ssl/bin openssl req \
  498. + -new -nodes -out $@ -keyout QMAIL/control/servercert.pem
  499. + chmod 640 QMAIL/control/servercert.pem
  500. + chown `head -2 conf-users | tail -1`:`head -1 conf-groups` QMAIL/control/servercert.pem
  501. + @echo
  502. + @echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
  503. + @echo "cat signed_req.pem >> QMAIL/control/servercert.pem"
  504. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qmail-control.9 ./netqmail-1.05/netqmail-1.05/qmail-control.9
  505. --- ./netqmail-1.05.orig/netqmail-1.05/qmail-control.9 1998-06-15 06:53:16.000000000 -0400
  506. +++ ./netqmail-1.05/netqmail-1.05/qmail-control.9 2006-05-10 19:29:13.782888633 -0400
  507. @@ -20,7 +20,11 @@
  508.  
  509. Comments are allowed
  510. in
  511. +.IR badhelo ,
  512. .IR badmailfrom ,
  513. +.IR badmailfromnorelay ,
  514. +.IR badmailto ,
  515. +.IR badmailtonorelay ,
  516. .IR locals ,
  517. .IR percenthack ,
  518. .IR qmqpservers ,
  519. @@ -40,14 +44,22 @@
  520. .ta 5c 10c
  521. control default used by
  522.  
  523. +.I badhelo \fR(none) \fRqmail-smtpd
  524. .I badmailfrom \fR(none) \fRqmail-smtpd
  525. +.I badmailfromnorelay \fR(none) \fRqmail-smtpd
  526. +.I badmailto \fR(none) \fRqmail-smtpd
  527. +.I badmailtonorelay \fR(none) \fRqmail-smtpd
  528. .I bouncefrom \fRMAILER-DAEMON \fRqmail-send
  529. .I bouncehost \fIme \fRqmail-send
  530. +.I clientca.pem \fR(none) \fRqmail-smtpd
  531. +.I clientcert.pem \fR(none) \fRqmail-remote
  532. .I concurrencylocal \fR10 \fRqmail-send
  533. .I concurrencyremote \fR20 \fRqmail-send
  534. .I defaultdomain \fIme \fRqmail-inject
  535. .I defaulthost \fIme \fRqmail-inject
  536. .I databytes \fR0 \fRqmail-smtpd
  537. +.I dh1024.pem \fR(none) \fRqmail-smtpd
  538. +.I dh512.pem \fR(none) \fRqmail-smtpd
  539. .I doublebouncehost \fIme \fRqmail-send
  540. .I doublebounceto \fRpostmaster \fRqmail-send
  541. .I envnoathost \fIme \fRqmail-send
  542. @@ -61,11 +73,17 @@
  543. .I qmqpservers \fR(none) \fRqmail-qmqpc
  544. .I queuelifetime \fR604800 \fRqmail-send
  545. .I rcpthosts \fR(none) \fRqmail-smtpd
  546. +.I rsa512.pem \fR(none) \fRqmail-smtpd
  547. +.I servercert.pem \fR(none) \fRqmail-smtpd
  548. .I smtpgreeting \fIme \fRqmail-smtpd
  549. .I smtproutes \fR(none) \fRqmail-remote
  550. .I timeoutconnect \fR60 \fRqmail-remote
  551. .I timeoutremote \fR1200 \fRqmail-remote
  552. .I timeoutsmtpd \fR1200 \fRqmail-smtpd
  553. +.I tlsclients \fR(none) \fRqmail-smtpd
  554. +.I tlsclientciphers \fR(none) \fRqmail-remote
  555. +.I tlshosts/FQDN.pem \fR(none) \fRqmail-remote
  556. +.I tlsserverciphers \fR(none) \fRqmail-smtpd
  557. .I virtualdomains \fR(none) \fRqmail-send
  558. .fi
  559. .RE
  560. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qmail-remote.8 ./netqmail-1.05/netqmail-1.05/qmail-remote.8
  561. --- ./netqmail-1.05.orig/netqmail-1.05/qmail-remote.8 1998-06-15 06:53:16.000000000 -0400
  562. +++ ./netqmail-1.05/netqmail-1.05/qmail-remote.8 2006-05-10 19:28:51.226864864 -0400
  563. @@ -114,6 +114,10 @@
  564. always exits zero.
  565. .SH "CONTROL FILES"
  566. .TP 5
  567. +.I clientcert.pem
  568. +SSL certificate that is used to authenticate with the remote server
  569. +during a TLS session.
  570. +.TP 5
  571. .I helohost
  572. Current host name,
  573. for use solely in saying hello to the remote SMTP server.
  574. @@ -123,6 +127,16 @@
  575. otherwise
  576. .B qmail-remote
  577. refuses to run.
  578. +
  579. +.TP 5
  580. +.I notlshosts/<FQDN>
  581. +.B qmail-remote
  582. +will not try TLS on servers for which this file exists
  583. +.RB ( <FQDN>
  584. +is the fully-qualified domain name of the server).
  585. +.IR (tlshosts/<FQDN>.pem
  586. +takes precedence over this file however).
  587. +
  588. .TP 5
  589. .I smtproutes
  590. Artificial SMTP routes.
  591. @@ -156,6 +170,8 @@
  592. this tells
  593. .B qmail-remote
  594. to look up MX records as usual.
  595. +.I port
  596. +value of 465 (deprecated smtps port) causes TLS session to be started.
  597. .I smtproutes
  598. may include wildcards:
  599.  
  600. @@ -195,6 +211,33 @@
  601. .B qmail-remote
  602. will wait for each response from the remote SMTP server.
  603. Default: 1200.
  604. +
  605. +.TP 5
  606. +.I tlsclientciphers
  607. +A set of OpenSSL client cipher strings. Multiple ciphers
  608. +contained in a string should be separated by a colon.
  609. +
  610. +.TP 5
  611. +.I tlshosts/<FQDN>.pem
  612. +.B qmail-remote
  613. +requires TLS authentication from servers for which this file exists
  614. +.RB ( <FQDN>
  615. +is the fully-qualified domain name of the server). One of the
  616. +.I dNSName
  617. +or the
  618. +.I CommonName
  619. +attributes have to match. The file contains the trusted CA certificates.
  620. +
  621. +.B WARNING:
  622. +this option may cause mail to be delayed, bounced, doublebounced, or lost.
  623. +
  624. +.TP 5
  625. +.I tlshosts/exhaustivelist
  626. +if this file exists
  627. +no TLS will be tried on hosts other than those for which a file
  628. +.B tlshosts/<FQDN>.pem
  629. +exists.
  630. +
  631. .SH "SEE ALSO"
  632. addresses(5),
  633. envelopes(5),
  634. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qmail-remote.c ./netqmail-1.05/netqmail-1.05/qmail-remote.c
  635. --- ./netqmail-1.05.orig/netqmail-1.05/qmail-remote.c 1998-06-15 06:53:16.000000000 -0400
  636. +++ ./netqmail-1.05/netqmail-1.05/qmail-remote.c 2006-05-10 19:28:51.227864688 -0400
  637. @@ -28,6 +28,7 @@
  638. #include "timeoutconn.h"
  639. #include "timeoutread.h"
  640. #include "timeoutwrite.h"
  641. +#include "base64.h"
  642.  
  643. #define HUGESMTPTEXT 5000
  644.  
  645. @@ -43,11 +44,27 @@
  646. struct constmap maproutes;
  647. stralloc host = {0};
  648. stralloc sender = {0};
  649. +stralloc auth_smtp_user = {0};
  650. +stralloc auth_smtp_pass = {0};
  651. +stralloc auth_b64_user = {0};
  652. +stralloc auth_b64_pass = {0};
  653. +stralloc auth_status = {0};
  654.  
  655. saa reciplist = {0};
  656.  
  657. struct ip_address partner;
  658.  
  659. +#ifdef TLS
  660. +# include <sys/stat.h>
  661. +# include "tls.h"
  662. +# include "ssl_timeoutio.h"
  663. +# include <openssl/x509v3.h>
  664. +# define EHLO 1
  665. +
  666. +int tls_init();
  667. +const char *ssl_err_str = 0;
  668. +#endif
  669. +
  670. void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
  671. void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
  672. void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
  673. @@ -85,6 +102,18 @@
  674. Sorry. Although I'm listed as a best-preference MX or A for that host,\n\
  675. it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
  676. zerodie(); }
  677. +void auth_user_not_set() {
  678. + if(!stralloc_copys(&auth_status, \
  679. + "User and password not set, continuing without authentication.\n"))
  680. + temp_nomem();
  681. + if(!stralloc_0(&auth_status)) temp_nomem();
  682. +}
  683. +void no_supported_auth() {
  684. + if(!stralloc_copys(&auth_status, \
  685. + "No supported AUTH method found, continuing without authentication.\n"))
  686. + temp_nomem();
  687. + if(!stralloc_0(&auth_status)) temp_nomem();
  688. +}
  689.  
  690. void outhost()
  691. {
  692. @@ -99,6 +128,9 @@
  693. outhost();
  694. out(" but connection died. ");
  695. if (flagcritical) out("Possible duplicate! ");
  696. +#ifdef TLS
  697. + if (ssl_err_str) { out(ssl_err_str); out(" "); }
  698. +#endif
  699. out("(#4.4.2)\n");
  700. zerodie();
  701. }
  702. @@ -110,6 +142,12 @@
  703. int saferead(fd,buf,len) int fd; char *buf; int len;
  704. {
  705. int r;
  706. +#ifdef TLS
  707. + if (ssl) {
  708. + r = ssl_timeoutread(timeout, smtpfd, smtpfd, ssl, buf, len);
  709. + if (r < 0) ssl_err_str = ssl_error_str();
  710. + } else
  711. +#endif
  712. r = timeoutread(timeout,smtpfd,buf,len);
  713. if (r <= 0) dropped();
  714. return r;
  715. @@ -117,6 +155,12 @@
  716. int safewrite(fd,buf,len) int fd; char *buf; int len;
  717. {
  718. int r;
  719. +#ifdef TLS
  720. + if (ssl) {
  721. + r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len);
  722. + if (r < 0) ssl_err_str = ssl_error_str();
  723. + } else
  724. +#endif
  725. r = timeoutwrite(timeout,smtpfd,buf,len);
  726. if (r <= 0) dropped();
  727. return r;
  728. @@ -163,6 +207,65 @@
  729. return code;
  730. }
  731.  
  732. +#ifdef EHLO
  733. +saa ehlokw = {0}; /* list of EHLO keywords and parameters */
  734. +int maxehlokwlen = 0;
  735. +
  736. +unsigned long ehlo()
  737. +{
  738. + stralloc *sa;
  739. + char *s, *e, *p;
  740. + unsigned long code;
  741. +
  742. + if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
  743. + ehlokw.len = 0;
  744. +
  745. +# ifdef MXPS
  746. + if (type == 's') return 0;
  747. +# endif
  748. +
  749. + substdio_puts(&smtpto, "EHLO ");
  750. + substdio_put(&smtpto, helohost.s, helohost.len);
  751. + substdio_puts(&smtpto, "\r\n");
  752. + substdio_flush(&smtpto);
  753. +
  754. + code = smtpcode();
  755. + if (code != 250) return code;
  756. +
  757. + s = smtptext.s;
  758. + while (*s++ != '\n') ; /* skip the first line: contains the domain */
  759. +
  760. + e = smtptext.s + smtptext.len - 6; /* 250-?\n */
  761. + while (s <= e)
  762. + {
  763. + int wasspace = 0;
  764. +
  765. + if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
  766. + sa = ehlokw.sa + ehlokw.len++;
  767. + if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
  768. +
  769. + /* smtptext is known to end in a '\n' */
  770. + for (p = (s += 4); ; ++p)
  771. + if (*p == '\n' || *p == ' ' || *p == '\t') {
  772. + if (!wasspace)
  773. + if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
  774. + if (*p == '\n') break;
  775. + wasspace = 1;
  776. + } else if (wasspace == 1) {
  777. + wasspace = 0;
  778. + s = p;
  779. + }
  780. + s = ++p;
  781. +
  782. + /* keyword should consist of alpha-num and '-'
  783. + * broken AUTH might use '=' instead of space */
  784. + for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
  785. + }
  786. +
  787. + return 250;
  788. +}
  789. +#endif
  790. +
  791. void outsmtptext()
  792. {
  793. int i;
  794. @@ -179,6 +282,11 @@
  795. char *prepend;
  796. char *append;
  797. {
  798. +#ifdef TLS
  799. + /* shouldn't talk to the client unless in an appropriate state */
  800. + int state = ssl ? ssl->state : SSL_ST_BEFORE;
  801. + if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
  802. +#endif
  803. substdio_putsflush(&smtpto,"QUIT\r\n");
  804. /* waiting for remote side is just too ridiculous */
  805. out(prepend);
  806. @@ -186,6 +294,30 @@
  807. out(append);
  808. out(".\n");
  809. outsmtptext();
  810. +
  811. +#if defined(TLS) && defined(DEBUG)
  812. + if (ssl) {
  813. + X509 *peercert;
  814. +
  815. + out("STARTTLS proto="); out(SSL_get_version(ssl));
  816. + out("; cipher="); out(SSL_get_cipher(ssl));
  817. +
  818. + /* we want certificate details */
  819. + if (peercert = SSL_get_peer_certificate(ssl)) {
  820. + char *str;
  821. +
  822. + str = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0);
  823. + out("; subject="); out(str); OPENSSL_free(str);
  824. +
  825. + str = X509_NAME_oneline(X509_get_issuer_name(peercert), NULL, 0);
  826. + out("; issuer="); out(str); OPENSSL_free(str);
  827. +
  828. + X509_free(peercert);
  829. + }
  830. + out(";\n");
  831. + }
  832. +#endif
  833. +
  834. zerodie();
  835. }
  836.  
  837. @@ -214,26 +346,297 @@
  838. substdio_flush(&smtpto);
  839. }
  840.  
  841. +#ifdef TLS
  842. +char *partner_fqdn = 0;
  843. +
  844. +# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "")
  845. +void tls_quit(const char *s1, const char *s2)
  846. +{
  847. + out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT;
  848. +}
  849. +# define tls_quit_error(s) tls_quit(s, ssl_error())
  850. +
  851. +int match_partner(const char *s, int len)
  852. +{
  853. + if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1;
  854. + /* we also match if the name is *.domainname */
  855. + if (*s == '*') {
  856. + const char *domain = partner_fqdn + str_chr(partner_fqdn, '.');
  857. + if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
  858. + }
  859. + return 0;
  860. +}
  861. +
  862. +/* don't want to fail handshake if certificate can't be verified */
  863. +int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
  864. +
  865. +int tls_init()
  866. +{
  867. + int i;
  868. + SSL *myssl;
  869. + SSL_CTX *ctx;
  870. + stralloc saciphers = {0};
  871. + const char *ciphers, *servercert = 0;
  872. +
  873. + if (partner_fqdn) {
  874. + struct stat st;
  875. + stralloc tmp = {0};
  876. + if (!stralloc_copys(&tmp, "control/tlshosts/")
  877. + || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))
  878. + || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
  879. + if (stat(tmp.s, &st) == 0)
  880. + servercert = tmp.s;
  881. + else {
  882. + if (!stralloc_copys(&tmp, "control/notlshosts/")
  883. + || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1))
  884. + temp_nomem();
  885. + if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
  886. + (stat(tmp.s, &st) == 0)) {
  887. + alloc_free(tmp.s);
  888. + return 0;
  889. + }
  890. + alloc_free(tmp.s);
  891. + }
  892. + }
  893. +
  894. + if (!smtps) {
  895. + stralloc *sa = ehlokw.sa;
  896. + unsigned int len = ehlokw.len;
  897. + /* look for STARTTLS among EHLO keywords */
  898. + for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
  899. + if (!len) {
  900. + if (!servercert) return 0;
  901. + out("ZNo TLS achieved while "); out(servercert);
  902. + out(" exists"); smtptext.len = 0; TLS_QUIT;
  903. + }
  904. + }
  905. +
  906. + SSL_library_init();
  907. + ctx = SSL_CTX_new(SSLv23_client_method());
  908. + if (!ctx) {
  909. + if (!smtps && !servercert) return 0;
  910. + smtptext.len = 0;
  911. + tls_quit_error("ZTLS error initializing ctx");
  912. + }
  913. +
  914. + if (servercert) {
  915. + if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) {
  916. + SSL_CTX_free(ctx);
  917. + smtptext.len = 0;
  918. + out("ZTLS unable to load "); tls_quit_error(servercert);
  919. + }
  920. + /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
  921. + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
  922. + }
  923. +
  924. + /* let the other side complain if it needs a cert and we don't have one */
  925. +# define CLIENTCERT "control/clientcert.pem"
  926. + if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
  927. + SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
  928. +# undef CLIENTCERT
  929. +
  930. + myssl = SSL_new(ctx);
  931. + SSL_CTX_free(ctx);
  932. + if (!myssl) {
  933. + if (!smtps && !servercert) return 0;
  934. + smtptext.len = 0;
  935. + tls_quit_error("ZTLS error initializing ssl");
  936. + }
  937. +
  938. + if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n");
  939. +
  940. + /* while the server is preparing a responce, do something else */
  941. + if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
  942. + { SSL_free(myssl); temp_control(); }
  943. + if (saciphers.len) {
  944. + for (i = 0; i < saciphers.len - 1; ++i)
  945. + if (!saciphers.s[i]) saciphers.s[i] = ':';
  946. + ciphers = saciphers.s;
  947. + }
  948. + else ciphers = "DEFAULT";
  949. + SSL_set_cipher_list(myssl, ciphers);
  950. + alloc_free(saciphers.s);
  951. +
  952. + /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */
  953. + SSL_set_fd(myssl, smtpfd);
  954. +
  955. + /* read the responce to STARTTLS */
  956. + if (!smtps) {
  957. + if (smtpcode() != 220) {
  958. + SSL_free(myssl);
  959. + if (!servercert) return 0;
  960. + out("ZSTARTTLS rejected while ");
  961. + out(servercert); out(" exists"); TLS_QUIT;
  962. + }
  963. + smtptext.len = 0;
  964. + }
  965. +
  966. + ssl = myssl;
  967. + if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0)
  968. + tls_quit("ZTLS connect failed", ssl_error_str());
  969. +
  970. + if (servercert) {
  971. + X509 *peercert;
  972. + STACK_OF(GENERAL_NAME) *gens;
  973. +
  974. + int r = SSL_get_verify_result(ssl);
  975. + if (r != X509_V_OK) {
  976. + out("ZTLS unable to verify server with ");
  977. + tls_quit(servercert, X509_verify_cert_error_string(r));
  978. + }
  979. + alloc_free(servercert);
  980. +
  981. + peercert = SSL_get_peer_certificate(ssl);
  982. + if (!peercert) {
  983. + out("ZTLS unable to verify server ");
  984. + tls_quit(partner_fqdn, "no certificate provided");
  985. + }
  986. +
  987. + /* RFC 2595 section 2.4: find a matching name
  988. + * first find a match among alternative names */
  989. + gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
  990. + if (gens) {
  991. + for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i)
  992. + {
  993. + const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
  994. + if (gn->type == GEN_DNS)
  995. + if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break;
  996. + }
  997. + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
  998. + }
  999. +
  1000. + /* no alternative name matched, look up commonName */
  1001. + if (!gens || i >= r) {
  1002. + stralloc peer = {0};
  1003. + X509_NAME *subj = X509_get_subject_name(peercert);
  1004. + i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
  1005. + if (i >= 0) {
  1006. + const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value;
  1007. + if (s) { peer.len = s->length; peer.s = s->data; }
  1008. + }
  1009. + if (peer.len <= 0) {
  1010. + out("ZTLS unable to verify server ");
  1011. + tls_quit(partner_fqdn, "certificate contains no valid commonName");
  1012. + }
  1013. + if (!match_partner(peer.s, peer.len)) {
  1014. + out("ZTLS unable to verify server "); out(partner_fqdn);
  1015. + out(": received certificate for "); outsafe(&peer); TLS_QUIT;
  1016. + }
  1017. + }
  1018. +
  1019. + X509_free(peercert);
  1020. + }
  1021. +
  1022. + if (smtps) if (smtpcode() != 220)
  1023. + quit("ZTLS Connected to "," but greeting failed");
  1024. +
  1025. + return 1;
  1026. +}
  1027. +#endif
  1028. +
  1029. stralloc recip = {0};
  1030.  
  1031. +void mail_without_auth()
  1032. +{
  1033. + substdio_puts(&smtpto,"MAIL FROM:<");
  1034. + substdio_put(&smtpto,sender.s,sender.len);
  1035. + substdio_puts(&smtpto,">\r\n");
  1036. + substdio_flush(&smtpto);
  1037. +}
  1038. +
  1039. void smtp()
  1040. {
  1041. unsigned long code;
  1042. int flagbother;
  1043. - int i;
  1044. + int i, j;
  1045. +
  1046. +#ifndef PORT_SMTP
  1047. + /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */
  1048. +# define port smtp_port
  1049. +#endif
  1050. +
  1051. +#ifdef TLS
  1052. +# ifdef MXPS
  1053. + if (type == 'S') smtps = 1;
  1054. + else if (type != 's')
  1055. +# endif
  1056. + if (port == 465) smtps = 1;
  1057. + if (!smtps)
  1058. +#endif
  1059.  
  1060. if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
  1061.  
  1062. +#ifdef EHLO
  1063. +# ifdef TLS
  1064. + if (!smtps)
  1065. +# endif
  1066. + code = ehlo();
  1067. +
  1068. +# ifdef TLS
  1069. + if (tls_init())
  1070. + /* RFC2487 says we should issue EHLO (even if we might not need
  1071. + * extensions); at the same time, it does not prohibit a server
  1072. + * to reject the EHLO and make us fallback to HELO */
  1073. + code = ehlo();
  1074. +# endif
  1075. +
  1076. + if (code == 250) {
  1077. + /* add EHLO response checks here */
  1078. +
  1079. + /* and if EHLO failed, use HELO */
  1080. + } else {
  1081. +#endif
  1082. +
  1083. substdio_puts(&smtpto,"HELO ");
  1084. substdio_put(&smtpto,helohost.s,helohost.len);
  1085. substdio_puts(&smtpto,"\r\n");
  1086. substdio_flush(&smtpto);
  1087. if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
  1088.  
  1089. - substdio_puts(&smtpto,"MAIL FROM:<");
  1090. - substdio_put(&smtpto,sender.s,sender.len);
  1091. - substdio_puts(&smtpto,">\r\n");
  1092. - substdio_flush(&smtpto);
  1093. +#ifdef EHLO
  1094. + }
  1095. +#endif
  1096. + i = 0;
  1097. + if (auth_smtp_user.len && auth_smtp_pass.len) {
  1098. + while((i += str_chr(smtptext.s+i,'\n') + 1) &&
  1099. + (i+8 < smtptext.len) &&
  1100. + str_diffn(smtptext.s+i+4,"AUTH",4));
  1101. + if (((i+9 < smtptext.len) &&
  1102. + (str_diffn(smtptext.s+i+9," ",1) ||
  1103. + str_diffn(smtptext.s+i+9,"=",1))) &&
  1104. + ( i += str_chr(smtptext.s+i,'L') + 1 ) &&
  1105. + str_diffn(smtptext.s+i+1,"OGIN",4)) {
  1106. +
  1107. + if (b64encode(&auth_smtp_user,&auth_b64_user)) quit("ZConnected to "," but unable to base64encode user");
  1108. + if (b64encode(&auth_smtp_pass,&auth_b64_pass)) quit("ZConnected to "," but unable to base64encode pass");
  1109. +
  1110. + substdio_puts(&smtpto,"AUTH LOGIN\r\n");
  1111. + substdio_flush(&smtpto);
  1112. + if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)");
  1113. + substdio_put(&smtpto,auth_b64_user.s,auth_b64_user.len);
  1114. + substdio_puts(&smtpto,"\r\n");
  1115. + substdio_flush(&smtpto);
  1116. + if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username)");
  1117. + substdio_put(&smtpto,auth_b64_pass.s,auth_b64_pass.len);
  1118. + substdio_puts(&smtpto,"\r\n");
  1119. + substdio_flush(&smtpto);
  1120. + if (smtpcode() != 235) quit("ZConnected to "," but authentication was rejected (password)");
  1121. + substdio_puts(&smtpto,"MAIL FROM:<");
  1122. + substdio_put(&smtpto,sender.s,sender.len);
  1123. + substdio_puts(&smtpto,"> AUTH=<");
  1124. + substdio_put(&smtpto,sender.s,sender.len);
  1125. + substdio_puts(&smtpto,">\r\n");
  1126. + substdio_flush(&smtpto);
  1127. + if(!stralloc_copys(&auth_status, "Delivered with authenticated connection to \n")) temp_nomem();
  1128. + if(!stralloc_0(&auth_status)) temp_nomem();
  1129. + } else {
  1130. + no_supported_auth();
  1131. + mail_without_auth();
  1132. + }
  1133. + } else {
  1134. + auth_user_not_set();
  1135. + mail_without_auth();
  1136. + }
  1137. code = smtpcode();
  1138. if (code >= 500) quit("DConnected to "," but sender was rejected");
  1139. if (code >= 400) quit("ZConnected to "," but sender was rejected");
  1140. @@ -246,15 +649,22 @@
  1141. substdio_flush(&smtpto);
  1142. code = smtpcode();
  1143. if (code >= 500) {
  1144. - out("h"); outhost(); out(" does not like recipient.\n");
  1145. + out("h"); out(auth_status.s); outhost();
  1146. + out(" does not like recipient.\n");
  1147. outsmtptext(); zero();
  1148. }
  1149. else if (code >= 400) {
  1150. - out("s"); outhost(); out(" does not like recipient.\n");
  1151. + out("s"); out(auth_status.s); outhost();
  1152. + out(" does not like recipient.\n");
  1153. outsmtptext(); zero();
  1154. }
  1155. else {
  1156. - out("r"); zero();
  1157. + /*
  1158. + * James Raftery <james@now.ie>
  1159. + * Log _real_ envelope recipient, post canonicalisation.
  1160. + */
  1161. + out("r"); out(auth_status.s);
  1162. + out("<"); outsafe(&reciplist.sa[i]); out("> "); zero();
  1163. flagbother = 1;
  1164. }
  1165. }
  1166. @@ -331,7 +741,7 @@
  1167. char **argv;
  1168. {
  1169. static ipalloc ip = {0};
  1170. - int i;
  1171. + int i,j;
  1172. unsigned long random;
  1173. char **recips;
  1174. unsigned long prefme;
  1175. @@ -347,6 +757,9 @@
  1176.  
  1177. if (!stralloc_copys(&host,argv[1])) temp_nomem();
  1178.  
  1179. + if (!stralloc_copys(&auth_smtp_user,"")) temp_nomem();
  1180. + if (!stralloc_copys(&auth_smtp_pass,"")) temp_nomem();
  1181. +
  1182. relayhost = 0;
  1183. for (i = 0;i <= host.len;++i)
  1184. if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
  1185. @@ -355,6 +768,16 @@
  1186. if (relayhost && !*relayhost) relayhost = 0;
  1187.  
  1188. if (relayhost) {
  1189. + i = str_chr(relayhost,' ');
  1190. + if (relayhost[i]) {
  1191. + j = str_chr(relayhost + i + 1,' ');
  1192. + if (relayhost[j]) {
  1193. + relayhost[i] = 0;
  1194. + relayhost[i + j + 1] = 0;
  1195. + if (!stralloc_copys(&auth_smtp_user,relayhost + i + 1)) temp_nomem();
  1196. + if (!stralloc_copys(&auth_smtp_pass,relayhost + i + j + 2)) temp_nomem();
  1197. + }
  1198. + }
  1199. i = str_chr(relayhost,':');
  1200. if (relayhost[i]) {
  1201. scan_ulong(relayhost + i + 1,&port);
  1202. @@ -417,6 +840,9 @@
  1203. if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
  1204. tcpto_err(&ip.ix[i].ip,0);
  1205. partner = ip.ix[i].ip;
  1206. +#ifdef TLS
  1207. + partner_fqdn = ip.ix[i].fqdn;
  1208. +#endif
  1209. smtp(); /* does not return */
  1210. }
  1211. tcpto_err(&ip.ix[i].ip,errno == error_timeout);
  1212. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qmail-showctl.c ./netqmail-1.05/netqmail-1.05/qmail-showctl.c
  1213. --- ./netqmail-1.05.orig/netqmail-1.05/qmail-showctl.c 1998-06-15 06:53:16.000000000 -0400
  1214. +++ ./netqmail-1.05/netqmail-1.05/qmail-showctl.c 2006-05-10 19:29:13.783888457 -0400
  1215. @@ -214,7 +214,11 @@
  1216. _exit(111);
  1217. }
  1218.  
  1219. - do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
  1220. + do_lst("badhelo","Any HELO host name is allowed.",""," HELO host name denied if it matches this pattern.");
  1221. + do_lst("badmailfrom","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern.");
  1222. + do_lst("badmailfromnorelay","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern and RELAYCLIENT is not set.");
  1223. + do_lst("badmailto","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern.");
  1224. + do_lst("badmailtonorelay","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern and RELAYCLIENT is not set.");
  1225. do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
  1226. do_str("bouncehost",1,"bouncehost","Bounce host name is ");
  1227. do_int("concurrencylocal","10","Local concurrency is ","");
  1228. @@ -267,7 +271,11 @@
  1229. if (str_equal(d->d_name,"..")) continue;
  1230. if (str_equal(d->d_name,"bouncefrom")) continue;
  1231. if (str_equal(d->d_name,"bouncehost")) continue;
  1232. + if (str_equal(d->d_name,"badhelo")) continue;
  1233. if (str_equal(d->d_name,"badmailfrom")) continue;
  1234. + if (str_equal(d->d_name,"badmailfromnorelay")) continue;
  1235. + if (str_equal(d->d_name,"badmailto")) continue;
  1236. + if (str_equal(d->d_name,"badmailtonorelay")) continue;
  1237. if (str_equal(d->d_name,"bouncefrom")) continue;
  1238. if (str_equal(d->d_name,"bouncehost")) continue;
  1239. if (str_equal(d->d_name,"concurrencylocal")) continue;
  1240. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qmail-smtpd.8 ./netqmail-1.05/netqmail-1.05/qmail-smtpd.8
  1241. --- ./netqmail-1.05.orig/netqmail-1.05/qmail-smtpd.8 1998-06-15 06:53:16.000000000 -0400
  1242. +++ ./netqmail-1.05/netqmail-1.05/qmail-smtpd.8 2006-05-10 20:24:02.114316580 -0400
  1243. @@ -14,6 +14,15 @@
  1244. see
  1245. .BR tcp-environ(5) .
  1246.  
  1247. +If the environment variable
  1248. +.B SMTPS
  1249. +is non-empty,
  1250. +.B qmail-smtpd
  1251. +starts a TLS session (to support the deprecated SMTPS protocol,
  1252. +normally on port 465). Otherwise,
  1253. +.B qmail-smtpd
  1254. +offers the STARTTLS extension to ESMTP.
  1255. +
  1256. .B qmail-smtpd
  1257. is responsible for counting hops.
  1258. It rejects any message with 100 or more
  1259. @@ -23,7 +32,30 @@
  1260. header fields.
  1261.  
  1262. .B qmail-smtpd
  1263. -supports ESMTP, including the 8BITMIME and PIPELINING options.
  1264. +supports ESMTP, including the 8BITMIME, DATA, PIPELINING, SIZE, and AUTH options.
  1265. +.B qmail-smtpd
  1266. +includes a \'MAIL FROM:\' parameter parser and obeys \'Auth\' and \'Size\' advertisements.
  1267. +.B qmail-smtpd
  1268. +can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes
  1269. +.IR checkprogram ,
  1270. +which reads on file descriptor 3 the username, a 0 byte, the password
  1271. +or CRAM-MD5 digest/response derived from the SMTP client,
  1272. +another 0 byte, a CRAM-MD5 challenge (if applicable to the AUTH type),
  1273. +and a final 0 byte.
  1274. +.I checkprogram
  1275. +invokes
  1276. +.I subprogram
  1277. +upon successful authentication, which should in turn return 0 to
  1278. +.BR qmail-smtpd ,
  1279. +effectively setting the environment variables $RELAYCLIENT and $TCPREMOTEINFO
  1280. +(any supplied value replaced with the authenticated username).
  1281. +.B qmail-smtpd
  1282. +will reject the authentication attempt if it receives a nonzero return
  1283. +value from
  1284. +.I checkprogram
  1285. +or
  1286. +.IR subprogram .
  1287. +
  1288. .SH TRANSPARENCY
  1289. .B qmail-smtpd
  1290. converts the SMTP newline convention into the UNIX newline convention
  1291. @@ -37,11 +69,26 @@
  1292. even though such messages violate the SMTP protocol.
  1293. .SH "CONTROL FILES"
  1294. .TP 5
  1295. +.I badhelo
  1296. +Unacceptable HELO/EHLO host names.
  1297. +.B qmail-smtpd
  1298. +will reject every recipient address for a message if
  1299. +the host name is listed in,
  1300. +or matches a POSIX regular expression pattern listed in,
  1301. +.IR badhelo .
  1302. +If the
  1303. +.B NOBADHELO
  1304. +environment variable is set, then the contents of
  1305. +.IR badhelo
  1306. +will be ignored.
  1307. +For more information, please have a look at doc/README.qregex.
  1308. +.TP 5
  1309. .I badmailfrom
  1310. Unacceptable envelope sender addresses.
  1311. .B qmail-smtpd
  1312. will reject every recipient address for a message
  1313. -if the envelope sender address is listed in
  1314. +if the envelope sender address is listed in, or matches a POSIX regular expression
  1315. +pattern listed in,
  1316. .IR badmailfrom .
  1317. A line in
  1318. .I badmailfrom
  1319. @@ -49,6 +96,45 @@
  1320. .BR @\fIhost ,
  1321. meaning every address at
  1322. .IR host .
  1323. +For more information, please have a look at doc/README.qregex.
  1324. +.TP 5
  1325. +.I badmailfromnorelay
  1326. +Functions the same as the
  1327. +.IR badmailfrom
  1328. +control file but is read only if the
  1329. +.B RELAYCLIENT
  1330. +environment variable is not set.
  1331. +For more information, please have a look at doc/README.qregex.
  1332. +.TP 5
  1333. +.I badmailto
  1334. +Unacceptable envelope recipient addresses.
  1335. +.B qmail-smtpd
  1336. +will reject every recipient address for a message if the recipient address
  1337. +is listed in,
  1338. +or matches a POSIX regular expression pattern listed in,
  1339. +.IR badmailto .
  1340. +For more information, please have a look at doc/README.qregex.
  1341. +.TP 5
  1342. +.I badmailtonorelay
  1343. +Functions the same as the
  1344. +.IR badmailto
  1345. +control file but is read only if the
  1346. +.B RELAYCLIENT
  1347. +environment variable is not set.
  1348. +For more information, please have a look at doc/README.qregex.
  1349. +
  1350. +.TP 5
  1351. +.I clientca.pem
  1352. +A list of Certifying Authority (CA) certificates that are used to verify
  1353. +the client-presented certificates during a TLS-encrypted session.
  1354. +
  1355. +.TP 5
  1356. +.I clientcrl.pem
  1357. +A list of Certificate Revocation Lists (CRLs). If present it
  1358. +should contain the CRLs of the CAs in
  1359. +.I clientca.pem
  1360. +and client certs will be checked for revocation.
  1361. +
  1362. .TP 5
  1363. .I databytes
  1364. Maximum number of bytes allowed in a message,
  1365. @@ -76,6 +162,18 @@
  1366. .B DATABYTES
  1367. is set, it overrides
  1368. .IR databytes .
  1369. +
  1370. +.TP 5
  1371. +.I dh1024.pem
  1372. +If these 1024 bit DH parameters are provided,
  1373. +.B qmail-smtpd
  1374. +will use them for TLS sessions instead of generating one on-the-fly
  1375. +(which is very timeconsuming).
  1376. +.TP 5
  1377. +.I dh512.pem
  1378. +512 bit counterpart for
  1379. +.B dh1024.pem.
  1380. +
  1381. .TP 5
  1382. .I localiphost
  1383. Replacement host name for local IP addresses.
  1384. @@ -151,6 +249,19 @@
  1385.  
  1386. Envelope recipient addresses without @ signs are
  1387. always allowed through.
  1388. +
  1389. +.TP 5
  1390. +.I rsa512.pem
  1391. +If this 512 bit RSA key is provided,
  1392. +.B qmail-smtpd
  1393. +will use it for TLS sessions instead of generating one on-the-fly.
  1394. +
  1395. +.TP 5
  1396. +.I servercert.pem
  1397. +SSL certificate to be presented to clients in TLS-encrypted sessions.
  1398. +Should contain both the certificate and the private key. Certifying Authority
  1399. +(CA) and intermediate certificates can be added at the end of the file.
  1400. +
  1401. .TP 5
  1402. .I smtpgreeting
  1403. SMTP greeting message.
  1404. @@ -169,6 +280,24 @@
  1405. .B qmail-smtpd
  1406. will wait for each new buffer of data from the remote SMTP client.
  1407. Default: 1200.
  1408. +
  1409. +.TP 5
  1410. +.I tlsclients
  1411. +A list of email addresses. When relay rules would reject an incoming message,
  1412. +.B qmail-smtpd
  1413. +can allow it if the client presents a certificate that can be verified against
  1414. +the CA list in
  1415. +.I clientca.pem
  1416. +and the certificate email address is in
  1417. +.IR tlsclients .
  1418. +
  1419. +.TP 5
  1420. +.I tlsserverciphers
  1421. +A set of OpenSSL cipher strings. Multiple ciphers contained in a
  1422. +string should be separated by a colon. If the environment variable
  1423. +.B TLSCIPHERS
  1424. +is set to such a string, it takes precedence.
  1425. +
  1426. .SH "SEE ALSO"
  1427. tcp-env(1),
  1428. tcp-environ(5),
  1429. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qmail-smtpd.c ./netqmail-1.05/netqmail-1.05/qmail-smtpd.c
  1430. --- ./netqmail-1.05.orig/netqmail-1.05/qmail-smtpd.c 2004-06-04 21:51:58.000000000 -0400
  1431. +++ ./netqmail-1.05/netqmail-1.05/qmail-smtpd.c 2006-05-10 20:22:01.244635083 -0400
  1432. @@ -23,14 +23,44 @@
  1433. #include "timeoutread.h"
  1434. #include "timeoutwrite.h"
  1435. #include "commands.h"
  1436. +#include "wait.h"
  1437. +#include "qregex.h"
  1438. +#include "strerr.h"
  1439. +
  1440. +#define BMCHECK_BMF 0
  1441. +#define BMCHECK_BMFNR 1
  1442. +#define BMCHECK_BMT 2
  1443. +#define BMCHECK_BMTNR 3
  1444. +#define BMCHECK_BHELO 4
  1445. +
  1446. +#define CRAM_MD5
  1447. +#define AUTHSLEEP 5
  1448.  
  1449. #define MAXHOPS 100
  1450. unsigned int databytes = 0;
  1451. int timeout = 1200;
  1452.  
  1453. +const char *protocol = "SMTP";
  1454. +
  1455. +#ifdef TLS
  1456. +#include <sys/stat.h>
  1457. +#include "tls.h"
  1458. +#include "ssl_timeoutio.h"
  1459. +
  1460. +void tls_init();
  1461. +int tls_verify();
  1462. +void tls_nogateway();
  1463. +int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */
  1464. +#endif
  1465. +
  1466. int safewrite(fd,buf,len) int fd; char *buf; int len;
  1467. {
  1468. int r;
  1469. +#ifdef TLS
  1470. + if (ssl && fd == ssl_wfd)
  1471. + r = ssl_timeoutwrite(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
  1472. + else
  1473. +#endif
  1474. r = timeoutwrite(timeout,fd,buf,len);
  1475. if (r <= 0) _exit(1);
  1476. return r;
  1477. @@ -49,8 +79,20 @@
  1478. void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
  1479. void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
  1480.  
  1481. -void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
  1482. +void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
  1483. +void err_bmf() { out("553 sorry, your envelope sender has been denied (#5.7.1)\r\n"); }
  1484. +void err_bmt() { out("553 sorry, your envelope recipient has been denied (#5.7.1)\r\n"); }
  1485. +void err_bhelo() { out("553 sorry, your HELO host name has been denied (#5.7.1)\r\n"); }
  1486. +#ifndef TLS
  1487. void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
  1488. +#else
  1489. +void err_nogateway()
  1490. +{
  1491. + out("553 sorry, that domain isn't in my list of allowed rcpthosts");
  1492. + tls_nogateway();
  1493. + out(" (#5.7.1)\r\n");
  1494. +}
  1495. +#endif
  1496. void err_unimpl(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); }
  1497. void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
  1498. void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
  1499. @@ -59,6 +101,16 @@
  1500. void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); }
  1501. void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
  1502.  
  1503. +int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
  1504. +int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
  1505. +int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
  1506. +int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
  1507. +void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
  1508. +void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
  1509. +int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
  1510. +int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; }
  1511. +int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
  1512. +void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
  1513.  
  1514. stralloc greeting = {0};
  1515.  
  1516. @@ -93,9 +145,24 @@
  1517.  
  1518. int liphostok = 0;
  1519. stralloc liphost = {0};
  1520. +
  1521. int bmfok = 0;
  1522. stralloc bmf = {0};
  1523. -struct constmap mapbmf;
  1524. +
  1525. +int bmfnrok = 0;
  1526. +stralloc bmfnr = {0};
  1527. +
  1528. +int bmtok = 0;
  1529. +stralloc bmt = {0};
  1530. +
  1531. +int bmtnrok = 0;
  1532. +stralloc bmtnr = {0};
  1533. +
  1534. +int bhelook = 0;
  1535. +stralloc bhelo = {0};
  1536. +
  1537. +int logregex = 0;
  1538. +stralloc matchedregex = {0};
  1539.  
  1540. void setup()
  1541. {
  1542. @@ -109,13 +176,25 @@
  1543. if (liphostok == -1) die_control();
  1544. if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
  1545. if (timeout <= 0) timeout = 1;
  1546. -
  1547. if (rcpthosts_init() == -1) die_control();
  1548.  
  1549. bmfok = control_readfile(&bmf,"control/badmailfrom",0);
  1550. if (bmfok == -1) die_control();
  1551. - if (bmfok)
  1552. - if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
  1553. +
  1554. + bmfnrok = control_readfile(&bmfnr,"control/badmailfromnorelay",0);
  1555. + if (bmfnrok == -1) die_control();
  1556. +
  1557. + bmtok = control_readfile(&bmt,"control/badmailto",0);
  1558. + if (bmtok == -1) die_control();
  1559. +
  1560. + bmtnrok = control_readfile(&bmtnr,"control/badmailtonorelay",0);
  1561. + if (bmtnrok == -1) die_control();
  1562. +
  1563. + bhelook = control_readfile(&bhelo, "control/badhelo",0);
  1564. + if (bhelook == -1) die_control();
  1565. + if (env_get("NOBADHELO")) bhelook = 0;
  1566. +
  1567. + if (env_get("LOGREGEX")) logregex = 1;
  1568.  
  1569. if (control_readint(&databytes,"control/databytes") == -1) die_control();
  1570. x = env_get("DATABYTES");
  1571. @@ -131,6 +210,11 @@
  1572. if (!remotehost) remotehost = "unknown";
  1573. remoteinfo = env_get("TCPREMOTEINFO");
  1574. relayclient = env_get("RELAYCLIENT");
  1575. +
  1576. +#ifdef TLS
  1577. + if (env_get("SMTPS")) { smtps = 1; tls_init(); }
  1578. + else
  1579. +#endif
  1580. dohelo(remotehost);
  1581. }
  1582.  
  1583. @@ -197,14 +281,56 @@
  1584. return 1;
  1585. }
  1586.  
  1587. -int bmfcheck()
  1588. +int bmcheck(which) int which;
  1589. {
  1590. - int j;
  1591. - if (!bmfok) return 0;
  1592. - if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
  1593. - j = byte_rchr(addr.s,addr.len,'@');
  1594. - if (j < addr.len)
  1595. - if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
  1596. + int i = 0;
  1597. + int j = 0;
  1598. + int x = 0;
  1599. + int negate = 0;
  1600. + static stralloc bmb = {0};
  1601. + static stralloc curregex = {0};
  1602. +
  1603. + if (which == BMCHECK_BMF) {
  1604. + if (!stralloc_copy(&bmb,&bmf)) die_nomem();
  1605. + } else if (which == BMCHECK_BMFNR) {
  1606. + if (!stralloc_copy(&bmb,&bmfnr)) die_nomem();
  1607. + } else if (which == BMCHECK_BMT) {
  1608. + if (!stralloc_copy(&bmb,&bmt)) die_nomem();
  1609. + } else if (which == BMCHECK_BMTNR) {
  1610. + if (!stralloc_copy(&bmb,&bmtnr)) die_nomem();
  1611. + } else if (which == BMCHECK_BHELO) {
  1612. + if (!stralloc_copy(&bmb,&bhelo)) die_nomem();
  1613. + } else {
  1614. + die_control();
  1615. + }
  1616. +
  1617. + while (j < bmb.len) {
  1618. + i = j;
  1619. + while ((bmb.s[i] != '\0') && (i < bmb.len)) i++;
  1620. + if (bmb.s[j] == '!') {
  1621. + negate = 1;
  1622. + j++;
  1623. + }
  1624. + if (!stralloc_copyb(&curregex,bmb.s + j,(i - j))) die_nomem();
  1625. + if (!stralloc_0(&curregex)) die_nomem();
  1626. + if (which == BMCHECK_BHELO) {
  1627. + x = matchregex(helohost.s, curregex.s);
  1628. + } else {
  1629. + x = matchregex(addr.s, curregex.s);
  1630. + }
  1631. + if ((negate) && (x == 0)) {
  1632. + if (!stralloc_copyb(&matchedregex,bmb.s + j - 1,(i - j + 1))) die_nomem();
  1633. + if (!stralloc_0(&matchedregex)) die_nomem();
  1634. + return 1;
  1635. + }
  1636. + if (!(negate) && (x > 0)) {
  1637. + if (!stralloc_copyb(&matchedregex,bmb.s + j,(i - j))) die_nomem();
  1638. + if (!stralloc_0(&matchedregex)) die_nomem();
  1639. + return 1;
  1640. + }
  1641. + j = i + 1;
  1642. + negate = 0;
  1643. + }
  1644. return 0;
  1645. }
  1646.  
  1647. @@ -213,24 +339,110 @@
  1648. int r;
  1649. r = rcpthosts(addr.s,str_len(addr.s));
  1650. if (r == -1) die_control();
  1651. +#ifdef TLS
  1652. + if (r == 0) if (tls_verify()) r = -2;
  1653. +#endif
  1654. return r;
  1655. }
  1656.  
  1657.  
  1658. int seenmail = 0;
  1659. -int flagbarf; /* defined if seenmail */
  1660. +int flagbarfbmf; /* defined if seenmail */
  1661. +int flagbarfbmt;
  1662. +int flagbarfbhelo;
  1663. +int flagsize;
  1664. stralloc mailfrom = {0};
  1665. stralloc rcptto = {0};
  1666. +stralloc fuser = {0};
  1667. +stralloc mfparms = {0};
  1668. +
  1669. +int mailfrom_size(arg) char *arg;
  1670. +{
  1671. + long r;
  1672. + unsigned long sizebytes = 0;
  1673. +
  1674. + scan_ulong(arg,&r);
  1675. + sizebytes = r;
  1676. + if (databytes) if (sizebytes > databytes) return 1;
  1677. + return 0;
  1678. +}
  1679. +
  1680. +void mailfrom_auth(arg,len)
  1681. +char *arg;
  1682. +int len;
  1683. +{
  1684. + int j;
  1685. +
  1686. + if (!stralloc_copys(&fuser,"")) die_nomem();
  1687. + if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
  1688. + else
  1689. + while (len) {
  1690. + if (*arg == '+') {
  1691. + if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
  1692. + if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
  1693. + }
  1694. + else
  1695. + if (!stralloc_catb(&fuser,arg,1)) die_nomem();
  1696. + arg++; len--;
  1697. + }
  1698. + if(!stralloc_0(&fuser)) die_nomem();
  1699. + if (!remoteinfo) {
  1700. + remoteinfo = fuser.s;
  1701. + if (!env_unset("TCPREMOTEINFO")) die_read();
  1702. + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
  1703. + }
  1704. +}
  1705. +
  1706. +void mailfrom_parms(arg) char *arg;
  1707. +{
  1708. + int i;
  1709. + int len;
  1710. +
  1711. + len = str_len(arg);
  1712. + if (!stralloc_copys(&mfparms,"")) die_nomem;
  1713. + i = byte_chr(arg,len,'>');
  1714. + if (i > 4 && i < len) {
  1715. + while (len) {
  1716. + arg++; len--;
  1717. + if (*arg == ' ' || *arg == '\0' ) {
  1718. + if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
  1719. + if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);
  1720. + if (!stralloc_copys(&mfparms,"")) die_nomem;
  1721. + }
  1722. + else
  1723. + if (!stralloc_catb(&mfparms,arg,1)) die_nomem;
  1724. + }
  1725. + }
  1726. +}
  1727.  
  1728. void smtp_helo(arg) char *arg;
  1729. {
  1730. smtp_greet("250 "); out("\r\n");
  1731. seenmail = 0; dohelo(arg);
  1732. + if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
  1733. }
  1734. +/* ESMTP extensions are published here */
  1735. void smtp_ehlo(arg) char *arg;
  1736. {
  1737. - smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
  1738. +#ifdef TLS
  1739. + struct stat st;
  1740. +#endif
  1741. + char size[FMT_ULONG];
  1742. + size[fmt_ulong(size,(unsigned int) databytes)] = 0;
  1743. + smtp_greet("250-");
  1744. +#ifdef TLS
  1745. + if (!ssl && (stat("control/servercert.pem",&st) == 0))
  1746. + out("\r\n250-STARTTLS");
  1747. +#endif
  1748. + out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
  1749. + out("250-SIZE "); out(size); out("\r\n");
  1750. +#ifdef CRAM_MD5
  1751. + out("250 AUTH LOGIN PLAIN CRAM-MD5\r\n");
  1752. +#else
  1753. + out("250 AUTH LOGIN PLAIN\r\n");
  1754. +#endif
  1755. seenmail = 0; dohelo(arg);
  1756. + if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
  1757. }
  1758. void smtp_rset(arg) char *arg;
  1759. {
  1760. @@ -240,7 +452,14 @@
  1761. void smtp_mail(arg) char *arg;
  1762. {
  1763. if (!addrparse(arg)) { err_syntax(); return; }
  1764. - flagbarf = bmfcheck();
  1765. + flagsize = 0;
  1766. + mailfrom_parms(arg);
  1767. + if (flagsize) { err_size(); return; }
  1768. + flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */
  1769. + if ((bmfok) && (addr.len != 1)) flagbarfbmf = bmcheck(BMCHECK_BMF);
  1770. + if ((!flagbarfbmf) && (bmfnrok) && (addr.len != 1) && (!relayclient)) {
  1771. + flagbarfbmf = bmcheck(BMCHECK_BMFNR);
  1772. + }
  1773. seenmail = 1;
  1774. if (!stralloc_copys(&rcptto,"")) die_nomem();
  1775. if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
  1776. @@ -250,7 +469,37 @@
  1777. void smtp_rcpt(arg) char *arg; {
  1778. if (!seenmail) { err_wantmail(); return; }
  1779. if (!addrparse(arg)) { err_syntax(); return; }
  1780. - if (flagbarf) { err_bmf(); return; }
  1781. + if (flagbarfbhelo) {
  1782. + if (logregex) {
  1783. + strerr_warn6("qmail-smtpd: badhelo: <",helohost.s,"> at ",remoteip," matches pattern: ",matchedregex.s,0);
  1784. + } else {
  1785. + strerr_warn4("qmail-smtpd: badhelo: <",helohost.s,"> at ",remoteip,0);
  1786. + }
  1787. + err_bhelo();
  1788. + return;
  1789. + }
  1790. + if (flagbarfbmf) {
  1791. + if (logregex) {
  1792. + strerr_warn6("qmail-smtpd: badmailfrom: <",mailfrom.s,"> at ",remoteip," matches pattern: ",matchedregex.s,0);
  1793. + } else {
  1794. + strerr_warn4("qmail-smtpd: badmailfrom: <",mailfrom.s,"> at ",remoteip,0);
  1795. + }
  1796. + err_bmf();
  1797. + return;
  1798. + }
  1799. + if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT);
  1800. + if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) {
  1801. + flagbarfbmt = bmcheck(BMCHECK_BMTNR);
  1802. + }
  1803. + if (flagbarfbmt) {
  1804. + if (logregex) {
  1805. + strerr_warn6("qmail-smtpd: badmailto: <",addr.s,"> at ",remoteip," matches pattern: ",matchedregex.s,0);
  1806. + } else {
  1807. + strerr_warn4("qmail-smtpd: badmailto: <",addr.s,"> at ",remoteip,0);
  1808. + }
  1809. + err_bmt();
  1810. + return;
  1811. + }
  1812. if (relayclient) {
  1813. --addr.len;
  1814. if (!stralloc_cats(&addr,relayclient)) die_nomem();
  1815. @@ -269,6 +518,11 @@
  1816. {
  1817. int r;
  1818. flush();
  1819. +#ifdef TLS
  1820. + if (ssl && fd == ssl_rfd)
  1821. + r = ssl_timeoutread(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
  1822. + else
  1823. +#endif
  1824. r = timeoutread(timeout,fd,buf,len);
  1825. if (r == -1) if (errno == error_timeout) die_alarm();
  1826. if (r <= 0) die_read();
  1827. @@ -378,7 +632,7 @@
  1828. qp = qmail_qp(&qqt);
  1829. out("354 go ahead\r\n");
  1830.  
  1831. - received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
  1832. + received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
  1833. blast(&hops);
  1834. hops = (hops >= MAXHOPS);
  1835. if (hops) qmail_fail(&qqt);
  1836. @@ -388,28 +642,494 @@
  1837. qqx = qmail_close(&qqt);
  1838. if (!*qqx) { acceptmessage(qp); return; }
  1839. if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
  1840. - if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
  1841. + if (databytes) if (!bytestooverflow) { err_size(); return; }
  1842. if (*qqx == 'D') out("554 "); else out("451 ");
  1843. out(qqx + 1);
  1844. out("\r\n");
  1845. }
  1846.  
  1847. +/* this file is too long ----------------------------------------- SMTP AUTH */
  1848. +
  1849. +char unique[FMT_ULONG + FMT_ULONG + 3];
  1850. +static stralloc authin = {0}; /* input from SMTP client */
  1851. +static stralloc user = {0}; /* authorization user-id */
  1852. +static stralloc pass = {0}; /* plain passwd or digest */
  1853. +static stralloc resp = {0}; /* b64 response */
  1854. +#ifdef CRAM_MD5
  1855. +static stralloc chal = {0}; /* plain challenge */
  1856. +static stralloc slop = {0}; /* b64 challenge */
  1857. +#endif
  1858. +
  1859. +int flagauth = 0;
  1860. +char **childargs;
  1861. +char ssauthbuf[512];
  1862. +substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
  1863. +
  1864. +int authgetl(void) {
  1865. + int i;
  1866. +
  1867. + if (!stralloc_copys(&authin,"")) die_nomem();
  1868. + for (;;) {
  1869. + if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
  1870. + i = substdio_get(&ssin,authin.s + authin.len,1);
  1871. + if (i != 1) die_read();
  1872. + if (authin.s[authin.len] == '\n') break;
  1873. + ++authin.len;
  1874. + }
  1875. +
  1876. + if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
  1877. + authin.s[authin.len] = 0;
  1878. + if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
  1879. + if (authin.len == 0) { return err_input(); }
  1880. + return authin.len;
  1881. +}
  1882. +
  1883. +int authenticate(void)
  1884. +{
  1885. + int child;
  1886. + int wstat;
  1887. + int pi[2];
  1888. +
  1889. + if (!stralloc_0(&user)) die_nomem();
  1890. + if (!stralloc_0(&pass)) die_nomem();
  1891. +#ifdef CRAM_MD5
  1892. + if (!stralloc_0(&chal)) die_nomem();
  1893. +#endif
  1894. +
  1895. + if (pipe(pi) == -1) return err_pipe();
  1896. + switch(child = fork()) {
  1897. + case -1:
  1898. + return err_fork();
  1899. + case 0:
  1900. + close(pi[1]);
  1901. + if(fd_copy(3,pi[0]) == -1) return err_pipe();
  1902. + sig_pipedefault();
  1903. + execvp(*childargs, childargs);
  1904. + _exit(1);
  1905. + }
  1906. + close(pi[0]);
  1907. +
  1908. + substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
  1909. + if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
  1910. + if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
  1911. +#ifdef CRAM_MD5
  1912. + if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
  1913. +#endif
  1914. + if (substdio_flush(&ssauth) == -1) return err_write();
  1915. +
  1916. + close(pi[1]);
  1917. +#ifdef CRAM_MD5
  1918. + if (!stralloc_copys(&chal,"")) die_nomem();
  1919. + if (!stralloc_copys(&slop,"")) die_nomem();
  1920. +#endif
  1921. + byte_zero(ssauthbuf,sizeof ssauthbuf);
  1922. + if (wait_pid(&wstat,child) == -1) return err_child();
  1923. + if (wait_crashed(wstat)) return err_child();
  1924. + if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */
  1925. + return 0; /* yes */
  1926. +}
  1927. +
  1928. +int auth_login(arg) char *arg;
  1929. +{
  1930. + int r;
  1931. +
  1932. + if (*arg) {
  1933. + if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
  1934. + }
  1935. + else {
  1936. + out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
  1937. + if (authgetl() < 0) return -1;
  1938. + if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
  1939. + }
  1940. + if (r == -1) die_nomem();
  1941. +
  1942. + out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
  1943. +
  1944. + if (authgetl() < 0) return -1;
  1945. + if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
  1946. + if (r == -1) die_nomem();
  1947. +
  1948. + if (!user.len || !pass.len) return err_input();
  1949. + return authenticate();
  1950. +}
  1951. +
  1952. +int auth_plain(arg) char *arg;
  1953. +{
  1954. + int r, id = 0;
  1955. +
  1956. + if (*arg) {
  1957. + if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input();
  1958. + }
  1959. + else {
  1960. + out("334 \r\n"); flush();
  1961. + if (authgetl() < 0) return -1;
  1962. + if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
  1963. + }
  1964. + if (r == -1 || !stralloc_0(&resp)) die_nomem();
  1965. + while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */
  1966. +
  1967. + if (resp.len > id + 1)
  1968. + if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
  1969. + if (resp.len > id + user.len + 2)
  1970. + if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
  1971. +
  1972. + if (!user.len || !pass.len) return err_input();
  1973. + return authenticate();
  1974. +}
  1975. +
  1976. +#ifdef CRAM_MD5
  1977. +int auth_cram()
  1978. +{
  1979. + int i, r;
  1980. + char *s;
  1981. +
  1982. + s = unique; /* generate challenge */
  1983. + s += fmt_uint(s,getpid());
  1984. + *s++ = '.';
  1985. + s += fmt_ulong(s,(unsigned long) now());
  1986. + *s++ = '@';
  1987. + *s++ = 0;
  1988. + if (!stralloc_copys(&chal,"<")) die_nomem();
  1989. + if (!stralloc_cats(&chal,unique)) die_nomem();
  1990. + if (!stralloc_cats(&chal,local)) die_nomem();
  1991. + if (!stralloc_cats(&chal,">")) die_nomem();
  1992. + if (b64encode(&chal,&slop) < 0) die_nomem();
  1993. + if (!stralloc_0(&slop)) die_nomem();
  1994. +
  1995. + out("334 "); /* "334 base64_challenge \r\n" */
  1996. + out(slop.s);
  1997. + out("\r\n");
  1998. + flush();
  1999. +
  2000. + if (authgetl() < 0) return -1; /* got response */
  2001. + if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
  2002. + if (r == -1 || !stralloc_0(&resp)) die_nomem();
  2003. +
  2004. + i = str_chr(resp.s,' ');
  2005. + s = resp.s + i;
  2006. + while (*s == ' ') ++s;
  2007. + resp.s[i] = 0;
  2008. + if (!stralloc_copys(&user,resp.s)) die_nomem(); /* userid */
  2009. + if (!stralloc_copys(&pass,s)) die_nomem(); /* digest */
  2010. +
  2011. + if (!user.len || !pass.len) return err_input();
  2012. + return authenticate();
  2013. +}
  2014. +#endif
  2015. +
  2016. +struct authcmd {
  2017. + char *text;
  2018. + int (*fun)();
  2019. +} authcmds[] = {
  2020. + { "login",auth_login }
  2021. +, { "plain",auth_plain }
  2022. +#ifdef CRAM_MD5
  2023. +, { "cram-md5",auth_cram }
  2024. +#endif
  2025. +, { 0,err_noauth }
  2026. +};
  2027. +
  2028. +void smtp_auth(arg)
  2029. +char *arg;
  2030. +{
  2031. + int i;
  2032. + char *cmd = arg;
  2033. +
  2034. + if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
  2035. + if (flagauth) { err_authd(); return; }
  2036. + if (seenmail) { err_authmail(); return; }
  2037. +
  2038. + if (!stralloc_copys(&user,"")) die_nomem();
  2039. + if (!stralloc_copys(&pass,"")) die_nomem();
  2040. + if (!stralloc_copys(&resp,"")) die_nomem();
  2041. +#ifdef CRAM_MD5
  2042. + if (!stralloc_copys(&chal,"")) die_nomem();
  2043. +#endif
  2044. +
  2045. + i = str_chr(cmd,' ');
  2046. + arg = cmd + i;
  2047. + while (*arg == ' ') ++arg;
  2048. + cmd[i] = 0;
  2049. +
  2050. + for (i = 0;authcmds[i].text;++i)
  2051. + if (case_equals(authcmds[i].text,cmd)) break;
  2052. +
  2053. + switch (authcmds[i].fun(arg)) {
  2054. + case 0:
  2055. + flagauth = 1;
  2056. + protocol = "ESMTPA";
  2057. + relayclient = "";
  2058. + remoteinfo = user.s;
  2059. + if (!env_unset("TCPREMOTEINFO")) die_read();
  2060. + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
  2061. + if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
  2062. + out("235 ok, go ahead (#2.0.0)\r\n");
  2063. + break;
  2064. + case 1:
  2065. + err_authfail(user.s,authcmds[i].text);
  2066. + }
  2067. +}
  2068. +
  2069. +
  2070. +/* this file is too long --------------------------------------------- GO ON */
  2071. +
  2072. +#ifdef TLS
  2073. +stralloc proto = {0};
  2074. +int ssl_verified = 0;
  2075. +const char *ssl_verify_err = 0;
  2076. +
  2077. +void smtp_tls(char *arg)
  2078. +{
  2079. + if (ssl) err_unimpl();
  2080. + else if (*arg) out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
  2081. + else tls_init();
  2082. +}
  2083. +
  2084. +RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen)
  2085. +{
  2086. + if (!export) keylen = 512;
  2087. + if (keylen == 512) {
  2088. + FILE *in = fopen("control/rsa512.pem", "r");
  2089. + if (in) {
  2090. + RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL);
  2091. + fclose(in);
  2092. + if (rsa) return rsa;
  2093. + }
  2094. + }
  2095. + return RSA_generate_key(keylen, RSA_F4, NULL, NULL);
  2096. +}
  2097. +
  2098. +DH *tmp_dh_cb(SSL *ssl, int export, int keylen)
  2099. +{
  2100. + if (!export) keylen = 1024;
  2101. + if (keylen == 512) {
  2102. + FILE *in = fopen("control/dh512.pem", "r");
  2103. + if (in) {
  2104. + DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
  2105. + fclose(in);
  2106. + if (dh) return dh;
  2107. + }
  2108. + }
  2109. + if (keylen == 1024) {
  2110. + FILE *in = fopen("control/dh1024.pem", "r");
  2111. + if (in) {
  2112. + DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
  2113. + fclose(in);
  2114. + if (dh) return dh;
  2115. + }
  2116. + }
  2117. + return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL);
  2118. +}
  2119. +
  2120. +/* don't want to fail handshake if cert isn't verifiable */
  2121. +int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
  2122. +
  2123. +void tls_nogateway()
  2124. +{
  2125. + /* there may be cases when relayclient is set */
  2126. + if (!ssl || relayclient) return;
  2127. + out("; no valid cert for gatewaying");
  2128. + if (ssl_verify_err) { out(": "); out(ssl_verify_err); }
  2129. +}
  2130. +void tls_out(const char *s1, const char *s2)
  2131. +{
  2132. + out("454 TLS "); out(s1);
  2133. + if (s2) { out(": "); out(s2); }
  2134. + out(" (#4.3.0)\r\n"); flush();
  2135. +}
  2136. +void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); }
  2137. +
  2138. +# define CLIENTCA "control/clientca.pem"
  2139. +# define CLIENTCRL "control/clientcrl.pem"
  2140. +# define SERVERCERT "control/servercert.pem"
  2141. +
  2142. +int tls_verify()
  2143. +{
  2144. + stralloc clients = {0};
  2145. + struct constmap mapclients;
  2146. +
  2147. + if (!ssl || relayclient || ssl_verified) return 0;
  2148. + ssl_verified = 1; /* don't do this twice */
  2149. +
  2150. + /* request client cert to see if it can be verified by one of our CAs
  2151. + * and the associated email address matches an entry in tlsclients */
  2152. + switch (control_readfile(&clients, "control/tlsclients", 0))
  2153. + {
  2154. + case 1:
  2155. + if (constmap_init(&mapclients, clients.s, clients.len, 0)) {
  2156. + /* if CLIENTCA contains all the standard root certificates, a
  2157. + * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE;
  2158. + * it is probably due to 0.9.6b supporting only 8k key exchange
  2159. + * data while the 0.9.6c release increases that limit to 100k */
  2160. + STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA);
  2161. + if (sk) {
  2162. + SSL_set_client_CA_list(ssl, sk);
  2163. + SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
  2164. + break;
  2165. + }
  2166. + constmap_free(&mapclients);
  2167. + }
  2168. + case 0: alloc_free(clients.s); return 0;
  2169. + case -1: die_control();
  2170. + }
  2171. +
  2172. + if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) {
  2173. + const char *err = ssl_error_str();
  2174. + tls_out("rehandshake failed", err); die_read();
  2175. + }
  2176. +
  2177. + do { /* one iteration */
  2178. + X509 *peercert;
  2179. + X509_NAME *subj;
  2180. + stralloc email = {0};
  2181. +
  2182. + int n = SSL_get_verify_result(ssl);
  2183. + if (n != X509_V_OK)
  2184. + { ssl_verify_err = X509_verify_cert_error_string(n); break; }
  2185. + peercert = SSL_get_peer_certificate(ssl);
  2186. + if (!peercert) break;
  2187. +
  2188. + subj = X509_get_subject_name(peercert);
  2189. + n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1);
  2190. + if (n >= 0) {
  2191. + const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value;
  2192. + if (s) { email.len = s->length; email.s = s->data; }
  2193. + }
  2194. +
  2195. + if (email.len <= 0)
  2196. + ssl_verify_err = "contains no email address";
  2197. + else if (!constmap(&mapclients, email.s, email.len))
  2198. + ssl_verify_err = "email address not in my list of tlsclients";
  2199. + else {
  2200. + /* add the cert email to the proto if it helped allow relaying */
  2201. + --proto.len;
  2202. + if (!stralloc_cats(&proto, "\n (cert ") /* continuation line */
  2203. + || !stralloc_catb(&proto, email.s, email.len)
  2204. + || !stralloc_cats(&proto, ")")
  2205. + || !stralloc_0(&proto)) die_nomem();
  2206. + relayclient = "";
  2207. + protocol = proto.s;
  2208. + }
  2209. +
  2210. + X509_free(peercert);
  2211. + } while (0);
  2212. + constmap_free(&mapclients); alloc_free(clients.s);
  2213. +
  2214. + /* we are not going to need this anymore: free the memory */
  2215. + SSL_set_client_CA_list(ssl, NULL);
  2216. + SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
  2217. +
  2218. + return relayclient ? 1 : 0;
  2219. +}
  2220. +
  2221. +void tls_init()
  2222. +{
  2223. + SSL *myssl;
  2224. + SSL_CTX *ctx;
  2225. + const char *ciphers;
  2226. + stralloc saciphers = {0};
  2227. + X509_STORE *store;
  2228. + X509_LOOKUP *lookup;
  2229. +
  2230. + SSL_library_init();
  2231. +
  2232. + /* a new SSL context with the bare minimum of options */
  2233. + ctx = SSL_CTX_new(SSLv23_server_method());
  2234. + if (!ctx) { tls_err("unable to initialize ctx"); return; }
  2235. +
  2236. + if (!SSL_CTX_use_certificate_chain_file(ctx, SERVERCERT))
  2237. + { SSL_CTX_free(ctx); tls_err("missing certificate"); return; }
  2238. + SSL_CTX_load_verify_locations(ctx, CLIENTCA, NULL);
  2239. +
  2240. +#if OPENSSL_VERSION_NUMBER >= 0x00907000L
  2241. + /* crl checking */
  2242. + store = SSL_CTX_get_cert_store(ctx);
  2243. + if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) &&
  2244. + (X509_load_crl_file(lookup, CLIENTCRL, X509_FILETYPE_PEM) == 1))
  2245. + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
  2246. + X509_V_FLAG_CRL_CHECK_ALL);
  2247. +#endif
  2248. +
  2249. + /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
  2250. + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
  2251. +
  2252. + /* a new SSL object, with the rest added to it directly to avoid copying */
  2253. + myssl = SSL_new(ctx);
  2254. + SSL_CTX_free(ctx);
  2255. + if (!myssl) { tls_err("unable to initialize ssl"); return; }
  2256. +
  2257. + /* this will also check whether public and private keys match */
  2258. + if (!SSL_use_RSAPrivateKey_file(myssl, SERVERCERT, SSL_FILETYPE_PEM))
  2259. + { SSL_free(myssl); tls_err("no valid RSA private key"); return; }
  2260. +
  2261. + ciphers = env_get("TLSCIPHERS");
  2262. + if (!ciphers) {
  2263. + if (control_readfile(&saciphers, "control/tlsserverciphers", 0) == -1)
  2264. + { SSL_free(myssl); die_control(); }
  2265. + if (saciphers.len) { /* convert all '\0's except the last one to ':' */
  2266. + int i;
  2267. + for (i = 0; i < saciphers.len - 1; ++i)
  2268. + if (!saciphers.s[i]) saciphers.s[i] = ':';
  2269. + ciphers = saciphers.s;
  2270. + }
  2271. + }
  2272. + if (!ciphers || !*ciphers) ciphers = "DEFAULT";
  2273. + SSL_set_cipher_list(myssl, ciphers);
  2274. + alloc_free(saciphers.s);
  2275. +
  2276. + SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb);
  2277. + SSL_set_tmp_dh_callback(myssl, tmp_dh_cb);
  2278. + SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin));
  2279. + SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout));
  2280. +
  2281. + if (!smtps) { out("220 ready for tls\r\n"); flush(); }
  2282. +
  2283. + if (ssl_timeoutaccept(timeout, ssl_rfd, ssl_wfd, myssl) <= 0) {
  2284. + /* neither cleartext nor any other response here is part of a standard */
  2285. + const char *err = ssl_error_str();
  2286. + ssl_free(myssl); tls_out("connection failed", err); die_read();
  2287. + }
  2288. + ssl = myssl;
  2289. +
  2290. + /* populate the protocol string, used in Received */
  2291. + if (!stralloc_copys(&proto, "ESMTPS (")
  2292. + || !stralloc_cats(&proto, SSL_get_cipher(ssl))
  2293. + || !stralloc_cats(&proto, " encrypted)")) die_nomem();
  2294. + if (!stralloc_0(&proto)) die_nomem();
  2295. + protocol = proto.s;
  2296. +
  2297. + /* have to discard the pre-STARTTLS HELO/EHLO argument, if any */
  2298. + dohelo(remotehost);
  2299. +}
  2300. +
  2301. +# undef SERVERCERT
  2302. +# undef CLIENTCA
  2303. +
  2304. +#endif
  2305. +
  2306. struct commands smtpcommands[] = {
  2307. { "rcpt", smtp_rcpt, 0 }
  2308. , { "mail", smtp_mail, 0 }
  2309. , { "data", smtp_data, flush }
  2310. +, { "auth", smtp_auth, flush }
  2311. , { "quit", smtp_quit, flush }
  2312. , { "helo", smtp_helo, flush }
  2313. , { "ehlo", smtp_ehlo, flush }
  2314. , { "rset", smtp_rset, 0 }
  2315. , { "help", smtp_help, flush }
  2316. +#ifdef TLS
  2317. +, { "starttls", smtp_tls, flush }
  2318. +#endif
  2319. , { "noop", err_noop, flush }
  2320. , { "vrfy", err_vrfy, flush }
  2321. , { 0, err_unimpl, flush }
  2322. } ;
  2323.  
  2324. -void main()
  2325. +void main(argc,argv)
  2326. +int argc;
  2327. +char **argv;
  2328. {
  2329. + childargs = argv + 1;
  2330. sig_pipeignore();
  2331. if (chdir(auto_qmail) == -1) die_control();
  2332. setup();
  2333. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qregex.c ./netqmail-1.05/netqmail-1.05/qregex.c
  2334. --- ./netqmail-1.05.orig/netqmail-1.05/qregex.c 1969-12-31 19:00:00.000000000 -0500
  2335. +++ ./netqmail-1.05/netqmail-1.05/qregex.c 2006-05-10 19:29:13.789887397 -0400
  2336. @@ -0,0 +1,57 @@
  2337. +/*
  2338. + * qregex (v2)
  2339. + * $Id: qregex.c,v 2.1 2001/12/28 07:05:21 evan Exp $
  2340. + *
  2341. + * Author : Evan Borgstrom (evan at unixpimps dot org)
  2342. + * Created : 2001/12/14 23:08:16
  2343. + * Modified: $Date: 2001/12/28 07:05:21 $
  2344. + * Revision: $Revision: 2.1 $
  2345. + *
  2346. + * Do POSIX regex matching on addresses for anti-relay / spam control.
  2347. + * It logs to the maillog
  2348. + * See the qregex-readme file included with this tarball.
  2349. + * If you didn't get this file in a tarball please see the following URL:
  2350. + * http://www.unixpimps.org/software/qregex
  2351. + *
  2352. + * qregex.c is released under a BSD style copyright.
  2353. + * See http://www.unixpimps.org/software/qregex/copyright.html
  2354. + *
  2355. + * Note: this revision follows the coding guidelines set forth by the rest of
  2356. + * the qmail code and that described at the following URL.
  2357. + * http://cr.yp.to/qmail/guarantee.html
  2358. + *
  2359. + */
  2360. +
  2361. +#include <sys/types.h>
  2362. +#include <regex.h>
  2363. +#include "qregex.h"
  2364. +
  2365. +#define REGCOMP(X,Y) regcomp(&X, Y, REG_EXTENDED|REG_ICASE)
  2366. +#define REGEXEC(X,Y) regexec(&X, Y, (size_t)0, (regmatch_t *)0, (int)0)
  2367. +
  2368. +int matchregex(char *text, char *regex) {
  2369. + regex_t qreg;
  2370. + int retval = 0;
  2371. +
  2372. +
  2373. + /* build the regex */
  2374. + if ((retval = REGCOMP(qreg, regex)) != 0) {
  2375. + regfree(&qreg);
  2376. + return(-retval);
  2377. + }
  2378. +
  2379. + /* execute the regex */
  2380. + if ((retval = REGEXEC(qreg, text)) != 0) {
  2381. + /* did we just not match anything? */
  2382. + if (retval == REG_NOMATCH) {
  2383. + regfree(&qreg);
  2384. + return(0);
  2385. + }
  2386. + regfree(&qreg);
  2387. + return(-retval);
  2388. + }
  2389. +
  2390. + /* signal the match */
  2391. + regfree(&qreg);
  2392. + return(1);
  2393. +}
  2394. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/qregex.h ./netqmail-1.05/netqmail-1.05/qregex.h
  2395. --- ./netqmail-1.05.orig/netqmail-1.05/qregex.h 1969-12-31 19:00:00.000000000 -0500
  2396. +++ ./netqmail-1.05/netqmail-1.05/qregex.h 2006-05-10 19:29:13.789887397 -0400
  2397. @@ -0,0 +1,5 @@
  2398. +/* simple header file for the matchregex prototype */
  2399. +#ifndef _QREGEX_H_
  2400. +#define _QREGEX_H_
  2401. +int matchregex(char *text, char *regex);
  2402. +#endif
  2403. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/README.auth ./netqmail-1.05/netqmail-1.05/README.auth
  2404. --- ./netqmail-1.05.orig/netqmail-1.05/README.auth 1969-12-31 19:00:00.000000000 -0500
  2405. +++ ./netqmail-1.05/netqmail-1.05/README.auth 2006-05-10 19:28:51.237862925 -0400
  2406. @@ -0,0 +1,66 @@
  2407. +README qmail-smtpd SMTP Authentication
  2408. +======================================
  2409. +
  2410. +
  2411. +History:
  2412. +--------
  2413. +
  2414. +This patch is based on Krzysztof Dabrowski's qmail-smtpd-auth-0.31 patch
  2415. +which itself uses "Mrs. Brisby's" initial code.
  2416. +Version 0.41 of this patch fixes the "CAPS-LOCK" typo announcing
  2417. +'CRAM_MD5' instead of 'CRAM-MD5' (german keyboard) - tx to Mike Garrison.
  2418. +Version 0.42 fixes the '421 unable to read controls (#4.3.0)' problem
  2419. +(can't read control/morercpthosts.cdb) because FD 3 was already closed - tx Richard Lyons.
  2420. +Version 0.43 fixes the ba64decode() failure in case CRAM_MD5 is not enabled - tx Vladimir Zidar.
  2421. +Version 0.51 includes the evaluation of the 'Auth' and the 'Size' parameter in the 'Mail From:' command.
  2422. +Version 0.52 uses DJB functions to copy FDs.
  2423. +Version 0.56 corrects some minor mistakes displaying the 'Auth' userid.
  2424. +Version 0.57 uses keyword "ESMTPA" in Received header in case of authentication to comply with RFC 3848.
  2425. +
  2426. +
  2427. +Scope:
  2428. +------
  2429. +
  2430. +This patch supports RFC 2554 "SMTP Service Extension for Authentication" for qmail-smtpd.
  2431. +Additionally, RFC 1870 is honoured ("SMTP Service Extension for Message Size Declaration").
  2432. +For more technical details see: http://www.fehcom.de/qmail/docu/smtpauth.html.
  2433. +
  2434. +
  2435. +Installation:
  2436. +-------------
  2437. +
  2438. +* Untar the source in the qmail-1.03 home direcotry.
  2439. +* Run ./install_auth.
  2440. +* Modify the compile time option "#define CRAM_MD5" to your needs.
  2441. +* Re-make qmail.
  2442. +
  2443. +
  2444. +Setup:
  2445. +------
  2446. +
  2447. +In order to use SMTP Authentication you have to use a 'Pluggable Authentication Module'
  2448. +PAM to be called by qmail-smtpd; typically
  2449. +
  2450. + /var/qmail/bin/qmail-smtpd /bin/checkpassword true 2>&1
  2451. +
  2452. +Since qmail-smtpd does not run as root, checkpassword has to be made sticky.
  2453. +There is no need to include additionally the hostname in the call.
  2454. +In order to compute the CRAM-MD5 challenge, qmail-smtpd uses the 'tcplocalhost' information.
  2455. +
  2456. +
  2457. +Changes wrt. Krysztof Dabrowski's patch:
  2458. +----------------------------------------
  2459. +
  2460. +* Avoid the 'hostname' in the call of the PAM.
  2461. +* Confirm to Dan Bernstein's checkpassword interface even for CRAM-MD5.
  2462. +* Doesn't close FD 2; thus not inhibiting logging to STDERR.
  2463. +* Fixed bugs in base64.c.
  2464. +* Modified unconditional close of FD 3 in order to sustain reading of 'control/morecpthosts.cdb'.
  2465. +* Evaluation of the (informational) Mail From: < > Auth=username.
  2466. +* Additional support for the advertised "Size" via 'Mail From: <return-path> SIZE=123456780' (RFC 1870).
  2467. +* RFC 3848 conformance for Received header in case of SMTP Auth.
  2468. +
  2469. +
  2470. +Erwin Hoffmann - Cologne 2005-01-23 (www.fehcom.de)
  2471. +
  2472. +
  2473. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/README.qregex ./netqmail-1.05/netqmail-1.05/README.qregex
  2474. --- ./netqmail-1.05.orig/netqmail-1.05/README.qregex 1969-12-31 19:00:00.000000000 -0500
  2475. +++ ./netqmail-1.05/netqmail-1.05/README.qregex 2006-05-10 19:29:13.790887220 -0400
  2476. @@ -0,0 +1,203 @@
  2477. +QREGEX (v2) 20060423 - README April 23, 2006
  2478. +A Regular Expression matching patch for qmail 1.03 and netqmail
  2479. +
  2480. +
  2481. +OVERVIEW:
  2482. +
  2483. +qregex adds the ability to match address evelopes via Regular Expressions (REs)
  2484. +in the qmail-smtpd process. It has the abiltiy to match `helo/ehlo` (host name),
  2485. +`mail from` (envelope sender), and `rcpt to` (envelope recipient) commands.
  2486. +It follows all the base rules that are set out with qmail (ie using control
  2487. +files) so it makes for easy integretion into an existing setup (see the
  2488. +install instructions for more info). The v2 is specified because qregex was
  2489. +re-written to better conform to the security guarantee set forth by the author
  2490. +of qmail. The original version used stdio.h and stdlib.h for reading the
  2491. +control files whereas v2 now uses all stralloc functions which are much more
  2492. +regulated against buffer overruns and the like.
  2493. +See: http://cr.yp.to/qmail/guarantee.html
  2494. +
  2495. +
  2496. +FEATURES:
  2497. +
  2498. +Features of qregex include:
  2499. +
  2500. +1. Performs pattern matching on envelope senders and envelope
  2501. + recipients against REs in the badmailfrom and badmailto control
  2502. + files. Two additional control files, badmailfromnorelay and
  2503. + badmailtonorelay, are used for pattern matching when the
  2504. + RELAYCLIENT environment variable is not set.
  2505. +
  2506. +2. Performs pattern matching on the helo/ehlo host name. Setting the
  2507. + NOBADHELO environment variable prevents the host name from being
  2508. + compared to the patterns in the badhelo control file.
  2509. +
  2510. +3. Matches to patterns are logged. Setting the LOGREGEX environment
  2511. + variable causes the matched regex pattern to be included in the log.
  2512. +
  2513. +4. Matching is case insensitive.
  2514. +
  2515. +5. qregex ignores empty envelope senders. An empty envelope sender is not
  2516. + compared to the patterns in the badmailfrom and badmailfromnorelay
  2517. + control files and is always accepted.
  2518. +
  2519. +
  2520. +PLATFORMS:
  2521. +
  2522. +qregex has been built and tested on the following platforms. I'm sure it won't
  2523. +have any problems on any platform that qmail will run on (providing they have
  2524. +a regex interface) but if you run into problems let me know.
  2525. +
  2526. + - OpenBSD 3.x
  2527. + - FreeBSD 4.x, 5.x
  2528. + - Mandrake Linux 9.x
  2529. + - SuSE Linux 8.x
  2530. +
  2531. +
  2532. +
  2533. +INSTALLATION INSTRUCTIONS:
  2534. +
  2535. +Installation is very simple, there is only one requirement. You need to use the
  2536. +GNU version of the patch utility (http://www.gnu.org/software/patch/patch.html).
  2537. +(For Solaris 8 users it is installed as 'gpatch')
  2538. +
  2539. +- If this is a new setup.
  2540. +Unpack the qmail archive, cd into the qmail-1.03 directory and run
  2541. +"patch < /path/to/qregex-<version>.patch". Follow the instructions as per the
  2542. +included qmail INSTALL file. Once you are done come back to this file and read
  2543. +the section on the control files.
  2544. +
  2545. +If you are using netqmail, then unpack the netqmail archive. Run the collate.sh
  2546. +script and cd into the resulting netqmail-<version> directory. From there, run
  2547. +"patch < /path/to/qregex-<version>.patch". Complete the netqmail installation
  2548. +normally. Once you are done, come back to this file and read the section on the
  2549. +control files.
  2550. +
  2551. +- If this is an existing setup.
  2552. +FIRST: create your control files (see below).
  2553. +cd into your existing qmail or netqmail source directory. Run
  2554. +"patch < /path/to/qregex-<version>.patch" then "make qmail-smtpd". Now run
  2555. +./qmail-smtpd and test your new rules to make sure they work as expected.
  2556. +
  2557. +Install the new binary by cd'ing to /var/qmail/bin and as root (in one command)
  2558. +copy the existing binary to 'qmail-smtpd.old' and copy the new binary from the
  2559. +source directory to 'qmail-smtpd'.
  2560. +(ex. cp qmail-smtpd qmail-smtpd.old && cp ~/qmail-1.03/qmail-smtpd qmail-smtpd)
  2561. +
  2562. +You can also optionally just run "make setup check" as it will install the
  2563. +updated documentation and man pages provided with this patch. Stopping qmail
  2564. +before doing the "make setup check" is always a good idea.
  2565. +
  2566. +
  2567. +LOGGING:
  2568. +
  2569. +qregex will log matches to the patterns in the various control files. Log
  2570. +messages will take these three forms depending on which control file was
  2571. +matched:
  2572. +
  2573. +badhelo
  2574. +qmail-smtpd: badhelo: <host> at <remote IP>
  2575. +
  2576. +badmailfrom and badmailfromnorelay
  2577. +qmail-smtpd: badmailfrom: <sender address> at <remote IP>
  2578. +
  2579. +badmailto and badmailtonorelay
  2580. +qmail-smtpd: badmailto: <rcpt address> at <remote IP>
  2581. +
  2582. +When the LOGREGEX environment variable is set, the matched pattern will
  2583. +be included in the log. Log messages will have the regex pattern appended
  2584. +to them. For example, a badhelo log message will look like this:
  2585. +
  2586. +qmail-smtpd: badhelo: <host> at <remote IP> matches pattern: <regex>
  2587. +
  2588. +
  2589. +CONTROL FILES:
  2590. +
  2591. +qregex provides you with five control files. None of these control files
  2592. +is mandatory and you can use them in any combination you choose in your setup.
  2593. +
  2594. +The "control/badmailfrom" and "control/badmailto" files contain your REs for
  2595. +matching against the 'mail from' (envelope sender) and 'rcpt to' (envelope
  2596. +recipient) smtp commands respectively.
  2597. +The "control/badmailfromnorelay" and "control/badmailtonorelay" match against
  2598. +the same commands but are read only when the RELAYCLIENT environment variable
  2599. +is not set.
  2600. +The "control/badhelo" file matches against the 'helo/ehlo' smtp command.
  2601. +
  2602. +If you prefer you can symlink the badmailfrom and badmailto control files
  2603. +(ln -s badmailfrom badmailto) and maintain fewer sets of rules. Beware
  2604. +this might cause problems in certain setups.
  2605. +
  2606. + Here's an example "badhelo" file.
  2607. + -----------------------------------
  2608. + # block host strings with no dot (not a FQDN)
  2609. + !\.
  2610. + -----------------------------------
  2611. +
  2612. + An example "badmailfrom" file.
  2613. + -----------------------------------
  2614. + # this will drop everything containing the string
  2615. + # bad.domain.com or Bad.Domain.Com or BAD.domain.COM
  2616. + bad\.domain\.com
  2617. + # force users to fully qualify themselves
  2618. + # (i.e. deny "user", accept "user@domain")
  2619. + !@
  2620. + -----------------------------------
  2621. +
  2622. + And "badmailto" (a little more interesting)
  2623. + -----------------------------------
  2624. + # must not contain invalid characters, brakets or multiple @'s
  2625. + [!%#:*^(){}]
  2626. + @.*@
  2627. + -----------------------------------
  2628. +
  2629. +You can use the non-RE character '!' to start an RE as a signal to qregex to
  2630. +negate the action. As used above in the badmailfrom file, by negating the '@'
  2631. +symbol qregex will signal qmail-smtpd to deny the 'mail from' command whenever
  2632. +the address doesn't contain an @ symbol. When used inside a bracket expression,
  2633. +the '!' character looses this special meaning. This is shown in the badmailto
  2634. +example.
  2635. +
  2636. +The norelay control files follow the same rules as the other control files but
  2637. +are intended to address two specific scenarios.
  2638. +The badmailfromnorelay file can be used to block mail trying to spoof a domain
  2639. +hosted on your mail server. It prevents a mail client that is not allowed to
  2640. +relay email through your server from using one of your hosted domains as its
  2641. +envelope sender.
  2642. +The badmailtonorelay file can be used to create email addresses that cannot
  2643. +receive mail from any source not allowed to relay email through your server.
  2644. +This is handy for creating email addresses for use only within your own
  2645. +domain(s) that can't receive spam from the world at large.
  2646. +
  2647. +
  2648. +INTERNALS:
  2649. +
  2650. +qregex (or regexmatch as the function is called) will be called during the
  2651. +`helo/ehlo`, `rcpt to` and `mail from` handling routines in "qmail-smtpd.c".
  2652. +When called, it will read the proper control file then one by one compile and
  2653. +execute the regex on the string passed into qmail-smtpd. If the regex matches
  2654. +it returns TRUE (1) and the qmail-smtpd process will deny the user the ability
  2655. +to continue. If you change anything and think it betters this patch please
  2656. +send me a new diff file so I can take a peek.
  2657. +
  2658. +
  2659. +CONTACT:
  2660. +qregex is maintained by:
  2661. + Andrew St. Jean
  2662. + andrew@arda.homeunix.net
  2663. + www.arda.homeunix.net/store/qmail/
  2664. +
  2665. +Contributers to qregex:
  2666. + Jeremy Kitchen
  2667. + kitchen at scriptkitchen dot com
  2668. + http://www.scriptkitchen.com/qmail
  2669. +
  2670. + Alex Pleiner
  2671. + alex@zeitform.de
  2672. + zeitform Internet Dienste
  2673. + http://www.zeitform.de/
  2674. +
  2675. + Thanos Massias
  2676. +
  2677. +Original qregex patch written by:
  2678. + Evan Borgstrom
  2679. + evan at unixpimps dot org
  2680. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/README.remote-auth ./netqmail-1.05/netqmail-1.05/README.remote-auth
  2681. --- ./netqmail-1.05.orig/netqmail-1.05/README.remote-auth 1969-12-31 19:00:00.000000000 -0500
  2682. +++ ./netqmail-1.05/netqmail-1.05/README.remote-auth 2006-05-10 19:28:51.237862925 -0400
  2683. @@ -0,0 +1,31 @@
  2684. +Docs for http://www.qmail.org/qmail-remote_authenticated_smtp.patch
  2685. +a patch to convince qmail-remote to use Authenticated SMTP when
  2686. +talking to certain hosts.
  2687. +
  2688. +This version of the patch has been modified by Robert Sanders so that
  2689. +base64 encoding of usernames and passwords is done automatically by
  2690. +qmail-remote.
  2691. +
  2692. +After applying the patch, the username password go into
  2693. +/var/qmail/control/smtproutes like so:
  2694. +
  2695. +domain:relay username password
  2696. +
  2697. +The domain:relay part is identical to a normal smtproutes entry (see
  2698. +the qmail-remote man page). For sites that require authentication, you
  2699. +simply add two space separated fields to the line, where the first
  2700. +field is the username, the second is the password. For example:
  2701. +
  2702. +inside.af.mil:firewall.af.mil:26 johndoe secret
  2703. +
  2704. +would send mail for inside.af.mil to firewall.af.mil, port 26 using
  2705. +username 'johndoe' and password 'secret'
  2706. +
  2707. +Since smtproutes will contain plain text usernames and passwords
  2708. +you might want to make the file owned by qmailr and set its permissions
  2709. +to 0600. Of course, the entries are going to go over the wire in the clear
  2710. +anyway as part of the SMTP transaction.
  2711. +
  2712. +Good luck.
  2713. +
  2714. +j.
  2715. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/README.starttls ./netqmail-1.05/netqmail-1.05/README.starttls
  2716. --- ./netqmail-1.05.orig/netqmail-1.05/README.starttls 1969-12-31 19:00:00.000000000 -0500
  2717. +++ ./netqmail-1.05/netqmail-1.05/README.starttls 2006-05-10 19:28:51.238862749 -0400
  2718. @@ -0,0 +1,103 @@
  2719. +Frederik Vermeulen <qmail-tls akrul inoa.net> 20060104
  2720. +http://inoa.net/qmail-tls/
  2721. +
  2722. +This patch implements RFC 3207 (was RFC 2487) in qmail.
  2723. +This means you can get SSL or TLS encrypted and
  2724. +authenticated SMTP between the MTAs and from MUA to MTA.
  2725. +The code is considered experimental (but has worked for
  2726. +many since its first release on 1999-03-21).
  2727. +
  2728. +Usage: - install OpenSSL-0.9.8 http://www.openssl.org/
  2729. + (any 0.9.6 to 0.9.8 version is presumed to work)
  2730. + - apply patch to netqmail-1.05 http://qmail.org/netqmail
  2731. + (should work on qmail-1.03 too). The patches to
  2732. + qmail-remote.c and qmail-smtpd.c can be applied separately.
  2733. + - provide a server certificate in /var/qmail/control/servercert.pem.
  2734. + "make cert" makes a self-signed certificate.
  2735. + "make cert-req" makes a certificate request.
  2736. + Note: you can add the CA certificate and intermediate
  2737. + certs to the end of servercert.pem.
  2738. + - replace qmail-smtpd and/or qmail-remote binary
  2739. + - verify operation (header information should show
  2740. + something like
  2741. + "Received [..] with (DHE-RSA-AES256-SHA encrypted) SMTP;")
  2742. + If you don't have a server to test with, you can test
  2743. + by sending mail to tag-ping@tbs-internet.com,
  2744. + which will bounce your mail.
  2745. +
  2746. +Optional: - when DEBUG is defined, some extra TLS info will be logged
  2747. + - qmail-remote will authenticate with the certificate in
  2748. + /var/qmail/control/clientcert.pem. By preference this is
  2749. + the same as servercert.pem, where nsCertType should be
  2750. + == server,client or be a generic certificate (no usage specified).
  2751. + - when a 512 bit RSA key is provided in /var/qmail/control/rsa512.pem,
  2752. + this key will be used instead of (slow) on-the-fly generation by
  2753. + qmail-smtpd. Idem for 512 and 1024 DH params in control/dh512.pem
  2754. + and control/dh1024.pem. `make tmprsadh` does this.
  2755. + Periodical replacement can be done by crontab:
  2756. + 01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1
  2757. + - server authentication:
  2758. + qmail-remote requires authentication from servers for which
  2759. + /var/qmail/control/tlshosts/host.dom.ain.pem exists.
  2760. + The .pem file contains the validating CA certificates
  2761. + (or self-signed server certificate). CommonName has to match.
  2762. + WARNING: this option may cause mail to be delayed, bounced,
  2763. + doublebounced, and lost.
  2764. + If /var/qmail/control/tlshosts/exhaustivelist is present,
  2765. + the lists of hosts in /var/qmail/control/tlshosts is
  2766. + an exhaustive list of hosts TLS is tried on.
  2767. + If /var/qmail/control/notlshosts/host.dom.ain is present,
  2768. + no TLS is tried on this host.
  2769. + - client authentication:
  2770. + when relay rules would reject an incoming mail,
  2771. + qmail-smtpd can allow the mail based on a presented cert.
  2772. + Certs are verified against a CA list in
  2773. + /var/qmail/control/clientca.pem (eg. http://www.modssl.org/
  2774. + source/cvs/exp/mod_ssl/pkg.mod_ssl/pkg.sslcfg/ca-bundle.crt)
  2775. + and the cert email-address has to match a line in
  2776. + /var/qmail/control/tlsclients. This email-address is logged
  2777. + in the headers. CRLs can be provided through
  2778. + /var/qmail/control/clientcrl.pem.
  2779. + - cipher selection:
  2780. + qmail-remote:
  2781. + openssl cipher string (`man ciphers`) read from
  2782. + /var/qmail/control/tlsclientciphers
  2783. + qmail-smtpd:
  2784. + openssl cipher string read from TLSCIPHERS environment variable
  2785. + (can vary based on client IP address e.g.)
  2786. + or if that is not available /var/qmail/control/tlsserverciphers
  2787. + - smtps (deprecated SMTP over TLS via port 465):
  2788. + qmail-remote: when connecting to port 465
  2789. + qmail-smtpd: when SMTPS environment variable is not empty
  2790. +
  2791. +Caveats: - do a `make clean` after patching
  2792. + - binaries dynamically linked with current openssl versions need
  2793. + recompilation when the shared openssl libs are upgraded.
  2794. + - this patch could conflict with other patches (notably those
  2795. + replacing \n with \r\n, which is a bad idea on encrypted links).
  2796. + - some broken servers have a problem with TLSv1 compatibility.
  2797. + Uncomment the line where we set the SSL_OP_NO_TLSv1 option.
  2798. + - needs working /dev/urandom (or EGD for openssl versions >0.9.7)
  2799. + for seeding random number generator.
  2800. + - packagers should make sure that installing without a valid
  2801. + servercert is impossible
  2802. + - when applied in combination with AUTH patch, AUTH patch
  2803. + should be applied first and first part of this patch
  2804. + will fail. This error can be ignored. Packagers should
  2805. + cut the first 12 lines of this patch to make a happy
  2806. + patch
  2807. + - `make tmprsadh` is recommended (or should I say required),
  2808. + otherwise DH generation can be unpredictably slow
  2809. + - some need "-I/usr/kerberos/include" to be added in conf-cc
  2810. +
  2811. +Copyright: GPL
  2812. + Links with OpenSSL
  2813. + Inspiration and code from examples in SSLeay (E. Young
  2814. + <eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>),
  2815. + stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>),
  2816. + Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>),
  2817. + modssl (R. Engelschall <rse@engelschall.com>),
  2818. + openssl examples of E. Rescorla <ekr@rtfm.com>.
  2819. +
  2820. +Bug reports: mailto:<qmail-tls akrul inoa.net>
  2821. +
  2822. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/ssl_timeoutio.c ./netqmail-1.05/netqmail-1.05/ssl_timeoutio.c
  2823. --- ./netqmail-1.05.orig/netqmail-1.05/ssl_timeoutio.c 1969-12-31 19:00:00.000000000 -0500
  2824. +++ ./netqmail-1.05/netqmail-1.05/ssl_timeoutio.c 2006-05-10 19:28:51.238862749 -0400
  2825. @@ -0,0 +1,95 @@
  2826. +#include "select.h"
  2827. +#include "error.h"
  2828. +#include "ndelay.h"
  2829. +#include "now.h"
  2830. +#include "ssl_timeoutio.h"
  2831. +
  2832. +int ssl_timeoutio(int (*fun)(),
  2833. + int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
  2834. +{
  2835. + int n;
  2836. + const datetime_sec end = (datetime_sec)t + now();
  2837. +
  2838. + do {
  2839. + fd_set fds;
  2840. + struct timeval tv;
  2841. +
  2842. + const int r = buf ? fun(ssl, buf, len) : fun(ssl);
  2843. + if (r > 0) return r;
  2844. +
  2845. + t = end - now();
  2846. + if (t < 0) break;
  2847. + tv.tv_sec = (time_t)t; tv.tv_usec = 0;
  2848. +
  2849. + FD_ZERO(&fds);
  2850. + switch (SSL_get_error(ssl, r))
  2851. + {
  2852. + default: return r; /* some other error */
  2853. + case SSL_ERROR_WANT_READ:
  2854. + FD_SET(rfd, &fds); n = select(rfd + 1, &fds, NULL, NULL, &tv);
  2855. + break;
  2856. + case SSL_ERROR_WANT_WRITE:
  2857. + FD_SET(wfd, &fds); n = select(wfd + 1, NULL, &fds, NULL, &tv);
  2858. + break;
  2859. + }
  2860. +
  2861. + /* n is the number of descriptors that changed status */
  2862. + } while (n > 0);
  2863. +
  2864. + if (n != -1) errno = error_timeout;
  2865. + return -1;
  2866. +}
  2867. +
  2868. +int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl)
  2869. +{
  2870. + int r;
  2871. +
  2872. + /* if connection is established, keep NDELAY */
  2873. + if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
  2874. + r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
  2875. +
  2876. + if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
  2877. + else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
  2878. +
  2879. + return r;
  2880. +}
  2881. +
  2882. +int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl)
  2883. +{
  2884. + int r;
  2885. +
  2886. + /* if connection is established, keep NDELAY */
  2887. + if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
  2888. + r = ssl_timeoutio(SSL_connect, t, rfd, wfd, ssl, NULL, 0);
  2889. +
  2890. + if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
  2891. + else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
  2892. +
  2893. + return r;
  2894. +}
  2895. +
  2896. +int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl)
  2897. +{
  2898. + int r;
  2899. +
  2900. + SSL_renegotiate(ssl);
  2901. + r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
  2902. + if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r;
  2903. +
  2904. + /* this is for the server only */
  2905. + ssl->state = SSL_ST_ACCEPT;
  2906. + return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
  2907. +}
  2908. +
  2909. +int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
  2910. +{
  2911. + if (!buf) return 0;
  2912. + if (SSL_pending(ssl)) return SSL_read(ssl, buf, len);
  2913. + return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
  2914. +}
  2915. +
  2916. +int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
  2917. +{
  2918. + if (!buf) return 0;
  2919. + return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
  2920. +}
  2921. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/ssl_timeoutio.h ./netqmail-1.05/netqmail-1.05/ssl_timeoutio.h
  2922. --- ./netqmail-1.05.orig/netqmail-1.05/ssl_timeoutio.h 1969-12-31 19:00:00.000000000 -0500
  2923. +++ ./netqmail-1.05/netqmail-1.05/ssl_timeoutio.h 2006-05-10 19:28:51.239862573 -0400
  2924. @@ -0,0 +1,21 @@
  2925. +#ifndef SSL_TIMEOUTIO_H
  2926. +#define SSL_TIMEOUTIO_H
  2927. +
  2928. +#include <openssl/ssl.h>
  2929. +
  2930. +/* the version is like this: 0xMNNFFPPS: major minor fix patch status */
  2931. +#if OPENSSL_VERSION_NUMBER < 0x00906000L
  2932. +# error "Need OpenSSL version at least 0.9.6"
  2933. +#endif
  2934. +
  2935. +int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl);
  2936. +int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl);
  2937. +int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl);
  2938. +
  2939. +int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
  2940. +int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
  2941. +
  2942. +int ssl_timeoutio(
  2943. + int (*fun)(), int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
  2944. +
  2945. +#endif
  2946. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/TARGETS ./netqmail-1.05/netqmail-1.05/TARGETS
  2947. --- ./netqmail-1.05.orig/netqmail-1.05/TARGETS 1998-06-15 06:53:16.000000000 -0400
  2948. +++ ./netqmail-1.05/netqmail-1.05/TARGETS 2006-05-10 19:29:13.791887044 -0400
  2949. @@ -10,6 +10,7 @@
  2950. qmail.o
  2951. quote.o
  2952. now.o
  2953. +base64.o
  2954. gfrom.o
  2955. myctime.o
  2956. slurpclose.o
  2957. @@ -168,6 +169,8 @@
  2958. constmap.o
  2959. timeoutread.o
  2960. timeoutwrite.o
  2961. +tls.o
  2962. +ssl_timeoutio.o
  2963. timeoutconn.o
  2964. tcpto.o
  2965. dns.o
  2966. @@ -252,6 +255,7 @@
  2967. qmail-qmtpd
  2968. qmail-smtpd.o
  2969. qmail-smtpd
  2970. +qregex.o
  2971. sendmail.o
  2972. sendmail
  2973. tcp-env.o
  2974. @@ -320,6 +324,7 @@
  2975. binm2+df
  2976. binm3
  2977. binm3+df
  2978. +Makefile-cert
  2979. it
  2980. qmail-local.0
  2981. qmail-lspawn.0
  2982. @@ -385,3 +390,4 @@
  2983. man
  2984. setup
  2985. check
  2986. +update_tmprsadh
  2987. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/tls.c ./netqmail-1.05/netqmail-1.05/tls.c
  2988. --- ./netqmail-1.05.orig/netqmail-1.05/tls.c 1969-12-31 19:00:00.000000000 -0500
  2989. +++ ./netqmail-1.05/netqmail-1.05/tls.c 2006-05-10 19:28:51.240862397 -0400
  2990. @@ -0,0 +1,25 @@
  2991. +#include "exit.h"
  2992. +#include "error.h"
  2993. +#include <openssl/ssl.h>
  2994. +#include <openssl/err.h>
  2995. +
  2996. +int smtps = 0;
  2997. +SSL *ssl = NULL;
  2998. +
  2999. +void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); }
  3000. +void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); }
  3001. +
  3002. +const char *ssl_error()
  3003. +{
  3004. + int r = ERR_get_error();
  3005. + if (!r) return NULL;
  3006. + SSL_load_error_strings();
  3007. + return ERR_error_string(r, NULL);
  3008. +}
  3009. +const char *ssl_error_str()
  3010. +{
  3011. + const char *err = ssl_error();
  3012. + if (err) return err;
  3013. + if (!errno) return 0;
  3014. + return (errno == error_timeout) ? "timed out" : error_str(errno);
  3015. +}
  3016. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/tls.h ./netqmail-1.05/netqmail-1.05/tls.h
  3017. --- ./netqmail-1.05.orig/netqmail-1.05/tls.h 1969-12-31 19:00:00.000000000 -0500
  3018. +++ ./netqmail-1.05/netqmail-1.05/tls.h 2006-05-10 19:28:51.240862397 -0400
  3019. @@ -0,0 +1,16 @@
  3020. +#ifndef TLS_H
  3021. +#define TLS_H
  3022. +
  3023. +#include <openssl/ssl.h>
  3024. +
  3025. +extern int smtps;
  3026. +extern SSL *ssl;
  3027. +
  3028. +void ssl_free(SSL *myssl);
  3029. +void ssl_exit(int status);
  3030. +# define _exit ssl_exit
  3031. +
  3032. +const char *ssl_error();
  3033. +const char *ssl_error_str();
  3034. +
  3035. +#endif
  3036. diff -u --unidirectional-new-file ./netqmail-1.05.orig/netqmail-1.05/update_tmprsadh.sh ./netqmail-1.05/netqmail-1.05/update_tmprsadh.sh
  3037. --- ./netqmail-1.05.orig/netqmail-1.05/update_tmprsadh.sh 1969-12-31 19:00:00.000000000 -0500
  3038. +++ ./netqmail-1.05/netqmail-1.05/update_tmprsadh.sh 2006-05-10 19:28:51.240862397 -0400
  3039. @@ -0,0 +1,25 @@
  3040. +#!/bin/sh
  3041. +
  3042. +# Update temporary RSA and DH keys
  3043. +# Frederik Vermeulen 2004-05-31 GPL
  3044. +
  3045. +umask 0077 || exit 0
  3046. +
  3047. +export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin"
  3048. +
  3049. +openssl genrsa -out QMAIL/control/rsa512.new 512 &&
  3050. +chmod 600 QMAIL/control/rsa512.new &&
  3051. +chown UGQMAILD QMAIL/control/rsa512.new &&
  3052. +mv -f QMAIL/control/rsa512.new QMAIL/control/rsa512.pem
  3053. +echo
  3054. +
  3055. +openssl dhparam -2 -out QMAIL/control/dh512.new 512 &&
  3056. +chmod 600 QMAIL/control/dh512.new &&
  3057. +chown UGQMAILD QMAIL/control/dh512.new &&
  3058. +mv -f QMAIL/control/dh512.new QMAIL/control/dh512.pem
  3059. +echo
  3060. +
  3061. +openssl dhparam -2 -out QMAIL/control/dh1024.new 1024 &&
  3062. +chmod 600 QMAIL/control/dh1024.new &&
  3063. +chown UGQMAILD QMAIL/control/dh1024.new &&
  3064. +mv -f QMAIL/control/dh1024.new QMAIL/control/dh1024.pem
  3065.