#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "znc.h"
#include "HTTPSock.h"
#include "Server.h"
class CAdminMod;
class CAdminSock : public CHTTPSock {
public:
CAdminSock(CAdminMod* pModule);
CAdminSock(CAdminMod* pModule, const CString& sHostname, unsigned short uPort, int iTimeout = 60);
virtual ~CAdminSock();
virtual bool OnPageRequest(const CString& sURI, CString& sPageRet);
virtual bool OnLogin(const CString& sUser, const CString& sPass);
CString Header(const CString& sTitle) {
return "\r\n"
"\r\n
" + sTitle + "\r\n"
"\r\n"
"" + sTitle + "
\r\n";
}
CString Footer() {
return "\r\n\r\n";
}
void PrintMainPage(CString& sPageRet) {
sPageRet = Header("Main Page");
sPageRet += "Add a user
\r\n"
"List all users
\r\n";
sPageRet += Footer();
}
void GetErrorPage(CString& sPageRet, const CString& sError) {
sPageRet = Header("Error");
sPageRet += "" + sError.Escape_n(CString::EHTML) + "
\r\n";
sPageRet += Footer();
}
void ListUsersPage(CString& sPageRet);
bool UserPage(CString& sPageRet, CUser* pUser = NULL);
CUser* GetNewUser(CString& sPageRet);
void ListPage(CString& sPageRet) {
VCString vsParams;
const map& msvsParams = GetParams();
sPageRet = Header("fooooooo");
if (msvsParams.empty()) {
sPageRet += "You passed in no params.\r\n";
} else {
for (map::const_iterator it = msvsParams.begin(); it != msvsParams.end(); it++) {
sPageRet += "" + it->first + "
\r\n\r\n";
const VCString vsParams = it->second;
for (unsigned int a = 0; a < vsParams.size(); a++) {
sPageRet += "- [" + vsParams[a] + "]
\r\n";
}
sPageRet += "
\r\n";
}
}
sPageRet += Footer();
}
virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort);
private:
protected:
CAdminMod* m_pModule;
CUser* m_pUser;
};
class CAdminMod : public CGlobalModule {
public:
CAdminMod(void *pDLL, CZNC* pZNC, const CString& sModName) : CGlobalModule(pDLL, pZNC, sModName) {
m_uPort = 8080;
}
virtual ~CAdminMod() {
for (set::iterator it = m_sSocks.begin(); it != m_sSocks.end(); it++) {
m_pManager->DelSockByAddr(*it);
}
}
virtual bool OnBoot() {
return true;
}
virtual bool OnLoad(const CString& sArgs) {
bool bSSL = false;
CString sPort = sArgs.Token(0);
if (sPort.Left(1) == "+") {
sPort.TrimLeft("+");
bSSL = true;
}
m_uPort = sPort.ToUInt();
m_sUser = sArgs.Token(1);
m_sPass = sArgs.Token(2);
if (m_sPass.empty()) {
return false;
}
CAdminSock* pListenSock = new CAdminSock(this);
if (bSSL) {
pListenSock->SetPemLocation(m_pZNC->GetPemLocation());
}
return m_pManager->ListenAll(m_uPort, "Admin::Listener", bSSL, SOMAXCONN, pListenSock);
}
void AddSock(CAdminSock* pSock) {
m_sSocks.insert(pSock);
}
void SockDestroyed(CAdminSock* pSock) {
m_sSocks.erase(pSock);
}
const CString& GetUser() const { return m_sUser; }
const CString& GetPass() const { return m_sPass; }
private:
unsigned int m_uPort;
CString m_sUser;
CString m_sPass;
set m_sSocks;
};
bool CAdminSock::OnLogin(const CString& sUser, const CString& sPass) {
if (GetUser() == m_pModule->GetUser() && GetPass() == m_pModule->GetPass()) {
return true;
}
CUser* pUser = m_pModule->GetZNC()->FindUser(GetUser());
if (pUser && pUser->CheckPass(GetPass())) {
m_pUser = pUser;
return true;
}
return false;
}
void CAdminSock::ListUsersPage(CString& sPageRet) {
const map& msUsers = m_pModule->GetZNC()->GetUserMap();
sPageRet = Header("List Users");
if (!msUsers.size()) {
sPageRet += "There are no users defined. Click here if you would like to add one.\r\n";
} else {
sPageRet += "\r\n";
}
sPageRet += Footer();
}
Csock* CAdminSock::GetSockObj(const CString& sHost, unsigned short uPort) {
CAdminSock* pSock = new CAdminSock(m_pModule, sHost, uPort);
pSock->SetSockName("Admin::Client");
pSock->SetTimeout(120);
m_pModule->AddSock(pSock);
return pSock;
}
CAdminSock::CAdminSock(CAdminMod* pModule) : CHTTPSock() {
m_pModule = pModule;
m_pUser = NULL;
m_pModule->AddSock(this);
}
CAdminSock::CAdminSock(CAdminMod* pModule, const CString& sHostname, unsigned short uPort, int iTimeout) : CHTTPSock(sHostname, uPort, iTimeout) {
m_pModule = pModule;
m_pUser = NULL;
m_pModule->AddSock(this);
}
CAdminSock::~CAdminSock() {
m_pModule->SockDestroyed(this);
}
bool CAdminSock::OnPageRequest(const CString& sURI, CString& sPageRet) {
DEBUG_ONLY(cout << "Request for [" << sURI << "] ");
if (!ForceLogin()) {
DEBUG_ONLY(cout << "- User not logged in!" << endl);
return false;
}
if (sURI == "/") {
if (m_pUser) {
Redirect("/edituser");
return false;
}
PrintMainPage(sPageRet);
} else if (sURI == "/adduser") {
if (m_pUser) {
return false;
}
if (!UserPage(sPageRet)) {
DEBUG_ONLY(cout << "- 302 Redirect" << endl);
return false;
}
} else if (sURI == "/edituser") {
CUser* pUser = (m_pUser) ? m_pUser : m_pModule->GetZNC()->FindUser(GetParam("user"));
if (pUser) {
if (!UserPage(sPageRet, pUser)) {
DEBUG_ONLY(cout << "- 302 Redirect" << endl);
return false;
}
} else {
GetErrorPage(sPageRet, "No such username");
}
} else if (sURI == "/listusers") {
if (m_pUser) {
return false;
}
ListUsersPage(sPageRet);
} else if (sURI == "/deluser") {
if (m_pModule->GetZNC()->DeleteUser(GetParam("user"))) {
if (!m_pModule->GetZNC()->WriteConfig()) {
GetErrorPage(sPageRet, "User deleted, but config was not written");
return true;
}
DEBUG_ONLY(cout << "- 302 Redirect" << endl);
Redirect("/listusers");
return false;
} else {
GetErrorPage(sPageRet, "No such username");
}
//} else if (sURI == "/list") {
// ListPage(sPageRet);
} else {
DEBUG_ONLY(cout << "- 404 Not Found!" << endl);
return false;
}
DEBUG_ONLY(cout << "- 200 OK!" << endl);
return true;
}
bool CAdminSock::UserPage(CString& sPageRet, CUser* pUser) {
if (!GetParam("submitted").ToUInt()) {
sPageRet = Header((pUser) ? CString("Edit User [" + pUser->GetUserName().Escape_n(CString::EHTML) + "]") : CString("Add User"));
CString sAllowedHosts, sServers, sChans, sCTCPReplies;
if (pUser) {
const set& ssAllowedHosts = pUser->GetAllowedHosts();
for (set::const_iterator it = ssAllowedHosts.begin(); it != ssAllowedHosts.end(); it++) {
sAllowedHosts += *it + "\r\n";
}
const vector& vServers = pUser->GetServers();
for (unsigned int a = 0; a < vServers.size(); a++) {
sServers += vServers[a]->GetName() + "\r\n";
}
const vector& vChans = pUser->GetChans();
for (unsigned int b = 0; b < vChans.size(); b++) {
CChan* pChan = vChans[b];
if (pChan->InConfig()) {
sChans += vChans[b]->GetName() + "\r\n";
}
}
const MCString& msCTCPReplies = pUser->GetCTCPReplies();
for (MCString::const_iterator it2 = msCTCPReplies.begin(); it2 != msCTCPReplies.end(); it2++) {
sCTCPReplies += it2->first + " " + it2->second + "\r\n";
}
}
sPageRet += "\r\n";
sPageRet += Footer();
return true;
}
CString sUsername = GetParam("user");
if (!pUser && m_pModule->GetZNC()->FindUser(sUsername)) {
GetErrorPage(sPageRet, "Invalid Submission [User " + sUsername.Escape_n(CString::EHTML) + " already exists]");
return true;
}
CUser* pNewUser = GetNewUser(sPageRet);
if (!pNewUser) {
return true;
}
CString sErr;
if (!pUser) {
// Add User Submission
if (!pNewUser->IsValid(sErr)) {
delete pNewUser;
GetErrorPage(sPageRet, "Invalid submission [" + sErr.Escape_n(CString::EHTML) + "]");
return true;
}
m_pModule->GetZNC()->AddUser(pNewUser);
if (!m_pModule->GetZNC()->WriteConfig()) {
GetErrorPage(sPageRet, "User edited, but config was not written");
return true;
}
} else {
// Edit User Submission
if (!pUser->Clone(*pNewUser, sErr)) {
delete pNewUser;
GetErrorPage(sPageRet, "Invalid Submission [" + sErr.Escape_n(CString::EHTML) + "]");
return true;
}
delete pNewUser;
if (!m_pModule->GetZNC()->WriteConfig()) {
GetErrorPage(sPageRet, "User edited, but config was not written");
return true;
}
}
if (m_pUser) {
Redirect("/edituser");
} else {
Redirect("/listusers");
}
return false;
}
CUser* CAdminSock::GetNewUser(CString& sPageRet) {
CString sUsername = GetParam("newuser");
if (sUsername.empty()) {
sUsername = GetParam("user");
}
if (sUsername.empty()) {
GetErrorPage(sPageRet, "Invalid Submission [Username is required]");
return NULL;
}
CString sArg = GetParam("password");
if (sArg != GetParam("password2")) {
GetErrorPage(sPageRet, "Invalid Submission [Passwords do not match]");
return NULL;
}
CUser* pNewUser = new CUser(sUsername, m_pModule->GetZNC());
if (!sArg.empty()) {
pNewUser->SetPass(sArg.MD5(), true);
}
VCString vsArgs;
GetParam("servers").Split("\n", vsArgs);
unsigned int a = 0;
for (a = 0; a < vsArgs.size(); a++) {
pNewUser->AddServer(vsArgs[a].Trim_n());
}
GetParam("allowedips").Split("\n", vsArgs);
for (a = 0; a < vsArgs.size(); a++) {
pNewUser->AddAllowedHost(vsArgs[a].Trim_n());
}
GetParam("ctcpreplies").Split("\n", vsArgs);
for (a = 0; a < vsArgs.size(); a++) {
CString sReply = vsArgs[a].TrimRight_n("\r");
pNewUser->AddCTCPReply(sReply.Token(0).Trim_n(), sReply.Token(1, true).Trim_n());
}
GetParamValues("loadmod", vsArgs);
for (a = 0; a < vsArgs.size(); a++) {
CString sModRet;
CString sArg = vsArgs[a].TrimRight_n("\r");
if (!sArg.empty()) {
pNewUser->GetModules().LoadModule(sArg, "", pNewUser, sModRet);
}
}
sArg = GetParam("nick"); if (!sArg.empty()) { pNewUser->SetNick(sArg); }
sArg = GetParam("altnick"); if (!sArg.empty()) { pNewUser->SetAltNick(sArg); }
sArg = GetParam("awaysuffix"); if (!sArg.empty()) { pNewUser->SetAwaySuffix(sArg); }
sArg = GetParam("statusprefix"); if (!sArg.empty()) { pNewUser->SetStatusPrefix(sArg); }
sArg = GetParam("ident"); if (!sArg.empty()) { pNewUser->SetIdent(sArg); }
sArg = GetParam("realname"); if (!sArg.empty()) { pNewUser->SetRealName(sArg); }
sArg = GetParam("vhost"); if (!sArg.empty()) { pNewUser->SetVHost(sArg); }
sArg = GetParam("quitmsg"); if (!sArg.empty()) { pNewUser->SetQuitMsg(sArg); }
sArg = GetParam("chanmodes"); if (!sArg.empty()) { pNewUser->SetDefaultChanModes(sArg); }
pNewUser->SetBufferCount(GetParam("bufsize").ToUInt());
pNewUser->SetKeepBuffer(GetParam("keepbuffer").ToBool());
pNewUser->SetBounceDCCs(GetParam("bouncedccs").ToBool());
pNewUser->SetAutoCycle(GetParam("autocycle").ToBool());
pNewUser->SetKeepNick(GetParam("keepnick").ToBool());
pNewUser->SetUseClientIP(GetParam("useclientip").ToBool());
pNewUser->SetDenyLoadMod(GetParam("denyloadmod").ToBool());
GetParam("channels").Split("\n", vsArgs);
for (a = 0; a < vsArgs.size(); a++) {
pNewUser->AddChan(vsArgs[a].TrimRight_n("\r"), true);
}
return pNewUser;
}
GLOBALMODULEDEFS(CAdminMod, "Add, Edit, Remove users on the fly")