diff -uNr stock-20030801/Makefile smtpauth-20030801/Makefile
--- stock-20030801/Makefile	Mon Aug  4 16:42:57 2003
+++ smtpauth-20030801/Makefile	Mon Aug  4 17:21:30 2003
@@ -19,6 +19,13 @@
 # -DSMTPEXECCHECK to enable smtp DOS/Windows executable detection
 #LDAPFLAGS=-DQLDAP_CLUSTER -DEXTERNAL_TODO -DDASH_EXT -DDATA_COMPRESS
 
+
+# SMTP Authentication
+# Comment out the next three lines if you do NOT want SMTP Authentication
+SMTPAUTH=-DUSE_SMTPAUTH -DUSE_OLD_GREETING -DUSE_NEW_GREETING
+SMTPAUTHOBJS=base64.o
+SMTPAUTHINCLUDES=base64.h
+
 # Perhaps you have different ldap libraries, change them here
 LDAPLIBS=-L/usr/local/lib -lldap -llber
 # and change the location of the include files here
@@ -89,7 +96,7 @@
 default: it qldap
 
 qldap: qmail-quotawarn qmail-reply auth_pop auth_imap digest qmail-ldaplookup \
-pbsadd pbscheck pbsdbd qmail-todo
+pbsadd pbscheck pbsdbd qmail-todo auth_smtp
 
 addresses.0: \
 addresses.5
@@ -431,6 +438,14 @@
 	./compile $(LDAPFLAGS) $(SHADOWOPTS) $(LDAPINCLUDES) $(DEBUG) \
 	checkpassword.c
 
+checkpassword_smtp.o: \
+compile checkpassword_smtp.c qmail-ldap.h stralloc.h auth_mod.h qldap-ldaplib.h \
+qldap-errno.h readwrite.h error.h str.h open.h substdio.h getln.h select.h \
+digest_md4.h digest_md5.h digest_rmd160.h digest_sha1.h dns.h \
+ipalloc.h timeoutconn.h byte.h scan.h fmt.h alloc.h qldap-debug.h
+	./compile $(LDAPFLAGS) $(SHADOWOPTS) $(LDAPINCLUDES) $(DEBUG) checkpassword_smtp.c
+
+
 chkshsgr: \
 load chkshsgr.o
 	./load chkshsgr 
@@ -1856,13 +1871,13 @@
 timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
 date822fmt.o now.o qmail.o execcheck.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 dns.lib socket.lib
+error.a str.a fs.a auto_qmail.o dns.lib socket.lib ${SMTPAUTHOBJS}
 	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o rbl.o \
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
 	received.o date822fmt.o now.o qmail.o execcheck.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 fs.a auto_qmail.o dns.o str.a \
-	`cat dns.lib` `cat socket.lib` $(TLSLIBS) $(ZLIB)
+	${SMTPAUTHOBJS} `cat dns.lib` `cat socket.lib` $(TLSLIBS) $(ZLIB)
 
 qmail-smtpd.0: \
 qmail-smtpd.8
@@ -1875,7 +1890,7 @@
 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 rbl.h
 	./compile $(LDAPFLAGS) $(TLS) $(TLSINCLUDES) $(ZINCLUDES) \
-	qmail-smtpd.c
+	$(SMTPAUTH) qmail-smtpd.c
 
 qmail-start: \
 load qmail-start.o prot.o fd.a auto_uids.o
@@ -2499,3 +2514,25 @@
 backup: \
 clean
 	tar cf $(BACKUPPATH) .
+
+
+
+auth_smtp.o: \
+compile auth_smtp.c error.h qldap-errno.h readwrite.h stralloc.h env.h \
+str.h timeoutread.h auth_mod.h qldap-mdm.h exit.h fmt.h sig.h wait.h \
+scan.h alloc.h
+	./compile $(LDAPFLAGS) $(HDIRMAKE) $(DEBUG) auth_smtp.c
+
+auth_smtp: \
+load auth_smtp.o checkpassword_smtp.o check.o control.o getln.a qldap-debug.o \
+fs.a open.a stralloc.a alloc.a substdio.a error.a env.a auto_qmail.o \
+str.a base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \
+dns.o timeoutconn.o ndelay.a ipalloc.o dns.lib socket.lib qldap-ldaplib.o \
+timeoutread.o qldap-mdm.o wait.a prot.o qldap-errno.o output.o constmap.o case.a
+	./load auth_smtp checkpassword_smtp.o check.o control.o qldap-ldaplib.o \
+	qldap-debug.o output.o auto_qmail.o dns.o timeoutconn.o timeoutread.o \
+	ip.o base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \
+	ipalloc.o constmap.o case.a getln.a open.a env.a stralloc.a alloc.a \
+	substdio.a str.a qldap-mdm.o wait.a qldap-errno.o error.a fs.a \
+	ndelay.a prot.o \
+	$(LDAPLIBS) $(SHADOWLIBS) `cat dns.lib` `cat socket.lib`
diff -uNr stock-20030801/TARGETS smtpauth-20030801/TARGETS
--- stock-20030801/TARGETS	Mon Aug  4 16:42:57 2003
+++ smtpauth-20030801/TARGETS	Mon Aug  4 16:45:14 2003
@@ -393,6 +393,7 @@
 digest_sha1.o
 checkpassword
 checkpassword.o
+checkpassword_smtp.o
 digest
 digest.o
 endian
@@ -404,11 +405,13 @@
 maildir++.o
 auth_imap.o
 auth_pop.o
+auth_smtp.o
 qldap-debug.o
 qldap-ldaplib.o
 qldap-mdm.o
 auth_imap
 auth_pop
+auth_smtp
 qldap-errno.o
 qmail-ldaplookup.o
 qmail-ldaplookup
diff -uNr stock-20030801/auth_smtp.c smtpauth-20030801/auth_smtp.c
--- stock-20030801/auth_smtp.c	Thu Jan  1 01:00:00 1970
+++ smtpauth-20030801/auth_smtp.c	Mon Aug  4 16:45:14 2003
@@ -0,0 +1,145 @@
+/* auth_smtp.c, Henning Brauer <lists-qmailldap@bsws.de> */
+#include <errno.h>
+#include "error.h"
+#include "qldap-errno.h"
+#include "readwrite.h"
+#include "stralloc.h"
+#include "env.h"
+#include "str.h"
+#include "exit.h"
+#include "timeoutread.h"
+#include "prot.h"
+#include "auth_mod.h"
+#include "qmail-ldap.h"
+#include "qldap-debug.h"
+
+unsigned int auth_port;
+
+
+void auth_init(int argc, char **argv, stralloc *login, stralloc *authdata)
+/* this function should return the 0-terminated string login and authdata */
+{
+#define UP_LEN 513
+	char up[UP_LEN];
+	char *l;
+	char *p;
+	int  uplen;
+	int  i;
+
+	uplen = 0;
+	for (;;)
+	{
+		do i = read(3,up + uplen,sizeof(up) - uplen);
+		while ((i == -1) && (errno == EINTR));
+		if (i == -1) {
+			qldap_errno = ERRNO;
+			auth_error();
+		}
+		if (i == 0) break;
+		uplen += i;
+		if (uplen >= sizeof(up)) {
+			qldap_errno = AUTH_PANIC;
+			auth_error();
+		}
+	}
+	close(3);
+
+	i = 0;
+	l = up + i;
+	while (up[i++]) if (i == uplen) {
+		qldap_errno = AUTH_NEEDED;
+		auth_error();
+	}
+	p = up + i;
+	if (i == uplen) {
+		qldap_errno = AUTH_NEEDED;
+		auth_error();
+	}
+	while (up[i++]) if (i == uplen) {
+		qldap_errno = AUTH_NEEDED;
+		auth_error();
+	}
+
+	if (!stralloc_copys(login, l) ) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+	if (!stralloc_0(login) ) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+
+	if (!stralloc_copys(authdata, p) ) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+	if (!stralloc_0(authdata) ) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+
+	/* up no longer needed so delete it */
+	for ( i=0; i<UP_LEN; up[i++] = 0) ;
+
+}
+
+void auth_fail(int argc, char **argv, char *login)
+/* Checks if it was a hard fail (bad password) or just a soft error 
+ * (user not found) argc and argv are the arguments of the next auth_module. */
+{
+	/* in the qmail-pop3 chain it is not possible to have multiples 
+	 * authentication modules. So lets exit with the correct number ... */
+	/* In this case we can use auth_error() */
+     qldap_errno = AUTH_FAILED;	
+     auth_error();	
+}
+
+void auth_success(int argc, char **argv, char *login, int uid, int gid,
+	   			  char* home, char* homedirmake, char *md)
+/* starts the next auth_module, or what ever (argv ... ) */
+{
+   
+	log(16, "auth_success: login=%s, uid=%u, ", login, uid);
+	log(16, "gid=%u, home=%s, maildir=%s, aliasempty=%s, hdm=%s\n",
+			gid, home, md, argv[2], homedirmake );
+	
+	_exit(0);
+	/* end */
+}
+
+void auth_error(void)
+/* error handler for this module, does not return */
+{
+	/* Error exit codes:
+	 * 1 = error in server configuration
+	 * 2 = unable to contact authorization server
+	 * 25= user record incorrect
+	 * 3 = authorization failed
+	 * 4 = account disabled
+	 * 5 = mailhost is unreachable
+	 * 6 = mailbox is corrupted
+	 * 7 = unable to start subprogram
+	 * 8 = out of memory
+	 */
+
+        log(2, "warning: auth_error: authorization failed (%s)\n",
+		   qldap_err_str(qldap_errno) );
+
+   
+	if ( qldap_errno == LDAP_INIT ) _exit(1);
+	if ( qldap_errno == LDAP_BIND ) _exit(2);
+	if ( qldap_errno == AUTH_FAILED || qldap_errno == LDAP_REBIND || 
+		 qldap_errno == AUTH_NOSUCH ) _exit(3);
+	if ( qldap_errno == LDAP_SEARCH || qldap_errno == LDAP_NEEDED ||
+		 qldap_errno == ILL_AUTH || qldap_errno == ILL_PATH ) _exit(25);
+	if ( qldap_errno == ACC_DISABLED ) _exit(4);
+	if ( qldap_errno == BADCLUSTER ) _exit(5);
+	if ( qldap_errno == MAILDIR_CORRUPT ) _exit(6);
+	if ( qldap_errno == AUTH_EXEC ) _exit(7);
+	if ( qldap_errno == ERRNO && errno == error_nomem ) _exit(8);
+	_exit(111);
+}
+
+void auth_forward(int fd, char *login, char *passwd) 
+{
+}
diff -uNr stock-20030801/checkpassword_smtp.c smtpauth-20030801/checkpassword_smtp.c
--- stock-20030801/checkpassword_smtp.c	Thu Jan  1 01:00:00 1970
+++ smtpauth-20030801/checkpassword_smtp.c	Mon Aug  4 16:45:14 2003
@@ -0,0 +1,608 @@
+/* checkpasswd_smtp.c, Henning Brauer <lists-qmailldap@bsws.de> */
+#include "qmail-ldap.h"
+#include "stralloc.h"
+#include "auth_mod.h"
+#include "qldap-ldaplib.h"
+#include "qldap-errno.h"
+#include "readwrite.h"
+#include "error.h"
+#include "str.h"
+#include "open.h"
+#include "substdio.h"
+#include "getln.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "digest_md4.h"
+#include "digest_md5.h"
+#include "digest_rmd160.h"
+#include "digest_sha1.h"
+#include "select.h"
+#include "ipalloc.h"
+#include "dns.h"
+#include "timeoutconn.h"
+#include "byte.h"
+#include "scan.h"
+#include "fmt.h"
+#include "alloc.h"
+#include "check.h"
+#include "qldap-debug.h"
+#include "output.h"
+#ifdef QLDAP_CLUSTER
+#include "constmap.h"
+#endif
+
+/* Edit the first lines in the Makefile to enable local passwd lookups 
+ * and debug options.
+ * To use shadow passwords under Solaris, uncomment the 'SHADOWOPTS' line 
+ * in the Makefile.
+ * To use shadow passwords under Linux, uncomment the 'SHADOWOPTS' line and
+ * the 'SHADOWLIBS=-lshadow' line in the Makefile.
+ */
+#include <pwd.h>
+#ifdef PW_SHADOW
+#include <shadow.h>
+#endif
+#ifdef AIX
+#include <userpw.h>
+#endif
+
+extern stralloc qldap_me;
+extern stralloc qldap_objectclass;
+
+int rebind; 
+int cluster;
+
+static int check_ldap(stralloc *login,
+	   				  stralloc *authdata,
+					  unsigned long *uid,
+					  unsigned long *gid,
+					  stralloc *home,
+					  stralloc *maildir);
+
+static int check_passwd(stralloc *login,
+	   					stralloc *authdata,
+						unsigned long *uid,
+						unsigned long *gid,
+						stralloc *home,
+						stralloc *md);
+
+static int cmp_passwd(unsigned char *clear, char *encrypted);
+
+static int get_local_maildir(stralloc *home, stralloc *maildir);
+
+#ifdef QLDAP_CLUSTER
+extern struct constmap qldap_mailhosts;
+
+static void copyloop(int infd, int outfd, int timeout);
+static void forward_session(char *host, char *name, char *passwd);
+#endif
+
+static int make_filter(stralloc *value, stralloc *filter);
+static void free_stralloc(stralloc *sa);
+
+void main(int argc, char **argv)
+{
+	int locald;
+	stralloc login = {0};
+	stralloc authdata = {0};
+	stralloc home = {0};
+	stralloc homemaker = {0};
+	stralloc maildir = {0};
+	unsigned long uid;
+	unsigned long gid;
+
+	log_init(STDERR, 255, 0); /* XXX limited to 64 so it is not possible to get
+							   * XXX passwords via debug on normal systems */
+
+	auth_init(argc, argv, &login, &authdata);
+	log(256, "auth_init: login=%s, authdata=%s\n", login.s, authdata.s);
+
+	if ( authdata.len <= 1 ) {
+		log(1, "alert: null password.\n");
+		qldap_errno = AUTH_NEEDED;
+		auth_fail(argc, argv, login.s);
+	}
+	
+	if ( init_ldap(&locald, &cluster, &rebind, &homemaker, 0, 0, 0) == -1 ) {
+		log(1, "alert: init_ldap failed.\n");
+		_exit(1);
+	}
+	log(64, "init_ldap: ld=%i, cluster=%i, rebind=%i, hdm=%s\n", 
+			locald, cluster, rebind, homemaker.s);
+	
+	if ( check_ldap(&login, &authdata, &uid, &gid, &home, &maildir) ) {
+		log(16, "authentication with ldap was not successful\n");
+		if ( locald == 1 && 
+				(qldap_errno == LDAP_NOSUCH || qldap_errno == LDAP_SEARCH) ) {
+			log(16, "trying to authenticate with the local passwd db\n");
+			if ( check_passwd(&login, &authdata, &uid, &gid, &home, &maildir) ) {
+				auth_fail(argc, argv, login.s);
+			}
+		} else {
+			auth_fail(argc, argv, login.s);
+		}
+	}
+	
+	auth_success(argc, argv, login.s, uid, gid, home.s, homemaker.s, maildir.s);
+	_exit(1); /* should never get here */
+}
+
+int check_ldap(stralloc *login, stralloc *authdata, unsigned long *uid, 
+			   unsigned long *gid, stralloc *home, stralloc *maildir)
+{
+	userinfo	info;
+	extrainfo	extra[2];
+	searchinfo	search;
+	stralloc    filter = {0};
+	int			ret;
+	char		*attrs[] = { LDAP_UID, /* the first 6 attrs are default */
+							 LDAP_QMAILUID,
+							 LDAP_QMAILGID,
+							 LDAP_ISACTIVE,
+							 LDAP_MAILHOST,
+							 LDAP_MAILSTORE,
+							 LDAP_HOMEDIR,
+							 LDAP_PASSWD, 0 }; /* passwd is extra */
+
+	/* initalize the different info objects */
+	if ( rebind ) {
+		extra[0].what = 0;	/* under rebind mode no additional info is needed */
+		search.bindpw = authdata->s;
+		attrs[7] = 0;
+		/* rebind on, check passwd via ldap rebind */ 
+	} else {
+		extra[0].what = LDAP_PASSWD; /* need to get the crypted password */
+		search.bindpw = 0; 	/* rebind off */
+	}
+	extra[1].what = 0;		/* end marker for extra info */
+	
+	if ( !make_filter(login, &filter ) ) { 
+		/* create search filter */
+		log(4, "warning: check_ldap: could not make a filter\n");
+		/* qldap_errno set by make_filter */
+		return -1;
+	}
+	search.filter = filter.s;
+	
+	if ( (ret = qldap_open() ) != -1 ) {
+		ret = qldap_lookup(&search, attrs, &info, extra);
+		qldap_close();
+	}
+	free_stralloc(&filter);	/* free the old filter */
+	if ( ret != 0 ) {
+		log(4, "warning: check_ldap: qldap_lookup not successful!\n");
+		/* qldap_errno set by qldap_lookup */
+		return -1;
+	}
+	/* check the status of the account !!! */
+	if ( info.status == STATUS_BOUNCE  ) {
+		qldap_errno = ACC_DISABLED;
+		return -1;
+	}
+   
+
+	scan_ulong(info.uid, uid);	/* get uid, gid and home */
+	scan_ulong(info.gid, gid);	/* the values are checked later */
+   
+	/* XXX have a look at check.c and qmail-ldap.h for chck_pathb */
+/*	if ( !chck_pathb(home->s,home->len) ) {
+		log(2, "warning: check_ldap: path contains illegal chars!\n");
+		qldap_errno = ILL_PATH; 
+		return -1; 
+	}  */
+/*	if (!stralloc_0(home) ) {
+		qldap_errno = ERRNO;
+		return -1;
+	}
+	if (!stralloc_0(maildir) ) {
+		qldap_errno = ERRNO;
+		return -1;
+	}*/
+   
+   
+	/* free a part of the info struct */
+	alloc_free(info.user);
+	alloc_free(info.uid);
+	alloc_free(info.gid);
+	if (info.homedir) alloc_free(info.homedir);
+	if (info.mms) alloc_free(info.mms); 
+	
+ 
+   
+	if ( rebind && search.bind_ok ) {
+		log(32, 
+			"check_ldap: qldap_lookup sucessfully authenticated with rebind\n");
+		return 0; 
+		/* if we got till here under rebind mode, the user is authenticated */
+	} else if ( rebind ) {
+		log(32, 
+			"check_ldap: qldap_lookup authentication failed with rebind\n");
+		qldap_errno = AUTH_FAILED;
+		return -1; /* user authentification failed */
+	}
+
+	if ( ! extra[0].vals ) {
+		log(2, "warning: check_ldap: password is missing for uid %s\n", 
+				login);
+		qldap_errno = AUTH_NEEDED;
+		return -1; 
+	}
+	
+	ret = cmp_passwd((unsigned char*) authdata->s, extra[0].vals[0]); 
+	log(32, "check_ldap: password compare was %s\n", 
+			ret==0?"successful":"not successful");
+	ldap_value_free(extra[0].vals);
+	return ret;
+}
+
+static int check_passwd(stralloc *login, stralloc *authdata, unsigned long *uid,
+				 unsigned long *gid, stralloc *home, stralloc *md)
+{
+	int ret;
+	struct passwd *pw;
+#ifdef PW_SHADOW
+	struct spwd *spw;
+#endif
+#ifdef AIX
+	struct userpw *spw;
+#endif
+	
+	pw = getpwnam(login->s);
+	if (!pw) {
+		/* XXX: unfortunately getpwnam() hides temporary errors */
+		log(32, "check_passwd: user %s not found in passwd db\n", login->s);
+		qldap_errno = AUTH_NOSUCH;
+		return -1;
+	}
+	*gid = pw->pw_gid;
+	*uid = pw->pw_uid;
+
+	/* here we don't check the home and maildir path, if a user has a faked 
+	 * passwd entry, then you have a bigger problem on your system than just 
+	 * a guy how can read the mail of other users/customers */
+	if (!stralloc_copys(home, pw->pw_dir) ) {
+		qldap_errno = ERRNO;
+		return -1;
+	}
+	
+	if ( get_local_maildir(home, md) == -1 ) {
+		/* function sets qldap_errno */
+		return -1;
+	}
+	log(32, "get_local_maildir: maildir=%s\n", md->s);
+	
+	if (!stralloc_0(home) ) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+	
+#ifdef PW_SHADOW
+	spw = getspnam(login->s);
+	if (!spw) {
+		/* XXX: again, temp hidden */
+		qldap_errno = AUTH_ERROR;
+		return -1;
+	}
+	ret = cmp_passwd((unsigned char*) authdata->s, spw->sp_pwdp);
+#else /* no PW_SHADOW */
+#ifdef AIX
+	spw = getuserpw(login->s);
+	if (!spw) {
+		/* XXX: and again */
+		qldap_errno = AUTH_ERROR;
+		return -1;
+	}
+	ret = cmp_passwd((unsigned char*) authdata->s, spw->upw_passwd);
+#else /* no AIX */
+	ret = cmp_passwd((unsigned char*) authdata->s, pw->pw_passwd);
+#endif /* END AIX */
+#endif /* END PW_SHADOW */
+	log(32, "check_pw: password compare was %s\n", 
+			ret==0?"successful":"not successful");
+	return ret;
+	
+}
+
+static int cmp_passwd(unsigned char *clear, char *encrypted)
+{
+#define HASH_LEN 100	/* XXX is this enough, I think yes */
+						/* What do you think ? */
+	char hashed[HASH_LEN]; /* these to buffers can not be used for exploits */
+	char salt[33];
+	int  shift;
+	
+	if (encrypted[0] == '{') { /* hashed */
+		if (!str_diffn("{crypt}", encrypted, 7) ) {
+			/* CRYPT */
+			shift = 7;
+			str_copy(hashed, crypt(clear, encrypted+shift) );
+		} else if (!str_diffn("{MD4}", encrypted, 5) ) {
+			/* MD4 */
+			shift = 5;
+			MD4DataBase64(clear, str_len(clear), hashed, sizeof(hashed));
+		} else if (!str_diffn("{MD5}", encrypted, 5) ) {
+			/* MD5 */
+			shift = 5;
+			MD5DataBase64(clear, str_len(clear), hashed, sizeof(hashed));
+		} else if (!str_diffn("{NS-MTA-MD5}", encrypted, 12) ) {
+			/* NS-MTA-MD5 */
+			shift = 12;
+			if (!str_len(encrypted) == 76) {
+				qldap_errno = ILL_AUTH;
+				return -1;
+			} /* boom */
+			byte_copy(salt, 32, &encrypted[44]);
+			salt[32] = 0;
+			if (ns_mta_hash_alg(hashed, salt, (char *) clear) == -1) {
+				qldap_errno = ERRNO;
+				return -1;
+			}
+			byte_copy(&hashed[32], 33, salt);
+		} else if (!str_diffn("{SHA}", encrypted, 5) ) {
+			/* SHA */
+			shift = 5;
+			SHA1DataBase64(clear, str_len(clear), hashed, sizeof(hashed));
+		} else  if (!str_diffn("{RMD160}", encrypted, 8) ) {
+			/* RMD160 */
+			shift = 8;
+			RMD160DataBase64(clear, str_len(clear), hashed, sizeof(hashed));
+		} else {
+			/* unknown hash function detected */ 
+			shift = 0;
+			qldap_errno = ILL_AUTH;
+			return -1;
+		}
+		/* End getting correct hash-func hashed */
+		log(256, "cpm_passwd: comparing hashed passwd (%s == %s)\n", 
+				hashed, encrypted);
+		if (!*encrypted || str_diff(hashed,encrypted+shift) ) {
+			qldap_errno = AUTH_FAILED;
+			return -1;
+		}
+		/* hashed passwds are equal */
+	} else { /* crypt or clear text */
+		log(256, "cpm_passwd: comparing standart passwd (%s == %s)\n", 
+				crypt(clear,encrypted), encrypted);
+		if (!*encrypted || str_diff(encrypted, crypt(clear,encrypted) ) ) {
+			/* CLEARTEXTPASSWD ARE NOT GOOD */
+			/* so they are disabled by default */
+#ifdef CLEARTEXTPASSWD
+#warning ___CLEARTEXT_PASSWORD_SUPPORT_IS_ON___
+			if (!*encrypted || str_diff(encrypted, clear) ) {
+#endif
+			qldap_errno = AUTH_FAILED;
+			return -1;
+#ifdef CLEARTEXTPASSWD
+			}
+#endif
+			/* crypted or cleartext passwd ok */
+		}
+	} /* end -- hashed or crypt/clear text */
+
+	return 0;
+
+}
+
+static int get_local_maildir(stralloc *home, stralloc *maildir)
+{
+	substdio ss;
+	stralloc dotqmail = {0};
+	char buf[512];
+	int match;
+	int fd;
+	
+	if ( ! stralloc_copy(&dotqmail, home) ) {
+		qldap_errno = ERRNO;
+		return -1;
+	}
+	if ( ! stralloc_cats(&dotqmail, "/.qmail") ) {
+		qldap_errno = ERRNO;
+		return -1;
+	}
+	if ( ! stralloc_0(&dotqmail) ) {
+		qldap_errno = ERRNO;
+		return -1;
+	}
+	
+	if ( ( fd = open_read(dotqmail.s) ) == -1 ) {
+		if ( errno == error_noent ) return 0;
+		qldap_errno = ERRNO;
+		return -1;
+	}
+
+	substdio_fdbuf(&ss,read,fd,buf,sizeof(buf));
+	while (1) {
+		if (getln(&ss,&dotqmail,&match,'\n') != 0) goto tryclose;
+		if (!match && !dotqmail.len) break;
+		if ( (dotqmail.s[0] == '.' || dotqmail.s[0] == '/') && 
+			  dotqmail.s[dotqmail.len-2] == '/' ) { /* is a maildir line ? */
+			if ( ! stralloc_copy(maildir, &dotqmail) ) goto tryclose;
+			maildir->s[maildir->len-1] = '\0';
+			break;
+		}		
+	}
+	
+	close(fd);
+	for (match = 0; match<512; buf[match++]=0 ) ; /* trust nobody */
+	free_stralloc(&dotqmail);
+	return 0;
+
+tryclose:
+	for (match = 0; match<512; buf[match++]=0 ) ; /* trust nobody */
+	match = errno; /* preserve errno */
+	close(fd);
+	free_stralloc(&dotqmail);
+	errno = match;
+	qldap_errno = ERRNO;
+	return -1;
+
+}
+
+#ifdef QLDAP_CLUSTER
+static void copyloop(int infd, int outfd, int timeout)
+{
+	fd_set iofds;
+	fd_set savedfds;
+	int maxfd;			/* Maximum numbered fd used */
+	struct timeval tv;
+	unsigned long bytes;
+	char buf[4096];		/* very big buffer ethernet pkgs are normaly
+						   around 1500 bytes long */
+
+	/* file descriptor bits */
+	FD_ZERO(&savedfds);
+	FD_SET(infd, &savedfds);
+	FD_SET(outfd, &savedfds);
+
+	if (infd > outfd) {
+		maxfd = infd;
+	} else {
+		maxfd = outfd;
+	}
+
+	while(1) {
+		/* Set up timeout *//* because of LINUX this has to be done everytime */
+		tv.tv_sec = timeout;
+		tv.tv_usec = 0;
+
+		byte_copy(&iofds, sizeof(iofds), &savedfds);
+
+		if ( select( maxfd + 1, &iofds, (fd_set *)0, (fd_set *)0, &tv) <= 0 ) {
+			break;
+		}
+
+		if(FD_ISSET(infd, &iofds)) {
+			if((bytes = read(infd, buf, sizeof(buf))) <= 0)
+				break;
+			if(write(outfd, buf, bytes) != bytes)
+				break;
+		}
+		if(FD_ISSET(outfd, &iofds)) {
+			if((bytes = read(outfd, buf, sizeof(buf))) <= 0)
+				break;
+			if(write(infd, buf, bytes) != bytes)
+				break;
+		}
+	}
+
+	shutdown(infd,0);
+	shutdown(outfd,0);
+	close(infd);
+	close(outfd);
+	for(bytes=0; bytes<4096; buf[bytes++] = 0 ) ; /* paranoia */
+	return;
+}
+
+static void forward_session(char *host, char *name, char *passwd)
+{
+	ipalloc ip = {0};
+	stralloc host_stralloc = {0};
+	int ffd;
+	int timeout = 31*60; /* ~30 min timeout RFC1730 */
+	int ctimeout = 20;
+	
+	if (!stralloc_copys(&host_stralloc, host)) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+
+	dns_init(0);
+	switch (dns_ip(&ip,&host_stralloc)) {
+		case DNS_MEM:
+			qldap_errno = ERRNO;
+			auth_error();
+		case DNS_SOFT:
+			qldap_errno = BADCLUSTER;
+			auth_error();
+		case DNS_HARD:
+			qldap_errno = BADCLUSTER;
+			auth_error();
+		case 1:
+			if (ip.len <= 0) {
+				qldap_errno = BADCLUSTER;
+				auth_error();
+			}
+	}
+/*	if ( ip.len != 1 ) {
+		qldap_errno = BADCLUSTER;
+		auth_error();
+	} */ /* 20010523 do not check if only one IP is returned, so it is
+			possible to have a cluster node consisting of multiple machines 
+			XXX if your mailhost is bad (bad entries in ldap) you will get
+			bad loops.
+		  */
+	
+	ffd = socket(AF_INET,SOCK_STREAM,0);
+	if (ffd == -1) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+	
+	if (timeoutconn(ffd, &ip.ix[0].ip, auth_port, ctimeout) != 0) {
+		qldap_errno = ERRNO;
+		auth_error();
+	}
+	
+	/* We have a connection, first send user and pass */
+	auth_forward(ffd, name, passwd);
+	copyloop(0, ffd, timeout);
+
+	_exit(0); /* all went ok, exit normaly */
+
+}
+#endif /* QLDAP_CLUSTER */
+
+static int make_filter(stralloc *value, stralloc *filter)
+/* create a searchfilter, "(uid=VALUE)" */
+{
+	stralloc tmp = {0};
+	
+	
+	if ( !stralloc_copy(&tmp, value) ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}
+	if ( !escape_forldap(&tmp) ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}
+	if ( !stralloc_copys(filter,"(" ) ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}	
+	if ( qldap_objectclass.len && (
+		 !stralloc_cats(filter,"&(" ) || 
+		 !stralloc_cats(filter,LDAP_OBJECTCLASS) ||
+		 !stralloc_cats(filter,"=") ||
+		 !stralloc_cat(filter,&qldap_objectclass) ||
+		 !stralloc_cats(filter,")(") ) ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}
+	if ( !stralloc_cats(filter, LDAP_UID) ||
+		 !stralloc_cats(filter, "=") ||
+		 !stralloc_cat(filter, &tmp) ||
+		 !stralloc_cats(filter, ")") ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}
+	if ( qldap_objectclass.len && 
+		 !stralloc_cats(filter,")") ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}
+	if ( !stralloc_0(filter) ) {
+		qldap_errno = ERRNO;
+		return 0;
+	}
+	free_stralloc(&tmp);
+	return 1;
+}
+
+static void free_stralloc(stralloc* sa)
+{
+	alloc_free(sa->s);
+	sa->s = 0;
+	return;
+}
+
diff -uNr stock-20030801/hier.c smtpauth-20030801/hier.c
--- stock-20030801/hier.c	Mon Aug  4 16:42:57 2003
+++ smtpauth-20030801/hier.c	Mon Aug  4 16:45:14 2003
@@ -160,6 +160,7 @@
   c(auto_qmail,"bin","qmail-quotawarn",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","auth_pop",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","auth_imap",auto_uido,auto_gidq,0700);
+  c(auto_qmail,"bin","auth_smtp",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","qmail-ldaplookup",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","digest",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","pbsadd",auto_uido,auto_gidq,0755);
diff -uNr stock-20030801/qmail-smtpd.c smtpauth-20030801/qmail-smtpd.c
--- stock-20030801/qmail-smtpd.c	Mon Aug  4 16:42:57 2003
+++ smtpauth-20030801/qmail-smtpd.c	Mon Aug  4 16:53:01 2003
@@ -1,5 +1,7 @@
 #include "sig.h"
-#include "readwrite.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
 #include "stralloc.h"
 #include "substdio.h"
 #include "subfd.h"
@@ -17,6 +19,7 @@
 #include "scan.h"
 #include "byte.h"
 #include "case.h"
+#include "wait.h"
 #include "env.h"
 #include "now.h"
 #include "exit.h"
@@ -37,6 +40,9 @@
 /* zlib needs to be after openssl includes or build will fail */
 #include <zlib.h>
 #endif
+#ifdef USE_SMTPAUTH
+#include "base64.h"
+#endif
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -135,6 +141,8 @@
 void die_read() { logline(1,"read error, connection closed"); _exit(1); }
 void die_alarm() { out("451 timeout (#4.4.2)\r\n"); logline(1,"connection timed out, closing connection"); flush(); _exit(1); }
 void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); logline(1,"out of memory, closing connection"); flush(); _exit(1); }
+void die_crash() { out("421 child crashed (#4.3.0)\r\n"); logline(1,"child crashed, closing connection"); flush(); _exit(1); }
+void die_fork() { out("421 unable to start checkpassword.\r\n"); logline(1,"unable to start checkpassword, closing connection"); flush(); _exit(1); }
 void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); logline(1,"unable to read controls, closing connection"); flush(); _exit(1); }
 void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); logline(1,"unable to figure out my IP address, closing connection"); flush(); _exit(1); }
 void err_dns() { out("421 DNS temporary failure at return MX check, try again later (#4.3.0)\r\n"); }
@@ -601,6 +609,14 @@
   if (!ssl)
     out("250-STARTTLS\r\n");
 #endif
+#ifdef USE_SMTPAUTH
+#ifdef USE_OLD_GREETING
+  out("250-AUTH=LOGIN PLAIN\r\n");
+#endif
+#ifdef USE_NEW_GREETING
+  out("250-AUTH LOGIN PLAIN\r\n");
+#endif
+#endif
   out("250 8BITMIME\r\n");
 
   seenmail = 0; dohelo(arg);
@@ -1233,10 +1249,223 @@
 }
 #endif
 
+#ifdef USE_SMTPAUTH
+static unsigned char authenticated=0;
+static char **smtpauth_argv;
+static char *auth_argv[4];
+static stralloc smtpauth = {0};
+static char smtpauthlogin[65];
+static char smtpauthpass[65];
+static char smtpauthtimestamp[65];
+char unique[FMT_ULONG + FMT_ULONG + 3];
+
+static int smtpauth_getl(void) {
+  int i;
+  if (!stralloc_copys(&smtpauth, "")) return -1;
+  for (;;) {
+    if (!stralloc_readyplus(&smtpauth,1)) return -1;
+    i = substdio_get(&ssin, smtpauth.s + smtpauth.len, 1);
+    if (i != 1) return i;
+    if (smtpauth.s[smtpauth.len] == '\n') break;
+    ++smtpauth.len;
+  }
+  if (smtpauth.len > 0) if (smtpauth.s[smtpauth.len-1] == '\r') --smtpauth.len;
+  smtpauth.s[smtpauth.len] = 0;
+  return smtpauth.len;
+}
+
+static void smtpauth_authenticate(void)
+{
+  int st, pid, fds[2];
+ 
+    if (pipe(fds)) {
+      out("535 pipe failure\r\n");
+      flush();
+      logpid(1); logstring(1, "err:"); logstring(1, "SMTP AUTH: pipe failure"); logflush(1);
+      _exit(0);
+    }
+   
+    if ( ! auth_argv[1] ) {
+      out("535 parameter problem\r\n");
+      flush();
+      logpid(1); logstring(1, "err:"); logstring(1, "SMTP AUTH: parameter problem, no checkpasswd given"); logflush(1);
+      _exit(0);
+    }
+   
+    /* spawn external program
+       external program should return '0' if it was successful,
+       submit: /path/to/auth_smtp */
+   
+    switch ((pid=fork())) {
+      case -1: die_fork(); logpid(1); logstring(1, "err:"); logstring(1, "SMTP AUTH: cannot fork!"); logflush(1);
+      case 0: close(fds[1]);
+        fd_copy(3,fds[0]);
+        flush();
+        execvp(auth_argv[1], auth_argv+1);
+        logpid(1); logstring(1, "err: SMTP AUTH:");	    
+	    logstring(1, "exec failed:"); 
+	    logstring(1, strerror(errno));
+	    logstring(1, auth_argv[1]);
+	    logflush(1);
+        die_fork();
+    };
+    close(fds[0]);
+    write(fds[1], smtpauthlogin, str_len(smtpauthlogin)+1);
+    write(fds[1], smtpauthpass, str_len(smtpauthpass)+1);
+    if (str_len(smtpauthtimestamp))
+    {
+          write(fds[1], smtpauthtimestamp, str_len(smtpauthtimestamp)+1);
+    }
+    close(fds[1]);
+    wait_pid(&st, pid);
+
+    if (wait_crashed(st)) {
+      logpid(1); logstring(1, "err: SMTP AUTH:");	    
+	  logstring(1, "child crashed!");
+	  logflush(1);
+      die_crash();
+	}
+    if (wait_exitcode(st) == 0) {
+      out("235 go ahead\r\n");
+      flush();
+      relayok=relayclient="";
+      authenticated=1;
+      remoteinfo=smtpauthlogin;
+      logpid(3); logstring(3, "inf: SMTP AUTH:");	    
+	  logstring(3, "user ");
+	  logstring(3, smtpauthlogin);
+	  logstring(3, " logged in successfull");
+	  logflush(3);
+	  return;
+    }
+    sleep(2);
+    out("535 auth failure\r\n"); 
+    flush(); 
+    logpid(3); logstring(3, "inf: SMTP AUTH:");	    
+	logstring(3, "failed login for ");
+	logstring(3, smtpauthlogin);
+	logflush(3);
+    return;
+}
+
+void smtp_auth(arg) char *arg; {
+  int ret;
+  if (!authenticated)
+  {
+    if ((ret=strncasecmp(arg,"login",5))==0)
+    {
+      while (arg && *arg && *arg != ' ') arg++;
+
+      /* pass over the space */
+      while (arg && *arg && *arg == ' ') arg++;
+
+      if (arg && *arg) {
+        /* here's the base64 encoded login */
+        b64_pton(arg, smtpauthlogin, sizeof(smtpauthlogin));
+      } else {
+        out("334 VXNlcm5hbWU6\r\n"); /* b64 <- 'Username:' */
+        flush();
+        if (smtpauth_getl() > 0)
+          b64_pton(smtpauth.s, smtpauthlogin, sizeof(smtpauthlogin));
+        else
+          die_read();
+      }
+      out("334 UGFzc3dvcmQ6\r\n"); /* b64 <- 'Password:' */
+      flush();
+      if (smtpauth_getl() > 0)
+        b64_pton(smtpauth.s, smtpauthpass, sizeof(smtpauthpass));
+      else
+        die_read();
+      smtpauthtimestamp[0]=0;
+      auth_argv[1]=smtpauth_argv[1];	/* change checkpass prg */
+      auth_argv[2]=smtpauth_argv[2];	/* change checkpass prg */
+      auth_argv[3]=NULL;			/* change checkpass prg */
+      smtpauth_authenticate();  
+      return;
+    }
+    else if ((ret=strncasecmp(arg,"plain",5))==0)
+    {
+      int start;
+      static char smtpauthloginpass[200];
+
+      while (arg && *arg && *arg != ' ') arg++;
+
+      /* pass over the space */
+      while (arg && *arg && *arg == ' ') arg++;
+ 
+      if (arg && *arg)
+      {
+        if(strlen(arg)*3/4 >= sizeof(smtpauthloginpass))
+        {
+          out("535 input too long\r\n");
+          flush();
+          return;
+        }
+        /* here's the base64 encoded login/password */
+        b64_pton(arg, smtpauthloginpass, sizeof(smtpauthloginpass)-1);
+      } else {
+	int i;
+        out("334 \r\n");
+        flush();
+        i=smtpauth_getl();
+        if(i <= 0)
+          die_read();
+        else if(i*3/4 >= sizeof(smtpauthloginpass))
+        {
+          out("535 input too long\r\n");
+          flush();
+          return;
+        } else b64_pton(smtpauth.s, smtpauthloginpass, sizeof(smtpauthloginpass)-1);
+      }
+      smtpauthloginpass[sizeof(smtpauthloginpass)-1]=0;
+      start=strlen(smtpauthloginpass)+1;
+      if((start >= sizeof(smtpauthloginpass)) || (strlen(smtpauthloginpass+start) >= 65))
+      {
+          out("535 malformed input\r\n");
+          flush();
+          return;
+      }
+      strcpy(smtpauthlogin,smtpauthloginpass+start);
+
+      start+=strlen(smtpauthlogin)+1;
+      if((start >= sizeof(smtpauthloginpass)) || (strlen(smtpauthloginpass+start) >= 65))
+      {
+          out("535 malformed input\r\n");
+          flush();
+          return;
+      }
+      strcpy(smtpauthpass,smtpauthloginpass+start);
+
+      smtpauthtimestamp[0]=0;
+      auth_argv[1]=smtpauth_argv[1];	/* change checkpass prg */
+      auth_argv[2]=smtpauth_argv[2];	/* change checkpass prg */
+      auth_argv[3]=NULL;		/* change checkpass prg */
+      smtpauth_authenticate();
+      return;
+    }
+    else
+    {
+      out("504 auth type not supported\r\n"); 
+      flush();
+      return;
+    }
+  }
+  else
+  {
+      out("503 you are already authenticated\r\n"); 
+      flush(); 
+      return;
+  }
+}
+#endif
+
 struct commands smtpcommands[] = {
   { "rcpt", smtp_rcpt, 0 }
 , { "mail", smtp_mail, 0 }
 , { "data", smtp_data, flush }
+#ifdef USE_SMTPAUTH
+, { "auth", smtp_auth, flush }
+#endif
 , { "quit", smtp_quit, flush }
 , { "helo", smtp_helo, flush }
 , { "ehlo", smtp_ehlo, flush }
@@ -1253,8 +1482,11 @@
 , { 0, err_unimpl, flush }
 } ;
 
-void main()
+void main(argc,argv) int argc; char **argv;
 {
+#ifdef USE_SMTPAUTH
+  smtpauth_argv = argv;
+#endif
 #ifdef TLS_SMTPD
   sig_alarmcatch(sigalrm);
 #endif
