updated on Wed Jan 25 00:20:47 UTC 2012
[aur-mirror.git] / qmail / qmail-authentication-064.patch
blobcb6ee3614d7b73be6f48e6179a3fd7b7a41ed6f6
1 diff -u --new-file qmail-1.03-orig/base64.c qmail-1.03/base64.c
2 --- qmail-1.03-orig/base64.c 1969-12-31 21:00:00.000000000 -0300
3 +++ qmail-1.03/base64.c 2006-03-21 18:40:50.000000000 -0300
4 @@ -0,0 +1,122 @@
5 +#include "base64.h"
6 +#include "stralloc.h"
7 +#include "substdio.h"
8 +#include "str.h"
10 +static char *b64alpha =
11 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
12 +#define B64PAD '='
14 +/* returns 0 ok, 1 illegal, -1 problem */
16 +int b64decode(in,l,out)
17 +const unsigned char *in;
18 +int l;
19 +stralloc *out; /* not null terminated */
21 + int p = 0;
22 + int n;
23 + unsigned int x;
24 + int i, j;
25 + char *s;
26 + unsigned char b[3];
28 + if (l == 0)
29 + {
30 + if (!stralloc_copys(out,"")) return -1;
31 + return 0;
32 + }
34 + while(in[l-1] == B64PAD) {
35 + p ++;
36 + l--;
37 + }
39 + n = (l + p) / 4;
40 + out->len = (n * 3) - p;
41 + if (!stralloc_ready(out,out->len)) return -1;
42 + s = out->s;
44 + for(i = 0; i < n - 1 ; i++) {
45 + x = 0;
46 + for(j = 0; j < 4; j++) {
47 + if(in[j] >= 'A' && in[j] <= 'Z')
48 + x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
49 + else if(in[j] >= 'a' && in[j] <= 'z')
50 + x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
51 + else if(in[j] >= '0' && in[j] <= '9')
52 + x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
53 + else if(in[j] == '+')
54 + x = (x << 6) + 62;
55 + else if(in[j] == '/')
56 + x = (x << 6) + 63;
57 + else if(in[j] == '=')
58 + x = (x << 6);
59 + }
61 + s[2] = (unsigned char)(x & 255); x >>= 8;
62 + s[1] = (unsigned char)(x & 255); x >>= 8;
63 + s[0] = (unsigned char)(x & 255); x >>= 8;
64 + s += 3; in += 4;
65 + }
67 + x = 0;
68 + for(j = 0; j < 4; j++) {
69 + if(in[j] >= 'A' && in[j] <= 'Z')
70 + x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
71 + else if(in[j] >= 'a' && in[j] <= 'z')
72 + x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
73 + else if(in[j] >= '0' && in[j] <= '9')
74 + x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
75 + else if(in[j] == '+')
76 + x = (x << 6) + 62;
77 + else if(in[j] == '/')
78 + x = (x << 6) + 63;
79 + else if(in[j] == '=')
80 + x = (x << 6);
81 + }
83 + b[2] = (unsigned char)(x & 255); x >>= 8;
84 + b[1] = (unsigned char)(x & 255); x >>= 8;
85 + b[0] = (unsigned char)(x & 255); x >>= 8;
87 + for(i = 0; i < 3 - p; i++)
88 + s[i] = b[i];
90 + return 0;
93 +int b64encode(in,out)
94 +stralloc *in;
95 +stralloc *out; /* not null terminated */
97 + unsigned char a, b, c;
98 + int i;
99 + char *s;
101 + if (in->len == 0)
103 + if (!stralloc_copys(out,"")) return -1;
104 + return 0;
107 + if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1;
108 + s = out->s;
110 + for (i = 0;i < in->len;i += 3) {
111 + a = in->s[i];
112 + b = i + 1 < in->len ? in->s[i + 1] : 0;
113 + c = i + 2 < in->len ? in->s[i + 2] : 0;
115 + *s++ = b64alpha[a >> 2];
116 + *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)];
118 + if (i + 1 >= in->len) *s++ = B64PAD;
119 + else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)];
121 + if (i + 2 >= in->len) *s++ = B64PAD;
122 + else *s++ = b64alpha[c & 63];
124 + out->len = s - out->s;
125 + return 0;
127 diff -u --new-file qmail-1.03-orig/base64.h qmail-1.03/base64.h
128 --- qmail-1.03-orig/base64.h 1969-12-31 21:00:00.000000000 -0300
129 +++ qmail-1.03/base64.h 2006-03-21 18:40:50.000000000 -0300
130 @@ -0,0 +1,7 @@
131 +#ifndef BASE64_H
132 +#define BASE64_H
134 +extern int b64decode();
135 +extern int b64encode();
137 +#endif
138 diff -u --new-file qmail-1.03-orig/case_startb.c qmail-1.03/case_startb.c
139 --- qmail-1.03-orig/case_startb.c 1969-12-31 21:00:00.000000000 -0300
140 +++ qmail-1.03/case_startb.c 2006-03-21 18:40:50.000000000 -0300
141 @@ -0,0 +1,21 @@
142 +#include "case.h"
144 +int case_startb(s,len,t)
145 +register char *s;
146 +unsigned int len;
147 +register char *t;
149 + register unsigned char x;
150 + register unsigned char y;
152 + for (;;) {
153 + y = *t++ - 'A';
154 + if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
155 + if (!y) return 1;
156 + if (!len) return 0;
157 + --len;
158 + x = *s++ - 'A';
159 + if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
160 + if (x != y) return 0;
163 diff -u --new-file qmail-1.03-orig/FILES.auth qmail-1.03/FILES.auth
164 --- qmail-1.03-orig/FILES.auth 1969-12-31 21:00:00.000000000 -0300
165 +++ qmail-1.03/FILES.auth 2006-03-21 18:40:50.000000000 -0300
166 @@ -0,0 +1,24 @@
167 +The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files:
169 += TARGETS
170 += Makefile
171 += qmail-smtpd.c
172 += qmail-smtpd.8
173 += qmail-remote.c
174 += qmail-remote.8
175 += qmail-showctl.c
176 += qmail-control.9
178 +Added files:
180 ++ base64.c
181 ++ base64.h
182 ++ case_startb.c
184 +Informational files:
186 +% install_auth.sh (Installation shell script)
187 +% LICENSE.authentication (some sort of ...)
188 +% README.auth
189 +% README.auth.old (old description of SMTP Auth)
190 +% README.qmail-remote-auth (ASCII version of Bjoern Kalkbrenner index.html)
191 diff -u --new-file qmail-1.03-orig/install_authentication.sh qmail-1.03/install_authentication.sh
192 --- qmail-1.03-orig/install_authentication.sh 1969-12-31 21:00:00.000000000 -0300
193 +++ qmail-1.03/install_authentication.sh 2006-03-21 18:40:50.000000000 -0300
194 @@ -0,0 +1,100 @@
195 +#!/bin/sh
197 +# qmail-smtpd AUTH (UN)INSTALL Script (install_auth.sh)
198 +# -----------------------------------------------------
200 +# Purpose: To install and uninstall the qmail-smtpd Authentication Patch
202 +# Parameters: -u (uninstall)
203 +# VRF (Version to be uninstalled)
205 +# Usage: ./install_auth.sh [-u] [Version]
207 +# Installation: ./install_auth.sh
208 +# Uninstallation: ./install_auth.sh -u 105
210 +# Return Codes: 0 - Patches applied successfully
211 +# 1 - Original QMAIL files not found (Patch not extracted in QMAIL source directory)
212 +# 2 - Patch files not found
214 +# Output: install_auth.log
216 +# History: 1.0.0 - Erwin Hoffmann - Initial release
217 +# 1.0.1 - - grep fix; Gentoo fix
218 +# 1.0.2 - removed '-v' optio for cp
219 +# 1.0.3 - mods for 'qmail authentication'
221 +#---------------------------------------------------------------------------------------
223 +DATE=$(date)
224 +LOCDIR=${PWD}
225 +QMAILHOME=$(head -n 1 conf-qmail)
226 +SOLARIS=$(sh ./find-systype.sh | grep -ci "SunOS")
227 +LOGFILE=auth.log
228 +TARGETS=FILES.auth
229 +IFSKEEP=${IFS}
230 +REL=064 # Should be identical to qmail AUTH level
231 +BUILD=2005178232427
234 +if [ $# -eq 0 ] ; then
236 + echo "Installing qmail-smtpd AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1
238 + for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
239 + echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
240 + if [ -s ${FILE} ] ; then
241 + cp ${FILE} ${FILE}.$REL | tee -a $LOGFILE 2>&1
242 + echo "--> ${FILE} copied to ${FILE}.$REL" | tee -a $LOGFILE 2>&1
243 + else
244 + echo "${FILE} not found !"
245 + exit 1
246 + fi
247 + if [ -s ${FILE}.patch ] ; then
248 + if [ ${SOLARIS} -gt 0 ]; then
249 + echo "--> Patching qmail source file ${FILE} for Solaris ...." | tee -a $LOGFILE 2>&1
250 + patch -i ${FILE}.patch ${FILE} 2>&1 | tee -a $LOGFILE
251 + else
252 + echo "--> Patching qmail source file ${FILE} ...." | tee -a $LOGFILE 2>&1
253 + patch ${FILE} ${FILE}.patch 2>&1 | tee -a $LOGFILE
254 + fi
255 + else
256 + echo "!! ${FILE}.patch not found !"
257 + exit 2
258 + fi
259 + done
262 + echo "Copying documentation and samples to ${QMAILHOME}/doc/ ..." | tee -a $LOGFILE 2>&1
264 + cp README.auth* ${QMAILHOME}/doc/ | tee -a $LOGFILE 2>&1
265 + echo ""
266 + echo "If you dont wont CRAM-MD5 suport disable '#define CRAM_MD5' in qmail-smtpd !"
267 + echo "Installation of qmail authentication $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1
269 +# Now go for the uninstallation....
271 +elif [ "$1" = "-u" ] ; then
273 +# Get the Version Number from INPUT
275 + if [ $# -eq 2 ] ; then
276 + REL=$2
277 + fi
279 + echo "De-installing qmail authentication $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1
281 + for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
282 + echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
283 + if [ -s ${FILE}.$REL ] ; then
284 + mv ${FILE}.$REL ${FILE} | tee -a $LOGFILE 2>&1
285 + touch ${FILE}
286 + echo "--> ${FILE}.$REL moved to ${FILE}" | tee -a $LOGFILE 2>&1
287 + else
288 + echo "!! ${FILE}.$REL not found !"
289 + fi
290 + done
291 + echo "De-installation of qmail authentication $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1
294 +exit 0
295 diff -u --new-file qmail-1.03-orig/LICENSE.authentication qmail-1.03/LICENSE.authentication
296 --- qmail-1.03-orig/LICENSE.authentication 1969-12-31 21:00:00.000000000 -0300
297 +++ qmail-1.03/LICENSE.authentication 2006-03-21 18:40:50.000000000 -0300
298 @@ -0,0 +1,43 @@
299 +AUTHOR
300 +======
302 +Author:
303 + Dr. Erwin Hoffmann - FEHCom Germany
304 +Web-Site:
305 + http://www.fehcom.de/qmail.html
306 +E-Mail:
307 + feh@fehcom.de
310 +LICENSE
311 +=======
313 +qmail AUTHENTICATION is free software.
314 +This includes:
315 + You can download and use qmail AUTHENTICATION (and parts of it) as you like.
316 + You can modify the source code without notification to or permission by the author.
317 +Please check:
318 + http://www.cr.yp.to/softwarelaw.html
321 +DEPENDENCIES
322 +============
324 +qmail AUTHENTICATION patches (modifies) parts of the qmail-1.03 source files.
325 +It should only be applied against the source as supplied by D.J. Bernstein.
328 +FITNESS
329 +=======
331 +The Author does not guarantee a specific fitness of qmail AUTHENTICATION.
332 +If you use qmail AUTHENTICATION, it's on your own risk.
335 +DISTRIBUTION
336 +============
338 +qmail AUTHENTICATION may be included in ports and packages under the following conditions:
339 + The port/package has to show the current version number of qmail AUTHENTICATION.
340 + All files (namely this) have to be included.
342 diff -u --new-file qmail-1.03-orig/Makefile qmail-1.03/Makefile
343 --- qmail-1.03-orig/Makefile 2006-03-21 18:39:35.000000000 -0300
344 +++ qmail-1.03/Makefile 2006-03-21 18:44:49.000000000 -0300
345 @@ -106,6 +106,10 @@
346 compile auto_usera.c
347 ./compile auto_usera.c
349 +base64.o: \
350 +compile base64.c base64.h stralloc.h substdio.h str.h
351 + ./compile base64.c
353 binm1: \
354 binm1.sh conf-qmail
355 cat binm1.sh \
356 @@ -1456,12 +1460,12 @@
357 load qmail-remote.o control.o timeoutread.o timeoutwrite.o \
358 timeoutconn.o constmap.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
359 ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
360 -substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
361 +substdio.a error.a str.a fs.a auto_qmail.o dns.lib base64.o socket.lib
362 ./load qmail-remote control.o timeoutread.o \
363 timeoutwrite.o timeoutconn.o constmap.o tcpto.o now.o dns.o ip.o \
364 ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
365 lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
366 - str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
367 + str.a fs.a auto_qmail.o base64.o `cat dns.lib` `cat socket.lib`
369 qmail-remote.0: \
370 qmail-remote.8
371 @@ -1551,13 +1555,13 @@
372 ucspitls.o \
373 date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
374 open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
375 -fs.a auto_qmail.o socket.lib
376 +fs.a auto_qmail.o base64.o socket.lib
377 ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
378 timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
379 ucspitls.o \
380 received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
381 datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
382 - alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \
383 + alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \
384 socket.lib`
386 qmail-smtpd.0: \
387 @@ -1569,7 +1573,7 @@
388 substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \
389 error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \
390 substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \
391 -exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h
392 +exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h
393 ./compile qmail-smtpd.c
395 qmail-start: \
396 Subdirectorios comunes: qmail-1.03-orig/qmail-rhinit y qmail-1.03/qmail-rhinit
397 diff -u --new-file qmail-1.03-orig/qmail-smtpd.8 qmail-1.03/qmail-smtpd.8
398 --- qmail-1.03-orig/qmail-smtpd.8 2006-03-21 18:39:35.000000000 -0300
399 +++ qmail-1.03/qmail-smtpd.8 2006-03-21 18:46:16.000000000 -0300
400 @@ -23,7 +23,30 @@
401 header fields.
403 .B qmail-smtpd
404 -supports ESMTP, including the 8BITMIME and PIPELINING options.
405 +supports ESMTP, including the 8BITMIME, DATA, PIPELINING, SIZE, and AUTH options.
406 +.B qmail-smtpd
407 +includes a \'MAIL FROM:\' parameter parser and obeys \'Auth\' and \'Size\' advertisements.
408 +.B qmail-smtpd
409 +can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes
410 +.IR checkprogram ,
411 +which reads on file descriptor 3 the username, a 0 byte, the password
412 +or CRAM-MD5 digest/response derived from the SMTP client,
413 +another 0 byte, a CRAM-MD5 challenge (if applicable to the AUTH type),
414 +and a final 0 byte.
415 +.I checkprogram
416 +invokes
417 +.I subprogram
418 +upon successful authentication, which should in turn return 0 to
419 +.BR qmail-smtpd ,
420 +effectively setting the environment variables $RELAYCLIENT and $TCPREMOTEINFO
421 +(any supplied value replaced with the authenticated username).
422 +.B qmail-smtpd
423 +will reject the authentication attempt if it receives a nonzero return
424 +value from
425 +.I checkprogram
427 +.IR subprogram .
429 .SH TRANSPARENCY
430 .B qmail-smtpd
431 converts the SMTP newline convention into the UNIX newline convention
432 diff -u --new-file qmail-1.03-orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c
433 --- qmail-1.03-orig/qmail-smtpd.c 2006-03-21 18:39:35.000000000 -0300
434 +++ qmail-1.03/qmail-smtpd.c 2006-03-21 18:53:10.000000000 -0300
435 @@ -24,6 +24,10 @@
436 #include "timeoutwrite.h"
437 #include "commands.h"
438 #include "ucspitls.h"
439 +#include "wait.h"
441 +#define CRAM_MD5
442 +#define AUTHSLEEP 5
444 #define MAXHOPS 100
445 unsigned int databytes = 0;
446 @@ -51,6 +55,7 @@
447 void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
448 void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
449 void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
450 +void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
451 void die_syserr() { out("421 system error (#4.3.0)\r\n"); flush(); _exit(1); }
453 void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
454 @@ -63,6 +68,16 @@
455 void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
456 void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
458 +int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
459 +int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
460 +int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
461 +int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
462 +void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
463 +void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
464 +int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
465 +int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; }
466 +int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
467 +void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
469 stralloc greeting = {0};
471 @@ -80,6 +95,7 @@
472 smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
475 +char *protocol;
476 char *remoteip;
477 char *remotehost;
478 char *remoteinfo;
479 @@ -126,6 +142,7 @@
480 if (x) { scan_ulong(x,&u); databytes = u; }
481 if (!(databytes + 1)) --databytes;
483 + protocol = "SMTP";
484 remoteip = env_get("TCPREMOTEIP");
485 if (!remoteip) remoteip = "unknown";
486 local = env_get("TCPLOCALHOST");
487 @@ -223,8 +240,70 @@
489 int seenmail = 0;
490 int flagbarf; /* defined if seenmail */
491 +int flagsize;
492 stralloc mailfrom = {0};
493 stralloc rcptto = {0};
494 +stralloc fuser = {0};
495 +stralloc mfparms = {0};
497 +int mailfrom_size(arg) char *arg;
499 + long r;
500 + unsigned long sizebytes = 0;
502 + scan_ulong(arg,&r);
503 + sizebytes = r;
504 + if (databytes) if (sizebytes > databytes) return 1;
505 + return 0;
508 +void mailfrom_auth(arg,len)
509 +char *arg;
510 +int len;
512 + int j;
514 + if (!stralloc_copys(&fuser,"")) die_nomem();
515 + if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
516 + else
517 + while (len) {
518 + if (*arg == '+') {
519 + if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
520 + if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
522 + else
523 + if (!stralloc_catb(&fuser,arg,1)) die_nomem();
524 + arg++; len--;
526 + if(!stralloc_0(&fuser)) die_nomem();
527 + if (!remoteinfo) {
528 + remoteinfo = fuser.s;
529 + if (!env_unset("TCPREMOTEINFO")) die_read();
530 + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
534 +void mailfrom_parms(arg) char *arg;
536 + int i;
537 + int len;
539 + len = str_len(arg);
540 + if (!stralloc_copys(&mfparms,"")) die_nomem;
541 + i = byte_chr(arg,len,'>');
542 + if (i > 4 && i < len) {
543 + while (len) {
544 + arg++; len--;
545 + if (*arg == ' ' || *arg == '\0' ) {
546 + if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
547 + if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);
548 + if (!stralloc_copys(&mfparms,"")) die_nomem;
550 + else
551 + if (!stralloc_catb(&mfparms,arg,1)) die_nomem;
556 void smtp_helo(arg) char *arg;
558 @@ -233,10 +312,21 @@
560 void smtp_ehlo(arg) char *arg;
562 - smtp_greet("250-");
564 + char size[FMT_ULONG];
565 + size[fmt_ulong(size,(unsigned int) databytes)] = 0;
566 + smtp_greet("250-");
567 if (tls_available && !tls_started)
568 out("\r\n250-STARTTLS");
569 - out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
570 + out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
571 + out("250-SIZE "); out(size); out("\r\n");
572 +#ifdef CRAM_MD5
573 + out("250-AUTH=LOGIN PLAIN CRAM-MD5\r\n");
574 + out("250 AUTH LOGIN PLAIN CRAM-MD5\r\n");
575 +#else
576 + out("250-AUTH=LOGIN PLAIN\r\n");
577 + out("250 AUTH LOGIN PLAIN\r\n");
578 +#endif
579 seenmail = 0; dohelo(arg);
581 void smtp_rset()
582 @@ -247,6 +335,9 @@
583 void smtp_mail(arg) char *arg;
585 if (!addrparse(arg)) { err_syntax(); return; }
586 + flagsize = 0;
587 + mailfrom_parms(arg);
588 + if (flagsize) { err_size(); return; }
589 flagbarf = bmfcheck();
590 seenmail = 1;
591 if (!stralloc_copys(&rcptto,"")) die_nomem();
592 @@ -401,7 +492,7 @@
593 qp = qmail_qp(&qqt);
594 out("354 go ahead\r\n");
596 - received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
597 + received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
598 blast(&hops);
599 hops = (hops >= MAXHOPS);
600 if (hops) qmail_fail(&qqt);
601 @@ -411,16 +502,244 @@
602 qqx = qmail_close(&qqt);
603 if (!*qqx) { acceptmessage(qp); return; }
604 if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
605 - if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
606 + if (databytes) if (!bytestooverflow) { err_size(); return; }
607 if (*qqx == 'D') out("554 "); else out("451 ");
608 out(qqx + 1);
609 out("\r\n");
612 +/* this file is too long ----------------------------------------- SMTP AUTH */
614 +char unique[FMT_ULONG + FMT_ULONG + 3];
615 +static stralloc authin = {0}; /* input from SMTP client */
616 +static stralloc user = {0};
617 +static stralloc pass = {0}; /* plain passwd or digest */
618 +static stralloc resp = {0}; /* b64 response */
619 +#ifdef CRAM_MD5
620 +static stralloc chal = {0}; /* plain challenge */
621 +static stralloc slop = {0}; /* b64 challenge */
622 +#endif
624 +int flagauth = 0;
625 +char **childargs;
626 +char ssauthbuf[512];
627 +substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
629 +int authgetl(void) {
630 + int i;
632 + if (!stralloc_copys(&authin,"")) die_nomem();
633 + for (;;) {
634 + if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
635 + i = substdio_get(&ssin,authin.s + authin.len,1);
636 + if (i != 1) die_read();
637 + if (authin.s[authin.len] == '\n') break;
638 + ++authin.len;
641 + if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
642 + authin.s[authin.len] = 0;
643 + if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
644 + if (authin.len == 0) { return err_input(); }
645 + return authin.len;
648 +int authenticate(void)
650 + int child;
651 + int wstat;
652 + int pi[2];
654 + if (!stralloc_0(&user)) die_nomem();
655 + if (!stralloc_0(&pass)) die_nomem();
656 +#ifdef CRAM_MD5
657 + if (!stralloc_0(&chal)) die_nomem();
658 +#endif
660 + if (pipe(pi) == -1) return err_pipe();
661 + switch(child = fork()) {
662 + case -1:
663 + return err_fork();
664 + case 0:
665 + close(pi[1]);
666 + if(fd_copy(3,pi[0]) == -1) return err_pipe();
667 + sig_pipedefault();
668 + execvp(*childargs, childargs);
669 + _exit(1);
671 + close(pi[0]);
673 + substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
674 + if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
675 + if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
676 +#ifdef CRAM_MD5
677 + if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
678 +#endif
679 + if (substdio_flush(&ssauth) == -1) return err_write();
681 + close(pi[1]);
682 +#ifdef CRAM_MD5
683 + if (!stralloc_copys(&chal,"")) die_nomem();
684 + if (!stralloc_copys(&slop,"")) die_nomem();
685 +#endif
686 + byte_zero(ssauthbuf,sizeof ssauthbuf);
687 + if (wait_pid(&wstat,child) == -1) return err_child();
688 + if (wait_crashed(wstat)) return err_child();
689 + if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */
690 + return 0; /* yes */
693 +int auth_login(arg) char *arg;
695 + int r;
697 + if (*arg) {
698 + if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
700 + else {
701 + out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
702 + if (authgetl() < 0) return -1;
703 + if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
705 + if (r == -1) die_nomem();
707 + out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
709 + if (authgetl() < 0) return -1;
710 + if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
711 + if (r == -1) die_nomem();
713 + if (!user.len || !pass.len) return err_input();
714 + return authenticate();
717 +int auth_plain(arg) char *arg;
719 + int r, id = 0;
721 + if (*arg) {
722 + if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input();
724 + else {
725 + out("334 \r\n"); flush();
726 + if (authgetl() < 0) return -1;
727 + if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
729 + if (r == -1 || !stralloc_0(&resp)) die_nomem();
730 + while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */
732 + if (resp.len > id + 1)
733 + if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
734 + if (resp.len > id + user.len + 2)
735 + if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
737 + if (!user.len || !pass.len) return err_input();
738 + return authenticate();
741 +#ifdef CRAM_MD5
742 +int auth_cram()
744 + int i, r;
745 + char *s;
747 + s = unique; /* generate challenge */
748 + s += fmt_uint(s,getpid());
749 + *s++ = '.';
750 + s += fmt_ulong(s,(unsigned long) now());
751 + *s++ = '@';
752 + *s++ = 0;
753 + if (!stralloc_copys(&chal,"<")) die_nomem();
754 + if (!stralloc_cats(&chal,unique)) die_nomem();
755 + if (!stralloc_cats(&chal,local)) die_nomem();
756 + if (!stralloc_cats(&chal,">")) die_nomem();
757 + if (b64encode(&chal,&slop) < 0) die_nomem();
758 + if (!stralloc_0(&slop)) die_nomem();
760 + out("334 "); /* "334 base64_challenge \r\n" */
761 + out(slop.s);
762 + out("\r\n");
763 + flush();
765 + if (authgetl() < 0) return -1; /* got response */
766 + if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
767 + if (r == -1 || !stralloc_0(&resp)) die_nomem();
769 + i = str_chr(resp.s,' ');
770 + s = resp.s + i;
771 + while (*s == ' ') ++s;
772 + resp.s[i] = 0;
773 + if (!stralloc_copys(&user,resp.s)) die_nomem(); /* userid */
774 + if (!stralloc_copys(&pass,s)) die_nomem(); /* digest */
776 + if (!user.len || !pass.len) return err_input();
777 + return authenticate();
779 +#endif
781 +struct authcmd {
782 + char *text;
783 + int (*fun)();
784 +} authcmds[] = {
785 + { "login",auth_login }
786 +, { "plain",auth_plain }
787 +#ifdef CRAM_MD5
788 +, { "cram-md5",auth_cram }
789 +#endif
790 +, { 0,err_noauth }
793 +void smtp_auth(arg)
794 +char *arg;
796 + int i;
797 + char *cmd = arg;
799 + if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
800 + if (flagauth) { err_authd(); return; }
801 + if (seenmail) { err_authmail(); return; }
803 + if (!stralloc_copys(&user,"")) die_nomem();
804 + if (!stralloc_copys(&pass,"")) die_nomem();
805 + if (!stralloc_copys(&resp,"")) die_nomem();
806 +#ifdef CRAM_MD5
807 + if (!stralloc_copys(&chal,"")) die_nomem();
808 +#endif
810 + i = str_chr(cmd,' ');
811 + arg = cmd + i;
812 + while (*arg == ' ') ++arg;
813 + cmd[i] = 0;
815 + for (i = 0;authcmds[i].text;++i)
816 + if (case_equals(authcmds[i].text,cmd)) break;
818 + switch (authcmds[i].fun(arg)) {
819 + case 0:
820 + flagauth = 1;
821 + protocol = "ESMTPA";
822 + relayclient = "";
823 + remoteinfo = user.s;
824 + if (!env_unset("TCPREMOTEINFO")) die_read();
825 + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
826 + if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
827 + out("235 ok, go ahead (#2.0.0)\r\n");
828 + break;
829 + case 1:
830 + err_authfail(user.s,authcmds[i].text);
835 +/* this file is too long --------------------------------------------- GO ON */
839 struct commands smtpcommands[] = {
840 { "rcpt", smtp_rcpt, 0 }
841 , { "mail", smtp_mail, 0 }
842 , { "data", smtp_data, flush }
843 +, { "auth", smtp_auth, flush }
844 , { "quit", smtp_quit, flush }
845 , { "helo", smtp_helo, flush }
846 , { "ehlo", smtp_ehlo, flush }
847 @@ -432,8 +751,11 @@
848 , { 0, err_unimpl, flush }
851 -void main()
852 +void main(argc,argv)
853 +int argc;
854 +char **argv;
856 + childargs = argv + 1;
857 sig_pipeignore();
858 if (chdir(auto_qmail) == -1) die_control();
859 setup();
860 diff -u --new-file qmail-1.03-orig/README.auth qmail-1.03/README.auth
861 --- qmail-1.03-orig/README.auth 1969-12-31 21:00:00.000000000 -0300
862 +++ qmail-1.03/README.auth 2006-03-21 18:40:50.000000000 -0300
863 @@ -0,0 +1,104 @@
864 +README qmail Authentication
865 +===========================
868 +Scope:
869 +------
871 +This patch supports RFC 2554 "SMTP Service Extension for Authentication" for
873 +- qmail-smtpd (AUTH types LOGIN, PLAIN, and CRAM-MD5) and
874 +- qmail-remote (AUTH types LOGIN, PLAIN).
876 +Additionally, RFC 1870 is honoured ("SMTP Service Extension for Message Size Declaration").
877 +For more technical details see: http://www.fehcom.de/qmail/docu/smtpauth.html.
880 +History:
881 +--------
883 +This patch was based on Krzysztof Dabrowski's qmail-smtpd-auth-0.31 patch
884 +which itself uses "Mrs. Brisby's" initial code.
885 +Version 0.41 of this patch fixes the "CAPS-LOCK" typo announcing
886 +'CRAM_MD5' instead of 'CRAM-MD5' (german keyboard) - tx to Mike Garrison.
887 +Version 0.42 fixes the '421 unable to read controls (#4.3.0)' problem
888 +(can't read control/morercpthosts.cdb) because FD 3 was already closed - tx Richard Lyons.
889 +Version 0.43 fixes the ba64decode() failure in case CRAM_MD5 is not enabled - tx Vladimir Zidar.
890 +Version 0.51 includes the evaluation of the 'Auth' and the 'Size' parameter in the 'Mail From:' command.
891 +Version 0.52 uses DJB functions to copy FDs.
892 +Version 0.56 corrects some minor mistakes displaying the 'Auth' userid.
893 +Version 0.57 uses keyword "ESMTPA" in Received header in case of authentication to comply with RFC 3848.
895 +Starting with version 0.60 the patch includes the qmail-smtp-auth-send enhancement
896 +from Bjoern Kalkbrenner to support SMTP autentication for qmail-remote.
899 +Installation:
900 +-------------
902 +* Untar the source in the qmail-1.03 home directory.
903 +* Run ./install_authentication.
904 +* Modify the compile time option "#define CRAM_MD5" to your needs.
905 +* Re-make qmail.
908 +Setup for qmail-smtpd:
909 +----------------------
911 +In order to use SMTP Authentication you have to use a 'Pluggable Authentication Module'
912 +PAM to be called by qmail-smtpd; typically
914 + /var/qmail/bin/qmail-smtpd /bin/checkpassword true 2>&1
916 +Since qmail-smtpd does not run as root, checkpassword has to be made sticky.
917 +There is no need to include additionally the hostname in the call.
918 +In order to compute the CRAM-MD5 challenge, qmail-smtpd uses the 'tcplocalhost' information.
921 +Setup for qmail-remote:
922 +-----------------------
924 +See man page qmail-remote.
926 +A control file control/authsenders has to be generated and populated accordingly.
929 +Changes wrt. Krysztof Dabrowski's patch:
930 +----------------------------------------
932 +* Avoid the 'hostname' in the call of the PAM.
933 +* Confirm to Dan Bernstein's checkpassword interface even for CRAM-MD5.
934 +* Doesn't close FD 2; thus not inhibiting logging to STDERR.
935 +* Fixed bugs in base64.c.
936 +* Modified unconditional close of FD 3 in order to sustain reading of 'control/morecpthosts.cdb'.
937 +* Evaluation of the (informational) Mail From: < > Auth=username.
938 +* Additional support for the advertised "Size" via 'Mail From: <return-path> SIZE=123456780' (RFC 1870).
939 +* RFC 3848 conformance for Received header in case of SMTP Auth.
942 +Changes wrt. Bjoern Kalkbrenner's patch:
943 +----------------------------------------
945 +* Included AUTH PLAIN support.
946 +* Fixed wrong use of 'MAIL FROM: <return-path> AUTH=user'.
947 +* Modular design.
948 +* Renamed "smtproutes_user" to "authsenders".
949 +* Added man page for qmail-remote including AUTH behaviour.
950 +* Modified qmail-control man page to include "authsenders".
951 +* Modified qmail-showctl to parse "authsenders".
954 +History
955 +-------
957 +0.6.0 includes SMTP authentication for qmail-remote.
958 +0.6.1 Initial Version: Transmitts 'user' in Mail From: as xtext; flexible AUTH recognition.
959 +0.6.2 Auth plain: mailfrom\0user-id\0password; thus authorization-id is the Return-Path.
960 +0.6.3 Compliance with RFC 3848 (synced with qmail-auth-smtpd.057).
961 +0.6.4 FIXED a bug in PLAIN checking for the wrong SMTP Reply code
962 + FIXED a bug in the evaluation of the SENDER (tx. Benjamin Meyer).
965 +Erwin Hoffmann - Cologne 2005-06-27 (www.fehcom.de)
968 diff -u --new-file qmail-1.03-orig/README.qmail-remote-auth qmail-1.03/README.qmail-remote-auth
969 --- qmail-1.03-orig/README.qmail-remote-auth 1969-12-31 21:00:00.000000000 -0300
970 +++ qmail-1.03/README.qmail-remote-auth 2006-03-21 18:40:50.000000000 -0300
971 @@ -0,0 +1,58 @@
972 ++++++++++++++++++++++++++++
973 ++ +
974 ++ THIS FILE IS OBSOLETE +
975 ++ +
976 ++++++++++++++++++++++++++++
979 +Qmail 1.03 qmail-remote.c SMTP-AUTH send patch
981 + * Date: 20020715
982 + * Version: 0.0.1 ;)
983 + * Author: Bjoern Kalkbrenner
984 + * Location: Home | Download
986 +Quick install:
988 + 1. Copy the base64.c and base64.h to your qmail source and chdir into it.
989 + 2. Patch the source with patch -p1 <smtp-auth-send.patch
990 + 3. make setup check
991 + 4. ...follow the qmail-installation or copy your new qmail-remote to
992 + /var/qmail/bin
993 + 5. create your /var/qmail/control/smtproutes_users
995 +Quick info:
997 +This patch is based on Robert Sander's AUTH LOGIN patch which is based on
998 +the qmail-smtpd-auth patch which itself is based on the patch from Mrs.
999 +Brisby...
1000 +Confusing ;)
1002 +I made this patch because my ISP also switched to AUTH LOGIN on his SMTP
1003 +relay and we are using an internal linux qmail server in our company, but
1004 +the patch Robert wrote was only working for 1 user. . Several users use
1005 +this ISP for outgoing mail, mails are fetched with fetchmail, (scanned for
1006 +viruses) and send to the local mailaccounts which is used as relay. Now it
1007 +is easy for us to internal mailaccounts mapped to the external mailservers.
1008 +You can even select the outgoing mailserver with the smtproutes_users file.
1010 +The username and password for the remote smtp relay are stored in
1011 +/var/qmail/control/smtproutes_users (new controlfile!) separated with pipes
1012 +after the entry for the relay server.
1013 +For example:
1015 +#mailuser-example
1016 +mail@example.com:smtp.example.com|example.com1|examplePasswd
1017 +info@example.com:smtp.example.com|example.com2|anotherPasswd
1019 +mailuser-examples sending to port 26
1020 +anotherport@example.com:smtp.example.com:26|example.com3|justfoobar
1022 +#default, not sure if this entry is used, untested!!!!!! Maybe i had to
1023 +code this.
1024 +:relay.provider.com|username|password
1026 +Password has to be stored in cleartext. This is maybe not bug-free, but
1027 +like Robert said:
1029 +It works for me, no guarantee...
1030 diff -u --new-file qmail-1.03-orig/TARGETS qmail-1.03/TARGETS
1031 --- qmail-1.03-orig/TARGETS 2006-03-21 18:39:35.000000000 -0300
1032 +++ qmail-1.03/TARGETS 2006-03-21 18:53:38.000000000 -0300
1033 @@ -10,6 +10,7 @@
1034 qmail.o
1035 quote.o
1036 now.o
1037 +base64.o
1038 gfrom.o
1039 myctime.o
1040 slurpclose.o