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

[evol] added PAM support for login

parent 176ac080
......@@ -78,6 +78,10 @@ irc {
# }
}
users {
use_pam_auth = false
}
file_transfers {
# Enable file transfers feature.
......
......@@ -12,6 +12,7 @@ ADD_EXECUTABLE(${BIN_NAME}
server_poll/inetd.cpp
server_poll/daemon_fork.cpp
im/im.cpp
im/user.cpp
im/protocol.cpp
im/account.cpp
im/roomlist.cpp
......@@ -37,7 +38,7 @@ ADD_EXECUTABLE(${BIN_NAME}
irc/conversation_channel.cpp
)
TARGET_LINK_LIBRARIES(${BIN_NAME} "-lpthread -lstdc++" ${PURPLE_LDFLAGS} ${CACA_LDFLAGS} ${IMLIB_LDFLAGS} ${GSTREAMER_LDFLAGS} ${FARSIGHT_LDFLAGS})
TARGET_LINK_LIBRARIES(${BIN_NAME} "-lpthread -lstdc++ -lpam" ${PURPLE_LDFLAGS} ${CACA_LDFLAGS} ${IMLIB_LDFLAGS} ${GSTREAMER_LDFLAGS} ${FARSIGHT_LDFLAGS})
INSTALL(TARGETS ${BIN_NAME}
DESTINATION bin)
......@@ -59,6 +59,9 @@ Minbif::Minbif()
sub->AddItem(new ConfigItem_string("login", "Nickname of IRC operator"), true);
sub->AddItem(new ConfigItem_string("password", "IRC operator password"));
section = conf.AddSection("aaa", "Authentication, Authorization and Accounting", false);
section->AddItem(new ConfigItem_bool("use_pam", "Use PAM mechanisms instead of local database", "false"));
section = conf.AddSection("file_transfers", "File transfers parameters", false);
section->AddItem(new ConfigItem_bool("enabled", "Enable file transfers", "true"));
section->AddItem(new ConfigItem_bool("dcc", "Send files to IRC user with DCC", "true"));
......
......@@ -113,11 +113,6 @@ string IM::getPassword() const
return purple_prefs_get_string("/minbif/password");
}
bool IM::authenticate(const string password)
{
return getPassword() == password
}
void IM::setTypingNotice(bool enabled)
{
purple_prefs_set_int("/minbif/typing_notice", enabled ? 1 : 0);
......
/*
* Minbif - IRC instant messaging gateway
* Copyright(C) 2009 Romain Bignon
*
* This program 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 of the License.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <cstring>
#include <cerrno>
#include "user.h"
#include "core/log.h"
#include "core/util.h"
#include "core/config.h"
#include "irc/irc.h"
namespace im
{
User::User(irc::IRC* _irc, string _username)
: username(_username),
irc(_irc)
{
use_pam = conf.GetSection("aaa")->GetItem("use_pam")->Boolean();
im = NULL;
}
bool User::exists()
{
if (use_pam)
return true;
else
return im::IM::exists(username);
}
bool User::authenticate(const string password)
{
if(use_pam)
{
if (!authenticate_pam(username, password))
return false;
im = new im::IM(irc, username);
}
else
{
if (!im::IM::exists(username))
return false;
im = new im::IM(irc, username);
if (!authenticate_local(password))
return false;
}
return true;
}
bool User::authenticate_local(const string password)
{
b_log[W_INFO] << "Authenticating user " << im->getUsername() << " using local database";
return im->getPassword() == password;
}
static int pam_conv_func(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr)
{
int count = 0;
struct pam_response *reply;
reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response));
if (reply == NULL)
{
b_log[W_ERR] << "PAM: Could not allocate enough memory";
return PAM_CONV_ERR;
}
for (count = 0; count < num_msg; ++count)
{
switch (msgm[count]->msg_style)
{
case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON:
reply[count].resp_retcode = 0;
reply[count].resp = strndup((const char*)appdata_ptr, PAM_MAX_MSG_SIZE);
break;
case PAM_ERROR_MSG:
b_log[W_ERR] << "PAM: " << msgm[count]->msg;
break;
case PAM_TEXT_INFO:
b_log[W_INFO] << "PAM: " << msgm[count]->msg;
break;
default:
b_log[W_ERR] << "PAM: erroneous conversation (" << msgm[count]->msg_style << ")";
goto failed_conversation;
}
}
*response = reply;
return PAM_SUCCESS;
failed_conversation:
for (count = 0; count < num_msg; ++count)
{
if (reply[count].resp != NULL)
free(reply[count].resp);
}
free(reply);
*response = NULL;
return PAM_CONV_ERR;
}
bool User::authenticate_pam(const string username, const string password)
{
pam_handle_t *pamh=NULL;
int retval, retval2;
b_log[W_INFO] << "Authenticating user " << username << " using PAM mechanism";
pam_conversation.conv = pam_conv_func;
pam_conversation.appdata_ptr = (void*) password.c_str();
retval = pam_start("minbif", username.c_str(), &pam_conversation, &pamh);
if (retval == PAM_SUCCESS)
retval = pam_authenticate(pamh, 0); /* is user really user? */
if (retval == PAM_SUCCESS)
retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
retval2 = pam_end(pamh, retval);
if (retval2 != PAM_SUCCESS) { /* close Linux-PAM */
b_log[W_ERR] << "PAM: Could not release authenticatori: " << pam_strerror(pamh, retval2);
throw IMError();
}
return (retval == PAM_SUCCESS);
}
im::IM* User::create(const string password)
{
im = new im::IM(irc, username);
im->setPassword(password);
return im;
}
im::IM* User::getIM()
{
return im;
}
}; /* namespace im */
/*
* Minbif - IRC instant messaging gateway
* Copyright(C) 2009 Romain Bignon
*
* This program 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 of the License.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef IM_USER_H
#define IM_USER_H
#include <exception>
#include <string>
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include "im.h"
/** IM related classes */
namespace im
{
class User
{
public:
User(irc::IRC* _irc, string _username);
bool exists();
bool authenticate(const string password);
im::IM* create(const string password);
im::IM* getIM();
private:
string username;
irc::IRC* irc;
bool use_pam;
im::IM *im;
struct pam_conv pam_conversation;
bool authenticate_local(const string password);
bool authenticate_pam(const string username, const string password);
};
};
#endif /* IM_USER_H */
......@@ -31,6 +31,7 @@
#include "core/sock.h"
#include "core/config.h"
#include "im/im.h"
#include "im/user.h"
#include "server_poll/poll.h"
#include "irc/irc.h"
#include "irc/settings.h"
......@@ -430,7 +431,9 @@ void IRC::sendWelcome()
try
{
if(!IM::exists(user->getNickname()))
im::User *im_user = new im::User(this, user->getNickname());
if(!im_user->exists())
{
/* New user. */
......@@ -441,16 +444,15 @@ void IRC::sendWelcome()
return;
}
im = new im::IM(this, user->getNickname());
im->setPassword(user->getPassword());
im_user->create(user->getPassword());
}
else if(im->authenticate(user->getPassword()))
else if(!im_user->authenticate(user->getPassword()))
{
quit("Incorrect password");
return;
}
else
im = new im::IM(this, user->getNickname());
im = im_user->getIM();
user->setFlag(Nick::REGISTERED);
......
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