mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-26 07:59:35 -05:00
Prevent multiple instances from running on Unix systems.
Every call to RsInit::LoadCertificates() now creates a file: ~/.retroshare/xxxxxxxxxxxxxxxxxxxx/lock which is then bound to a system lock (fcntl F_SETLK). If the lock request fails, it means another instance is already running with the same profile. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3241 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
840f077826
commit
fe46d7618a
@ -310,7 +310,7 @@ int AuthGPG::GPGInit(std::string ownId)
|
|||||||
|
|
||||||
std::cerr << "AuthGPG::GPGInit finished." << std::endl;
|
std::cerr << "AuthGPG::GPGInit finished." << std::endl;
|
||||||
|
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthGPG::~AuthGPG()
|
AuthGPG::~AuthGPG()
|
||||||
@ -780,7 +780,7 @@ bool AuthGPG::DoOwnSignature(const void *data, unsigned int datalen, void *buf_s
|
|||||||
// gpgme_data_write (gpgmeSig, "", 1); // to be able to convert it into a string
|
// gpgme_data_write (gpgmeSig, "", 1); // to be able to convert it into a string
|
||||||
char *export_sig = gpgme_data_release_and_get_mem(gpgmeSig, &len);
|
char *export_sig = gpgme_data_release_and_get_mem(gpgmeSig, &len);
|
||||||
#ifdef GPG_DEBUG
|
#ifdef GPG_DEBUG
|
||||||
fprintf(stderr, "AuthGPG::Signature len: %d \n", len);
|
std::cerr << "AuthGPG::Signature len: " << len << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (len < *outl) // -1 because we added a 0 at the end.
|
if (len < *outl) // -1 because we added a 0 at the end.
|
||||||
|
@ -66,7 +66,7 @@ class RsInit
|
|||||||
static bool GeneratePGPCertificate(std::string name, std::string email, std::string passwd, std::string &pgpId, std::string &errString);
|
static bool GeneratePGPCertificate(std::string name, std::string email, std::string passwd, std::string &pgpId, std::string &errString);
|
||||||
|
|
||||||
/* Login PGP */
|
/* Login PGP */
|
||||||
static bool SelectGPGAccount(std::string id);
|
static bool SelectGPGAccount(const std::string& gpgId);
|
||||||
static bool LoadGPGPassword(std::string passwd);
|
static bool LoadGPGPassword(std::string passwd);
|
||||||
|
|
||||||
/* Create SSL Certificates */
|
/* Create SSL Certificates */
|
||||||
@ -78,8 +78,11 @@ class RsInit
|
|||||||
/** Final Certificate load. This can be called if:
|
/** Final Certificate load. This can be called if:
|
||||||
* a) InitRetroshare() returns true -> autoLoad/password Set.
|
* a) InitRetroshare() returns true -> autoLoad/password Set.
|
||||||
* b) SelectGPGAccount() && LoadPassword()
|
* b) SelectGPGAccount() && LoadPassword()
|
||||||
|
*
|
||||||
|
* This wrapper is used to lock the profile first before
|
||||||
|
* finalising the login
|
||||||
*/
|
*/
|
||||||
static int LoadCertificates(bool autoLoginNT) ;
|
static int LockAndLoadCertificates(bool autoLoginNT);
|
||||||
|
|
||||||
|
|
||||||
/* Post Login Options */
|
/* Post Login Options */
|
||||||
@ -108,6 +111,12 @@ class RsInit
|
|||||||
static bool RsStoreAutoLogin() ;
|
static bool RsStoreAutoLogin() ;
|
||||||
static bool RsTryAutoLogin() ;
|
static bool RsTryAutoLogin() ;
|
||||||
|
|
||||||
|
/* Lock/unlock profile directory */
|
||||||
|
static int LockConfigDirectory(const std::string& accountDir);
|
||||||
|
static void UnlockConfigDirectory();
|
||||||
|
|
||||||
|
/* The true LoadCertificates() method */
|
||||||
|
static int LoadCertificates(bool autoLoginNT) ;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,6 +27,12 @@
|
|||||||
* the GUI / External via a hidden class */
|
* the GUI / External via a hidden class */
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// for locking instances
|
||||||
|
#ifndef WINDOWS_SYS
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "util/rsdebug.h"
|
#include "util/rsdebug.h"
|
||||||
#include "util/rsdir.h"
|
#include "util/rsdir.h"
|
||||||
#include "rsiface/rsinit.h"
|
#include "rsiface/rsinit.h"
|
||||||
@ -78,6 +84,11 @@ class RsInitConfig
|
|||||||
/* for certificate creation */
|
/* for certificate creation */
|
||||||
//static std::string gpgPasswd;
|
//static std::string gpgPasswd;
|
||||||
|
|
||||||
|
#ifndef WINDOWS_SYS
|
||||||
|
static int lockHandle;
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
/* These fields are needed for login */
|
/* These fields are needed for login */
|
||||||
static std::string loginId;
|
static std::string loginId;
|
||||||
static std::string configDir;
|
static std::string configDir;
|
||||||
@ -131,6 +142,11 @@ static const int SSLPWD_LEN = 6;
|
|||||||
std::list<accountId> RsInitConfig::accountIds;
|
std::list<accountId> RsInitConfig::accountIds;
|
||||||
std::string RsInitConfig::preferedId;
|
std::string RsInitConfig::preferedId;
|
||||||
|
|
||||||
|
#ifndef WINDOWS_SYS
|
||||||
|
int RsInitConfig::lockHandle;
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string RsInitConfig::configDir;
|
std::string RsInitConfig::configDir;
|
||||||
std::string RsInitConfig::load_cert;
|
std::string RsInitConfig::load_cert;
|
||||||
std::string RsInitConfig::load_key;
|
std::string RsInitConfig::load_key;
|
||||||
@ -203,6 +219,7 @@ void RsInit::InitRsConfig()
|
|||||||
{
|
{
|
||||||
#ifndef WINDOWS_SYS
|
#ifndef WINDOWS_SYS
|
||||||
RsInitConfig::dirSeperator = '/'; // For unix.
|
RsInitConfig::dirSeperator = '/'; // For unix.
|
||||||
|
RsInitConfig::lockHandle = -1;
|
||||||
#else
|
#else
|
||||||
RsInitConfig::dirSeperator = '\\'; // For windows.
|
RsInitConfig::dirSeperator = '\\'; // For windows.
|
||||||
#endif
|
#endif
|
||||||
@ -878,29 +895,102 @@ int RsInit::GetPGPLoginDetails(std::string id, std::string &name, std::stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To prevent several running instances from using the same directory
|
||||||
|
* simultaneously we have to use a global lock.
|
||||||
|
* We use a lock file on Unix systems.
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* 0 : Success
|
||||||
|
* 1 : Another instance already has the lock
|
||||||
|
* 2 : Unexpected error
|
||||||
|
*/
|
||||||
|
int RsInit::LockConfigDirectory(const std::string& accountDir)
|
||||||
|
{
|
||||||
|
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||||
|
#ifndef WINDOWS_SYS
|
||||||
|
const std::string lockFile = accountDir + RsInitConfig::dirSeperator + "lock";
|
||||||
|
|
||||||
|
if(RsInitConfig::lockHandle != -1)
|
||||||
|
close(RsInitConfig::lockHandle);
|
||||||
|
|
||||||
|
// open the file in write mode, create it if necessary, truncate it (it should be empty)
|
||||||
|
RsInitConfig::lockHandle = open(lockFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
|
||||||
|
|
||||||
|
if(RsInitConfig::lockHandle == -1)
|
||||||
|
{
|
||||||
|
std::cerr << "Could not open lock file " << lockFile.c_str() << std::flush;
|
||||||
|
perror(NULL);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see "man fcntl" for the details, in short: non blocking lock creation on the whole file contents
|
||||||
|
struct flock lockDetails;
|
||||||
|
lockDetails.l_type = F_WRLCK;
|
||||||
|
lockDetails.l_whence = SEEK_SET;
|
||||||
|
lockDetails.l_start = 0;
|
||||||
|
lockDetails.l_len = 0;
|
||||||
|
|
||||||
|
if(fcntl(RsInitConfig::lockHandle, F_SETLK, &lockDetails) == -1)
|
||||||
|
{
|
||||||
|
int fcntlErr = errno;
|
||||||
|
std::cerr << "Could not request lock on file " << lockFile.c_str() << std::flush;
|
||||||
|
perror(NULL);
|
||||||
|
|
||||||
|
// there's no lock so let's release the file handle immediately
|
||||||
|
close(RsInitConfig::lockHandle);
|
||||||
|
RsInitConfig::lockHandle = -1;
|
||||||
|
|
||||||
|
if(fcntlErr == EACCES || fcntlErr == EAGAIN)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlock the currently locked profile, if there is one.
|
||||||
|
* For Unix systems we simply close the handle of the lock file.
|
||||||
|
*/
|
||||||
|
void RsInit::UnlockConfigDirectory()
|
||||||
|
{
|
||||||
|
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||||
|
#ifndef WINDOWS_SYS
|
||||||
|
if(RsInitConfig::lockHandle != -1)
|
||||||
|
{
|
||||||
|
close(RsInitConfig::lockHandle);
|
||||||
|
RsInitConfig::lockHandle = -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Before any SSL stuff can be loaded, the correct PGP must be selected / generated:
|
/* Before any SSL stuff can be loaded, the correct PGP must be selected / generated:
|
||||||
**/
|
**/
|
||||||
|
|
||||||
bool RsInit::SelectGPGAccount(std::string id)
|
bool RsInit::SelectGPGAccount(const std::string& gpgId)
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool retVal = false;
|
||||||
std::string gpgId = id;
|
|
||||||
std::string name = id;
|
|
||||||
|
|
||||||
if (0 < AuthGPG::getAuthGPG() -> GPGInit(gpgId))
|
if (0 < AuthGPG::getAuthGPG() -> GPGInit(gpgId))
|
||||||
{
|
{
|
||||||
ok = true;
|
retVal = true;
|
||||||
std::cerr << "PGP Auth Success! ";
|
std::cerr << "PGP Auth Success!";
|
||||||
std::cerr << "ID: " << id << " NAME: " << name;
|
|
||||||
std::cerr << std::endl;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
std::cerr << "PGP Auth Failed!";
|
std::cerr << "PGP Auth Failed!";
|
||||||
std::cerr << "ID: " << id << " NAME: " << name;
|
|
||||||
std::cerr << std::endl;
|
std::cerr << " ID: " << gpgId << std::endl;
|
||||||
}
|
|
||||||
return ok;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1044,7 +1134,6 @@ bool RsInit::GenerateSSLCertificate(std::string gpg_id, std::string org, std
|
|||||||
std::cerr << "rename FAILED" << std::endl;
|
std::cerr << "rename FAILED" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Flag as first time run */
|
/* Flag as first time run */
|
||||||
RsInitConfig::firsttime_run = true;
|
RsInitConfig::firsttime_run = true;
|
||||||
|
|
||||||
@ -1145,13 +1234,40 @@ bool RsInit::LoadPassword(std::string id, std::string inPwd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the profile directory and tries to finalize the login procedure
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* 0 : success
|
||||||
|
* 1 : another instance is already running
|
||||||
|
* 2 : unexpected error while locking
|
||||||
|
* 3 : unexpected error while loading certificates
|
||||||
|
*/
|
||||||
|
int RsInit::LockAndLoadCertificates(bool autoLoginNT)
|
||||||
|
{
|
||||||
|
int retVal = LockConfigDirectory(RsInitConfig::configDir);
|
||||||
|
if(retVal != 0)
|
||||||
|
return retVal;
|
||||||
|
|
||||||
/***************************** FINAL LOADING OF SETUP *************************
|
retVal = LoadCertificates(autoLoginNT);
|
||||||
|
if(retVal != 1) {
|
||||||
|
UnlockConfigDirectory();
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** *************************** FINAL LOADING OF SETUP *************************
|
||||||
* Requires:
|
* Requires:
|
||||||
* PGPid to be selected (Password not required).
|
* PGPid to be selected (Password not required).
|
||||||
* CertId to be selected (Password Required).
|
* CertId to be selected (Password Required).
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* 0 : unexpected error
|
||||||
|
* 1 : success
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int RsInit::LoadCertificates(bool autoLoginNT)
|
int RsInit::LoadCertificates(bool autoLoginNT)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1224,7 +1340,7 @@ int RsInit::LoadCertificates(bool autoLoginNT)
|
|||||||
FILE *sslPassphraseFile = fopen(RsInitConfig::ssl_passphrase_file.c_str(), "r");
|
FILE *sslPassphraseFile = fopen(RsInitConfig::ssl_passphrase_file.c_str(), "r");
|
||||||
if (sslPassphraseFile == NULL)
|
if (sslPassphraseFile == NULL)
|
||||||
{
|
{
|
||||||
std::cerr << "No password povided, and no sslPassphraseFile : " << RsInitConfig::ssl_passphrase_file.c_str() << std::endl;
|
std::cerr << "No password provided, and no sslPassphraseFile : " << RsInitConfig::ssl_passphrase_file.c_str() << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "opening sslPassphraseFile : " << RsInitConfig::ssl_passphrase_file.c_str() << std::endl;
|
std::cerr << "opening sslPassphraseFile : " << RsInitConfig::ssl_passphrase_file.c_str() << std::endl;
|
||||||
|
@ -320,19 +320,27 @@ void GenCertDialog::checkChanged(int i)
|
|||||||
|
|
||||||
void GenCertDialog::loadCertificates()
|
void GenCertDialog::loadCertificates()
|
||||||
{
|
{
|
||||||
bool autoSave = false;
|
int retVal = RsInit::LockAndLoadCertificates(false);
|
||||||
/* Final stage of loading */
|
switch(retVal)
|
||||||
if (RsInit::LoadCertificates(autoSave))
|
|
||||||
{
|
{
|
||||||
close();
|
case 0: close();
|
||||||
}
|
break;
|
||||||
else
|
case 1: QMessageBox::warning( this,
|
||||||
{
|
tr("Multiple instances"),
|
||||||
/* some error msg */
|
tr("Another RetroShare using the same profile is "
|
||||||
QMessageBox::warning ( NULL,
|
"already running on your system. Please close "
|
||||||
"Generate ID Failure",
|
"that instance first") );
|
||||||
"Failed to Load your new Certificate!",
|
break;
|
||||||
QMessageBox::Ok);
|
case 2: QMessageBox::warning( this,
|
||||||
|
tr("Multiple instances"),
|
||||||
|
tr("An unexpected error occurred when Retroshare"
|
||||||
|
"tried to acquire the single instance lock") );
|
||||||
|
break;
|
||||||
|
case 3: QMessageBox::warning( this,
|
||||||
|
tr("Generate ID Failure"),
|
||||||
|
tr("Failed to Load your new Certificate!") );
|
||||||
|
break;
|
||||||
|
default: std::cerr << "StartDialog::loadCertificates() unexpected switch value " << retVal << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,18 +152,27 @@ void StartDialog::loadPerson()
|
|||||||
void StartDialog::loadCertificates()
|
void StartDialog::loadCertificates()
|
||||||
{
|
{
|
||||||
/* Final stage of loading */
|
/* Final stage of loading */
|
||||||
|
int retVal = RsInit::LockAndLoadCertificates(ui.autologin_checkbox->isChecked());
|
||||||
if (RsInit::LoadCertificates(ui.autologin_checkbox->isChecked()))
|
switch(retVal)
|
||||||
{
|
{
|
||||||
close();
|
case 0: close();
|
||||||
}
|
break;
|
||||||
else
|
case 1: QMessageBox::warning( this,
|
||||||
{
|
tr("Multiple instances"),
|
||||||
/* some error msg */
|
tr("Another RetroShare using the same profile is "
|
||||||
QMessageBox::warning ( this,
|
"already running on your system. Please close "
|
||||||
tr("Login Failure"),
|
"that instance first, or choose another profile") );
|
||||||
tr("Maybe password is wrong"),
|
break;
|
||||||
QMessageBox::Ok);
|
case 2: QMessageBox::warning( this,
|
||||||
|
tr("Multiple instances"),
|
||||||
|
tr("An unexpected error occurred when Retroshare"
|
||||||
|
"tried to acquire the single instance lock") );
|
||||||
|
break;
|
||||||
|
case 3: QMessageBox::warning( this,
|
||||||
|
tr("Login Failure"),
|
||||||
|
tr("Maybe password is wrong") );
|
||||||
|
break;
|
||||||
|
default: std::cerr << "StartDialog::loadCertificates() unexpected switch value " << retVal << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,27 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// true: note auto-login is active
|
// true: note auto-login is active
|
||||||
RsInit::LoadCertificates(true);
|
int retVal = RsInit::LockAndLoadCertificates(true);
|
||||||
|
switch(retVal)
|
||||||
|
{
|
||||||
|
case 0: break;
|
||||||
|
case 1: QMessageBox::warning( 0,
|
||||||
|
QObject::tr("Multiple instances"),
|
||||||
|
QObject::tr("Another RetroShare using the same profile is "
|
||||||
|
"already running on your system. Please close "
|
||||||
|
"that instance first") );
|
||||||
|
return 1;
|
||||||
|
case 2: QMessageBox::critical( 0,
|
||||||
|
QObject::tr("Multiple instances"),
|
||||||
|
QObject::tr("An unexpected error occurred when Retroshare"
|
||||||
|
"tried to acquire the single instance lock") );
|
||||||
|
return 1;
|
||||||
|
case 3: QMessageBox::critical( 0,
|
||||||
|
QObject::tr("Login Failure"),
|
||||||
|
QObject::tr("Maybe password is wrong") );
|
||||||
|
return 1;
|
||||||
|
default: std::cerr << "StartDialog::loadCertificates() unexpected switch value " << retVal << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rsicontrol->StartupRetroShare();
|
rsicontrol->StartupRetroShare();
|
||||||
|
@ -91,7 +91,19 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* Key + Certificate are loaded into libretroshare */
|
/* Key + Certificate are loaded into libretroshare */
|
||||||
|
|
||||||
RsInit::LoadCertificates(false);
|
int retVal = RsInit::LockAndLoadCertificates(false);
|
||||||
|
switch(retVal)
|
||||||
|
{
|
||||||
|
case 0: break;
|
||||||
|
case 1: std::cerr << "Error: another instance of retroshare is already using this profile" << std::endl;
|
||||||
|
return 1;
|
||||||
|
case 2: std::cerr << "An unexpected error occurred while locking the profile" << std::endl;
|
||||||
|
return 1;
|
||||||
|
case 3: std::cerr << "An error occurred while login with the profile" << std::endl;
|
||||||
|
return 1;
|
||||||
|
default: std::cerr << "Main: Unexpected switch value " << retVal << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Start-up libretroshare server threads */
|
/* Start-up libretroshare server threads */
|
||||||
rsServer -> StartupRetroShare();
|
rsServer -> StartupRetroShare();
|
||||||
|
Loading…
Reference in New Issue
Block a user