00001
00002
00003 #include "module.h"
00004 #include "ldap.h"
00005 #include <ldap.h>
00006
00007 static Pipe *me;
00008
00009 class LDAPService : public LDAPProvider, public Thread, public Condition
00010 {
00011 Anope::string server;
00012 int port;
00013 Anope::string admin_binddn;
00014 Anope::string admin_pass;
00015
00016 LDAP *con;
00017
00018 time_t last_connect;
00019
00020 LDAPMod **BuildMods(const LDAPMods &attributes)
00021 {
00022 LDAPMod **mods = new LDAPMod*[attributes.size() + 1];
00023 memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1));
00024 for (unsigned x = 0; x < attributes.size(); ++x)
00025 {
00026 const LDAPModification &l = attributes[x];
00027 mods[x] = new LDAPMod();
00028
00029 if (l.op == LDAPModification::LDAP_ADD)
00030 mods[x]->mod_op = LDAP_MOD_ADD;
00031 else if (l.op == LDAPModification::LDAP_DEL)
00032 mods[x]->mod_op = LDAP_MOD_DELETE;
00033 else if (l.op == LDAPModification::LDAP_REPLACE)
00034 mods[x]->mod_op = LDAP_MOD_REPLACE;
00035 else if (l.op != 0)
00036 throw LDAPException("Unknown LDAP operation");
00037 mods[x]->mod_type = strdup(l.name.c_str());
00038 mods[x]->mod_values = new char*[l.values.size() + 1];
00039 memset(mods[x]->mod_values, 0, sizeof(char *) * (l.values.size() + 1));
00040 for (unsigned j = 0, c = 0; j < l.values.size(); ++j)
00041 if (!l.values[j].empty())
00042 mods[x]->mod_values[c++] = strdup(l.values[j].c_str());
00043 }
00044 return mods;
00045 }
00046
00047 void FreeMods(LDAPMod **mods)
00048 {
00049 for (int i = 0; mods[i] != NULL; ++i)
00050 {
00051 free(mods[i]->mod_type);
00052 for (int j = 0; mods[i]->mod_values[j] != NULL; ++j)
00053 free(mods[i]->mod_values[j]);
00054 delete [] mods[i]->mod_values;
00055 }
00056 delete [] mods;
00057 }
00058
00059 void Reconnect()
00060 {
00061
00062 if (last_connect > Anope::CurTime - 60)
00063 throw LDAPException("Unable to connect to LDAP service " + this->name + ": reconnecting too fast");
00064 last_connect = Anope::CurTime;
00065
00066 ldap_unbind_ext(this->con, NULL, NULL);
00067 int i = ldap_initialize(&this->con, this->server.c_str());
00068 if (i != LDAP_SUCCESS)
00069 throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
00070 }
00071
00072 public:
00073 typedef std::map<int, LDAPInterface *> query_queue;
00074 typedef std::vector<std::pair<LDAPInterface *, LDAPResult *> > result_queue;
00075 query_queue queries;
00076 result_queue results;
00077
00078 LDAPService(Module *o, const Anope::string &n, const Anope::string &s, int po, const Anope::string &b, const Anope::string &p) : LDAPProvider(o, "ldap/" + n), server(s), port(po), admin_binddn(b), admin_pass(p), last_connect(0)
00079 {
00080 int i = ldap_initialize(&this->con, this->server.c_str());
00081 if (i != LDAP_SUCCESS)
00082 throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
00083 static const int version = LDAP_VERSION3;
00084 i = ldap_set_option(this->con, LDAP_OPT_PROTOCOL_VERSION, &version);
00085 if (i != LDAP_OPT_SUCCESS)
00086 throw LDAPException("Unable to set protocol version for " + this->name + ": " + ldap_err2string(i));
00087 }
00088
00089 ~LDAPService()
00090 {
00091 this->Lock();
00092
00093 for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end; ++it)
00094 {
00095 ldap_abandon_ext(this->con, it->first, NULL, NULL);
00096 it->second->OnDelete();
00097 }
00098 this->queries.clear();
00099
00100 for (result_queue::iterator it = this->results.begin(), it_end = this->results.end(); it != it_end; ++it)
00101 {
00102 it->second->error = "LDAP Interface is going away";
00103 it->first->OnError(*it->second);
00104 }
00105 this->results.clear();
00106
00107 this->Unlock();
00108
00109 ldap_unbind_ext(this->con, NULL, NULL);
00110 }
00111
00112 LDAPQuery BindAsAdmin(LDAPInterface *i)
00113 {
00114 return this->Bind(i, this->admin_binddn, this->admin_pass);
00115 }
00116
00117 LDAPQuery Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) anope_override
00118 {
00119 berval cred;
00120 cred.bv_val = strdup(pass.c_str());
00121 cred.bv_len = pass.length();
00122
00123 LDAPQuery msgid;
00124 int ret = ldap_sasl_bind(con, who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid);
00125 free(cred.bv_val);
00126 if (ret != LDAP_SUCCESS)
00127 {
00128 if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
00129 {
00130 this->Reconnect();
00131 return this->Bind(i, who, pass);
00132 }
00133 else
00134 throw LDAPException(ldap_err2string(ret));
00135 }
00136
00137 if (i != NULL)
00138 {
00139 this->Lock();
00140 this->queries[msgid] = i;
00141 this->Unlock();
00142 }
00143 this->Wakeup();
00144
00145 return msgid;
00146 }
00147
00148 LDAPQuery Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) anope_override
00149 {
00150 if (i == NULL)
00151 throw LDAPException("No interface");
00152
00153 LDAPQuery msgid;
00154 int ret = ldap_search_ext(this->con, base.c_str(), LDAP_SCOPE_SUBTREE, filter.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msgid);
00155 if (ret != LDAP_SUCCESS)
00156 {
00157 if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
00158 {
00159 this->Reconnect();
00160 return this->Search(i, base, filter);
00161 }
00162 else
00163 throw LDAPException(ldap_err2string(ret));
00164 }
00165
00166 this->Lock();
00167 this->queries[msgid] = i;
00168 this->Unlock();
00169 this->Wakeup();
00170
00171 return msgid;
00172 }
00173
00174 LDAPQuery Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) anope_override
00175 {
00176 LDAPMod **mods = this->BuildMods(attributes);
00177 LDAPQuery msgid;
00178 int ret = ldap_add_ext(this->con, dn.c_str(), mods, NULL, NULL, &msgid);
00179 this->FreeMods(mods);
00180
00181 if (ret != LDAP_SUCCESS)
00182 {
00183 if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
00184 {
00185 this->Reconnect();
00186 return this->Add(i, dn, attributes);
00187 }
00188 else
00189 throw LDAPException(ldap_err2string(ret));
00190 }
00191
00192 if (i != NULL)
00193 {
00194 this->Lock();
00195 this->queries[msgid] = i;
00196 this->Unlock();
00197 }
00198 this->Wakeup();
00199
00200 return msgid;
00201 }
00202
00203 LDAPQuery Del(LDAPInterface *i, const Anope::string &dn) anope_override
00204 {
00205 LDAPQuery msgid;
00206 int ret = ldap_delete_ext(this->con, dn.c_str(), NULL, NULL, &msgid);
00207
00208 if (ret != LDAP_SUCCESS)
00209 {
00210 if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
00211 {
00212 this->Reconnect();
00213 return this->Del(i, dn);
00214 }
00215 else
00216 throw LDAPException(ldap_err2string(ret));
00217 }
00218
00219 if (i != NULL)
00220 {
00221 this->Lock();
00222 this->queries[msgid] = i;
00223 this->Unlock();
00224 }
00225 this->Wakeup();
00226
00227 return msgid;
00228 }
00229
00230 LDAPQuery Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) anope_override
00231 {
00232 LDAPMod **mods = this->BuildMods(attributes);
00233 LDAPQuery msgid;
00234 int ret = ldap_modify_ext(this->con, base.c_str(), mods, NULL, NULL, &msgid);
00235 this->FreeMods(mods);
00236
00237 if (ret != LDAP_SUCCESS)
00238 {
00239 if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
00240 {
00241 this->Reconnect();
00242 return this->Modify(i, base, attributes);
00243 }
00244 else
00245 throw LDAPException(ldap_err2string(ret));
00246 }
00247
00248 if (i != NULL)
00249 {
00250 this->Lock();
00251 this->queries[msgid] = i;
00252 this->Unlock();
00253 }
00254 this->Wakeup();
00255
00256 return msgid;
00257 }
00258
00259 void Run() anope_override
00260 {
00261 while (!this->GetExitState())
00262 {
00263 if (this->queries.empty())
00264 {
00265 this->Lock();
00266 this->Wait();
00267 this->Unlock();
00268 if (this->GetExitState())
00269 break;
00270 }
00271
00272 static struct timeval tv = { 1, 0 };
00273 LDAPMessage *result;
00274 int rtype = ldap_result(this->con, LDAP_RES_ANY, 1, &tv, &result);
00275 if (rtype <= 0 || this->GetExitState())
00276 continue;
00277
00278 int cur_id = ldap_msgid(result);
00279
00280 this->Lock();
00281
00282 query_queue::iterator it = this->queries.find(cur_id);
00283 if (it == this->queries.end())
00284 {
00285 this->Unlock();
00286 ldap_msgfree(result);
00287 continue;
00288 }
00289 LDAPInterface *i = it->second;
00290 this->queries.erase(it);
00291
00292 this->Unlock();
00293
00294 LDAPResult *ldap_result = new LDAPResult();
00295 ldap_result->id = cur_id;
00296
00297 for (LDAPMessage *cur = ldap_first_message(this->con, result); cur; cur = ldap_next_message(this->con, cur))
00298 {
00299 int cur_type = ldap_msgtype(cur);
00300
00301 LDAPAttributes attributes;
00302
00303 char *dn = ldap_get_dn(this->con, cur);
00304 if (dn != NULL)
00305 {
00306 attributes["dn"].push_back(dn);
00307 ldap_memfree(dn);
00308 dn = NULL;
00309 }
00310
00311 switch (cur_type)
00312 {
00313 case LDAP_RES_BIND:
00314 ldap_result->type = LDAPResult::QUERY_BIND;
00315 break;
00316 case LDAP_RES_SEARCH_ENTRY:
00317 ldap_result->type = LDAPResult::QUERY_SEARCH;
00318 break;
00319 case LDAP_RES_ADD:
00320 ldap_result->type = LDAPResult::QUERY_ADD;
00321 break;
00322 case LDAP_RES_DELETE:
00323 ldap_result->type = LDAPResult::QUERY_DELETE;
00324 break;
00325 case LDAP_RES_MODIFY:
00326 ldap_result->type = LDAPResult::QUERY_MODIFY;
00327 break;
00328 case LDAP_RES_SEARCH_RESULT:
00329
00330
00331 ldap_result->type = LDAPResult::QUERY_SEARCH;
00332 break;
00333 default:
00334 Log(LOG_DEBUG) << "m_ldap: Unknown msg type " << cur_type;
00335 continue;
00336 }
00337
00338 switch (cur_type)
00339 {
00340 case LDAP_RES_BIND:
00341 {
00342 int errcode = -1;
00343 int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
00344 if (parse_result != LDAP_SUCCESS)
00345 ldap_result->error = ldap_err2string(parse_result);
00346 else if (errcode != LDAP_SUCCESS)
00347 ldap_result->error = ldap_err2string(errcode);
00348 break;
00349 }
00350 case LDAP_RES_SEARCH_ENTRY:
00351 {
00352 BerElement *ber = NULL;
00353 for (char *attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber))
00354 {
00355 berval **vals = ldap_get_values_len(this->con, cur, attr);
00356 int count = ldap_count_values_len(vals);
00357
00358 std::vector<Anope::string> attrs;
00359 for (int j = 0; j < count; ++j)
00360 attrs.push_back(vals[j]->bv_val);
00361 attributes[attr] = attrs;
00362
00363 ldap_value_free_len(vals);
00364 ldap_memfree(attr);
00365 }
00366 if (ber != NULL)
00367 ber_free(ber, 0);
00368
00369 break;
00370 }
00371 case LDAP_RES_ADD:
00372 case LDAP_RES_DELETE:
00373 case LDAP_RES_MODIFY:
00374 {
00375 int errcode = -1;
00376 int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
00377 if (parse_result != LDAP_SUCCESS)
00378 ldap_result->error = ldap_err2string(parse_result);
00379 else if (errcode != LDAP_SUCCESS)
00380 ldap_result->error = ldap_err2string(errcode);
00381 break;
00382 }
00383 default:
00384 continue;
00385 }
00386
00387 ldap_result->messages.push_back(attributes);
00388 }
00389
00390 ldap_msgfree(result);
00391
00392 this->Lock();
00393 this->results.push_back(std::make_pair(i, ldap_result));
00394 this->Unlock();
00395
00396 me->Notify();
00397 }
00398 }
00399 };
00400
00401 class ModuleLDAP : public Module, public Pipe
00402 {
00403 std::map<Anope::string, LDAPService *> LDAPServices;
00404 public:
00405
00406 ModuleLDAP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED)
00407 {
00408 me = this;
00409
00410 Implementation i[] = { I_OnReload, I_OnModuleUnload };
00411 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00412
00413 OnReload();
00414 }
00415
00416 ~ModuleLDAP()
00417 {
00418 for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it)
00419 {
00420 it->second->SetExitState();
00421 it->second->Wakeup();
00422 it->second->Join();
00423 delete it->second;
00424 }
00425 LDAPServices.clear();
00426 }
00427
00428 void OnReload() anope_override
00429 {
00430 ConfigReader config;
00431 int i, num;
00432
00433 for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end();)
00434 {
00435 const Anope::string &cname = it->first;
00436 LDAPService *s = it->second;
00437 ++it;
00438
00439 for (i = 0, num = config.Enumerate("ldap"); i < num; ++i)
00440 {
00441 if (config.ReadValue("ldap", "name", "main", i) == cname)
00442 {
00443 break;
00444 }
00445 }
00446
00447 if (i == num)
00448 {
00449 Log(LOG_NORMAL, "ldap") << "LDAP: Removing server connection " << cname;
00450
00451 s->SetExitState();
00452 s->Wakeup();
00453 this->LDAPServices.erase(cname);
00454 }
00455 }
00456
00457 for (i = 0, num = config.Enumerate("ldap"); i < num; ++i)
00458 {
00459 Anope::string connname = config.ReadValue("ldap", "name", "main", i);
00460
00461 if (this->LDAPServices.find(connname) == this->LDAPServices.end())
00462 {
00463 Anope::string server = config.ReadValue("ldap", "server", "127.0.0.1", i);
00464 int port = config.ReadInteger("ldap", "port", "389", i, true);
00465 Anope::string admin_binddn = config.ReadValue("ldap", "admin_binddn", "", i);
00466 Anope::string admin_password = config.ReadValue("ldap", "admin_password", "", i);
00467
00468 try
00469 {
00470 LDAPService *ss = new LDAPService(this, connname, server, port, admin_binddn, admin_password);
00471 ss->Start();
00472 this->LDAPServices.insert(std::make_pair(connname, ss));
00473
00474 Log(LOG_NORMAL, "ldap") << "LDAP: Successfully connected to server " << connname << " (" << server << ")";
00475 }
00476 catch (const LDAPException &ex)
00477 {
00478 Log(LOG_NORMAL, "ldap") << "LDAP: " << ex.GetReason();
00479 }
00480 }
00481 }
00482 }
00483
00484 void OnModuleUnload(User *, Module *m) anope_override
00485 {
00486 for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it)
00487 {
00488 LDAPService *s = it->second;
00489 s->Lock();
00490 for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();)
00491 {
00492 int msgid = it2->first;
00493 LDAPInterface *i = it2->second;
00494 ++it2;
00495
00496 if (i->owner == m)
00497 {
00498 i->OnDelete();
00499 s->queries.erase(msgid);
00500 }
00501 }
00502 for (unsigned i = s->results.size(); i > 0; --i)
00503 {
00504 LDAPInterface *li = s->results[i - 1].first;
00505 if (li->owner == m)
00506 s->results.erase(s->results.begin() + i - 1);
00507 }
00508 s->Unlock();
00509 }
00510 }
00511
00512 void OnNotify() anope_override
00513 {
00514 for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it)
00515 {
00516 LDAPService *s = it->second;
00517
00518 s->Lock();
00519 LDAPService::result_queue results = s->results;
00520 s->results.clear();
00521 s->Unlock();
00522
00523 for (unsigned i = 0; i < results.size(); ++i)
00524 {
00525 LDAPInterface *li = results[i].first;
00526 LDAPResult *r = results[i].second;
00527
00528 if (!r->error.empty())
00529 li->OnError(*r);
00530 else
00531 li->OnResult(*r);
00532 }
00533 }
00534 }
00535 };
00536
00537 MODULE_INIT(ModuleLDAP)
00538