Commit 5a4f8924 authored by Marc Dequènes (Duck)'s avatar Marc Dequènes (Duck)

[evol] proper AAA mechanisms selection and chaining

parent b68a3155
......@@ -83,14 +83,19 @@ irc {
# Authentication, Authorization and Accounting
aaa {
# Enable pam authentication (need the ENABLE_PAM compile flag)
# Enable local user database (defaults to true)
#use_local = true
# Enable PAM authentication/authorization (need the ENABLE_PAM compile flag)
#use_pam = false
# Enable connection information for authentication/authorization
# (currently only used with TLS client certificates)
#use_connection = false
tls {
#trust_file = /etc/ssl/certs/ca.crt
#cert_file = /etc/minbif/server.crt
#key_file = /etc/minbif/server.key
priority = PERFORMANCE
#priority = PERFORMANCE
}
}
......
......@@ -74,10 +74,11 @@ Minbif::Minbif()
sub->AddItem(new ConfigItem_string("password", "IRC operator password"));
section = conf.AddSection("aaa", "Authentication, Authorization and Accounting", MyConfig::OPTIONAL);
section->AddItem(new ConfigItem_bool("use_local", "Use local database to authenticate users", "true"));
#ifdef HAVE_PAM
section->AddItem(new ConfigItem_bool("use_pam", "Use PAM mechanisms instead of local database", "false"));
section->AddItem(new ConfigItem_bool("use_pam", "Use PAM mechanisms to authenticate/authorize users", "false"));
#endif
section->AddItem(new ConfigItem_bool("use_connection", "Use connection information instead of local database or PAM", "false"));
section->AddItem(new ConfigItem_bool("use_connection", "Use connection information to authenticate/authorize users", "false"));
#ifdef HAVE_TLS
sub = section->AddSection("tls", "TLS information", MyConfig::OPTIONAL);
sub->AddItem(new ConfigItem_string("trust_file", "CA certificate file for TLS", " "));
......
......@@ -18,6 +18,7 @@
#include <cstring>
#include <cerrno>
#include <vector>
#include "auth.h"
#include "core/log.h"
#include "core/util.h"
......@@ -31,15 +32,62 @@
namespace im
{
Auth* Auth::build(irc::IRC* _irc, string _username)
Auth* Auth::validate(irc::IRC* irc, const string username, const string password)
{
vector<Auth*> mechanisms;
Auth* mech_ok = NULL;
/* check aaa mechanisms, the more secure first */
if (conf.GetSection("aaa")->GetItem("use_connection")->Boolean())
return new AuthConnection(_irc, _username);
mechanisms.push_back(new AuthConnection(irc, username));
#ifdef HAVE_PAM
else if (conf.GetSection("aaa")->GetItem("use_pam")->Boolean())
return new AuthPAM(_irc, _username);
if (conf.GetSection("aaa")->GetItem("use_pam")->Boolean())
mechanisms.push_back(new AuthPAM(irc, username));
#endif
return new AuthLocal(_irc, _username);
if (conf.GetSection("aaa")->GetItem("use_local")->Boolean())
mechanisms.push_back(new AuthLocal(irc, username));
if (mechanisms.empty())
{
b_log[W_ERR] << "Login disabled (please consult your administrator)";
throw IMError();
}
for (vector<Auth*>::iterator m = mechanisms.begin(); m != mechanisms.end(); ++m)
{
if ((mech_ok == NULL) && (*m)->exists() && (*m)->authenticate(password))
mech_ok = *m;
else
delete *m;
}
return mech_ok;
}
Auth* Auth::generate(irc::IRC* irc, const string username, const string password)
{
vector<Auth*> mechanisms;
Auth* mech_ok = NULL;
/* check aaa mechanisms allowing user creation, the more secure first */
if (conf.GetSection("aaa")->GetItem("use_local")->Boolean())
mechanisms.push_back(new AuthLocal(irc, username));
if (mechanisms.empty())
{
b_log[W_ERR] << "Private server: account creation disabled";
throw IMError();
}
for (vector<Auth*>::iterator m = mechanisms.begin(); m != mechanisms.end(); ++m)
{
if ((mech_ok == NULL) && (*m)->create(password))
mech_ok = *m;
else
delete *m;
}
return mech_ok;
}
Auth::Auth(irc::IRC* _irc, string _username)
......@@ -51,8 +99,13 @@ Auth::Auth(irc::IRC* _irc, string _username)
im::IM* Auth::create(const string password)
{
if (exists())
return NULL;
b_log[W_DEBUG] << "Creating user " << username;
im = new im::IM(irc, username);
im->setPassword(password);
setPassword(password);
return im;
}
......
......@@ -37,7 +37,9 @@ namespace im
class Auth
{
public:
static Auth* build(irc::IRC* _irc, string _username);
static Auth* validate(irc::IRC* irc, const string username, const string password);
static Auth* generate(irc::IRC* irc, const string username, const string password);
Auth(irc::IRC* _irc, string _username);
virtual bool exists() = 0;
virtual bool authenticate(const string password) = 0;
......
......@@ -44,10 +44,15 @@ bool AuthConnection::authenticate(const string password)
return false;
SockWrapper* sockw = irc->getSockWrap();
im = new im::IM(irc, username);
b_log[W_DEBUG] << "Authenticating user " << im->getUsername() << " using connection information";
return sockw->GetClientUsername() == username;
b_log[W_DEBUG] << "Authenticating user " << username << " using connection information";
if (sockw->GetClientUsername() == username)
{
im = new im::IM(irc, username);
return true;
}
return false;
}
bool AuthConnection::setPassword(const string& password)
......
......@@ -45,7 +45,7 @@ bool AuthLocal::authenticate(const string password)
im = new im::IM(irc, username);
b_log[W_DEBUG] << "Authenticating user " << im->getUsername() << " using local database";
b_log[W_DEBUG] << "Authenticating user " << username << " using local database";
return im->getPassword() == password;
}
......@@ -53,7 +53,7 @@ bool AuthLocal::setPassword(const string& password)
{
if(password.find(' ') != string::npos || password.size() < 8)
{
irc->notice(irc->getUser(), "Password must be at least 8 characters, and does not contain whitespaces.");
irc->notice(irc->getUser(), "Password must be at least 8 characters, and cannot contain whitespaces.");
return false;
}
im->setPassword(password);
......
......@@ -127,11 +127,14 @@ bool AuthPAM::authenticate(const string password)
retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
if (retval == PAM_SUCCESS)
{
im = new im::IM(irc, username);
return true;
}
else
close(retval);
return (retval == PAM_SUCCESS);
return false;
}
void AuthPAM::close(int retval)
......
......@@ -400,19 +400,23 @@ void IRC::sendWelcome()
user->getIdentname().empty())
return;
if(user->getPassword().empty())
{
quit("Please set a password");
return;
}
try
{
im_auth = im::Auth::build(this, user->getNickname());
if(!im_auth->exists())
if (im::IM::exists(user->getNickname()))
{
im_auth = im::Auth::validate(this, user->getNickname(), user->getPassword());
if (!im_auth)
quit("Incorrect credentials");
}
else
{
/* New user. */
/* New User */
if (user->getPassword().empty())
{
quit("Please set a password for this new account");
return;
}
string global_passwd = conf.GetSection("irc")->GetItem("password")->String();
if(global_passwd != " " && user->getPassword() != global_passwd)
......@@ -421,12 +425,9 @@ void IRC::sendWelcome()
return;
}
im_auth->create(user->getPassword());
}
else if(!im_auth->authenticate(user->getPassword()))
{
quit("Incorrect password");
return;
im_auth = im::Auth::generate(this, user->getNickname(), user->getPassword());
if (!im_auth)
quit("Creation of new account failed");
}
im = im_auth->getIM();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment