]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_ldapoper.cpp
Windows: In-depth cleanup (see details)
[user/henk/code/inspircd.git] / src / modules / extra / m_ldapoper.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
5  *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
6  *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
7  *   Copyright (C) 2007 Carsten Valdemar Munk <carsten.munk+inspircd@gmail.com>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include "users.h"
25 #include "channels.h"
26 #include "modules.h"
27
28 #include <ldap.h>
29
30 #ifdef _WIN32
31 # pragma comment(lib, "ldap.lib")
32 # pragma comment(lib, "lber.lib")
33 #endif
34
35 /* $ModDesc: Adds the ability to authenticate opers via LDAP */
36 /* $LinkerFlags: -lldap */
37
38 class ModuleLDAPAuth : public Module
39 {
40         std::string base;
41         std::string ldapserver;
42         std::string username;
43         std::string password;
44         int searchscope;
45         LDAP *conn;
46
47 public:
48         ModuleLDAPAuth()
49                 {
50                 conn = NULL;
51                 Implementation eventlist[] = { I_OnRehash, I_OnPassCompare };
52                 ServerInstance->Modules->Attach(eventlist, this, 2);
53                 OnRehash(NULL);
54         }
55
56         virtual ~ModuleLDAPAuth()
57         {
58                 if (conn)
59                         ldap_unbind_ext(conn, NULL, NULL);
60         }
61
62         virtual void OnRehash(User* user)
63         {
64                 ConfigReader Conf;
65
66                 base                    = Conf.ReadValue("ldapoper", "baserdn", 0);
67                 ldapserver              = Conf.ReadValue("ldapoper", "server", 0);
68                 std::string scope       = Conf.ReadValue("ldapoper", "searchscope", 0);
69                 username                = Conf.ReadValue("ldapoper", "binddn", 0);
70                 password                = Conf.ReadValue("ldapoper", "bindauth", 0);
71
72                 if (scope == "base")
73                         searchscope = LDAP_SCOPE_BASE;
74                 else if (scope == "onelevel")
75                         searchscope = LDAP_SCOPE_ONELEVEL;
76                 else searchscope = LDAP_SCOPE_SUBTREE;
77
78                 Connect();
79         }
80
81         bool Connect()
82         {
83                 if (conn != NULL)
84                         ldap_unbind_ext(conn, NULL, NULL);
85                 int res, v = LDAP_VERSION3;
86                 res = ldap_initialize(&conn, ldapserver.c_str());
87                 if (res != LDAP_SUCCESS)
88                 {
89                         conn = NULL;
90                         return false;
91                 }
92
93                 res = ldap_set_option(conn, LDAP_OPT_PROTOCOL_VERSION, (void *)&v);
94                 if (res != LDAP_SUCCESS)
95                 {
96                         ldap_unbind_ext(conn, NULL, NULL);
97                         conn = NULL;
98                         return false;
99                 }
100                 return true;
101         }
102
103         virtual ModResult OnPassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
104         {
105                 if (hashtype == "ldap")
106                 {
107                         if (LookupOper(data, input))
108                                 /* This is an ldap oper and has been found, claim the OPER command */
109                                 return MOD_RES_ALLOW;
110                         else
111                                 return MOD_RES_DENY;
112                 }
113                 /* We don't know this oper! */
114                 return MOD_RES_PASSTHRU;
115         }
116
117         bool LookupOper(const std::string &what, const std::string &opassword)
118         {
119                 if (conn == NULL)
120                         if (!Connect())
121                                 return false;
122
123                 int res;
124                 char* authpass = strdup(password.c_str());
125                 // bind anonymously if no bind DN and authentication are given in the config
126                 struct berval cred;
127                 cred.bv_val = authpass;
128                 cred.bv_len = password.length();
129
130                 if ((res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) != LDAP_SUCCESS)
131                 {
132                         if (res == LDAP_SERVER_DOWN)
133                         {
134                                 // Attempt to reconnect if the connection dropped
135                                 ServerInstance->SNO->WriteToSnoMask('a', "LDAP server has gone away - reconnecting...");
136                                 Connect();
137                                 res = ldap_sasl_bind_s(conn, username.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
138                         }
139
140                         if (res != LDAP_SUCCESS)
141                         {
142                                 free(authpass);
143                                 ldap_unbind_ext(conn, NULL, NULL);
144                                 conn = NULL;
145                                 return false;
146                         }
147                 }
148                 free(authpass);
149
150                 LDAPMessage *msg, *entry;
151                 if ((res = ldap_search_ext_s(conn, base.c_str(), searchscope, what.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS)
152                 {
153                         return false;
154                 }
155                 if (ldap_count_entries(conn, msg) > 1)
156                 {
157                         ldap_msgfree(msg);
158                         return false;
159                 }
160                 if ((entry = ldap_first_entry(conn, msg)) == NULL)
161                 {
162                         ldap_msgfree(msg);
163                         return false;
164                 }
165                 authpass = strdup(opassword.c_str());
166                 cred.bv_val = authpass;
167                 cred.bv_len = opassword.length();
168                 if ((res = ldap_sasl_bind_s(conn, ldap_get_dn(conn, entry), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL)) == LDAP_SUCCESS)
169                 {
170                         free(authpass);
171                         ldap_msgfree(msg);
172                         return true;
173                 }
174                 else
175                 {
176                         free(authpass);
177                         ldap_msgfree(msg);
178                         return false;
179                 }
180         }
181
182         virtual Version GetVersion()
183         {
184                 return Version("Adds the ability to authenticate opers via LDAP", VF_VENDOR);
185         }
186
187 };
188
189 MODULE_INIT(ModuleLDAPAuth)