Skip to content

Instantly share code, notes, and snippets.

@kylef
Created September 14, 2011 16:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kylef/1217088 to your computer and use it in GitHub Desktop.
Save kylef/1217088 to your computer and use it in GitHub Desktop.
ZNC module for YubiKey
extern "C" {
#include <ykclient.h>
}
#include <znc/Modules.h>
#include <znc/znc.h>
#include <znc/User.h>
#define CLIENT_ID 1
#define DEFAULT_TOKEN_ID_LEN 12
class CYubikeyMod : public CModule {
public:
MODCONSTRUCTOR(CYubikeyMod) {
AddHelpCommand();
AddCommand("Add", static_cast<CModCommand::ModCmdFunc>(&CYubikeyMod::AddTokenCommand), "<token>");
AddCommand("Del", static_cast<CModCommand::ModCmdFunc>(&CYubikeyMod::DelTokenCommand), "<token>");
AddCommand("List", static_cast<CModCommand::ModCmdFunc>(&CYubikeyMod::ListTokens));
}
virtual ~CYubikeyMod() {}
virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
CString const sPassword = Auth->GetPassword();
CUser *pUser = CZNC::Get().FindUser(Auth->GetUsername());
if (pUser && CheckToken(pUser, sPassword.Left(DEFAULT_TOKEN_ID_LEN))) {
DEBUG("yubikey: Lookup for " << sPassword.Left(DEFAULT_TOKEN_ID_LEN));
// The following call is blocking.
//int result = ykclient_verify_otp(sPassword.c_str(), CLIENT_ID, NULL);
int result = ykclient_verify_otp_v2(NULL, sPassword.c_str(), CLIENT_ID, NULL, 0, NULL, NULL);
DEBUG("yubikey: " << ykclient_strerror(result));
if (result == YKCLIENT_OK) {
Auth->AcceptLogin(*pUser);
} else {
Auth->RefuseLogin(ykclient_strerror(result));
}
return HALT;
}
return CONTINUE;
}
SCString GetUserTokens(CUser *pUser) {
SCString ssTokens;
GetNV(pUser->GetUserName()).Split(" ", ssTokens);
return ssTokens;
}
void SetUserTokens(CUser *pUser, SCString ssTokens) {
CString sVal;
for (SCString::const_iterator it = ssTokens.begin(); it != ssTokens.end(); ++it) {
sVal += *it + " ";
}
SetNV(pUser->GetUserName(), sVal);
}
bool CheckToken(CUser *pUser, CString sToken) {
SCString ssTokens = GetUserTokens(pUser);
return ssTokens.find(sToken) != ssTokens.end();
}
void AddToken(CString sToken) {
SCString ssTokens = GetUserTokens(m_pUser);
SCString::iterator it = ssTokens.find(sToken);
if (it == ssTokens.end()) {
ssTokens.insert(sToken);
SetUserTokens(m_pUser, ssTokens);
}
}
void DelToken(const CString sToken) {
SCString ssTokens = GetUserTokens(m_pUser);
SCString::iterator it = ssTokens.find(sToken);
if (it != ssTokens.end()) {
ssTokens.erase(it);
SetUserTokens(m_pUser, ssTokens);
}
}
void AddTokenCommand(const CString& sLine) {
CString sToken = sLine.Token(1).Left(DEFAULT_TOKEN_ID_LEN);
if (sToken.length() != 12) {
PutModule("Invalid token ID");
return;
}
AddToken(sToken);
PutModule(sToken + " added");
}
void DelTokenCommand(const CString& sLine) {
CString sToken = sLine.Token(1).Left(DEFAULT_TOKEN_ID_LEN);
if (sToken.length() != 12) {
PutModule("Invalid token ID");
return;
}
DelToken(sToken);
PutModule(sToken + " removed");
}
void ListTokens(const CString& sLine) {
SCString ssTokens = GetUserTokens(m_pUser);
CTable table;
table.AddColumn("Token");
for (SCString::const_iterator it = ssTokens.begin(); it != ssTokens.end(); ++it) {
table.AddRow();
table.SetCell("Token", *it);
}
if (PutModule(table) == 0) {
PutModule("No tokens set for your user");
}
}
};
GLOBALMODULEDEFS(CYubikeyMod, "Allow users to authenticate with a yubikey")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment