From 3f27be8bde34420d7278450fee5d26156bc48b32 Mon Sep 17 00:00:00 2001 From: psychon Date: Sun, 25 Nov 2007 17:35:36 +0000 Subject: [PATCH] Add saslauth. This modules has been waiting in crox' branch for like ever git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@880 726aef4b-f618-498e-8847-2d620e286838 --- configure.in | 14 ++++++ modules/Makefile.in | 17 ++++++++ modules/saslauth.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 modules/saslauth.cpp diff --git a/configure.in b/configure.in index 5e6d6156..c30d6206 100644 --- a/configure.in +++ b/configure.in @@ -84,6 +84,9 @@ AC_ARG_ENABLE( [openssl], AC_ARG_ENABLE( [perl], AC_HELP_STRING([--disable-perl], [disable perl]), [if test "$enableval" = "no" ; then NOPERL=1; fi],) +AC_ARG_ENABLE( [sasl], + AC_HELP_STRING([--enable-sasl], [enable sasl]), + [if test "$enableval" = "yes" ; then SASL=1; fi],) appendCXX -Wall -W -Wno-unused @@ -169,6 +172,11 @@ if test "$MODULES" = "yes"; then AC_ERROR([Could not find perl binary. Try --disable-perl]) fi fi + + if test -n "$SASL"; then + AC_CHECK_LIB( sasl2, sasl_server_init,, + AC_ERROR([Could not find libsasl2.])) + fi fi fi @@ -187,6 +195,7 @@ AC_SUBST([MODTARGET]) AC_SUBST([VERSION]) AC_SUBST([NOSSL]) AC_SUBST([PERL]) +AC_SUBST([SASL]) AC_SUBST([MODDIR]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([znc-config]) @@ -211,4 +220,9 @@ if test x"$PERL" = "x" ; then else echo "perl: yes" fi +if test x"$SASL" = "x" ; then + echo "sasl: no" +else + echo "sasl: yes" +fi diff --git a/modules/Makefile.in b/modules/Makefile.in index 24fc6d12..52a0da8d 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -26,6 +26,10 @@ PERLHOOK := FILES := $(shell echo $(FILES) | sed -e "s/modperl//") endif +ifeq "@SASL@" "" +FILES := $(shell echo $(FILES) | sed -e "s/saslauth//") +endif + SRCS := $(wildcard ../*.cpp) $(addsuffix .cpp, $(FILES)) OBJS := $(addsuffix .o, $(FILES)) TARGETS := $(addsuffix .so, $(FILES)) @@ -84,4 +88,17 @@ modperl_install: @echo -n "" endif +ifeq "@SASL@" "1" +saslauth.so: saslauth.o + $(CXX) $(LDFLAGS) -shared -o $@ $< -lsasl2 + +saslauth.o: saslauth.cpp + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $< +else +saslauth.so: + @echo -n "" +saslauth.o: + @echo -n "" +endif + -include .depend diff --git a/modules/saslauth.cpp b/modules/saslauth.cpp new file mode 100644 index 00000000..5ac6f045 --- /dev/null +++ b/modules/saslauth.cpp @@ -0,0 +1,101 @@ +/** + * @class CSASLAuthMod + * @author Heiko Hund + * @brief SASL authentication module for znc. + * + * Licensed under the GPLv2. + */ + +#include + +#include "Modules.h" +#include "znc.h" + +class CSASLAuthMod : public CGlobalModule { +public: + GLOBALMODCONSTRUCTOR(CSASLAuthMod) { + m_Cache.SetTTL(60000/*ms*/); + } + virtual ~CSASLAuthMod() {} + + virtual bool OnBoot() { + return true; + } + + virtual bool OnLoad(const CString& sArgs, CString& sMessage) { + int i(0); + CString arg(sArgs.Token(i)); + + while (!arg.empty()) { + if (arg.StrCmp("saslauthd") || arg.StrCmp("auxprop")) { + method += arg + " "; + } + else { + CUtils::PrintError("Ignoring invalid SASL pwcheck method: " + arg); + } + arg = sArgs.Token(++i); + } + method.TrimRight(); + + if (sasl_server_init(NULL, NULL) != SASL_OK){ + CUtils::PrintError("SASL Could Not Be Initialized - Halting Startup"); + return false; + } + + return true; + } + + virtual EModRet OnLoginAttempt(CSmartPtr Auth) { + CString const user(Auth->GetUsername()); + CString const pass(Auth->GetPassword()); + CUser* pUser(CZNC::Get().FindUser(user)); + sasl_conn_t *sasl_conn(0); + + if (!pUser) { // @todo Will want to do some sort of && !m_bAllowCreate in the future + Auth->RefuseLogin("Invalid User - Halting SASL Authentication"); + return HALT; + } + + CString const key(CString(user + ":" + pass).MD5()); + if (m_Cache.HasItem(key)) { + Auth->AcceptLogin(*pUser); + DEBUG_ONLY(cerr << "+++ Found in cache" << endl); + } + else if (sasl_server_new("znc", NULL, NULL, NULL, NULL, cbs, 0, &sasl_conn) == SASL_OK && + sasl_checkpass(sasl_conn, user.c_str(), user.size(), pass.c_str(), pass.size()) == SASL_OK) { + Auth->AcceptLogin(*pUser); + m_Cache.AddItem(key); + DEBUG_ONLY(cerr << "+++ Successful SASL password check" << endl); + } + else { + Auth->RefuseLogin("SASL Authentication failed"); + DEBUG_ONLY(cerr << "--- FAILED SASL password check" << endl); + } + + sasl_dispose(&sasl_conn); + return HALT; + } + +private: + TCacheMap m_Cache; + + static sasl_callback_t cbs[]; + static CString method; + + static int getopt(void *context, const char *plugin_name, const char *option, const char **result, unsigned *len) { + if (!method.empty() && strcmp(option, "pwcheck_method") == 0) { + *result = method.c_str(); + return SASL_OK; + } + return SASL_CONTINUE; + } +}; + +sasl_callback_t CSASLAuthMod::cbs[] = { + { SASL_CB_GETOPT, reinterpret_cast(CSASLAuthMod::getopt), NULL }, + { SASL_CB_LIST_END, NULL, NULL } +}; + +CString CSASLAuthMod::method; + +GLOBALMODULEDEFS(CSASLAuthMod, "Allow users to authenticate via SASL password verification method")