Import most of znc-extra

This imports all modules from znc-extra except modtcl under modules/extra.


git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1606 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
psychon
2009-08-20 19:54:27 +00:00
parent 0b7576a474
commit 658e529c96
15 changed files with 1597 additions and 0 deletions
+1
View File
@@ -22,3 +22,4 @@ Sebastian Ramacher <sebastinas@users.sourceforge.net>
cnu - master of destruction (security issues)
Ingmar "KiNgMaR" Runge <mail@irsoft.de>
Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
Robert Lacroix (http://www.robertlacroix.com)
+101
View File
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "Nick.h"
#include "User.h"
class CAntiIdle;
class CAntiIdleJob : public CTimer
{
public:
CAntiIdleJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription)
: CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CAntiIdleJob() {}
protected:
virtual void RunJob();
};
class CAntiIdle : public CModule
{
public:
MODCONSTRUCTOR(CAntiIdle) {
SetInterval(30);
}
virtual ~CAntiIdle() {}
virtual bool OnLoad(const CString& sArgs, CString& sErrorMsg)
{
if(!sArgs.Trim_n().empty())
SetInterval(sArgs.ToInt());
return true;
}
virtual void OnModCommand( const CString& sCommand )
{
CString sCmdName = sCommand.Token(0).AsLower();
if(sCmdName == "set")
{
CString sInterval = sCommand.Token(1, true);
SetInterval(sInterval.ToInt());
if(m_uiInterval == 0)
PutModule("AntiIdle is now turned off.");
else
PutModule("AntiIdle is now set to " + CString(m_uiInterval) + " seconds.");
} else if(sCmdName == "off") {
SetInterval(0);
PutModule("AntiIdle is now turned off");
} else if(sCmdName == "show") {
if(m_uiInterval == 0)
PutModule("AntiIdle is turned off.");
else
PutModule("AntiIdle is set to " + CString(m_uiInterval) + " seconds.");
} else {
PutModule("Commands: set, off, show");
}
}
virtual EModRet OnPrivMsg(CNick &Nick, CString &sMessage)
{
if(Nick.GetNick() == GetUser()->GetIRCNick().GetNick()
&& sMessage == "\xAE")
return HALTCORE;
return CONTINUE;
}
private:
void SetInterval(int i)
{
if(i < 0)
return;
m_uiInterval = i;
RemTimer("AntiIdle");
if(m_uiInterval == 0) {
return;
}
AddTimer(new CAntiIdleJob(this, m_uiInterval, 0, "AntiIdle", "Periodically sends a msg to the user"));
}
unsigned int m_uiInterval;
};
//! This function sends a query with (r) back to the user
void CAntiIdleJob::RunJob() {
CString sNick = GetModule()->GetUser()->GetIRCNick().GetNick();
GetModule()->PutIRC("PRIVMSG " + sNick + " :\xAE");
}
MODULEDEFS(CAntiIdle, "Hides your real idle time")
+278
View File
@@ -0,0 +1,278 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "Chan.h"
#include "User.h"
class CAutoVoiceUser {
public:
CAutoVoiceUser() {}
CAutoVoiceUser(const CString& sLine) {
FromString(sLine);
}
CAutoVoiceUser(const CString& sUsername, const CString& sHostmask, const CString& sChannels) :
m_sUsername(sUsername),
m_sHostmask(sHostmask) {
AddChans(sChannels);
}
virtual ~CAutoVoiceUser() {}
const CString& GetUsername() const { return m_sUsername; }
const CString& GetHostmask() const { return m_sHostmask; }
bool ChannelMatches(const CString& sChan) const {
for (set<CString>::const_iterator it = m_ssChans.begin(); it != m_ssChans.end(); it++) {
if (sChan.AsLower().WildCmp(*it)) {
return true;
}
}
return false;
}
bool HostMatches(const CString& sHostmask) {
return sHostmask.WildCmp(m_sHostmask);
}
CString GetChannels() const {
CString sRet;
for (set<CString>::const_iterator it = m_ssChans.begin(); it != m_ssChans.end(); it++) {
if (!sRet.empty()) {
sRet += " ";
}
sRet += *it;
}
return sRet;
}
void DelChans(const CString& sChans) {
VCString vsChans;
sChans.Split(" ", vsChans);
for (unsigned int a = 0; a < vsChans.size(); a++) {
m_ssChans.erase(vsChans[a].AsLower());
}
}
void AddChans(const CString& sChans) {
VCString vsChans;
sChans.Split(" ", vsChans);
for (unsigned int a = 0; a < vsChans.size(); a++) {
m_ssChans.insert(vsChans[a].AsLower());
}
}
CString ToString() const {
CString sChans;
for (set<CString>::const_iterator it = m_ssChans.begin(); it != m_ssChans.end(); it++) {
if (!sChans.empty()) {
sChans += " ";
}
sChans += *it;
}
return m_sUsername + "\t" + m_sHostmask + "\t" + sChans;
}
bool FromString(const CString& sLine) {
m_sUsername = sLine.Token(0, false, "\t");
m_sHostmask = sLine.Token(1, false, "\t");
sLine.Token(2, false, "\t").Split(" ", m_ssChans);
return !m_sHostmask.empty();
}
private:
protected:
CString m_sUsername;
CString m_sHostmask;
set<CString> m_ssChans;
};
class CAutoVoiceMod : public CModule {
public:
MODCONSTRUCTOR(CAutoVoiceMod) {}
virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
// Load the chans from the command line
unsigned int a = 0;
CString sChan = sArgs.Token(a++);
while (!sChan.empty()) {
CString sName = "Args";
sName += CString(a);
AddUser(sName, "*", sChan);
sChan = sArgs.Token(a++);
}
// Load the saved users
for (MCString::iterator it = BeginNV(); it != EndNV(); it++) {
const CString& sLine = it->second;
CAutoVoiceUser* pUser = new CAutoVoiceUser;
if (!pUser->FromString(sLine) || FindUser(pUser->GetUsername().AsLower())) {
delete pUser;
} else {
m_msUsers[pUser->GetUsername().AsLower()] = pUser;
}
}
return true;
}
virtual ~CAutoVoiceMod() {
for (map<CString, CAutoVoiceUser*>::iterator it = m_msUsers.begin(); it != m_msUsers.end(); it++) {
delete it->second;
}
m_msUsers.clear();
}
virtual void OnJoin(const CNick& Nick, CChan& Channel) {
// If we have ops in this chan
if (Channel.HasPerm(CChan::Op) || Channel.HasPerm(CChan::HalfOp)) {
for (map<CString, CAutoVoiceUser*>::iterator it = m_msUsers.begin(); it != m_msUsers.end(); it++) {
// and the nick who joined is a valid user
if (it->second->HostMatches(Nick.GetHostMask()) && it->second->ChannelMatches(Channel.GetName())) {
PutIRC("MODE " + Channel.GetName() + " +v " + Nick.GetNick());
break;
}
}
}
}
virtual void OnModCommand(const CString& sLine) {
CString sCommand = sLine.Token(0).AsUpper();
if (sCommand.Equals("HELP")) {
PutModule("Commands are: ListUsers, AddChans, DelChans, AddUser, DelUser");
} else if (sCommand.Equals("ADDUSER") || sCommand.Equals("DELUSER")) {
CString sUser = sLine.Token(1);
CString sHost = sLine.Token(2);
if (sCommand.Equals("ADDUSER")) {
if (sHost.empty()) {
PutModule("Usage: " + sCommand + " <user> <hostmask> [channels]");
} else {
CAutoVoiceUser* pUser = AddUser(sUser, sHost, sLine.Token(3, true));
if (pUser) {
SetNV(sUser, pUser->ToString());
}
}
} else {
DelUser(sUser);
DelNV(sUser);
}
} else if (sCommand.Equals("LISTUSERS")) {
if (m_msUsers.empty()) {
PutModule("There are no users defined");
return;
}
CTable Table;
Table.AddColumn("User");
Table.AddColumn("Hostmask");
Table.AddColumn("Channels");
for (map<CString, CAutoVoiceUser*>::iterator it = m_msUsers.begin(); it != m_msUsers.end(); it++) {
Table.AddRow();
Table.SetCell("User", it->second->GetUsername());
Table.SetCell("Hostmask", it->second->GetHostmask());
Table.SetCell("Channels", it->second->GetChannels());
}
PutModule(Table);
} else if (sCommand.Equals("ADDCHANS") || sCommand.Equals("DELCHANS")) {
CString sUser = sLine.Token(1);
CString sChans = sLine.Token(2, true);
if (sChans.empty()) {
PutModule("Usage: " + sCommand + " <user> <channel> [channel] ...");
return;
}
CAutoVoiceUser* pUser = FindUser(sUser);
if (!pUser) {
PutModule("No such user");
return;
}
if (sCommand.Equals("ADDCHANS")) {
pUser->AddChans(sChans);
PutModule("Channel(s) added to user [" + pUser->GetUsername() + "]");
} else {
pUser->DelChans(sChans);
PutModule("Channel(s) Removed from user [" + pUser->GetUsername() + "]");
}
SetNV(pUser->GetUsername(), pUser->ToString());
} else {
PutModule("Unknown command, try HELP");
}
}
CAutoVoiceUser* FindUser(const CString& sUser) {
map<CString, CAutoVoiceUser*>::iterator it = m_msUsers.find(sUser.AsLower());
return (it != m_msUsers.end()) ? it->second : NULL;
}
CAutoVoiceUser* FindUserByHost(const CString& sHostmask, const CString& sChannel = "") {
for (map<CString, CAutoVoiceUser*>::iterator it = m_msUsers.begin(); it != m_msUsers.end(); it++) {
CAutoVoiceUser* pUser = it->second;
if (pUser->HostMatches(sHostmask) && (sChannel.empty() || pUser->ChannelMatches(sChannel))) {
return pUser;
}
}
return NULL;
}
void DelUser(const CString& sUser) {
map<CString, CAutoVoiceUser*>::iterator it = m_msUsers.find(sUser.AsLower());
if (it == m_msUsers.end()) {
PutModule("That user does not exist");
return;
}
delete it->second;
m_msUsers.erase(it);
PutModule("User [" + sUser + "] removed");
}
CAutoVoiceUser* AddUser(const CString& sUser, const CString& sHost, const CString& sChans) {
if (m_msUsers.find(sUser) != m_msUsers.end()) {
PutModule("That user already exists");
return NULL;
}
CAutoVoiceUser* pUser = new CAutoVoiceUser(sUser, sHost, sChans);
m_msUsers[sUser.AsLower()] = pUser;
PutModule("User [" + sUser + "] added with hostmask [" + sHost + "]");
return pUser;
}
private:
map<CString, CAutoVoiceUser*> m_msUsers;
};
MODULEDEFS(CAutoVoiceMod, "Auto voice the good guys")
+133
View File
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "User.h"
#include "IRCSock.h"
#include "znc.h"
#define MESSAGE "Your account has been disabled. Contact your administrator."
class CBlockUser : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CBlockUser) {}
virtual ~CBlockUser() {}
virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
VCString vArgs;
VCString::iterator it;
MCString::iterator it2;
// Load saved settings
for (it2 = BeginNV(); it2 != EndNV(); it2++) {
// Ignore errors
Block(it2->first);
}
// Parse arguments, each argument is a user name to block
sArgs.Split(" ", vArgs, false);
for (it = vArgs.begin(); it != vArgs.end(); it++) {
if (!Block(*it)) {
sMessage = "Could not block [" + *it + "]";
return false;
}
}
return true;
}
virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
if (IsBlocked(Auth->GetUsername())) {
Auth->RefuseLogin(MESSAGE);
return HALT;
}
return CONTINUE;
}
void OnModCommand(const CString& sCommand) {
CString sCmd = sCommand.Token(0);
if (sCmd.Equals("list")) {
CTable Table;
MCString::iterator it;
Table.AddColumn("Blocked user");
for (it = BeginNV(); it != EndNV(); it++) {
Table.AddRow();
Table.SetCell("Blocked user", it->first);
}
if (PutModule(Table) == 0)
PutModule("No users blocked");
} else if (sCmd.Equals("block")) {
CString sUser = sCommand.Token(1, true);
if (m_pUser->GetUserName().Equals(sUser)) {
PutModule("You can't block yourself");
return;
}
if (Block(sUser))
PutModule("Blocked [" + sUser + "]");
else
PutModule("Could not block [" + sUser + "] (misspelled?)");
} else if (sCmd.Equals("unblock")) {
CString sUser = sCommand.Token(1, true);
if (DelNV(sUser))
PutModule("Unblocked [" + sUser + "]");
else
PutModule("This user is not blocked");
} else if (sCmd.Equals("help")) {
PutModule("Commands: list, block [user], unblock [user]");
}
}
private:
bool IsBlocked(const CString& sUser) {
MCString::iterator it;
for (it = BeginNV(); it != EndNV(); it++) {
if (sUser.Equals(it->first)) {
return true;
}
}
return false;
}
bool Block(const CString& sUser) {
CUser *pUser = CZNC::Get().FindUser(sUser);
if (!pUser)
return false;
// Disconnect all clients
vector<CClient*>& vpClients = pUser->GetClients();
vector<CClient*>::iterator it;
for (it = vpClients.begin(); it != vpClients.end(); it++) {
(*it)->PutStatusNotice(MESSAGE);
(*it)->Close(Csock::CLT_AFTERWRITE);
}
// Disconnect from IRC...
CIRCSock *pIRCSock = pUser->GetIRCSock();
if (pIRCSock) {
pIRCSock->Quit();
}
// ...and don't reconnect
pUser->SetIRCConnectEnabled(false);
SetNV(pUser->GetUserName(), "");
return true;
}
};
GLOBALMODULEDEFS(CBlockUser, "Block certain users from logging in")
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "znc.h"
class CConnectThrottleMod : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CConnectThrottleMod) {}
virtual ~CConnectThrottleMod() {}
virtual bool OnLoad(const CString& sArgs, CString& sMessage)
{
unsigned int timeout = sArgs.ToUInt();
if (sArgs.empty()) {
timeout = 60; // 1 min
} else if (timeout == 0 && sArgs != "0") {
sMessage = "Invalid argument, must be a positive number "
"which is the time one has to wait after failed login attempts";
return false;
}
// SetTTL() wants milliseconds
m_Cache.SetTTL(timeout * 1000);
return true;
}
virtual void OnClientConnect(CClient* pClient, const CString& sHost, unsigned short uPort) {
if (sHost.empty() || !m_Cache.HasItem(sHost)) {
return;
}
// refresh their ban
m_Cache.AddItem(sHost);
pClient->PutClient("ERROR :Closing link [Please try again later - reconnecting too fast]");
pClient->Close(Csock::CLT_AFTERWRITE);
}
virtual void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {
m_Cache.AddItem(sRemoteIP);
}
virtual EModRet OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
// e.g. webadmin ends up here
const CString &sRemoteIP = Auth->GetRemoteIP();
if (sRemoteIP.empty())
return CONTINUE;
if (m_Cache.HasItem(sRemoteIP)) {
// refresh their ban
m_Cache.AddItem(sRemoteIP);
Auth->RefuseLogin("Please try again later - reconnecting too fast");
return HALT;
}
return CONTINUE;
}
private:
TCacheMap<CString> m_Cache;
};
GLOBALMODULEDEFS(CConnectThrottleMod, "Limit the number of login attempts a user can make per time")
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "Modules.h"
#include "Chan.h"
class CCtcpFloodMod : public CModule {
public:
MODCONSTRUCTOR(CCtcpFloodMod) {
m_tLastCTCP = 0;
m_iNumCTCP = 0;
}
~CCtcpFloodMod() {
}
void Save() {
// We save the settings twice because the module arguments can
// be more easily edited via webadmin, while the SetNV() stuff
// survives e.g. /msg *status reloadmod ctcpflood.
SetNV("secs", CString(m_iThresholdSecs));
SetNV("msgs", CString(m_iThresholdMsgs));
SetArgs(CString(m_iThresholdMsgs) + " " + CString(m_iThresholdSecs));
}
bool OnLoad(const CString& sArgs, CString& sMessage) {
m_iThresholdMsgs = sArgs.Token(0).ToUInt();
m_iThresholdSecs = sArgs.Token(1).ToUInt();
if (m_iThresholdMsgs == 0 || m_iThresholdSecs == 0) {
m_iThresholdMsgs = GetNV("msgs").ToUInt();
m_iThresholdSecs = GetNV("secs").ToUInt();
}
if (m_iThresholdSecs == 0)
m_iThresholdSecs = 2;
if (m_iThresholdMsgs == 0)
m_iThresholdMsgs = 4;
Save();
return true;
}
EModRet Message(const CNick& Nick, const CString& sMessage) {
// We never block /me, because it doesn't cause a reply
if (sMessage.Token(0).Equals("ACTION"))
return CONTINUE;
if (m_tLastCTCP + m_iThresholdSecs < time(NULL)) {
m_tLastCTCP = time(NULL);
m_iNumCTCP = 0;
}
m_iNumCTCP++;
if (m_iNumCTCP < m_iThresholdMsgs)
return CONTINUE;
else if (m_iNumCTCP == m_iThresholdMsgs)
PutModule("Limit reached by [" + Nick.GetHostMask() + "], blocking all CTCP");
// Reset the timeout so that we continue blocking messages
m_tLastCTCP = time(NULL);
return HALT;
}
EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) {
return Message(Nick, sMessage);
}
EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) {
return Message(Nick, sMessage);
}
void OnModCommand(const CString& sCommand) {
const CString& sCmd = sCommand.Token(0);
const CString& sArg = sCommand.Token(1, true);
if (sCmd.Equals("secs") && !sArg.empty()) {
m_iThresholdSecs = sArg.ToUInt();
if (m_iThresholdSecs == 0)
m_iThresholdSecs = 1;
PutModule("Set seconds limit to [" + CString(m_iThresholdSecs) + "]");
Save();
} else if (sCmd.Equals("lines") && !sArg.empty()) {
m_iThresholdMsgs = sArg.ToUInt();
if (m_iThresholdMsgs == 0)
m_iThresholdMsgs = 2;
PutModule("Set lines limit to [" + CString(m_iThresholdMsgs) + "]");
Save();
} else if (sCmd.Equals("show")) {
PutModule("Current limit is " + CString(m_iThresholdMsgs) + " CTCPs "
"in " + CString(m_iThresholdSecs) + " secs");
} else {
PutModule("Commands: show, secs [limit], lines [limit]");
}
}
private:
time_t m_tLastCTCP;
unsigned int m_iNumCTCP;
time_t m_iThresholdSecs;
unsigned int m_iThresholdMsgs;
};
MODULEDEFS(CCtcpFloodMod, "Don't forward CTCP floods to clients")
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "Modules.h"
#include "User.h"
#include "Chan.h"
class CKickClientOnIRCDisconnect: public CModule {
public:
MODCONSTRUCTOR(CKickClientOnIRCDisconnect) {}
void OnIRCDisconnected()
{
const vector<CChan*>& vChans = m_pUser->GetChans();
for(vector<CChan*>::const_iterator it = vChans.begin(); it != vChans.end(); it++)
{
PutUser(":ZNC!znc@znc.in KICK " + (*it)->GetName() + " " + m_pUser->GetIRCNick().GetNick()
+ " :You have been disconnected from the IRC server");
}
}
};
MODULEDEFS(CKickClientOnIRCDisconnect, "Kicks the client from all channels when the connection to the IRC server is lost")
+144
View File
@@ -0,0 +1,144 @@
/*
* droproot.cpp
*
* Copyright (c) 2009 Vadtec (vadtec@vadtec.net)
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* Copyright (C) 2004-2008 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "znc.h"
#include "User.h"
#include <pwd.h>
#include <grp.h>
class CDroproot : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CDroproot) {
}
virtual ~CDroproot() {
}
uid_t GetUser(const CString& sUser, CString& sMessage) {
uid_t ret = sUser.ToUInt();
if (ret != 0)
return ret;
struct passwd *pUser = getpwnam(sUser.c_str());
if (!pUser) {
sMessage = "User [" + sUser + "] not found!";
return 0;
}
return pUser->pw_uid;
}
gid_t GetGroup(const CString& sGroup, CString& sMessage) {
gid_t ret = sGroup.ToUInt();
if (ret != 0)
return ret;
struct group *pGroup = getgrnam(sGroup.c_str());
if (!pGroup) {
sMessage = "Group [" + sGroup + "] not found!";
return 0;
}
return pGroup->gr_gid;
}
virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
CString sUser = sArgs.Token(0);
CString sGroup = sArgs.Token(1, true);
if (sUser.empty() || sGroup.empty()) {
sMessage = "Usage: LoadModule = Droproot <uid> <gid>";
return false;
}
m_user = GetUser(sUser, sMessage);
if (m_user == 0) {
sMessage
= "Error: Cannot run as root, check your config file | Useage: LoadModule = Droproot <uid> <gid>";
return false;
}
m_group = GetGroup(sGroup, sMessage);
if (m_group == 0) {
sMessage
= "Error: Cannot run as root, check your config file | Useage: LoadModule = Droproot <uid> <gid>";
return false;
}
return true;
}
virtual bool OnBoot() {
int u, eu, g, eg, sg;
if ((geteuid() == 0) || (getuid() == 0) || (getegid() == 0) || (getgid()
== 0)) {
CUtils::PrintAction("Dropping root permissions");
// Clear all the supplementary groups
sg = setgroups(0, NULL);
if (sg < 0) {
CUtils::PrintStatus(false,
"Could not remove supplementary groups! ["
+ CString(strerror(errno)) + "]");
return false;
}
// Set the group (if we are root, this sets all three group IDs)
g = setgid(m_group);
eg = setegid(m_group);
if ((g < 0) || (eg < 0)) {
CUtils::PrintStatus(false, "Could not switch group id! ["
+ CString(strerror(errno)) + "]");
return false;
}
// and set the user (if we are root, this sets all three user IDs)
u = setuid(m_user);
eu = seteuid(m_user);
if ((u < 0) || (eu < 0)) {
CUtils::PrintStatus(false, "Could not switch user id! ["
+ CString(strerror(errno)) + "]");
return false;
}
CUtils::PrintStatus(true);
return true;
}
return true;
}
protected:
uid_t m_user;
gid_t m_group;
};
GLOBALMODULEDEFS(CDroproot, "Allows ZNC to drop root privileges and run as an un-privileged user.")
+93
View File
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2008-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "User.h"
#include "znc.h"
class CFOModule : public CModule {
public:
MODCONSTRUCTOR(CFOModule) {}
virtual ~CFOModule() {}
bool IsOnlineModNick(const CString& sNick) {
const CString& sPrefix = m_pUser->GetStatusPrefix();
if (!sNick.Equals(sPrefix, false, sPrefix.length()))
return false;
CString sModNick = sNick.substr(sPrefix.length());
if (!sModNick.Equals("status") &&
!m_pUser->GetModules().FindModule(sModNick) &&
!CZNC::Get().GetModules().FindModule(sModNick))
return false;
return true;
}
virtual EModRet OnUserRaw(CString& sLine) {
//Handle ISON
if (sLine.Token(0).Equals("ison")) {
VCString vsNicks;
VCString::const_iterator it;
// Get the list of nicks which are being asked for
sLine.Token(1, true).TrimLeft_n(":").Split(" ", vsNicks, false);
CString sBNCNicks = "";
for (it = vsNicks.begin(); it != vsNicks.end(); it++) {
if (IsOnlineModNick(*it)) {
sBNCNicks += " " + *it;
}
}
// Remove the leading space
sBNCNicks.LeftChomp();
// We let the server handle this request and then act on
// the 303 response.
m_ISONRequests.push_back(sBNCNicks);
}
//Handle WHOIS
if (sLine.Token(0).Equals("whois")) {
CString sNick = sLine.Token(1);
if (IsOnlineModNick(sNick)) {
PutUser(":znc.in 311 " + m_pUser->GetCurNick() + " " + sNick + " " + sNick + " znc.in * :" + sNick);
PutUser(":znc.in 312 " + m_pUser->GetCurNick() + " " + sNick + " *.znc.in :Bouncer");
PutUser(":znc.in 318 " + m_pUser->GetCurNick() + " " + sNick + " :End of /WHOIS list.");
return HALT;
}
}
return CONTINUE;
}
virtual EModRet OnRaw(CString& sLine) {
//Handle 303 reply if m_Requests is not empty
if (sLine.Token(1) == "303" && !m_ISONRequests.empty()) {
VCString::iterator it = m_ISONRequests.begin();
sLine.Trim();
// Only append a space if this isn't an empty reply
if (sLine.Right(1) != ":") {
sLine += " ";
}
//add BNC nicks to the reply
sLine += *it;
m_ISONRequests.erase(it);
}
return CONTINUE;
}
private:
VCString m_ISONRequests;
};
MODULEDEFS(CFOModule, "Fakes online status of ZNC *-users.")
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "User.h"
#include "znc.h"
using std::map;
class CLastSeenMod : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CLastSeenMod)
{
}
virtual ~CLastSeenMod() {}
time_t GetTime(CUser *pUser)
{
return GetNV(pUser->GetUserName()).ToULong();
}
void SetTime(CUser *pUser)
{
SetNV(pUser->GetUserName(), CString(time(NULL)));
}
virtual void OnModCommand(const CString& sLine)
{
const CString sCommand = sLine.Token(0).AsLower();
if (!GetUser()->IsAdmin()) {
PutModule("Access denied");
return;
}
if (sCommand == "show") {
char buf[1024];
const map<CString, CUser*>& mUsers = CZNC::Get().GetUserMap();
map<CString, CUser*>::const_iterator it;
CTable Table;
Table.AddColumn("User");
Table.AddColumn("Last Seen");
for (it = mUsers.begin(); it != mUsers.end(); it++) {
CUser *pUser = it->second;
time_t last = GetTime(pUser);
Table.AddRow();
Table.SetCell("User", it->first);
if (last == 0)
Table.SetCell("Last Seen", "never");
else {
strftime(buf, sizeof(buf), "%c", localtime(&last));
Table.SetCell("Last Seen", buf);
}
}
PutModule(Table);
} else {
PutModule("This module only supports 'show'");
}
}
virtual void OnClientLogin()
{
SetTime(GetUser());
}
virtual void OnClientDisconnect()
{
SetTime(GetUser());
}
private:
};
GLOBALMODULEDEFS(CLastSeenMod, "Collects data about when a user last logged in")
+208
View File
@@ -0,0 +1,208 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "Modules.h"
#include "User.h"
#include "znc.h"
#include <queue>
class CSocketSorter {
public:
CSocketSorter(Csock* p) {
m_pSock = p;
}
bool operator<(const CSocketSorter& other) const {
// The 'biggest' item is displayed first.
// return false: this is first
// return true: other is first
// Listeners go to the top
if (m_pSock->GetType() != other.m_pSock->GetType()) {
if (m_pSock->GetType() == Csock::LISTENER)
return false;
if (other.m_pSock->GetType() == Csock::LISTENER)
return true;
}
const CString& sMyName = m_pSock->GetSockName();
const CString& sMyName2 = sMyName.Token(1, true, "::");
bool bMyEmpty = sMyName2.empty();
const CString& sHisName = other.GetSock()->GetSockName();
const CString& sHisName2 = sHisName.Token(1, true, "::");
bool bHisEmpty = sHisName2.empty();
// Then sort by first token after "::"
if (bMyEmpty && !bHisEmpty)
return false;
if (bHisEmpty && !bMyEmpty)
return true;
if (!bMyEmpty && !bHisEmpty) {
int c = sMyName2.StrCmp(sHisName2);
if (c < 0)
return false;
if (c > 0)
return true;
}
// and finally sort by the whole socket name
return sMyName.StrCmp(sHisName) > 0;
}
Csock* GetSock() const { return m_pSock; }
private:
Csock* m_pSock;
};
class CListSockets : public CModule {
public:
MODCONSTRUCTOR(CListSockets) {}
virtual bool OnLoad(const CString& sArgs, CString& sMessage)
{
#ifndef MOD_LISTSOCKETS_ALLOW_EVERYONE
if (!m_pUser->IsAdmin()) {
sMessage = "You must be admin to use this module";
return false;
}
#endif
return true;
}
virtual void OnModCommand(const CString& sLine) {
CString sCommand = sLine.Token(0);
CString sArg = sLine.Token(1, true);
if (sCommand.Equals("LIST")) {
bool bShowHosts = true;
if (sArg.Equals("-n")) {
bShowHosts = false;
}
ShowSocks(bShowHosts);
} else {
PutModule("Use 'list' to view a list of active sockets");
PutModule("Use 'list -n' if you want IP addresses to be displayed");
}
}
void ShowSocks(bool bShowHosts) {
CSockManager& m = CZNC::Get().GetManager();
if (!m.size()) {
PutStatus("You have no open sockets.");
return;
}
std::priority_queue<CSocketSorter> socks;
for (unsigned int a = 0; a < m.size(); a++) {
socks.push(m[a]);
}
CTable Table;
Table.AddColumn("Name");
Table.AddColumn("Created");
Table.AddColumn("State");
#ifdef HAVE_LIBSSL
Table.AddColumn("SSL");
#endif
Table.AddColumn("Local");
Table.AddColumn("Remote");
while (!socks.empty()) {
Csock* pSocket = socks.top().GetSock();
socks.pop();
Table.AddRow();
switch (pSocket->GetType()) {
case Csock::LISTENER:
Table.SetCell("State", "Listen");
break;
case Csock::INBOUND:
Table.SetCell("State", "Inbound");
break;
case Csock::OUTBOUND:
if (pSocket->IsConnected())
Table.SetCell("State", "Outbound");
else
Table.SetCell("State", "Connecting");
break;
default:
Table.SetCell("State", "UNKNOWN");
break;
}
unsigned long long iStartTime = pSocket->GetStartTime();
time_t iTime = iStartTime / 1000;
Table.SetCell("Created", FormatTime("%Y-%m-%d %H:%M:%S", iTime));
#ifdef HAVE_LIBSSL
if (pSocket->GetSSL()) {
Table.SetCell("SSL", "Yes");
} else {
Table.SetCell("SSL", "No");
}
#endif
Table.SetCell("Name", pSocket->GetSockName());
CString sVHost;
if (bShowHosts) {
sVHost = pSocket->GetBindHost();
}
if (sVHost.empty()) {
sVHost = pSocket->GetLocalIP();
}
Table.SetCell("Local", sVHost + " " + CString(pSocket->GetLocalPort()));
CString sHost;
if (!bShowHosts) {
sHost = pSocket->GetRemoteIP();
}
// While connecting, there might be no ip available
if (sHost.empty()) {
sHost = pSocket->GetHostName();
}
u_short uPort;
// While connecting, GetRemotePort() would return 0
if (pSocket->GetType() == Csock::OUTBOUND) {
uPort = pSocket->GetPort();
} else {
uPort = pSocket->GetRemotePort();
}
if (uPort != 0) {
Table.SetCell("Remote", sHost + " " + CString(uPort));
} else {
Table.SetCell("Remote", sHost);
}
}
PutModule(Table);
return;
}
virtual ~CListSockets() {
}
CString FormatTime(const CString& sFormat, time_t tm = 0) const {
char szTimestamp[1024];
if (tm == 0) {
tm = time(NULL);
}
// offset is in hours
tm += (time_t)(m_pUser->GetTimezoneOffset() * 60 * 60);
strftime(szTimestamp, sizeof(szTimestamp) / sizeof(char),
sFormat.c_str(), localtime(&tm));
return szTimestamp;
}
};
MODULEDEFS(CListSockets, "List active sockets")
+214
View File
@@ -0,0 +1,214 @@
/*
* Copyright (C) 2008-2009 See the AUTHORS file for details.
* Copyright (C) 2006-2007, CNU <bshalm@broadpark.no> (http://cnu.dieplz.net/znc)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "User.h"
#include "Chan.h"
#include "Server.h"
class CLogMod: public CModule {
public:
MODCONSTRUCTOR(CLogMod) {}
void PutLog(const CString& sLine, const CString& sWindow = "status");
void PutLog(const CString& sLine, const CChan& Channel);
void PutLog(const CString& sLine, const CNick& Nick);
CString GetServer();
virtual void OnIRCConnected();
virtual void OnIRCDisconnected();
virtual EModRet OnBroadcast(CString& sMessage);
virtual void OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs);
virtual void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage);
virtual void OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans);
virtual void OnJoin(const CNick& Nick, CChan& Channel);
virtual void OnPart(const CNick& Nick, CChan& Channel);
virtual void OnNick(const CNick& OldNick, const CString& sNewNick, const vector<CChan*>& vChans);
virtual EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic);
/* notices */
virtual EModRet OnUserNotice(CString& sTarget, CString& sMessage);
virtual EModRet OnPrivNotice(CNick& Nick, CString& sMessage);
virtual EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage);
/* actions */
virtual EModRet OnUserAction(CString& sTarget, CString& sMessage);
virtual EModRet OnPrivAction(CNick& Nick, CString& sMessage);
virtual EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage);
/* msgs */
virtual EModRet OnUserMsg(CString& sTarget, CString& sMessage);
virtual EModRet OnPrivMsg(CNick& Nick, CString& sMessage);
virtual EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage);
};
void CLogMod::PutLog(const CString& sLine, const CString& sWindow /*= "Status"*/)
{
CString sPath;
time_t curtime;
tm* timeinfo;
char buffer[1024];
time(&curtime);
// Don't forget the user's timezone offset (which is in hours and we want seconds)
curtime += (time_t) (m_pUser->GetTimezoneOffset() * 60 * 60);
timeinfo = localtime(&curtime);
/* Generate file name: ~/.znc/users/<user>/moddata/log/WINDOW_YYYYMMDD.log */
sPath = GetSavePath() + "/" + sWindow.Replace_n("/", "?") + "_";
snprintf(buffer, sizeof(buffer), "%04d%02d%02d.log", timeinfo->tm_year + 1900,
timeinfo->tm_mon + 1, timeinfo->tm_mday);
sPath += buffer;
CFile LogFile(sPath);
if (LogFile.Open(O_WRONLY | O_APPEND | O_CREAT))
{
snprintf(buffer, sizeof(buffer), "[%02d:%02d:%02d] ",
timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
LogFile.Write(buffer + sLine + "\n");
} else
DEBUG("Could not open log file [" << sPath << "]: " << strerror(errno));
}
void CLogMod::PutLog(const CString& sLine, const CChan& Channel)
{
PutLog(sLine, Channel.GetName());
}
void CLogMod::PutLog(const CString& sLine, const CNick& Nick)
{
PutLog(sLine, Nick.GetNick());
}
CString CLogMod::GetServer()
{
CServer* pServer = m_pUser->GetCurrentServer();
CString sSSL;
if (!pServer)
return "(no server)";
if (pServer->IsSSL())
sSSL = "+";
return pServer->GetName() + ":" + sSSL + CString(pServer->GetPort());
}
void CLogMod::OnIRCConnected()
{
PutLog("Connected to IRC (" + GetServer() + ")");
}
void CLogMod::OnIRCDisconnected()
{
PutLog("Disconnected from IRC (" + GetServer() + ")");
}
CModule::EModRet CLogMod::OnBroadcast(CString& sMessage)
{
PutLog("Broadcast: " + sMessage);
return CONTINUE;
}
void CLogMod::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs)
{
PutLog("*** " + OpNick.GetNick() + " sets mode: " + sModes + " " + sArgs, Channel);
}
void CLogMod::OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage)
{
PutLog("*** " + sKickedNick + " was kicked by " + OpNick.GetNick() + " (" + sMessage + ")", Channel);
}
void CLogMod::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans)
{
for (std::vector<CChan*>::const_iterator pChan = vChans.begin(); pChan != vChans.end(); ++pChan)
PutLog("*** Quits: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ") (" + sMessage + ")", **pChan);
}
void CLogMod::OnJoin(const CNick& Nick, CChan& Channel)
{
PutLog("*** Joins: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ")", Channel);
}
void CLogMod::OnPart(const CNick& Nick, CChan& Channel)
{
PutLog("*** Parts: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ")", Channel);
}
void CLogMod::OnNick(const CNick& OldNick, const CString& sNewNick, const vector<CChan*>& vChans)
{
for (std::vector<CChan*>::const_iterator pChan = vChans.begin(); pChan != vChans.end(); ++pChan)
PutLog("*** " + OldNick.GetNick() + " is now known as " + sNewNick, **pChan);
}
CModule::EModRet CLogMod::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic)
{
PutLog("*** " + Nick.GetNick() + " changes topic to '" + sTopic + "'", Channel);
return CONTINUE;
}
/* notices */
CModule::EModRet CLogMod::OnUserNotice(CString& sTarget, CString& sMessage)
{
PutLog("-" + GetUser()->GetCurNick() + "- " + sMessage, sTarget);
return CONTINUE;
}
CModule::EModRet CLogMod::OnPrivNotice(CNick& Nick, CString& sMessage)
{
PutLog("-" + Nick.GetNick() + "- " + sMessage, Nick);
return CONTINUE;
}
CModule::EModRet CLogMod::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage)
{
PutLog("-" + Nick.GetNick() + "- " + sMessage, Channel);
return CONTINUE;
}
/* actions */
CModule::EModRet CLogMod::OnUserAction(CString& sTarget, CString& sMessage)
{
PutLog("* " + GetUser()->GetCurNick() + " " + sMessage, sTarget);
return CONTINUE;
}
CModule::EModRet CLogMod::OnPrivAction(CNick& Nick, CString& sMessage)
{
PutLog("* " + Nick.GetNick() + " " + sMessage, Nick);
return CONTINUE;
}
CModule::EModRet CLogMod::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage)
{
PutLog("* " + Nick.GetNick() + " " + sMessage, Channel);
return CONTINUE;
}
/* msgs */
CModule::EModRet CLogMod::OnUserMsg(CString& sTarget, CString& sMessage)
{
PutLog("<" + GetUser()->GetCurNick() + "> " + sMessage, sTarget);
return CONTINUE;
}
CModule::EModRet CLogMod::OnPrivMsg(CNick& Nick, CString& sMessage)
{
PutLog("<" + Nick.GetNick() + "> " + sMessage, Nick);
return CONTINUE;
}
CModule::EModRet CLogMod::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage)
{
PutLog("<" + Nick.GetNick() + "> " + sMessage, Channel);
return CONTINUE;
}
MODULEDEFS(CLogMod, "Write IRC logs")
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "Modules.h"
#include "Client.h"
class CMotdFileMod : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CMotdFileMod) {}
virtual ~CMotdFileMod() {}
virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
if (sArgs.empty()) {
sMessage = "Argument must be path to a MOTD file";
return false;
}
return true;
}
virtual void OnClientLogin() {
CString sFile = GetArgs();
CString sBuffer;
CFile cFile(sFile);
if (!cFile.Open(O_RDONLY)) {
m_pClient->PutStatusNotice("Could not open MOTD file");
return;
}
while (cFile.ReadLine(sBuffer))
m_pClient->PutStatusNotice(sBuffer);
cFile.Close();
}
};
GLOBALMODULEDEFS(CMotdFileMod, "Send MOTD from a file")
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "znc.h"
class CNotifyConnectMod : public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CNotifyConnectMod) {}
virtual void OnClientLogin()
{
SendAdmins(m_pUser->GetUserName() + " attached");
}
virtual void OnClientDisconnect()
{
SendAdmins(m_pUser->GetUserName() + " detached");
}
private:
void SendAdmins(const CString &msg)
{
CZNC::Get().Broadcast(msg, true, NULL, GetClient());
}
};
GLOBALMODULEDEFS(CNotifyConnectMod, "");
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2004-2009 See the AUTHORS file for details.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "User.h"
#include "znc.h"
class CSendRaw_Mod: public CGlobalModule {
public:
GLOBALMODCONSTRUCTOR(CSendRaw_Mod) {}
virtual ~CSendRaw_Mod() {
}
virtual void OnModCommand(const CString& sLine) {
CString sUser = sLine.Token(0);
CString sSend = sLine.Token(1, true);
CUser *pUser;
if (!m_pUser->IsAdmin()) {
PutModule("You must have admin privileges to use this");
return;
}
pUser = CZNC::Get().FindUser(sUser);
if (!pUser) {
PutModule("User not found");
PutModule("The expected format is: <user> <line to send>");
return;
}
pUser->PutIRC(sSend);
PutModule("done");
}
};
GLOBALMODULEDEFS(CSendRaw_Mod, "Let's you send some raw IRC lines as someone else");