ejabberd_auth_sasl-1.0.0

SASL2 auth library, like http://www.ejabberd.im/pam

Quote:

diff -r -u -N src/aclocal.m4 src/aclocal.m4
--- src/aclocal.m4 2007-01-29 19:21:57.000000000 +0300
+++ src/aclocal.m4 2007-01-30 00:50:11.000000000 +0300
@@ -321,3 +321,36 @@
AC_SUBST(PAM_LIBS)
fi
])
+
+AC_DEFUN(AM_WITH_SASL,
+[ AC_ARG_WITH(sasl2, [ --with-sasl=PREFIX prefix where SASL is installed ])
+unset SASL_LIBS;
+unset SASL_CFLAGS;
+
+if test x"$with_sasl" != x; then
+ SASL_CFLAGS="-I$with_sasl/include"
+ SASL_LIBS="-L$with_sasl/lib"
+fi
+
+AC_CHECK_LIB(sasl2, sasl_server_init,
+ [ SASL_LIBS="$SASL_LIBS -lsasl2" sasl_found=yes ],
+ [ sasl_found=no ],
+ "$SASL_LIBS")
+
+if test $sasl_found = no; then
+ AC_MSG_ERROR([Could not find sasl/sasl.h])
+fi
+
+if test $sasl_found = yes; then
+ sasl_save_CFLAGS="$CFLAGS"
+ CFLAGS="$SASL_CFLAGS $CFLAGS"
+ AC_CHECK_HEADERS(sasl/sasl.h, ,$sasl_found=no)
+ if test $sasl_found = no; then
+ AC_MSG_ERROR([Could not find sasl/sasl.h])
+ fi
+ CFLAGS=$sasl_save_CFLAGS
+
+ AC_SUBST(SASL_CFLAGS)
+ AC_SUBST(SASL_LIBS)
+fi
+])
diff -r -u -N src/configure.ac src/configure.ac
--- src/configure.ac 2007-01-29 19:21:57.000000000 +0300
+++ src/configure.ac 2007-01-29 22:11:44.000000000 +0300
@@ -20,6 +20,8 @@
AM_WITH_ZLIB
#locating Linux-PAM
AM_WITH_PAM
+# for SASL
+AM_WITH_SASL

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -32,6 +34,7 @@
AC_HEADER_STDC

AC_MOD_ENABLE(pam, yes)
+AC_MOD_ENABLE(sasl, yes)
AC_MOD_ENABLE(mod_pubsub, yes)
AC_MOD_ENABLE(mod_irc, yes)
AC_MOD_ENABLE(mod_muc, yes)
@@ -61,6 +64,7 @@

AC_CONFIG_FILES([Makefile
$make_pam
+ $make_sasl
$make_mod_irc
$make_mod_muc
$make_mod_pubsub
diff -r -u -N src/Makefile.in src/Makefile.in
--- src/Makefile.in 2007-01-29 19:21:57.000000000 +0300
+++ src/Makefile.in 2007-01-29 22:04:06.000000000 +0300
@@ -27,7 +27,7 @@

prefix =

-SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ @pam@
+SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ @pam@ @sasl@
ERLSHLIBS = expat_erl.so
SOURCES = $(wildcard *.erl)
BEAMS = $(SOURCES:.erl=.beam)
diff -r -u -N src/sasl/ejabberd_auth_sasl.c src/sasl/ejabberd_auth_sasl.c
--- src/sasl/ejabberd_auth_sasl.c 1970-01-01 03:00:00.000000000 +0300
+++ src/sasl/ejabberd_auth_sasl.c 2007-01-30 00:56:31.000000000 +0300
@@ -0,0 +1,175 @@
+#include
+#include
+#include
+#include
+#include
+
+typedef struct
+{
+ ErlDrvPort port;
+
+ /* The SASL context kept for the life of the connection */
+ sasl_conn_t *conn;
+
+} ejabberd_sasl_data;
+
+void sasl_start(ejabberd_sasl_data* data)
+{
+ int result;
+
+ /* Initialize SASL */
+ result=sasl_server_init(NULL, /* Callbacks supported */
+ "TestServer"); /* Name of the application */
+
+ /* Make a new context for this connection */
+ result=sasl_server_new("ejabberd_auth_sasl", /* Registered name of service */
+ NULL, /* my fully qualified domain name;
+ NULL says use gethostname() */
+ NULL, /* The user realm used for password
+ lookups; NULL means default to serverFQDN
+ Note: This does not affect Kerberos */
+ NULL, NULL, /* IP Address information strings */
+ NULL, /* Callbacks supported only for this connection */
+ 0, /* security flags (security layers are enabled
+ * using security properties, separately)*/
+ &data->conn);
+}
+
+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=sasl_checkpass(data->conn,user,strlen(user),pass,strlen(pass));
+
+ //printf("%s\r\n",sasl_errstring(result,NULL,NULL));
+
+ if(result==SASL_OK)
+ return 1;
+
+ return 0;
+}
+
+int exist(ejabberd_sasl_data* data,const char* user)
+{
+ int result;
+ const char *out;
+
+ //printf("exist %s\r\n",user);
+
+ result=sasl_user_exists(data->conn,"ejabberd_auth_sasl",NULL,user);
+
+ //printf("%s\r\n",sasl_errstring(result,NULL,NULL));
+
+ if(result)!=SASL_NOUSER)
+ return 1;
+
+ return 0;
+}
+
+void sasl_stop(ejabberd_sasl_data* data)
+{
+ int result;
+
+ sasl_dispose(&data->conn);
+ sasl_done();
+}
+
+#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( "SASL-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( "SASL-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_sasl", /* 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_sasl) /* must match name in driver_entry */
+{
+ return &entry;
+};
+
diff -r -u -N src/sasl/ejabberd_auth_sasl.erl src/sasl/ejabberd_auth_sasl.erl
--- src/sasl/ejabberd_auth_sasl.erl 1970-01-01 03:00:00.000000000 +0300
+++ src/sasl/ejabberd_auth_sasl.erl 2007-01-30 00:55:13.000000000 +0300
@@ -0,0 +1,70 @@
+-module(ejabberd_auth_sasl).
+-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_sasl) 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_sasl }, [ 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_sasl }, [ 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 src/sasl/Makefile.in src/sasl/Makefile.in
--- src/sasl/Makefile.in 1970-01-01 03:00:00.000000000 +0300
+++ src/sasl/Makefile.in 2007-01-30 00:34:06.000000000 +0300
@@ -0,0 +1,35 @@
+# $Id: Makefile.in 285 2006-12-11 10:16:21Z $
+
+CC = @CC@
+CFLAGS = @CFLAGS@ @PAM_CFLAGS@ @SASL_CFLAGS@ @ERLANG_CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@ @SASL_LIBS@ @ERLANG_LIBS@
+
+SUBDIRS =
+
+ERLSHLIBS = ../ejabberd_auth_sasl.so
+
+OUTDIR = ..
+EFLAGS = -I .. -pz ..
+OBJS = \
+ $(OUTDIR)/ejabberd_auth_sasl.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

Some silly questions

Hi, I'd like to add your patch to the Contributions page, but since I don't know much about SASL and PAM, let me ask some (silly) questions:

  • Is SASL a different authentication method than PAM?
  • If they are different, how can an admin configure ejabberd to use SASL, once he installs and compiles your patch?
  • Does your SASL method require the PAM patch to be installed, or are they independent?

SASL

Hi!

* SASL is protocol specification for security authentication, is not authentication mechanism like PAM. I use SASL not by specification, because transport layer implementation available in ejabber code.

Example:
SASL client - (network - sasl lib) - SASL server

SASL server library send client request to server side, and your server-side realization can pass thought client request to auth mechanism, supported by sasl library;

SASL client [make pair (name,pass)] -> | SASL API | -> SASL Server side -> |SASL API| -> Your implementation ->
|SASL AUTH API|

http://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer

Next. I say about partial implementation of SASL library, because i use only SASL AUTH API, all transport layer eabberd specific.

* Auth api is very simply to PAM, but no configuration available at now.

* required ejabberd-1.1.2 only;

this patch better then pam patch because have correct exist_user function.

I've uploaded the patch

I've uploaded the patch (slightly fixed), and added a page to Contributions: Authenticate Against SASL.

Syndicate content