Apply Erwin Hoffmann's SMTP authentication for qmail-smtpd, qmail-remote.
From https://www.fehcom.de/qmail/smtpauth.html#PATCHES Generic SMTP authentication for qmail-smtpd and qmail-remote. Complies to RFC 3848 and RFC 4409. * Provides now CRAM-MD5 authentication for qmail-remote as well. * Fine tuning of SMTPAUTH annoncements for qmail-smtpd and SUBMISSION support. * Sender based authentication according to 'Mail From:' and authenticated smarthost relaying for qmail-remote. * Fixed bug (0.8.2): qmail-smtpd secretly allows auth even when disabled! (tx Chris P.) * Fixed AMD64 bug for MD5 (0.8.3) and small others (tx Alan P.)
This commit is contained in:
parent
08a0b794f3
commit
36d7678ec9
20 changed files with 1827 additions and 47 deletions
27
FILES.auth
Normal file
27
FILES.auth
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files:
|
||||||
|
|
||||||
|
= TARGETS
|
||||||
|
= Makefile
|
||||||
|
= qmail-smtpd.c
|
||||||
|
= qmail-smtpd.8
|
||||||
|
= qmail-remote.c
|
||||||
|
= qmail-remote.8
|
||||||
|
= qmail-showctl.c
|
||||||
|
= qmail-control.9
|
||||||
|
|
||||||
|
Added files:
|
||||||
|
|
||||||
|
+ base64.c
|
||||||
|
+ base64.h
|
||||||
|
+ case_startb.c
|
||||||
|
+ hmac_md5.h
|
||||||
|
+ hmac_md5.c
|
||||||
|
+ global.h
|
||||||
|
+ md5.h
|
||||||
|
+ md5c.c
|
||||||
|
|
||||||
|
Informational files:
|
||||||
|
|
||||||
|
% install_auth.sh (Installation shell script)
|
||||||
|
% LICENSE.authentication (some sort of ...)
|
||||||
|
% README.auth
|
||||||
43
LICENSE.authentication
Normal file
43
LICENSE.authentication
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
AUTHOR
|
||||||
|
======
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Dr. Erwin Hoffmann - FEHCom Germany
|
||||||
|
Web-Site:
|
||||||
|
http://www.fehcom.de/qmail.html
|
||||||
|
E-Mail:
|
||||||
|
feh@fehcom.de
|
||||||
|
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
=======
|
||||||
|
|
||||||
|
qmail AUTHENTICATION is free software.
|
||||||
|
This includes:
|
||||||
|
You can download and use qmail AUTHENTICATION (and parts of it) as you like.
|
||||||
|
You can modify the source code without notification to or permission by the author.
|
||||||
|
Please check:
|
||||||
|
http://www.cr.yp.to/softwarelaw.html
|
||||||
|
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
============
|
||||||
|
|
||||||
|
qmail AUTHENTICATION patches (modifies) parts of the qmail-1.03 source files.
|
||||||
|
It should only be applied against the source as supplied by D.J. Bernstein.
|
||||||
|
|
||||||
|
|
||||||
|
FITNESS
|
||||||
|
=======
|
||||||
|
|
||||||
|
The Author does not guarantee a specific fitness of qmail AUTHENTICATION.
|
||||||
|
If you use qmail AUTHENTICATION, it's on your own risk.
|
||||||
|
|
||||||
|
|
||||||
|
DISTRIBUTION
|
||||||
|
============
|
||||||
|
|
||||||
|
qmail AUTHENTICATION may be included in ports and packages under the following conditions:
|
||||||
|
The port/package has to show the current version number of qmail AUTHENTICATION.
|
||||||
|
All files (namely this) have to be included.
|
||||||
|
|
||||||
23
Makefile
23
Makefile
|
|
@ -136,6 +136,18 @@ auto_usera.o: \
|
||||||
compile auto_usera.c
|
compile auto_usera.c
|
||||||
./compile auto_usera.c
|
./compile auto_usera.c
|
||||||
|
|
||||||
|
base64.o: \
|
||||||
|
compile base64.c base64.h stralloc.h substdio.h str.h
|
||||||
|
./compile base64.c
|
||||||
|
|
||||||
|
md5c.o : \
|
||||||
|
compile md5c.c md5.h
|
||||||
|
./compile md5c.c
|
||||||
|
|
||||||
|
hmac_md5.o : \
|
||||||
|
compile hmac_md5.c hmac_md5.h global.h
|
||||||
|
./compile hmac_md5.c
|
||||||
|
|
||||||
binm1: \
|
binm1: \
|
||||||
binm1.sh conf-qmail
|
binm1.sh conf-qmail
|
||||||
cat binm1.sh \
|
cat binm1.sh \
|
||||||
|
|
@ -1441,11 +1453,14 @@ qmail-remote: \
|
||||||
load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
|
load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
|
||||||
timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
|
timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
|
||||||
ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
|
ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
|
||||||
substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
|
substdio.a error.a str.a fs.a auto_qmail.o \
|
||||||
|
base64.o md5c.o hmac_md5.o \
|
||||||
|
dns.lib socket.lib
|
||||||
./load qmail-remote control.o constmap.o timeoutread.o \
|
./load qmail-remote control.o constmap.o timeoutread.o \
|
||||||
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
|
timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
|
||||||
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
|
ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
|
||||||
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
|
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
|
||||||
|
base64.o md5c.o hmac_md5.o \
|
||||||
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
||||||
|
|
||||||
qmail-remote.0: \
|
qmail-remote.0: \
|
||||||
|
|
@ -1536,12 +1551,12 @@ load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
|
||||||
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
|
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
|
||||||
date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
|
date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
|
||||||
open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
|
open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
|
||||||
fs.a auto_qmail.o socket.lib
|
fs.a auto_qmail.o base64.o socket.lib
|
||||||
./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
|
./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
|
||||||
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
|
timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
|
||||||
received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
|
received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
|
||||||
datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
|
datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
|
||||||
alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \
|
alloc.a substdio.a error.a str.a fs.a auto_qmail.o base64.o `cat \
|
||||||
socket.lib`
|
socket.lib`
|
||||||
|
|
||||||
qmail-smtpd.0: \
|
qmail-smtpd.0: \
|
||||||
|
|
@ -1553,7 +1568,7 @@ compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \
|
||||||
substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \
|
substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \
|
||||||
error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \
|
error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \
|
||||||
substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \
|
substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \
|
||||||
exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h
|
exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h
|
||||||
./compile qmail-smtpd.c
|
./compile qmail-smtpd.c
|
||||||
|
|
||||||
qmail-start: \
|
qmail-start: \
|
||||||
|
|
|
||||||
154
README.auth
Normal file
154
README.auth
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
README qmail SMTP Authentication
|
||||||
|
================================
|
||||||
|
|
||||||
|
Scope:
|
||||||
|
------
|
||||||
|
|
||||||
|
This patch supports RFC 2554 "SMTP Service Extension for Authentication" and
|
||||||
|
RFC 4409 "Message Submission for Mail" for
|
||||||
|
|
||||||
|
* qmail-smtpd and
|
||||||
|
* qmail-remote
|
||||||
|
|
||||||
|
and supports commonly the AUTH methods
|
||||||
|
|
||||||
|
- CRAM-MD5
|
||||||
|
- LOGIN (unsecure)
|
||||||
|
- PLAIN (unsecure)
|
||||||
|
|
||||||
|
Additionally, RFC 1870 is honoured ("SMTP Service Extension for Message Size Declaration").
|
||||||
|
For more technical details see: http://www.fehcom.de/qmail/docu/smtpauth.html.
|
||||||
|
|
||||||
|
|
||||||
|
Installation:
|
||||||
|
-------------
|
||||||
|
|
||||||
|
* Untar the source in the qmail-1.03 home direcotry.
|
||||||
|
* Run ./install_auth.
|
||||||
|
* Re-make qmail.
|
||||||
|
|
||||||
|
|
||||||
|
Setup for qmail-smtpd:
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
1. Prereqs:
|
||||||
|
|
||||||
|
In order to use SMTP Authentication you have to use a 'Pluggable Authentication Module'
|
||||||
|
PAM to be called by qmail-smtpd; typically
|
||||||
|
|
||||||
|
/var/qmail/bin/qmail-smtpd /bin/checkpassword true 2>&1
|
||||||
|
|
||||||
|
Since qmail-smtpd does not run as root, checkpassword has to be made sticky.
|
||||||
|
There is no need to include additionally the hostname in the call.
|
||||||
|
In order to compute the CRAM-MD5 challenge, qmail-smtpd uses the 'tcplocalhost' information.
|
||||||
|
|
||||||
|
2. Invocation:
|
||||||
|
|
||||||
|
In order activate SMTP authentication, you need to provide the environment
|
||||||
|
variable 'SMTPAUTH' to qmail-smtpd.
|
||||||
|
|
||||||
|
Possible choices:
|
||||||
|
|
||||||
|
a) SMTPAUTH=""; qmail-smtpd supports auth of type PLAIN and/or LOGIN.
|
||||||
|
b) SMTPAUTH="+cram"; qmail-smtpd will additionally annonce CRAM-MD5,
|
||||||
|
this requires a CRAM-MD5 supporting PAM.
|
||||||
|
c) SMTPAUTH="cram"; qmail-smtpd will only annonce CRAM-MD5.
|
||||||
|
d) SMTPAUTH="!"; this instructs qmail-smtpd to require (any type) authentication for this connection.
|
||||||
|
This behavior is equivalent to the Submission feaure.
|
||||||
|
e) SMTPAUTH="!cram"; same as d) but now CRAM-MD5 is the only method instead.
|
||||||
|
|
||||||
|
|
||||||
|
Setup for qmail-remote:
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
SMTP Authentication with qmail-remote is faclitated by two means:
|
||||||
|
|
||||||
|
a) SMTP Authentication by sender/sending domain as provided in the 'Mail From:'
|
||||||
|
|
||||||
|
The control file 'authsenders' which works similar to 'control/smtproutes'
|
||||||
|
but with additional authentication information (username + password):
|
||||||
|
|
||||||
|
@example.com:relay.example.com|user|passwd
|
||||||
|
info@example.com:relay.example.com:26|infouser|infopasswd
|
||||||
|
:mailrelay.example.com:587|e=mc2|testpass
|
||||||
|
|
||||||
|
Note: The choice of the AUTH method depends on the capabilities of the server.
|
||||||
|
|
||||||
|
b) SMTP Authentication by recipient domain:
|
||||||
|
|
||||||
|
The control file 'smtproutes' is enhanced with the authentication information:
|
||||||
|
|
||||||
|
authdomain.com:mx.authdomain.com:125|myuserid|mypassword
|
||||||
|
:mailrelay.example.com:587|e=mc2|testpass
|
||||||
|
|
||||||
|
|
||||||
|
Historical Notes:
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
SMTP authentication for qmail-smtpd was initially provided by Krysztof Dabrowski (version 0.31):
|
||||||
|
|
||||||
|
|
||||||
|
Changes wrt. Krysztof Dabrowski's patch:
|
||||||
|
|
||||||
|
* Avoid the 'hostname' in the call of the PAM.
|
||||||
|
* Confirm to Dan Bernstein's checkpassword interface even for CRAM-MD5.
|
||||||
|
* Doesn't close FD 2; thus not inhibiting logging to STDERR.
|
||||||
|
* Fixed bugs in base64.c.
|
||||||
|
* Modified unconditional close of FD 3 in order to sustain reading of 'control/morecpthosts.cdb'.
|
||||||
|
* Evaluation of the (informational) Mail From: < > Auth=username.
|
||||||
|
* Additional support for the advertised "Size" via 'Mail From: <return-path> SIZE=123456780' (RFC 1870).
|
||||||
|
* RFC 3848 conformance for Received header in case of SMTP Auth (keyword ESMTPA).
|
||||||
|
* Added SMTPAUTH environment variable.
|
||||||
|
* The particular Submission feature has been removed; obsolete.
|
||||||
|
|
||||||
|
|
||||||
|
SMTP authentication for qmail-remote is taken from Bjoern Kalkbrenner.
|
||||||
|
|
||||||
|
Changes wrt. Bjoern Kalkbrenner's patch (version 0.0.1 / 20020715):
|
||||||
|
|
||||||
|
* Uniform, modular support for LOGIN and PLAIN.
|
||||||
|
* Added 'Mail From: < > Auth=username' information in provisionally XTEXT format.
|
||||||
|
* Added CRAM-MD5 support.
|
||||||
|
* Added authentication by recipient domain.
|
||||||
|
|
||||||
|
|
||||||
|
Release Notes:
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Version: Notes: Date:
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
0.5.9 qmail-smtpd AUTH (only) 25.3.2008
|
||||||
|
0.6.9 qmail-authentication 1.2.2010
|
||||||
|
0.7.0 Based on qmail-authentication 0.69
|
||||||
|
including now CRAM-MD5 support
|
||||||
|
for qmail-remote 31.7.2010
|
||||||
|
0.7.1 cosmetics for qmail-remote 5.8.2010
|
||||||
|
0.7.2 authorization-id = authentication-id
|
||||||
|
for qmail-remote;
|
||||||
|
added SMTPAUTH environment variable
|
||||||
|
for qmail-smtpd; backport from SC 2.7 29.4.2012
|
||||||
|
0.7.3 Fixed missing AUTH for qmai-smtpd announcement.
|
||||||
|
Improved SUBMISSION port handling. 2.5.2012
|
||||||
|
0.7.4 Fixed missing 250 statements for AUTH.
|
||||||
|
Changed SMTPAUTH settings for cram-md5 18.5.2012
|
||||||
|
0.7.5 Fixed bug in qmail-remote not respecting
|
||||||
|
announced AUTH types. Tx. Callum Gibson.
|
||||||
|
Added '432' server code evaluation for
|
||||||
|
AUTH password expired in qmail-remote. 23.10.2012
|
||||||
|
0.7.6 Fixed order of SMTP commands (tx roberto).
|
||||||
|
02.02.2013
|
||||||
|
0.8.0 Added authentication by recipient domain
|
||||||
|
for qmail-remote.
|
||||||
|
Removed SUBMISSION port feature for
|
||||||
|
qmail-smtpd. 22.03.2013
|
||||||
|
0.8.1 Added SMTPAUTH="!+crom" feature. 24.03.2013
|
||||||
|
0.8.2 Bug fix: qmail-smtpd ACCEPTS auth commands
|
||||||
|
even if SMTPAUTH="-". (tx chris). 21.01.2015
|
||||||
|
0.8.3 Fixed bug in MD5 calculation for AMD64.
|
||||||
|
Fixed 'die_nomem' bug in qmail-smtpd. 23.08.2015
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Erwin Hoffmann - Hoehn 2015-08-23 (www.fehcom.de)
|
||||||
|
|
||||||
|
|
||||||
3
TARGETS
3
TARGETS
|
|
@ -10,6 +10,7 @@ qmail-local.o
|
||||||
qmail.o
|
qmail.o
|
||||||
quote.o
|
quote.o
|
||||||
now.o
|
now.o
|
||||||
|
base64.o
|
||||||
gfrom.o
|
gfrom.o
|
||||||
myctime.o
|
myctime.o
|
||||||
slurpclose.o
|
slurpclose.o
|
||||||
|
|
@ -182,6 +183,8 @@ dns.lib
|
||||||
qmail-remote
|
qmail-remote
|
||||||
qmail-rspawn.o
|
qmail-rspawn.o
|
||||||
tcpto_clean.o
|
tcpto_clean.o
|
||||||
|
md5c.o
|
||||||
|
hmac_md5.o
|
||||||
qmail-rspawn
|
qmail-rspawn
|
||||||
direntry.h
|
direntry.h
|
||||||
qmail-clean.o
|
qmail-clean.o
|
||||||
|
|
|
||||||
124
base64.c
Normal file
124
base64.c
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
#include "base64.h"
|
||||||
|
#include "stralloc.h"
|
||||||
|
#include "substdio.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
static char *b64alpha =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
#define B64PAD '='
|
||||||
|
|
||||||
|
/* returns 0 ok, 1 illegal, -1 problem */
|
||||||
|
|
||||||
|
int b64decode(in,l,out)
|
||||||
|
const unsigned char *in;
|
||||||
|
int l;
|
||||||
|
stralloc *out; /* not null terminated */
|
||||||
|
{
|
||||||
|
int p = 0;
|
||||||
|
int n;
|
||||||
|
unsigned int x;
|
||||||
|
int i, j;
|
||||||
|
char *s;
|
||||||
|
unsigned char b[3];
|
||||||
|
|
||||||
|
if (l == 0)
|
||||||
|
{
|
||||||
|
if (!stralloc_copys(out,"")) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(in[l-1] == B64PAD) {
|
||||||
|
p ++;
|
||||||
|
l--;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = (l + p) / 4;
|
||||||
|
i = (n * 3) - p;
|
||||||
|
if (!stralloc_ready(out,i)) return -1;
|
||||||
|
out->len = i;
|
||||||
|
s = out->s;
|
||||||
|
|
||||||
|
for(i = 0; i < n - 1 ; i++) {
|
||||||
|
x = 0;
|
||||||
|
for(j = 0; j < 4; j++) {
|
||||||
|
if(in[j] >= 'A' && in[j] <= 'Z')
|
||||||
|
x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
|
||||||
|
else if(in[j] >= 'a' && in[j] <= 'z')
|
||||||
|
x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
|
||||||
|
else if(in[j] >= '0' && in[j] <= '9')
|
||||||
|
x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
|
||||||
|
else if(in[j] == '+')
|
||||||
|
x = (x << 6) + 62;
|
||||||
|
else if(in[j] == '/')
|
||||||
|
x = (x << 6) + 63;
|
||||||
|
else if(in[j] == '=')
|
||||||
|
x = (x << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
s[2] = (unsigned char)(x & 255); x >>= 8;
|
||||||
|
s[1] = (unsigned char)(x & 255); x >>= 8;
|
||||||
|
s[0] = (unsigned char)(x & 255); x >>= 8;
|
||||||
|
s += 3; in += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
for(j = 0; j < 4; j++) {
|
||||||
|
if(in[j] >= 'A' && in[j] <= 'Z')
|
||||||
|
x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
|
||||||
|
else if(in[j] >= 'a' && in[j] <= 'z')
|
||||||
|
x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
|
||||||
|
else if(in[j] >= '0' && in[j] <= '9')
|
||||||
|
x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
|
||||||
|
else if(in[j] == '+')
|
||||||
|
x = (x << 6) + 62;
|
||||||
|
else if(in[j] == '/')
|
||||||
|
x = (x << 6) + 63;
|
||||||
|
else if(in[j] == '=')
|
||||||
|
x = (x << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
b[2] = (unsigned char)(x & 255); x >>= 8;
|
||||||
|
b[1] = (unsigned char)(x & 255); x >>= 8;
|
||||||
|
b[0] = (unsigned char)(x & 255); x >>= 8;
|
||||||
|
|
||||||
|
for(i = 0; i < 3 - p; i++)
|
||||||
|
s[i] = b[i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int b64encode(in,out)
|
||||||
|
stralloc *in;
|
||||||
|
stralloc *out; /* not null terminated */
|
||||||
|
{
|
||||||
|
unsigned char a, b, c;
|
||||||
|
int i;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if (in->len == 0)
|
||||||
|
{
|
||||||
|
if (!stralloc_copys(out,"")) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = in->len / 3 * 4 + 4;
|
||||||
|
if (!stralloc_ready(out,i)) return -1;
|
||||||
|
s = out->s;
|
||||||
|
|
||||||
|
for (i = 0;i < in->len;i += 3) {
|
||||||
|
a = in->s[i];
|
||||||
|
b = i + 1 < in->len ? in->s[i + 1] : 0;
|
||||||
|
c = i + 2 < in->len ? in->s[i + 2] : 0;
|
||||||
|
|
||||||
|
*s++ = b64alpha[a >> 2];
|
||||||
|
*s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)];
|
||||||
|
|
||||||
|
if (i + 1 >= in->len) *s++ = B64PAD;
|
||||||
|
else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)];
|
||||||
|
|
||||||
|
if (i + 2 >= in->len) *s++ = B64PAD;
|
||||||
|
else *s++ = b64alpha[c & 63];
|
||||||
|
}
|
||||||
|
out->len = s - out->s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
base64.h
Normal file
7
base64.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef BASE64_H
|
||||||
|
#define BASE64_H
|
||||||
|
|
||||||
|
extern int b64decode();
|
||||||
|
extern int b64encode();
|
||||||
|
|
||||||
|
#endif
|
||||||
21
case_startb.c
Normal file
21
case_startb.c
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "case.h"
|
||||||
|
|
||||||
|
int case_startb(s,len,t)
|
||||||
|
register char *s;
|
||||||
|
unsigned int len;
|
||||||
|
register char *t;
|
||||||
|
{
|
||||||
|
register unsigned char x;
|
||||||
|
register unsigned char y;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
y = *t++ - 'A';
|
||||||
|
if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
|
||||||
|
if (!y) return 1;
|
||||||
|
if (!len) return 0;
|
||||||
|
--len;
|
||||||
|
x = *s++ - 'A';
|
||||||
|
if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
|
||||||
|
if (x != y) return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
global.h
Normal file
51
global.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* GLOBAL.H - RSAREF types and constants */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "uint32.h"
|
||||||
|
|
||||||
|
/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
|
||||||
|
Inc., created 1991. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GLOBAL_H_
|
||||||
|
#define _GLOBAL_H_ 1
|
||||||
|
|
||||||
|
/* PROTOTYPES should be set to one if and only if the compiler supports
|
||||||
|
function argument prototyping.
|
||||||
|
The following makes PROTOTYPES default to 1 if it has not already been
|
||||||
|
defined as 0 with C compiler flags.
|
||||||
|
*/
|
||||||
|
#ifndef PROTOTYPES
|
||||||
|
#define PROTOTYPES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* POINTER defines a generic pointer type */
|
||||||
|
typedef unsigned char *POINTER;
|
||||||
|
|
||||||
|
/* UINT2 defines a two byte word */
|
||||||
|
typedef unsigned short int UINT2;
|
||||||
|
|
||||||
|
/* UINT4 defines a four byte word */
|
||||||
|
#ifdef UINT32_H
|
||||||
|
#define UINT4 uint32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NULL_PTR
|
||||||
|
#define NULL_PTR ((POINTER)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UNUSED_ARG
|
||||||
|
#define UNUSED_ARG(x) x = *(&x);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
|
||||||
|
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
|
||||||
|
returns an empty list.
|
||||||
|
*/
|
||||||
|
#if PROTOTYPES
|
||||||
|
#define PROTO_LIST(list) list
|
||||||
|
#else
|
||||||
|
#define PROTO_LIST(list) ()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* end _GLOBAL_H_ */
|
||||||
76
hmac_md5.c
Normal file
76
hmac_md5.c
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include "global.h"
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Function: hmac_md5
|
||||||
|
*/
|
||||||
|
|
||||||
|
void hmac_md5(text, text_len, key, key_len, digest)
|
||||||
|
unsigned char* text; /* pointer to data stream */
|
||||||
|
int text_len; /* length of data stream */
|
||||||
|
unsigned char* key; /* pointer to authentication key */
|
||||||
|
int key_len; /* length of authentication key */
|
||||||
|
unsigned char *digest; /* caller digest to be filled in */
|
||||||
|
|
||||||
|
{
|
||||||
|
MD5_CTX context;
|
||||||
|
unsigned char k_ipad[65]; /* inner padding -
|
||||||
|
* key XORd with ipad
|
||||||
|
*/
|
||||||
|
unsigned char k_opad[65]; /* outer padding -
|
||||||
|
* key XORd with opad
|
||||||
|
*/
|
||||||
|
unsigned char tk[16];
|
||||||
|
int i;
|
||||||
|
/* if key is longer than 64 bytes reset it to key=MD5(key) */
|
||||||
|
if (key_len > 64) {
|
||||||
|
|
||||||
|
MD5_CTX tctx;
|
||||||
|
|
||||||
|
MD5Init(&tctx);
|
||||||
|
MD5Update(&tctx, key, key_len);
|
||||||
|
MD5Final(tk, &tctx);
|
||||||
|
|
||||||
|
key = tk;
|
||||||
|
key_len = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the HMAC_MD5 transform looks like:
|
||||||
|
*
|
||||||
|
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||||
|
*
|
||||||
|
* where K is an n byte key
|
||||||
|
* ipad is the byte 0x36 repeated 64 times
|
||||||
|
* opad is the byte 0x5c repeated 64 times
|
||||||
|
* and text is the data being protected
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* start out by storing key in pads */
|
||||||
|
bzero( k_ipad, sizeof k_ipad);
|
||||||
|
bzero( k_opad, sizeof k_opad);
|
||||||
|
bcopy( key, k_ipad, key_len);
|
||||||
|
bcopy( key, k_opad, key_len);
|
||||||
|
|
||||||
|
/* XOR key with ipad and opad values */
|
||||||
|
for (i=0; i<64; i++) {
|
||||||
|
k_ipad[i] ^= 0x36;
|
||||||
|
k_opad[i] ^= 0x5c;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* perform inner MD5
|
||||||
|
*/
|
||||||
|
MD5Init(&context); /* init context for 1st pass */
|
||||||
|
MD5Update(&context, k_ipad, 64); /* start with inner pad */
|
||||||
|
MD5Update(&context, text, text_len); /* then text of datagram */
|
||||||
|
MD5Final(digest, &context); /* finish up 1st pass */
|
||||||
|
/*
|
||||||
|
* perform outer MD5
|
||||||
|
*/
|
||||||
|
MD5Init(&context); /* init context for 2nd
|
||||||
|
* pass */
|
||||||
|
MD5Update(&context, k_opad, 64); /* start with outer pad */
|
||||||
|
MD5Update(&context, digest, 16); /* then results of 1st
|
||||||
|
* hash */
|
||||||
|
MD5Final(digest, &context); /* finish up 2nd pass */
|
||||||
|
}
|
||||||
11
hmac_md5.h
Normal file
11
hmac_md5.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
/* prototypes */
|
||||||
|
|
||||||
|
void hmac_md5( unsigned char* text, int text_len, unsigned char* key, int key_len, unsigned char* digest);
|
||||||
|
|
||||||
|
/* pointer to data stream */
|
||||||
|
/* length of data stream */
|
||||||
|
/* pointer to authentication key */
|
||||||
|
/* length of authentication key */
|
||||||
|
/* caller digest to be filled in */
|
||||||
|
|
||||||
101
install_authentication.sh
Executable file
101
install_authentication.sh
Executable file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# qmail-smtpd AUTH (UN)INSTALL Script (install_authentication.sh)
|
||||||
|
# -------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Purpose: To install and uninstall the qmail-smtpd Authentication Patch
|
||||||
|
#
|
||||||
|
# Parameters: -u (uninstall)
|
||||||
|
# VRF (Version to be uninstalled)
|
||||||
|
#
|
||||||
|
# Usage: ./install_authentication.sh [-u] [Version]
|
||||||
|
#
|
||||||
|
# Installation: ./install_authentication.sh
|
||||||
|
# Uninstallation: ./install_authentication.sh -u 105
|
||||||
|
#
|
||||||
|
# Return Codes: 0 - Patches applied successfully
|
||||||
|
# 1 - Original QMAIL files not found (Patch not extracted in QMAIL source directory)
|
||||||
|
# 2 - Patch files not found
|
||||||
|
#
|
||||||
|
# Output: install_auth.log
|
||||||
|
#
|
||||||
|
# History: 1.0.0 - Erwin Hoffmann - Initial release
|
||||||
|
# 1.0.1 - - grep fix; Gentoo fix
|
||||||
|
# 1.0.2 - removed '-v' optio for cp
|
||||||
|
# 1.0.3 - mods for 'qmail authentication'
|
||||||
|
# 1.0.4 - some renameing
|
||||||
|
#
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
DATE=$(date)
|
||||||
|
LOCDIR=${PWD}
|
||||||
|
QMAILHOME=$(head -n 1 conf-qmail)
|
||||||
|
SOLARIS=$(sh ./find-systype.sh | grep -ci "SunOS")
|
||||||
|
LOGFILE=auth.log
|
||||||
|
TARGETS=FILES.auth
|
||||||
|
IFSKEEP=${IFS}
|
||||||
|
REL=083 # Should be identical to qmail AUTH level
|
||||||
|
BUILD=20150823180830
|
||||||
|
|
||||||
|
|
||||||
|
if [ $# -eq 0 ] ; then
|
||||||
|
|
||||||
|
echo "Installing qmail AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1
|
||||||
|
|
||||||
|
for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
|
||||||
|
echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
|
||||||
|
if [ -s ${FILE} ] ; then
|
||||||
|
cp ${FILE} ${FILE}.$REL | tee -a $LOGFILE 2>&1
|
||||||
|
echo "--> ${FILE} copied to ${FILE}.$REL" | tee -a $LOGFILE 2>&1
|
||||||
|
else
|
||||||
|
echo "${FILE} not found !"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -s ${FILE}.patch ] ; then
|
||||||
|
if [ ${SOLARIS} -gt 0 ]; then
|
||||||
|
echo "--> Patching qmail source file ${FILE} for Solaris ...." | tee -a $LOGFILE 2>&1
|
||||||
|
patch -i ${FILE}.patch ${FILE} 2>&1 | tee -a $LOGFILE
|
||||||
|
else
|
||||||
|
echo "--> Patching qmail source file ${FILE} ...." | tee -a $LOGFILE 2>&1
|
||||||
|
patch ${FILE} ${FILE}.patch 2>&1 | tee -a $LOGFILE
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "!! ${FILE}.patch not found !"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
echo "Copying documentation and samples to ${QMAILHOME}/doc/ ..." | tee -a $LOGFILE 2>&1
|
||||||
|
|
||||||
|
cp README.auth* ${QMAILHOME}/doc/ | tee -a $LOGFILE 2>&1
|
||||||
|
echo ""
|
||||||
|
echo "If you dont wont CRAM-MD5 suport disable '#define CRAM_MD5' in qmail-smtpd !"
|
||||||
|
echo "Installation of qmail authentication $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1
|
||||||
|
|
||||||
|
# Now go for the uninstallation....
|
||||||
|
|
||||||
|
elif [ "$1" = "-u" ] ; then
|
||||||
|
|
||||||
|
# Get the Version Number from INPUT
|
||||||
|
|
||||||
|
if [ $# -eq 2 ] ; then
|
||||||
|
REL=$2
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "De-installing qmail authentication $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1
|
||||||
|
|
||||||
|
for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
|
||||||
|
echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
|
||||||
|
if [ -s ${FILE}.$REL ] ; then
|
||||||
|
mv ${FILE}.$REL ${FILE} | tee -a $LOGFILE 2>&1
|
||||||
|
touch ${FILE}
|
||||||
|
echo "--> ${FILE}.$REL moved to ${FILE}" | tee -a $LOGFILE 2>&1
|
||||||
|
else
|
||||||
|
echo "!! ${FILE}.$REL not found !"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "De-installation of qmail authentication $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
49
md5.h
Normal file
49
md5.h
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
/* MD5.H - header file for MD5C.C
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||||
|
rights reserved.
|
||||||
|
|
||||||
|
License to copy and use this software is granted provided that it
|
||||||
|
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||||
|
Algorithm" in all material mentioning or referencing this software
|
||||||
|
or this function.
|
||||||
|
|
||||||
|
License is also granted to make and use derivative works provided
|
||||||
|
that such works are identified as "derived from the RSA Data
|
||||||
|
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||||
|
mentioning or referencing the derived work.
|
||||||
|
|
||||||
|
RSA Data Security, Inc. makes no representations concerning either
|
||||||
|
the merchantability of this software or the suitability of this
|
||||||
|
software for any particular purpose. It is provided "as is"
|
||||||
|
without express or implied warranty of any kind.
|
||||||
|
|
||||||
|
These notices must be retained in any copies of any part of this
|
||||||
|
documentation and/or software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MD5_H_
|
||||||
|
#define _MD5_H_ 1
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MD5 context. */
|
||||||
|
typedef struct {
|
||||||
|
UINT4 state[4]; /* state (ABCD) */
|
||||||
|
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||||
|
unsigned char buffer[64]; /* input buffer */
|
||||||
|
} MD5_CTX;
|
||||||
|
|
||||||
|
void MD5Init PROTO_LIST ((MD5_CTX *));
|
||||||
|
void MD5Update PROTO_LIST
|
||||||
|
((MD5_CTX *, unsigned char *, unsigned int));
|
||||||
|
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
334
md5c.c
Normal file
334
md5c.c
Normal file
|
|
@ -0,0 +1,334 @@
|
||||||
|
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||||
|
rights reserved.
|
||||||
|
|
||||||
|
License to copy and use this software is granted provided that it
|
||||||
|
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||||
|
Algorithm" in all material mentioning or referencing this software
|
||||||
|
or this function.
|
||||||
|
|
||||||
|
License is also granted to make and use derivative works provided
|
||||||
|
that such works are identified as "derived from the RSA Data
|
||||||
|
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||||
|
mentioning or referencing the derived work.
|
||||||
|
|
||||||
|
RSA Data Security, Inc. makes no representations concerning either
|
||||||
|
the merchantability of this software or the suitability of this
|
||||||
|
software for any particular purpose. It is provided "as is"
|
||||||
|
without express or implied warranty of any kind.
|
||||||
|
|
||||||
|
These notices must be retained in any copies of any part of this
|
||||||
|
documentation and/or software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "md5.h"
|
||||||
|
|
||||||
|
/* Constants for MD5Transform routine.
|
||||||
|
*/
|
||||||
|
#define S11 7
|
||||||
|
#define S12 12
|
||||||
|
#define S13 17
|
||||||
|
#define S14 22
|
||||||
|
#define S21 5
|
||||||
|
#define S22 9
|
||||||
|
#define S23 14
|
||||||
|
#define S24 20
|
||||||
|
#define S31 4
|
||||||
|
#define S32 11
|
||||||
|
#define S33 16
|
||||||
|
#define S34 23
|
||||||
|
#define S41 6
|
||||||
|
#define S42 10
|
||||||
|
#define S43 15
|
||||||
|
#define S44 21
|
||||||
|
|
||||||
|
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
|
||||||
|
static void Encode PROTO_LIST
|
||||||
|
((unsigned char *, UINT4 *, unsigned int));
|
||||||
|
static void Decode PROTO_LIST
|
||||||
|
((UINT4 *, unsigned char *, unsigned int));
|
||||||
|
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
|
||||||
|
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
|
||||||
|
|
||||||
|
static unsigned char PADDING[64] = {
|
||||||
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* F, G, H and I are basic MD5 functions.
|
||||||
|
*/
|
||||||
|
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||||
|
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||||
|
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||||
|
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||||
|
|
||||||
|
/* ROTATE_LEFT rotates x left n bits.
|
||||||
|
*/
|
||||||
|
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||||
|
|
||||||
|
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||||
|
Rotation is separate from addition to prevent recomputation.
|
||||||
|
*/
|
||||||
|
#define FF(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
#define GG(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
#define HH(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
#define II(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||||
|
*/
|
||||||
|
void MD5Init (context)
|
||||||
|
MD5_CTX *context; /* context */
|
||||||
|
{
|
||||||
|
context->count[0] = context->count[1] = 0;
|
||||||
|
|
||||||
|
/* Load magic initialization constants.
|
||||||
|
*/
|
||||||
|
context->state[0] = 0x67452301;
|
||||||
|
context->state[1] = 0xefcdab89;
|
||||||
|
context->state[2] = 0x98badcfe;
|
||||||
|
context->state[3] = 0x10325476;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD5 block update operation. Continues an MD5 message-digest
|
||||||
|
operation, processing another message block, and updating the
|
||||||
|
context.
|
||||||
|
*/
|
||||||
|
void MD5Update (context, input, inputLen)
|
||||||
|
MD5_CTX *context; /* context */
|
||||||
|
unsigned char *input; /* input block */
|
||||||
|
unsigned int inputLen; /* length of input block */
|
||||||
|
{
|
||||||
|
unsigned int i, index, partLen;
|
||||||
|
|
||||||
|
/* Compute number of bytes mod 64 */
|
||||||
|
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||||
|
|
||||||
|
/* Update number of bits */
|
||||||
|
if ((context->count[0] += ((UINT4)inputLen << 3))
|
||||||
|
< ((UINT4)inputLen << 3))
|
||||||
|
context->count[1]++;
|
||||||
|
context->count[1] += ((UINT4)inputLen >> 29);
|
||||||
|
|
||||||
|
partLen = 64 - index;
|
||||||
|
|
||||||
|
/* Transform as many times as possible.
|
||||||
|
*/
|
||||||
|
if (inputLen >= partLen) {
|
||||||
|
MD5_memcpy
|
||||||
|
((POINTER)&context->buffer[index], (POINTER)input, partLen);
|
||||||
|
MD5Transform (context->state, context->buffer);
|
||||||
|
|
||||||
|
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||||
|
MD5Transform (context->state, &input[i]);
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Buffer remaining input */
|
||||||
|
MD5_memcpy
|
||||||
|
((POINTER)&context->buffer[index], (POINTER)&input[i],
|
||||||
|
inputLen-i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||||
|
the message digest and zeroizing the context.
|
||||||
|
*/
|
||||||
|
void MD5Final (digest, context)
|
||||||
|
unsigned char digest[16]; /* message digest */
|
||||||
|
MD5_CTX *context; /* context */
|
||||||
|
{
|
||||||
|
unsigned char bits[8];
|
||||||
|
unsigned int index, padLen;
|
||||||
|
|
||||||
|
/* Save number of bits */
|
||||||
|
Encode (bits, context->count, 8);
|
||||||
|
|
||||||
|
/* Pad out to 56 mod 64.
|
||||||
|
*/
|
||||||
|
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||||
|
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||||
|
MD5Update (context, PADDING, padLen);
|
||||||
|
|
||||||
|
/* Append length (before padding) */
|
||||||
|
MD5Update (context, bits, 8);
|
||||||
|
|
||||||
|
/* Store state in digest */
|
||||||
|
Encode (digest, context->state, 16);
|
||||||
|
|
||||||
|
/* Zeroize sensitive information.
|
||||||
|
*/
|
||||||
|
MD5_memset ((POINTER)context, 0, sizeof (*context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD5 basic transformation. Transforms state based on block.
|
||||||
|
*/
|
||||||
|
static void MD5Transform (state, block)
|
||||||
|
UINT4 state[4];
|
||||||
|
unsigned char block[64];
|
||||||
|
{
|
||||||
|
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||||
|
|
||||||
|
Decode (x, block, 64);
|
||||||
|
|
||||||
|
/* Round 1 */
|
||||||
|
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||||
|
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||||
|
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||||
|
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||||
|
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||||
|
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||||
|
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||||
|
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||||
|
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||||
|
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||||
|
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||||
|
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||||
|
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||||
|
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||||
|
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||||
|
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||||
|
|
||||||
|
/* Round 2 */
|
||||||
|
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||||
|
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||||
|
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||||
|
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||||
|
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||||
|
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||||
|
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||||
|
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||||
|
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||||
|
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||||
|
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||||
|
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||||
|
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||||
|
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||||
|
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||||
|
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||||
|
|
||||||
|
/* Round 3 */
|
||||||
|
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||||
|
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||||
|
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||||
|
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||||
|
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||||
|
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||||
|
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||||
|
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||||
|
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||||
|
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||||
|
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||||
|
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||||
|
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||||
|
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||||
|
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||||
|
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||||
|
|
||||||
|
/* Round 4 */
|
||||||
|
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||||
|
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||||
|
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||||
|
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||||
|
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||||
|
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||||
|
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||||
|
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||||
|
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||||
|
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||||
|
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||||
|
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||||
|
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||||
|
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||||
|
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||||
|
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||||
|
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
|
||||||
|
/* Zeroize sensitive information.
|
||||||
|
*/
|
||||||
|
MD5_memset ((POINTER)x, 0, sizeof (x));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||||
|
a multiple of 4.
|
||||||
|
*/
|
||||||
|
static void Encode (output, input, len)
|
||||||
|
unsigned char *output;
|
||||||
|
UINT4 *input;
|
||||||
|
unsigned int len;
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||||
|
output[j] = (unsigned char)(input[i] & 0xff);
|
||||||
|
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||||
|
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||||
|
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||||
|
a multiple of 4.
|
||||||
|
*/
|
||||||
|
static void Decode (output, input, len)
|
||||||
|
UINT4 *output;
|
||||||
|
unsigned char *input;
|
||||||
|
unsigned int len;
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||||
|
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
|
||||||
|
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||||
|
*/
|
||||||
|
static void MD5_memcpy (output, input, len)
|
||||||
|
POINTER output;
|
||||||
|
POINTER input;
|
||||||
|
unsigned int len;
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
output[i] = input[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: Replace "for loop" with standard memset if possible.
|
||||||
|
*/
|
||||||
|
static void MD5_memset (output, value, len)
|
||||||
|
POINTER output;
|
||||||
|
int value;
|
||||||
|
unsigned int len;
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
((char *)output)[i] = (char)value;
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,7 @@ See the corresponding man pages for further details.
|
||||||
.ta 5c 10c
|
.ta 5c 10c
|
||||||
control default used by
|
control default used by
|
||||||
|
|
||||||
|
.I authsender \fR(none) \fRqmail-remote
|
||||||
.I badmailfrom \fR(none) \fRqmail-smtpd
|
.I badmailfrom \fR(none) \fRqmail-smtpd
|
||||||
.I bouncefrom \fRMAILER-DAEMON \fRqmail-send
|
.I bouncefrom \fRMAILER-DAEMON \fRqmail-send
|
||||||
.I bouncehost \fIme \fRqmail-send
|
.I bouncehost \fIme \fRqmail-send
|
||||||
|
|
|
||||||
122
qmail-remote.8
122
qmail-remote.8
|
|
@ -53,6 +53,7 @@ does not take options
|
||||||
and does not follow the
|
and does not follow the
|
||||||
.B getopt
|
.B getopt
|
||||||
standard.
|
standard.
|
||||||
|
|
||||||
.SH TRANSPARENCY
|
.SH TRANSPARENCY
|
||||||
End-of-file in SMTP is encoded as dot CR LF.
|
End-of-file in SMTP is encoded as dot CR LF.
|
||||||
A dot at the beginning of a line is encoded as dot dot.
|
A dot at the beginning of a line is encoded as dot dot.
|
||||||
|
|
@ -100,6 +101,73 @@ Message report: permanent failure.
|
||||||
After this letter comes a human-readable description of
|
After this letter comes a human-readable description of
|
||||||
what happened.
|
what happened.
|
||||||
|
|
||||||
|
.B qmail-remote
|
||||||
|
may use SMTP Authenticaton of type CRAM-MD4, PLAIN, or LOGIN
|
||||||
|
(in this order) to connect to remote hosts.
|
||||||
|
The following reports are provided:
|
||||||
|
.TP 5
|
||||||
|
K
|
||||||
|
no supported AUTH method found, continuing without authentication.
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but authentication was rejected (AUTH PLAIN).
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but unable to base64encode (plain).
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but authentication was rejected (plain)."
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but authentication was rejected (AUTH LOGIN).
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but unable to base64encode user.
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but authentication was rejected (username).
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but unable to base64encode pass.
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but authentication was rejected (AUTH CRAM-MD5).
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but unable to base64decode challenge.
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but unable to base64encode username+digest.
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but password expired.
|
||||||
|
.TP 5
|
||||||
|
Z
|
||||||
|
Connected to
|
||||||
|
.I host
|
||||||
|
but authentication was rejected (username+digest).
|
||||||
|
.PP
|
||||||
The recipient reports will always be printed in the same order as
|
The recipient reports will always be printed in the same order as
|
||||||
.BR qmail-remote 's
|
.BR qmail-remote 's
|
||||||
.I recip
|
.I recip
|
||||||
|
|
@ -114,6 +182,51 @@ arguments.
|
||||||
always exits zero.
|
always exits zero.
|
||||||
.SH "CONTROL FILES"
|
.SH "CONTROL FILES"
|
||||||
.TP 5
|
.TP 5
|
||||||
|
.I authsenders
|
||||||
|
Authenticated sender.
|
||||||
|
For each
|
||||||
|
.I sender
|
||||||
|
included in
|
||||||
|
.IR authsenders :
|
||||||
|
.I sender\fB:\fIrelay\fB:\fIport\fB|\fIuser\fB|\fIpassword
|
||||||
|
.B qmail-remote
|
||||||
|
will try SMTP Authentication
|
||||||
|
of type CRAM-MD5, LOGIN, or PLAIN
|
||||||
|
with the provided user name
|
||||||
|
.I user
|
||||||
|
and password
|
||||||
|
.I password
|
||||||
|
(the authentication information)
|
||||||
|
and eventually relay the
|
||||||
|
mail through
|
||||||
|
.I relay
|
||||||
|
on port
|
||||||
|
.IR port .
|
||||||
|
The use of
|
||||||
|
.I relay
|
||||||
|
and
|
||||||
|
.I port
|
||||||
|
follows the same rules as for
|
||||||
|
.IR smtproutes
|
||||||
|
Note: In case
|
||||||
|
.I sender
|
||||||
|
is empty,
|
||||||
|
.B qmail-remote
|
||||||
|
will try to deliver each outgoing mail
|
||||||
|
SMTP authenticated. If the authentication
|
||||||
|
information is missing, the mail is
|
||||||
|
delivered none-authenticated.
|
||||||
|
.I authsenders
|
||||||
|
can be constructed as follows:
|
||||||
|
|
||||||
|
.EX
|
||||||
|
@example.com|generic|passwd
|
||||||
|
.subdomain.example.com|other|otherpw
|
||||||
|
mail@example.com|test|testpass
|
||||||
|
info@example.com:smtp.example.com:26|other|otherpw
|
||||||
|
:mailrelay.example.com:587|e=mc2|testpass
|
||||||
|
.EE
|
||||||
|
.TP 5
|
||||||
.I helohost
|
.I helohost
|
||||||
Current host name,
|
Current host name,
|
||||||
for use solely in saying hello to the remote SMTP server.
|
for use solely in saying hello to the remote SMTP server.
|
||||||
|
|
@ -128,7 +241,9 @@ refuses to run.
|
||||||
Artificial SMTP routes.
|
Artificial SMTP routes.
|
||||||
Each route has the form
|
Each route has the form
|
||||||
.IR domain\fB:\fIrelay ,
|
.IR domain\fB:\fIrelay ,
|
||||||
without any extra spaces.
|
or
|
||||||
|
.IR domain\fB:\fIrelay\fB|\fIuser\fB|\fIpassword
|
||||||
|
in case of authenticated routes without any extra spaces.
|
||||||
If
|
If
|
||||||
.I domain
|
.I domain
|
||||||
matches
|
matches
|
||||||
|
|
@ -149,6 +264,7 @@ normal SMTP port, 25:
|
||||||
|
|
||||||
.EX
|
.EX
|
||||||
inside.af.mil:firewall.af.mil:26
|
inside.af.mil:firewall.af.mil:26
|
||||||
|
:submission.myrelay.com:587|myuserid|mypasswd
|
||||||
.EE
|
.EE
|
||||||
|
|
||||||
.I relay
|
.I relay
|
||||||
|
|
@ -182,6 +298,10 @@ However,
|
||||||
you are always safe using
|
you are always safe using
|
||||||
.I smtproutes
|
.I smtproutes
|
||||||
if you do not accept mail from the network.
|
if you do not accept mail from the network.
|
||||||
|
Note:
|
||||||
|
.I authsender
|
||||||
|
routes have precedence over
|
||||||
|
.IR smtproutes .
|
||||||
.TP 5
|
.TP 5
|
||||||
.I timeoutconnect
|
.I timeoutconnect
|
||||||
Number of seconds
|
Number of seconds
|
||||||
|
|
|
||||||
263
qmail-remote.c
263
qmail-remote.c
|
|
@ -28,6 +28,7 @@
|
||||||
#include "timeoutconn.h"
|
#include "timeoutconn.h"
|
||||||
#include "timeoutread.h"
|
#include "timeoutread.h"
|
||||||
#include "timeoutwrite.h"
|
#include "timeoutwrite.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
#define HUGESMTPTEXT 5000
|
#define HUGESMTPTEXT 5000
|
||||||
|
|
||||||
|
|
@ -44,6 +45,16 @@ struct constmap maproutes;
|
||||||
stralloc host = {0};
|
stralloc host = {0};
|
||||||
stralloc sender = {0};
|
stralloc sender = {0};
|
||||||
|
|
||||||
|
stralloc authsenders = {0};
|
||||||
|
struct constmap mapauthsenders;
|
||||||
|
stralloc user = {0};
|
||||||
|
stralloc pass = {0};
|
||||||
|
stralloc auth = {0};
|
||||||
|
stralloc plain = {0};
|
||||||
|
stralloc chal = {0};
|
||||||
|
stralloc slop = {0};
|
||||||
|
char *authsender;
|
||||||
|
|
||||||
saa reciplist = {0};
|
saa reciplist = {0};
|
||||||
|
|
||||||
struct ip_address partner;
|
struct ip_address partner;
|
||||||
|
|
@ -86,6 +97,12 @@ Sorry. Although I'm listed as a best-preference MX or A for that host,\n\
|
||||||
it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
|
it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
|
||||||
zerodie(); }
|
zerodie(); }
|
||||||
|
|
||||||
|
void err_authprot() {
|
||||||
|
out("Kno supported AUTH method found, continuing without authentication.\n");
|
||||||
|
zero();
|
||||||
|
substdio_flush(subfdoutsmall);
|
||||||
|
}
|
||||||
|
|
||||||
void outhost()
|
void outhost()
|
||||||
{
|
{
|
||||||
char x[IPFMT];
|
char x[IPFMT];
|
||||||
|
|
@ -216,24 +233,192 @@ void blast()
|
||||||
|
|
||||||
stralloc recip = {0};
|
stralloc recip = {0};
|
||||||
|
|
||||||
|
void mailfrom()
|
||||||
|
{
|
||||||
|
substdio_puts(&smtpto,"MAIL FROM:<");
|
||||||
|
substdio_put(&smtpto,sender.s,sender.len);
|
||||||
|
substdio_puts(&smtpto,">\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
}
|
||||||
|
|
||||||
|
stralloc xuser = {0};
|
||||||
|
|
||||||
|
int xtext(sa,s,len)
|
||||||
|
stralloc *sa;
|
||||||
|
char *s;
|
||||||
|
int len;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!stralloc_copys(sa,"")) temp_nomem();
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (s[i] == '=') {
|
||||||
|
if (!stralloc_cats(sa,"+3D")) temp_nomem();
|
||||||
|
} else if (s[i] == '+') {
|
||||||
|
if (!stralloc_cats(sa,"+2B")) temp_nomem();
|
||||||
|
} else if ((int) s[i] < 33 || (int) s[i] > 126) {
|
||||||
|
if (!stralloc_cats(sa,"+3F")) temp_nomem(); /* ok. not correct */
|
||||||
|
} else if (!stralloc_catb(sa,s+i,1)) {
|
||||||
|
temp_nomem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sa->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mailfrom_xtext()
|
||||||
|
{
|
||||||
|
if (!xtext(&xuser,user.s,user.len)) temp_nomem();
|
||||||
|
substdio_puts(&smtpto,"MAIL FROM:<");
|
||||||
|
substdio_put(&smtpto,sender.s,sender.len);
|
||||||
|
substdio_puts(&smtpto,"> AUTH=");
|
||||||
|
substdio_put(&smtpto,xuser.s,xuser.len);
|
||||||
|
substdio_puts(&smtpto,"\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mailfrom_plain()
|
||||||
|
{
|
||||||
|
substdio_puts(&smtpto,"AUTH PLAIN\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH PLAIN)."); return -1; }
|
||||||
|
|
||||||
|
if (!stralloc_cat(&plain,&user)) temp_nomem(); /* <authorization-id> */
|
||||||
|
if (!stralloc_0(&plain)) temp_nomem();
|
||||||
|
if (!stralloc_cat(&plain,&user)) temp_nomem(); /* <authentication-id> */
|
||||||
|
if (!stralloc_0(&plain)) temp_nomem();
|
||||||
|
if (!stralloc_cat(&plain,&pass)) temp_nomem(); /* password */
|
||||||
|
if (b64encode(&plain,&auth)) quit("ZConnected to "," but unable to base64encode (plain).");
|
||||||
|
substdio_put(&smtpto,auth.s,auth.len);
|
||||||
|
substdio_puts(&smtpto,"\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
|
||||||
|
else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
|
||||||
|
else { quit("ZConnected to "," but authentication was rejected (plain)."); return 1; }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mailfrom_login()
|
||||||
|
{
|
||||||
|
substdio_puts(&smtpto,"AUTH LOGIN\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)."); return -1; }
|
||||||
|
|
||||||
|
if (!stralloc_copys(&auth,"")) temp_nomem();
|
||||||
|
if (b64encode(&user,&auth)) quit("ZConnected to "," but unable to base64encode user.");
|
||||||
|
substdio_put(&smtpto,auth.s,auth.len);
|
||||||
|
substdio_puts(&smtpto,"\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username).");
|
||||||
|
|
||||||
|
if (!stralloc_copys(&auth,"")) temp_nomem();
|
||||||
|
if (b64encode(&pass,&auth)) quit("ZConnected to "," but unable to base64encode pass.");
|
||||||
|
substdio_put(&smtpto,auth.s,auth.len);
|
||||||
|
substdio_puts(&smtpto,"\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
|
||||||
|
else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
|
||||||
|
else { quit("ZConnected to "," but authentication was rejected (password)."); return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int mailfrom_cram()
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
unsigned char h;
|
||||||
|
unsigned char digest[16];
|
||||||
|
unsigned char digascii[33];
|
||||||
|
static char hextab[]="0123456789abcdef";
|
||||||
|
|
||||||
|
substdio_puts(&smtpto,"AUTH CRAM-MD5\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH CRAM-MD5)."); return -1; }
|
||||||
|
|
||||||
|
if (str_chr(smtptext.s+4,' ')) { /* Challenge */
|
||||||
|
if(!stralloc_copys(&slop,"")) temp_nomem();
|
||||||
|
if (!stralloc_copyb(&slop,smtptext.s+4,smtptext.len-5)) temp_nomem();
|
||||||
|
if (b64decode(slop.s,slop.len,&chal)) quit("ZConnected to "," but unable to base64decode challenge.");
|
||||||
|
}
|
||||||
|
|
||||||
|
hmac_md5(chal.s,chal.len,pass.s,pass.len,digest);
|
||||||
|
|
||||||
|
for (j = 0;j < 16;j++) /* HEX => ASCII */
|
||||||
|
{
|
||||||
|
digascii[2*j] = hextab[digest[j] >> 4];
|
||||||
|
digascii[2*j+1] = hextab[digest[j] & 0xf];
|
||||||
|
}
|
||||||
|
digascii[32]=0;
|
||||||
|
|
||||||
|
slop.len = 0;
|
||||||
|
if (!stralloc_copys(&slop,"")) temp_nomem();
|
||||||
|
if (!stralloc_cat(&slop,&user)) temp_nomem(); /* user-id */
|
||||||
|
if (!stralloc_cats(&slop," ")) temp_nomem();
|
||||||
|
if (!stralloc_catb(&slop,digascii,32)) temp_nomem(); /* digest */
|
||||||
|
|
||||||
|
if (!stralloc_copys(&auth,"")) temp_nomem();
|
||||||
|
if (b64encode(&slop,&auth)) quit("ZConnected to "," but unable to base64encode username+digest.");
|
||||||
|
substdio_put(&smtpto,auth.s,auth.len);
|
||||||
|
substdio_puts(&smtpto,"\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
|
||||||
|
else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
|
||||||
|
else { quit("ZConnected to "," but authentication was rejected (username+digest)."); return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void smtp_auth()
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i + 8 < smtptext.len; i += str_chr(smtptext.s+i,'\n')+1)
|
||||||
|
if (!str_diffn(smtptext.s+i+4,"AUTH",4)) {
|
||||||
|
if (j = str_chr(smtptext.s+i+8,'C') > 0)
|
||||||
|
if (case_starts(smtptext.s+i+8+j,"CRAM"))
|
||||||
|
if (mailfrom_cram() >= 0) return;
|
||||||
|
|
||||||
|
if (j = str_chr(smtptext.s+i+8,'P') > 0)
|
||||||
|
if (case_starts(smtptext.s+i+8+j,"PLAIN"))
|
||||||
|
if (mailfrom_plain() >= 0) return;
|
||||||
|
|
||||||
|
if (j = str_chr(smtptext.s+i+8,'L') > 0)
|
||||||
|
if (case_starts(smtptext.s+i+8+j,"LOGIN"))
|
||||||
|
if (mailfrom_login() >= 0) return;
|
||||||
|
|
||||||
|
err_authprot();
|
||||||
|
mailfrom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void smtp()
|
void smtp()
|
||||||
{
|
{
|
||||||
unsigned long code;
|
unsigned long code;
|
||||||
int flagbother;
|
int flagbother;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
|
code = smtpcode();
|
||||||
|
if (code >= 500) quit("DConnected to "," but greeting failed");
|
||||||
|
if (code != 220) quit("ZConnected to "," but greeting failed");
|
||||||
|
|
||||||
|
substdio_puts(&smtpto,"EHLO ");
|
||||||
|
substdio_put(&smtpto,helohost.s,helohost.len);
|
||||||
|
substdio_puts(&smtpto,"\r\n");
|
||||||
|
substdio_flush(&smtpto);
|
||||||
|
|
||||||
|
if (smtpcode() != 250) {
|
||||||
substdio_puts(&smtpto,"HELO ");
|
substdio_puts(&smtpto,"HELO ");
|
||||||
substdio_put(&smtpto,helohost.s,helohost.len);
|
substdio_put(&smtpto,helohost.s,helohost.len);
|
||||||
substdio_puts(&smtpto,"\r\n");
|
substdio_puts(&smtpto,"\r\n");
|
||||||
substdio_flush(&smtpto);
|
substdio_flush(&smtpto);
|
||||||
if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
|
code = smtpcode();
|
||||||
|
if (code >= 500) quit("DConnected to "," but my name was rejected");
|
||||||
|
if (code != 250) quit("ZConnected to "," but my name was rejected");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.len && pass.len)
|
||||||
|
smtp_auth();
|
||||||
|
else
|
||||||
|
mailfrom();
|
||||||
|
|
||||||
substdio_puts(&smtpto,"MAIL FROM:<");
|
|
||||||
substdio_put(&smtpto,sender.s,sender.len);
|
|
||||||
substdio_puts(&smtpto,">\r\n");
|
|
||||||
substdio_flush(&smtpto);
|
|
||||||
code = smtpcode();
|
code = smtpcode();
|
||||||
if (code >= 500) quit("DConnected to "," but sender was rejected");
|
if (code >= 500) quit("DConnected to "," but sender was rejected");
|
||||||
if (code >= 400) quit("ZConnected to "," but sender was rejected");
|
if (code >= 400) quit("ZConnected to "," but sender was rejected");
|
||||||
|
|
@ -324,14 +509,23 @@ void getcontrols()
|
||||||
case 1:
|
case 1:
|
||||||
if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
|
if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(control_readfile(&authsenders,"control/authsenders",0)) {
|
||||||
|
case -1:
|
||||||
|
temp_control();
|
||||||
|
case 0:
|
||||||
|
if (!constmap_init(&mapauthsenders,"",0,1)) temp_nomem(); break;
|
||||||
|
case 1:
|
||||||
|
if (!constmap_init(&mapauthsenders,authsenders.s,authsenders.len,1)) temp_nomem(); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(argc,argv)
|
int main(argc,argv)
|
||||||
int argc;
|
int argc;
|
||||||
char **argv;
|
char **argv;
|
||||||
{
|
{
|
||||||
static ipalloc ip = {0};
|
static ipalloc ip = {0};
|
||||||
int i;
|
int i, j;
|
||||||
unsigned long random;
|
unsigned long random;
|
||||||
char **recips;
|
char **recips;
|
||||||
unsigned long prefme;
|
unsigned long prefme;
|
||||||
|
|
@ -344,17 +538,64 @@ char **argv;
|
||||||
if (chdir(auto_qmail) == -1) temp_chdir();
|
if (chdir(auto_qmail) == -1) temp_chdir();
|
||||||
getcontrols();
|
getcontrols();
|
||||||
|
|
||||||
|
|
||||||
if (!stralloc_copys(&host,argv[1])) temp_nomem();
|
if (!stralloc_copys(&host,argv[1])) temp_nomem();
|
||||||
|
|
||||||
|
authsender = 0;
|
||||||
relayhost = 0;
|
relayhost = 0;
|
||||||
|
|
||||||
|
addrmangle(&sender,argv[2],&flagalias,0);
|
||||||
|
|
||||||
|
for (i = 0;i <= sender.len;++i)
|
||||||
|
if ((i == 0) || (i == sender.len) || (sender.s[i] == '.') || (sender.s[i] == '@'))
|
||||||
|
if (authsender = constmap(&mapauthsenders,sender.s + i,sender.len - i))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (authsender && !*authsender) authsender = 0;
|
||||||
|
|
||||||
|
if (authsender) {
|
||||||
|
i = str_chr(authsender,'|');
|
||||||
|
if (authsender[i]) {
|
||||||
|
j = str_chr(authsender + i + 1,'|');
|
||||||
|
if (authsender[j]) {
|
||||||
|
authsender[i] = 0;
|
||||||
|
authsender[i + j + 1] = 0;
|
||||||
|
if (!stralloc_copys(&user,"")) temp_nomem();
|
||||||
|
if (!stralloc_copys(&user,authsender + i + 1)) temp_nomem();
|
||||||
|
if (!stralloc_copys(&pass,"")) temp_nomem();
|
||||||
|
if (!stralloc_copys(&pass,authsender + i + j + 2)) temp_nomem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = str_chr(authsender,':');
|
||||||
|
if (authsender[i]) {
|
||||||
|
scan_ulong(authsender + i + 1,&port);
|
||||||
|
authsender[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stralloc_copys(&relayhost,authsender)) temp_nomem();
|
||||||
|
if (!stralloc_copys(&host,authsender)) temp_nomem();
|
||||||
|
|
||||||
|
}
|
||||||
|
else { /* default smtproutes -- authenticated */
|
||||||
for (i = 0;i <= host.len;++i)
|
for (i = 0;i <= host.len;++i)
|
||||||
if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
|
if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
|
||||||
if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
|
if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (relayhost && !*relayhost) relayhost = 0;
|
if (relayhost && !*relayhost) relayhost = 0;
|
||||||
|
|
||||||
if (relayhost) {
|
if (relayhost) {
|
||||||
|
i = str_chr(relayhost,'|');
|
||||||
|
if (relayhost[i]) {
|
||||||
|
j = str_chr(relayhost + i + 1,'|');
|
||||||
|
if (relayhost[j]) {
|
||||||
|
relayhost[i] = 0;
|
||||||
|
relayhost[i + j + 1] = 0;
|
||||||
|
if (!stralloc_copys(&user,"")) temp_nomem();
|
||||||
|
if (!stralloc_copys(&user,relayhost + i + 1)) temp_nomem();
|
||||||
|
if (!stralloc_copys(&pass,"")) temp_nomem();
|
||||||
|
if (!stralloc_copys(&pass,relayhost + i + j + 2)) temp_nomem();
|
||||||
|
}
|
||||||
|
}
|
||||||
i = str_chr(relayhost,':');
|
i = str_chr(relayhost,':');
|
||||||
if (relayhost[i]) {
|
if (relayhost[i]) {
|
||||||
scan_ulong(relayhost + i + 1,&port);
|
scan_ulong(relayhost + i + 1,&port);
|
||||||
|
|
@ -362,9 +603,7 @@ char **argv;
|
||||||
}
|
}
|
||||||
if (!stralloc_copys(&host,relayhost)) temp_nomem();
|
if (!stralloc_copys(&host,relayhost)) temp_nomem();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addrmangle(&sender,argv[2],&flagalias,0);
|
|
||||||
|
|
||||||
if (!saa_readyplus(&reciplist,0)) temp_nomem();
|
if (!saa_readyplus(&reciplist,0)) temp_nomem();
|
||||||
if (ipme_init() != 1) temp_oserr();
|
if (ipme_init() != 1) temp_oserr();
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ void main()
|
||||||
_exit(111);
|
_exit(111);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_lst("authsenders","No authenticated SMTP sender.","Authenicated SMTP sender: ","");
|
||||||
do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
|
do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
|
||||||
do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
|
do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
|
||||||
do_str("bouncehost",1,"bouncehost","Bounce host name is ");
|
do_str("bouncehost",1,"bouncehost","Bounce host name is ");
|
||||||
|
|
@ -265,8 +266,7 @@ void main()
|
||||||
while (d = readdir(dir)) {
|
while (d = readdir(dir)) {
|
||||||
if (str_equal(d->d_name,".")) continue;
|
if (str_equal(d->d_name,".")) continue;
|
||||||
if (str_equal(d->d_name,"..")) continue;
|
if (str_equal(d->d_name,"..")) continue;
|
||||||
if (str_equal(d->d_name,"bouncefrom")) continue;
|
if (str_equal(d->d_name,"authsenders")) continue;
|
||||||
if (str_equal(d->d_name,"bouncehost")) continue;
|
|
||||||
if (str_equal(d->d_name,"badmailfrom")) continue;
|
if (str_equal(d->d_name,"badmailfrom")) continue;
|
||||||
if (str_equal(d->d_name,"bouncefrom")) continue;
|
if (str_equal(d->d_name,"bouncefrom")) continue;
|
||||||
if (str_equal(d->d_name,"bouncehost")) continue;
|
if (str_equal(d->d_name,"bouncehost")) continue;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,30 @@ or
|
||||||
header fields.
|
header fields.
|
||||||
|
|
||||||
.B qmail-smtpd
|
.B qmail-smtpd
|
||||||
supports ESMTP, including the 8BITMIME and PIPELINING options.
|
supports ESMTP, including the 8BITMIME, DATA, PIPELINING, SIZE, and AUTH options.
|
||||||
|
.B qmail-smtpd
|
||||||
|
includes a \'MAIL FROM:\' parameter parser and obeys \'Auth\' and \'Size\' advertisements.
|
||||||
|
.B qmail-smtpd
|
||||||
|
can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes
|
||||||
|
.IR checkprogram ,
|
||||||
|
which reads on file descriptor 3 the username, a 0 byte, the password
|
||||||
|
or CRAM-MD5 digest/response derived from the SMTP client,
|
||||||
|
another 0 byte, a CRAM-MD5 challenge (if applicable to the AUTH type),
|
||||||
|
and a final 0 byte.
|
||||||
|
.I checkprogram
|
||||||
|
invokes
|
||||||
|
.I subprogram
|
||||||
|
upon successful authentication, which should in turn return 0 to
|
||||||
|
.BR qmail-smtpd ,
|
||||||
|
effectively setting the environment variables $RELAYCLIENT and $TCPREMOTEINFO
|
||||||
|
(any supplied value replaced with the authenticated username).
|
||||||
|
.B qmail-smtpd
|
||||||
|
will reject the authentication attempt if it receives a nonzero return
|
||||||
|
value from
|
||||||
|
.I checkprogram
|
||||||
|
or
|
||||||
|
.IR subprogram .
|
||||||
|
|
||||||
.SH TRANSPARENCY
|
.SH TRANSPARENCY
|
||||||
.B qmail-smtpd
|
.B qmail-smtpd
|
||||||
converts the SMTP newline convention into the UNIX newline convention
|
converts the SMTP newline convention into the UNIX newline convention
|
||||||
|
|
@ -169,6 +192,67 @@ Number of seconds
|
||||||
.B qmail-smtpd
|
.B qmail-smtpd
|
||||||
will wait for each new buffer of data from the remote SMTP client.
|
will wait for each new buffer of data from the remote SMTP client.
|
||||||
Default: 1200.
|
Default: 1200.
|
||||||
|
|
||||||
|
.SH "ENVIRONMENT VARIABLES READ"
|
||||||
|
Environment variables may be defined globally in the
|
||||||
|
.B qmail-smtpd
|
||||||
|
startup script and/or individually as part of the
|
||||||
|
.B tcpserver's
|
||||||
|
cdb database.
|
||||||
|
The environment variables may be quoted ("variable", or 'variable') and
|
||||||
|
in case of global use, have to be exported.
|
||||||
|
.B qmail-smtpd
|
||||||
|
supports the following legacy environment variables, typically
|
||||||
|
provided by
|
||||||
|
.B tcpserver
|
||||||
|
or
|
||||||
|
.B sslserver
|
||||||
|
or
|
||||||
|
.BR tcp-env :
|
||||||
|
.IR TCPREMOTEIP ,
|
||||||
|
.IR TCPREMOTEHOST
|
||||||
|
.IR TCPREMOTEINFO
|
||||||
|
and
|
||||||
|
.IR TCPLOCALPORT
|
||||||
|
as well as
|
||||||
|
.IR RELAYCLIENT .
|
||||||
|
|
||||||
|
.B qmail-smtpd
|
||||||
|
may use the following environment variables for SMTP authentication:
|
||||||
|
.TP 5
|
||||||
|
.IR SMTPAUTH
|
||||||
|
is used to enable SMTP Authentication for the AUTH types
|
||||||
|
LOGIN and PLAIN.
|
||||||
|
In case
|
||||||
|
.TP 5
|
||||||
|
.IR SMTPAUTH='+cram'
|
||||||
|
is defined,
|
||||||
|
.B qmail-smtpd
|
||||||
|
honors LOGIN, PLAIN, and additionally CRAM-MD5 authentication.
|
||||||
|
Simply
|
||||||
|
.TP 5
|
||||||
|
.IR SMTPAUTH='cram'
|
||||||
|
restricts authentication just to CRAM-MD5.
|
||||||
|
If however
|
||||||
|
.TP 5
|
||||||
|
.IR SMTPAUTH='!'
|
||||||
|
starts with an exclamation mark, AUTH is required.
|
||||||
|
You can enforce 'Submission' using this option
|
||||||
|
and binding
|
||||||
|
.B qmail-smtpd
|
||||||
|
to the SUBMISSION port \'587'\.
|
||||||
|
In particular,
|
||||||
|
.TP 5
|
||||||
|
.IR SMTPAUTH='!cram'
|
||||||
|
may be useful.
|
||||||
|
In opposite, if
|
||||||
|
.TP 5
|
||||||
|
.IR SMTPAUTH='-'
|
||||||
|
starts with a dash, AUTH is disabled for particular
|
||||||
|
connections.
|
||||||
|
|
||||||
|
Note: The use of 'cram' requires a CRAM-MD5 enabled PAM.
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
tcp-env(1),
|
tcp-env(1),
|
||||||
tcp-environ(5),
|
tcp-environ(5),
|
||||||
|
|
|
||||||
336
qmail-smtpd.c
336
qmail-smtpd.c
|
|
@ -23,6 +23,9 @@
|
||||||
#include "timeoutread.h"
|
#include "timeoutread.h"
|
||||||
#include "timeoutwrite.h"
|
#include "timeoutwrite.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
#include "wait.h"
|
||||||
|
|
||||||
|
#define AUTHSLEEP 5
|
||||||
|
|
||||||
#define MAXHOPS 100
|
#define MAXHOPS 100
|
||||||
unsigned int databytes = 0;
|
unsigned int databytes = 0;
|
||||||
|
|
@ -49,6 +52,7 @@ void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _
|
||||||
void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
|
void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
|
||||||
void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
|
void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
|
||||||
|
|
||||||
|
void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
|
||||||
void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
|
void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
|
||||||
void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
|
void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
|
||||||
void err_unimpl(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); }
|
void err_unimpl(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); }
|
||||||
|
|
@ -59,6 +63,17 @@ void err_noop(arg) char *arg; { out("250 ok\r\n"); }
|
||||||
void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); }
|
void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); }
|
||||||
void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
|
void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
|
||||||
|
|
||||||
|
int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
|
||||||
|
int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
|
||||||
|
int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
|
||||||
|
int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
|
||||||
|
void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
|
||||||
|
void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
|
||||||
|
int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
|
||||||
|
int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; }
|
||||||
|
int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
|
||||||
|
void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
|
||||||
|
void err_submission() { out("530 Authorization required (#5.7.1) \r\n"); }
|
||||||
|
|
||||||
stralloc greeting = {0};
|
stralloc greeting = {0};
|
||||||
|
|
||||||
|
|
@ -76,11 +91,14 @@ void smtp_quit(arg) char *arg;
|
||||||
smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
|
smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *protocol;
|
||||||
char *remoteip;
|
char *remoteip;
|
||||||
char *remotehost;
|
char *remotehost;
|
||||||
char *remoteinfo;
|
char *remoteinfo;
|
||||||
char *local;
|
char *local;
|
||||||
|
char *localport;
|
||||||
char *relayclient;
|
char *relayclient;
|
||||||
|
char *auth;
|
||||||
|
|
||||||
stralloc helohost = {0};
|
stralloc helohost = {0};
|
||||||
char *fakehelo; /* pointer into helohost, or 0 */
|
char *fakehelo; /* pointer into helohost, or 0 */
|
||||||
|
|
@ -91,6 +109,7 @@ void dohelo(arg) char *arg; {
|
||||||
fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
|
fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int smtpauth = 0;
|
||||||
int liphostok = 0;
|
int liphostok = 0;
|
||||||
stralloc liphost = {0};
|
stralloc liphost = {0};
|
||||||
int bmfok = 0;
|
int bmfok = 0;
|
||||||
|
|
@ -109,7 +128,6 @@ void setup()
|
||||||
if (liphostok == -1) die_control();
|
if (liphostok == -1) die_control();
|
||||||
if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
|
if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
|
||||||
if (timeout <= 0) timeout = 1;
|
if (timeout <= 0) timeout = 1;
|
||||||
|
|
||||||
if (rcpthosts_init() == -1) die_control();
|
if (rcpthosts_init() == -1) die_control();
|
||||||
|
|
||||||
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
|
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
|
||||||
|
|
@ -122,19 +140,32 @@ void setup()
|
||||||
if (x) { scan_ulong(x,&u); databytes = u; }
|
if (x) { scan_ulong(x,&u); databytes = u; }
|
||||||
if (!(databytes + 1)) --databytes;
|
if (!(databytes + 1)) --databytes;
|
||||||
|
|
||||||
|
protocol = "SMTP";
|
||||||
remoteip = env_get("TCPREMOTEIP");
|
remoteip = env_get("TCPREMOTEIP");
|
||||||
if (!remoteip) remoteip = "unknown";
|
if (!remoteip) remoteip = "unknown";
|
||||||
local = env_get("TCPLOCALHOST");
|
local = env_get("TCPLOCALHOST");
|
||||||
if (!local) local = env_get("TCPLOCALIP");
|
if (!local) local = env_get("TCPLOCALIP");
|
||||||
if (!local) local = "unknown";
|
if (!local) local = "unknown";
|
||||||
|
localport = env_get("TCPLOCALPORT");
|
||||||
|
if (!localport) localport = "0";
|
||||||
remotehost = env_get("TCPREMOTEHOST");
|
remotehost = env_get("TCPREMOTEHOST");
|
||||||
if (!remotehost) remotehost = "unknown";
|
if (!remotehost) remotehost = "unknown";
|
||||||
remoteinfo = env_get("TCPREMOTEINFO");
|
remoteinfo = env_get("TCPREMOTEINFO");
|
||||||
relayclient = env_get("RELAYCLIENT");
|
relayclient = env_get("RELAYCLIENT");
|
||||||
|
auth = env_get("SMTPAUTH");
|
||||||
|
if (auth) {
|
||||||
|
smtpauth = 1;
|
||||||
|
case_lowers(auth);
|
||||||
|
if (!case_diffs(auth,"-")) smtpauth = 0;
|
||||||
|
if (!case_diffs(auth,"!")) smtpauth = 11;
|
||||||
|
if (case_starts(auth,"cram")) smtpauth = 2;
|
||||||
|
if (case_starts(auth,"+cram")) smtpauth = 3;
|
||||||
|
if (case_starts(auth,"!cram")) smtpauth = 12;
|
||||||
|
if (case_starts(auth,"!+cram")) smtpauth = 13;
|
||||||
|
}
|
||||||
dohelo(remotehost);
|
dohelo(remotehost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
|
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
|
||||||
|
|
||||||
int addrparse(arg)
|
int addrparse(arg)
|
||||||
|
|
@ -216,11 +247,72 @@ int addrallowed()
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *auth;
|
||||||
|
int seenauth = 0;
|
||||||
int seenmail = 0;
|
int seenmail = 0;
|
||||||
int flagbarf; /* defined if seenmail */
|
int flagbarf; /* defined if seenmail */
|
||||||
|
int flagsize;
|
||||||
stralloc mailfrom = {0};
|
stralloc mailfrom = {0};
|
||||||
stralloc rcptto = {0};
|
stralloc rcptto = {0};
|
||||||
|
stralloc fuser = {0};
|
||||||
|
stralloc mfparms = {0};
|
||||||
|
|
||||||
|
int mailfrom_size(arg) char *arg;
|
||||||
|
{
|
||||||
|
long r;
|
||||||
|
unsigned long sizebytes = 0;
|
||||||
|
|
||||||
|
scan_ulong(arg,&r);
|
||||||
|
sizebytes = r;
|
||||||
|
if (databytes) if (sizebytes > databytes) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mailfrom_auth(arg,len)
|
||||||
|
char *arg;
|
||||||
|
int len;
|
||||||
|
{
|
||||||
|
if (!stralloc_copys(&fuser,"")) die_nomem();
|
||||||
|
if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
|
||||||
|
else
|
||||||
|
while (len) {
|
||||||
|
if (*arg == '+') {
|
||||||
|
if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
|
||||||
|
if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!stralloc_catb(&fuser,arg,1)) die_nomem();
|
||||||
|
arg++; len--;
|
||||||
|
}
|
||||||
|
if(!stralloc_0(&fuser)) die_nomem();
|
||||||
|
if (!remoteinfo) {
|
||||||
|
remoteinfo = fuser.s;
|
||||||
|
if (!env_unset("TCPREMOTEINFO")) die_read();
|
||||||
|
if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mailfrom_parms(arg) char *arg;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = str_len(arg);
|
||||||
|
if (!stralloc_copys(&mfparms,"")) die_nomem();
|
||||||
|
i = byte_chr(arg,len,'>');
|
||||||
|
if (i > 4 && i < len) {
|
||||||
|
while (len) {
|
||||||
|
arg++; len--;
|
||||||
|
if (*arg == ' ' || *arg == '\0' ) {
|
||||||
|
if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
|
||||||
|
if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);
|
||||||
|
if (!stralloc_copys(&mfparms,"")) die_nomem();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!stralloc_catb(&mfparms,arg,1)) die_nomem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void smtp_helo(arg) char *arg;
|
void smtp_helo(arg) char *arg;
|
||||||
{
|
{
|
||||||
|
|
@ -229,17 +321,30 @@ void smtp_helo(arg) char *arg;
|
||||||
}
|
}
|
||||||
void smtp_ehlo(arg) char *arg;
|
void smtp_ehlo(arg) char *arg;
|
||||||
{
|
{
|
||||||
smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
|
char size[FMT_ULONG];
|
||||||
|
size[fmt_ulong(size,(unsigned int) databytes)] = 0;
|
||||||
|
smtp_greet("250-");
|
||||||
|
out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
|
||||||
|
if (smtpauth == 1 || smtpauth == 11) out("250-AUTH LOGIN PLAIN\r\n");
|
||||||
|
if (smtpauth == 2 || smtpauth == 12) out("250-AUTH CRAM-MD5\r\n");
|
||||||
|
if (smtpauth == 3 || smtpauth == 13) out("250-AUTH LOGIN PLAIN CRAM-MD5\r\n");
|
||||||
|
out("250 SIZE "); out(size); out("\r\n");
|
||||||
seenmail = 0; dohelo(arg);
|
seenmail = 0; dohelo(arg);
|
||||||
}
|
}
|
||||||
void smtp_rset(arg) char *arg;
|
void smtp_rset(arg) char *arg;
|
||||||
{
|
{
|
||||||
seenmail = 0;
|
seenmail = 0; seenauth = 0;
|
||||||
|
mailfrom.len = 0; rcptto.len = 0;
|
||||||
out("250 flushed\r\n");
|
out("250 flushed\r\n");
|
||||||
}
|
}
|
||||||
void smtp_mail(arg) char *arg;
|
void smtp_mail(arg) char *arg;
|
||||||
{
|
{
|
||||||
|
if (smtpauth)
|
||||||
|
if (smtpauth > 10 && !seenauth) { err_submission(); return; }
|
||||||
if (!addrparse(arg)) { err_syntax(); return; }
|
if (!addrparse(arg)) { err_syntax(); return; }
|
||||||
|
flagsize = 0;
|
||||||
|
mailfrom_parms(arg);
|
||||||
|
if (flagsize) { err_size(); return; }
|
||||||
flagbarf = bmfcheck();
|
flagbarf = bmfcheck();
|
||||||
seenmail = 1;
|
seenmail = 1;
|
||||||
if (!stralloc_copys(&rcptto,"")) die_nomem();
|
if (!stralloc_copys(&rcptto,"")) die_nomem();
|
||||||
|
|
@ -378,7 +483,7 @@ void smtp_data(arg) char *arg; {
|
||||||
qp = qmail_qp(&qqt);
|
qp = qmail_qp(&qqt);
|
||||||
out("354 go ahead\r\n");
|
out("354 go ahead\r\n");
|
||||||
|
|
||||||
received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
|
received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
|
||||||
blast(&hops);
|
blast(&hops);
|
||||||
hops = (hops >= MAXHOPS);
|
hops = (hops >= MAXHOPS);
|
||||||
if (hops) qmail_fail(&qqt);
|
if (hops) qmail_fail(&qqt);
|
||||||
|
|
@ -388,16 +493,228 @@ void smtp_data(arg) char *arg; {
|
||||||
qqx = qmail_close(&qqt);
|
qqx = qmail_close(&qqt);
|
||||||
if (!*qqx) { acceptmessage(qp); return; }
|
if (!*qqx) { acceptmessage(qp); return; }
|
||||||
if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
|
if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
|
||||||
if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
|
if (databytes) if (!bytestooverflow) { err_size(); return; }
|
||||||
if (*qqx == 'D') out("554 "); else out("451 ");
|
if (*qqx == 'D') out("554 "); else out("451 ");
|
||||||
out(qqx + 1);
|
out(qqx + 1);
|
||||||
out("\r\n");
|
out("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this file is too long ----------------------------------------- SMTP AUTH */
|
||||||
|
|
||||||
|
char unique[FMT_ULONG + FMT_ULONG + 3];
|
||||||
|
static stralloc authin = {0}; /* input from SMTP client */
|
||||||
|
static stralloc user = {0}; /* authorization user-id */
|
||||||
|
static stralloc pass = {0}; /* plain passwd or digest */
|
||||||
|
static stralloc resp = {0}; /* b64 response */
|
||||||
|
static stralloc chal = {0}; /* plain challenge */
|
||||||
|
static stralloc slop = {0}; /* b64 challenge */
|
||||||
|
|
||||||
|
char **childargs;
|
||||||
|
char ssauthbuf[512];
|
||||||
|
substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
|
||||||
|
|
||||||
|
int authgetl(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!stralloc_copys(&authin,"")) die_nomem();
|
||||||
|
for (;;) {
|
||||||
|
if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
|
||||||
|
i = substdio_get(&ssin,authin.s + authin.len,1);
|
||||||
|
if (i != 1) die_read();
|
||||||
|
if (authin.s[authin.len] == '\n') break;
|
||||||
|
++authin.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
|
||||||
|
authin.s[authin.len] = 0;
|
||||||
|
if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
|
||||||
|
if (authin.len == 0) { return err_input(); }
|
||||||
|
return authin.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int authenticate(void)
|
||||||
|
{
|
||||||
|
int child;
|
||||||
|
int wstat;
|
||||||
|
int pi[2];
|
||||||
|
|
||||||
|
if (!stralloc_0(&user)) die_nomem();
|
||||||
|
if (!stralloc_0(&pass)) die_nomem();
|
||||||
|
if (!stralloc_0(&chal)) die_nomem();
|
||||||
|
|
||||||
|
if (pipe(pi) == -1) return err_pipe();
|
||||||
|
switch(child = fork()) {
|
||||||
|
case -1:
|
||||||
|
return err_fork();
|
||||||
|
case 0:
|
||||||
|
close(pi[1]);
|
||||||
|
if(fd_copy(3,pi[0]) == -1) return err_pipe();
|
||||||
|
sig_pipedefault();
|
||||||
|
execvp(*childargs, childargs);
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
close(pi[0]);
|
||||||
|
|
||||||
|
substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
|
||||||
|
if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
|
||||||
|
if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
|
||||||
|
if (smtpauth == 2 || smtpauth == 3 || smtpauth == 12 || smtpauth == 13)
|
||||||
|
if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
|
||||||
|
if (substdio_flush(&ssauth) == -1) return err_write();
|
||||||
|
|
||||||
|
close(pi[1]);
|
||||||
|
if (!stralloc_copys(&chal,"")) die_nomem();
|
||||||
|
if (!stralloc_copys(&slop,"")) die_nomem();
|
||||||
|
byte_zero(ssauthbuf,sizeof ssauthbuf);
|
||||||
|
if (wait_pid(&wstat,child) == -1) return err_child();
|
||||||
|
if (wait_crashed(wstat)) return err_child();
|
||||||
|
if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */
|
||||||
|
return 0; /* yes */
|
||||||
|
}
|
||||||
|
|
||||||
|
int auth_login(arg) char *arg;
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (*arg) {
|
||||||
|
if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
|
||||||
|
if (authgetl() < 0) return -1;
|
||||||
|
if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
|
||||||
|
}
|
||||||
|
if (r == -1) die_nomem();
|
||||||
|
|
||||||
|
out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
|
||||||
|
|
||||||
|
if (authgetl() < 0) return -1;
|
||||||
|
if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
|
||||||
|
if (r == -1) die_nomem();
|
||||||
|
|
||||||
|
if (!user.len || !pass.len) return err_input();
|
||||||
|
return authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int auth_plain(arg) char *arg;
|
||||||
|
{
|
||||||
|
int r, id = 0;
|
||||||
|
|
||||||
|
if (*arg) {
|
||||||
|
if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out("334 \r\n"); flush();
|
||||||
|
if (authgetl() < 0) return -1;
|
||||||
|
if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
|
||||||
|
}
|
||||||
|
if (r == -1 || !stralloc_0(&resp)) die_nomem();
|
||||||
|
while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */
|
||||||
|
|
||||||
|
if (resp.len > id + 1)
|
||||||
|
if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
|
||||||
|
if (resp.len > id + user.len + 2)
|
||||||
|
if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
|
||||||
|
|
||||||
|
if (!user.len || !pass.len) return err_input();
|
||||||
|
return authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int auth_cram()
|
||||||
|
{
|
||||||
|
int i, r;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = unique; /* generate challenge */
|
||||||
|
s += fmt_uint(s,getpid());
|
||||||
|
*s++ = '.';
|
||||||
|
s += fmt_ulong(s,(unsigned long) now());
|
||||||
|
*s++ = '@';
|
||||||
|
*s++ = 0;
|
||||||
|
if (!stralloc_copys(&chal,"<")) die_nomem();
|
||||||
|
if (!stralloc_cats(&chal,unique)) die_nomem();
|
||||||
|
if (!stralloc_cats(&chal,local)) die_nomem();
|
||||||
|
if (!stralloc_cats(&chal,">")) die_nomem();
|
||||||
|
if (b64encode(&chal,&slop) < 0) die_nomem();
|
||||||
|
if (!stralloc_0(&slop)) die_nomem();
|
||||||
|
|
||||||
|
out("334 "); /* "334 base64_challenge \r\n" */
|
||||||
|
out(slop.s);
|
||||||
|
out("\r\n");
|
||||||
|
flush();
|
||||||
|
|
||||||
|
if (authgetl() < 0) return -1; /* got response */
|
||||||
|
if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
|
||||||
|
if (r == -1 || !stralloc_0(&resp)) die_nomem();
|
||||||
|
|
||||||
|
i = str_rchr(resp.s,' ');
|
||||||
|
s = resp.s + i;
|
||||||
|
while (*s == ' ') ++s;
|
||||||
|
resp.s[i] = 0;
|
||||||
|
if (!stralloc_copys(&user,resp.s)) die_nomem(); /* userid */
|
||||||
|
if (!stralloc_copys(&pass,s)) die_nomem(); /* digest */
|
||||||
|
|
||||||
|
if (!user.len || !pass.len) return err_input();
|
||||||
|
return authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct authcmd {
|
||||||
|
char *text;
|
||||||
|
int (*fun)();
|
||||||
|
} authcmds[] = {
|
||||||
|
{ "login",auth_login }
|
||||||
|
, { "plain",auth_plain }
|
||||||
|
, { "cram-md5",auth_cram }
|
||||||
|
, { 0,err_noauth }
|
||||||
|
};
|
||||||
|
|
||||||
|
void smtp_auth(arg)
|
||||||
|
char *arg;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *cmd = arg;
|
||||||
|
|
||||||
|
if (!smtpauth || !*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
|
||||||
|
if (seenauth) { err_authd(); return; }
|
||||||
|
if (seenmail) { err_authmail(); return; }
|
||||||
|
|
||||||
|
if (!stralloc_copys(&user,"")) die_nomem();
|
||||||
|
if (!stralloc_copys(&pass,"")) die_nomem();
|
||||||
|
if (!stralloc_copys(&resp,"")) die_nomem();
|
||||||
|
if (!stralloc_copys(&chal,"")) die_nomem();
|
||||||
|
|
||||||
|
i = str_chr(cmd,' ');
|
||||||
|
arg = cmd + i;
|
||||||
|
while (*arg == ' ') ++arg;
|
||||||
|
cmd[i] = 0;
|
||||||
|
|
||||||
|
for (i = 0;authcmds[i].text;++i)
|
||||||
|
if (case_equals(authcmds[i].text,cmd)) break;
|
||||||
|
|
||||||
|
switch (authcmds[i].fun(arg)) {
|
||||||
|
case 0:
|
||||||
|
seenauth = 1;
|
||||||
|
protocol = "ESMTPA";
|
||||||
|
relayclient = "";
|
||||||
|
remoteinfo = user.s;
|
||||||
|
if (!env_unset("TCPREMOTEINFO")) die_read();
|
||||||
|
if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
|
||||||
|
if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
|
||||||
|
out("235 ok, go ahead (#2.0.0)\r\n");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
err_authfail(user.s,authcmds[i].text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* this file is too long --------------------------------------------- GO ON */
|
||||||
|
|
||||||
struct commands smtpcommands[] = {
|
struct commands smtpcommands[] = {
|
||||||
{ "rcpt", smtp_rcpt, 0 }
|
{ "rcpt", smtp_rcpt, 0 }
|
||||||
, { "mail", smtp_mail, 0 }
|
, { "mail", smtp_mail, 0 }
|
||||||
, { "data", smtp_data, flush }
|
, { "data", smtp_data, flush }
|
||||||
|
, { "auth", smtp_auth, flush }
|
||||||
, { "quit", smtp_quit, flush }
|
, { "quit", smtp_quit, flush }
|
||||||
, { "helo", smtp_helo, flush }
|
, { "helo", smtp_helo, flush }
|
||||||
, { "ehlo", smtp_ehlo, flush }
|
, { "ehlo", smtp_ehlo, flush }
|
||||||
|
|
@ -408,8 +725,11 @@ struct commands smtpcommands[] = {
|
||||||
, { 0, err_unimpl, flush }
|
, { 0, err_unimpl, flush }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
void main()
|
void main(argc,argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
{
|
{
|
||||||
|
childargs = argv + 1;
|
||||||
sig_pipeignore();
|
sig_pipeignore();
|
||||||
if (chdir(auto_qmail) == -1) die_control();
|
if (chdir(auto_qmail) == -1) die_control();
|
||||||
setup();
|
setup();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue