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.
|
||||
|
||||
25
Makefile
25
Makefile
|
|
@ -136,6 +136,18 @@ auto_usera.o: \
|
|||
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.sh conf-qmail
|
||||
cat binm1.sh \
|
||||
|
|
@ -1441,12 +1453,15 @@ qmail-remote: \
|
|||
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 \
|
||||
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 \
|
||||
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 \
|
||||
lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
|
||||
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
||||
base64.o md5c.o hmac_md5.o \
|
||||
str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
|
||||
|
||||
qmail-remote.0: \
|
||||
qmail-remote.8
|
||||
|
|
@ -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 \
|
||||
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 \
|
||||
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 \
|
||||
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 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`
|
||||
|
||||
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 \
|
||||
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 \
|
||||
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
|
||||
|
||||
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
|
||||
quote.o
|
||||
now.o
|
||||
base64.o
|
||||
gfrom.o
|
||||
myctime.o
|
||||
slurpclose.o
|
||||
|
|
@ -182,6 +183,8 @@ dns.lib
|
|||
qmail-remote
|
||||
qmail-rspawn.o
|
||||
tcpto_clean.o
|
||||
md5c.o
|
||||
hmac_md5.o
|
||||
qmail-rspawn
|
||||
direntry.h
|
||||
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
|
||||
control default used by
|
||||
|
||||
.I authsender \fR(none) \fRqmail-remote
|
||||
.I badmailfrom \fR(none) \fRqmail-smtpd
|
||||
.I bouncefrom \fRMAILER-DAEMON \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
|
||||
.B getopt
|
||||
standard.
|
||||
|
||||
.SH TRANSPARENCY
|
||||
End-of-file in SMTP is encoded as dot CR LF.
|
||||
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
|
||||
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
|
||||
.BR qmail-remote 's
|
||||
.I recip
|
||||
|
|
@ -114,6 +182,51 @@ arguments.
|
|||
always exits zero.
|
||||
.SH "CONTROL FILES"
|
||||
.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
|
||||
Current host name,
|
||||
for use solely in saying hello to the remote SMTP server.
|
||||
|
|
@ -128,7 +241,9 @@ refuses to run.
|
|||
Artificial SMTP routes.
|
||||
Each route has the form
|
||||
.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
|
||||
.I domain
|
||||
matches
|
||||
|
|
@ -149,6 +264,7 @@ normal SMTP port, 25:
|
|||
|
||||
.EX
|
||||
inside.af.mil:firewall.af.mil:26
|
||||
:submission.myrelay.com:587|myuserid|mypasswd
|
||||
.EE
|
||||
|
||||
.I relay
|
||||
|
|
@ -182,6 +298,10 @@ However,
|
|||
you are always safe using
|
||||
.I smtproutes
|
||||
if you do not accept mail from the network.
|
||||
Note:
|
||||
.I authsender
|
||||
routes have precedence over
|
||||
.IR smtproutes .
|
||||
.TP 5
|
||||
.I timeoutconnect
|
||||
Number of seconds
|
||||
|
|
|
|||
289
qmail-remote.c
289
qmail-remote.c
|
|
@ -28,6 +28,7 @@
|
|||
#include "timeoutconn.h"
|
||||
#include "timeoutread.h"
|
||||
#include "timeoutwrite.h"
|
||||
#include "base64.h"
|
||||
|
||||
#define HUGESMTPTEXT 5000
|
||||
|
||||
|
|
@ -44,6 +45,16 @@ struct constmap maproutes;
|
|||
stralloc host = {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};
|
||||
|
||||
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");
|
||||
zerodie(); }
|
||||
|
||||
void err_authprot() {
|
||||
out("Kno supported AUTH method found, continuing without authentication.\n");
|
||||
zero();
|
||||
substdio_flush(subfdoutsmall);
|
||||
}
|
||||
|
||||
void outhost()
|
||||
{
|
||||
char x[IPFMT];
|
||||
|
|
@ -216,24 +233,192 @@ void blast()
|
|||
|
||||
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()
|
||||
{
|
||||
unsigned long code;
|
||||
int flagbother;
|
||||
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,"HELO ");
|
||||
substdio_puts(&smtpto,"EHLO ");
|
||||
substdio_put(&smtpto,helohost.s,helohost.len);
|
||||
substdio_puts(&smtpto,"\r\n");
|
||||
substdio_flush(&smtpto);
|
||||
if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
|
||||
|
||||
substdio_puts(&smtpto,"MAIL FROM:<");
|
||||
substdio_put(&smtpto,sender.s,sender.len);
|
||||
substdio_puts(&smtpto,">\r\n");
|
||||
substdio_flush(&smtpto);
|
||||
if (smtpcode() != 250) {
|
||||
substdio_puts(&smtpto,"HELO ");
|
||||
substdio_put(&smtpto,helohost.s,helohost.len);
|
||||
substdio_puts(&smtpto,"\r\n");
|
||||
substdio_flush(&smtpto);
|
||||
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();
|
||||
|
||||
code = smtpcode();
|
||||
if (code >= 500) quit("DConnected to "," but sender was rejected");
|
||||
if (code >= 400) quit("ZConnected to "," but sender was rejected");
|
||||
|
|
@ -324,14 +509,23 @@ void getcontrols()
|
|||
case 1:
|
||||
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;
|
||||
char **argv;
|
||||
{
|
||||
static ipalloc ip = {0};
|
||||
int i;
|
||||
int i, j;
|
||||
unsigned long random;
|
||||
char **recips;
|
||||
unsigned long prefme;
|
||||
|
|
@ -344,28 +538,73 @@ char **argv;
|
|||
if (chdir(auto_qmail) == -1) temp_chdir();
|
||||
getcontrols();
|
||||
|
||||
|
||||
if (!stralloc_copys(&host,argv[1])) temp_nomem();
|
||||
|
||||
authsender = 0;
|
||||
relayhost = 0;
|
||||
for (i = 0;i <= host.len;++i)
|
||||
if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
|
||||
if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
|
||||
break;
|
||||
if (relayhost && !*relayhost) relayhost = 0;
|
||||
|
||||
if (relayhost) {
|
||||
i = str_chr(relayhost,':');
|
||||
if (relayhost[i]) {
|
||||
scan_ulong(relayhost + i + 1,&port);
|
||||
relayhost[i] = 0;
|
||||
}
|
||||
if (!stralloc_copys(&host,relayhost)) temp_nomem();
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
|
||||
if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
|
||||
break;
|
||||
|
||||
if (relayhost && !*relayhost) relayhost = 0;
|
||||
|
||||
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,':');
|
||||
if (relayhost[i]) {
|
||||
scan_ulong(relayhost + i + 1,&port);
|
||||
relayhost[i] = 0;
|
||||
}
|
||||
if (!stralloc_copys(&host,relayhost)) temp_nomem();
|
||||
}
|
||||
}
|
||||
|
||||
if (!saa_readyplus(&reciplist,0)) temp_nomem();
|
||||
if (ipme_init() != 1) temp_oserr();
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ void main()
|
|||
_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_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
|
||||
do_str("bouncehost",1,"bouncehost","Bounce host name is ");
|
||||
|
|
@ -265,8 +266,7 @@ void main()
|
|||
while (d = readdir(dir)) {
|
||||
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,"bouncehost")) continue;
|
||||
if (str_equal(d->d_name,"authsenders")) continue;
|
||||
if (str_equal(d->d_name,"badmailfrom")) continue;
|
||||
if (str_equal(d->d_name,"bouncefrom")) continue;
|
||||
if (str_equal(d->d_name,"bouncehost")) continue;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,30 @@ or
|
|||
header fields.
|
||||
|
||||
.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
|
||||
.B qmail-smtpd
|
||||
converts the SMTP newline convention into the UNIX newline convention
|
||||
|
|
@ -169,6 +192,67 @@ Number of seconds
|
|||
.B qmail-smtpd
|
||||
will wait for each new buffer of data from the remote SMTP client.
|
||||
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"
|
||||
tcp-env(1),
|
||||
tcp-environ(5),
|
||||
|
|
|
|||
336
qmail-smtpd.c
336
qmail-smtpd.c
|
|
@ -23,6 +23,9 @@
|
|||
#include "timeoutread.h"
|
||||
#include "timeoutwrite.h"
|
||||
#include "commands.h"
|
||||
#include "wait.h"
|
||||
|
||||
#define AUTHSLEEP 5
|
||||
|
||||
#define MAXHOPS 100
|
||||
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 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_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"); }
|
||||
|
|
@ -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_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};
|
||||
|
||||
|
|
@ -76,11 +91,14 @@ void smtp_quit(arg) char *arg;
|
|||
smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
|
||||
}
|
||||
|
||||
char *protocol;
|
||||
char *remoteip;
|
||||
char *remotehost;
|
||||
char *remoteinfo;
|
||||
char *local;
|
||||
char *localport;
|
||||
char *relayclient;
|
||||
char *auth;
|
||||
|
||||
stralloc helohost = {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;
|
||||
}
|
||||
|
||||
int smtpauth = 0;
|
||||
int liphostok = 0;
|
||||
stralloc liphost = {0};
|
||||
int bmfok = 0;
|
||||
|
|
@ -109,7 +128,6 @@ void setup()
|
|||
if (liphostok == -1) die_control();
|
||||
if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
|
||||
if (timeout <= 0) timeout = 1;
|
||||
|
||||
if (rcpthosts_init() == -1) die_control();
|
||||
|
||||
bmfok = control_readfile(&bmf,"control/badmailfrom",0);
|
||||
|
|
@ -122,19 +140,32 @@ void setup()
|
|||
if (x) { scan_ulong(x,&u); databytes = u; }
|
||||
if (!(databytes + 1)) --databytes;
|
||||
|
||||
protocol = "SMTP";
|
||||
remoteip = env_get("TCPREMOTEIP");
|
||||
if (!remoteip) remoteip = "unknown";
|
||||
local = env_get("TCPLOCALHOST");
|
||||
if (!local) local = env_get("TCPLOCALIP");
|
||||
if (!local) local = "unknown";
|
||||
localport = env_get("TCPLOCALPORT");
|
||||
if (!localport) localport = "0";
|
||||
remotehost = env_get("TCPREMOTEHOST");
|
||||
if (!remotehost) remotehost = "unknown";
|
||||
remoteinfo = env_get("TCPREMOTEINFO");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
|
||||
|
||||
int addrparse(arg)
|
||||
|
|
@ -216,11 +247,72 @@ int addrallowed()
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
char *auth;
|
||||
int seenauth = 0;
|
||||
int seenmail = 0;
|
||||
int flagbarf; /* defined if seenmail */
|
||||
int flagsize;
|
||||
stralloc mailfrom = {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;
|
||||
{
|
||||
|
|
@ -229,17 +321,30 @@ void smtp_helo(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);
|
||||
}
|
||||
void smtp_rset(arg) char *arg;
|
||||
{
|
||||
seenmail = 0;
|
||||
seenmail = 0; seenauth = 0;
|
||||
mailfrom.len = 0; rcptto.len = 0;
|
||||
out("250 flushed\r\n");
|
||||
}
|
||||
void smtp_mail(arg) char *arg;
|
||||
{
|
||||
if (smtpauth)
|
||||
if (smtpauth > 10 && !seenauth) { err_submission(); return; }
|
||||
if (!addrparse(arg)) { err_syntax(); return; }
|
||||
flagsize = 0;
|
||||
mailfrom_parms(arg);
|
||||
if (flagsize) { err_size(); return; }
|
||||
flagbarf = bmfcheck();
|
||||
seenmail = 1;
|
||||
if (!stralloc_copys(&rcptto,"")) die_nomem();
|
||||
|
|
@ -378,7 +483,7 @@ void smtp_data(arg) char *arg; {
|
|||
qp = qmail_qp(&qqt);
|
||||
out("354 go ahead\r\n");
|
||||
|
||||
received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
|
||||
received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
|
||||
blast(&hops);
|
||||
hops = (hops >= MAXHOPS);
|
||||
if (hops) qmail_fail(&qqt);
|
||||
|
|
@ -388,16 +493,228 @@ void smtp_data(arg) char *arg; {
|
|||
qqx = qmail_close(&qqt);
|
||||
if (!*qqx) { acceptmessage(qp); 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 ");
|
||||
out(qqx + 1);
|
||||
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[] = {
|
||||
{ "rcpt", smtp_rcpt, 0 }
|
||||
, { "mail", smtp_mail, 0 }
|
||||
, { "data", smtp_data, flush }
|
||||
, { "auth", smtp_auth, flush }
|
||||
, { "quit", smtp_quit, flush }
|
||||
, { "helo", smtp_helo, flush }
|
||||
, { "ehlo", smtp_ehlo, flush }
|
||||
|
|
@ -408,8 +725,11 @@ struct commands smtpcommands[] = {
|
|||
, { 0, err_unimpl, flush }
|
||||
} ;
|
||||
|
||||
void main()
|
||||
void main(argc,argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
childargs = argv + 1;
|
||||
sig_pipeignore();
|
||||
if (chdir(auto_qmail) == -1) die_control();
|
||||
setup();
|
||||
|
|
|
|||
Loading…
Reference in a new issue