- /*
- * Copyright (C) 2004-2010 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.
- *
- * Buffer Saving thing, incase your shit goes out while your out
- * Author: imaginos <imaginos@imaginos.net>
- *
- * Its only as secure as your shell, the encryption only offers a slightly
- * better solution then plain text.
- */
- #define REQUIRESSL
- #define LEGACY_SAVEBUFF
- #include "Chan.h"
- #include "User.h"
- #include <sys/stat.h>
- #define CRYPT_VERIFICATION_TOKEN "::__:SAVEBUFF:__::"
- // this is basically plain text, but so is having the pass in the command line so *shrug*
- // you could at least do something kind of cool like a bunch of unprintable text
- #define CRYPT_LAME_PASS "::__:NOPASS:__::"
- #define CRYPT_ASK_PASS "--ask-pass"
- class CSaveBuff;
- class CSaveBuffJob : public CTimer
- {
- public:
- CSaveBuffJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription)
- : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {}
- virtual ~CSaveBuffJob() {}
- protected:
- virtual void RunJob();
- };
- class CSaveBuff : public CModule
- {
- public:
- MODCONSTRUCTOR(CSaveBuff)
- {
- m_bBootError = false;
- m_bFirstLoad = false;
- }
- virtual ~CSaveBuff()
- {
- if (!m_bBootError)
- {
- SaveBufferToDisk();
- }
- }
- virtual bool OnLoad(const CString& sArgs, CString& sMessage)
- {
- if( sArgs == CRYPT_ASK_PASS )
- {
- char *pPass = getpass( "Enter pass for savebuff: " );
- if( pPass )
- m_sPassword = CBlowfish::MD5( pPass );
- else
- {
- m_bBootError = true;
- sMessage = "Nothing retrieved from console. aborting";
- }
- }
- else if( sArgs.empty() )
- m_sPassword = CBlowfish::MD5( CRYPT_LAME_PASS );
- else
- m_sPassword = CBlowfish::MD5(sArgs);
- return( !m_bBootError );
- }
- virtual void OnIRCConnected()
- {
- // dropped this into here because there seems to have been a changed where the module is loaded before the channels.
- // this is a good trigger to tell it to backfill the channels
- if( !m_bFirstLoad )
- {
- m_bFirstLoad = true;
- AddTimer(new CSaveBuffJob(this, 60, 0, "SaveBuff", "Saves the current buffer to disk every 1 minute"));
- const vector<CChan *>& vChans = m_pUser->GetChans();
- for (u_int a = 0; a < vChans.size(); a++)
- {
- if (!vChans[a]->KeepBuffer())
- continue;
- if (!BootStrap(vChans[a]))
- {
- PutUser(":***!znc@znc.in PRIVMSG " + vChans[a]->GetName() + " :Failed to decrypt this channel, did you change the encryption pass?");
- }
- }
- }
- }
- bool BootStrap(CChan *pChan)
- {
- CString sFile;
- if (DecryptChannel(pChan->GetName(), sFile))
- {
- if (!pChan->GetBuffer().empty())
- return(true); // reloaded a module probably in this case, so just verify we can decrypt the file
- VCString vsLines;
- VCString::iterator it;
- sFile.Split("\n", vsLines);
- for (it = vsLines.begin(); it != vsLines.end(); it++) {
- CString sLine(*it);
- sLine.Trim();
- pChan->AddBuffer(sLine);
- }
- } else
- {
- m_sPassword = "";
- CUtils::PrintError("[" + GetModName() + ".so] Failed to Decrypt [" + pChan->GetName() + "]");
- return(false);
- }
- return(true);
- }
- void SaveBufferToDisk()
- {
- if (!m_sPassword.empty())
- {
- const vector<CChan *>& vChans = m_pUser->GetChans();
- for (u_int a = 0; a < vChans.size(); a++)
- {
- CString sPath = GetPath(vChans[a]->GetName());
- CFile File(sPath);
- if (!vChans[a]->KeepBuffer()) {
- File.Delete();
- continue;
- }
- const vector<CString> & vBuffer = vChans[a]->GetBuffer();
- CString sFile = CRYPT_VERIFICATION_TOKEN;
- for (u_int b = 0; b < vBuffer.size(); b++)
- {
- sFile += vBuffer[b] + "\n";
- }
- CBlowfish c(m_sPassword, BF_ENCRYPT);
- sFile = c.Crypt(sFile);
- if (!sPath.empty())
- {
- if (File.Open(O_WRONLY | O_CREAT | O_TRUNC, 0600)) {
- File.Chmod(0600);
- File.Write(sFile);
- }
- File.Close();
- }
- }
- }
- else
- {
- PutModule( "Password is unset usually meaning the decryption failed. You can setpass to the appropriate pass and things should start working, or setpass to a new pass and save to reinstantiate" );
- }
- }
- virtual void OnModCommand(const CString& sCmdLine)
- {
- CString sCommand = sCmdLine.Token(0);
- CString sArgs = sCmdLine.Token(1, true);
- if (sCommand.Equals("setpass"))
- {
- PutModule("Password set to [" + sArgs + "]");
- m_sPassword = CBlowfish::MD5(sArgs);
- } else if (sCommand.Equals("dumpbuff"))
- {
- CString sFile;
- if (DecryptChannel(sArgs, sFile))
- {
- VCString vsLines;
- VCString::iterator it;
- sFile.Split("\n", vsLines);
- for (it = vsLines.begin(); it != vsLines.end(); it++) {
- CString sLine(*it);
- sLine.Trim();
- PutModule("[" + sLine + "]");
- }
- }
- PutModule("//!-- EOF " + sArgs);
- } else if (sCommand.Equals("replay"))
- {
- Replay(sArgs);
- PutModule("Replayed " + sArgs);
- } else if (sCommand.Equals("save"))
- {
- SaveBufferToDisk();
- PutModule("Done.");
- } else
- PutModule("Unknown command [" + sCommand + "]");
- }
- void Replay(const CString & sChan)
- {
- CString sFile;
- PutUser(":***!znc@znc.in PRIVMSG " + sChan + " :Buffer Playback...");
- if (DecryptChannel(sChan, sFile))
- {
- VCString vsLines;
- VCString::iterator it;
- sFile.Split("\n", vsLines);
- for (it = vsLines.begin(); it != vsLines.end(); it++) {
- CString sLine(*it);
- sLine.Trim();
- PutUser(sLine);
- }
- }
- PutUser(":***!znc@znc.in PRIVMSG " + sChan + " :Playback Complete.");
- }
- CString GetPath(const CString & sChannel)
- {
- CString sBuffer = m_pUser->GetUserName() + sChannel.AsLower();
- CString sRet = GetSavePath();
- sRet += "/" + CBlowfish::MD5(sBuffer, true);
- return(sRet);
- }
- #ifdef LEGACY_SAVEBUFF /* event logging is deprecated now in savebuf. Use buffextras module along side of this */
- CString SpoofChanMsg(const CString & sChannel, const CString & sMesg)
- {
- CString sReturn = ":*" + GetModName() + "!znc@znc.in PRIVMSG " + sChannel + " :" + CString(time(NULL)) + " " + sMesg;
- return(sReturn);
- }
- void AddBuffer(CChan& chan, const CString &sLine)
- {
- // If they have keep buffer disabled, only add messages if no client is connected
- if (!chan.KeepBuffer() && m_pUser->IsUserAttached())
- return;
- chan.AddBuffer(sLine);
- }
- virtual void OnRawMode(const CNick& cOpNick, CChan& cChannel, const CString& sModes, const CString& sArgs)
- {
- AddBuffer(cChannel, SpoofChanMsg(cChannel.GetName(), cOpNick.GetNickMask() + " MODE " + sModes + " " + sArgs));
- }
- virtual void OnQuit(const CNick& cNick, const CString& sMessage, const vector<CChan*>& vChans)
- {
- for (u_int a = 0; a < vChans.size(); a++)
- {
- AddBuffer(*vChans[a], SpoofChanMsg(vChans[a]->GetName(), cNick.GetNickMask() + " QUIT " + sMessage));
- }
- if (cNick.GetNick().Equals(m_pUser->GetNick()))
- SaveBufferToDisk(); // need to force a save here to see this!
- }
- virtual void OnNick(const CNick& cNick, const CString& sNewNick, const vector<CChan*>& vChans)
- {
- for (u_int a = 0; a < vChans.size(); a++)
- {
- AddBuffer(*vChans[a], SpoofChanMsg(vChans[a]->GetName(), cNick.GetNickMask() + " NICK " + sNewNick));
- }
- }
- virtual void OnKick(const CNick& cNick, const CString& sOpNick, CChan& cChannel, const CString& sMessage)
- {
- AddBuffer(cChannel, SpoofChanMsg(cChannel.GetName(), sOpNick + " KICK " + cNick.GetNickMask() + " " + sMessage));
- }
- virtual void OnJoin(const CNick& cNick, CChan& cChannel)
- {
- if (cNick.GetNick().Equals(m_pUser->GetNick()) && cChannel.GetBuffer().empty())
- {
- BootStrap((CChan *)&cChannel);
- if (!cChannel.GetBuffer().empty())
- Replay(cChannel.GetName());
- }
- AddBuffer(cChannel, SpoofChanMsg(cChannel.GetName(), cNick.GetNickMask() + " JOIN"));
- }
- virtual void OnPart(const CNick& cNick, CChan& cChannel)
- {
- AddBuffer(cChannel, SpoofChanMsg(cChannel.GetName(), cNick.GetNickMask() + " PART"));
- if (cNick.GetNick().Equals(m_pUser->GetNick()))
- SaveBufferToDisk(); // need to force a save here to see this!
- }
- virtual EModRet OnTopic (CNick &cNick, CChan &cChannel, CString &sTopic)
- {
- AddBuffer(cChannel, SpoofChanMsg(cChannel.GetName(), cNick.GetNickMask() + " TOPIC :" + sTopic));
- return CONTINUE;
- }
- #endif /* LEGACY_SAVEBUFF */
- private:
- bool m_bBootError;
- bool m_bFirstLoad;
- CString m_sPassword;
- bool DecryptChannel(const CString & sChan, CString & sBuffer)
- {
- CString sChannel = GetPath(sChan);
- CString sFile;
- sBuffer = "";
- CFile File(sChannel);
- if (sChannel.empty() || !File.Open() || !File.ReadFile(sFile))
- return(true); // gonna be successful here
- File.Close();
- if (!sFile.empty())
- {
- CBlowfish c(m_sPassword, BF_DECRYPT);
- sBuffer = c.Crypt(sFile);
- if (sBuffer.Left(strlen(CRYPT_VERIFICATION_TOKEN)) != CRYPT_VERIFICATION_TOKEN)
- {
- // failed to decode :(
- PutModule("Unable to decode Encrypted file [" + sChannel + "]");
- return(false);
- }
- sBuffer.erase(0, strlen(CRYPT_VERIFICATION_TOKEN));
- }
- return(true);
- }
- };
- void CSaveBuffJob::RunJob()
- {
- CSaveBuff *p = (CSaveBuff *)m_pModule;
- p->SaveBufferToDisk();
- }
- MODULEDEFS(CSaveBuff, "Stores channel buffers to disk, encrypted")
ZNC modified savebuff.cpp
Posted by Admin on Sun 7th Mar 2010 11:16
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.