]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/extra/m_ldapoper.cpp
Change Windows libraries to be dynamically linked
[user/henk/code/inspircd.git] / src / modules / extra / m_ldapoper.cpp
index 68e7ffc28bfcbbcfda166ed499ceb92ada40f485..1f46361d4d34555b50c71b07f423d506893d6425 100644 (file)
@@ -1,26 +1,25 @@
-/*       +------------------------------------+
- *       | Inspire Internet Relay Chat Daemon |
- *       +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
  *
- *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
- * See: http://wiki.inspircd.org/Credits
+ *   Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ *   Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
  *
- * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ * This file is part of InspIRCd.  InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
  *
- * ---------------------------------------------------
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
  *
- * Taken from the UnrealIRCd 4.0 SVN version, based on
- * InspIRCd 1.1.x.
- *
- * UnrealIRCd 4.0 (C) 2007 Carsten Valdemar Munk
- * This program is free but copyrighted software; see
- *         the file COPYING for details.
- *
- * ---------------------------------------------------
- * Heavily based on SQLauth
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+
 #include "inspircd.h"
 #include "users.h"
 #include "channels.h"
 
 #include <ldap.h>
 
-/* $ModDesc: Allow/Deny connections based upon answer from LDAP server */
+#ifdef _WIN32
+# pragma comment(lib, "libldap.lib")
+# pragma comment(lib, "liblber.lib")
+#endif
+
+/* $ModDesc: Adds the ability to authenticate opers via LDAP */
 /* $LinkerFlags: -lldap */
 
+// Duplicated code, also found in cmd_oper and m_sqloper
+static bool OneOfMatches(const char* host, const char* ip, const std::string& hostlist)
+{
+       std::stringstream hl(hostlist);
+       std::string xhost;
+       while (hl >> xhost)
+       {
+               if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map))
+               {
+                       return true;
+               }
+       }
+       return false;
+}
+
+struct RAIILDAPString
+{
+       char *str;
+
+       RAIILDAPString(char *Str)
+               : str(Str)
+       {
+       }
+
+       ~RAIILDAPString()
+       {
+               ldap_memfree(str);
+       }
+
+       operator char*()
+       {
+               return str;
+       }
+
+       operator std::string()
+       {
+               return str;
+       }
+};
+
 class ModuleLDAPAuth : public Module
 {
        std::string base;
        std::string ldapserver;
        std::string username;
        std::string password;
+       std::string attribute;
        int searchscope;
        LDAP *conn;
 
+       bool HandleOper(LocalUser* user, const std::string& opername, const std::string& inputpass)
+       {
+               OperIndex::iterator it = ServerInstance->Config->oper_blocks.find(opername);
+               if (it == ServerInstance->Config->oper_blocks.end())
+                       return false;
+
+               ConfigTag* tag = it->second->oper_block;
+               if (!tag)
+                       return false;
+
+               std::string acceptedhosts = tag->getString("host");
+               std::string hostname = user->ident + "@" + user->host;
+               if (!OneOfMatches(hostname.c_str(), user->GetIPString(), acceptedhosts))
+                       return false;
+
+               if (!LookupOper(opername, inputpass))
+                       return false;
+
+               user->Oper(it->second);
+               return true;
+       }
+
 public:
-       ModuleLDAPAuth(InspIRCd* Me)
-       : Module(Me)
+       ModuleLDAPAuth()
+               : conn(NULL)
+       {
+       }
+
+       void init()
        {
-               conn = NULL;
-               Implementation eventlist[] = { I_OnRehash, I_OnPassCompare };
-               ServerInstance->Modules->Attach(eventlist, this, 2);
-               OnRehash(NULL,"");
+               Implementation eventlist[] = { I_OnRehash, I_OnPreCommand };
+               ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+               OnRehash(NULL);
        }
 
        virtual ~ModuleLDAPAuth()
@@ -56,15 +126,16 @@ public:
                        ldap_unbind_ext(conn, NULL, NULL);
        }
 
-       virtual void OnRehash(User* user, const std::string &parameter)
+       virtual void OnRehash(User* user)
        {
-               ConfigReader Conf(ServerInstance);
+               ConfigTag* tag = ServerInstance->Config->ConfValue("ldapoper");
 
-               base                    = Conf.ReadValue("ldapoper", "baserdn", 0);
-               ldapserver              = Conf.ReadValue("ldapoper", "server", 0);
-               std::string scope       = Conf.ReadValue("ldapoper", "searchscope", 0);
-               username                = Conf.ReadValue("ldapoper", "binddn", 0);
-               password                = Conf.ReadValue("ldapoper", "bindauth", 0);
+               base                    = tag->getString("baserdn");
+               ldapserver              = tag->getString("server");
+               std::string scope       = tag->getString("searchscope");
+               username                = tag->getString("binddn");
+               password                = tag->getString("bindauth");
+               attribute               = tag->getString("attribute");
 
                if (scope == "base")
                        searchscope = LDAP_SCOPE_BASE;
@@ -97,22 +168,17 @@ public:
                return true;
        }
 
-       virtual int OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
+       ModResult OnPreCommand(std::string& command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string& original_line)
        {
-               User* user = dynamic_cast<User*>(ex);
-               if (hashtype == "ldap")
+               if (validated && command == "OPER" && parameters.size() >= 2)
                {
-                       if (LookupOper(user, data, input))
-                       {
-                               /* This is an ldap oper and has been found, claim the OPER command */
-                               return 1;
-                       }
+                       if (HandleOper(user, parameters[0], parameters[1]))
+                               return MOD_RES_DENY;
                }
-               /* We don't know this oper! */
-               return 0;
+               return MOD_RES_PASSTHRU;
        }
 
-       bool LookupOper(User* user, const std::string &what, const std::string &opassword)
+       bool LookupOper(const std::string& opername, const std::string& opassword)
        {
                if (conn == NULL)
                        if (!Connect())
@@ -127,14 +193,26 @@ public:
 
                if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
                {
-                       free(authpass);
-                       ldap_unbind_ext(conn, NULL, NULL);
-                       conn = NULL;
-                       return false;
+                       if (res == LDAP_SERVER_DOWN)
+                       {
+                               // Attempt to reconnect if the connection dropped
+                               ServerInstance->SNO->WriteToSnoMask('a', "LDAP server has gone away - reconnecting...");
+                               Connect();
+                               res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
+                       }
+
+                       if (res != LDAP_SUCCESS)
+                       {
+                               free(authpass);
+                               ldap_unbind_ext(conn, NULL, NULL);
+                               conn = NULL;
+                               return false;
+                       }
                }
                free(authpass);
 
                LDAPMessage *msg, *entry;
+               std::string what = attribute + "=" + opername;
                if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
                {
                        return false;
@@ -152,7 +230,8 @@ public:
                authpass = strdup(opassword.c_str());
                cred.bv_val = authpass;
                cred.bv_len = opassword.length();
-               if ((res = ldap_sasl_bind_s(conn, ldap_get_dn(conn, entry), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
+               RAIILDAPString DN(ldap_get_dn(conn, entry));
+               if ((res = ldap_sasl_bind_s(conn, DN, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
                {
                        free(authpass);
                        ldap_msgfree(msg);
@@ -168,7 +247,7 @@ public:
 
        virtual Version GetVersion()
        {
-               return Version("$Id$", VF_VENDOR, API_VERSION);
+               return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
        }
 
 };