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