qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
}
-static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
+static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qboolean inuserdir)
{
char vabuf[1024];
qfile_t *f = NULL;
fs_offset_t n;
- if(*fs_userdir)
- f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_userdir, path), "rb", false);
- if(!f)
+ if(inuserdir)
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false);
+ else
f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false);
if(!f)
return 0;
challenge_append_length = p - challenge_append;
}
-static void Crypto_LoadKeys(void)
+void Crypto_LoadKeys(void)
{
char buf[8192];
size_t len, len2;
int i;
char vabuf[1024];
+ if(!d0_blind_id_dll) // don't if we can't
+ return;
+
+ if(crypto_idstring) // already loaded? then not
+ return;
+
+ Host_LockSession(); // we use the session ID here
+
// load keys
// note: we are just a CLIENT
// so we load:
memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
pubkeys_havepriv[i] = false;
- len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf));
+ len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false);
if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
{
len2 = FP64_SIZE;
if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
{
Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
- len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si", i), buf, sizeof(buf));
+ len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true);
if(len)
{
if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
len2 = FP64_SIZE;
if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
{
- Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (public key fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
+ Con_Printf("Loaded private ID key_%d.d0si%s for key_%d.d0pk (public key fingerprint: %s)\n", i, sessionid.string, i, pubkeys_priv_fp64[i]);
pubkeys_havepriv[i] = true;
strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
}
crypto_idstring = NULL;
}
-
static mempool_t *cryptomempool;
#ifdef __cplusplus
Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
Crypto_InitHostKeys();
- Crypto_LoadKeys();
}
// end
return;
}
- if(*fs_userdir)
- {
- FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_userdir, keygen_i));
- f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
- }
+ FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
if(!f)
{
- FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_basedir, keygen_i));
- f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
- }
- if(!f)
- {
- Con_Printf("Cannot open key_%d.d0si\n", keygen_i);
+ Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
keygen_i = -1;
if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
return;
FS_Write(f, buf2, buf2size);
FS_Close(f);
- Con_Printf("Saved to key_%d.d0si\n", keygen_i);
+ Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
keygen_i = -1;
if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
}
return;
}
if (crypto_mutex) Thread_LockMutex(crypto_mutex);
+ Crypto_LoadKeys();
i = atoi(Cmd_Argv(1));
if(!pubkeys[i])
{
{
Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
if(pubkeys_havepriv[i])
- Con_Printf(" private ID key_%d.d0si (public key fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
+ Con_Printf(" private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]);
}
}
}
void Crypto_Init(void);
void Crypto_Init_Commands(void);
+void Crypto_LoadKeys(void);
void Crypto_Shutdown(void);
qboolean Crypto_Available(void);
void sha256(unsigned char *out, const unsigned char *in, int n); // may ONLY be called if Crypto_Available()
static pack_t *FS_LoadPackPK3 (const char *packfile)
{
int packhandle;
-#if _MSC_VER >= 1400
- _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
- packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
+ packhandle = FS_SysOpenFD (packfile, "rb", false);
if (packhandle < 0)
return NULL;
return FS_LoadPackPK3FromFD(packfile, packhandle, false);
pack_t *pack;
dpackfile_t *info;
-#if _MSC_VER >= 1400
- _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
- packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
+ packhandle = FS_SysOpenFD(packfile, "rb", false);
if (packhandle < 0)
return NULL;
if(read (packhandle, (void *)&header, sizeof(header)) != sizeof(header))
// see if we can write to this path (note: won't create path)
#ifdef WIN32
-# if _MSC_VER >= 1400
- _sopen_s(&fd, va(vabuf, sizeof(vabuf), "%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE); // note: no O_TRUNC here!
-# else
- fd = open (va(vabuf, sizeof(vabuf), "%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, 0666); // note: no O_TRUNC here!
-# endif
+ // no access() here, we must try to open the file for appending
+ fd = Sys_OpenFD(va(vabuf, sizeof(vabuf), "%s%s/config.cfg", userdir, gamedirname1), "a", false);
if(fd >= 0)
close(fd);
#else
int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
{
- int handle;
+ int handle = -1;
int mod, opt;
unsigned int ind;
+ qboolean dolock = false;
// Parse the mode string
switch (mode[0])
case 'b':
opt |= O_BINARY;
break;
+ case 'l':
+ dolock = true;
+ break;
default:
Con_Printf ("FS_SysOpen(%s, %s): unknown character in mode (%c)\n",
filepath, mode, mode[ind]);
if (nonblocking)
opt |= O_NONBLOCK;
-#if _MSC_VER >= 1400
- _sopen_s(&handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+#ifdef WIN32
+# if _MSC_VER >= 1400
+ _sopen_s(&handle, filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
+# else
+ handle = _sopen (filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
+# endif
#else
handle = open (filepath, mod | opt, 0666);
+ if(handle >= 0 && dolock)
+ {
+ struct flock l;
+ l.l_type = ((mod == O_RDONLY) ? F_RDLCK : F_WRLCK);
+ l.l_whence = SEEK_SET;
+ l.l_start = 0;
+ l.l_len = 0;
+ if(fcntl(handle, F_SETLK, &l) == -1)
+ {
+ close(handle);
+ handle = -1;
+ }
+ }
#endif
+
return handle;
}
cvar_t timestamps = {CVAR_SAVE, "timestamps", "0", "prints timestamps on console messages"};
cvar_t timeformat = {CVAR_SAVE, "timeformat", "[%Y-%m-%d %H:%M:%S] ", "time format to use on timestamped console messages"};
+cvar_t sessionid = {CVAR_READONLY, "sessionid", "", "ID of the current session (use the -sessionid parameter to set it); this is always either empty or begins with a dot (.)"};
+cvar_t locksession = {0, "locksession", "0", "Lock the session? 0 = no, 1 = yes and abort on failure, 2 = yes and continue on failure"};
+
/*
================
Host_AbortCurrentFrame
extern qboolean host_stuffcmdsrun;
+static qfile_t *locksession_fh = NULL;
+static qboolean locksession_run = false;
+static void Host_InitSession(void)
+{
+ int i;
+ Cvar_RegisterVariable(&sessionid);
+ Cvar_RegisterVariable(&locksession);
+
+ // load the session ID into the read-only cvar
+ if ((i = COM_CheckParm("-sessionid")) && (i + 1 < com_argc))
+ {
+ char vabuf[1024];
+ if(com_argv[i+1][0] == '.')
+ Cvar_SetQuick(&sessionid, com_argv[i+1]);
+ else
+ Cvar_SetQuick(&sessionid, va(vabuf, sizeof(vabuf), ".%s", com_argv[i+1]));
+ }
+}
+void Host_LockSession(void)
+{
+ if(locksession_run)
+ return;
+ locksession_run = true;
+ if(locksession.integer != 0)
+ {
+ char vabuf[1024];
+ locksession_fh = FS_SysOpen(va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string), "wl", false);
+ // TODO maybe write the pid into the lockfile, while we are at it? may help server management tools
+ if(!locksession_fh)
+ {
+ if(locksession.integer == 2)
+ {
+ Con_Printf("WARNING: session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+ }
+ else
+ {
+ Sys_Error("session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+ }
+ }
+ }
+}
+void Host_UnlockSession(void)
+{
+ if(!locksession_run)
+ return;
+ locksession_run = false;
+
+ if(locksession_fh)
+ {
+ FS_Close(locksession_fh);
+ // NOTE: we can NOT unlink the lock here, as doing so would
+ // create a race condition if another process created it
+ // between our close and our unlink
+ locksession_fh = NULL;
+ }
+}
+
/*
====================
Host_Init
// initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name)
FS_Init();
+ // register the cvars for session locking
+ Host_InitSession();
+
// must be after FS_Init
Crypto_Init();
Crypto_Init_Commands();
Sys_Shutdown();
Log_Close();
Crypto_Shutdown();
- FS_Shutdown();
+
+ Host_UnlockSession();
+
+ S_Shutdown();
Con_Shutdown();
Memory_Shutdown();
}
{
int port;
NetConn_CloseClientPorts();
+
+ Crypto_LoadKeys(); // client sockets
+
port = bound(0, cl_netport.integer, 65535);
if (cl_netport.integer != port)
Cvar_SetValueQuick(&cl_netport, port);
{
int port;
NetConn_CloseServerPorts();
+
+ Crypto_LoadKeys(); // server sockets
+
NetConn_UpdateSockets();
port = bound(0, sv_netport.integer, 65535);
if (port == 0)
if (prog->loaded)
prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name );
+ Host_LockSession(); // all progs can use the session cvar
+ Crypto_LoadKeys(); // all progs might use the keys at init time
+
dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name);
extern cvar_t developer_loadfile;
extern cvar_t developer_loading;
+extern cvar_t sessionid;
+
#define STARTCONFIGFILENAME "quake.rc"
#define CONFIGFILENAME "config.cfg"
void Host_ShutdownServer(void);
void Host_Reconnect_f(void);
void Host_NoOperation_f(void);
+void Host_LockSession(void);
+void Host_UnlockSession(void);
void Host_AbortCurrentFrame(void);