summaryrefslogtreecommitdiff
path: root/bin/bbstored
diff options
context:
space:
mode:
Diffstat (limited to 'bin/bbstored')
-rw-r--r--bin/bbstored/BBStoreDHousekeeping.cpp192
-rw-r--r--bin/bbstored/BackupCommands.cpp96
-rw-r--r--bin/bbstored/BackupConstants.h2
-rw-r--r--bin/bbstored/BackupContext.cpp17
-rw-r--r--bin/bbstored/BackupContext.h2
-rw-r--r--bin/bbstored/BackupStoreDaemon.cpp93
-rw-r--r--bin/bbstored/BackupStoreDaemon.h17
-rw-r--r--bin/bbstored/HousekeepStoreAccount.cpp72
-rw-r--r--bin/bbstored/HousekeepStoreAccount.h2
-rw-r--r--bin/bbstored/Makefile.extra2
-rwxr-xr-xbin/bbstored/bbstored-certs2
-rwxr-xr-xbin/bbstored/bbstored-certs.in319
-rwxr-xr-xbin/bbstored/bbstored-config2
-rwxr-xr-xbin/bbstored/bbstored-config.in242
-rw-r--r--bin/bbstored/bbstored.cpp16
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
}