diff -r -u -N aclocal.m4 aclocal.m4
--- aclocal.m4	2006-09-28 00:49:59.000000000 +0400
+++ aclocal.m4	2007-02-03 18:50:05.000000000 +0300
@@ -292,3 +292,44 @@
 fi
 ])
 dnl <openssl/>
+
+dnl bsd_sockets.m4--which socket libraries do we need? 
+dnl Derrick Brashear
+dnl from Zephyr
+dnl $Id: bsd_sockets.m4,v 1.10 2005/04/26 19:14:07 shadow Exp $
+
+dnl Hacked on by Rob Earhart to not just toss stuff in LIBS
+dnl It now puts everything required for sockets into LIB_SOCKET
+
+AC_DEFUN([AM_WITH_SOCKETS], [
+	save_LIBS="$LIBS"
+	LIB_SOCKET=""
+	AC_CHECK_FUNC(connect, :,
+		AC_CHECK_LIB(nsl, gethostbyname,
+			     LIB_SOCKET="-lnsl $LIB_SOCKET")
+		AC_CHECK_LIB(socket, connect,
+			     LIB_SOCKET="-lsocket $LIB_SOCKET")
+	)
+	LIBS="$LIB_SOCKET $save_LIBS"
+	AC_CHECK_FUNC(res_search, :,
+		LIBS="-lresolv $LIB_SOCKET $save_LIBS"
+		AC_TRY_LINK([[
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+#include <arpa/nameser_compat.h>
+#endif
+#include <resolv.h>]],[[
+const char host[12]="openafs.org";
+u_char ans[1024];
+res_search( host, C_IN, T_MX, (u_char *)&ans, sizeof(ans));
+return 0;
+]], LIB_SOCKET="-lresolv $LIB_SOCKET")
+        )
+	LIBS="$LIB_SOCKET $save_LIBS"
+	AC_CHECK_FUNCS(dn_expand dns_lookup)
+	LIBS="$save_LIBS"
+	AC_SUBST(LIB_SOCKET)
+	])
+ 
diff -r -u -N configure.ac configure.ac
--- configure.ac	2006-09-28 00:49:59.000000000 +0400
+++ configure.ac	2007-02-03 18:55:33.000000000 +0300
@@ -16,6 +16,10 @@
 AM_WITH_EXPAT
 #locating zlib
 AM_WITH_ZLIB
+#locating zlib
+AM_WITH_ZLIB
+#locating socket
+AM_WITH_SOCKETS
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -27,6 +33,7 @@
 AC_FUNC_MALLOC
 AC_HEADER_STDC
 
+AC_MOD_ENABLE(saslauthd, yes)
 AC_MOD_ENABLE(mod_pubsub, yes)
 AC_MOD_ENABLE(mod_irc, yes)
 AC_MOD_ENABLE(mod_muc, yes)
@@ -55,6 +62,7 @@
 AC_SUBST(db_type)
 
 AC_CONFIG_FILES([Makefile
+                 $make_saslauthd
                  $make_mod_irc
                  $make_mod_muc
                  $make_mod_pubsub
diff -r -u -N ejabberd.cfg.example ejabberd.cfg.example
--- ejabberd.cfg.example	2006-09-28 00:49:59.000000000 +0400
+++ ejabberd.cfg.example	2007-02-03 14:24:57.000000000 +0300
@@ -95,6 +95,9 @@
 %{auth_method, odbc}.
 %{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
 
+% If you want to allow both internal and saslauthd authentication:
+{auth_method, [internal, saslauthd]}.
+
 
 % Host name:
 {hosts, ["localhost"]}.
diff -r -u -N Makefile.in Makefile.in
--- Makefile.in	2007-02-03 18:50:19.000000000 +0300
+++ Makefile.in	2007-02-03 18:56:01.000000000 +0300
@@ -27,7 +27,7 @@
 
 prefix = 
 
-SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
+SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ @saslauthd@
 ERLSHLIBS = expat_erl.so
 SOURCES = $(wildcard *.erl)
 BEAMS = $(SOURCES:.erl=.beam)
diff -r -u -N saslauthd/ejabberd_auth_saslauthd.c saslauthd/ejabberd_auth_saslauthd.c
--- saslauthd/ejabberd_auth_saslauthd.c	1970-01-01 03:00:00.000000000 +0300
+++ saslauthd/ejabberd_auth_saslauthd.c	2007-02-03 17:00:41.000000000 +0300
@@ -0,0 +1,476 @@
+/* test-saslauthd.c: saslauthd test utility
+ * Rob Siemborski
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef USE_DOORS
+#include <door.h>
+#endif
+#include <assert.h>
+
+#include <string.h>
+#include <ei.h>
+#include <erl_driver.h>
+#include <sasl/sasl.h>
+
+#define PATH_SASLAUTHD_RUNDIR "/var/run/saslauthd"
+#define LOG_USE_STDERR          (1 << 3) 
+
+int saslauthd_verify_password(const char *saslauthd_path,
+				   const char *userid, 
+				   const char *passwd,
+				   const char *service,
+				   const char *user_realm);
+
+typedef struct
+{
+  ErlDrvPort port;
+} ejabberd_sasl_data;
+
+static void sasl_start(ejabberd_sasl_data* data)
+{
+}
+
+static int login(ejabberd_sasl_data* data,const char* user,const char* pass)
+{
+  int result;
+  const char *out;
+
+  //printf("login %s %s\r\n",user,pass);
+
+  result = saslauthd_verify_password(NULL, user, pass, NULL, NULL); 
+
+  //printf("%s\r\n",sasl_errstring(result,NULL,NULL));
+
+  if(result==0)
+    return 1;
+
+  return 0;
+}
+
+static int exist(ejabberd_sasl_data* data,const char* user)
+{
+  int result;
+  
+  return 0;
+}
+
+static void sasl_stop(ejabberd_sasl_data* data)
+{
+}
+
+#define DECODE_STRING(buffer, index, result)      \
+    {                                             \
+        int tmp = 0; int size = 0;                \
+        ei_get_type(buffer, index, &tmp, &size);  \
+        result = malloc(size + 1);                \
+        ei_decode_string(buffer, index, result);  \
+    }
+
+#define RETURN_INT(value) \
+    {                                             \
+        ErlDrvBinary* b = driver_alloc_binary(1); \
+        rlen = 1;                                 \
+        b->orig_bytes[0] = value;                 \
+        *rbuf = (char*)b;                         \
+        return rlen;                              \
+    }
+
+static ErlDrvData start( ErlDrvPort port, char* command )
+{
+  printf( "SASLD-AUTH driver start\r\n" );
+
+  ejabberd_sasl_data *d = (ejabberd_sasl_data *)driver_alloc( sizeof( ejabberd_sasl_data ));
+  d->port = port;
+  set_port_control_flags( port, PORT_CONTROL_FLAG_BINARY );
+
+  sasl_start(d);
+
+  return (ErlDrvData)d;
+};
+
+static void stop( ErlDrvData handle ) {
+  sasl_stop(handle);
+
+  driver_free( (char *)handle );
+
+  printf( "SASLD-AUTH driver stop\r\n" );
+};
+
+static int er_login(ErlDrvData drv_data, char* buf)
+{
+  int iSize = 0;
+  int iIndex = 0;
+  int iResult = 0;
+  // Parse the version and tuple header
+  ei_decode_version( buf, &iIndex, &iSize );
+  ei_decode_tuple_header( buf, &iIndex, &iSize );
+  if ( iSize == 2 )
+  {
+    const char* user;
+    const char* pass;
+    // The first item in the tuple should be the username
+    DECODE_STRING( buf, &iIndex, user );
+    DECODE_STRING( buf, &iIndex, pass );
+    if(login(drv_data,user,pass))
+      return 1;
+  }else if(iSize==1)
+  {
+    const char* user;
+    DECODE_STRING( buf, &iIndex, user );
+    if(exist(drv_data,user))
+      return 1;
+  }else
+  {
+    ;// wrong args
+  }
+  return 0;
+};
+
+static int control( ErlDrvData drv_data, unsigned int command, char *buf, int len, char** rbuf, int rlen )
+{
+  int iResult;
+  iResult=er_login(drv_data, buf );
+  RETURN_INT( iResult );
+};
+
+static ErlDrvEntry entry =
+{
+  NULL,			/* F_PTR init, N/A */
+  start,		/* L_PTR start, called when port is opened */
+  stop,	        	/* F_PTR stop, called when port is closed */
+  NULL,			/* F_PTR output, called when erlang has sent */
+  NULL,			/* F_PTR ready_input, called when input descriptor ready */
+  NULL,			/* F_PTR ready_output, called when output descriptor ready */
+  "ejabberd_auth_saslauthd",  /* char *driver_name, the argument to open_port */
+  NULL,			/* F_PTR finish, called when unloaded */
+  NULL,			/* handle */
+  control,		/* F_PTR control, port_command callback */
+  NULL,			/* F_PTR timeout, reserved */
+  NULL			/* F_PTR outputv, reserved */
+};
+
+DRIVER_INIT(ejabberd_auth_saslauthd) /* must match name in driver_entry */
+{
+  return &entry;
+};
+
+/* make utils.c happy */
+static int flags = LOG_USE_STDERR;
+
+/*
+ * Keep calling the read() system call with 'fd', 'buf', and 'nbyte'
+ * until all the data is read in or an error occurs.
+ */
+static int retry_read(int fd, void *inbuf, unsigned nbyte)
+{
+    int n;
+    int nread = 0;
+    char *buf = (char *)inbuf;
+
+    if (nbyte == 0) return 0;
+
+    for (;;) {
+	n = read(fd, buf, nbyte);
+	if (n == -1 || n == 0) {
+	    if (errno == EINTR || errno == EAGAIN) continue;
+	    return -1;
+	}
+
+	nread += n;
+
+	if (n >= (int) nbyte) return nread;
+
+	buf += n;
+	nbyte -= n;
+    }
+}
+
+/*
+ * Keep calling the write() system call with 'fd', 'buf', and 'nbyte'
+ * until all the data is written out or an error occurs.
+ */
+int retry_write(int fd, const char *buf, size_t nbyte)
+{
+    int n;
+    int written = 0;
+
+    if (nbyte == 0) return 0;
+
+    for (;;) {
+        n = write(fd, buf, nbyte);
+        if (n == -1) {
+            if (errno == EINTR) continue;
+            return -1;
+        }
+
+        written += n;
+
+        if (((size_t) n) >= nbyte) return written;
+
+        buf += n;
+        nbyte -= n;
+    }
+}
+
+/*
+ * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
+ * until all the data is written out or an error occurs.
+ */
+int
+retry_writev(fd, iov, iovcnt)
+int fd;
+struct iovec *iov;
+int iovcnt;
+{
+    int n;
+    int i;
+    int written = 0;
+    static int iov_max =
+#ifdef MAXIOV
+	MAXIOV
+#else
+#ifdef IOV_MAX
+	IOV_MAX
+#else
+	8192
+#endif
+#endif
+	;
+    
+    for (;;) {
+	while (iovcnt && iov[0].iov_len == 0) {
+	    iov++;
+	    iovcnt--;
+	}
+
+	if (!iovcnt) return written;
+
+	n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
+	if (n == -1) {
+	    if (errno == EINVAL && iov_max > 10) {
+		iov_max /= 2;
+		continue;
+	    }
+	    if (errno == EINTR) continue;
+	    return -1;
+	}
+
+	written += n;
+
+	for (i = 0; i < iovcnt; i++) {
+	    if (iov[i].iov_len > (size_t) n) {
+		iov[i].iov_base = (char *)iov[i].iov_base + n;
+		iov[i].iov_len -= n;
+		break;
+	    }
+	    n -= iov[i].iov_len;
+	    iov[i].iov_len = 0;
+	}
+
+	if (i == iovcnt) return written;
+    }
+}
+
+/* saslauthd-authenticated login */
+int saslauthd_verify_password(const char *saslauthd_path,
+				   const char *userid, 
+				   const char *passwd,
+				   const char *service,
+				   const char *user_realm)
+{
+    char response[1024];
+    char query[8192];
+    char *query_end = query;
+    int s;
+    struct sockaddr_un srvaddr;
+    int r;
+    unsigned short count;
+    void *context;
+    char pwpath[sizeof(srvaddr.sun_path)];
+    const char *p = NULL;
+#ifdef USE_DOORS
+    door_arg_t arg;
+#endif
+
+    if(!service) service = "imap";
+    if(!user_realm) user_realm = "";
+    if(!userid || !passwd) return -1;
+    
+    if (saslauthd_path) {
+	strncpy(pwpath, saslauthd_path, sizeof(pwpath));
+    } else {
+	if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
+	    return -1;
+
+	strcpy(pwpath, PATH_SASLAUTHD_RUNDIR);
+	strcat(pwpath, "/mux");
+    }
+
+    /*
+     * build request of the form:
+     *
+     * count authid count password count service count realm
+     */
+    {
+ 	unsigned short u_len, p_len, s_len, r_len;
+ 	struct iovec iov[8];
+ 
+ 	u_len = htons(strlen(userid));
+ 	p_len = htons(strlen(passwd));
+	s_len = htons(strlen(service));
+	r_len = htons((user_realm ? strlen(user_realm) : 0));
+
+	memcpy(query_end, &u_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	while (*userid) *query_end++ = *userid++;
+
+	memcpy(query_end, &p_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	while (*passwd) *query_end++ = *passwd++;
+
+	memcpy(query_end, &s_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	while (*service) *query_end++ = *service++;
+
+	memcpy(query_end, &r_len, sizeof(unsigned short));
+	query_end += sizeof(unsigned short);
+	if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
+    }
+
+#ifdef USE_DOORS
+    s = open(pwpath, O_RDONLY);
+    if (s < 0) {
+	perror("open");
+	return -1;
+    }
+
+    arg.data_ptr = query;
+    arg.data_size = query_end - query;
+    arg.desc_ptr = NULL;
+    arg.desc_num = 0;
+    arg.rbuf = response;
+    arg.rsize = sizeof(response);
+
+    if(door_call(s, &arg) != 0) {
+	printf("NO \"door_call failed\"\n");
+	return -1;	
+    }
+
+    assert(arg.data_size < sizeof(response));
+    response[arg.data_size] = '\0';
+
+    close(s);
+#else
+    s = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (s == -1) {
+	perror("socket() ");
+	return -1;
+    }
+
+    memset((char *)&srvaddr, 0, sizeof(srvaddr));
+    srvaddr.sun_family = AF_UNIX;
+    strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
+
+    r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+    if (r == -1) {
+        perror("connect() ");
+	return -1;
+    }
+
+    {
+ 	struct iovec iov[8];
+ 
+	iov[0].iov_len = query_end - query;
+	iov[0].iov_base = query;
+
+	if (retry_writev(s, iov, 1) == -1) {
+            fprintf(stderr,"write failed\n");
+  	    return -1;
+  	}
+    }
+  
+    /*
+     * read response of the form:
+     *
+     * count result
+     */
+    if (retry_read(s, &count, sizeof(count)) < (int) sizeof(count)) {
+        fprintf(stderr,"size read failed\n");
+	return -1;
+    }
+  
+    count = ntohs(count);
+    if (count < 2) { /* MUST have at least "OK" or "NO" */
+	close(s);
+        fprintf(stderr,"bad response from saslauthd\n");
+	return -1;
+    }
+  
+    count = (int)sizeof(response) < count ? sizeof(response) : count;
+    if (retry_read(s, response, count) < count) {
+	close(s);
+        fprintf(stderr,"read failed\n");
+	return -1;
+    }
+    response[count] = '\0';
+  
+    close(s);
+#endif /* USE_DOORS */
+  
+    if (!strncmp(response, "OK", 2)) {
+	printf("OK \"Success.\"\n");
+	return 0;
+    }
+  
+    printf("NO \"authentication failed\"\n");
+    return -1;
+}
diff -r -u -N saslauthd/ejabberd_auth_saslauthd.erl saslauthd/ejabberd_auth_saslauthd.erl
--- saslauthd/ejabberd_auth_saslauthd.erl	1970-01-01 03:00:00.000000000 +0300
+++ saslauthd/ejabberd_auth_saslauthd.erl	2007-02-03 14:47:51.000000000 +0300
@@ -0,0 +1,70 @@
+-module(ejabberd_auth_saslauthd).
+-author('').
+
+-export([
+         start/1,
+         plain_password_required/0, 
+         set_password/3, 
+	 try_register/3,
+         remove_user/2,
+         remove_user/3, 
+         get_password/2,
+         get_password_s/2,
+         is_user_exists/2,
+         get_vh_registered_users/1,
+         check_password/3,
+	 check_password/5
+        ]).
+
+start( _Host ) ->
+  case erl_ddll:load_driver( ejabberd:get_so_path(), ejabberd_auth_saslauthd) of
+    ok -> ok;
+    {error, already_loaded} -> ok;
+    Error -> exit({error, could_not_load_driver, Error})
+  end.
+
+plain_password_required() ->
+  true.
+
+check_password( User, Server, Password ) ->
+  Port = open_port( { spawn, ejabberd_auth_saslauthd }, [ binary ] ),
+  Bin = term_to_binary( { User, Password }),
+  Res = port_control( Port, 0, Bin ),
+  case Res of
+    <<1>> -> true;
+    _ -> false
+  end.
+
+check_password( User, Server, Password,  _StreamID, _Digest ) ->
+  check_password( User, Server,  Password ).
+
+set_password( _User, _Server, _Password ) ->
+  { error, not_allowed }.
+
+try_register( _User, _Server, _Password ) ->
+  { error, not_allowed }.
+
+remove_user( _User, _Server ) ->
+  { error, not_allowed }.
+
+remove_user( _User, _Server, _Password ) ->
+  { error, not_allowed }.
+    
+get_vh_registered_users( _Server ) ->
+  [].
+    
+is_user_exists( _User, _Server ) ->
+  Port = open_port( { spawn, ejabberd_auth_sasld }, [ binary ] ),
+  Bin = term_to_binary( { _User }),
+  Res = port_control( Port, 0, Bin ),
+  case Res of
+    <<1>> -> true;
+    _ -> false
+  end.
+
+get_password( _User, _Server ) ->
+  false.
+
+get_password_s( _User, _Server ) ->
+  "".
+
diff -r -u -N saslauthd/Makefile.in saslauthd/Makefile.in
--- saslauthd/Makefile.in	1970-01-01 03:00:00.000000000 +0300
+++ saslauthd/Makefile.in	2007-02-03 14:24:57.000000000 +0300
@@ -0,0 +1,35 @@
+# $Id: Makefile.in 285 2006-12-11 10:16:21Z $
+
+CC = @CC@
+CFLAGS = @CFLAGS@ @ERLANG_CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@ @ERLANG_LIBS@ @LIB_SOCKET@
+
+SUBDIRS = 
+
+ERLSHLIBS = ../ejabberd_auth_saslauthd.so
+
+OUTDIR = ..
+EFLAGS = -I .. -pz ..
+OBJS   = \
+	$(OUTDIR)/ejabberd_auth_saslauthd.beam
+
+all:    $(OBJS) $(ERLSHLIBS)
+
+$(OUTDIR)/%.beam:       %.erl
+	@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
+
+$(ERLSHLIBS):	../%.so:	%.c
+	$(CC) -Wall $(CFLAGS) $(LDFLAGS) \
+	$(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
+	-o $@ -fpic -shared
+
+clean:
+	rm -f $(OBJS) $(ERLSHLIBS)
+
+distclean: clean
+	rm -f Makefile
+
+TAGS:
+	etags *.erl
