From: divverent Date: Tue, 1 Nov 2011 14:45:57 +0000 (+0000) Subject: Command line: -sessionid, cvars: locksession, (R/O) sessionid X-Git-Tag: xonotic-v0.6.0~163^2~44 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=927bd7b13c9a18fb07a8681c7483f632c7ea32f3;p=xonotic%2Fdarkplaces.git Command line: -sessionid, cvars: locksession, (R/O) sessionid Allows games to require a session lock. Put "locksession 1" in the game's default config file and users then need to run instances with unique -sessionid parameter. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11513 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/crypto.c b/crypto.c index adf5cb96..f9cfbbb5 100644 --- a/crypto.c +++ b/crypto.c @@ -356,14 +356,14 @@ void sha256(unsigned char *out, const unsigned char *in, int n) 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; @@ -765,13 +765,21 @@ static void Crypto_BuildChallengeAppend(void) 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: @@ -785,14 +793,14 @@ static void Crypto_LoadKeys(void) 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)) @@ -800,7 +808,7 @@ static void Crypto_LoadKeys(void) 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)); } @@ -885,7 +893,6 @@ static void Crypto_UnloadKeys(void) crypto_idstring = NULL; } - static mempool_t *cryptomempool; #ifdef __cplusplus @@ -983,7 +990,6 @@ void Crypto_Init(void) Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical Crypto_InitHostKeys(); - Crypto_LoadKeys(); } // end @@ -1163,19 +1169,11 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch 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; @@ -1183,7 +1181,7 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch 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); } @@ -1207,6 +1205,7 @@ static void Crypto_KeyGen_f(void) return; } if (crypto_mutex) Thread_LockMutex(crypto_mutex); + Crypto_LoadKeys(); i = atoi(Cmd_Argv(1)); if(!pubkeys[i]) { @@ -1295,7 +1294,7 @@ static void Crypto_Keys_f(void) { 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]); } } } diff --git a/crypto.h b/crypto.h index 2cff5c2d..7b2b9921 100644 --- a/crypto.h +++ b/crypto.h @@ -31,6 +31,7 @@ crypto_t; 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() diff --git a/fs.c b/fs.c index ff6c0eef..e5c7015f 100644 --- a/fs.c +++ b/fs.c @@ -775,11 +775,7 @@ static pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle, qbool 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); @@ -949,11 +945,7 @@ static pack_t *FS_LoadPackPAK (const char *packfile) 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)) @@ -1890,11 +1882,8 @@ static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t use // 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 @@ -2119,9 +2108,10 @@ void FS_Shutdown (void) 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]) @@ -2152,6 +2142,9 @@ int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking) 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]); @@ -2161,11 +2154,29 @@ int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking) 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; } diff --git a/host.c b/host.c index 729e998d..a8a8e0de 100644 --- a/host.c +++ b/host.c @@ -85,6 +85,9 @@ cvar_t developer_entityparsing = {0, "developer_entityparsing", "0", "prints det 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 @@ -1071,6 +1074,63 @@ qboolean sys_nostdout = false; 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 @@ -1168,6 +1228,9 @@ static void Host_Init (void) // 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(); @@ -1356,7 +1419,10 @@ void Host_Shutdown(void) Sys_Shutdown(); Log_Close(); Crypto_Shutdown(); - FS_Shutdown(); + + Host_UnlockSession(); + + S_Shutdown(); Con_Shutdown(); Memory_Shutdown(); } diff --git a/netconn.c b/netconn.c index aa839eef..2e1e9adb 100755 --- a/netconn.c +++ b/netconn.c @@ -922,6 +922,9 @@ void NetConn_OpenClientPorts(void) { 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); @@ -987,6 +990,9 @@ void NetConn_OpenServerPorts(int opennetports) { int port; NetConn_CloseServerPorts(); + + Crypto_LoadKeys(); // server sockets + NetConn_UpdateSockets(); port = bound(0, sv_netport.integer, 65535); if (port == 0) diff --git a/prvm_edict.c b/prvm_edict.c index e60c14d4..25f9899a 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -1896,6 +1896,9 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, int numrequiredfun 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); diff --git a/quakedef.h b/quakedef.h index f656b26f..65f24159 100644 --- a/quakedef.h +++ b/quakedef.h @@ -405,6 +405,8 @@ extern cvar_t developer_insane; extern cvar_t developer_loadfile; extern cvar_t developer_loading; +extern cvar_t sessionid; + #define STARTCONFIGFILENAME "quake.rc" #define CONFIGFILENAME "config.cfg" @@ -515,6 +517,8 @@ void Host_ClientCommands(const char *fmt, ...) DP_FUNC_PRINTF(1); 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);