summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/backupclient/BackupDaemonConfigVerify.cpp9
-rw-r--r--lib/backupstore/BackupStoreCheck.cpp10
-rw-r--r--lib/backupstore/BackupStoreCheck2.cpp2
-rw-r--r--lib/backupstore/BackupStoreRefCountDatabase.cpp11
-rw-r--r--lib/backupstore/BackupStoreRefCountDatabase.h3
-rw-r--r--lib/backupstore/StoreTestUtils.cpp55
-rw-r--r--lib/backupstore/StoreTestUtils.h11
-rw-r--r--lib/bbackupd/BackupDaemon.cpp3
-rw-r--r--lib/common/BoxException.h3
-rw-r--r--lib/common/BoxPortsAndFiles.h.in4
-rw-r--r--lib/common/Configuration.cpp15
-rw-r--r--lib/common/Configuration.h1
-rw-r--r--lib/common/FileStream.h1
-rw-r--r--lib/common/Test.cpp138
-rw-r--r--lib/common/Test.h10
-rw-r--r--lib/server/ConnectionException.txt1
-rw-r--r--lib/server/Daemon.cpp4
-rw-r--r--lib/server/Daemon.h2
-rw-r--r--lib/server/ServerControl.cpp171
-rw-r--r--lib/server/ServerControl.h16
-rw-r--r--lib/server/ServerException.txt1
-rw-r--r--lib/server/ServerStream.h11
-rw-r--r--lib/server/ServerTLS.h9
-rw-r--r--lib/server/SocketStream.cpp4
-rw-r--r--lib/server/SocketStream.h1
-rw-r--r--lib/server/SocketStreamTLS.cpp51
-rw-r--r--lib/server/SocketStreamTLS.h3
-rw-r--r--lib/server/TLSContext.cpp72
-rw-r--r--lib/server/TLSContext.h3
-rwxr-xr-xlib/win32/getopt_long.cpp1092
-rwxr-xr-xlib/win32/messages.rc4
31 files changed, 977 insertions, 744 deletions
diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp
index 865ee413..e28e26ff 100644
--- a/lib/backupclient/BackupDaemonConfigVerify.cpp
+++ b/lib/backupclient/BackupDaemonConfigVerify.cpp
@@ -8,10 +8,11 @@
// --------------------------------------------------------------------------
#include "Box.h"
+
+#include "BackupConstants.h"
#include "BackupDaemonConfigVerify.h"
-#include "Daemon.h"
#include "BoxPortsAndFiles.h"
-#include "BackupConstants.h"
+#include "Daemon.h"
#include "MemLeakFindOn.h"
@@ -148,7 +149,9 @@ static const ConfigurationVerifyKey verifyrootkeys[] =
ConfigTest_IsUint32),
ConfigurationVerifyKey("CertificateFile", 0),
ConfigurationVerifyKey("PrivateKeyFile", 0),
- ConfigurationVerifyKey("TrustedCAsFile", ConfigTest_LastEntry),
+ ConfigurationVerifyKey("TrustedCAsFile", 0),
+ ConfigurationVerifyKey("SSLSecurityLevel", ConfigTest_IsInt | ConfigTest_LastEntry,
+ BOX_DEFAULT_SSL_SECURITY_LEVEL),
};
const ConfigurationVerify BackupDaemonConfigVerify =
diff --git a/lib/backupstore/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp
index b53ebf6d..37e45b03 100644
--- a/lib/backupstore/BackupStoreCheck.cpp
+++ b/lib/backupstore/BackupStoreCheck.cpp
@@ -174,9 +174,17 @@ void BackupStoreCheck::Check()
try
{
+ // We should be able to load a reference to the old refcount database
+ // (read-only) at the same time that we have a reference to the new one
+ // (temporary) open but not yet committed.
std::auto_ptr<BackupStoreRefCountDatabase> apOldRefs =
BackupStoreRefCountDatabase::Load(account, false);
- mNumberErrorsFound += mapNewRefs->ReportChangesTo(*apOldRefs);
+
+ // If we have created a new lost+found directory (and thus allocated it a nonzero
+ // object ID) then it's not surprising that the previous refcount DB did not have
+ // a reference to this directory, and not an error, so ignore it.
+ mNumberErrorsFound += mapNewRefs->ReportChangesTo(*apOldRefs,
+ mLostAndFoundDirectoryID); // ignore_object_id
}
catch(BoxException &e)
{
diff --git a/lib/backupstore/BackupStoreCheck2.cpp b/lib/backupstore/BackupStoreCheck2.cpp
index 13831a09..3775cc4a 100644
--- a/lib/backupstore/BackupStoreCheck2.cpp
+++ b/lib/backupstore/BackupStoreCheck2.cpp
@@ -429,7 +429,7 @@ int64_t BackupStoreCheck::GetLostAndFoundDirID()
if(!mFixErrors)
{
// The result will never be used anyway if errors aren't being fixed
- return 1;
+ return 0;
}
// Load up the root directory
diff --git a/lib/backupstore/BackupStoreRefCountDatabase.cpp b/lib/backupstore/BackupStoreRefCountDatabase.cpp
index b2ea1abd..86da0943 100644
--- a/lib/backupstore/BackupStoreRefCountDatabase.cpp
+++ b/lib/backupstore/BackupStoreRefCountDatabase.cpp
@@ -347,17 +347,22 @@ bool BackupStoreRefCountDatabase::RemoveReference(int64_t ObjectID)
return (refcount > 0);
}
-int BackupStoreRefCountDatabase::ReportChangesTo(BackupStoreRefCountDatabase& rOldRefs)
+int BackupStoreRefCountDatabase::ReportChangesTo(BackupStoreRefCountDatabase& rOldRefs,
+ int64_t ignore_object_id)
{
int ErrorCount = 0;
int64_t MaxOldObjectId = rOldRefs.GetLastObjectIDUsed();
int64_t MaxNewObjectId = GetLastObjectIDUsed();
for (int64_t ObjectID = BACKUPSTORE_ROOT_DIRECTORY_ID;
- ObjectID < std::max(MaxOldObjectId, MaxNewObjectId);
+ ObjectID <= std::max(MaxOldObjectId, MaxNewObjectId);
ObjectID++)
{
- typedef BackupStoreRefCountDatabase::refcount_t refcount_t;
+ if(ObjectID == ignore_object_id)
+ {
+ continue;
+ }
+
refcount_t OldRefs = (ObjectID <= MaxOldObjectId) ?
rOldRefs.GetRefCount(ObjectID) : 0;
refcount_t NewRefs = (ObjectID <= MaxNewObjectId) ?
diff --git a/lib/backupstore/BackupStoreRefCountDatabase.h b/lib/backupstore/BackupStoreRefCountDatabase.h
index 915653a4..6c16516e 100644
--- a/lib/backupstore/BackupStoreRefCountDatabase.h
+++ b/lib/backupstore/BackupStoreRefCountDatabase.h
@@ -87,7 +87,8 @@ public:
void AddReference(int64_t ObjectID);
// RemoveReference returns false if refcount drops to zero
bool RemoveReference(int64_t ObjectID);
- int ReportChangesTo(BackupStoreRefCountDatabase& rOldRefs);
+ int ReportChangesTo(BackupStoreRefCountDatabase& rOldRefs,
+ int64_t ignore_object_id = 0);
private:
static std::string GetFilename(const BackupStoreAccountDatabase::Entry&
diff --git a/lib/backupstore/StoreTestUtils.cpp b/lib/backupstore/StoreTestUtils.cpp
index 2b773cb1..902552d5 100644
--- a/lib/backupstore/StoreTestUtils.cpp
+++ b/lib/backupstore/StoreTestUtils.cpp
@@ -54,7 +54,7 @@ bool delete_account()
}
std::vector<uint32_t> ExpectedRefCounts;
-int bbstored_pid = 0, bbackupd_pid = 0;
+int bbstored_pid = 0, bbackupd_pid = 0, s3simulator_pid = 0;
void set_refcount(int64_t ObjectID, uint32_t RefCount)
{
@@ -266,11 +266,11 @@ bool check_reference_counts()
return counts_ok;
}
-bool StartServer()
+bool StartServer(const std::string& daemon_args)
{
- bbstored_pid = StartDaemon(bbstored_pid,
- BBSTORED " " + bbstored_args + " testfiles/bbstored.conf",
- "testfiles/bbstored.pid");
+ const std::string& daemon_args_final(daemon_args.size() ? daemon_args : bbstored_args);
+ bbstored_pid = StartDaemon(bbstored_pid, BBSTORED " " + daemon_args_final +
+ " testfiles/bbstored.conf", "testfiles/bbstored.pid");
return bbstored_pid != 0;
}
@@ -282,11 +282,11 @@ bool StopServer(bool wait_for_process)
return result;
}
-bool StartClient(const std::string& bbackupd_conf_file)
+bool StartClient(const std::string& bbackupd_conf_file, const std::string& daemon_args)
{
- bbackupd_pid = StartDaemon(bbackupd_pid,
- BBACKUPD " " + bbackupd_args + " " + bbackupd_conf_file,
- "testfiles/bbackupd.pid");
+ const std::string& daemon_args_final(daemon_args.size() ? daemon_args : bbackupd_args);
+ bbackupd_pid = StartDaemon(bbackupd_pid, BBACKUPD " " + daemon_args_final + " -c " +
+ bbackupd_conf_file, "testfiles/bbackupd.pid");
return bbackupd_pid != 0;
}
@@ -298,3 +298,40 @@ bool StopClient(bool wait_for_process)
return result;
}
+bool StartSimulator()
+{
+ s3simulator_pid = StartDaemon(s3simulator_pid,
+ "../../bin/s3simulator/s3simulator " + bbstored_args +
+ " testfiles/s3simulator.conf", "testfiles/s3simulator.pid");
+ return s3simulator_pid != 0;
+}
+
+bool StopSimulator()
+{
+ bool result = StopDaemon(s3simulator_pid, "testfiles/s3simulator.pid",
+ "s3simulator.memleaks", true);
+ s3simulator_pid = 0;
+ return result;
+}
+
+bool kill_running_daemons()
+{
+ bool success = true;
+
+ if(FileExists("testfiles/bbstored.pid"))
+ {
+ TEST_THAT_OR(KillServer("testfiles/bbstored.pid", true), success = false);
+ }
+
+ if(FileExists("testfiles/bbackupd.pid"))
+ {
+ TEST_THAT_OR(KillServer("testfiles/bbackupd.pid", true), success = false);
+ }
+
+ if(FileExists("testfiles/s3simulator.pid"))
+ {
+ TEST_THAT_OR(KillServer("testfiles/s3simulator.pid", true), success = false);
+ }
+
+ return success;
+}
diff --git a/lib/backupstore/StoreTestUtils.h b/lib/backupstore/StoreTestUtils.h
index b3faebb5..794fbd44 100644
--- a/lib/backupstore/StoreTestUtils.h
+++ b/lib/backupstore/StoreTestUtils.h
@@ -66,17 +66,24 @@ bool run_housekeeping_and_check_account();
bool check_reference_counts();
//! Starts the bbstored test server running, which must not already be running.
-bool StartServer();
+bool StartServer(const std::string& daemon_args = "");
//! Stops the currently running bbstored test server.
bool StopServer(bool wait_for_process = false);
//! Starts the bbackupd client running, which must not already be running.
-bool StartClient(const std::string& bbackupd_conf_file = "testfiles/bbackupd.conf");
+bool StartClient(const std::string& bbackupd_conf_file = "testfiles/bbackupd.conf",
+ const std::string& daemon_args = "");
//! Stops the currently running bbackupd client.
bool StopClient(bool wait_for_process = false);
+bool StartSimulator();
+
+bool StopSimulator();
+
+bool kill_running_daemons();
+
//! Creates the standard test account, for example after delete_account().
bool create_account(int soft, int hard);
diff --git a/lib/bbackupd/BackupDaemon.cpp b/lib/bbackupd/BackupDaemon.cpp
index 996c1919..d75aa381 100644
--- a/lib/bbackupd/BackupDaemon.cpp
+++ b/lib/bbackupd/BackupDaemon.cpp
@@ -579,8 +579,9 @@ void BackupDaemon::InitCrypto()
std::string certFile(conf.GetKeyValue("CertificateFile"));
std::string keyFile(conf.GetKeyValue("PrivateKeyFile"));
std::string caFile(conf.GetKeyValue("TrustedCAsFile"));
+ int ssl_security_level(conf.GetKeyValueInt("SSLSecurityLevel"));
mTlsContext.Initialise(false /* as client */, certFile.c_str(),
- keyFile.c_str(), caFile.c_str());
+ keyFile.c_str(), caFile.c_str(), ssl_security_level);
// Set up the keys for various things
BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile"));
diff --git a/lib/common/BoxException.h b/lib/common/BoxException.h
index 361f04e8..e3a2268a 100644
--- a/lib/common/BoxException.h
+++ b/lib/common/BoxException.h
@@ -34,6 +34,9 @@ public:
private:
};
+#define EXCEPTION_IS_TYPE(exception_obj, type, subtype) \
+ (exception_obj.GetType() == type::ExceptionType && \
+ exception_obj.GetSubType() == type::subtype)
#endif // BOXEXCEPTION__H
diff --git a/lib/common/BoxPortsAndFiles.h.in b/lib/common/BoxPortsAndFiles.h.in
index 047a828f..f63e614b 100644
--- a/lib/common/BoxPortsAndFiles.h.in
+++ b/lib/common/BoxPortsAndFiles.h.in
@@ -20,6 +20,10 @@
// directory within the RAIDFILE root for the backup store daemon
#define BOX_RAIDFILE_ROOT_BBSTORED "backup"
+// default security level if SSLSecurityLevel is not specified: see
+// https://github.com/boxbackup/boxbackup/wiki/WeakSSLCertificates
+const int BOX_DEFAULT_SSL_SECURITY_LEVEL = -1;
+
// configuration file paths
#ifdef WIN32
// no default config file path, use these macros to call
diff --git a/lib/common/Configuration.cpp b/lib/common/Configuration.cpp
index 8ce8d389..9860864a 100644
--- a/lib/common/Configuration.cpp
+++ b/lib/common/Configuration.cpp
@@ -470,6 +470,16 @@ int Configuration::GetKeyValueInt(const std::string& rKeyName) const
}
+int Configuration::GetKeyValueInt(const std::string& rKeyName, int default_value) const
+{
+ if(!KeyExists(rKeyName))
+ {
+ return default_value;
+ }
+ return GetKeyValueInt(rKeyName);
+}
+
+
// --------------------------------------------------------------------------
//
// Function
@@ -778,8 +788,7 @@ bool Configuration::Verify(const ConfigurationVerify &rVerify,
}
else if(pvkey->HasDefaultValue())
{
- mKeys[pvkey->Name()] =
- pvkey->DefaultValue();
+ mKeys[pvkey->Name()] = pvkey->DefaultValue();
}
}
@@ -922,5 +931,3 @@ bool Configuration::Verify(const ConfigurationVerify &rVerify,
return ok;
}
-
-
diff --git a/lib/common/Configuration.h b/lib/common/Configuration.h
index e6498e80..f9b5eb77 100644
--- a/lib/common/Configuration.h
+++ b/lib/common/Configuration.h
@@ -122,6 +122,7 @@ public:
bool KeyExists(const std::string& rKeyName) const;
const std::string &GetKeyValue(const std::string& rKeyName) const;
int GetKeyValueInt(const std::string& rKeyName) const;
+ int GetKeyValueInt(const std::string& rKeyName, int default_value) const;
uint32_t GetKeyValueUint32(const std::string& rKeyName) const;
bool GetKeyValueBool(const std::string& rKeyName) const;
std::vector<std::string> GetKeyNames() const;
diff --git a/lib/common/FileStream.h b/lib/common/FileStream.h
index 1426d8a2..26442212 100644
--- a/lib/common/FileStream.h
+++ b/lib/common/FileStream.h
@@ -42,6 +42,7 @@ public:
virtual pos_type BytesLeftToRead();
virtual void Write(const void *pBuffer, int NBytes,
int Timeout = IOStream::TimeOutInfinite);
+ using IOStream::Write;
virtual pos_type GetPosition() const;
virtual void Seek(IOStream::pos_type Offset, int SeekType);
virtual void Close();
diff --git a/lib/common/Test.cpp b/lib/common/Test.cpp
index 2c51cd61..3d1620a1 100644
--- a/lib/common/Test.cpp
+++ b/lib/common/Test.cpp
@@ -28,7 +28,7 @@
int num_tests_selected = 0;
int num_failures = 0;
-int old_failure_count = 0;
+static int old_failure_count = 0; // do not expose!
int first_fail_line;
std::string original_working_dir;
std::string first_fail_file;
@@ -97,6 +97,8 @@ bool setUp(const char* function_name)
if(StartsWith("TestDir", filename) ||
StartsWith("0_", filename) ||
filename == "accounts.txt" ||
+ filename == "bbackupd-data" ||
+ filename == "ca" ||
StartsWith("file", filename) ||
StartsWith("notifyran", filename) ||
StartsWith("notifyscript.tag", filename) ||
@@ -105,7 +107,9 @@ bool setUp(const char* function_name)
filename == "syncallowscript.control" ||
StartsWith("syncallowscript.notifyran.", filename) ||
filename == "test2.downloaded" ||
- EndsWith("testfile", filename))
+ EndsWith("testfile", filename) ||
+ filename == "tmp" ||
+ EndsWith(".qdbm", filename))
{
std::string filepath = std::string("testfiles\\") + filename;
@@ -201,7 +205,8 @@ bool setUp(const char* function_name)
"testfiles/restore* testfiles/bbackupd-data "
"testfiles/syncallowscript.control "
"testfiles/syncallowscript.notifyran.* "
- "testfiles/test2.downloaded"
+ "testfiles/test2.downloaded "
+ "testfiles/tmp "
) == 0);
TEST_THAT_THROWONFAIL(system("touch testfiles/accounts.txt") == 0);
#endif
@@ -382,133 +387,6 @@ int ReadPidFile(const char *pidFile)
return pid;
}
-int LaunchServer(const std::string& rCommandLine, const char *pidFile)
-{
- BOX_INFO("Starting server: " << rCommandLine);
-
-#ifdef WIN32
-
- PROCESS_INFORMATION procInfo;
-
- STARTUPINFO startInfo;
- startInfo.cb = sizeof(startInfo);
- startInfo.lpReserved = NULL;
- startInfo.lpDesktop = NULL;
- startInfo.lpTitle = NULL;
- startInfo.dwFlags = 0;
- startInfo.cbReserved2 = 0;
- startInfo.lpReserved2 = NULL;
-
- std::string cmd = ConvertPaths(rCommandLine);
- CHAR* tempCmd = strdup(cmd.c_str());
-
- DWORD result = CreateProcess
- (
- NULL, // lpApplicationName, naughty!
- tempCmd, // lpCommandLine
- NULL, // lpProcessAttributes
- NULL, // lpThreadAttributes
- false, // bInheritHandles
- 0, // dwCreationFlags
- NULL, // lpEnvironment
- NULL, // lpCurrentDirectory
- &startInfo, // lpStartupInfo
- &procInfo // lpProcessInformation
- );
-
- free(tempCmd);
-
- TEST_THAT_OR(result != 0,
- BOX_LOG_WIN_ERROR("Launch failed: " << rCommandLine);
- return -1;
- );
-
- CloseHandle(procInfo.hProcess);
- CloseHandle(procInfo.hThread);
-
- return WaitForServerStartup(pidFile, (int)procInfo.dwProcessId);
-
-#else // !WIN32
-
- TEST_THAT_OR(RunCommand(rCommandLine) == 0,
- TEST_FAIL_WITH_MESSAGE("Failed to start server: " << rCommandLine);
- return -1;
- )
-
- return WaitForServerStartup(pidFile, 0);
-
-#endif // WIN32
-}
-
-int WaitForServerStartup(const char *pidFile, int pidIfKnown)
-{
- #ifdef WIN32
- if (pidFile == NULL)
- {
- return pidIfKnown;
- }
- #else
- // on other platforms there is no other way to get
- // the PID, so a NULL pidFile doesn't make sense.
- ASSERT(pidFile != NULL);
- #endif
-
- // time for it to start up
- BOX_TRACE("Waiting for server to start");
-
- for (int i = 0; i < 15; i++)
- {
- if (TestFileNotEmpty(pidFile))
- {
- break;
- }
-
- if (pidIfKnown && !ServerIsAlive(pidIfKnown))
- {
- break;
- }
-
- ::sleep(1);
- }
-
- // on Win32 we can check whether the process is alive
- // without even checking the PID file
-
- if (pidIfKnown && !ServerIsAlive(pidIfKnown))
- {
- TEST_FAIL_WITH_MESSAGE("Server died!");
- return -1;
- }
-
- if (!TestFileNotEmpty(pidFile))
- {
- TEST_FAIL_WITH_MESSAGE("Server didn't save PID file");
- return -1;
- }
-
- BOX_TRACE("Server started");
-
- // wait a second for the pid to be written to the file
- ::sleep(1);
-
- // read pid file
- int pid = ReadPidFile(pidFile);
-
- // On Win32 we can check whether the PID in the pidFile matches
- // the one returned by the system, which it always should.
-
- if (pidIfKnown && pid != pidIfKnown)
- {
- BOX_ERROR("Server wrote wrong pid to file (" << pidFile <<
- "): expected " << pidIfKnown << " but found " <<
- pid);
- TEST_FAIL_WITH_MESSAGE("Server wrote wrong pid to file");
- return -1;
- }
-
- return pid;
-}
-
void TestRemoteProcessMemLeaksFunc(const char *filename,
const char* file, int line)
{
diff --git a/lib/common/Test.h b/lib/common/Test.h
index 4b5cef61..35443c29 100644
--- a/lib/common/Test.h
+++ b/lib/common/Test.h
@@ -23,6 +23,7 @@
#define BBACKUPQUERY "..\\..\\bin\\bbackupquery\\bbackupquery.exe"
#define BBSTOREACCOUNTS "..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts.exe"
#define TEST_RETURN(actual, expected) TEST_EQUAL(expected, actual);
+#define TEST_RETURN_COMMAND(actual, expected, command) TEST_EQUAL_LINE(expected, actual, command);
#else
#define BBACKUPCTL "../../bin/bbackupctl/bbackupctl"
#define BBACKUPD "../../bin/bbackupd/bbackupd"
@@ -30,12 +31,16 @@
#define BBACKUPQUERY "../../bin/bbackupquery/bbackupquery"
#define BBSTOREACCOUNTS "../../bin/bbstoreaccounts/bbstoreaccounts"
#define TEST_RETURN(actual, expected) TEST_EQUAL((expected << 8), actual);
+#define TEST_RETURN_COMMAND(actual, expected, command) TEST_EQUAL_LINE((expected << 8), actual, command);
#endif
+#define DEFAULT_BBSTORED_CONFIG_FILE "testfiles/bbstored.conf"
+#define DEFAULT_BBACKUPD_CONFIG_FILE "testfiles/bbackupd.conf"
+#define DEFAULT_S3_CACHE_DIR "testfiles/bbackupd-cache"
+
extern int num_failures;
extern int first_fail_line;
extern int num_tests_selected;
-extern int old_failure_count;
extern std::string first_fail_file;
extern std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
extern std::list<std::string> run_only_named_tests;
@@ -215,6 +220,7 @@ int finish_test_suite();
bool TestFileExists(const char *Filename);
bool TestDirExists(const char *Filename);
+bool TestFileNotEmpty(const char *Filename);
// -1 if doesn't exist
int TestGetFileSize(const std::string& Filename);
@@ -222,8 +228,6 @@ std::string ConvertPaths(const std::string& rOriginal);
int RunCommand(const std::string& rCommandLine);
bool ServerIsAlive(int pid);
int ReadPidFile(const char *pidFile);
-int LaunchServer(const std::string& rCommandLine, const char *pidFile);
-int WaitForServerStartup(const char *pidFile, int pidIfKnown);
#define TestRemoteProcessMemLeaks(filename) \
TestRemoteProcessMemLeaksFunc(filename, __FILE__, __LINE__)
diff --git a/lib/server/ConnectionException.txt b/lib/server/ConnectionException.txt
index 7dcaadeb..74390853 100644
--- a/lib/server/ConnectionException.txt
+++ b/lib/server/ConnectionException.txt
@@ -15,6 +15,7 @@ TLSNoPeerCertificate 36
TLSPeerCertificateInvalid 37 Check certification process
TLSClosedWhenWriting 38
TLSHandshakeTimedOut 39
+TLSPeerWeakCertificate 40 The peer's certificate is too weak for the current SSL Security Level, see https://github.com/boxbackup/boxbackup/wiki/WeakSSLCertificates
Protocol_Timeout 41 Probably a network issue between client and server.
Protocol_ObjTooBig 42
Protocol_BadCommandRecieved 44
diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp
index d3c8441f..76141b6f 100644
--- a/lib/server/Daemon.cpp
+++ b/lib/server/Daemon.cpp
@@ -42,6 +42,7 @@
#include "autogen_ConnectionException.h"
#include "autogen_ServerException.h"
+#include "BoxPortsAndFiles.h"
#include "Configuration.h"
#include "Daemon.h"
#include "FileModificationTime.h"
@@ -52,6 +53,9 @@
#include "MemLeakFindOn.h"
+const ConfigurationVerifyKey ssl_security_level_key("SSLSecurityLevel",
+ ConfigTest_IsInt | ConfigTest_LastEntry, BOX_DEFAULT_SSL_SECURITY_LEVEL);
+
Daemon *Daemon::spDaemon = 0;
diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h
index b5384918..60ce4507 100644
--- a/lib/server/Daemon.h
+++ b/lib/server/Daemon.h
@@ -121,5 +121,7 @@ private:
ConfigurationVerifyKey("LogFacility", 0), \
ConfigurationVerifyKey("User", ConfigTest_LastEntry)
+extern const ConfigurationVerifyKey ssl_security_level_key;
+
#endif // DAEMON__H
diff --git a/lib/server/ServerControl.cpp b/lib/server/ServerControl.cpp
index f1a718df..b6cadab3 100644
--- a/lib/server/ServerControl.cpp
+++ b/lib/server/ServerControl.cpp
@@ -18,7 +18,9 @@
#include "BoxTime.h"
#include "IOStreamGetLine.h"
#include "ServerControl.h"
+#include "SocketStream.h"
#include "Test.h"
+#include "autogen_ServerException.h"
#ifdef WIN32
@@ -227,7 +229,7 @@ bool KillServer(int pid, bool WaitForProcess)
return !ServerIsAlive(pid);
}
-bool KillServer(std::string pid_file, bool WaitForProcess)
+bool KillServer(const std::string& pid_file, bool WaitForProcess)
{
FileStream fs(pid_file);
IOStreamGetLine getline(fs);
@@ -251,11 +253,174 @@ bool KillServer(std::string pid_file, bool WaitForProcess)
return status;
}
-int StartDaemon(int current_pid, const std::string& cmd_line, const char* pid_file)
+int LaunchServer(const std::string& rCommandLine, const char *pidFile, int port,
+ const std::string& socket_path)
+{
+ BOX_INFO("Starting server: " << rCommandLine);
+
+#ifdef WIN32
+
+ // Use a Windows "Job Object" as a container for all our child
+ // processes. The test runner will create this job object when
+ // it starts, and close the handle (killing any running daemons)
+ // when it exits. This is the best way to avoid daemons hanging
+ // around and causing subsequent tests to fail, and/or the test
+ // runner to hang waiting for a daemon that will never terminate.
+
+ PROCESS_INFORMATION procInfo;
+
+ STARTUPINFO startInfo;
+ startInfo.cb = sizeof(startInfo);
+ startInfo.lpReserved = NULL;
+ startInfo.lpDesktop = NULL;
+ startInfo.lpTitle = NULL;
+ startInfo.dwFlags = 0;
+ startInfo.cbReserved2 = 0;
+ startInfo.lpReserved2 = NULL;
+
+ std::string cmd = ConvertPaths(rCommandLine);
+ CHAR* tempCmd = strdup(cmd.c_str());
+
+ DWORD result = CreateProcess
+ (
+ NULL, // lpApplicationName, naughty!
+ tempCmd, // lpCommandLine
+ NULL, // lpProcessAttributes
+ NULL, // lpThreadAttributes
+ false, // bInheritHandles
+ 0, // dwCreationFlags
+ NULL, // lpEnvironment
+ NULL, // lpCurrentDirectory
+ &startInfo, // lpStartupInfo
+ &procInfo // lpProcessInformation
+ );
+
+ free(tempCmd);
+
+ TEST_THAT_OR(result != 0,
+ BOX_LOG_WIN_ERROR("Failed to CreateProcess: " << rCommandLine);
+ return -1;
+ );
+
+ CloseHandle(procInfo.hProcess);
+ CloseHandle(procInfo.hThread);
+
+ return WaitForServerStartup(pidFile, (int)procInfo.dwProcessId, port, socket_path);
+
+#else // !WIN32
+
+ TEST_THAT_OR(RunCommand(rCommandLine) == 0,
+ TEST_FAIL_WITH_MESSAGE("Failed to start server: " << rCommandLine);
+ return -1;
+ )
+
+ return WaitForServerStartup(pidFile, 0, port, socket_path);
+
+#endif // WIN32
+}
+
+int WaitForServerStartup(const char *pidFile, int pidIfKnown, int port,
+ const std::string& socket_path)
+{
+#ifdef WIN32
+ if(pidFile == NULL && port == 0 && socket_path == "")
+ {
+ return pidIfKnown;
+ }
+#else
+ // On other platforms there is no other way to get the PID, so a NULL pidFile doesn't
+ // make sense.
+ ASSERT(pidFile != NULL);
+#endif
+
+ // time for it to start up
+ BOX_TRACE("Waiting for server to start");
+
+ for (int i = 150; i >= 0; i--)
+ {
+ if(i == 0)
+ {
+ // ran out of time waiting
+ TEST_FAIL_WITH_MESSAGE("Server didn't start within expected time");
+ return -1;
+ }
+
+ ShortSleep(MilliSecondsToBoxTime(100), false);
+
+ if(!TestFileNotEmpty(pidFile))
+ {
+ // Hasn't written a complete PID file yet, go round again
+ continue;
+ }
+
+ // Once we know what PID the process has/had, we can check if it has died during or
+ // shortly after startup:
+ if (pidIfKnown && !ServerIsAlive(pidIfKnown))
+ {
+ TEST_FAIL_WITH_MESSAGE("Server died!");
+ return -1;
+ }
+
+ if(port != 0 || socket_path != "")
+ {
+ try
+ {
+ if(port != 0)
+ {
+ SocketStream conn;
+ conn.Open(Socket::TypeINET, "localhost", port);
+ }
+
+ if(socket_path != "")
+ {
+ SocketStream conn;
+ conn.Open(Socket::TypeUNIX, socket_path);
+ }
+ }
+ catch(ServerException &e)
+ {
+ if(EXCEPTION_IS_TYPE(e, ServerException, SocketOpenError))
+ {
+ // not listening on port, go round again
+ continue;
+ }
+ else
+ {
+ // something bad happened, break
+ throw;
+ }
+ }
+ }
+
+ // All tests that we can do have passed, looks good!
+ break;
+ }
+
+ BOX_TRACE("Server started");
+
+ // read pid file
+ int pid = ReadPidFile(pidFile);
+
+ // On Win32 we can check whether the PID in the pidFile matches
+ // the one returned by the system, which it always should.
+ if (pidIfKnown && pid != pidIfKnown)
+ {
+ BOX_ERROR("Server wrote wrong pid to file (" << pidFile <<
+ "): expected " << pidIfKnown << " but found " <<
+ pid);
+ TEST_FAIL_WITH_MESSAGE("Server wrote wrong pid to file");
+ return -1;
+ }
+
+ return pid;
+}
+
+int StartDaemon(int current_pid, const std::string& cmd_line, const char* pid_file, int port,
+ const std::string& socket_path)
{
TEST_THAT_OR(current_pid == 0, return 0);
- int new_pid = LaunchServer(cmd_line, pid_file);
+ int new_pid = LaunchServer(cmd_line, pid_file, port, socket_path);
TEST_THAT_OR(new_pid != -1 && new_pid != 0, return 0);
::sleep(1);
diff --git a/lib/server/ServerControl.h b/lib/server/ServerControl.h
index be2464c1..28320491 100644
--- a/lib/server/ServerControl.h
+++ b/lib/server/ServerControl.h
@@ -4,11 +4,17 @@
#include "Test.h"
bool HUPServer(int pid);
-bool KillServer(int pid, bool WaitForProcess = false);
-bool KillServer(std::string pid_file, bool WaitForProcess = false);
-int StartDaemon(int current_pid, const std::string& cmd_line, const char* pid_file);
-bool StopDaemon(int current_pid, const std::string& pid_file,
- const std::string& memleaks_file, bool wait_for_process);
+bool KillServer(int pid, bool wait_for_process = false);
+bool KillServer(const std::string& pid_file, bool wait_for_process = false);
+bool KillServerInternal(int pid);
+int StartDaemon(int current_pid, const std::string& cmd_line, const char* pid_file, int port = 0,
+ const std::string& socket_path = "");
+bool StopDaemon(int current_pid, const std::string& pid_file, const std::string& memleaks_file,
+ bool wait_for_process);
+int LaunchServer(const std::string& rCommandLine, const char *pidFile, int port = 0,
+ const std::string& socket_path = "");
+int WaitForServerStartup(const char *pidFile, int pidIfKnown, int port = 0,
+ const std::string& socket_path = "");
#ifdef WIN32
#include "WinNamedPipeStream.h"
diff --git a/lib/server/ServerException.txt b/lib/server/ServerException.txt
index 474b4067..02fb379c 100644
--- a/lib/server/ServerException.txt
+++ b/lib/server/ServerException.txt
@@ -29,6 +29,7 @@ TLSSetCiphersFailed 28
SSLLibraryInitialisationError 29
TLSNoSSLObject 31
TLSAlreadyHandshaked 35
+TLSServerWeakCertificate 36 Our SSL certificate is too weak for the current SSL Security Level, see https://github.com/boxbackup/boxbackup/wiki/WeakSSLCertificates
SocketSetNonBlockingFailed 40
Protocol_BadUsage 43
Protocol_UnsuitableStreamTypeForSending 51
diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h
index 3f6eed7e..db8beaf2 100644
--- a/lib/server/ServerStream.h
+++ b/lib/server/ServerStream.h
@@ -306,7 +306,16 @@ public:
#endif // !WIN32
// Just handle in this process
SetProcessTitle("handling");
- HandleConnection(connection);
+ try
+ {
+ HandleConnection(connection);
+ }
+ catch(BoxException &e)
+ {
+ BOX_ERROR("Error in child handler, terminating connection: "
+ "exception " << e.what() << "(" << e.GetType() << "/" <<
+ e.GetSubType() << ")");
+ }
SetProcessTitle("idle");
#ifndef WIN32
}
diff --git a/lib/server/ServerTLS.h b/lib/server/ServerTLS.h
index f748f4b2..6b53e860 100644
--- a/lib/server/ServerTLS.h
+++ b/lib/server/ServerTLS.h
@@ -10,6 +10,7 @@
#ifndef SERVERTLS__H
#define SERVERTLS__H
+#include "BoxPortsAndFiles.h"
#include "ServerStream.h"
#include "SocketStreamTLS.h"
#include "SSLLib.h"
@@ -52,8 +53,12 @@ public:
std::string certFile(serverconf.GetKeyValue("CertificateFile"));
std::string keyFile(serverconf.GetKeyValue("PrivateKeyFile"));
std::string caFile(serverconf.GetKeyValue("TrustedCAsFile"));
+
+ int ssl_security_level(serverconf.GetKeyValueInt("SSLSecurityLevel",
+ BOX_DEFAULT_SSL_SECURITY_LEVEL));
+
mContext.Initialise(true /* as server */, certFile.c_str(),
- keyFile.c_str(), caFile.c_str());
+ keyFile.c_str(), caFile.c_str(), ssl_security_level);
// Then do normal stream server stuff
ServerStream<SocketStreamTLS, Port, ListenBacklog,
@@ -75,6 +80,8 @@ private:
ConfigurationVerifyKey("CertificateFile", ConfigTest_Exists), \
ConfigurationVerifyKey("PrivateKeyFile", ConfigTest_Exists), \
ConfigurationVerifyKey("TrustedCAsFile", ConfigTest_Exists), \
+ ConfigurationVerifyKey("SSLSecurityLevel", ConfigTest_IsInt, \
+ BOX_DEFAULT_SSL_SECURITY_LEVEL), \
SERVERSTREAM_VERIFY_SERVER_KEYS(DEFAULT_ADDRESSES)
#endif // SERVERTLS__H
diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp
index edb5e5b8..f8c6c85c 100644
--- a/lib/server/SocketStream.cpp
+++ b/lib/server/SocketStream.cpp
@@ -171,6 +171,10 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port)
Socket::NameLookupToSockAddr(addr, sockDomain, Type, rName, Port,
addrLen);
+ std::ostringstream oss;
+ oss << rName << ":" << Port;
+ mPeerSocketDesc = oss.str();
+
// Create the socket
mSocketHandle = ::socket(sockDomain, SOCK_STREAM,
0 /* let OS choose protocol */);
diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h
index fd57af8f..6b029387 100644
--- a/lib/server/SocketStream.h
+++ b/lib/server/SocketStream.h
@@ -114,6 +114,7 @@ private:
protected:
off_t mBytesRead;
off_t mBytesWritten;
+ std::string mPeerSocketDesc;
public:
off_t GetBytesRead() const {return mBytesRead;}
diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp
index e6299bfa..fc9652b7 100644
--- a/lib/server/SocketStreamTLS.cpp
+++ b/lib/server/SocketStreamTLS.cpp
@@ -10,8 +10,7 @@
#include "Box.h"
#define TLS_CLASS_IMPLEMENTATION_CPP
-#include <openssl/ssl.h>
-#include <openssl/bio.h>
+
#include <errno.h>
#include <fcntl.h>
@@ -19,6 +18,10 @@
#include <poll.h>
#endif
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
#include "autogen_ConnectionException.h"
#include "autogen_ServerException.h"
#include "BoxTime.h"
@@ -126,8 +129,8 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
mpBIO = ::BIO_new(::BIO_s_socket());
if(mpBIO == 0)
{
- CryptoUtils::LogError("creating socket bio");
- THROW_EXCEPTION(ServerException, TLSAllocationFailed)
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSAllocationFailed,
+ "Failed to create SSL BIO: " << CryptoUtils::LogError("creating socket bio"));
}
tOSSocketHandle socket = GetSocketHandle();
@@ -137,8 +140,8 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
mpSSL = ::SSL_new(rContext.GetRawContext());
if(mpSSL == 0)
{
- CryptoUtils::LogError("creating SSL object");
- THROW_EXCEPTION(ServerException, TLSAllocationFailed)
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSAllocationFailed,
+ "Failed to create SSL object: " << CryptoUtils::LogError("creating SSL object"));
}
// Make the socket non-blocking so timeouts on Read work
@@ -203,15 +206,43 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
default: // (and SSL_ERROR_ZERO_RETURN)
// Error occured
+#if HAVE_DECL_SSL_R_EE_KEY_TOO_SMALL
+ int err_reason = ERR_GET_REASON(ERR_peek_error());
+ const char *file, *data;
+ int line, flags;
+ ERR_peek_error_line_data(&file, &line, &data, &flags);
+ long verify_result = SSL_get_verify_result(mpSSL);
+
+ if(se == SSL_ERROR_SSL && verify_result == X509_V_ERR_CA_KEY_TOO_SMALL)
+ {
+ // Would be nice to use GetPeerCommonName() in these error messages,
+ // but since the certificate isn't trusted, that might be misleading,
+ // and it's not available to us anyway :(
+
+ THROW_EXCEPTION_MESSAGE(ConnectionException, TLSPeerWeakCertificate,
+ (IsServer ? "Failed to accept connection from" :
+ "Failed to connect to") << " " << mPeerSocketDesc <<
+ ": key too short for current security level");
+ }
+ else if(se == SSL_ERROR_SSL && verify_result == X509_V_ERR_CA_MD_TOO_WEAK)
+ {
+ THROW_EXCEPTION_MESSAGE(ConnectionException, TLSPeerWeakCertificate,
+ (IsServer ? "Failed to accept connection from" :
+ "Failed to connect to") << " " << mPeerSocketDesc <<
+ ": hash too weak for current security level");
+ }
+ else
+#endif // HAVE_DECL_SSL_R_EE_KEY_TOO_SMALL
if(IsServer)
{
- CryptoUtils::LogError("accepting connection");
- THROW_EXCEPTION(ConnectionException, TLSHandshakeFailed)
+ THROW_EXCEPTION_MESSAGE(ConnectionException, TLSHandshakeFailed,
+ "Failed to accept connection: " <<
+ CryptoUtils::LogError("accepting connection"));
}
else
{
- CryptoUtils::LogError("connecting");
- THROW_EXCEPTION(ConnectionException, TLSHandshakeFailed)
+ THROW_EXCEPTION_MESSAGE(ConnectionException, TLSHandshakeFailed,
+ "Failed to connect: " << CryptoUtils::LogError("connecting"));
}
}
}
diff --git a/lib/server/SocketStreamTLS.h b/lib/server/SocketStreamTLS.h
index 3fda98c1..8a793966 100644
--- a/lib/server/SocketStreamTLS.h
+++ b/lib/server/SocketStreamTLS.h
@@ -34,10 +34,11 @@ public:
SocketStreamTLS();
SocketStreamTLS(int socket);
~SocketStreamTLS();
+
private:
SocketStreamTLS(const SocketStreamTLS &rToCopy);
-public:
+public:
void Open(const TLSContext &rContext, Socket::Type Type,
const std::string& rName, int Port = 0);
void Handshake(const TLSContext &rContext, bool IsServer = false);
diff --git a/lib/server/TLSContext.cpp b/lib/server/TLSContext.cpp
index 1a6d4a53..9c01452b 100644
--- a/lib/server/TLSContext.cpp
+++ b/lib/server/TLSContext.cpp
@@ -10,10 +10,12 @@
#include "Box.h"
#define TLS_CLASS_IMPLEMENTATION_CPP
+#include <openssl/err.h>
#include <openssl/ssl.h>
#include "autogen_ConnectionException.h"
#include "autogen_ServerException.h"
+#include "BoxPortsAndFiles.h"
#include "CryptoUtils.h"
#include "SSLLib.h"
#include "TLSContext.h"
@@ -21,7 +23,7 @@
#include "MemLeakFindOn.h"
#define MAX_VERIFICATION_DEPTH 2
-#define CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
+#define CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
// Macros to allow compatibility with OpenSSL 1.0 and 1.1 APIs. See
// https://github.com/charybdis-ircd/charybdis/blob/release/3.5/libratbox/src/openssl_ratbox.h
@@ -71,7 +73,8 @@ TLSContext::~TLSContext()
// Created: 2003/08/06
//
// --------------------------------------------------------------------------
-void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const char *PrivateKeyFile, const char *TrustedCAsFile)
+void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const char *PrivateKeyFile,
+ const char *TrustedCAsFile, int SSLSecurityLevel)
{
if(mpContext != 0)
{
@@ -84,29 +87,65 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
+#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
+ if(SSLSecurityLevel == -1)
+ {
+ BOX_WARNING("SSLSecurityLevel not set. Your connection may not be secure. "
+ "Please see https://github.com/boxbackup/boxbackup/wiki/WeakSSLCertificates "
+ "for details");
+ SSLSecurityLevel = 1; // Default for now. Unsafe, but we warned the user.
+ // TODO: upgrade to level 2 soon.
+ }
+
+ SSL_CTX_set_security_level(mpContext, SSLSecurityLevel);
+#else
+ if(SSLSecurityLevel != BOX_DEFAULT_SSL_SECURITY_LEVEL)
+ {
+ BOX_WARNING("SSLSecurityLevel is set, but this Box Backup is not compiled with "
+ "OpenSSL 1.1 or higher, so will be ignored (compiled with "
+ OPENSSL_VERSION_TEXT ")");
+ }
+#endif
+
// Setup our identity
if(::SSL_CTX_use_certificate_chain_file(mpContext, CertificatesFile) != 1)
{
- std::string msg = "loading certificates from ";
- msg += CertificatesFile;
- CryptoUtils::LogError(msg);
- THROW_EXCEPTION(ServerException, TLSLoadCertificatesFailed)
+#if HAVE_DECL_SSL_R_EE_KEY_TOO_SMALL
+ int err_reason = ERR_GET_REASON(ERR_peek_error());
+ if(err_reason == SSL_R_EE_KEY_TOO_SMALL)
+ {
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSServerWeakCertificate,
+ "Failed to load certificates from " << CertificatesFile << ": "
+ "key too short for current security level");
+ }
+ else if(err_reason == SSL_R_CA_MD_TOO_WEAK)
+ {
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSServerWeakCertificate,
+ "Failed to load certificates from " << CertificatesFile << ": "
+ "hash too weak for current security level");
+ }
+ else
+#endif // HAVE_DECL_SSL_R_EE_KEY_TOO_SMALL
+ {
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSLoadCertificatesFailed,
+ "Failed to load certificates from " << CertificatesFile << ": " <<
+ CryptoUtils::LogError("loading certificates"));
+ }
}
+
if(::SSL_CTX_use_PrivateKey_file(mpContext, PrivateKeyFile, SSL_FILETYPE_PEM) != 1)
{
- std::string msg = "loading private key from ";
- msg += PrivateKeyFile;
- CryptoUtils::LogError(msg);
- THROW_EXCEPTION(ServerException, TLSLoadPrivateKeyFailed)
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSLoadPrivateKeyFailed,
+ "Failed to load private key from " << PrivateKeyFile << ": " <<
+ CryptoUtils::LogError("loading private key"));
}
// Setup the identify of CAs we trust
if(::SSL_CTX_load_verify_locations(mpContext, TrustedCAsFile, NULL) != 1)
{
- std::string msg = "loading CA cert from ";
- msg += TrustedCAsFile;
- CryptoUtils::LogError(msg);
- THROW_EXCEPTION(ServerException, TLSLoadTrustedCAsFailed)
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSLoadTrustedCAsFailed,
+ "Failed to load CA certificate from " << TrustedCAsFile << ": " <<
+ CryptoUtils::LogError("loading CA cert"));
}
// Setup options to require these certificates
@@ -117,8 +156,9 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
// Setup allowed ciphers
if(::SSL_CTX_set_cipher_list(mpContext, CIPHER_LIST) != 1)
{
- CryptoUtils::LogError("setting cipher list to " CIPHER_LIST);
- THROW_EXCEPTION(ServerException, TLSSetCiphersFailed)
+ THROW_EXCEPTION_MESSAGE(ServerException, TLSSetCiphersFailed,
+ "Failed to set cipher list to " << CIPHER_LIST << ": " <<
+ CryptoUtils::LogError("setting cipher list"));
}
}
diff --git a/lib/server/TLSContext.h b/lib/server/TLSContext.h
index f52f5457..6239d136 100644
--- a/lib/server/TLSContext.h
+++ b/lib/server/TLSContext.h
@@ -30,7 +30,8 @@ public:
private:
TLSContext(const TLSContext &);
public:
- void Initialise(bool AsServer, const char *CertificatesFile, const char *PrivateKeyFile, const char *TrustedCAsFile);
+ void Initialise(bool AsServer, const char *CertificatesFile, const char *PrivateKeyFile,
+ const char *TrustedCAsFile, int SSLSecurityLevel = -1);
SSL_CTX *GetRawContext() const;
private:
diff --git a/lib/win32/getopt_long.cpp b/lib/win32/getopt_long.cpp
index af2833a1..825de2a0 100755
--- a/lib/win32/getopt_long.cpp
+++ b/lib/win32/getopt_long.cpp
@@ -1,546 +1,546 @@
-/* $OpenBSD: getopt_long.c,v 1.20 2005/10/25 15:49:37 jmc Exp $ */
-/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
-// Adapted for Box Backup by Chris Wilson <chris+boxbackup@qwirx.com>
-
-/*
- * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Dieter Baron and Thomas Klausner.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-// #include "Box.h"
-#include "emu.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "box_getopt.h"
-
-#ifdef REPLACE_GETOPT // until end of file
-
-int opterr = 1; /* if error message should be printed */
-int optind = 1; /* index into parent argv vector */
-int optopt = '?'; /* character checked for validity */
-int optreset; /* reset getopt */
-char *optarg; /* argument associated with option */
-
-#define PRINT_ERROR ((opterr) && (*options != ':'))
-
-#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
-#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
-#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
-
-/* return values */
-#define BADCH (int)'?'
-#define BADARG ((*options == ':') ? (int)':' : (int)'?')
-#define INORDER (int)1
-
-#define EMSG ""
-
-static void warnx(const char* fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-}
-
-static int getopt_internal(int, char * const *, const char *,
- const struct option *, int *, int);
-static int parse_long_options(char * const *, const char *,
- const struct option *, int *, int);
-static int gcd(int, int);
-static void permute_args(int, int, int, char * const *);
-
-static char *place = EMSG; /* option letter processing */
-
-/* XXX: set optreset to 1 rather than these two */
-static int nonopt_start = -1; /* first non option argument (for permute) */
-static int nonopt_end = -1; /* first option after non options (for permute) */
-
-/* Error messages */
-static const char recargchar[] = "option requires an argument -- %c";
-static const char recargstring[] = "option requires an argument -- %s";
-static const char ambig[] = "ambiguous option -- %.*s";
-static const char noarg[] = "option doesn't take an argument -- %.*s";
-static const char illoptchar[] = "unknown option -- %c";
-static const char illoptstring[] = "unknown option -- %s";
-
-/*
- * Compute the greatest common divisor of a and b.
- */
-static int
-gcd(int a, int b)
-{
- int c;
-
- c = a % b;
- while (c != 0) {
- a = b;
- b = c;
- c = a % b;
- }
-
- return (b);
-}
-
-/*
- * Exchange the block from nonopt_start to nonopt_end with the block
- * from nonopt_end to opt_end (keeping the same order of arguments
- * in each block).
- */
-static void
-permute_args(int panonopt_start, int panonopt_end, int opt_end,
- char * const *nargv)
-{
- int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
- char *swap;
-
- /*
- * compute lengths of blocks and number and size of cycles
- */
- nnonopts = panonopt_end - panonopt_start;
- nopts = opt_end - panonopt_end;
- ncycle = gcd(nnonopts, nopts);
- cyclelen = (opt_end - panonopt_start) / ncycle;
-
- for (i = 0; i < ncycle; i++) {
- cstart = panonopt_end+i;
- pos = cstart;
- for (j = 0; j < cyclelen; j++) {
- if (pos >= panonopt_end)
- pos -= nnonopts;
- else
- pos += nopts;
- swap = nargv[pos];
- /* LINTED const cast */
- ((char **) nargv)[pos] = nargv[cstart];
- /* LINTED const cast */
- ((char **)nargv)[cstart] = swap;
- }
- }
-}
-
-/*
- * parse_long_options --
- * Parse long options in argc/argv argument vector.
- * Returns -1 if short_too is set and the option does not match long_options.
- */
-static int
-parse_long_options(char * const *nargv, const char *options,
- const struct option *long_options, int *idx, int short_too)
-{
- char *current_argv, *has_equal;
- size_t current_argv_len;
- int i, match;
-
- current_argv = place;
- match = -1;
-
- optind++;
-
- if ((has_equal = strchr(current_argv, '=')) != NULL) {
- /* argument found (--option=arg) */
- current_argv_len = has_equal - current_argv;
- has_equal++;
- } else
- current_argv_len = strlen(current_argv);
-
- for (i = 0; long_options[i].name; i++) {
- /* find matching long option */
- if (strncmp(current_argv, long_options[i].name,
- current_argv_len))
- continue;
-
- if (strlen(long_options[i].name) == current_argv_len) {
- /* exact match */
- match = i;
- break;
- }
- /*
- * If this is a known short option, don't allow
- * a partial match of a single character.
- */
- if (short_too && current_argv_len == 1)
- continue;
-
- if (match == -1) /* partial match */
- match = i;
- else {
- /* ambiguous abbreviation */
- if (PRINT_ERROR)
- warnx(ambig, (int)current_argv_len,
- current_argv);
- optopt = 0;
- return (BADCH);
- }
- }
- if (match != -1) { /* option found */
- if (long_options[match].has_arg == no_argument
- && has_equal) {
- if (PRINT_ERROR)
- warnx(noarg, (int)current_argv_len,
- current_argv);
- /*
- * XXX: GNU sets optopt to val regardless of flag
- */
- if (long_options[match].flag == NULL)
- optopt = long_options[match].val;
- else
- optopt = 0;
- return (BADARG);
- }
- if (long_options[match].has_arg == required_argument ||
- long_options[match].has_arg == optional_argument) {
- if (has_equal)
- optarg = has_equal;
- else if (long_options[match].has_arg ==
- required_argument) {
- /*
- * optional argument doesn't use next nargv
- */
- optarg = nargv[optind++];
- }
- }
- if ((long_options[match].has_arg == required_argument)
- && (optarg == NULL)) {
- /*
- * Missing argument; leading ':' indicates no error
- * should be generated.
- */
- if (PRINT_ERROR)
- warnx(recargstring,
- current_argv);
- /*
- * XXX: GNU sets optopt to val regardless of flag
- */
- if (long_options[match].flag == NULL)
- optopt = long_options[match].val;
- else
- optopt = 0;
- --optind;
- return (BADARG);
- }
- } else { /* unknown option */
- if (short_too) {
- --optind;
- return (-1);
- }
- if (PRINT_ERROR)
- warnx(illoptstring, current_argv);
- optopt = 0;
- return (BADCH);
- }
- if (idx)
- *idx = match;
- if (long_options[match].flag) {
- *long_options[match].flag = long_options[match].val;
- return (0);
- } else
- return (long_options[match].val);
-}
-
-/*
- * getopt_internal --
- * Parse argc/argv argument vector. Called by user level routines.
- */
-static int
-getopt_internal(int nargc, char * const *nargv, const char *options,
- const struct option *long_options, int *idx, int flags)
-{
- const char * oli; /* option letter list index */
- int optchar, short_too;
- static int posixly_correct = -1;
-
- if (options == NULL)
- return (-1);
-
- /*
- * Disable GNU extensions if POSIXLY_CORRECT is set or options
- * string begins with a '+'.
- */
- if (posixly_correct == -1)
- posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
- if (posixly_correct || *options == '+')
- flags &= ~FLAG_PERMUTE;
- else if (*options == '-')
- flags |= FLAG_ALLARGS;
- if (*options == '+' || *options == '-')
- options++;
-
- /*
- * XXX Some GNU programs (like cvs) set optind to 0 instead of
- * XXX using optreset. Work around this braindamage.
- */
- if (optind == 0)
- optind = optreset = 1;
-
- optarg = NULL;
- if (optreset)
- nonopt_start = nonopt_end = -1;
-start:
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc) { /* end of argument vector */
- place = EMSG;
- if (nonopt_end != -1) {
- /* do permutation, if we have to */
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- optind -= nonopt_end - nonopt_start;
- }
- else if (nonopt_start != -1) {
- /*
- * If we skipped non-options, set optind
- * to the first of them.
- */
- optind = nonopt_start;
- }
- nonopt_start = nonopt_end = -1;
- return (-1);
- }
- if (*(place = nargv[optind]) != '-' ||
- (place[1] == '\0' && strchr(options, '-') == NULL)) {
- place = EMSG; /* found non-option */
- if (flags & FLAG_ALLARGS) {
- /*
- * GNU extension:
- * return non-option as argument to option 1
- */
- optarg = nargv[optind++];
- return (INORDER);
- }
- if (!(flags & FLAG_PERMUTE)) {
- /*
- * If no permutation wanted, stop parsing
- * at first non-option.
- */
- return (-1);
- }
- /* do permutation */
- if (nonopt_start == -1)
- nonopt_start = optind;
- else if (nonopt_end != -1) {
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- nonopt_start = optind -
- (nonopt_end - nonopt_start);
- nonopt_end = -1;
- }
- optind++;
- /* process next argument */
- goto start;
- }
- if (nonopt_start != -1 && nonopt_end == -1)
- nonopt_end = optind;
-
- /*
- * If we have "-" do nothing, if "--" we are done.
- */
- if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
- optind++;
- place = EMSG;
- /*
- * We found an option (--), so if we skipped
- * non-options, we have to permute.
- */
- if (nonopt_end != -1) {
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- optind -= nonopt_end - nonopt_start;
- }
- nonopt_start = nonopt_end = -1;
- return (-1);
- }
- }
-
- /*
- * Check long options if:
- * 1) we were passed some
- * 2) the arg is not just "-"
- * 3) either the arg starts with -- we are getopt_long_only()
- */
- if (long_options != NULL && place != nargv[optind] &&
- (*place == '-' || (flags & FLAG_LONGONLY))) {
- short_too = 0;
- if (*place == '-')
- place++; /* --foo long option */
- else if (*place != ':' && strchr(options, *place) != NULL)
- short_too = 1; /* could be short option too */
-
- optchar = parse_long_options(nargv, options, long_options,
- idx, short_too);
- if (optchar != -1) {
- place = EMSG;
- return (optchar);
- }
- }
-
- if ((optchar = (int)*place++) == (int)':' ||
- optchar == (int)'-' && *place != '\0' ||
- (oli = strchr(options, optchar)) == NULL) {
- /*
- * If the user specified "-" and '-' isn't listed in
- * options, return -1 (non-option) as per POSIX.
- * Otherwise, it is an unknown option character (or ':').
- */
- if (optchar == (int)'-' && *place == '\0')
- return (-1);
- if (!*place)
- ++optind;
- if (PRINT_ERROR)
- warnx(illoptchar, optchar);
- optopt = optchar;
- return (BADCH);
- }
- if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
- /* -W long-option */
- if (*place) /* no space */
- /* NOTHING */;
- else if (++optind >= nargc) { /* no arg */
- place = EMSG;
- if (PRINT_ERROR)
- warnx(recargchar, optchar);
- optopt = optchar;
- return (BADARG);
- } else /* white space */
- place = nargv[optind];
- optchar = parse_long_options(nargv, options, long_options,
- idx, 0);
- place = EMSG;
- return (optchar);
- }
- if (*++oli != ':') { /* doesn't take argument */
- if (!*place)
- ++optind;
- } else { /* takes (optional) argument */
- optarg = NULL;
- if (*place) /* no white space */
- optarg = place;
- /* XXX: disable test for :: if PC? (GNU doesn't) */
- else if (oli[1] != ':') { /* arg not optional */
- if (++optind >= nargc) { /* no arg */
- place = EMSG;
- if (PRINT_ERROR)
- warnx(recargchar, optchar);
- optopt = optchar;
- return (BADARG);
- } else
- optarg = nargv[optind];
- } else if (!(flags & FLAG_PERMUTE)) {
- /*
- * If permutation is disabled, we can accept an
- * optional arg separated by whitespace so long
- * as it does not start with a dash (-).
- */
- if (optind + 1 < nargc && *nargv[optind + 1] != '-')
- optarg = nargv[++optind];
- }
- place = EMSG;
- ++optind;
- }
- /* dump back option letter */
- return (optchar);
-}
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- *
- * [eventually this will replace the BSD getopt]
- */
-int
-getopt(int nargc, char * const *nargv, const char *options)
-{
-
- /*
- * We don't pass FLAG_PERMUTE to getopt_internal() since
- * the BSD getopt(3) (unlike GNU) has never done this.
- *
- * Furthermore, since many privileged programs call getopt()
- * before dropping privileges it makes sense to keep things
- * as simple (and bug-free) as possible.
- */
- return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
-}
-
-/*
- * getopt_long --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long(int nargc, char * const *nargv, const char *options,
- const struct option *long_options, int *idx)
-{
-
- return (getopt_internal(nargc, nargv, options, long_options, idx,
- FLAG_PERMUTE));
-}
-
-/*
- * getopt_long_only --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long_only(int nargc, char * const *nargv, const char *options,
- const struct option *long_options, int *idx)
-{
-
- return (getopt_internal(nargc, nargv, options, long_options, idx,
- FLAG_PERMUTE|FLAG_LONGONLY));
-}
-
-#endif // REPLACE_GETOPT
+/* $OpenBSD: getopt_long.c,v 1.20 2005/10/25 15:49:37 jmc Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+// Adapted for Box Backup by Chris Wilson <chris+boxbackup@qwirx.com>
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// #include "Box.h"
+#include "emu.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "box_getopt.h"
+
+#ifdef REPLACE_GETOPT // until end of file
+
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static void warnx(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, match;
+
+ current_argv = place;
+ match = -1;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ const char * oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ if (posixly_correct == -1)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ else if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ optchar == (int)'-' && *place != '\0' ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ /* XXX: disable test for :: if PC? (GNU doesn't) */
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ } else if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If permutation is disabled, we can accept an
+ * optional arg separated by whitespace so long
+ * as it does not start with a dash (-).
+ */
+ if (optind + 1 < nargc && *nargv[optind + 1] != '-')
+ optarg = nargv[++optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
+
+#endif // REPLACE_GETOPT
diff --git a/lib/win32/messages.rc b/lib/win32/messages.rc
index 116522b7..0885a897 100755
--- a/lib/win32/messages.rc
+++ b/lib/win32/messages.rc
@@ -1,2 +1,2 @@
-LANGUAGE 0x9,0x1
-1 11 MSG00001.bin
+LANGUAGE 0x9,0x1
+1 11 MSG00001.bin