Ender Hikmet KILICOGLU wrote:

> I have installed and did everything as said on lwq/ldap (2 params and
> tcprules related) but helas same thing users can send mail without
> authanticated. what is wrong
> Or I coldnt remove relay values. I am useing supervise with tcp only one
> line
>
> 127.0.0.1:allow:RELAYCLIENT""
>
> thanks for reply

The patch for 20010501 is not correct, I just (re)found my adjusted patch I
use on my server, see attachment. Henning, could you add this to the
lwq/ldap site?

Franky
diff -uNb qmail-1.03/Makefile qmail-1.03.smtpauth/Makefile
--- qmail-1.03/Makefile Tue Jul  3 09:11:17 2001
+++ qmail-1.03.smtpauth/Makefile        Tue Jul  3 09:03:33 2001
@@ -8,6 +8,12 @@
 # -DCLEARTEXTPASSWD to the LDAPFLAGS
 LDAPFLAGS=-DQLDAP_CLUSTER
 
+# 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
@@ -68,7 +74,7 @@
 
 default: it qldap
 
-qldap: qmail-quotawarn qmail-reply auth_pop auth_imap digest qmail-ldaplookup
+qldap: qmail-quotawarn qmail-reply auth_pop auth_imap auth_smtp digest 
+qmail-ldaplookup
 
 addresses.0: \
 addresses.5
@@ -401,6 +407,13 @@
 ipalloc.h timeoutconn.h byte.h scan.h fmt.h alloc.h qldap-debug.h
        ./compile $(LDAPFLAGS) $(SHADOWOPTS) $(LDAPINCLUDES) 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) checkpassword_smtp.c
+
 chkshsgr: \
 load chkshsgr.o
        ./load chkshsgr 
@@ -1773,13 +1786,13 @@
 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 dns.lib socket.lib
+fs.a auto_qmail.o dns.lib socket.lib ${SMTPAUTHOBJS}
        ./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 fs.a auto_qmail.o dns.o str.a \
-       `cat dns.lib` `cat socket.lib` ${TLSLIBS}
+       ${SMTPAUTHOBJS} `cat dns.lib` `cat socket.lib` ${TLSLIBS}
 
 qmail-smtpd.0: \
 qmail-smtpd.8
@@ -1790,8 +1803,9 @@
 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
-       ./compile ${TLSON} ${TLSINCLUDES} qmail-smtpd.c
+exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h \
+${SMTPAUTHINCLUDES}
+       ./compile ${TLSON} ${TLSINCLUDES} ${SMTPAUTH} qmail-smtpd.c
 
 qmail-start: \
 load qmail-start.o prot.o fd.a auto_uids.o
@@ -2397,3 +2411,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 str.a
+       ./load auth_smtp checkpassword_smtp.o check.o control.o qldap-ldaplib.o \
+       qldap-debug.o auto_qmail.o dns.o timeoutconn.o timeoutread.o ip.o \
+       ipalloc.o getln.a open.a env.a stralloc.a alloc.a substdio.a str.a \
+       base64.o digest_md4.o digest_md5.o digest_rmd160.o digest_sha1.o \
+       qldap-mdm.o wait.a qldap-errno.o error.a fs.a ndelay.a prot.o \
+       $(LDAPLIBS) $(SHADOWLIBS) `cat dns.lib` `cat socket.lib` str.a
+
diff -uNb qmail-1.03/TARGETS qmail-1.03.smtpauth/TARGETS
--- qmail-1.03/TARGETS  Tue Jul  3 08:52:10 2001
+++ qmail-1.03.smtpauth/TARGETS Tue Jul  3 09:10:57 2001
@@ -393,6 +393,7 @@
 digest_sha1.o
 checkpassword
 checkpassword.o
+checkpassword_smtp.o
 digest
 digest.o
 endian
@@ -404,6 +405,7 @@
 maildir++.o
 auth_imap.o
 auth_pop.o
+auth_smtp.o
 qldap-debug.o
 qldap-ldaplib.o
 qldap-mdm.o
diff -uNb qmail-1.03/auth_smtp.c qmail-1.03.smtpauth/auth_smtp.c
--- qmail-1.03/auth_smtp.c      Thu Jan  1 01:00:00 1970
+++ qmail-1.03.smtpauth/auth_smtp.c     Mon Jul  2 15:16:10 2001
@@ -0,0 +1,149 @@
+/* auth_smtp.c, Henning Brauer <[EMAIL PROTECTED]> */
+#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
+ * argc and argv are the arguments of the next auth_module. */
+{
+#define UP_LEN 513
+       char up[UP_LEN];
+       char *l;
+       char *p;
+       int  uplen;
+       int  i;
+
+
+       if (!argv[1]) {
+               qldap_errno = AUTH_NEEDED;
+               auth_error();
+       }
+
+       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 ... ) */
+{
+       debug(16, "auth_success: login=%s, uid=%u, ", login, uid);
+       debug(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
+        */
+       debug(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 -uNb qmail-1.03/checkpassword_smtp.c qmail-1.03.smtpauth/checkpassword_smtp.c
--- qmail-1.03/checkpassword_smtp.c     Thu Jan  1 01:00:00 1970
+++ qmail-1.03.smtpauth/checkpassword_smtp.c    Mon Jul  2 18:48:31 2001
@@ -0,0 +1,597 @@
+/* checkpasswd_smtp.c, Henning Brauer <[EMAIL PROTECTED]> */
+#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"
+
+/* 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
+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;
+
+       init_debug(STDERR, 255); /* XXX limited to 64 so it is not possible to get
+                                                        * XXX passwords via debug on 
+normal systems */
+
+       auth_init(argc, argv, &login, &authdata);
+       debug(256, "auth_init: login=%s, authdata=%s\n", login.s, authdata.s);
+       
+        if ( authdata.len <= 1 ) {
+                debug(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 ) {
+               debug(1, "alert: init_ldap failed.\n");
+               _exit(1);
+       }
+       debug(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) ) {
+               debug(16, "authentication with ldap was not successful\n");
+               if ( locald == 1 && 
+                               (qldap_errno == LDAP_NOSUCH || qldap_errno == 
+LDAP_SEARCH) ) {
+                       debug(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 */
+               debug(4, "warning: check_ldap: could not make a filter\n");
+               /* qldap_errno set by make_filter */
+               return -1;
+       }
+       search.filter = filter.s;
+       
+       ret = ldap_lookup(&search, attrs, &info, extra);
+       free_stralloc(&filter); /* free the old filter */
+       if ( ret != 0 ) {
+               debug(4, "warning: check_ldap: ldap_lookup not successful!\n");
+               /* qldap_errno set by ldap_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) ) {
+               debug(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 ) {
+               debug(32, 
+                       "check_ldap: ldap_lookup sucessfully authenticated with 
+rebind\n");
+               return 0; 
+               /* if we got till here under rebind mode, the user is authenticated */
+       } else if ( rebind ) {
+               debug(32, 
+                       "check_ldap: ldap_lookup authentication failed with rebind\n");
+               qldap_errno = AUTH_FAILED;
+               return -1; /* user authentification failed */
+       }
+
+   
+       if ( ! extra[0].vals ) {
+               debug(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]); 
+       debug(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 */
+               debug(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;
+       }
+       debug(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 */
+       debug(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 */
+               debug(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 */
+               debug(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();
+       }
+       
+       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 -uNb qmail-1.03/hier.c qmail-1.03.smtpauth/hier.c
--- qmail-1.03/hier.c   Tue Jul  3 09:11:19 2001
+++ qmail-1.03.smtpauth/hier.c  Mon Jul  2 15:16:10 2001
@@ -152,6 +152,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,0700);
   c(auto_qmail,"bin","qmail-ldaplookup",auto_uido,auto_gidq,0700);
 
   c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
diff -uNb qmail-1.03/qmail-smtpd.c qmail-1.03.smtpauth/qmail-smtpd.c
--- qmail-1.03/qmail-smtpd.c    Tue Jul  3 09:11:22 2001
+++ qmail-1.03.smtpauth/qmail-smtpd.c   Mon Jul  2 18:48:48 2001
@@ -1,4 +1,7 @@
 #include "sig.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
 #include "readwrite.h"
 #include "stralloc.h"
 #include "substdio.h"
@@ -17,6 +20,7 @@
 #include "scan.h"
 #include "byte.h"
 #include "case.h"
+#include "wait.h"
 #include "env.h"
 #include "now.h"
 #include "exit.h"
@@ -32,6 +36,9 @@
 SSL *ssl = NULL;
 stralloc clientcert = {0};
 #endif
+#ifdef USE_SMTPAUTH
+#include "base64.h"
+#endif
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -130,6 +137,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"); flush(); _exit(1); }
+void die_fork() { out("421 unable to start checkpassword.\r\n"); flush(); _exit(1); }
 void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); 
logline(1,"unable to real 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 straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n";); 
logline(1,"stray new line detected, closing connection"); flush(); _exit(1); }
@@ -574,23 +583,21 @@
 {
   smtp_greet("250-"); 
   smtpsize[fmt_ulong(smtpsize,(unsigned long) databytes)] = 0;
-#ifdef TLS
-  if (ssl) {
    out("\r\n250-PIPELINING\r\n");
-   out("250-SIZE "); out(smtpsize); out("\r\n");
-   out("250 8BITMIME\r\n");
-  }
-  else {
+#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("\r\n250-PIPELINING\r\n");
 #ifdef TLS
+  if (!ssl)
   out("250-STARTTLS\r\n");
 #endif
   out("250-SIZE "); out(smtpsize); out("\r\n");
   out("250 8BITMIME\r\n");
-#ifdef TLS
-  }
-#endif
   seenmail = 0; dohelo(arg);
   logpid(3); logstring(3,"remote ehlo ="); logstring(3,arg); logflush(3);
   logpid(3); logstring(3,"max msg size ="); logstring(3,smtpsize); logflush(3);
@@ -1104,10 +1111,300 @@
 }
 #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();
+      _exit(0);
+    }
+    /* spawn external program
+
+    external program should return '0' if it was successful,
+
+    submit: /bin/checkpassword /bin/true
+  
+    */
+    switch ((pid=fork())) {
+      case -1: die_fork();
+      case 0: close(fds[1]);
+        fd_copy(3,fds[0]);
+        flush();
+        execvp(auth_argv[1], auth_argv+1);
+        die_nomem();
+    };
+    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))
+      die_crash();
+    if (wait_exitcode(st) == 0) {
+      out("235 go ahead\r\n");
+      flush();
+      relayok=relayclient="";
+      authenticated=1;
+      remoteinfo=smtpauthlogin;
+      return;
+    }
+    sleep(2);
+    out("535 auth failure\r\n"); 
+    flush(); 
+    return;
+}
+
+void smtp_auth(arg) char *arg; {
+  int ret;
+  /* netscape 4.5 sends AUTH LOGIN <base64encodedusername>
+     microsoft outlook express sends AUTH LOGIN
+
+     idea is simple
+
+     use an external program to test authority
+     if success, set 'RELAYCLIENT'
+     otherwise, let them know nicely (hangup)
+
+     note, i really don't like djb's coding style even though i'm using it here.
+     i think using spaces for tabs is bad.
+                                                [EMAIL PROTECTED]
+  */
+  /* Here i've added support for other auth types.
+  
+                                               [EMAIL PROTECTED]       */
+  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 ok. go on.\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 if ((ret=strncasecmp(arg,"cram-md5",8))==0)  
+    {
+      char *helper;
+      char *s;
+      int i;
+      static stralloc me = {0};
+      static stralloc greet = {0};
+      static stralloc greetenc = {0};
+      i = control_readline(&me,"control/me");
+      if (i != 1) 
+      {
+        out("535 internal server error\r\n"); flush(); _exit(0);
+      }
+      for (i=0;i <= me.len;i++)
+      {
+        if (me.s[i]=='\n')
+        {
+          me.s[i]=0;
+          break;
+        }
+      }
+
+      s = unique;
+      s += fmt_uint(s,getpid());
+      *s++ = '.';
+      s += fmt_ulong(s,(unsigned long) now());
+      *s++ = '@';
+      *s++ = 0;
+      if (greet.len)
+      {
+       for (i=0;i<greet.len;i++)
+         greet.s[i]=0;
+        greet.len=0;
+      }
+      stralloc_append(&greet,"<");
+      stralloc_cats(&greet,unique);
+      stralloc_cats(&greet,me.s);
+      stralloc_cats(&greet,">");
+      greet.s[greet.len]=0;    // obscure fix but it works
+      stralloc_readyplus(&greet,3);
+      if (greetenc.len)
+      {
+       for (i=0;i<greetenc.len;i++)
+         greetenc.s[i]=0;
+        greetenc.len=0;
+      }
+      flush();
+      b64_ntop(greet.s,greet.a,greetenc.s,greetenc.a);
+      greetenc.s[greetenc.len]=0;      // obscure fix but it works
+      out("334 ");
+      out(greetenc.s);
+      out("\r\n");
+      flush();
+      if (smtpauth_getl() > 0)
+      {
+        s=calloc((size_t) strlen(smtpauth.s),(size_t)1);
+        b64_pton(smtpauth.s, s, strlen(smtpauth.s));
+      }
+      helper=strtok(s," ");
+      if(helper!=NULL)
+      {
+        strncpy (smtpauthlogin,helper,64);
+      }
+      else
+      {
+        out("535 malformed input\r\n"); 
+        return;
+      }
+      helper=strtok(NULL," ");
+      if(helper!=NULL)
+      {
+        strncpy (smtpauthtimestamp,helper,64);
+      }
+      else
+      {
+        out("535 malformed input\r\n"); 
+        return;
+      }
+      strncpy (smtpauthpass,greet.s,64);
+      auth_argv[1]=smtpauth_argv[3];   /* change checkpass prg */
+      auth_argv[2]=smtpauth_argv[4];   /* 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 }
@@ -1121,8 +1418,11 @@
 , { 0, err_unimpl, flush }
 } ;
 
-void main()
+void main(argc,argv) int argc; char **argv;
 {
+#ifdef USE_SMTPAUTH
+  smtpauth_argv = argv;
+#endif
 #ifdef TLS
   sig_alarmcatch(sigalrm);
 #endif

Reply via email to