diff options
Diffstat (limited to 'bin/bbstored')
-rw-r--r-- | bin/bbstored/BBStoreDHousekeeping.cpp | 192 | ||||
-rw-r--r-- | bin/bbstored/BackupCommands.cpp | 96 | ||||
-rw-r--r-- | bin/bbstored/BackupConstants.h | 2 | ||||
-rw-r--r-- | bin/bbstored/BackupContext.cpp | 17 | ||||
-rw-r--r-- | bin/bbstored/BackupContext.h | 2 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreDaemon.cpp | 93 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreDaemon.h | 17 | ||||
-rw-r--r-- | bin/bbstored/HousekeepStoreAccount.cpp | 72 | ||||
-rw-r--r-- | bin/bbstored/HousekeepStoreAccount.h | 2 | ||||
-rw-r--r-- | bin/bbstored/Makefile.extra | 2 | ||||
-rwxr-xr-x | bin/bbstored/bbstored-certs | 2 | ||||
-rwxr-xr-x | bin/bbstored/bbstored-certs.in | 319 | ||||
-rwxr-xr-x | bin/bbstored/bbstored-config | 2 | ||||
-rwxr-xr-x | bin/bbstored/bbstored-config.in | 242 | ||||
-rw-r--r-- | bin/bbstored/bbstored.cpp | 16 |
15 files changed, 931 insertions, 145 deletions
diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index dd2afcba..5d6855ee 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -48,7 +48,6 @@ #include "Box.h" #include <stdio.h> -#include <syslog.h> #include "BackupStoreDaemon.h" #include "BackupStoreAccountDatabase.h" @@ -67,95 +66,143 @@ // Created: 11/12/03 // // -------------------------------------------------------------------------- +void BackupStoreDaemon::HousekeepingInit() +{ + + mLastHousekeepingRun = 0; +} + void BackupStoreDaemon::HousekeepingProcess() { + HousekeepingInit(); + // Get the time between housekeeping runs const Configuration &rconfig(GetConfiguration()); int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); - - int64_t lastHousekeepingRun = 0; while(!StopRun()) { - // Time now + RunHousekeepingIfNeeded(); + + // Calculate how long should wait before doing the next + // housekeeping run int64_t timeNow = GetCurrentBoxTime(); - // Do housekeeping if the time interval has elapsed since the last check - if((timeNow - lastHousekeepingRun) >= housekeepingInterval) - { - // Store the time - lastHousekeepingRun = timeNow; - ::syslog(LOG_INFO, "Starting housekeeping"); + time_t secondsToGo = BoxTimeToSeconds( + (mLastHousekeepingRun + housekeepingInterval) - + timeNow); + if(secondsToGo < 1) secondsToGo = 1; + if(secondsToGo > 60) secondsToGo = 60; + int32_t millisecondsToGo = ((int)secondsToGo) * 1000; + + // Check to see if there's any message pending + CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); + } +} - // Get the list of accounts - std::vector<int32_t> accounts; - if(mpAccountDatabase) - { - mpAccountDatabase->GetAllAccountIDs(accounts); - } +void BackupStoreDaemon::RunHousekeepingIfNeeded() +{ + // Get the time between housekeeping runs + const Configuration &rconfig(GetConfiguration()); + int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); + + // Time now + int64_t timeNow = GetCurrentBoxTime(); + + // Do housekeeping if the time interval has elapsed since the last check + if((timeNow - mLastHousekeepingRun) < housekeepingInterval) + { + return; + } + + // Store the time + mLastHousekeepingRun = timeNow; + BOX_INFO("Starting housekeeping"); + + // Get the list of accounts + std::vector<int32_t> accounts; + if(mpAccountDatabase) + { + mpAccountDatabase->GetAllAccountIDs(accounts); + } - SetProcessTitle("housekeeping, active"); + SetProcessTitle("housekeeping, active"); - // Check them all - for(std::vector<int32_t>::const_iterator i = accounts.begin(); i != accounts.end(); ++i) + // Check them all + for(std::vector<int32_t>::const_iterator i = accounts.begin(); i != accounts.end(); ++i) + { + try + { + if(mpAccounts) { - try - { - if(mpAccounts) - { - // Get the account root - std::string rootDir; - int discSet = 0; - mpAccounts->GetAccountRoot(*i, rootDir, discSet); - - // Do housekeeping on this account - HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); - housekeeping.DoHousekeeping(); - } - } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", - *i, e.what(), e.GetType(), e.GetSubType()); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", - *i, e.what()); - } - catch(...) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", - *i); - } + // Get the account root + std::string rootDir; + int discSet = 0; + mpAccounts->GetAccountRoot(*i, rootDir, discSet); - // Check to see if there's any message pending - CheckForInterProcessMsg(0 /* no account */); - - // Stop early? - if(StopRun()) - { - break; - } + // Do housekeeping on this account + HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); + housekeeping.DoHousekeeping(); } - - ::syslog(LOG_INFO, "Finished housekeeping"); } - - // Placed here for accuracy, if StopRun() is true, for example. - SetProcessTitle("housekeeping, idle"); - - // Calculate how long should wait before doing the next housekeeping run - timeNow = GetCurrentBoxTime(); - time_t secondsToGo = BoxTimeToSeconds((lastHousekeepingRun + housekeepingInterval) - timeNow); + catch(BoxException &e) + { + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(*i) << " threw exception, " + "aborting run for this account: " << + e.what() << " (" << + e.GetType() << "/" << e.GetSubType() << ")"); + } + catch(std::exception &e) + { + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(*i) << " threw exception, " + "aborting run for this account: " << + e.what()); + } + catch(...) + { + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(*i) << " threw exception, " + "aborting run for this account: " + "unknown exception"); + } + + int64_t timeNow = GetCurrentBoxTime(); + time_t secondsToGo = BoxTimeToSeconds( + (mLastHousekeepingRun + housekeepingInterval) - + timeNow); if(secondsToGo < 1) secondsToGo = 1; if(secondsToGo > 60) secondsToGo = 60; int32_t millisecondsToGo = ((int)secondsToGo) * 1000; - + // Check to see if there's any message pending CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); + + // Stop early? + if(StopRun()) + { + break; + } } + + BOX_INFO("Finished housekeeping"); + + // Placed here for accuracy, if StopRun() is true, for example. + SetProcessTitle("housekeeping, idle"); } +void BackupStoreDaemon::OnIdle() +{ + #ifdef WIN32 + if (!mHousekeepingInited) + { + HousekeepingInit(); + mHousekeepingInited = true; + } + + RunHousekeepingIfNeeded(); + #endif +} // -------------------------------------------------------------------------- // @@ -168,6 +215,11 @@ void BackupStoreDaemon::HousekeepingProcess() // -------------------------------------------------------------------------- bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitTime) { + if(!mInterProcessCommsSocket.IsOpened()) + { + return false; + } + // First, check to see if it's EOF -- this means something has gone wrong, and the housekeeping should terminate. if(mInterProcessComms.IsEOF()) { @@ -179,7 +231,7 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT std::string line; if(mInterProcessComms.GetLine(line, false /* no pre-processing */, MaximumWaitTime)) { - TRACE1("housekeeping received command '%s' over interprocess comms\n", line.c_str()); + TRACE1("Housekeeping received command '%s' over interprocess comms\n", line.c_str()); int account = 0; @@ -201,7 +253,9 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT if(account == AccountNum) { // Yes! -- need to stop now so when it retries to get the lock, it will succeed - ::syslog(LOG_INFO, "Housekeeping giving way to connection for account 0x%08x", AccountNum); + BOX_INFO("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(AccountNum) << + "giving way to client connection"); return true; } } diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index d6ffe0a7..aa1a5f94 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -47,7 +47,8 @@ #include "Box.h" -#include <syslog.h> +#include <set> +#include <sstream> #include "autogen_BackupProtocolServer.h" #include "BackupConstants.h" @@ -62,6 +63,8 @@ #include "BackupStoreInfo.h" #include "RaidFileController.h" #include "FileStream.h" +#include "InvisibleTempFileStream.h" +#include "BufferedStream.h" #include "MemLeakFindOn.h" @@ -119,11 +122,26 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco // Check given client ID against the ID in the certificate certificate // and that the client actually has an account on this machine - if(mClientID != rContext.GetClientID() || !rContext.GetClientHasAccount()) + if(mClientID != rContext.GetClientID()) { - ::syslog(LOG_INFO, "Failed login: Client ID presented was %08X", mClientID); - return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( - BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_BadLogin)); + BOX_WARNING("Failed login from client ID " << + BOX_FORMAT_ACCOUNT(mClientID) << + ": wrong certificate for this account"); + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_BadLogin)); + } + + if(!rContext.GetClientHasAccount()) + { + BOX_WARNING("Failed login from client ID " << + BOX_FORMAT_ACCOUNT(mClientID) << + ": no such account on this server"); + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_BadLogin)); } // If we need to write, check that nothing else has got a write lock @@ -132,9 +150,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco // See if the context will get the lock if(!rContext.AttemptToGetWriteLock()) { - ::syslog(LOG_INFO, "Failed to get write lock (for Client ID %08X)", mClientID); - return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( - BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_CannotLockStoreForWriting)); + BOX_WARNING("Failed to get write lock for Client ID " << + BOX_FORMAT_ACCOUNT(mClientID)); + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_CannotLockStoreForWriting)); } // Debug: check we got the lock @@ -151,7 +172,11 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco rContext.SetPhase(BackupContext::Phase_Commands); // Log login - ::syslog(LOG_INFO, "Login: Client ID %08X, %s", mClientID, ((mFlags & Flags_ReadOnly) != Flags_ReadOnly)?"Read/Write":"Read-only"); + BOX_NOTICE("Login from Client ID " << + BOX_FORMAT_ACCOUNT(mClientID) << + " " << + (((mFlags & Flags_ReadOnly) != Flags_ReadOnly) + ?"Read/Write":"Read-only")); // Get the usage info for reporting to the client int64_t blocksUsed = 0, blocksSoftLimit = 0, blocksHardLimit = 0; @@ -171,7 +196,8 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco // -------------------------------------------------------------------------- std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) { - ::syslog(LOG_INFO, "Session finished"); + BOX_NOTICE("Session finished for Client ID " << + BOX_FORMAT_ACCOUNT(rContext.GetClientID())); // Let the context know about it rContext.ReceivedFinishCommand(); @@ -342,13 +368,23 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto en = rdir.FindEntryByID(id); if(en == 0) { - ::syslog(LOG_ERR, "Object %llx in dir %llx for account %x references object %llx which does not exist in dir", - mObjectID, mInDirectory, rContext.GetClientID(), id); - return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( - BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_PatchConsistencyError)); + BOX_ERROR("Object " << + BOX_FORMAT_OBJECTID(mObjectID) << + " in dir " << + BOX_FORMAT_OBJECTID(mInDirectory) << + " for account " << + BOX_FORMAT_ACCOUNT(rContext.GetClientID()) << + " references object " << + BOX_FORMAT_OBJECTID(id) << + " which does not exist in dir"); + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_PatchConsistencyError)); } id = en->GetDependsNewer(); - } while(en != 0 && id != 0); + } + while(en != 0 && id != 0); // OK! The last entry in the chain is the full file, the others are patches back from it. // Open the last one, which is the current from file @@ -365,8 +401,11 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto std::auto_ptr<IOStream> diff2(rContext.OpenObject(patchID)); // Choose a temporary filename for the result of the combination - std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", - p + 16 /* rotate which disc it's on */)); + std::ostringstream fs(rContext.GetStoreRoot()); + fs << ".recombinetemp."; + fs << p; + std::string tempFn(fs.str()); + tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16); // Open the temporary file std::auto_ptr<IOStream> combined; @@ -374,14 +413,14 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto { { // Write nastily to allow this to work with gcc 2.x - std::auto_ptr<IOStream> t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL)); + std::auto_ptr<IOStream> t( + new InvisibleTempFileStream( + tempFn.c_str(), + O_RDWR | O_CREAT | + O_EXCL | O_BINARY | + O_TRUNC)); combined = t; } - // Unlink immediately as it's a temporary file - if(::unlink(tempFn.c_str()) != 0) - { - THROW_EXCEPTION(CommonException, OSFileError); - } } catch(...) { @@ -397,6 +436,7 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto combined->Seek(0, IOStream::SeekType_Absolute); // Then shuffle round for the next go + if (from.get()) from->Close(); from = combined; } @@ -416,9 +456,10 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto // Open the object std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID)); + BufferedStream buf(*object); // Verify it - if(!BackupStoreFile::VerifyEncodedFileFormat(*object)) + if(!BackupStoreFile::VerifyEncodedFileFormat(buf)) { return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_FileDoesNotVerify)); @@ -434,8 +475,9 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto stream = t; } - // Object will be deleted when the stream is deleted, so can release the object auto_ptr here to - // avoid premature deletiong + // Object will be deleted when the stream is deleted, + // so can release the object auto_ptr here to avoid + // premature deletion object.release(); } diff --git a/bin/bbstored/BackupConstants.h b/bin/bbstored/BackupConstants.h index 2b44929c..664fea54 100644 --- a/bin/bbstored/BackupConstants.h +++ b/bin/bbstored/BackupConstants.h @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index 2c741eeb..659cc5f8 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -62,6 +62,8 @@ #include "BackupStoreDaemon.h" #include "RaidFileController.h" #include "FileStream.h" +#include "InvisibleTempFileStream.h" +#include "BufferedStream.h" #include "MemLeakFindOn.h" @@ -343,7 +345,8 @@ BackupStoreDirectory &BackupContext::GetDirectoryInternal(int64_t ObjectID) std::auto_ptr<BackupStoreDirectory> dir(new BackupStoreDirectory); // Read it from the stream, then set it's revision ID - dir->ReadFromStream(*objectFile, IOStream::TimeOutInfinite); + BufferedStream buf(*objectFile); + dir->ReadFromStream(buf, IOStream::TimeOutInfinite); dir->SetRevisionID(revID); // Make sure the size of the directory is available for writing the dir back @@ -491,13 +494,21 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod try { // Open it twice +#ifdef WIN32 + InvisibleTempFileStream diff(tempFn.c_str(), + O_RDWR | O_CREAT | O_BINARY); + InvisibleTempFileStream diff2(tempFn.c_str(), + O_RDWR | O_BINARY); +#else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); FileStream diff2(tempFn.c_str(), O_RDONLY); - // Unlink it immediately, so it definately goes away + + // Unlink it immediately, so it definitely goes away if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } +#endif // Stream the incoming diff to this temporary file if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT)) diff --git a/bin/bbstored/BackupContext.h b/bin/bbstored/BackupContext.h index b8aed74b..df4f2189 100644 --- a/bin/bbstored/BackupContext.h +++ b/bin/bbstored/BackupContext.h @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 06198ea4..5234d6e0 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -49,9 +49,12 @@ #include <stdlib.h> #include <stdio.h> -#include <syslog.h> #include <signal.h> +#ifdef HAVE_SYSLOG_H + #include <syslog.h> +#endif + #include "BackupContext.h" #include "BackupStoreDaemon.h" #include "BackupStoreConfigVerify.h" @@ -77,6 +80,7 @@ BackupStoreDaemon::BackupStoreDaemon() mExtendedLogging(false), mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), + mHousekeepingInited(false), mInterProcessComms(mInterProcessCommsSocket) { } @@ -127,14 +131,9 @@ const char *BackupStoreDaemon::DaemonName() const // Created: 1/1/04 // // -------------------------------------------------------------------------- -const char *BackupStoreDaemon::DaemonBanner() const +std::string BackupStoreDaemon::DaemonBanner() const { -#ifndef NDEBUG - // Don't display banner in debug builds - return 0; -#else return BANNER_TEXT("Backup Store Server"); -#endif } @@ -166,7 +165,23 @@ void BackupStoreDaemon::SetupInInitialProcess() // Initialise the raid files controller RaidFileController &rcontroller = RaidFileController::GetController(); - rcontroller.Initialise(config.GetKeyValue("RaidFileConf").c_str()); + + std::string raidFileConfig; + + #ifdef WIN32 + if (!config.KeyExists("RaidFileConf")) + { + raidFileConfig = BOX_GET_DEFAULT_RAIDFILE_CONFIG_FILE; + } + else + { + raidFileConfig = config.GetKeyValue("RaidFileConf"); + } + #else + raidFileConfig = config.GetKeyValue("RaidFileConf"); + #endif + + rcontroller.Initialise(raidFileConfig); // Load the account database std::auto_ptr<BackupStoreAccountDatabase> pdb(BackupStoreAccountDatabase::Read(config.GetKeyValue("AccountDatabase").c_str())); @@ -194,6 +209,9 @@ void BackupStoreDaemon::Run() const Configuration &config(GetConfiguration()); mExtendedLogging = config.GetKeyValueBool("ExtendedLogging"); +#ifdef WIN32 + // Housekeeping runs synchronously on Win32 +#else // Fork off housekeeping daemon -- must only do this the first time Run() is called if(!mHaveForkedHousekeeping) { @@ -223,7 +241,7 @@ void BackupStoreDaemon::Run() // Change the log name ::openlog("bbstored/hk", LOG_PID, LOG_LOCAL6); // Log that housekeeping started - ::syslog(LOG_INFO, "Housekeeping process started"); + BOX_INFO("Housekeeping process started"); // Ignore term and hup // Parent will handle these and alert the child via the socket, don't want to randomly die ::signal(SIGHUP, SIG_IGN); @@ -249,6 +267,7 @@ void BackupStoreDaemon::Run() THROW_EXCEPTION(ServerException, SocketCloseError) } } +#endif // WIN32 if(mIsHousekeepingProcess) { @@ -259,12 +278,18 @@ void BackupStoreDaemon::Run() { // In server process -- use the base class to do the magic ServerTLS<BOX_PORT_BBSTORED>::Run(); - + + if (!mInterProcessCommsSocket.IsOpened()) + { + return; + } + // Why did it stop? Tell the housekeeping process to do the same if(IsReloadConfigWanted()) { mInterProcessCommsSocket.Write("h\n", 2); } + if(IsTerminateWanted()) { mInterProcessCommsSocket.Write("t\n", 2); @@ -272,22 +297,54 @@ void BackupStoreDaemon::Run() } } - // -------------------------------------------------------------------------- // // Function // Name: BackupStoreDaemon::Connection(SocketStreamTLS &) -// Purpose: Handles a connection +// Purpose: Handles a connection, by catching exceptions and +// delegating to Connection2 // Created: 2003/08/20 // // -------------------------------------------------------------------------- void BackupStoreDaemon::Connection(SocketStreamTLS &rStream) { + try + { + Connection2(rStream); + } + catch(BoxException &e) + { + BOX_ERROR("Error in child process, terminating connection: " << + e.what() << " (" << e.GetType() << "/" << + e.GetSubType() << ")"); + } + catch(std::exception &e) + { + BOX_ERROR("Error in child process, terminating connection: " << + e.what()); + } + catch(...) + { + BOX_ERROR("Error in child process, terminating connection: " << + "unknown exception"); + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreDaemon::Connection2(SocketStreamTLS &) +// Purpose: Handles a connection from bbackupd +// Created: 2006/11/12 +// +// -------------------------------------------------------------------------- +void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) +{ // Get the common name from the certificate std::string clientCommonName(rStream.GetPeerCommonName()); // Log the name - ::syslog(LOG_INFO, "Certificate CN: %s\n", clientCommonName.c_str()); + BOX_INFO("Client certificate CN: " << clientCommonName); // Check it int32_t id; @@ -333,8 +390,8 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, const SocketStreamTLS &s) { // Log the amount of data transferred - ::syslog(LOG_INFO, "Connection statistics for %s: " - "IN=%lld OUT=%lld TOTAL=%lld\n", commonName, - s.GetBytesRead(), s.GetBytesWritten(), - s.GetBytesRead() + s.GetBytesWritten()); + BOX_INFO("Connection statistics for " << commonName << ":" + " IN=" << s.GetBytesRead() << + " OUT=" << s.GetBytesWritten() << + " TOTAL=" << (s.GetBytesRead() + s.GetBytesWritten())); } diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index c320003a..d636f451 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -76,10 +76,12 @@ private: BackupStoreDaemon(const BackupStoreDaemon &rToCopy); public: - // For BackupContext to comminicate with housekeeping process + // For BackupContext to communicate with housekeeping process void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) { +#ifndef WIN32 mInterProcessCommsSocket.Write(Msg, MsgLen); +#endif } protected: @@ -88,10 +90,11 @@ protected: virtual void Run(); - void Connection(SocketStreamTLS &rStream); + virtual void Connection(SocketStreamTLS &rStream); + void Connection2(SocketStreamTLS &rStream); virtual const char *DaemonName() const; - virtual const char *DaemonBanner() const; + virtual std::string DaemonBanner() const; const ConfigurationVerify *GetConfigVerify() const; @@ -107,9 +110,15 @@ private: bool mExtendedLogging; bool mHaveForkedHousekeeping; bool mIsHousekeepingProcess; + bool mHousekeepingInited; SocketStream mInterProcessCommsSocket; IOStreamGetLine mInterProcessComms; + + virtual void OnIdle(); + void HousekeepingInit(); + void RunHousekeepingIfNeeded(); + int64_t mLastHousekeepingRun; }; diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index dac69946..fc9e83f1 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -47,9 +47,10 @@ #include "Box.h" -#include <map> #include <stdio.h> +#include <map> + #include "HousekeepStoreAccount.h" #include "BackupStoreDaemon.h" #include "StoreStructure.h" @@ -61,6 +62,7 @@ #include "NamedLock.h" #include "autogen_BackupStoreException.h" #include "BackupStoreFile.h" +#include "BufferedStream.h" #include "MemLeakFindOn.h" @@ -174,11 +176,18 @@ void HousekeepStoreAccount::DoHousekeeping() || (usedDeleted + mBlocksInDeletedFilesDelta) != mBlocksInDeletedFiles || usedDirectories != mBlocksInDirectories) { // Log this - ::syslog(LOG_ERR, "On housekeeping, sizes in store do not match calculated sizes, correcting"); - ::syslog(LOG_ERR, "different (store,calc): acc 0x%08x, used (%lld,%lld), old (%lld,%lld), deleted (%lld,%lld), dirs (%lld,%lld)", - mAccountID, - (used + mBlocksUsedDelta), mBlocksUsed, (usedOld + mBlocksInOldFilesDelta), mBlocksInOldFiles, - (usedDeleted + mBlocksInDeletedFilesDelta), mBlocksInDeletedFiles, usedDirectories, mBlocksInDirectories); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(mAccountID) << " found " + "and fixed wrong block counts: " + "used (" << + (used + mBlocksUsedDelta) << "," << + mBlocksUsed << "), old (" << + (usedOld + mBlocksInOldFilesDelta) << "," << + mBlocksInOldFiles << "), deleted (" << + (usedDeleted + mBlocksInDeletedFilesDelta) << + "," << mBlocksInDeletedFiles << "), dirs (" << + usedDirectories << "," << mBlocksInDirectories + << ")"); } // If the current values don't match, store them @@ -210,17 +219,33 @@ void HousekeepStoreAccount::DoHousekeeping() // Log deletion if anything was deleted if(mFilesDeleted > 0 || mEmptyDirectoriesDeleted > 0) { - ::syslog(LOG_INFO, "Account 0x%08x, removed %lld blocks (%lld files, %lld dirs)%s", mAccountID, 0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta), - mFilesDeleted, mEmptyDirectoriesDeleted, - deleteInterrupted?" was interrupted":""); + BOX_INFO("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(mAccountID) << " " + "removed " << + (0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta)) << + " blocks (" << mFilesDeleted << " files, " << + mEmptyDirectoriesDeleted << " dirs)" << + (deleteInterrupted?" and was interrupted":"")); } // Make sure the delta's won't cause problems if the counts are really wrong, and // it wasn't fixed because the store was updated during the scan. - if(mBlocksUsedDelta < (0 - info->GetBlocksUsed())) mBlocksUsedDelta = (0 - info->GetBlocksUsed()); - if(mBlocksInOldFilesDelta < (0 - info->GetBlocksInOldFiles())) mBlocksInOldFilesDelta = (0 - info->GetBlocksInOldFiles()); - if(mBlocksInDeletedFilesDelta < (0 - info->GetBlocksInDeletedFiles())) mBlocksInDeletedFilesDelta =(0 - info->GetBlocksInDeletedFiles()); - if(mBlocksInDirectoriesDelta < (0 - info->GetBlocksInDirectories())) mBlocksInDirectoriesDelta = (0 - info->GetBlocksInDirectories()); + if(mBlocksUsedDelta < (0 - info->GetBlocksUsed())) + { + mBlocksUsedDelta = (0 - info->GetBlocksUsed()); + } + if(mBlocksInOldFilesDelta < (0 - info->GetBlocksInOldFiles())) + { + mBlocksInOldFilesDelta = (0 - info->GetBlocksInOldFiles()); + } + if(mBlocksInDeletedFilesDelta < (0 - info->GetBlocksInDeletedFiles())) + { + mBlocksInDeletedFilesDelta = (0 - info->GetBlocksInDeletedFiles()); + } + if(mBlocksInDirectoriesDelta < (0 - info->GetBlocksInDirectories())) + { + mBlocksInDirectoriesDelta = (0 - info->GetBlocksInDirectories()); + } // Update the usage counts in the store info->ChangeBlocksUsed(mBlocksUsedDelta); @@ -263,6 +288,7 @@ void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rF // -------------------------------------------------------------------------- bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -273,6 +299,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) return false; } } +#endif // Get the filename std::string objectFilename; @@ -288,7 +315,9 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Read the directory in BackupStoreDirectory dir; - dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); + BufferedStream buf(*dirStream); + dir.ReadFromStream(buf, IOStream::TimeOutInfinite); + dirStream->Close(); // Is it empty? if(dir.GetNumberOfEntries() == 0) @@ -523,6 +552,7 @@ bool HousekeepStoreAccount::DeleteFiles() // (there is likely to be more in the set than should be actually deleted). for(std::set<DelEn, DelEnCompare>::iterator i(mPotentialDeletions.begin()); i != mPotentialDeletions.end(); ++i) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -533,6 +563,7 @@ bool HousekeepStoreAccount::DeleteFiles() return true; } } +#endif // Load up the directory it's in // Get the filename @@ -585,7 +616,14 @@ void HousekeepStoreAccount::DeleteFile(int64_t InDirectory, int64_t ObjectID, Ba BackupStoreDirectory::Entry *pentry = rDirectory.FindEntryByID(ObjectID); if(pentry == 0) { - ::syslog(LOG_ERR, "acc 0x%08x, object %lld not found in dir %lld, logic error/corruption? Run bbstoreaccounts check <accid> fix", mAccountID, ObjectID, InDirectory); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(mAccountID) << " " + "found error: object " << + BOX_FORMAT_OBJECTID(ObjectID) << " " + "not found in dir " << + BOX_FORMAT_OBJECTID(InDirectory) << ", " + "indicates logic error/corruption? Run " + "bbstoreaccounts check <accid> fix"); return; } @@ -767,6 +805,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() // Go through list for(std::vector<int64_t>::const_iterator i(mEmptyDirectories.begin()); i != mEmptyDirectories.end(); ++i) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -777,6 +816,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() return true; } } +#endif // Do not delete the root directory if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID) diff --git a/bin/bbstored/HousekeepStoreAccount.h b/bin/bbstored/HousekeepStoreAccount.h index 85180bf0..bdb012c6 100644 --- a/bin/bbstored/HousekeepStoreAccount.h +++ b/bin/bbstored/HousekeepStoreAccount.h @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. diff --git a/bin/bbstored/Makefile.extra b/bin/bbstored/Makefile.extra index 187d53ef..94bc3fb9 100644 --- a/bin/bbstored/Makefile.extra +++ b/bin/bbstored/Makefile.extra @@ -5,5 +5,5 @@ GEN_CMD_SRV = $(MAKEPROTOCOL) Server backupprotocol.txt # AUTOGEN SEEDING autogen_BackupProtocolServer.cpp autogen_BackupProtocolServer.h: $(MAKEPROTOCOL) backupprotocol.txt - perl $(GEN_CMD_SRV) + $(PERL) $(GEN_CMD_SRV) diff --git a/bin/bbstored/bbstored-certs b/bin/bbstored/bbstored-certs index bdaf50d5..22d6c5ad 100755 --- a/bin/bbstored/bbstored-certs +++ b/bin/bbstored/bbstored-certs @@ -1,5 +1,5 @@ #!/usr/bin/perl -# distribution boxbackup-0.10 (svn version: 494) +# distribution boxbackup-0.11rc1 (svn version: 2023_2024) # # Copyright (c) 2003 - 2006 # Ben Summers and contributors. All rights reserved. diff --git a/bin/bbstored/bbstored-certs.in b/bin/bbstored/bbstored-certs.in new file mode 100755 index 00000000..e0554d94 --- /dev/null +++ b/bin/bbstored/bbstored-certs.in @@ -0,0 +1,319 @@ +#!@PERL@ +use strict; + +# validity period for root certificates -- default is a very long time +my $root_sign_period = '10000'; + +# but less so for client certificates +my $sign_period = '5000'; + +# check and get command line parameters +if($#ARGV < 1) +{ + print <<__E; + +bbstored certificates utility. + +Bad command line parameters. +Usage: + bbstored-certs certs-dir command [arguments] + +certs-dir is the directory holding the root keys and certificates for the backup system +command is the action to perform, taking parameters. + +Commands are + + init + -- generate initial root certificates (certs-dir must not already exist) + sign certificate-name + -- sign a client certificate + sign-server certificate-name + -- sign a server certificate + +Signing requires confirmation that the certificate is correct and should be signed. + +__E + exit(1); +} + +# check for OPENSSL_CONF environment var being set +if(exists $ENV{'OPENSSL_CONF'}) +{ + print <<__E; + +--------------------------------------- + +WARNING: + You have the OPENSSL_CONF environment variable set. + Use of non-standard openssl configs may cause problems. + +--------------------------------------- + +__E +} + +# directory structure: +# +# roots/ +# clientCA.pem -- root certificate for client (used on server) +# serverCA.pem -- root certificate for servers (used on clients) +# keys/ +# clientRootKey.pem -- root key for clients +# serverRootKey.pem -- root key for servers +# servers/ +# hostname.pem -- certificate for server 'hostname' +# clients/ +# account.pem -- certficiate for account 'account' (ID in hex) +# + + +# check parameters +my ($cert_dir,$command,@args) = @ARGV; + +# check directory exists +if($command ne 'init') +{ + if(!-d $cert_dir) + { + die "$cert_dir does not exist"; + } +} + +# run command +if($command eq 'init') {&cmd_init;} +elsif($command eq 'sign') {&cmd_sign;} +elsif($command eq 'sign-server') {&cmd_sign_server;} +else +{ + die "Unknown command $command" +} + +sub cmd_init +{ + # create directories + unless(mkdir($cert_dir,0700) + && mkdir($cert_dir.'/roots',0700) + && mkdir($cert_dir.'/keys',0700) + && mkdir($cert_dir.'/servers',0700) + && mkdir($cert_dir.'/clients',0700)) + { + die "Failed to create directory structure" + } + + # create root keys and certrs + cmd_init_create_root('client'); + cmd_init_create_root('server'); +} + +sub cmd_init_create_root +{ + my $entity = $_[0]; + + my $cert = "$cert_dir/roots/".$entity.'CA.pem'; + my $serial = "$cert_dir/roots/".$entity.'CA.srl'; + my $key = "$cert_dir/keys/".$entity.'RootKey.pem'; + my $csr = "$cert_dir/keys/".$entity.'RootCSR.pem'; + + # generate key + if(system("openssl genrsa -out $key 2048") != 0) + { + die "Couldn't generate private key." + } + + # make CSR + die "Couldn't run openssl for CSR generation" unless + open(CSR,"|openssl req -new -key $key -sha1 -out $csr"); + print CSR <<__E; +. +. +. +. +. +Backup system $entity root +. +. +. + +__E + close CSR; + print "\n\n"; + die "Certificate request wasn't created.\n" unless -f $csr; + + # sign it to make a self-signed root CA key + if(system("openssl x509 -req -in $csr -sha1 -extensions v3_ca -signkey $key -out $cert -days $root_sign_period") != 0) + { + die "Couldn't generate root certificate." + } + + # write the initial serial number + open SERIAL,">$serial" or die "Can't open $serial for writing"; + print SERIAL "00\n"; + close SERIAL; +} + +sub cmd_sign +{ + my $csr = $args[0]; + + if(!-f $csr) + { + die "$csr does not exist"; + } + + # get the common name specified in this certificate + my $common_name = get_csr_common_name($csr); + + # look OK? + unless($common_name =~ m/\ABACKUP-([A-Fa-f0-9]+)\Z/) + { + die "The certificate presented does not appear to be a backup client certificate" + } + + my $acc = $1; + + # check against filename + if(!($csr =~ m/(\A|\/)([A-Fa-f0-9]+)-/) || $2 ne $acc) + { + die "Certificate request filename does not match name in certificate ($common_name)" + } + + print <<__E; + +This certificate is for backup account + + $acc + +Ensure this matches the account number you are expecting. The filename is + + $csr + +which should include this account number, and additionally, you should check +that you received it from the right person. + +Signing the wrong certificate compromises the security of your backup system. + +Would you like to sign this certificate? (type 'yes' to confirm) +__E + + return unless get_confirmation(); + + # out certificate + my $out_cert = "$cert_dir/clients/$acc"."-cert.pem"; + + # sign it! + if(system("openssl x509 -req -in $csr -sha1 -extensions usr_crt -CA $cert_dir/roots/clientCA.pem -CAkey $cert_dir/keys/clientRootKey.pem -out $out_cert -days $sign_period") != 0) + { + die "Signing failed" + } + + # tell user what to do next + print <<__E; + + +Certificate signed. + +Send the files + + $out_cert + $cert_dir/roots/serverCA.pem + +to the client. + +__E +} + +sub cmd_sign_server +{ + my $csr = $args[0]; + + if(!-f $csr) + { + die "$csr does not exist"; + } + + # get the common name specified in this certificate + my $common_name = get_csr_common_name($csr); + + # look OK? + if($common_name !~ m/\A[-a-zA-Z0-9.]+\Z/) + { + die "Invalid server name" + } + + print <<__E; + +This certificate is for backup server + + $common_name + +Signing the wrong certificate compromises the security of your backup system. + +Would you like to sign this certificate? (type 'yes' to confirm) +__E + + return unless get_confirmation(); + + # out certificate + my $out_cert = "$cert_dir/servers/$common_name"."-cert.pem"; + + # sign it! + if(system("openssl x509 -req -in $csr -sha1 -extensions usr_crt -CA $cert_dir/roots/serverCA.pem -CAkey $cert_dir/keys/serverRootKey.pem -out $out_cert -days $sign_period") != 0) + { + die "Signing failed" + } + + # tell user what to do next + print <<__E; + + +Certificate signed. + +Install the files + + $out_cert + $cert_dir/roots/clientCA.pem + +on the server. + +__E +} + + +sub get_csr_common_name +{ + my $csr = $_[0]; + + open CSRTEXT,"openssl req -text -in $csr |" or die "Can't open openssl for reading"; + + my $subject; + while(<CSRTEXT>) + { + $subject = $1 if m/Subject:.+?CN=([-\.\w]+)/ + } + close CSRTEXT; + + if($subject eq '') + { + die "No subject found in CSR $csr" + } + + return $subject +} + +sub get_confirmation() +{ + my $line = <STDIN>; + chomp $line; + if(lc $line ne 'yes') + { + print "CANCELLED\n"; + return 0; + } + + return 1; +} + + + + + diff --git a/bin/bbstored/bbstored-config b/bin/bbstored/bbstored-config index 7325e383..76d8cad9 100755 --- a/bin/bbstored/bbstored-config +++ b/bin/bbstored/bbstored-config @@ -1,5 +1,5 @@ #!/usr/bin/perl -# distribution boxbackup-0.10 (svn version: 494) +# distribution boxbackup-0.11rc1 (svn version: 2023_2024) # # Copyright (c) 2003 - 2006 # Ben Summers and contributors. All rights reserved. diff --git a/bin/bbstored/bbstored-config.in b/bin/bbstored/bbstored-config.in new file mode 100755 index 00000000..7bd79716 --- /dev/null +++ b/bin/bbstored/bbstored-config.in @@ -0,0 +1,242 @@ +#!@PERL@ +use strict; + +# should be running as root +if($> != 0) +{ + printf "\nWARNING: this should be run as root\n\n" +} + +# check and get command line parameters +if($#ARGV < 2) +{ + print <<__E; + +Setup bbstored config utility. + +Bad command line parameters. +Usage: + bbstored-config config-dir server-hostname username [raidfile-config] + +config-dir usually /etc/box +server-hostname is the hostname used by clients to connect to this server +username is the user to run the server under +raidfile-config is optional. Use if you have a non-standard raidfile.conf file. + +__E + exit(1); +} + +# check for OPENSSL_CONF environment var being set +if(exists $ENV{'OPENSSL_CONF'}) +{ + print <<__E; + +--------------------------------------- + +WARNING: + You have the OPENSSL_CONF environment variable set. + Use of non-standard openssl configs may cause problems. + +--------------------------------------- + +__E +} + +# default locations +my $default_config_location = '/etc/box/bbstored.conf'; + +# command line parameters +my ($config_dir,$server,$username,$raidfile_config) = @ARGV; + +$raidfile_config = $config_dir . '/raidfile.conf' unless $raidfile_config ne ''; + +# check server exists, but don't bother checking that it's actually this machine. +{ + my @r = gethostbyname($server); + if($#r < 0) + { + die "Server '$server' not found. (check server name, test DNS lookup failed.)" + } +} + +# check this exists +if(!-f $raidfile_config) +{ + print "The RaidFile configuration file $raidfile_config doesn't exist.\nYou may need to create it with raidfile-config.\nWon't configure bbstored without it.\n"; + exit(1); +} + +# check that the user exists +die "You shouldn't run bbstored as root" if $username eq 'root'; +my $user_uid = 0; +(undef,undef,$user_uid) = getpwnam($username); +if($user_uid == 0) +{ + die "User $username doesn't exist\n"; +} + +# check that directories are writeable +open RAIDCONF,$raidfile_config or die "Can't open $raidfile_config"; +{ + my %done = (); + while(<RAIDCONF>) + { + next unless m/Dir\d\s*=\s*(.+)/; + my $d = $1; + $d = $d.'/backup' if -e $d.'/backup'; + print "Checking permissions on $d\n"; + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($d); + my $req_perms = ($uid == $user_uid)?0700:0007; + if(($mode & $req_perms) != $req_perms) + { + print "$username doesn't appear to have the necessary permissions on $d\n"; + print "Either adjust permissions, or create a directory 'backup' inside the\n"; + print "directory specified in raidfile.conf which is writable.\n"; + exit(1); + } + } +} +close RAIDCONF; + +# ssl stuff +my $private_key = "$config_dir/bbstored/$server-key.pem"; +my $certificate_request = "$config_dir/bbstored/$server-csr.pem"; +my $certificate = "$config_dir/bbstored/$server-cert.pem"; +my $ca_root_cert = "$config_dir/bbstored/clientCA.pem"; + +# other files +my $config_file = "$config_dir/bbstored.conf"; +my $accounts_file = "$config_dir/bbstored/accounts.txt"; + +# summarise configuration + +print <<__E; + +Setup bbstored config utility. + +Configuration: + Writing configuration file: $config_file + Writing empty accounts file: $accounts_file + Server hostname: $server + RaidFile config: $raidfile_config + +__E + +# create directories +if(!-d $config_dir) +{ + print "Creating $config_dir...\n"; + mkdir $config_dir,0755 or die "Can't create $config_dir"; +} + +if(!-d "$config_dir/bbstored") +{ + print "Creating $config_dir/bbstored\n"; + mkdir "$config_dir/bbstored",0755 or die "Can't create $config_dir/bbstored"; +} + +# create blank accounts file +if(!-f $accounts_file) +{ + print "Creating blank accounts file\n"; + open ACC,">$accounts_file"; + close ACC; +} + +# generate the private key for the server +if(!-f $private_key) +{ + print "Generating private key...\n"; + if(system("openssl genrsa -out $private_key 2048") != 0) + { + die "Couldn't generate private key." + } +} + +# generate a certificate request +if(!-f $certificate_request) +{ + die "Couldn't run openssl for CSR generation" unless + open(CSR,"|openssl req -new -key $private_key -sha1 -out $certificate_request"); + print CSR <<__E; +. +. +. +. +. +$server +. +. +. + +__E + close CSR; + print "\n\n"; + die "Certificate request wasn't created.\n" unless -f $certificate_request +} + +# write the configuration file +print "Writing configuration file $config_file\n"; +open CONFIG,">$config_file" or die "Can't open config file for writing"; +print CONFIG <<__E; + +RaidFileConf = $raidfile_config +AccountDatabase = $accounts_file + +# Uncomment this line to see exactly what commands are being received from clients. +# ExtendedLogging = yes + +# scan all accounts for files which need deleting every 15 minutes. + +TimeBetweenHousekeeping = 900 + +Server +{ + PidFile = /var/run/bbstored.pid + User = $username + ListenAddresses = inet:$server + CertificateFile = $certificate + PrivateKeyFile = $private_key + TrustedCAsFile = $ca_root_cert +} + + +__E + +close CONFIG; + +# explain to the user what they need to do next +my $daemon_args = ($config_file eq $default_config_location)?'':" $config_file"; + +print <<__E; + +=================================================================== + +bbstored basic configuration complete. + +What you need to do now... + +1) Sign $certificate_request + using the bbstored-certs utility. + +2) Install the server certificate and root CA certificate as + $certificate + $ca_root_cert + +3) You may wish to read the configuration file + $config_file + and adjust as appropraite. + +4) Create accounts with bbstoreaccounts + +5) Start the backup store daemon with the command + /usr/local/bin/bbstored$daemon_args + in /etc/rc.local, or your local equivalent. + +=================================================================== + +__E + + + diff --git a/bin/bbstored/bbstored.cpp b/bin/bbstored/bbstored.cpp index ccf786cd..d3710b5f 100644 --- a/bin/bbstored/bbstored.cpp +++ b/bin/bbstored/bbstored.cpp @@ -1,4 +1,4 @@ -// distribution boxbackup-0.10 (svn version: 494) +// distribution boxbackup-0.11rc1 (svn version: 2023_2024) // // Copyright (c) 2003 - 2006 // Ben Summers and contributors. All rights reserved. @@ -48,6 +48,7 @@ #include "Box.h" #include "BackupStoreDaemon.h" #include "MainHelper.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -55,8 +56,19 @@ int main(int argc, const char *argv[]) { MAINHELPER_START + Logging::SetProgramName("Box Backup (bbstored)"); + Logging::ToConsole(true); + Logging::ToSyslog (true); + BackupStoreDaemon daemon; - return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG, argc, argv); + + #ifdef WIN32 + return daemon.Main(BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE, + argc, argv); + #else + return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG, + argc, argv); + #endif MAINHELPER_END } |