summaryrefslogtreecommitdiff
path: root/modules/extra
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2011-04-27 10:56:20 -0400
committerAdam <Adam@anope.org>2011-05-16 04:09:07 -0400
commit284af258bf3c4dc7f409722d66bb0ac59e01e37d (patch)
tree5649a27a7a247c2609a4ef13b52a357765cbdfcc /modules/extra
parente7887c1f013248274574ab8e3167f742ccb3d69b (diff)
Added more useful functions to our LDAP API, allow adding newly registered accounts to LDAP, removed some unnecessary OnPre events and fixed unloading all modules
Diffstat (limited to 'modules/extra')
-rw-r--r--modules/extra/cs_set_misc.cpp2
-rw-r--r--modules/extra/db_mysql_live.cpp4
-rw-r--r--modules/extra/ldap.h70
-rw-r--r--modules/extra/m_ldap.cpp152
-rw-r--r--modules/extra/m_ldap_authentication.cpp70
-rw-r--r--modules/extra/ns_set_misc.cpp2
6 files changed, 282 insertions, 18 deletions
diff --git a/modules/extra/cs_set_misc.cpp b/modules/extra/cs_set_misc.cpp
index 4bd7a772a..f71363795 100644
--- a/modules/extra/cs_set_misc.cpp
+++ b/modules/extra/cs_set_misc.cpp
@@ -75,7 +75,7 @@ class CSSetMisc : public Module
void RemoveAll()
{
- if (Commands.empty())
+ if (!chanserv || Commands.empty())
return;
Command *set = FindCommand(chanserv->Bot(), "SET");
diff --git a/modules/extra/db_mysql_live.cpp b/modules/extra/db_mysql_live.cpp
index 8faa11a1f..f1f0b855f 100644
--- a/modules/extra/db_mysql_live.cpp
+++ b/modules/extra/db_mysql_live.cpp
@@ -163,11 +163,11 @@ class MySQLLiveModule : public Module
MySQLLiveModule(const Anope::string &modname, const Anope::string &creator) :
Module(modname, creator), SQL("mysql/main"), ACS("asynch_commands")
{
- Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore, I_OnPreShutdown };
+ Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore, I_OnShutdown };
ModuleManager::Attach(i, this, 4);
}
- void OnPreShutdown()
+ void OnShutdown()
{
Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore };
for (size_t j = 0; j < 3; ++j)
diff --git a/modules/extra/ldap.h b/modules/extra/ldap.h
index acb9d8f53..6fbba7c11 100644
--- a/modules/extra/ldap.h
+++ b/modules/extra/ldap.h
@@ -1,3 +1,5 @@
+#ifndef ANOPE_LDAP_H
+#define ANOPE_LDAP_H
typedef int LDAPQuery;
@@ -9,6 +11,21 @@ class LDAPException : public ModuleException
virtual ~LDAPException() throw() { }
};
+struct LDAPModification
+{
+ enum LDAPOperation
+ {
+ LDAP_ADD,
+ LDAP_DEL,
+ LDAP_REPLACE
+ };
+
+ LDAPOperation op;
+ Anope::string name;
+ std::vector<Anope::string> values;
+};
+typedef std::vector<LDAPModification> LDAPMods;
+
struct LDAPAttributes : public std::map<Anope::string, std::vector<Anope::string> >
{
size_t size(const Anope::string &attr) const
@@ -50,7 +67,10 @@ struct LDAPResult
enum QueryType
{
QUERY_BIND,
- QUERY_SEARCH
+ QUERY_SEARCH,
+ QUERY_ADD,
+ QUERY_DELETE,
+ QUERY_MODIFY
};
QueryType type;
@@ -61,6 +81,11 @@ struct LDAPResult
return this->messages.size();
}
+ bool empty() const
+ {
+ return this->messages.empty();
+ }
+
const LDAPAttributes &get(size_t sz) const
{
if (sz >= this->messages.size())
@@ -86,14 +111,55 @@ class LDAPInterface
virtual void OnError(const LDAPResult &err) { }
};
-
class LDAPProvider : public Service
{
public:
LDAPProvider(Module *c, const Anope::string &n) : Service(c, n) { }
+ /** Attempt to bind to the LDAP server as an admin
+ * @param i The LDAPInterface the result is sent to
+ * @return The query ID
+ */
+ virtual LDAPQuery BindAsAdmin(LDAPInterface *i) = 0;
+
+ /** Bind to LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param who The binddn
+ * @param pass The password
+ * @return The query ID
+ */
virtual LDAPQuery Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) = 0;
+ /** Search ldap for the specified filter
+ * @param i The LDAPInterface the result is sent to
+ * @param base The base DN to search
+ * @param filter The filter to apply
+ * @return The query ID
+ */
virtual LDAPQuery Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) = 0;
+
+ /** Add an entry to LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param dn The dn of the entry to add
+ * @param attributes The attributes
+ * @return The query ID
+ */
+ virtual LDAPQuery Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) = 0;
+
+ /** Delete an entry from LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param dn The dn of the entry to delete
+ * @return The query ID
+ */
+ virtual LDAPQuery Del(LDAPInterface *i, const Anope::string &dn) = 0;
+
+ /** Modify an existing entry in LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param base The base DN to modify
+ * @param attributes The attributes to modify
+ * @return The query ID
+ */
+ virtual LDAPQuery Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) = 0;
};
+#endif // ANOPE_LDAP_H
diff --git a/modules/extra/m_ldap.cpp b/modules/extra/m_ldap.cpp
index 157bc70ac..188c9d02f 100644
--- a/modules/extra/m_ldap.cpp
+++ b/modules/extra/m_ldap.cpp
@@ -10,16 +10,57 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
{
Anope::string server;
int port;
+ Anope::string admin_binddn;
+ Anope::string admin_pass;
LDAP *con;
+ LDAPMod **BuildMods(const LDAPMods &attributes)
+ {
+ LDAPMod **mods = new LDAPMod*[attributes.size() + 1];
+ memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1));
+ for (unsigned x = 0; x < attributes.size(); ++x)
+ {
+ const LDAPModification &l = attributes[x];
+ mods[x] = new LDAPMod();
+
+ if (l.op == LDAPModification::LDAP_ADD)
+ mods[x]->mod_op = LDAP_MOD_ADD;
+ else if (l.op == LDAPModification::LDAP_DEL)
+ mods[x]->mod_op = LDAP_MOD_DELETE;
+ else if (l.op == LDAPModification::LDAP_REPLACE)
+ mods[x]->mod_op = LDAP_MOD_REPLACE;
+ else if (l.op != 0)
+ throw LDAPException("Unknown LDAP operation");
+ mods[x]->mod_type = strdup(l.name.c_str());
+ mods[x]->mod_values = new char*[l.values.size() + 1];
+ memset(mods[x]->mod_values, 0, sizeof(char *) * (l.values.size() + 1));
+ for (unsigned j = 0, c = 0; j < l.values.size(); ++j)
+ if (!l.values[j].empty())
+ mods[x]->mod_values[c++] = strdup(l.values[j].c_str());
+ }
+ return mods;
+ }
+
+ void FreeMods(LDAPMod **mods)
+ {
+ for (int i = 0; mods[i] != NULL; ++i)
+ {
+ free(mods[i]->mod_type);
+ for (int j = 0; mods[i]->mod_values[j] != NULL; ++j)
+ free(mods[i]->mod_values[j]);
+ delete [] mods[i]->mod_values;
+ }
+ delete [] mods;
+ }
+
public:
typedef std::map<int, LDAPInterface *> query_queue;
typedef std::vector<std::pair<LDAPInterface *, LDAPResult *> > result_queue;
query_queue queries;
result_queue results;
- LDAPService(Module *o, const Anope::string &n, const Anope::string &s, int po) : LDAPProvider(o, "ldap/" + n), server(s), port(po)
+ 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)
{
if (ldap_initialize(&this->con, this->server.c_str()) != LDAP_SUCCESS)
throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + Anope::LastError());
@@ -52,6 +93,11 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
ldap_unbind_ext(this->con, NULL, NULL);
}
+
+ LDAPQuery BindAsAdmin(LDAPInterface *i)
+ {
+ return this->Bind(i, this->admin_binddn, this->admin_pass);
+ }
LDAPQuery Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass)
{
@@ -94,6 +140,67 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
return msgid;
}
+ LDAPQuery Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes)
+ {
+ LDAPMod **mods = this->BuildMods(attributes);
+ LDAPQuery msgid;
+ int ret = ldap_add_ext(this->con, dn.c_str(), mods, NULL, NULL, &msgid);
+ this->FreeMods(mods);
+
+ if (ret != LDAP_SUCCESS)
+ throw LDAPException(ldap_err2string(ret));
+
+ if (i != NULL)
+ {
+ this->Lock();
+ this->queries[msgid] = i;
+ this->Unlock();
+ }
+ this->Wakeup();
+
+ return msgid;
+ }
+
+ LDAPQuery Del(LDAPInterface *i, const Anope::string &dn)
+ {
+ LDAPQuery msgid;
+ int ret = ldap_delete_ext(this->con, dn.c_str(), NULL, NULL, &msgid);
+
+ if (ret != LDAP_SUCCESS)
+ throw LDAPException(ldap_err2string(ret));
+
+ if (i != NULL)
+ {
+ this->Lock();
+ this->queries[msgid] = i;
+ this->Unlock();
+ }
+ this->Wakeup();
+
+ return msgid;
+ }
+
+ LDAPQuery Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes)
+ {
+ LDAPMod **mods = this->BuildMods(attributes);
+ LDAPQuery msgid;
+ int ret = ldap_modify_ext(this->con, base.c_str(), mods, NULL, NULL, &msgid);
+ this->FreeMods(mods);
+
+ if (ret != LDAP_SUCCESS)
+ throw LDAPException(ldap_err2string(ret));
+
+ if (i != NULL)
+ {
+ this->Lock();
+ this->queries[msgid] = i;
+ this->Unlock();
+ }
+ this->Wakeup();
+
+ return msgid;
+ }
+
void Run()
{
while (!this->GetExitState())
@@ -121,6 +228,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
if (it == this->queries.end())
{
this->Unlock();
+ ldap_msgfree(result);
continue;
}
LDAPInterface *i = it->second;
@@ -140,9 +248,30 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
switch (cur_type)
{
case LDAP_RES_BIND:
- {
ldap_result->type = LDAPResult::QUERY_BIND;
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ ldap_result->type = LDAPResult::QUERY_SEARCH;
+ case LDAP_RES_SEARCH_RESULT:
+ break;
+ case LDAP_RES_ADD:
+ ldap_result->type = LDAPResult::QUERY_ADD;
+ break;
+ case LDAP_RES_DELETE:
+ ldap_result->type = LDAPResult::QUERY_DELETE;
+ break;
+ case LDAP_RES_MODIFY:
+ ldap_result->type = LDAPResult::QUERY_MODIFY;
+ break;
+ default:
+ Log(LOG_DEBUG) << "m_ldap: Unknown msg type " << cur_type;
+ continue;
+ }
+ switch (cur_type)
+ {
+ case LDAP_RES_BIND:
+ {
int errcode = -1;
int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
if (parse_result != LDAP_SUCCESS)
@@ -153,8 +282,6 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
}
case LDAP_RES_SEARCH_ENTRY:
{
- ldap_result->type = LDAPResult::QUERY_SEARCH;
-
BerElement *ber = NULL;
for (char *attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber))
{
@@ -173,8 +300,19 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
break;
}
+ case LDAP_RES_ADD:
+ case LDAP_RES_DELETE:
+ case LDAP_RES_MODIFY:
+ {
+ int errcode = -1;
+ int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
+ if (parse_result != LDAP_SUCCESS)
+ ldap_result->error = ldap_err2string(parse_result);
+ else if (errcode != LDAP_SUCCESS)
+ ldap_result->error = ldap_err2string(errcode);
+ break;
+ }
default:
- Log(LOG_DEBUG) << "m_ldap: Unknown msg type " << cur_type;
continue;
}
@@ -262,10 +400,12 @@ class ModuleLDAP : public Module, public Pipe
{
Anope::string server = config.ReadValue("ldap", "server", "127.0.0.1", i);
int port = config.ReadInteger("ldap", "port", "389", i, true);
+ Anope::string admin_binddn = config.ReadValue("ldap", "admin_binddn", "", i);
+ Anope::string admin_password = config.ReadValue("ldap", "admin_password", "", i);
try
{
- LDAPService *ss = new LDAPService(this, connname, server, port);
+ LDAPService *ss = new LDAPService(this, connname, server, port, admin_binddn, admin_password);
this->LDAPServices.insert(std::make_pair(connname, ss));
ModuleManager::RegisterService(ss);
diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp
index f2caac63d..87d082e44 100644
--- a/modules/extra/m_ldap_authentication.cpp
+++ b/modules/extra/m_ldap_authentication.cpp
@@ -118,7 +118,7 @@ class OnIdentifyInterface : public LDAPInterface
User *u = finduser(it->second);
this->requests.erase(it);
- if (!u || !u->Account())
+ if (!u || !u->Account() || r.empty())
return;
try
@@ -146,25 +146,44 @@ class OnIdentifyInterface : public LDAPInterface
}
};
+class OnRegisterInterface : public LDAPInterface
+{
+ public:
+ OnRegisterInterface(Module *m) : LDAPInterface(m) { }
+
+ void OnResult(const LDAPResult &r)
+ {
+ Log() << "m_ldap_authentication: Successfully added newly created account to LDAP";
+ }
+
+ void OnError(const LDAPResult &r)
+ {
+ Log() << "m_ldap_authentication: Error adding newly created account to LDAP: " << r.getError();
+ }
+};
+
class NSIdentifyLDAP : public Module
{
service_reference<LDAPProvider> ldap;
IdentifyInterface iinterface;
OnIdentifyInterface oninterface;
+ OnRegisterInterface orinterface;
Anope::string binddn;
+ Anope::string object_class;
Anope::string username_attribute;
+ Anope::string password_attribute;
bool disable_register;
Anope::string disable_reason;
public:
NSIdentifyLDAP(const Anope::string &modname, const Anope::string &creator) :
- Module(modname, creator), ldap("ldap/main"), iinterface(this), oninterface(this)
+ Module(modname, creator), ldap("ldap/main"), iinterface(this), oninterface(this), orinterface(this)
{
this->SetAuthor("Anope");
this->SetType(SUPPORTED);
- Implementation i[] = { I_OnReload, I_OnPreCommand, I_OnCheckAuthentication, I_OnNickIdentify };
- ModuleManager::Attach(i, this, 4);
+ Implementation i[] = { I_OnReload, I_OnPreCommand, I_OnCheckAuthentication, I_OnNickIdentify, I_OnNickRegister };
+ ModuleManager::Attach(i, this, 5);
ModuleManager::SetPriority(this, PRIORITY_FIRST);
OnReload();
@@ -175,7 +194,9 @@ class NSIdentifyLDAP : public Module
ConfigReader config;
this->binddn = config.ReadValue("m_ldap_authentication", "binddn", "", 0);
+ this->object_class = config.ReadValue("m_ldap_authentication", "object_class", "", 0);
this->username_attribute = config.ReadValue("m_ldap_authentication", "username_attribute", "", 0);
+ this->password_attribute = config.ReadValue("m_ldap_authentication", "password_attribute", "", 0);
email_attribute = config.ReadValue("m_ldap_authentication", "email_attribute", "", 0);
this->disable_register = config.ReadFlag("m_ldap_authentication", "disable_ns_register", "false", 0);
this->disable_reason = config.ReadValue("m_ldap_authentication", "disable_reason", "", 0);
@@ -183,7 +204,7 @@ class NSIdentifyLDAP : public Module
EventReturn OnPreCommand(CommandSource &source, Command *command, const std::vector<Anope::string> &params)
{
- if (this->disable_register && nickserv && command->service == nickserv->Bot() && command->name == "REGISTER")
+ if (this->disable_register && !this->disable_reason.empty() && nickserv && command->service == nickserv->Bot() && command->name == "REGISTER")
{
source.Reply(_(this->disable_reason.c_str()));
return EVENT_STOP;
@@ -204,7 +225,7 @@ class NSIdentifyLDAP : public Module
else if (u->GetExt("m_ldap_authentication_error"))
{
u->Shrink("m_ldap_authentication_error");
- return EVENT_CONTINUE;;
+ return EVENT_CONTINUE;
}
IdentifyInfo *ii = new IdentifyInfo(u, c, params, account, password);
@@ -239,6 +260,43 @@ class NSIdentifyLDAP : public Module
Log() << "m_ldap_authentication: " << ex.GetReason();
}
}
+
+ void OnNickRegister(NickAlias *na)
+ {
+ if (this->disable_register || !this->ldap)
+ return;
+
+ try
+ {
+ this->ldap->BindAsAdmin(NULL);
+
+ LDAPMods attributes;
+ attributes.resize(4);
+
+ attributes[0].name = "objectClass";
+ attributes[0].values.push_back("top");
+ attributes[0].values.push_back(this->object_class);
+
+ attributes[1].name = this->username_attribute;
+ attributes[1].values.push_back(na->nick);
+
+ if (!na->nc->email.empty())
+ {
+ attributes[2].name = email_attribute;
+ attributes[2].values.push_back(na->nc->email);
+ }
+
+ attributes[3].name = this->password_attribute;
+ attributes[3].values.push_back(na->nc->pass);
+
+ Anope::string new_dn = this->username_attribute + "=" + na->nick + "," + this->binddn;
+ this->ldap->Add(&this->orinterface, new_dn, attributes);
+ }
+ catch (const LDAPException &ex)
+ {
+ Log() << "m_ldap_authentication: " << ex.GetReason();
+ }
+ }
};
MODULE_INIT(NSIdentifyLDAP)
diff --git a/modules/extra/ns_set_misc.cpp b/modules/extra/ns_set_misc.cpp
index 385fb9648..1bb1a95a1 100644
--- a/modules/extra/ns_set_misc.cpp
+++ b/modules/extra/ns_set_misc.cpp
@@ -78,7 +78,7 @@ class NSSetMisc : public Module
void RemoveAll()
{
- if (Commands.empty())
+ if (!nickserv || Commands.empty())
return;
Command *set = FindCommand(nickserv->Bot(), "SET");