forked from kylef-archive/znc-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
yubikey.cpp
128 lines (99 loc) · 3.15 KB
/
yubikey.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
extern "C" {
#include <ykclient.h>
}
#include "Modules.h"
#include "znc.h"
#include "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("Tolken");
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")