From b63dc8b8800d10432ec506176510f27961257181 Mon Sep 17 00:00:00 2001 From: Spoike Date: Wed, 25 Mar 2020 21:29:30 +0000 Subject: [PATCH] prepare for proper binary auth instead of depending upon tls certs (using sha2(512) to ensure no modification). probably buggy on windows so not fully enabled yet. allow for binary updates on linux as on windows (-allowupdate for modified/nonsvn builds). dlightmask is now size_t, because we might as well allow that on 64bit cpus, this allows for 64 lightmaphack lights instead of 32. fix potential openal issue with source=0. added q3bsp_ignorestyles cvar to ignore rbsp styles (and reduce needed batch counts), should only be used on maps with subtle lighting changes (ones that are properly lit without toggling any lightswitches). add support for directly loading foo.bsp.gz Added prints to clarify why servers might be listed under the 'UNKNOWN' category in the master server. Attempt to show hostnames anyway, to make it a little more obvious who's responsible for those badly configured servers. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5656 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- CMakeLists.txt | 3 +- engine/Makefile | 1 + engine/client/cl_input.c | 5 +- engine/client/cl_main.c | 7 +- engine/client/cl_parse.c | 13 +- engine/client/client.h | 6 +- engine/client/m_download.c | 326 ++++++++++++++++- engine/client/m_options.c | 8 +- engine/client/pr_csqc.c | 50 ++- engine/client/r_surf.c | 134 ++++--- engine/client/render.h | 2 +- engine/client/snd_al.c | 83 ++--- engine/client/sys_linux.c | 67 +++- engine/client/sys_win.c | 19 +- engine/client/valid.c | 2 +- engine/client/view.c | 16 +- engine/common/bothdefs.h | 5 + engine/common/bspfile.h | 34 +- engine/common/com_mesh.c | 10 + engine/common/common.c | 91 +++++ engine/common/common.h | 29 +- engine/common/fs.c | 13 +- engine/common/gl_q2bsp.c | 56 +-- engine/common/net.h | 2 +- engine/common/net_ice.c | 6 +- engine/common/net_ssl_gnutls.c | 180 +++++++++- engine/common/net_ssl_winsspi.c | 74 ++++ engine/common/net_wins.c | 49 ++- engine/common/netinc.h | 12 + engine/common/pr_bgcmd.c | 18 +- engine/common/q1bsp.c | 2 +- engine/common/sha1.c | 115 +++--- engine/common/sha2.c | 563 ++++++++++++++++++++++++++++++ engine/common/sys.h | 18 +- engine/common/sys_linux_threads.c | 97 +++++ engine/common/zone.h | 6 + engine/gl/gl_font.c | 7 + engine/gl/gl_heightmap.c | 2 +- engine/gl/gl_hlmdl.c | 2 +- engine/gl/gl_model.c | 20 +- engine/gl/gl_model.h | 18 +- engine/gl/gl_rlight.c | 18 +- engine/gl/gl_shader.c | 2 +- engine/gl/ltface.c | 18 +- engine/qclib/qccmain.c | 2 +- engine/server/pr_cmds.c | 22 +- engine/server/pr_q1qvm.c | 2 + engine/server/sv_ccmds.c | 6 +- engine/server/sv_init.c | 8 +- engine/server/sv_main.c | 28 +- engine/server/sv_master.c | 67 +++- engine/server/sv_mvd.c | 2 +- engine/shaders/makevulkanblob.c | 2 +- engine/vk/vk_init.c | 6 +- fteqtv/httpsv.c | 2 +- fteqtv/qtv.h | 19 +- fteqtv/source.c | 2 +- plugins/jabber/jabberclient.c | 12 +- plugins/jabber/sift.c | 2 +- 59 files changed, 1970 insertions(+), 421 deletions(-) create mode 100644 engine/common/sha2.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 76fcc0dd..6a0f5ed5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -469,6 +469,7 @@ SET(FTE_COMMON_FILES engine/common/q3common.c engine/common/qvm.c engine/common/sha1.c + engine/common/sha2.c engine/common/translate.c engine/common/zone.c @@ -773,7 +774,7 @@ ELSE() ${FTE_CLIENT_FILES} ) SET_TARGET_PROPERTIES(fteqw PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_DEFINES};${FTE_REVISON}") - TARGET_LINK_LIBRARIES(fteqw ${FTE_LIBS} ) + TARGET_LINK_LIBRARIES(fteqw ${FTE_LIBS}) SET(INSTALLTARGS ${INSTALLTARGS} fteqw) ADD_EXECUTABLE(fteqw-sv diff --git a/engine/Makefile b/engine/Makefile index 57fe5474..8ad47305 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -859,6 +859,7 @@ COMMON_OBJS = \ huff.o \ md4.o \ sha1.o \ + sha2.o \ log.o \ net_chan.o \ net_wins.o \ diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 2ff19718..a55f7254 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1620,12 +1620,13 @@ void CL_UseIndepPhysics(qboolean allow) } else { + CL_AllowIndependantSendCmd(true); //shut it down. runningindepphys = false; //tell thread to exit gracefully - Sys_LockMutex(indeplock); Sys_WaitOnThread(indepthread); - Sys_UnlockMutex(indeplock); + indepthread = NULL; Sys_DestroyMutex(indeplock); + indeplock = NULL; } } #else diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 5c9026c9..0df94154 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1506,6 +1506,7 @@ void CL_Rcon_f (void) const unsigned char **tokens = alloca(sizeof(*tokens)*(4+Cmd_Argc()*2)); size_t *tokensizes = alloca(sizeof(*tokensizes)*(4+Cmd_Argc()*2)); int j, k; + void *ctx = alloca(hash_sha1.contextsize); for (j = 0; j < sizeof(time_t); j++) { //little-endian byte order, but big-endian nibble order. just screwed. for compat with ezquake. @@ -1523,9 +1524,11 @@ void CL_Rcon_f (void) tokens[4+j*2+0] = Cmd_Argv(i+j); tokens[4+j*2+1] = " "; } + hash_sha1.init(ctx); for (k = 0; k < 4+j*2; k++) - tokensizes[k] = strlen(tokens[k]); - digestsize = SHA1_m(digest, sizeof(digest), k, tokens, tokensizes); + hash_sha1.process(ctx, tokens[k], strlen(tokens[k])); + hash_sha1.terminate(digest, ctx); + digestsize = hash_sha1.digestsize; for (j = 0; j < digestsize; j++) { diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index ee006d6e..7238a8ca 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -4517,15 +4517,18 @@ static void CLQ2_ParseConfigString (void) } else if (i == Q2CS_MAPCHECKSUM) { - extern int map_checksum; int serverchecksum = atoi(s); + int mapchecksum = 0; - if (cl.worldmodel && (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)) + if (cl.worldmodel) { - // the Q2 client normally exits here, however for our purposes we might as well ignore it - if (map_checksum != serverchecksum) - Con_Printf(CON_WARNING "WARNING: Client checksum does not match server checksum (%i != %i)", map_checksum, serverchecksum); + if (cl.worldmodel->loadstate == MLS_LOADING) + COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); + mapchecksum = cl.worldmodel->checksum; } + // the Q2 client normally exits here, however for our purposes we might as well ignore it + if (mapchecksum != serverchecksum) + Con_Printf(CON_WARNING "WARNING: Client checksum does not match server checksum (%i != %i)", mapchecksum, serverchecksum); } } #endif diff --git a/engine/client/client.h b/engine/client/client.h index 9123eee1..5b7ae0f1 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -295,8 +295,9 @@ typedef struct //the light array works thusly: //dlights are allocated DL_LAST downwards to 0, static wlights are allocated DL_LAST+1 to MAX_RTLIGHTS. //thus to clear the dlights but not rtlights, set the first light to RTL_FIRST -#define DL_LAST (sizeof(unsigned int)*8-1) -#define RTL_FIRST (sizeof(unsigned int)*8) +#define dlightbitmask_t size_t +#define DL_LAST (sizeof(dlightbitmask_t)*8-1) +#define RTL_FIRST (sizeof(dlightbitmask_t)*8) #define LFLAG_NORMALMODE (1<<0) /*ppl with r_shadow_realtime_dlight*/ #define LFLAG_REALTIMEMODE (1<<1) /*ppl with r_shadow_realtime_world*/ @@ -1488,6 +1489,7 @@ qboolean CSQC_Accelerometer(float x, float y, float z); qboolean CSQC_Gyroscope(float x, float y, float z); int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float vol, float attenuation, float pitchmod, float timeofs, unsigned int flags); void CSQC_ParseEntities(void); +const char *CSQC_GetExtraFieldInfo(void *went, char *out, size_t outsize); void CSQC_ResetTrails(void); qboolean CSQC_DeltaPlayer(int playernum, player_state_t *state); diff --git a/engine/client/m_download.c b/engine/client/m_download.c index e67fba4e..a4ff1a7b 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -1,8 +1,16 @@ //copyright 'Spike', license gplv2+ //provides both a package manager and downloads menu. //FIXME: block downloads of exe/dll/so/etc if not an https url (even if inside zips). also block such files from package lists over http. + +//Note: for a while we didn't have strong hashes, nor signing, so we depended upon known-self-signed tls certificates to prove authenticity +//we now have sha256 hashes(and sizes) to ensure that the file we wanted hasn't been changed in transit. +//and we have signature info, to prove that the hash specified was released by a known authority. This means that we should now be able to download such things over http without worries (or at least that we can use an untrustworthy CA that's trusted by insecurity-mafia browsers). +//WARNING: paks/pk3s may still be installed without signatures, without allowing dlls/exes/etc to be installed. +//signaturedata+hashes can be generated with 'fteqw -privkey key.priv -pubkey key.pub -certhost MyAuthority -sign pathtofile', but Auth_GetKnownCertificate will need to be updated for any allowed authorities. + #include "quakedef.h" #include "shader.h" +#include "netinc.h" #ifdef PACKAGEMANAGER #if !defined(NOBUILTINMENUS) && !defined(SERVERONLY) @@ -63,6 +71,9 @@ extern cvar_t pm_downloads_url; #define DPF_PLUGIN (1u<<13) //this is a plugin package, with a dll #define DPF_TRUSTED (1u<<14) //flag used when parsing package lists. if not set then packages will be ignored if they are anything but paks/pk3s +#define DPF_SIGNATUREREJECTED (1u<<15) //signature is bad +#define DPF_SIGNATUREACCEPTED (1u<<16) //signature is good (required for dll/so/exe files) +#define DPF_SIGNATUREUNKNOWN (1u<<17) //signature is unknown #define DPF_MARKED (DPF_USERMARKED|DPF_AUTOMARKED) #define DPF_PRESENT (DPF_NATIVE|DPF_CACHED) @@ -117,6 +128,11 @@ typedef struct package_s { char *arch; char *qhash; + quint64_t filesize; //in bytes, as part of verifying the hash. + char *filesha1; + char *filesha512; + char *signature; + char *title; char *description; char *license; @@ -137,6 +153,7 @@ typedef struct package_s { enum { DEP_CONFLICT, //don't install if we have the named package installed. + DEP_REPLACE, //obsoletes the specified package (or just acts as a conflict marker for now). DEP_FILECONFLICT, //don't install if this file already exists. DEP_REQUIRE, //don't install unless we have the named package installed. DEP_RECOMMEND, //like depend, but uninstalling will not bubble. @@ -192,6 +209,7 @@ static int downloadablessequence; //bumped any time any package is purged static void PM_WriteInstalledPackages(void); static void PM_PreparePackageList(void); +static qboolean PM_SignatureOkay(package_t *p); static void PM_FreePackage(package_t *p) { @@ -252,13 +270,98 @@ static qboolean PM_PurgeOnDisable(package_t *p) //hashed packages can also be present and not enabled, but only if they're in the cache and not native if (*p->gamedir && p->qhash && (p->flags & DPF_PRESENT)) return false; - //FIXME: add basedir-plugins to the package manager so they can be enabled/disabled properly. - //if (p->arch) - // return false; //all other packages must be deleted to disable them return true; } +void PM_ValidateAuthenticity(package_t *p) +{ + qbyte hashdata[512]; + size_t hashsize = 0; + qbyte signdata[1024]; + size_t signsize = 0; + int r; + char authority[MAX_QPATH], *sig; + +#if 1 +#pragma message("Temporary code.") + //this is temporary code and should be removed once everything else has been fixed. + //ignore the signature (flag as accepted) for any packages with all mirrors on our own update site. + //we can get away with this because we enforce a known certificate for the download. + if (!COM_CheckParm("-notlstrust")) + { + conchar_t musite[256], *e; + char site[256]; + char *oldprefix = "http://fte."; + char *newprefix = "https://updates."; + int m; + e = COM_ParseFunString(CON_WHITEMASK, ENGINEWEBSITE, musite, sizeof(musite), false); + COM_DeFunString(musite, e, site, sizeof(site)-1, true, true); + if (!strncmp(site, oldprefix, strlen(oldprefix))) + { + memmove(site+strlen(newprefix), site+strlen(oldprefix), strlen(site)-strlen(oldprefix)+1); + memcpy(site, newprefix, strlen(newprefix)); + } + Q_strncatz(site, "/", sizeof(site)); + for (m = 0; m < countof(p->mirror); m++) + { + if (p->mirror[m] && strncmp(p->mirror[m], site, strlen(site))) + break; //some other host + } + if (m == countof(p->mirror)) + { + p->flags |= DPF_SIGNATUREACCEPTED; + return; + } + } +#endif + + *authority = 0; + if (!p->signature) + r = VH_AUTHORITY_UNKNOWN; + else if (!p->filesha512) + r = VH_INCORRECT; + else + { + sig = strchr(p->signature, ':'); + if (sig && sig-p->signaturesignature, sig-p->signature); + authority[sig-p->signature] = 0; + sig++; + } + else + sig = p->signature; + hashsize = Base16_DecodeBlock(p->filesha512, hashdata, sizeof(hashdata)); + signsize = Base64_DecodeBlock(sig, NULL, signdata, sizeof(signdata)); + r = VH_UNSUPPORTED;//preliminary + } + + (void)signsize; + (void)hashsize; + + //try and get one of our providers to verify it... +#ifdef HAVE_WINSSPI + if (r == VH_UNSUPPORTED) + r = SSPI_VerifyHash(hashdata, hashsize, authority, signdata, signsize); +#endif +#ifdef HAVE_GNUTLS + if (r == VH_UNSUPPORTED) + r = GNUTLS_VerifyHash(hashdata, hashsize, authority, signdata, signsize); +#endif +#ifdef HAVE_OPENSSL + if (r == VH_UNSUPPORTED) + r = OSSL_VerifyHash(hashdata, hashsize, authority, signdata, signsize); +#endif + + if (r == VH_CORRECT) + p->flags |= DPF_SIGNATUREACCEPTED; + else if (r == VH_INCORRECT) + p->flags |= DPF_SIGNATUREREJECTED; + else if (p->signature) + p->flags |= DPF_SIGNATUREUNKNOWN; +} + //checks the status of each package static void PM_ValidatePackage(package_t *p) { @@ -952,6 +1055,8 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u PM_AddDep(p, DEP_REQUIRE, val); else if (!strcmp(key, "conflict")) PM_AddDep(p, DEP_CONFLICT, val); + else if (!strcmp(key, "replace")) + PM_AddDep(p, DEP_REPLACE, val); else if (!strcmp(key, "fileconflict")) PM_AddDep(p, DEP_FILECONFLICT, val); else if (!strcmp(key, "recommend")) @@ -975,6 +1080,14 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u else fsroot = FS_ROOT; } + else if (!strcmp(key, "dlsize")) + p->filesize = strtoull(val, NULL, 0); + else if (!strcmp(key, "sha1")) + Z_StrDupPtr(&p->filesha1, val); + else if (!strcmp(key, "sha512")) + Z_StrDupPtr(&p->filesha512, val); + else if (!strcmp(key, "sign")) + Z_StrDupPtr(&p->signature, val); else { Con_DPrintf("Unknown package property\n"); @@ -1051,6 +1164,9 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u p->mirror[m] = Z_StrDup(va("%s%s%s", mirror[m], relurl, ext)); } } + + PM_ValidateAuthenticity(p); + Z_Free(ver); Z_Free(file); Z_Free(url); @@ -1462,19 +1578,20 @@ static void PM_UnmarkPackage(package_t *package, unsigned int markflag) } //just flags, doesn't install -static void PM_MarkPackage(package_t *package, unsigned int markflag) +//returns true if it was marked (or already enabled etc), false if we're not allowed. +static qboolean PM_MarkPackage(package_t *package, unsigned int markflag) { package_t *o; struct packagedep_s *dep, *dep2; qboolean replacing = false; if (pkg_updating) - return; + return false; if (package->flags & DPF_MARKED) { package->flags |= markflag; - return; //looks like its already picked. marking it again will do no harm. + return true; //looks like its already picked. marking it again will do no harm. } #ifndef WEBCLIENT @@ -1482,10 +1599,13 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag) if (!(package->flags & DPF_PRESENT)) { //though we can at least unmark it for deletion... package->flags &= ~DPF_PURGE; - return; + return false; } #endif + if (!PM_SignatureOkay(package)) + return false; + //any file-conflicts prevent the package from being installable. //this is mostly for pak1.pak for (dep = package->deps; dep; dep = dep->next) @@ -1498,7 +1618,7 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag) else n = dep->name; if (PM_CheckFile(n, package->fsroot)) - return; + return false; } } @@ -1545,7 +1665,7 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag) //if we are replacing an existing one, then dependancies are already settled (only because we don't do version deps) if (replacing) - return; + return true; //satisfy our dependancies. for (dep = package->deps; dep; dep = dep->next) @@ -1567,7 +1687,7 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag) Con_DPrintf("Couldn't find dependancy \"%s\"\n", dep->name); } } - if (dep->dtype == DEP_CONFLICT) + if (dep->dtype == DEP_CONFLICT || dep->dtype == DEP_REPLACE) { for (;;) { @@ -1583,10 +1703,11 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag) for (o = availablepackages; o; o = o->next) { for (dep = o->deps; dep; dep = dep->next) - if (dep->dtype == DEP_CONFLICT) + if (dep->dtype == DEP_CONFLICT || dep->dtype == DEP_REPLACE) if (!strcmp(dep->name, package->name)) PM_UnmarkPackage(o, DPF_MARKED); } + return true; } static qboolean PM_NameIsInStrings(const char *strings, const char *match) @@ -2086,6 +2207,11 @@ static void PM_WriteInstalledPackages(void) Q_strncatz(buf, " ", sizeof(buf)); COM_QuotedConcat(va("preview=%s", p->previewimage), buf, sizeof(buf)); } + if (p->filesize) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("filesize=%s", p->previewimage), buf, sizeof(buf)); + } if (p->fsroot == FS_BINARYPATH) { @@ -2110,6 +2236,11 @@ static void PM_WriteInstalledPackages(void) Q_strncatz(buf, " ", sizeof(buf)); COM_QuotedConcat(va("conflict=%s", dep->name), buf, sizeof(buf)); } + else if (dep->dtype == DEP_REPLACE) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("replace=%s", dep->name), buf, sizeof(buf)); + } else if (dep->dtype == DEP_FILECONFLICT) { Q_strncatz(buf, " ", sizeof(buf)); @@ -2224,11 +2355,11 @@ static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, n = fname; if (FS_WriteFile(n, f, loc.len, p->fsroot)) p->flags |= DPF_NATIVE|DPF_ENABLED; - free(f); //keep track of the installed files, so we can delete them properly after. PM_AddDep(p, DEP_FILE, fname); } + free(f); } return 1; } @@ -2250,9 +2381,12 @@ static void PM_Download_Got(struct dl_download *dl) if (dl->file) { - VFS_CLOSE(dl->file); + if (!VFS_CLOSE(dl->file)) + successful = false; dl->file = NULL; } + else + successful = false; if (p) { @@ -2434,6 +2568,111 @@ static char *PM_GetTempName(package_t *p) Z_Free(ts); return Z_StrDup(destname); } + + +typedef struct { + vfsfile_t pub; + vfsfile_t *f; + hashfunc_t *hashfunc; + qofs_t sz; + qofs_t needsize; + qboolean fail; + qbyte need[256]; + qbyte ctx[1]; + char *fname; +} hashfile_t; +static int QDECL SHA1File_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite) +{ + hashfile_t *f = (hashfile_t*)file; + f->hashfunc->process(&f->ctx, buffer, bytestowrite); + if (bytestowrite != VFS_WRITE(f->f, buffer, bytestowrite)) + f->fail = true; //something went wrong. + if (f->fail) + return -1; //error! abort! fail! give up! + f->sz += bytestowrite; + return bytestowrite; +} +static void QDECL SHA1File_Flush (struct vfsfile_s *file) +{ + hashfile_t *f = (hashfile_t*)file; + VFS_FLUSH(f->f); +} +static qboolean QDECL SHA1File_Close (struct vfsfile_s *file) +{ + qbyte digest[256]; + hashfile_t *f = (hashfile_t*)file; + if (!VFS_CLOSE(f->f)) + f->fail = true; //something went wrong. + + f->hashfunc->terminate(digest, &f->ctx); + if (f->fail) + Con_Printf("Filesystem problems downloading %s\n", f->fname); //don't error if we failed on actual disk problems + else if (f->sz != f->needsize) + { + Con_Printf("Download truncated: %s\n", f->fname); //don't error if we failed on actual disk problems + f->fail = true; + } + else if (memcmp(digest, f->need, f->hashfunc->digestsize)) + { + Con_Printf("Invalid hash for downloaded file %s, try again later?\n", f->fname); + f->fail = true; + } + + return !f->fail; //true if all okay! +} +static vfsfile_t *FS_Sha1_ValidateWrites(vfsfile_t *f, const char *fname, qofs_t needsize, hashfunc_t *hashfunc, const char *hash) +{ //wraps a writable file with a layer that'll cause failures when the hash differs from what we expect. + if (f) + { + hashfile_t *n = Z_Malloc(sizeof(*n) + hashfunc->contextsize + strlen(fname)); + n->pub.WriteBytes = SHA1File_WriteBytes; + n->pub.Flush = SHA1File_Flush; + n->pub.Close = SHA1File_Close; + n->pub.seekstyle = SS_UNSEEKABLE; + n->f = f; + n->hashfunc = hashfunc; + n->fname = n->ctx+hashfunc->contextsize; + strcpy(n->fname, fname); + n->needsize = needsize; + Base16_DecodeBlock(hash, n->need, sizeof(n->need)); + n->fail = false; + f = &n->pub; + + n->hashfunc->init(&n->ctx); + } + return f; +} + +static qboolean PM_SignatureOkay(package_t *p) +{ + struct packagedep_s *dep; + char ext[MAX_QPATH]; + +// if (p->flags & (DPF_SIGNATUREREJECTED|DPF_SIGNATUREUNKNOWN)) //the sign key didn't match its sha512 hash +// return false; //just block it entirely. + if (p->flags & DPF_SIGNATUREACCEPTED) //sign value is present and correct + return true; //go for it. + if (p->flags & DPF_PRESENT) + return true; //we don't know where it came from, but someone manually installed it... + + //packages without a signature are only allowed under some limited conditions. + //basically we only allow meta packages, pk3s, and paks. + + if (p->extract == EXTRACT_ZIP) + return false; //extracting files is bad (there might be some weird .pif or whatever file in there, don't risk it) + for (dep = p->deps; dep; dep = dep->next) + { + if (dep->dtype != DEP_FILE) + continue; + + COM_FileExtension(dep->name, ext, sizeof(ext)); + if ((!stricmp(ext, "pak") || !stricmp(ext, "pk3")) && p->qhash) + ; + else + return false; + } + return true; +} #endif /*static void PM_AddDownloadedPackage(const char *filename) @@ -2545,6 +2784,11 @@ static void PM_StartADownload(void) continue; } + if (!PM_SignatureOkay(p) || (qofs_t)p->filesize != p->filesize) + { + p->flags &= ~DPF_MARKED; //refusing to do it. + continue; + } temp = PM_GetTempName(p); @@ -2584,6 +2828,11 @@ static void PM_StartADownload(void) continue; } + if (p->filesha512 && tmpfile) + tmpfile = FS_Sha1_ValidateWrites(tmpfile, p->name, p->filesize, &hash_sha512, p->filesha512); + else if (p->filesha1 && tmpfile) + tmpfile = FS_Sha1_ValidateWrites(tmpfile, p->name, p->filesize, &hash_sha1, p->filesha1); + if (tmpfile) { p->download = HTTP_CL_Get(mirror, NULL, PM_Download_Got); @@ -2999,6 +3248,7 @@ void PM_Command_f(void) { for (p = availablepackages; p; p=p->next) { + char quoted[8192]; const char *status; char *markup; if ((p->flags & DPF_HIDDEN) && !(p->flags & (DPF_MARKED|DPF_ENABLED|DPF_PURGE|DPF_CACHED))) @@ -3035,7 +3285,13 @@ void PM_Command_f(void) else status = ""; - Con_Printf(" ^["S_COLOR_GRAY"%s%s%s%s%s^] %s"S_COLOR_GRAY" %s (%s%s)\n", p->category?p->category:"", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":""); + Con_Printf(" ^["S_COLOR_GRAY"%s%s%s%s%s^] %s"S_COLOR_GRAY" %s (%s%s)", p->category?p->category:"", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":""); + + if (!(p->flags&DPF_MARKED) && p == PM_FindPackage(p->name)) + Con_Printf(" ^[[Add]\\type\\pkg add %s;pkg apply^]", COM_QuotedString(p->name, quoted, sizeof(quoted), false)); + if ((p->flags&DPF_MARKED) && p == PM_MarkedPackage(p->name, DPF_MARKED)) + Con_Printf(" ^[[Remove]\\type\\pkg rem %s;pkg apply^]", COM_QuotedString(p->name, quoted, sizeof(quoted), false)); + Con_Printf("\n"); } Con_Printf("\n"); } @@ -3401,6 +3657,8 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) if (!PM_CheckPackageFeatures(p)) Draw_FunStringWidth(0, y, "!", x+8, true, true); + if (!PM_SignatureOkay(p)) + Draw_FunStringWidth(0, y, "^b!", x+8, true, true); // if (!(p->flags & (DPF_ENABLED|DPF_MARKED|DPF_PRESENT)) // continue; @@ -3616,11 +3874,25 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix) slash = strchr(p->category+prefixlen, '/'); if (!slash) { - char *desc; + char *head; + char *desc = p->description; if (p->author || p->license || p->website) - desc = va("^aauthor: ^a%s\n^alicense: ^a%s\n^awebsite: ^a%s\n%s", p->author?p->author:"^hUnknown^h", p->license?p->license:"^hUnknown^h", p->website?p->website:"^hUnknown^h", p->description); + head = va("^aauthor:^U00A0^a%s\n^alicense:^U00A0^a%s\n^awebsite:^U00A0^a%s\n", p->author?p->author:"^hUnknown^h", p->license?p->license:"^hUnknown^h", p->website?p->website:"^hUnknown^h"); else - desc = p->description; + head = NULL; + if (p->filesize) + { + if (!head) + head = ""; + if (p->filesize < 1024) + head = va("%s^asize:^U00A0^a%.4f bytes\n", head, (double)p->filesize); + else if (p->filesize < 1024*1024) + head = va("%s^asize:^U00A0^a%.4f KB\n", head, (p->filesize/(1024.0))); + else if (p->filesize < 1024*1024*1024) + head = va("%s^asize:^U00A0^a%.4f MB\n", head, (p->filesize/(1024.0*1024))); + else + head = va("%s^asize:^U00A0^a%.4f GB\n", head, (p->filesize/(1024.0*1024*1024))); + } for (dep = p->deps; dep; dep = dep->next) { @@ -3630,12 +3902,28 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix) if (!PM_CheckFeature(dep->name, &featname, &enablecmd)) { if (enablecmd) - desc = va("^aDisabled: ^a%s\n%s", featname, desc); + head = va("^aDisabled: ^a%s\n%s", featname, head?head:""); else - desc = va("^aUnavailable: ^a%s\n%s", featname, desc); + head = va("^aUnavailable: ^a%s\n%s", featname, head?head:""); } } } + if (!PM_SignatureOkay(p)) + { + if (!p->signature) + head = va(CON_ERROR"Signature missing"CON_DEFAULT"\n%s", head?head:""); //some idiot forgot to include a signature + else if (p->flags & DPF_SIGNATUREREJECTED) + head = va(CON_ERROR"Signature invalid"CON_DEFAULT"\n%s", head?head:""); //some idiot got the wrong auth/sig/hash + else if (p->flags & DPF_SIGNATUREUNKNOWN) + head = va(CON_ERROR"Signature is not trusted"CON_DEFAULT"\n%s", head?head:""); //clientside permission. + else + head = va(CON_ERROR"Unable to verify signature"CON_DEFAULT"\n%s", head?head:""); //clientside problem. + } + + if (head && desc) + desc = va("%s\n%s", head, desc); + else if (head) + desc = head; c = MC_AddCustom(m, 0, y, p, downloadablessequence, desc); c->draw = MD_Draw; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index c3ba7b98..21ca334a 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -2830,10 +2830,10 @@ void M_Menu_Video_f (void) }; static const char *srgbopts[] = { - "Non-Linear", - "sRGB-Aware (PBR)", - "Linear (HDR)", - "Linearised", //-1 + "Non-Linear", //0 (legacy buggy linear->srgb non-transforms) + "sRGB-Aware", //1 (linear->srgb transforms) + "Linear (HDR)", //2 (try to use a float framebuffer, otherwise fall back on srgb framebuffer) + "Linearised", //-1 NULL }; static const char *srgbvalues[] = { "0", "1", "2", "-1", NULL}; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 54df7fef..50820523 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -608,9 +608,6 @@ static void CS_CheckVelocity(csqcedict_t *ent) - - - static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t *fte_restrict out) { //FTE_CSQC_HALFLIFE_MODELS @@ -1052,6 +1049,53 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *fte_restrict in, entity_t *ft return true; } +const char *CSQC_GetExtraFieldInfo(void *went, char *out, size_t outsize) +{ + csqcedict_t *ent = went; + char *r = out; + char *e = out+outsize; + int i; + skinfile_t *sk = Mod_LookupSkin((ent->skinobject<0)?-ent->skinobject:ent->skinobject); + if (sk) + { + Q_snprintfz(out, e-out, "skin %s\nrefs %i\n", sk->skinname, sk->refcount); + out+=strlen(out); + for (i = 0; i < sk->nummappings; i++) + { + Q_snprintfz(out, e-out, "replace \"%s\" \"%s\"\n", sk->mappings[i].surface, sk->mappings[i].shader?sk->mappings[i].shader->name:"NULL SHADER"); + out+=strlen(out); + } + for (i = 0; i < MAX_GEOMSETS; i++) + { + if (sk->geomset[i]) + { + Q_snprintfz(out, e-out, "geomset %i %i\n", i, sk->geomset[i]); + out+=strlen(out); + } + } +#ifdef QWSKINS + if (*sk->qwskinname) + { + Q_snprintfz(out, e-out, "qwskin %s\n", sk->qwskinname); + out+=strlen(out); + } + if (sk->q1upper != Q1UNSPECIFIED) + { + Q_snprintfz(out, e-out, "q1upper %#x\n", sk->q1upper); + out+=strlen(out); + } + if (sk->q1lower != Q1UNSPECIFIED) + { + Q_snprintfz(out, e-out, "q1lower %#x\n", sk->q1lower); + out+=strlen(out); + } +#endif + + return r; + } + return r==out?NULL:r; +} + static void QCBUILTIN PF_cs_makestatic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { //still does a remove. csqcedict_t *in = (void*)G_EDICT(prinst, OFS_PARM0); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 7eba0e07..cf2ee6ed 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -325,9 +325,9 @@ void Surf_LessenStains(void) R_AddDynamicLights =============== */ -static void Surf_AddDynamicLights (msurface_t *surf) +static void Surf_AddDynamicLights_Lum (msurface_t *surf) { - int lnum; + size_t lnum; int sd, td; float dist, rad, minlight; vec3_t impact, local; @@ -344,7 +344,7 @@ static void Surf_AddDynamicLights (msurface_t *surf) for (lnum=rtlights_first; lnumdlightbits & (1<dlightbits & ((dlightbitmask_t)1u<dlightbits & (1<dlightbits & ((dlightbitmask_t)1u<dlightbits & (1<dlightbits & ((dlightbitmask_t)1u<samples - wmodel->lightdata)/4)*3 + wmodel->deluxdata; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; for (i=0 ; isamples - wmodel->lightdata + wmodel->deluxdata; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; for (i=0 ; isamples - wmodel->lightdata)*3 + wmodel->deluxdata; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; for (i=0 ; i= 0.5) { //positive exponent - while (m >= (1<<(e)) && e < 30-15) //don't do nans. + while (m >= (1u<<(e)) && e < 30-15) //don't do nans. e++; } else { //negative exponent... - while (m < 1/(1<<-e) && e > -15) //don't do denormals. + while (m < 1/(1u<<-e) && e > -15) //don't do denormals. e--; } scale = pow(2, e-9); - scale *= (1< 15) m = 0; //infinity instead of a nan else - m = (u.u&((1<<23)-1))>>13; + m = (u.u&((1u<<23)-1))>>13; return ((e+15)<<10) | m; } static void Surf_PackRGB16F(void *result, int r, int g, int b, int one) @@ -830,10 +832,10 @@ static void Surf_PackRGB16F(void *result, int r, int g, int b, int one) ((unsigned short*)result)[0] = Surf_GenHalf(r / (float)one); ((unsigned short*)result)[1] = Surf_GenHalf(g / (float)one); ((unsigned short*)result)[2] = Surf_GenHalf(b / (float)one); - ((unsigned short*)result)[3] = /*Surf_GenHalf(1.0);*/0x0f<<10; //a standard ieee float should have all but the lead bit set of its exponent, and its mantissa 0. + ((unsigned short*)result)[3] = /*Surf_GenHalf(1.0);*/0x0fu<<10; //a standard ieee float should have all but the lead bit set of its exponent, and its mantissa 0. #endif } -static void Surf_PackRGB32F(void *result, int r, int g, int b, int one) +static void Surf_PackRGBX32F(void *result, int r, int g, int b, int one) { ((float*)result)[0] = r/(float)one; ((float*)result)[1] = g/(float)one; @@ -886,7 +888,7 @@ static void Surf_StoreLightmap_RGB(qbyte *dest, unsigned int *bl, int smax, int b *= 1023.0/m; } - *(unsigned int*)dest = (3<<30) | ((b&0x3ff)<<20) | ((g&0x3ff)<<10) | (r&0x3ff); + *(unsigned int*)dest = (3u<<30) | ((b&0x3ff)<<20) | ((g&0x3ff)<<10) | (r&0x3ff); dest += 4; } if (stainsrc) @@ -944,6 +946,7 @@ static void Surf_StoreLightmap_RGB(qbyte *dest, unsigned int *bl, int smax, int } break; case PTI_RGBA32F: + shift = 1u<<(shift+8); stride = (lm->width-smax)<<4; for (i=0 ; i> 8; } - Surf_PackRGB32F(dest, r,g,b,1<<(shift+8)); + Surf_PackRGBX32F(dest, r,g,b,shift); dest += sizeof(float)*4; } if (stainsrc) @@ -1312,7 +1315,7 @@ static void Surf_StoreLightmap_RGB(qbyte *dest, unsigned int *bl, int smax, int break; } } -static void Surf_StoreLightmap_Grey(qbyte *dest, unsigned int *bl, int smax, int tmax, unsigned int shift, stmap *stainsrc, unsigned int lmwidth) +static void Surf_StoreLightmap_Lum(qbyte *dest, unsigned int *bl, int smax, int tmax, unsigned int shift, stmap *stainsrc, unsigned int lmwidth) { int t; unsigned int i, j; @@ -1414,7 +1417,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map t = (-1-ambient)*255; for (i=0 ; icached_light[maps] = -1-ambient; surf->cached_colour[maps] = 0xff; @@ -1461,7 +1464,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map switch(currentmodel->lightmaps.fmt) { case LM_E5BGR9: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; @@ -1481,7 +1484,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map } break; case LM_RGB8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; @@ -1502,7 +1505,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map break; case LM_L8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction @@ -1529,7 +1532,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map // add all the dynamic lights if (surf->dlightframe == r_framecount) - Surf_AddDynamicLightsColours (surf); + Surf_AddDynamicLights_RGB (surf); Surf_StoreLightmap_RGB(dest, blocklights, smax, tmax, shift, stainsrc, lm); } @@ -1541,7 +1544,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map t = (-1-ambient)*255; for (i=0 ; icached_light[maps] = -1-ambient; surf->cached_colour[maps] = 0xff; @@ -1581,7 +1584,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map switch(currentmodel->lightmaps.fmt) { case LM_E5BGR9: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction @@ -1595,7 +1598,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map } break; case LM_RGB8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction @@ -1606,7 +1609,7 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map } break; case LM_L8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction @@ -1620,10 +1623,10 @@ static void Surf_BuildLightMap (model_t *currentmodel, msurface_t *surf, int map } // add all the dynamic lights if (surf->dlightframe == r_framecount) - Surf_AddDynamicLights (surf); + Surf_AddDynamicLights_Lum (surf); } - Surf_StoreLightmap_Grey(dest, blocklights, smax, tmax, shift, stainsrc, lm->width); + Surf_StoreLightmap_Lum(dest, blocklights, smax, tmax, shift, stainsrc, lm->width); } } @@ -1682,44 +1685,33 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh { // set to full bright if no light data if (ambient < 0) - { + { //abslight for hexen2 t = (-1-ambient)*255; for (i=0 ; icached_light[maps] = -1-ambient; surf->cached_colour[maps] = 0xff; } } - else if (r_fullbright.value>0) //not qw - { + else if (r_fullbright.value>0) + { //fullbright cheat for (i=0 ; ilightdata) - { - /*fullbright if map is not lit. but not overbright*/ + { /*fullbright if map is not lit. but not overbright*/ for (i=0 ; isamples) - { - /*no samples, but map is otherwise lit = pure black*/ - for (i=0 ; icached_light[0] = 0; - surf->cached_colour[0] = 0; - } else { // clear to no light @@ -1758,7 +1750,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh else switch(cl.worldmodel->lightmaps.fmt) { case LM_E5BGR9: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; @@ -1768,7 +1760,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh for (i=0 ; i>27]*(1<<7); + float e = rgb9e5tab[l>>27]*(1u<<7); blocklights[i*3+0] += scalergb[0] * e * ((l>> 0)&0x1ff); blocklights[i*3+1] += scalergb[1] * e * ((l>> 9)&0x1ff); blocklights[i*3+2] += scalergb[2] * e * ((l>>18)&0x1ff); @@ -1778,7 +1770,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh } break; case LM_RGB8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; @@ -1799,7 +1791,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh break; case LM_L8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { surf->cached_light[maps] = scale = d_lightstylevalue[surf->styles[maps]]; // 8.8 fraction @@ -1846,16 +1838,11 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh surf->cached_light[0] = d_lightstylevalue[0]; surf->cached_colour[0] = cl_lightstyle[0].colourkey; } - else if (!surf->samples) - { - for (i=0 ; ilightmaps.fmt) { case LM_E5BGR9: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - for (i=0 ; i>0)&0x1ff),((lm>>9)&0x1ff),((lm>>18)&0x1ff)) * scale * (rgb9e5tab[lm>>27]*(1<<7)); - } + if (scale) + for (i=0 ; i>0)&0x1ff),((lm>>9)&0x1ff),((lm>>18)&0x1ff)) * scale * (rgb9e5tab[lm>>27]*(1<<7)); + } lightmap += size*4; // skip to next lightmap } break; case LM_RGB8: - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - for (i=0 ; istyles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; surf->cached_light[maps] = scale; // 8.8 fraction surf->cached_colour[maps] = cl_lightstyle[surf->styles[maps]].colourkey; - for (i=0 ; iwidth); + Surf_StoreLightmap_Lum(dest, blocklights, smax, tmax, shift, stainsrc, lm->width); } //make sure we flag the output rect properly. @@ -1965,7 +1955,7 @@ void Surf_RenderDynamicLightmaps (msurface_t *fa) } else { - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && fa->styles[maps] != INVALID_LIGHTSTYLE ; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && fa->styles[maps] != INVALID_LIGHTSTYLE ; maps++) if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] || cl_lightstyle[fa->styles[maps]].colourkey != fa->cached_colour[maps]) @@ -2008,7 +1998,7 @@ static void Surf_RenderDynamicLightmaps_Worker (model_t *wmodel, msurface_t *fa, } else { - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && fa->styles[maps] != INVALID_LIGHTSTYLE ; + for (maps = 0 ; maps < MAXCPULIGHTMAPS && fa->styles[maps] != INVALID_LIGHTSTYLE ; maps++) if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] || cl_lightstyle[fa->styles[maps]].colourkey != fa->cached_colour[maps]) diff --git a/engine/client/render.h b/engine/client/render.h index aaf4a123..13a0a40f 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -129,7 +129,7 @@ typedef struct entity_s // only used for static objects // int dlightframe; // dynamic lighting -// int dlightbits; +// dlightbitmask_t dlightbits; // FIXME: could turn these into a union // int trivial_accept; diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 403318ab..4d370a18 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -683,11 +683,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat qboolean srcrel; if (chnum >= oali->max_sources) - { - size_t oc = oali->max_sources; Z_ReallocElements((void**)&oali->source, &oali->max_sources, chnum+1+64, sizeof(*oali->source)); - memset(oali->source+oc, 0, sizeof(*oali->source)*(oali->max_sources-oc)); - } //alcMakeContextCurrent @@ -696,7 +692,6 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat sfx = NULL; #endif - src = oali->source[chnum].handle; if (!oali->source[chnum].allocated) { //not currently playing. be prepared to create one @@ -722,58 +717,54 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat oali->source[chnum].allocated = true; schanged |= CUR_EVERYTHING; //should normally be true anyway, but hey } + else + src = oali->source[chnum].handle; PrintALError("pre start sound"); - if ((schanged&CUR_SOUNDCHANGE) && src) + if (schanged&CUR_SOUNDCHANGE) palSourceStop(src); //reclaim any queued buffers - if (src) + palGetSourcei(src, AL_SOURCE_TYPE, &buf); + if (buf == AL_STREAMING) { - palGetSourcei(src, AL_SOURCE_TYPE, &buf); - if (buf == AL_STREAMING) + for(;;) { - for(;;) - { - palGetSourcei(src, AL_BUFFERS_PROCESSED, &buf); - if (!buf) - break; - palSourceUnqueueBuffers(src, 1, &buf); - palDeleteBuffers(1, &buf); - } + palGetSourcei(src, AL_BUFFERS_PROCESSED, &buf); + if (!buf) + break; + palSourceUnqueueBuffers(src, 1, &buf); + palDeleteBuffers(1, &buf); } - else if (!schanged && sfx) //if we don't figure out when they've finished, they'll not get replaced properly. + } + else if (!schanged && sfx) //if we don't figure out when they've finished, they'll not get replaced properly. + { + palGetSourcei(src, AL_SOURCE_STATE, &buf); + if (buf != AL_PLAYING) { - palGetSourcei(src, AL_SOURCE_STATE, &buf); - if (buf != AL_PLAYING) - { - schanged |= CUR_EVERYTHING; - if(sfx->loopstart != -1) - chan->pos = sfx->loopstart<flags & CF_FORCELOOP) - chan->pos = 0; - else - sfx = chan->sfx = NULL; - } + schanged |= CUR_EVERYTHING; + if(sfx->loopstart != -1) + chan->pos = sfx->loopstart<flags & CF_FORCELOOP) + chan->pos = 0; + else + sfx = chan->sfx = NULL; } } /*just wanted to stop it?*/ if (!sfx) { - if (src) - { #ifdef FTE_TARGET_WEB - //emscripten's webaudio wrapper spams error messages after alDeleteSources has been called, if the context isn't also killed. - if (!schanged) - palSourceStop(src); + //emscripten's webaudio wrapper spams error messages after alDeleteSources has been called, if the context isn't also killed. + if (!schanged) + palSourceStop(src); #else - palDeleteSources(1, &src); - oali->source[chnum].handle = 0; - oali->source[chnum].allocated = false; + palDeleteSources(1, &src); + oali->source[chnum].handle = 0; + oali->source[chnum].allocated = false; #endif - } return; } @@ -791,11 +782,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat int sndnum = sfx-known_sfx; int buf; if (sndnum >= oali->max_sounds) - { - size_t oc = oali->max_sounds; Z_ReallocElements((void**)&oali->sounds, &oali->max_sounds, sndnum+1+64, sizeof(*oali->sounds)); - memset(oali->sounds+oc, 0, sizeof(*oali->sounds)*(oali->max_sounds-oc)); - } buf = oali->sounds[sndnum].buffer; if (!oali->sounds[sndnum].allocated || stream) { @@ -852,8 +839,8 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat { //build a buffer with it and queue it up. //buffer will be purged later on when its unqueued - OpenAL_LoadCache(oali, &buf, &sbuf, max(1,cvolume)); - palSourceQueueBuffers(src, 1, &buf); + if (OpenAL_LoadCache(oali, &buf, &sbuf, max(1,cvolume))) + palSourceQueueBuffers(src, 1, &buf); } else { //decoder isn't ready yet, but didn't signal an error/eof. queue a little silence, because that's better than constant micro stutters @@ -864,8 +851,8 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat silence.data = NULL; silence.length = 0.1 * silence.speed; silence.soundoffset = 0; - OpenAL_LoadCache(oali, &buf, &silence, 1); - palSourceQueueBuffers(src, 1, &buf); + if (OpenAL_LoadCache(oali, &buf, &silence, 1)) + palSourceQueueBuffers(src, 1, &buf); } queuedbufs++; @@ -893,8 +880,8 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat silence.data = NULL; silence.length = 0.1 * silence.speed; silence.soundoffset = 0; - OpenAL_LoadCache(oali, &buf, &silence, 1); - palSourceQueueBuffers(src, 1, &buf); + if (OpenAL_LoadCache(oali, &buf, &silence, 1)) + palSourceQueueBuffers(src, 1, &buf); queuedbufs++; } } diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index fa028524..ba470ede 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -62,6 +62,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "quakedef.h" +#include "netinc.h" #undef malloc @@ -946,6 +947,46 @@ char *Sys_ConsoleInput(void) return NULL; } +#ifdef HAVE_GNUTLS +static void DoSign(const char *fname) +{ + qbyte digest[1024]; + qbyte signature[2048]; + qbyte base64[2048*4]; + int sigsize; + vfsfile_t *f; + const char *auth = "Unknown"; + int i = COM_CheckParm("-certhost"); + if (i) + auth = com_argv[i+1]; + + f = FS_OpenVFS(fname, "rb", FS_SYSTEM); + if (f) + { + hashfunc_t *h = &hash_sha512; + size_t l, ts = 0; + void *ctx = alloca(h->contextsize); + qbyte data[65536*16]; + h->init(ctx); + while ((l=VFS_READ(f, data, sizeof(data)))>0) + { + h->process(ctx, data, l); + ts += l; + } + h->terminate(digest, ctx); + VFS_CLOSE(f); + printf(" \\\"dlsize=%zu\\\"", ts); + + Base16_EncodeBlock(digest, h->digestsize, base64, sizeof(base64)); + printf(" \\\"sha512=%s\\\"", base64); + + sigsize = GNUTLS_GenerateSignature(digest, h->digestsize, signature, sizeof(signature)); + Base64_EncodeBlock(signature, sigsize, base64, sizeof(base64)); + printf(" \\\"sign=%s:%s\\\"\n", auth, base64); + } +} +#endif + #ifdef _POSIX_C_SOURCE static void SigCont(int code) { @@ -1029,15 +1070,19 @@ int main (int c, const char **v) memset(bindir, 0, sizeof(bindir)); //readlink does NOT null terminate, apparently. #ifdef __linux__ //attempt to figure out where the exe is located - if (readlink("/proc/self/exe", bindir, sizeof(bindir)-1) > 0) + i = readlink("/proc/self/exe", bindir, sizeof(bindir)-1); + if (i > 0) { + bindir[i] = 0; *COM_SkipPath(bindir) = 0; parms.binarydir = bindir; } /*#elif defined(__bsd__) //attempt to figure out where the exe is located - if (readlink("/proc/self/file", bindir, sizeof(bindir)-1) > 0) + i = readlink("/proc/self/file", bindir, sizeof(bindir)-1); + if (i > 0) { + bindir[i] = 0; *COM_SkipPath(bindir) = 0; parms.binarydir = bindir; } @@ -1066,6 +1111,22 @@ int main (int c, const char **v) if (COM_CheckParm("-nostdout")) nostdout = 1; +#ifdef HAVE_GNUTLS + //fteqw -privcert privcert.key -pubcert pubcert.key -sign binaryfile.pk3 + i = COM_CheckParm("-sign"); + if (i) + { + //init some useless crap + host_parms = parms; + Cvar_Init(); + Memory_Init (); + COM_Init (); + + DoSign(com_argv[i+1]); + return EXIT_SUCCESS; + } +#endif + if (parms.binarydir) Sys_Printf("Binary is located at \"%s\"\n", bindir); @@ -1088,7 +1149,6 @@ int main (int c, const char **v) } #endif - Host_Init(&parms); for (i = 1; i < parms.argc; i++) @@ -1230,4 +1290,3 @@ qboolean Sys_RunInstaller(void) return false; } #endif - diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index d6cea765..2dbfa67a 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -2883,15 +2883,18 @@ qboolean Sys_EngineMayUpdate(void) { char *e; - //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. - if (!strcmp(SVNREVISIONSTR, "-")) - return false; + if (!COM_CheckParm("-allowupdate")) + { + //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. + if (!strcmp(SVNREVISIONSTR, "-")) + return false; - //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified. - //either way, its bad and autoupdates when we don't know what we're updating from is a bad idea. - strtoul(SVNREVISIONSTR, &e, 10); - if (!*SVNREVISIONSTR || *e) - return false; + //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified. + //either way, its bad and autoupdates when we don't know what we're updating from is a bad idea. + strtoul(SVNREVISIONSTR, &e, 10); + if (!*SVNREVISIONSTR || *e) + return false; + } //update blocked via commandline if (COM_CheckParm("-noupdate") || COM_CheckParm("--noupdate") || COM_CheckParm("-noautoupdate") || COM_CheckParm("--noautoupdate")) diff --git a/engine/client/valid.c b/engine/client/valid.c index 1024cb51..18524515 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -503,7 +503,7 @@ void Validation_FileLoaded(const char *filename, const qbyte *filedata, size_t f { if (!strcmp(filename, modifiles[i].name) && (modifiles[i].flags & (cl.teamfortress?FMOD_TF:FMOD_DM))) { - SHA1(digest, sizeof(digest), filedata, filesize); + CalcHash(&hash_sha1, digest, sizeof(digest), filedata, filesize); for (j = 0; j < modifiles[i].hashes; j++) { diff --git a/engine/client/view.c b/engine/client/view.c index d162bfdb..9bf9d514 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -2193,7 +2193,7 @@ void R_DrawNameTags(void) if (Matrix4x4_CM_Project(org, screenspace, r_refdef.viewangles, r_refdef.vieworg, r_refdef.fov_x, r_refdef.fov_y)) { char asciibuffer[8192]; - char *entstr; + const char *entstr; size_t buflen; int x, y; @@ -2205,7 +2205,19 @@ void R_DrawNameTags(void) vec2_t scale = {8,8}; x = screenspace[0]*r_refdef.vrect.width+r_refdef.vrect.x; y = (1-screenspace[1])*r_refdef.vrect.height+r_refdef.vrect.y; - R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_console, scale); + y += scale[1]*R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_console, scale); + +#ifdef CSQC_DAT + { + extern world_t csqc_world; + if (w == &csqc_world) + { + entstr = CSQC_GetExtraFieldInfo(e, asciibuffer, sizeof(asciibuffer)); + if (entstr) + y += scale[1]*R_DrawTextField(x, y, vid.width - x, vid.height - y, entstr, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_console, scale); + } + } +#endif } } } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index b8fc96e8..b8273f0c 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -839,8 +839,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_BACKBUFLEN 1200 +#ifdef Q1BSPS #define lightstyleindex_t unsigned short +#else +#define lightstyleindex_t qbyte +#endif #define INVALID_LIGHTSTYLE ((lightstyleindex_t)(~0u)) //the style that's invalid, signifying to stop adding more. +#define INVALID_VLIGHTSTYLE ((qbyte)(~0u)) //the style that's invalid for verticies, signifying to stop adding more. // // per-level limits diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index 8483e32c..5bd409d1 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -24,6 +24,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_MAP_HULLSDQ1 4 #define MAX_MAP_HULLSDH2 8 #define MAX_MAP_HULLSM 8 +#define RBSP_STYLESPERSURF 4 +#define Q1Q2BSP_STYLESPERSURF 4 +#ifdef Q1BSPS +#define MAXCPULIGHTMAPS 16 //max lightmaps mixed by the cpu (vanilla q1bsp=4, fte extensions=no real cap, must be >=MAXRLIGHTMAPS) +#elif defined(Q1BSPS) +#define MAXCPULIGHTMAPS Q1Q2BSP_STYLESPERSURF //max lightmaps mixed by the cpu (vanilla q1bsp=4, fte extensions=no real cap, must be >=MAXRLIGHTMAPS) +#else +#define MAXCPULIGHTMAPS MAXRLIGHTMAPS //max lightmaps mixed by the cpu (vanilla q1bsp=4, fte extensions=no real cap, must be >=MAXRLIGHTMAPS) +#endif //#define MAX_MAP_MODELS 256 //#define MAX_MAP_BRUSHES 0x8000 @@ -235,11 +244,10 @@ typedef struct } dledge_t; #ifdef RFBSPS -#define MAXRLIGHTMAPS 4 //max lightmaps mixed by the renderer (rbsp=4, otherwise 1) +#define MAXRLIGHTMAPS 4 //max lightmaps mixed by the gpu (rbsp=4, otherwise 1) #else -#define MAXRLIGHTMAPS 1 //max lightmaps mixed by the renderer (rbsp=4, otherwise 1) +#define MAXRLIGHTMAPS 1 //max lightmaps mixed by the gpu (rbsp=4, otherwise 1) #endif -#define MAXQ1LIGHTMAPS 16 typedef struct { short planenum; @@ -250,7 +258,7 @@ typedef struct short texinfo; // lighting info - qbyte styles[4]; + qbyte styles[Q1Q2BSP_STYLESPERSURF]; int lightofs; // start of [numstyles*surfsize] samples } dsface_t; typedef struct @@ -263,7 +271,7 @@ typedef struct int texinfo; // lighting info - qbyte styles[4]; + qbyte styles[Q1Q2BSP_STYLESPERSURF]; int lightofs; // start of [numstyles*surfsize] samples } dlface_t; @@ -821,9 +829,10 @@ typedef struct typedef struct { float point[3]; - float texcoords[5][2]; + float stcoords[2]; + float lmtexcoords[RBSP_STYLESPERSURF][2]; float normal[3]; - unsigned char color[4][4]; + unsigned char color[RBSP_STYLESPERSURF][4]; } rbspvertex_t; struct Q3FOG @@ -854,8 +863,7 @@ typedef struct int firstindex; int num_indexes; int lightmapnum; - int lightmap_x; - int lightmap_y; + int lightmap_offs[2]; int lightmap_width; int lightmap_height; float lightmap_origin[3]; @@ -874,10 +882,10 @@ typedef struct int num_vertices; int firstindex; int num_indexes; - unsigned char lm_styles[4]; - unsigned char vt_styles[4]; - int lightmapnum[4]; - int lightmap_offs[2][4]; + unsigned char lm_styles[RBSP_STYLESPERSURF]; + unsigned char vt_styles[RBSP_STYLESPERSURF]; + int lightmapnum[RBSP_STYLESPERSURF]; + int lightmap_offs[2][RBSP_STYLESPERSURF]; //yes, weird ordering. int lightmap_width; int lightmap_height; float lightmap_origin[3]; diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index f7e34a7a..986f6037 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -5466,6 +5466,16 @@ const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num) galiasinfo_t *inf; galiasskin_t *skin; + if (!model || model->loadstate != MLS_LOADED) + { + if (model && model->loadstate == MLS_NOTLOADED) + Mod_LoadModel(model, MLV_SILENT); + if (model && model->loadstate == MLS_LOADING) + COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING); + if (!model || model->loadstate != MLS_LOADED) + return NULL; + } + if (!model || model->type != mod_alias) { if (model->type == mod_brush && surfaceidx < model->numtextures && !num) diff --git a/engine/common/common.c b/engine/common/common.c index 6ecc9e10..8691ffba 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -6040,6 +6040,97 @@ static int Base64_Decode(char inp) //if (inp == '=') //padding char return 0; //invalid } + +size_t Base64_EncodeBlock(const qbyte *in, size_t length, char *out, size_t outsize) +{ + char *start = out; + char *end = out+outsize-1; + unsigned int v; + while(length > 0) + { + v = 0; + if (length > 0) + v |= in[0]<<16; + if (length > 1) + v |= in[1]<<8; + if (length > 2) + v |= in[2]<<0; + + if (out < end) *out++ = (length>=1)?Base64_Encode((v>>18)&63):'='; + if (out < end) *out++ = (length>=1)?Base64_Encode((v>>12)&63):'='; + if (out < end) *out++ = (length>=2)?Base64_Encode((v>>6)&63):'='; + if (out < end) *out++ = (length>=3)?Base64_Encode((v>>0)&63):'='; + + in+=3; + length -= 3; + } + end++; + if (out < end) + *out = 0; + return out-start; +} +size_t Base64_DecodeBlock(const char *in, const char *in_end, qbyte *out, size_t outsize) +{ + qbyte *start = out; + unsigned int v; + if (!in_end) + in_end = in + strlen(in); + if (!out) + return ((in_end-in+3)/4)*3 + 1; //upper estimate, with null terminator for convienience. + + for (; outsize > 1;) + { + while(*in > 0 && *in < ' ') + in++; + if (in >= in_end || !*in || outsize < 1) + break; //end of message when EOF, otherwise error + v = Base64_Decode(*in++)<<18; + while(*in > 0 && *in < ' ') + in++; + if (in >= in_end || !*in || outsize < 1) + break; //some kind of error + v |= Base64_Decode(*in++)<<12; + *out++ = (v>>16)&0xff; + if (in >= in_end || *in == '=' || !*in || outsize < 2) + break; //end of message when '=', otherwise error + v |= Base64_Decode(*in++)<<6; + *out++ = (v>>8)&0xff; + if (in >= in_end || *in == '=' || !*in || outsize < 3) + break; //end of message when '=', otherwise error + v |= Base64_Decode(*in++)<<0; + *out++ = (v>>0)&0xff; + outsize -= 3; + } + return out-start; //total written (no null, output is considered binary) +} +size_t Base16_DecodeBlock(const char *in, qbyte *out, size_t outsize) +{ + qbyte *start = out; + if (!out) + return ((strlen(in)+1)/2) + 1; + + for (; ishexcode(in[0]) && ishexcode(in[1]) && outsize > 0; outsize--, in+=2) + *out++ = (dehex(in[0])<<4) | dehex(in[1]); + return out-start; +} +size_t Base16_EncodeBlock(const char *in, size_t length, qbyte *out, size_t outsize) +{ + const char tab[16] = "0123456789abcdef"; + qbyte *start = out; + if (!out) + return (length*2) + 1; + + if (outsize > length*2) + *out = 0; + while (length --> 0) + { + *out++ = tab[(*in>>4)&0xf]; + *out++ = tab[(*in>>0)&0xf]; + in++; + } + return out-start; +} + /* Info Buffers */ diff --git a/engine/common/common.h b/engine/common/common.h index 42009a52..13365588 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -742,7 +742,7 @@ char *FS_GetManifestArgs(void); int FS_GetManifestArgv(char **argv, int maxargs); struct zonegroup_s; -void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path, size_t *fsize); +void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path, size_t *fsize, qboolean filters); qbyte *FS_LoadMallocFile (const char *path, size_t *fsize); qofs_t FS_LoadFile(const char *name, void **file); void FS_FreeFile(void *file); @@ -848,13 +848,26 @@ qbyte COM_BlockSequenceCheckByte (qbyte *base, int length, int sequence, unsigne qbyte COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence); qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence); -typedef size_t hashfunc_t(unsigned char *digest, size_t maxdigestsize, size_t numstrings, const unsigned char **strings, size_t *stringlens); -#define SHA1 SHA1_quake -#define HMAC HMAC_quake -hashfunc_t SHA1_m; -//int SHA1_m(char *digest, size_t maxdigestsize, size_t numstrings, const char **strings, size_t *stringlens); -//#define SHA1(digest,maxdigestsize,string,stringlen) SHA1_m(digest, maxdigestsize, 1, &string, &stringlen) -size_t SHA1(unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen); +size_t Base64_EncodeBlock(const qbyte *in, size_t length, char *out, size_t outsize); //tries to null terminate, but returns length without termination. +size_t Base64_DecodeBlock(const char *in, const char *in_end, qbyte *out, size_t outsize); // +/ and = +size_t Base16_EncodeBlock(const char *in, size_t length, qbyte *out, size_t outsize); +size_t Base16_DecodeBlock(const char *in, qbyte *out, size_t outsize); + +typedef struct +{ + unsigned int digestsize; + unsigned int contextsize; //you need to alloca(te) this much memory... + void (*init) (void *context); + void (*process) (void *context, const void *data, size_t datasize); + void (*terminate) (unsigned char *digest, void *context); +} hashfunc_t; +extern hashfunc_t hash_sha1; +extern hashfunc_t hash_sha224; +extern hashfunc_t hash_sha256; +extern hashfunc_t hash_sha384; +extern hashfunc_t hash_sha512; +#define HMAC HMAC_quake //stop conflicts... +size_t CalcHash(hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen); size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen); int version_number(void); diff --git a/engine/common/fs.c b/engine/common/fs.c index 360bafa4..95256eb9 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1824,7 +1824,7 @@ static vfsfile_t *VFS_Filter(const char *filename, vfsfile_t *handle) { // char *ext; - if (!handle || handle->WriteBytes || handle->seekstyle == SS_SLOW || handle->seekstyle == SS_UNSEEKABLE) //only on readonly files for which we can undo any header read damage + if (!handle || !handle->ReadBytes || handle->seekstyle == SS_SLOW || handle->seekstyle == SS_UNSEEKABLE) //only on readonly files for which we can undo any header read damage return handle; // ext = COM_FileExtension (filename); #ifdef AVAIL_GZDEC @@ -2170,7 +2170,7 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela if (loc.search) { - return VFS_Filter(filename, loc.search->handle->OpenVFS(loc.search->handle, &loc, mode)); + return loc.search->handle->OpenVFS(loc.search->handle, &loc, mode); } //if we're meant to be writing, best write to it. @@ -2406,14 +2406,19 @@ qbyte *FS_LoadMallocFile (const char *path, size_t *fsize) return COM_LoadFile (path, 0, 5, fsize); } -void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize) +void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize, qboolean filters) { char *mem = NULL; vfsfile_t *f = FS_OpenVFS(path, "rb", FS_GAME); + if (f && filters) + f = VFS_Filter(path, f); if (f) { int len = VFS_GETLEN(f); - mem = ZG_Malloc(ctx, len+1); + if (ctx) + mem = ZG_Malloc(ctx, len+1); + else + mem = BZ_Malloc(len+1); if (mem) { mem[len] = 0; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 48cbf2ca..8706fadc 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -38,6 +38,7 @@ cvar_t q3bsp_surf_meshcollision_flag = CVARD("q3bsp_surf_meshcollision_flag", "0x80000000", "The surfaceparm flag(s) that enables q3bsp trisoup collision"); cvar_t q3bsp_surf_meshcollision_force = CVARD("q3bsp_surf_meshcollision_force", "0", "Force mesh-based collisions on all q3bsp trisoup surfaces."); cvar_t q3bsp_mergeq3lightmaps = CVARD("q3bsp_mergelightmaps", "1", "Specifies whether to merge lightmaps into atlases in order to boost performance. Unfortunately this breaks tcgen on lightmap passes - if you care, set this to 0."); +cvar_t q3bsp_ignorestyles = CVARD("q3bsp_ignorestyles", "0", "Ignores multiple lightstyles in Raven's q3bsp variant(and derivatives) for better batch/rendering performance."); cvar_t q3bsp_bihtraces = CVARFD("_q3bsp_bihtraces", "0", CVAR_RENDERERLATCH, "Uses runtime-generated bih collision culling for faster traces."); #if Q3SURF_NODRAW != TI_NODRAW @@ -1696,7 +1697,7 @@ static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, lump out->styles[i] = style; } } - for ( ; istyles[i] = INVALID_LIGHTSTYLE; if (overrides.offsets) i = overrides.offsets[surfnum]; @@ -2476,11 +2477,11 @@ static qboolean CModRBSP_LoadVertexes (model_t *mod, qbyte *mod_base, lump_t *l) } for ( j=0 ; j < 2 ; j++) { - stout[i][j] = LittleFloat ( ((float *)in->texcoords)[j] ); - for (sty = 0; sty < MAXRLIGHTMAPS; sty++) - prv->vertlstmexcoords[sty][i][j] = LittleFloat ( ((float *)in->texcoords)[j+2*(sty+1)] ); + stout[i][j] = LittleFloat (in->stcoords[j]); + for (sty = 0; sty < min(MAXRLIGHTMAPS, RBSP_STYLESPERSURF); sty++) + prv->vertlstmexcoords[sty][i][j] = LittleFloat(in->lmtexcoords[sty][j]); } - for (sty = 0; sty < MAXRLIGHTMAPS; sty++) + for (sty = 0; sty < min(MAXRLIGHTMAPS, RBSP_STYLESPERSURF); sty++) { prv->colors4f_array[sty][i][0] = lmgamma[in->color[sty][0]]/255.0f; prv->colors4f_array[sty][i][1] = lmgamma[in->color[sty][1]]/255.0f; @@ -3203,17 +3204,17 @@ static qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) else if (out->lightmaptexturenums[0] < 0 /*|| facetype == MST_TRIANGLE_SOUP*/ || r_vertexlight.value) out->texinfo += mod->numtexinfo; //various surfaces use a different version of the same shader (with all the lightmaps collapsed) - out->light_s[0] = LittleLong(in->lightmap_x); - out->light_t[0] = LittleLong(in->lightmap_y); + out->light_s[0] = LittleLong(in->lightmap_offs[0]); + out->light_t[0] = LittleLong(in->lightmap_offs[1]); out->styles[0] = INVALID_LIGHTSTYLE; - out->vlstyles[0] = 255; + out->vlstyles[0] = INVALID_VLIGHTSTYLE; for (sty = 1; sty < MAXRLIGHTMAPS; sty++) { out->styles[sty] = INVALID_LIGHTSTYLE; - out->vlstyles[sty] = 255; + out->vlstyles[sty] = INVALID_VLIGHTSTYLE; out->lightmaptexturenums[sty] = -1; } - for (; sty < MAXQ1LIGHTMAPS; sty++) + for (; sty < MAXCPULIGHTMAPS; sty++) out->styles[sty] = INVALID_LIGHTSTYLE; out->lmshift = LMSHIFT_DEFAULT; //fixme: determine texturemins from lightmap_origin @@ -3300,6 +3301,8 @@ static qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) mesh_t *mesh; + int maxstyle = q3bsp_ignorestyles.ival?1:min(MAXRLIGHTMAPS, RBSP_STYLESPERSURF); + in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -3320,18 +3323,26 @@ static qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) out->plane = pl; facetype = LittleLong(in->facetype); out->texinfo = mod->texinfo + LittleLong(in->shadernum); - for (j = 0; j < 4 && j < MAXRLIGHTMAPS; j++) + for (j = 0; j < maxstyle; j++) { out->lightmaptexturenums[j] = LittleLong(in->lightmapnum[j]); out->light_s[j] = LittleLong(in->lightmap_offs[0][j]); out->light_t[j] = LittleLong(in->lightmap_offs[1][j]); out->styles[j] = (in->lm_styles[j]!=255)?in->lm_styles[j]:INVALID_LIGHTSTYLE; - out->vlstyles[j] = in->vt_styles[j]; + out->vlstyles[j] = (in->vt_styles[j]!=255)?in->vt_styles[j]:INVALID_VLIGHTSTYLE; if (mod->lightmaps.count < out->lightmaptexturenums[j]+1) mod->lightmaps.count = out->lightmaptexturenums[j]+1; } - for (; j < MAXQ1LIGHTMAPS; j++) + for (; j < MAXRLIGHTMAPS; j++) + { + out->lightmaptexturenums[j] = -1; + out->light_s[j] = 0; + out->light_t[j] = 0; + out->styles[j] = INVALID_LIGHTSTYLE; + out->vlstyles[j] = INVALID_VLIGHTSTYLE; + } + for (; j < MAXCPULIGHTMAPS; j++) out->styles[j] = INVALID_LIGHTSTYLE; if (facetype == MST_FLARE) out->texinfo = mod->texinfo + mod->numtexinfo*2; @@ -4217,7 +4228,7 @@ static qbyte *CM_LeafnumPVS (model_t *model, int leafnum, qbyte *buffer, unsigne #define GLQ2BSP_LightPointValues GLQ1BSP_LightPointValues extern int r_dlightframecount; -static void Q2BSP_MarkLights (dlight_t *light, int bit, mnode_t *node) +static void Q2BSP_MarkLights (dlight_t *light, dlightbitmask_t bit, mnode_t *node) { mplane_t *splitplane; float dist; @@ -4264,7 +4275,7 @@ static void Q2BSP_MarkLights (dlight_t *light, int bit, mnode_t *node) { if (surf->dlightframe != r_dlightframecount) { - surf->dlightbits = 0; + surf->dlightbits = 0u; surf->dlightframe = r_dlightframecount; } surf->dlightbits |= bit; @@ -4322,18 +4333,18 @@ CM_LoadMap Loads in the map and all submodels ================== */ -static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboolean clientload, unsigned *checksum) +static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboolean clientload) { unsigned *buf; int i; q2dheader_t header; int length; - static unsigned last_checksum; qboolean noerrors = true; model_t *wmod = mod; char loadname[32]; qbyte *mod_base = (qbyte *)filein; bspx_header_t *bspx = NULL; + unsigned int checksum; #ifdef Q3BSPS extern cvar_t gl_overbright; #endif @@ -4360,7 +4371,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole mod->leafs = ZG_Malloc(&mod->memgroup, 1 * sizeof(*mod->leafs)); prv->numcmodels = 1; prv->numareas = 1; - *checksum = 0; + mod->checksum = mod->checksum2 = 0; prv->cmodels[0].headnode = (mnode_t*)mod->leafs; //directly start with the empty leaf return &prv->cmodels[0]; // cinematic servers won't have anything at all } @@ -4376,8 +4387,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole return NULL; } - last_checksum = LittleLong (Com_BlockChecksum (buf, length)); - *checksum = last_checksum; + checksum = LittleLong (Com_BlockChecksum (buf, length)); header = *(q2dheader_t *)(buf); header.ident = LittleLong(header.ident); @@ -4775,7 +4785,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole #endif FloodAreaConnections (prv); - mod->checksum = mod->checksum2 = *checksum; + mod->checksum = mod->checksum2 = checksum; mod->nummodelsurfaces = mod->numsurfaces; memset(&mod->batches, 0, sizeof(mod->batches)); @@ -7702,11 +7712,10 @@ unsigned int Q2BSP_PointContents(model_t *mod, const vec3_t axis[3], const vec3_ -int map_checksum; qboolean QDECL Mod_LoadQ2BrushModel (model_t *mod, void *buffer, size_t fsize) { mod->fromgame = fg_quake2; - return CM_LoadMap(mod, buffer, fsize, true, &map_checksum) != NULL; + return CM_LoadMap(mod, buffer, fsize, true) != NULL; } void CM_Init(void) //register cvars. @@ -7718,6 +7727,7 @@ void CM_Init(void) //register cvars. Cvar_Register(&q3bsp_surf_meshcollision_flag, MAPOPTIONS); Cvar_Register(&q3bsp_surf_meshcollision_force, MAPOPTIONS); Cvar_Register(&q3bsp_mergeq3lightmaps, MAPOPTIONS); + Cvar_Register(&q3bsp_ignorestyles, MAPOPTIONS); Cvar_Register(&q3bsp_bihtraces, MAPOPTIONS); Cvar_Register(&r_subdivisions, MAPOPTIONS); diff --git a/engine/common/net.h b/engine/common/net.h index 4bb17e86..e21d75bf 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -93,7 +93,7 @@ typedef struct netadr_s } address; unsigned short port; - unsigned short connum; //which quake connection/socket the address is talking about. 1-based. 0 is unspecified. + unsigned short connum; //which quake connection/socket the address is talking about. 1-based. 0 is unspecified. this is NOT used for address equivelency. unsigned int scopeid; //ipv6 interface id thing. } netadr_t; diff --git a/engine/common/net_ice.c b/engine/common/net_ice.c index 6a8c8691..594b677e 100644 --- a/engine/common/net_ice.c +++ b/engine/common/net_ice.c @@ -477,7 +477,7 @@ static qboolean ICE_SendSpam(struct icestate_s *con) data[2] = ((buf.cursize+4+sizeof(integ)-20)>>8)&0xff; //hashed header length is up to the end of the hmac attribute data[3] = ((buf.cursize+4+sizeof(integ)-20)>>0)&0xff; //but the hash is to the start of the attribute's header - HMAC(SHA1_m, integ, sizeof(integ), data, buf.cursize, con->rpwd, strlen(con->rpwd)); + HMAC(&hash_sha1, integ, sizeof(integ), data, buf.cursize, con->rpwd, strlen(con->rpwd)); MSG_WriteShort(&buf, BigShort(0x8)); //MESSAGE-INTEGRITY MSG_WriteShort(&buf, BigShort(20)); //sha1 key length SZ_Write(&buf, integ, sizeof(integ)); //integrity data @@ -1523,7 +1523,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col) char key[20]; //the hmac is a bit weird. the header length includes the integrity attribute's length, but the checksum doesn't even consider the attribute header. stun->msglen = BigShort(integritypos+sizeof(integrity) - (char*)stun - sizeof(*stun)); - HMAC(SHA1_m, key, sizeof(key), (qbyte*)stun, integritypos-4 - (char*)stun, con->lpwd, strlen(con->lpwd)); + HMAC(&hash_sha1, key, sizeof(key), (qbyte*)stun, integritypos-4 - (char*)stun, con->lpwd, strlen(con->lpwd)); if (memcmp(key, integrity, sizeof(integrity))) { Con_DPrintf("Integrity is bad! needed %x got %x\n", *(int*)key, *(int*)integrity); @@ -1690,7 +1690,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col) data[2] = ((buf.cursize+4+sizeof(integrity)-20)>>8)&0xff; //hashed header length is up to the end of the hmac attribute data[3] = ((buf.cursize+4+sizeof(integrity)-20)>>0)&0xff; //but the hash is to the start of the attribute's header - HMAC(SHA1_m, integrity, sizeof(integrity), data, buf.cursize, con->lpwd, strlen(con->lpwd)); + HMAC(&hash_sha1, integrity, sizeof(integrity), data, buf.cursize, con->lpwd, strlen(con->lpwd)); MSG_WriteShort(&buf, BigShort(0x8)); //MESSAGE-INTEGRITY MSG_WriteShort(&buf, BigShort(sizeof(integrity))); //sha1 key length SZ_Write(&buf, integrity, sizeof(integrity)); //integrity data diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 42abdca5..2eb8725a 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -11,8 +11,6 @@ #endif #ifdef HAVE_GNUTLS -#define privname "privkey.pem" -#define pubname "cert.pem" #if defined(_WIN32) && !defined(MINGW) && 0 @@ -205,6 +203,7 @@ static int (VARGS *qgnutls_x509_crt_set_dn)(gnutls_x509_crt_t crt, const char * static int (VARGS *qgnutls_x509_crt_set_issuer_dn)(gnutls_x509_crt_t crt, const char *dn, const char **err); static int (VARGS *qgnutls_x509_crt_set_key)(gnutls_x509_crt_t crt, gnutls_x509_privkey_t key); static int (VARGS *qgnutls_x509_crt_export2)(gnutls_x509_crt_t cert, gnutls_x509_crt_fmt_t format, gnutls_datum_t * out); +static int (VARGS *qgnutls_x509_crt_import)(gnutls_x509_crt_t cert, const gnutls_datum_t *data, gnutls_x509_crt_fmt_t format); static int (VARGS *qgnutls_x509_privkey_init)(gnutls_x509_privkey_t * key); static void (VARGS *qgnutls_x509_privkey_deinit)(gnutls_x509_privkey_t key); static int (VARGS *qgnutls_x509_privkey_generate)(gnutls_x509_privkey_t key, gnutls_pk_algorithm_t algo, unsigned int bits, unsigned int flags); @@ -213,7 +212,14 @@ static int (VARGS *qgnutls_x509_crt_privkey_sign)(gnutls_x509_crt_t crt, gnutls static int (VARGS *qgnutls_privkey_init)(gnutls_privkey_t * key); static void (VARGS *qgnutls_privkey_deinit)(gnutls_privkey_t key); static int (VARGS *qgnutls_privkey_import_x509)(gnutls_privkey_t pkey, gnutls_x509_privkey_t key, unsigned int flags); +//static int (VARGS *qgnutls_privkey_sign_hash2)(gnutls_privkey_t signer, gnutls_sign_algorithm_t algo, unsigned int flags, const gnutls_datum_t * hash_data, gnutls_datum_t * signature); +static int (VARGS *qgnutls_privkey_sign_hash)(gnutls_privkey_t signer, gnutls_digest_algorithm_t hash_algo, unsigned int flags, const gnutls_datum_t * hash_data, gnutls_datum_t * signature); +static int (VARGS *qgnutls_pubkey_init)(gnutls_pubkey_t * key); +static int (VARGS *qgnutls_pubkey_import_x509)(gnutls_pubkey_t key, gnutls_x509_crt_t crt, unsigned int flags); +static int (VARGS *qgnutls_pubkey_verify_hash2)(gnutls_pubkey_t key, gnutls_sign_algorithm_t algo, unsigned int flags, const gnutls_datum_t * hash, const gnutls_datum_t * signature); static int (VARGS *qgnutls_certificate_set_x509_key_mem)(gnutls_certificate_credentials_t res, const gnutls_datum_t * cert, const gnutls_datum_t * key, gnutls_x509_crt_fmt_t type); +static int (VARGS *qgnutls_certificate_get_x509_key)(gnutls_certificate_credentials_t res, unsigned index, gnutls_x509_privkey_t *key); +static void (VARGS *qgnutls_certificate_free_credentials)(gnutls_certificate_credentials_t sc); static qboolean Init_GNUTLS(void) { @@ -384,6 +390,13 @@ static qboolean Init_GNUTLS(void) {(void**)&qgnutls_privkey_import_x509, "gnutls_privkey_import_x509"}, {(void**)&qgnutls_certificate_set_x509_key_mem, "gnutls_certificate_set_x509_key_mem"}, + {(void**)&qgnutls_certificate_get_x509_key, "gnutls_certificate_get_x509_key"}, + {(void**)&qgnutls_certificate_free_credentials, "gnutls_certificate_free_credentials"}, + {(void**)&qgnutls_pubkey_init, "gnutls_pubkey_init"}, + {(void**)&qgnutls_pubkey_import_x509, "gnutls_pubkey_import_x509"}, + {(void**)&qgnutls_privkey_sign_hash, "gnutls_privkey_sign_hash"}, + {(void**)&qgnutls_pubkey_verify_hash2, "gnutls_pubkey_verify_hash2"}, + {(void**)&qgnutls_x509_crt_import, "gnutls_x509_crt_import"}, {NULL, NULL} }; @@ -835,17 +848,68 @@ static gnutls_certificate_credentials_t xcred[2]; static gnutls_datum_t cookie_key; #endif +vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize) +{ +#define privname "privkey.pem" + vfsfile_t *privf; + const char *mode = nativename?"wb":"rb"; + int i = COM_CheckParm("-privkey"); + if (i++) + { + if (nativename) + Q_strncpyz(nativename, com_argv[i], nativesize); + privf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM); + } + else + { + if (nativename) + if (!FS_NativePath(privname, FS_ROOT, nativename, nativesize)) + return NULL; + + privf = FS_OpenVFS(privname, mode, FS_ROOT); + } + return privf; +#undef privname +} +vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize) +{ +#define pubname "cert.pem" + vfsfile_t *pubf; + const char *mode = nativename?"wb":"rb"; + int i = COM_CheckParm("-pubkey"); + if (i++) + { + if (nativename) + Q_strncpyz(nativename, com_argv[i], nativesize); + pubf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM); + } + else + { + if (nativename) + if (!FS_NativePath(pubname, FS_ROOT, nativename, nativesize)) + return NULL; + pubf = FS_OpenVFS(pubname, mode, FS_ROOT); + } + return pubf; +#undef pubname +} + static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred) { int ret = -1; gnutls_datum_t priv, pub; - vfsfile_t *privf = FS_OpenVFS(privname, "rb", FS_ROOT); - vfsfile_t *pubf = FS_OpenVFS(pubname, "rb", FS_ROOT); + vfsfile_t *privf = SSL_OpenPrivKey(NULL, 0); + vfsfile_t *pubf = SSL_OpenPubKey(NULL, 0); + const char *hostname = NULL; + + int i = COM_CheckParm("-certhost"); + if (i) + hostname = com_argv[i+1]; memset(&priv, 0, sizeof(priv)); memset(&pub, 0, sizeof(pub)); - if (!privf || !pubf) + if ((!privf || !pubf) && hostname) { //not found? generate a new one. //FIXME: how to deal with race conditions with multiple servers on the same host? //delay till the first connection? we at least write both files at the sameish time. @@ -856,7 +920,7 @@ static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred) char serial[64]; const char *errstr; gnutls_pk_algorithm_t privalgo = GNUTLS_PK_RSA; - + if (privf)VFS_CLOSE(privf);privf=NULL; if (pubf)VFS_CLOSE(pubf);pubf=NULL; @@ -880,11 +944,16 @@ static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred) qgnutls_x509_crt_set_activation_time(cert, time(NULL)-1); qgnutls_x509_crt_set_expiration_time(cert, time(NULL)+(time_t)10*365*24*60*60); qgnutls_x509_crt_set_serial(cert, serial, strlen(serial)); - if (qgnutls_x509_crt_set_dn(cert, "CN=localhost", &errstr) < 0) - Con_Printf("gnutls_x509_crt_set_dn failed: %s\n", errstr); - if (qgnutls_x509_crt_set_issuer_dn(cert, "CN=localhost", &errstr) < 0) - Con_Printf("gnutls_x509_crt_set_issuer_dn failed: %s\n", errstr); -// qgnutls_x509_crt_set_key_usage(cert, GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_DATA_ENCIPHERMENT|); + if (!hostname) + /*qgnutls_x509_crt_set_key_usage(cert, GNUTLS_KEY_DIGITAL_SIGNATURE)*/; + else + { + if (qgnutls_x509_crt_set_dn(cert, va("CN=%s", hostname), &errstr) < 0) + Con_Printf("gnutls_x509_crt_set_dn failed: %s\n", errstr); + if (qgnutls_x509_crt_set_issuer_dn(cert, va("CN=%s", hostname), &errstr) < 0) + Con_Printf("gnutls_x509_crt_set_issuer_dn failed: %s\n", errstr); +// qgnutls_x509_crt_set_key_usage(cert, GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_DATA_ENCIPHERMENT|); + } qgnutls_x509_crt_set_key(cert, key); /*sign it with our private key*/ @@ -906,31 +975,29 @@ static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred) if (priv.size && pub.size) { char fullname[MAX_OSPATH]; - privf = FS_OpenVFS(privname, "wb", FS_ROOT); + privf = SSL_OpenPrivKey(fullname, sizeof(fullname)); if (privf) { VFS_WRITE(privf, priv.data, priv.size); VFS_CLOSE(privf); - FS_NativePath(privname, FS_ROOT, fullname, sizeof(fullname)); Con_Printf("Wrote %s\n", fullname); } // memset(priv.data, 0, priv.size); (*qgnutls_free)(priv.data); memset(&priv, 0, sizeof(priv)); - pubf = FS_OpenVFS(pubname, "wb", FS_ROOT); + pubf = SSL_OpenPubKey(fullname, sizeof(fullname)); if (pubf) { VFS_WRITE(pubf, pub.data, pub.size); VFS_CLOSE(pubf); - FS_NativePath(pubname, FS_ROOT, fullname, sizeof(fullname)); Con_Printf("Wrote %s\n", fullname); } (*qgnutls_free)(pub.data); memset(&pub, 0, sizeof(pub)); - privf = FS_OpenVFS(privname, "rb", FS_ROOT); - pubf = FS_OpenVFS(pubname, "rb", FS_ROOT); + privf = SSL_OpenPrivKey(NULL, 0); + pubf = SSL_OpenPubKey(NULL, 0); Con_Printf("Certificate generated\n"); } @@ -961,7 +1028,7 @@ static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred) Con_Printf("gnutls_certificate_set_x509_key_mem failed: %i\n", ret); } else - Con_Printf("Unable to read/generate cert\n"); + Con_Printf("Unable to read/generate cert ('-certhost HOSTNAME' commandline arguments to autogenerate one)\n"); memset(priv.data, 0, priv.size);//just in case. FIXME: we didn't scrub the filesystem code. libc has its own caches etc. lets hope that noone comes up with some way to scrape memory remotely (although if they can inject code then we've lost either way so w/e) if (priv.data) @@ -1167,7 +1234,84 @@ int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) } } +//generates a signed blob +int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax) +{ + gnutls_datum_t hash = {hashdata, hashsize}; + gnutls_datum_t sign = {NULL, 0}; + gnutls_certificate_credentials_t cred; + if (Init_GNUTLS()) + { + qgnutls_certificate_allocate_credentials (&cred); + if (SSL_LoadPrivateCert(cred)) + { + gnutls_x509_privkey_t xkey; + gnutls_privkey_t privkey; + qgnutls_privkey_init(&privkey); + qgnutls_certificate_get_x509_key(cred, 0, &xkey); + qgnutls_privkey_import_x509(privkey, xkey, 0); + + qgnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA512, 0, &hash, &sign); + qgnutls_privkey_deinit(privkey); + } + else + sign.size = 0; + qgnutls_certificate_free_credentials(cred); + } + else + Con_Printf("Unable to init gnutls\n"); + memcpy(signdata, sign.data, sign.size); + return sign.size; +} + +//windows equivelent https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-signing-a-hash-and-verifying-the-hash-signature +enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize) +{ + gnutls_datum_t hash = {hashdata, hashsize}; + gnutls_datum_t sign = {signdata, signsize}; + int r; + + gnutls_datum_t rawcert; +#if 1 + size_t sz; + gnutls_pubkey_t pubkey; + gnutls_x509_crt_t cert; + + rawcert.data = Auth_GetKnownCertificate(authority, &sz); + if (!rawcert.data) + return VH_AUTHORITY_UNKNOWN; + if (!Init_GNUTLS()) + return VH_UNSUPPORTED; + rawcert.size = sz; + + qgnutls_pubkey_init(&pubkey); + qgnutls_x509_crt_init(&cert); + qgnutls_x509_crt_import(cert, &rawcert, GNUTLS_X509_FMT_PEM); + + qgnutls_pubkey_import_x509(pubkey, cert, 0); +#else + qgnutls_pubkey_import(pubkey, rawcert, GNUTLS_X509_FMT_PEM); +#endif + + r = qgnutls_pubkey_verify_hash2(pubkey, GNUTLS_SIGN_RSA_SHA512, 0, &hash, &sign); + if (r < 0) + { + if (r == GNUTLS_E_PK_SIG_VERIFY_FAILED) + { + Con_Printf("GNUTLS_VerifyHash: GNUTLS_E_PK_SIG_VERIFY_FAILED!\n"); + return VH_INCORRECT; + } + else if (r == GNUTLS_E_INSUFFICIENT_SECURITY) + { + Con_Printf("GNUTLS_VerifyHash: GNUTLS_E_INSUFFICIENT_SECURITY\n"); + return VH_AUTHORITY_UNKNOWN; //should probably be incorrect or something, but oh well + } + return VH_INCORRECT; + } + else + return VH_CORRECT; +} #ifdef HAVE_DTLS diff --git a/engine/common/net_ssl_winsspi.c b/engine/common/net_ssl_winsspi.c index 6ac9ef4e..b1471da5 100644 --- a/engine/common/net_ssl_winsspi.c +++ b/engine/common/net_ssl_winsspi.c @@ -1290,4 +1290,78 @@ const dtlsfuncs_t *SSPI_DTLS_InitClient(void) } #endif + +#include +enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize) +{ + NTSTATUS status; + BCRYPT_KEY_HANDLE pubkey; + size_t sz; + const char *pem = Auth_GetKnownCertificate(authority, &sz); + const char *pemend; + qbyte *der; + size_t dersize; + + static const void *(WINAPI *pCertCreateContext) (DWORD dwContextType, DWORD dwEncodingType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara); + static WINBOOL (WINAPI *pCryptImportPublicKeyInfoEx2) (DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD dwFlags, void *pvAuxInfo, BCRYPT_KEY_HANDLE *phKey); + static WINBOOL (WINAPI *pCertFreeCertificateContext) (PCCERT_CONTEXT pCertContext); + static dllhandle_t *crypt32; + static dllfunction_t crypt32funcs[] = { + {(void**)&pCertCreateContext, "CertCreateContext"}, + {(void**)&pCryptImportPublicKeyInfoEx2, "CryptImportPublicKeyInfoEx2"}, //WARNING: fails on wine. + {(void**)&pCertFreeCertificateContext, "CertFreeCertificateContext"}, + {NULL,NULL} + }; + + static NTSTATUS (WINAPI *pBCryptVerifySignature) (BCRYPT_KEY_HANDLE hKey, VOID *pPaddingInfo, PUCHAR pbHash, ULONG cbHash, PUCHAR pbSignature, ULONG cbSignature, ULONG dwFlags); + static NTSTATUS (WINAPI *pBCryptDestroyKey) (BCRYPT_KEY_HANDLE hKey); + static dllhandle_t *bcrypt; + static dllfunction_t bcryptfuncs[] = { + {(void**)&pBCryptVerifySignature, "BCryptVerifySignature"}, + {(void**)&pBCryptDestroyKey, "BCryptDestroyKey"}, + {NULL,NULL} + }; + + if (!crypt32) + crypt32 = Sys_LoadLibrary("crypt32.dll", crypt32funcs); + if (!bcrypt) + bcrypt = Sys_LoadLibrary("bcrypt.dll", bcryptfuncs); + if (!crypt32 || !bcrypt) + { + Con_Printf("Unable to obtain required crypto functions\n"); + return VH_UNSUPPORTED; + } + + if (!pem) + return VH_AUTHORITY_UNKNOWN; //no public cert/key for authority. + pem = strstr(pem, "-----BEGIN CERTIFICATE-----"); + if (!pem) + return VH_UNSUPPORTED; //not a pem + pem += strlen("-----BEGIN CERTIFICATE-----"); + pemend = strstr(pem, "-----END CERTIFICATE-----"); + if (!pemend) + return VH_UNSUPPORTED; + dersize = Base64_DecodeBlock(pem, pemend, NULL, 0); //guess + der = alloca(dersize); + dersize = Base64_DecodeBlock(pem, pemend, der, dersize); + //okay, now its in binary der format. + + //make sense of the cert and pull out its public key... + { + const CERT_CONTEXT* cert = pCertCreateContext(CERT_STORE_CERTIFICATE_CONTEXT, X509_ASN_ENCODING, der, dersize, 0, NULL); + if (!pCryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, 0, NULL, &pubkey)) + return VH_UNSUPPORTED; + pCertFreeCertificateContext(cert); + } + + //yay, now we can do what we actually wanted in the first place. + status = pBCryptVerifySignature(pubkey, NULL, hashdata, hashsize, signdata, signsize, 0); + pBCryptDestroyKey(pubkey); + if (status == STATUS_SUCCESS) + return VH_CORRECT; //its okay + else if (status == STATUS_INVALID_SIGNATURE) + return VH_INCORRECT; //its bad + return VH_UNSUPPORTED; //some weird transient error...? +} + #endif diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 134173ca..2d7b55c9 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -2178,6 +2178,49 @@ qboolean NET_IsLoopBackAddress (netadr_t *adr) #ifdef HAVE_SSL +void *Auth_GetKnownCertificate(const char *certname, size_t *size) +{ //our 'code signing' certs + //we only allow packages to be installed into the root dir (or with dll/so/exe extensions) when their signature is signed by one of these certificates + static struct + { + const char *name; + qbyte *cert; + } certs[] = + { //the contents of a -pubcert FILE + {"Spike", "-----BEGIN CERTIFICATE-----\n" + "MIIDnTCCAgUCCjE1ODQ4ODg2OTEwDQYJKoZIhvcNAQELBQAwEDEOMAwGA1UEAxMF\n" + "U3Bpa2UwHhcNMjAwMzIyMTQ1MTMwWhcNMzAwMzIwMTQ1MTMxWjAQMQ4wDAYDVQQD\n" + "EwVTcGlrZTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAN07KHTPc0Pn\n" + "lC8MlQNiI+OEUEJBakTjfNq+IJzJ6oTWXxfQbHrN+UpKXwxploDbeyxTE1Fniisi\n" + "nLWhOkW/XQqyXLXAv/3lxiSwe4QcVMOhQlw5U05VrdB7xHvFMShLsyc12sNvBiIa\n" + "Vw05wFJgIXYTd9nJfm9x3kpxRoTJBvdDbYl8OagT6SxzJfHkdmfI2TYVYxGUH9nX\n" + "R9zvwXTIXvV47cko2ON8scH9QQ6KgwMfcwyIBL74Btvl4ye+TrL2srj38FBxyyPG\n" + "SSdKPk4LN2zsfNsJm31hzWrdLEkl3CTOX5gHHSweOKpuPwmX/GPd1xo0nIMwDou4\n" + "BsMMBAhK/JSyLpUUzk5gbRmy4PwFccktHdFW6LF8ZvPY7e7LEiD5KOWZ7a7c1WR/\n" + "4oJrjo0t+7OugVADolxzLXFrq9ACBGrD8r6QlsGC8O7WqpKGQCT+4q3tUup9tPkh\n" + "3dhjC0jEkKljS+39uukbisV702bHwoEZPzjMpz4O9bHf6JbIJLlQzQIDAQABMA0G\n" + "CSqGSIb3DQEBCwUAA4IBgQC5rj7R7a9LLnqgiXMUITGnygK1lp0EV2BdnIrg/MHr\n" + "y+Gk9BA+XgFSI4W9odiG/hJnA7aQ0S2kk1GNYQ+NNzU2bQIMkaobaZApV9ojD4lL\n" + "s33Qbgt/Ocpadtpj8EiMInjLkn1B+wnqcX3S76Zcrf8RT4WP2A4klxcN3zBNBiBL\n" + "DAJ3SrH8hZ9wmruwAY5tMZhQzDHkeK8uaDb7nE0HA5GXeT4QYA/L7Ys2nGYgxj1O\n" + "L5YlGddBcX3O6XyJpSeCO2Z2kwl4qg8oiM+Y546lILotuL5qD/+FTDeX3dGd8nyD\n" + "e1g/7xd0V4IyKUjii8Vu2V1F7t0xVTPWEe13TqU/JTfKX4zvQnMF7zxgGFIwabHX\n" + "lzk2olte4rPp+iQzPmnynLiUrdkxGXLnE0V545VO+iGO8+bwclbJ+7SG6N5l8xox\n" + "WjGunhXXkEjitAk+ssBjbEh8kIfpFdVA09v60rMdm7BdfO3//QOsjwiwKkBOXcYW\n" + "QGE0Ue4J7anLVAKiQq4n1aU=\n" + "-----END CERTIFICATE-----\n"}, + }; + size_t i; + for (i = 0; i < countof(certs); i++) + { + if (!strcmp(certname, certs[i].name)) + { + *size = strlen(certs[i].cert); + return certs[i].cert; + } + } + return NULL; +} void *TLS_GetKnownCertificate(const char *certname, size_t *size) { //Note: This is XORed because of shitty scanners flagging binaries through false positive, flagging the sites that they were downloaded from, flagging binaries that contain references to those sites, and flagging any site that contains binaries. @@ -4851,7 +4894,7 @@ qboolean FTENET_TCP_ParseHTTPRequest(ftenet_tcp_connection_t *con, ftenet_tcp_st char *protoname = ""; blurgh = va("%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", arg[WCATTR_WSKEY]); - tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), blurgh, strlen(blurgh))); + tobase64(acceptkey, sizeof(acceptkey), sha1digest, CalcHash(&hash_sha1, sha1digest, sizeof(sha1digest), blurgh, strlen(blurgh))); if (st->remoteaddr.prot == NP_TLS) st->remoteaddr.prot = NP_WSS; @@ -8114,12 +8157,14 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket) FD_ZERO(&readfdset); FD_ZERO(&writefdset); +#ifndef _WIN32 if (stdinissocket) { sock = STDIN_FILENO; //stdin tends to be socket/filehandle 0 in unix FD_SET(sock, &readfdset); maxfd = sock; } +#endif #ifdef SV_MASTER { @@ -8185,8 +8230,10 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket) select(maxfd+1, &readfdset, &writefdset, NULL, &timeout); } +#ifndef _WIN32 if (stdinissocket) return FD_ISSET(STDIN_FILENO, &readfdset); +#endif #endif return true; } diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 8eafe74a..d72c744b 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -337,6 +337,13 @@ typedef struct ftenet_generic_connection_s { #endif } ftenet_generic_connection_t; +enum hashvalidation_e +{ + VH_UNSUPPORTED, //library not loaded (bad but not malicious) + VH_AUTHORITY_UNKNOWN, //don't know who signed it / untrusted (bad but probably not malicious) + VH_INCORRECT, //signature is wrong for that authority (bad, probably maliciously so) + VH_CORRECT //all is well. +}; #ifdef HAVE_DTLS typedef struct dtlsfuncs_s { @@ -355,18 +362,22 @@ const dtlsfuncs_t *DTLS_InitClient(void); int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); const dtlsfuncs_t *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available. const dtlsfuncs_t *SSPI_DTLS_InitClient(void); //should always return something, if implemented. + enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize); #endif #ifdef HAVE_GNUTLS vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); const dtlsfuncs_t *GNUDTLS_InitServer(void); //returns NULL if there's no cert available. const dtlsfuncs_t *GNUDTLS_InitClient(void); //should always return something, if implemented. + enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize); + int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax); #endif #ifdef HAVE_OPENSSL vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); const dtlsfuncs_t *OSSL_InitServer(void); //returns NULL if there's no cert available. const dtlsfuncs_t *OSSL_InitClient(void); //should always return something, if implemented. + enum hashvalidation_e OSSL_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize); #endif @@ -436,6 +447,7 @@ qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *na int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_generic_connection_s **con, unsigned int *adrflags, netadr_t *addresses, const char **adrparams, int maxaddresses); void *TLS_GetKnownCertificate(const char *certname, size_t *size); +void *Auth_GetKnownCertificate(const char *certname, size_t *size); vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server); int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize); //datasize should be preinitialised to the max length allowed. -1 for not implemented. 0 for peer problems. 1 for success #ifdef HAVE_PACKET diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index ba2f2d4b..da6448ef 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -4649,15 +4649,15 @@ static void QCBUILTIN PF_digest_internal (pubprogfuncs_t *prinst, struct globalv } //md5? else if (!strcmp(hashtype, "SHA1")) - { - digestsize = SHA1(digest, sizeof(digest), str, len); - } -// else if (!strcmp(hashtype, "SHA256")) -// { -// digestsize = SHA2(digest, sizeof(digest), str, len); -// } - //sha384 - //sha512 + digestsize = CalcHash(&hash_sha1, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA224")) + digestsize = CalcHash(&hash_sha224, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA256")) + digestsize = CalcHash(&hash_sha256, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA384")) + digestsize = CalcHash(&hash_sha384, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA512")) + digestsize = CalcHash(&hash_sha512, digest, sizeof(digest), str, len); else if (!strcmp(hashtype, "CRC16")) { digestsize = 2; diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 77b99bd9..5acb11d2 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -1727,7 +1727,7 @@ Rendering functions (Client only) extern int r_dlightframecount; //goes through the nodes marking the surfaces near the dynamic light as lit. -void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node) +void Q1BSP_MarkLights (dlight_t *light, dlightbitmask_t bit, mnode_t *node) { mplane_t *splitplane; float dist; diff --git a/engine/common/sha1.c b/engine/common/sha1.c index 4fd13863..ac7dfe3b 100644 --- a/engine/common/sha1.c +++ b/engine/common/sha1.c @@ -14,11 +14,20 @@ A million repetitions of "a" This file came to FTE via EzQuake. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ -#define SHA1HANDSOFF #include "quakedef.h" #include +/* #define SHA1HANDSOFF * Copies data before messing with it. */ +#define SHA1HANDSOFF + +typedef struct +{ + unsigned int state[5]; + size_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; +#define SHA1_DIGEST_SIZE 20 + #define BigLong(l) (((unsigned char*)&l)[0]<<24) | (((unsigned char*)&l)[1]<<16) | (((unsigned char*)&l)[2]<<8) | (((unsigned char*)&l)[3]<<0) @@ -36,23 +45,9 @@ This file came to FTE via EzQuake. #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); -typedef struct -{ - unsigned int state[5]; - size_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -#define DIGEST_SIZE 20 -void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, size_t len); -void SHA1Final(unsigned char digest[DIGEST_SIZE], SHA1_CTX* context); - - /* Hash a single 512-bit block. This is the core of the algorithm. */ -void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]) +static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]) { unsigned int a, b, c, d, e; typedef union @@ -108,8 +103,9 @@ void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]) /* SHA1Init - Initialize new context */ -void SHA1Init(SHA1_CTX* context) +static void SHA1Init(void *ctx) { + SHA1_CTX *context = ctx; /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; @@ -122,8 +118,9 @@ void SHA1Init(SHA1_CTX* context) /* Run your data through this. */ -void SHA1Update(SHA1_CTX* context, const unsigned char* data, size_t len) +static void SHA1Update(void *ctx, const void* data, size_t len) { + SHA1_CTX *context = ctx; size_t i, j; j = (context->count[0] >> 3) & 63; @@ -135,20 +132,21 @@ void SHA1Update(SHA1_CTX* context, const unsigned char* data, size_t len) SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); + SHA1Transform(context->state, (const qbyte*)data + i); } j = 0; } else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); + memcpy(&context->buffer[j], (const qbyte*)data + i, len - i); } /* Add padding and return the message digest. */ -void SHA1Final(unsigned char digest[DIGEST_SIZE], SHA1_CTX* context) +static void SHA1Final(unsigned char digest[SHA1_DIGEST_SIZE], void *ctx) { + SHA1_CTX *context = ctx; unsigned int i, j; unsigned char finalcount[8]; @@ -162,7 +160,7 @@ void SHA1Final(unsigned char digest[DIGEST_SIZE], SHA1_CTX* context) SHA1Update(context, (unsigned char *)"\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < DIGEST_SIZE; i++) + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); @@ -178,33 +176,26 @@ memset(&finalcount, 0, 8); #endif } - -size_t SHA1(unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen) +hashfunc_t hash_sha1 = { - SHA1_CTX context; - if (maxdigestsize < DIGEST_SIZE) - return 0; + SHA1_DIGEST_SIZE, + sizeof(SHA1_CTX), + SHA1Init, + SHA1Update, + SHA1Final, +}; - SHA1Init(&context); - SHA1Update(&context, (unsigned char*) string, stringlen); - SHA1Final(digest, &context); - return DIGEST_SIZE; -} -size_t SHA1_m(unsigned char *digest, size_t maxdigestsize, size_t numstrings, const unsigned char **strings, size_t *stringlens) +size_t CalcHash(hashfunc_t *func, unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen) { - size_t i; - SHA1_CTX context; - if (maxdigestsize < DIGEST_SIZE) - return 0; - - SHA1Init(&context); - for (i = 0; i < numstrings; i++) - SHA1Update(&context, (unsigned char*) strings[i], stringlens[i]); - SHA1Final(digest, &context); - - return DIGEST_SIZE; + void *ctx = alloca(func->contextsize); + if (maxdigestsize < func->digestsize) + return 0; //panic + func->init(ctx); + func->process(ctx, string, stringlen); + func->terminate(digest, ctx); + return func->digestsize; } /* hmac-sha1.c -- hashed message authentication codes @@ -245,18 +236,23 @@ size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen) { -#define HMAC_DIGEST_MAXSIZE 20 - char optkeybuf[HMAC_DIGEST_MAXSIZE]; - char innerhash[HMAC_DIGEST_MAXSIZE]; +#define HMAC_DIGEST_MAXSIZE 64 + qbyte optkeybuf[HMAC_DIGEST_MAXSIZE]; + qbyte innerhash[HMAC_DIGEST_MAXSIZE]; - char block[64]; - size_t innerhashsize; + qbyte block[64]; + + if (hashfunc->digestsize > HMAC_DIGEST_MAXSIZE || hashfunc->digestsize > maxdigestsize) + return 0; /* Reduce the key's size, so that it is never larger than a block. */ if (keylen > sizeof(block)) { - keylen = hashfunc(optkeybuf, sizeof(optkeybuf), 1, &key, &keylen); + qbyte *ctx = alloca(hashfunc->contextsize); + hashfunc->init(ctx); + hashfunc->process(ctx, key, keylen); + hashfunc->terminate(optkeybuf, ctx); key=optkeybuf; } @@ -266,9 +262,11 @@ size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, memxor (block, key, keylen); { - const unsigned char *strings_i[2] = {block, data}; - size_t stringlens_i[2] = {sizeof(block), datalen}; - innerhashsize = hashfunc(innerhash, sizeof(innerhash), 2, strings_i, stringlens_i); + qbyte *ctx = alloca(hashfunc->contextsize); + hashfunc->init(ctx); + hashfunc->process(ctx, block, sizeof(block)); + hashfunc->process(ctx, data, datalen); + hashfunc->terminate(innerhash, ctx); } /* Compute result from KEY and INNERHASH. */ @@ -277,8 +275,11 @@ size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, memxor (block, key, keylen); { - const unsigned char *strings_o[2] = {block, innerhash}; - size_t stringlens_o[2] = {sizeof(block), innerhashsize}; - return hashfunc(digest, maxdigestsize, 2, strings_o, stringlens_o); + qbyte *ctx = alloca(hashfunc->contextsize); + hashfunc->init(ctx); + hashfunc->process(ctx, block, sizeof(block)); + hashfunc->process(ctx, innerhash, hashfunc->digestsize); + hashfunc->terminate(digest, ctx); + return hashfunc->digestsize; } } diff --git a/engine/common/sha2.c b/engine/common/sha2.c new file mode 100644 index 00000000..549a5c46 --- /dev/null +++ b/engine/common/sha2.c @@ -0,0 +1,563 @@ +/* sha512.c - SHA384 and SHA512 hash functions + * Copyright (C) 2003, 2008, 2009 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + + +/* Test vectors from FIPS-180-2: + * + * "abc" + * 384: + * CB00753F 45A35E8B B5A03D69 9AC65007 272C32AB 0EDED163 + * 1A8B605A 43FF5BED 8086072B A1E7CC23 58BAECA1 34C825A7 + * 512: + * DDAF35A1 93617ABA CC417349 AE204131 12E6FA4E 89A97EA2 0A9EEEE6 4B55D39A + * 2192992A 274FC1A8 36BA3C23 A3FEEBBD 454D4423 643CE80E 2A9AC94F A54CA49F + * + * "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + * 384: + * 09330C33 F71147E8 3D192FC7 82CD1B47 53111B17 3B3B05D2 + * 2FA08086 E3B0F712 FCC7C71A 557E2DB9 66C3E9FA 91746039 + * 512: + * 8E959B75 DAE313DA 8CF4F728 14FC143F 8F7779C6 EB9F7FA1 7299AEAD B6889018 + * 501D289E 4900F7E4 331B99DE C4B5433A C7D329EE B6DD2654 5E96E55B 874BE909 + * + * "a" x 1000000 + * 384: + * 9D0E1809 716474CB 086E834E 310A4A1C ED149E9C 00F24852 + * 7972CEC5 704C2A5B 07B8B3DC 38ECC4EB AE97DDD8 7F3D8985 + * 512: + * E718483D 0CE76964 4E2E42C7 BC15B463 8E1F98B1 3B204428 5632A803 AFA973EB + * DE0FF244 877EA60A 4CB0432C E577C31B EB009C5C 2C49AA2E 4EADB217 AD8CC09B + */ + +#include "quakedef.h" + +#ifndef SHA2 +#define SHA2 256 +#include "sha2.c" +#undef SHA2 +#define SHA2 512 +#endif + +#undef U64_C +#undef U64_C_LOW +#undef u64 +#undef ROUNDS +#undef SHA2_CONTEXT +#undef sha2trunc_init +#undef sha2_init +#if SHA2==256 + #define U64_C(n) (n##ull>>32) + #define U64_C_LOW(n) (u64)U64_C(n) + #define u64 quint32_t + #define ROUNDS 64 + #define SHA2_CONTEXT SHA256_CONTEXT + #define sha2trunc_init sha224_init + #define sha2_init sha256_init +#else + #define U64_C(n) n##ull + #define U64_C_LOW(n) n##ull + #define u64 quint64_t + #define ROUNDS 80 + #define SHA2_CONTEXT SHA512_CONTEXT + #define ROTR ROTR64 + #define Ch Ch64 + #define Maj Maj64 + #define Sum0 Sum0_64 + #define Sum1 Sum1_64 + #define transform transform_64 + #define sha2trunc_init sha384_init + #define sha2_init sha512_init + #define sha2_write sha512_write + #define sha2_final sha512_final +#endif +#define BLOCKBYTES (16*sizeof(u64)) +#define byte qbyte + +typedef struct +{ + u64 h0, h1, h2, h3, h4, h5, h6, h7; + u64 nblocks; + byte buf[BLOCKBYTES]; + int count; +} SHA2_CONTEXT; + +static void +sha2_init (void *context) +{ + SHA2_CONTEXT *hd = context; + + hd->h0 = U64_C(0x6a09e667f3bcc908); + hd->h1 = U64_C(0xbb67ae8584caa73b); + hd->h2 = U64_C(0x3c6ef372fe94f82b); + hd->h3 = U64_C(0xa54ff53a5f1d36f1); + hd->h4 = U64_C(0x510e527fade682d1); + hd->h5 = U64_C(0x9b05688c2b3e6c1f); + hd->h6 = U64_C(0x1f83d9abfb41bd6b); + hd->h7 = U64_C(0x5be0cd19137e2179); + + hd->nblocks = 0; + hd->count = 0; +} +static void sha2trunc_init (void *context) +{ + SHA2_CONTEXT *hd = context; + + //sha224 uses only the low parts. + hd->h0 = U64_C_LOW(0xcbbb9d5dc1059ed8); + hd->h1 = U64_C_LOW(0x629a292a367cd507); + hd->h2 = U64_C_LOW(0x9159015a3070dd17); + hd->h3 = U64_C_LOW(0x152fecd8f70e5939); + hd->h4 = U64_C_LOW(0x67332667ffc00b31); + hd->h5 = U64_C_LOW(0x8eb44a8768581511); + hd->h6 = U64_C_LOW(0xdb0c2e0d64f98fa7); + hd->h7 = U64_C_LOW(0x47b5481dbefa4fa4); + + hd->nblocks = 0; + hd->count = 0; +} + +static inline u64 +ROTR (u64 x, u64 n) +{ + return ((x >> n) | (x << (64 - n))); +} + +static inline u64 +Ch (u64 x, u64 y, u64 z) +{ + return ((x & y) ^ ( ~x & z)); +} + +static inline u64 +Maj (u64 x, u64 y, u64 z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} + +#undef S0 +#undef S1 +#if SHA2==256 +#define S0(x) (ROTR((x),7) ^ ROTR((x),18) ^ ((x)>>3)) +#define S1(x) (ROTR((x),17) ^ ROTR((x),19) ^ ((x)>>10)) + +static inline u64 +Sum0 (u64 x) +{ + return (ROTR (x, 2) ^ ROTR (x, 13) ^ ROTR (x, 22)); +} + +static inline u64 +Sum1 (u64 x) +{ + return (ROTR (x, 6) ^ ROTR (x, 11) ^ ROTR (x, 25)); +} +#else +#define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) +#define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + +static inline u64 +Sum0 (u64 x) +{ + return (ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39)); +} + +static inline u64 +Sum1 (u64 x) +{ + return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41)); +} +#endif + +/**************** + * Transform the message W which consists of 16 64-bit-words + */ +static void +transform (SHA2_CONTEXT *hd, const unsigned char *data) +{ + u64 a, b, c, d, e, f, g, h; + u64 w[ROUNDS]; + int t; + static const u64 k[] = + { + U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd), + U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc), + U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019), + U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118), + U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe), + U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2), + U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1), + U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694), + U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3), + U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65), + U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483), + U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5), + U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210), + U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4), + U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725), + U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70), + U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926), + U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df), + U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8), + U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b), + U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001), + U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30), + U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910), + U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8), + U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53), + U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8), + U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb), + U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3), + U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60), + U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec), + U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9), + U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b), + U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207), + U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178), + U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6), + U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b), + U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493), + U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c), + U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a), + U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817) + }; + + /* get values from the chaining vars */ + a = hd->h0; + b = hd->h1; + c = hd->h2; + d = hd->h3; + e = hd->h4; + f = hd->h5; + g = hd->h6; + h = hd->h7; + +#ifdef WORDS_BIGENDIAN + memcpy (w, data, BLOCKBYTES); +#else + { + int i; + byte *p2; + + for (i = 0, p2 = (byte *) w; i < 16; i++, p2 += sizeof(*w)) + { +#if SHA2==512 + p2[7] = *data++; + p2[6] = *data++; + p2[5] = *data++; + p2[4] = *data++; +#endif + p2[3] = *data++; + p2[2] = *data++; + p2[1] = *data++; + p2[0] = *data++; + } + } +#endif + + for (t = 16; t < ROUNDS; t++) + w[t] = S1 (w[t - 2]) + w[t - 7] + S0 (w[t - 15]) + w[t - 16]; + + + for (t = 0; t < ROUNDS; ) + { + u64 t1, t2; + + /* Performance on a AMD Athlon(tm) Dual Core Processor 4050e + with gcc 4.3.3 using gcry_md_hash_buffer of each 10000 bytes + initialized to 0,1,2,3...255,0,... and 1000 iterations: + Not unrolled with macros: 440ms + Unrolled with macros: 350ms + Unrolled with inline: 330ms + */ +#if 0 /* Not unrolled. */ + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; + t2 = Sum0 (a) + Maj (a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; +#else /* Unrolled to interweave the chain variables. */ + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; + t2 = Sum0 (a) + Maj (a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[t+1]; + t2 = Sum0 (h) + Maj (h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[t+2]; + t2 = Sum0 (g) + Maj (g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[t+3]; + t2 = Sum0 (f) + Maj (f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[t+4]; + t2 = Sum0 (e) + Maj (e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[t+5]; + t2 = Sum0 (d) + Maj (d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[t+6]; + t2 = Sum0 (c) + Maj (c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[t+7]; + t2 = Sum0 (b) + Maj (b, c, d); + e += t1; + a = t1 + t2; + + t += 8; +#endif + } + + /* Update chaining vars. */ + hd->h0 += a; + hd->h1 += b; + hd->h2 += c; + hd->h3 += d; + hd->h4 += e; + hd->h5 += f; + hd->h6 += g; + hd->h7 += h; +} + + +/* Update the message digest with the contents + * of INBUF with length INLEN. + */ +static void +sha2_write (void *context, const void *inbuf_arg, size_t inlen) +{ + const unsigned char *inbuf = inbuf_arg; + SHA2_CONTEXT *hd = context; + + if (hd->count == BLOCKBYTES) + { /* flush the buffer */ + transform (hd, hd->buf); + hd->count = 0; + hd->nblocks++; + } + if (!inbuf) + return; + if (hd->count) + { + for (; inlen && hd->count < BLOCKBYTES; inlen--) + hd->buf[hd->count++] = *inbuf++; + sha2_write (context, NULL, 0); + if (!inlen) + return; + } + + while (inlen >= BLOCKBYTES) + { + transform (hd, inbuf); + hd->count = 0; + hd->nblocks++; + inlen -= BLOCKBYTES; + inbuf += BLOCKBYTES; + } + for (; inlen && hd->count < BLOCKBYTES; inlen--) + hd->buf[hd->count++] = *inbuf++; +} + + +/* The routine final terminates the computation and + * returns the digest. + * The handle is prepared for a new cycle, but adding bytes to the + * handle will the destroy the returned buffer. + * Returns: 64 bytes representing the digest. When used for sha384, + * we take the leftmost 48 of those bytes. + */ + +static void +sha2_final (void *context) +{ + SHA2_CONTEXT *hd = context; + u64 t, msb, lsb; + byte *p; + + sha2_write (context, NULL, 0); /* flush */ ; + + t = hd->nblocks; + /* multiply by 128 to make a byte count */ + lsb = t * BLOCKBYTES; + msb = t >> (sizeof(u64)*8-((BLOCKBYTES==128)?7:6)); + /* add the count */ + t = lsb; + if ((lsb += hd->count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> (sizeof(u64)*8-3); + + if (hd->count < BLOCKBYTES-sizeof(u64)*2) + { /* enough room */ + hd->buf[hd->count++] = 0x80; /* pad */ + while (hd->count < BLOCKBYTES-sizeof(u64)*2) + hd->buf[hd->count++] = 0; /* pad */ + } + else + { /* need one extra block */ + hd->buf[hd->count++] = 0x80; /* pad character */ + while (hd->count < BLOCKBYTES) + hd->buf[hd->count++] = 0; + sha2_write (context, NULL, 0); /* flush */ ; + memset (hd->buf, 0, BLOCKBYTES-sizeof(u64)*2); /* fill next block with zeroes */ + } + +#if SHA2==256 +#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ + *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) + + /* append the 128 bit count */ + hd->buf[56] = msb >> 24; + hd->buf[57] = msb >> 16; + hd->buf[58] = msb >> 8; + hd->buf[59] = msb; + + hd->buf[60] = lsb >> 24; + hd->buf[61] = lsb >> 16; + hd->buf[62] = lsb >> 8; + hd->buf[63] = lsb; +#else +#define X(a) do { *p++ = hd->h##a >> 56; *p++ = hd->h##a >> 48; \ + *p++ = hd->h##a >> 40; *p++ = hd->h##a >> 32; \ + *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ + *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) + + /* append the 128 bit count */ + hd->buf[112] = msb >> 56; + hd->buf[113] = msb >> 48; + hd->buf[114] = msb >> 40; + hd->buf[115] = msb >> 32; + hd->buf[116] = msb >> 24; + hd->buf[117] = msb >> 16; + hd->buf[118] = msb >> 8; + hd->buf[119] = msb; + + hd->buf[120] = lsb >> 56; + hd->buf[121] = lsb >> 48; + hd->buf[122] = lsb >> 40; + hd->buf[123] = lsb >> 32; + hd->buf[124] = lsb >> 24; + hd->buf[125] = lsb >> 16; + hd->buf[126] = lsb >> 8; + hd->buf[127] = lsb; +#endif + transform (hd, hd->buf); + + p = hd->buf; +#ifdef WORDS_BIGENDIAN +#undef X +#define X(a) do { *(u64*)p = hd->h##a ; p += sizeof(u64); } while (0) +#endif + X (0); + X (1); + X (2); + X (3); + X (4); + X (5); + /* Note that these last two chunks are included even for SHA384. + We just ignore them. */ + X (6); + X (7); +#undef X +} + +#if SHA2==256 +static void sha224_finish (qbyte *digest, void *context) +{ + SHA2_CONTEXT *hd = (SHA2_CONTEXT *) context; + sha2_final(context); + memcpy(digest, hd->buf, 224/8); //only the first 224 bits of the result... +} +static void sha256_finish (qbyte *digest, void *context) +{ + SHA2_CONTEXT *hd = (SHA2_CONTEXT *) context; + sha2_final(context); + memcpy(digest, hd->buf, 256/8); +} + +hashfunc_t hash_sha224 = +{ + 224/8, + sizeof(SHA2_CONTEXT), + sha224_init, + sha2_write, + sha224_finish +}; +hashfunc_t hash_sha256 = +{ + 256/8, + sizeof(SHA2_CONTEXT), + sha256_init, + sha2_write, + sha256_finish +}; +#endif +#if SHA2==512 +static void sha384_finish (qbyte *digest, void *context) +{ + SHA2_CONTEXT *hd = (SHA2_CONTEXT *) context; + sha2_final(context); + memcpy(digest, hd->buf, 384/8); +} + +static void sha512_finish (qbyte *digest, void *context) +{ + SHA2_CONTEXT *hd = (SHA2_CONTEXT *) context; + sha2_final(context); + memcpy(digest, hd->buf, 512/8); +} + +hashfunc_t hash_sha384 = +{ + 384/8, + sizeof(SHA2_CONTEXT), + sha384_init, + sha2_write, + sha384_finish +}; +hashfunc_t hash_sha512 = +{ + 512/8, + sizeof(SHA2_CONTEXT), + sha512_init, + sha2_write, + sha512_finish +}; +#endif diff --git a/engine/common/sys.h b/engine/common/sys.h index c2c05b02..e922ed02 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -182,17 +182,21 @@ void NPQTV_Sys_MainLoop(void); #define UPD_STABLE 1 #define UPD_TESTING 2 -#if defined(WEBCLIENT) && defined(_WIN32) && !defined(SERVERONLY) && !defined(_XBOX) -int StartLocalServer(int close); +#if defined(WEBCLIENT) && defined(PACKAGEMANAGER) + #if defined(_WIN32) && !defined(SERVERONLY) && !defined(_XBOX) + #define HAVEAUTOUPDATE + #endif + #if defined(__linux__) && !defined(ANDROID) + #define HAVEAUTOUPDATE + #endif +#endif -#define HAVEAUTOUPDATE -qboolean Sys_SetUpdatedBinary(const char *fname); //legacy, so old build can still deal with updates properly -qboolean Sys_EngineMayUpdate(void); //says whether the system code is able to invoke new binaries properly -//qboolean Sys_EngineWasUpdated(char *newbinary); //invoke the given system-path binary +#ifdef HAVEAUTOUPDATE +qboolean Sys_SetUpdatedBinary(const char *fname); //attempts to overwrite the working binary. +qboolean Sys_EngineMayUpdate(void); //says whether the system code is able/allowed to overwrite itself. #else #define Sys_EngineMayUpdate() false #define Sys_SetUpdatedBinary(n) false -//#define Sys_EngineWasUpdated(n) false #endif void Sys_Init (void); diff --git a/engine/common/sys_linux_threads.c b/engine/common/sys_linux_threads.c index d080a501..b6a8749a 100644 --- a/engine/common/sys_linux_threads.c +++ b/engine/common/sys_linux_threads.c @@ -546,3 +546,100 @@ void SSV_CheckFromMaster(void) } } #endif + + + + + +#ifdef HAVEAUTOUPDATE +#include +#include +qboolean Sys_SetUpdatedBinary(const char *newbinary) +{ + char enginebinary[MAX_OSPATH]; + char tmpbinary[MAX_OSPATH]; +// char enginebinarybackup[MAX_OSPATH+4]; +// size_t len; + int i; + struct stat src, dst; + + //windows is annoying. we can't delete a file that's in use (no orphaning) + //we can normally rename it to something else before writing a new file with the original name. + //then delete the old file later (sadly only on reboot) + + //get the binary name + i = readlink("/proc/self/exe", enginebinary, sizeof(enginebinary)-1); + if (i <= 0) + return false; + enginebinary[i] = 0; + + //generate the temp name + /*memcpy(enginebinarybackup, enginebinary, sizeof(enginebinary)); + len = strlen(enginebinarybackup); + if (len > 4 && !strcasecmp(enginebinarybackup+len-4, ".bin")) + len -= 4; //swap its extension over, if we can. + strcpy(enginebinarybackup+len, ".bak");*/ + + //copy over file permissions (don't ignore the user) + if (stat(enginebinary, &dst)<0) + dst.st_mode = 0777; + if (stat(newbinary, &src)<0) + src.st_mode = 0777; + +// if (src.st_dev != dst.st_dev) + { //oops, its on a different filesystem. create a copy + Q_snprintfz(tmpbinary, sizeof(tmpbinary), "%s.new", enginebinary); + if (!FS_Copy(newbinary, tmpbinary, FS_SYSTEM, FS_SYSTEM)) + return false; + newbinary = tmpbinary; + } + chmod(newbinary, dst.st_mode|S_IXUSR); //but make sure its executable, just in case... + + //overwrite the name we were started through. this is supposed to be atomic. + if (rename(newbinary, enginebinary) < 0) + { + Con_Printf("Failed to overwrite %s with %s\n", enginebinary, newbinary); + return false; //failed + } + return true; //succeeded. +} +qboolean Sys_EngineMayUpdate(void) +{ + char enginebinary[MAX_OSPATH]; + char *e; + int len; + +#define SVNREVISIONSTR STRINGIFY(SVNREVISION) + if (!COM_CheckParm("-allowupdate")) + { + //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. + if (!strcmp(SVNREVISIONSTR, "-")) + return false; + + //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified. + //either way, its bad and autoupdates when we don't know what we're updating from is a bad idea. + strtoul(SVNREVISIONSTR, &e, 10); + if (!*SVNREVISIONSTR || *e) + return false; + } + + //update blocked via commandline + if (COM_CheckParm("-noupdate") || COM_CheckParm("--noupdate") || COM_CheckParm("-noautoupdate") || COM_CheckParm("--noautoupdate")) + return false; + + + //check that we can actually do it. + len = readlink("/proc/self/exe", enginebinary, sizeof(enginebinary)-1); + if (len <= 0) + return false; + enginebinary[len] = 0; + if (access(enginebinary, R_OK|W_OK|X_OK) < 0) + return false; //can't write it. don't try downloading updates. + *COM_SkipPath(enginebinary) = 0; + if (access(enginebinary, R_OK|W_OK) < 0) + return false; //can't write to the containing directory. this does not bode well for moves/overwrites. + + + return true; +} +#endif diff --git a/engine/common/zone.h b/engine/common/zone.h index 8832422d..528a19f7 100644 --- a/engine/common/zone.h +++ b/engine/common/zone.h @@ -93,6 +93,12 @@ Zone block void Memory_Init (void); void Memory_DeInit(void); +//Prefixes: +//Z - just general 'zone' memory. +//B - allocated memory is not zero-filled. +//F - allocation can return NULL (otherwise sys_errors) +//G - special set of functions with its own rules. Frees must not be mixed. +//Tag - additional special set of functions with their own rules. Frees must not be mixed. void VARGS Z_Free (void *ptr); void *Z_Malloc (size_t size); // returns 0 filled memory void *ZF_Malloc (size_t size); // allowed to fail diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 00e93755..03e226b4 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1354,6 +1354,13 @@ static struct charcache_s *Font_GetChar(font_t *f, unsigned int codepoint) return &tc; } + if (charidx == 0x00a0) //nbsp + { + c = Font_GetCharIfLoaded(f, ' '); + if (c) + return c; + } + //not cached, can't get. c = Font_TryLoadGlyph(f, charidx); diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 99b321da..412c3bdd 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -4365,7 +4365,7 @@ void Heightmap_LightPointValues (model_t *mod, const vec3_t point, vec3_t res_di void Heightmap_StainNode (mnode_t *node, float *parms) { } -void Heightmap_MarkLights (dlight_t *light, int bit, mnode_t *node) +void Heightmap_MarkLights (dlight_t *light, dlightbitmask_t bit, mnode_t *node) { } diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index abd66abc..98c10cb2 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -590,7 +590,7 @@ void HL_SetupBones(hlmodel_t *model, int seqnum, int firstbone, int lastbone, fl return; } if (!model->animcache[sequence->seqindex]) - model->animcache[sequence->seqindex] = FS_LoadMallocGroupFile(model->memgroup, sequencedata->name+32, &fz); + model->animcache[sequence->seqindex] = FS_LoadMallocGroupFile(model->memgroup, sequencedata->name+32, &fz, true); if (!model->animcache[sequence->seqindex] || model->animcache[sequence->seqindex]->magic != (('I'<<0)|('D'<<8)|('S'<<16)|('Q'<<24)) || model->animcache[sequence->seqindex]->version != 10) { Sys_Error("Unable to load %s\n", sequencedata->name+32); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index c3d0e9af..dcf9f017 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1159,7 +1159,7 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b) char altname[MAX_QPATH]; Q_snprintfz(altname, sizeof(altname), "%s.%s", mdlbase, token); TRACE(("Mod_LoadModel: Trying to load (replacement) model \"%s\"\n", altname)); - buf = (unsigned *)FS_LoadMallocFile (altname, &filesize); + buf = (unsigned *)FS_LoadMallocGroupFile(NULL, altname, &filesize, true); if (buf) Q_strncpyz(mod->name, altname, sizeof(mod->name)); @@ -1167,7 +1167,7 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b) else { TRACE(("Mod_LoadModel: Trying to load model \"%s\"\n", mod->publicname)); - buf = (unsigned *)FS_LoadMallocFile (mod->publicname, &filesize); + buf = (unsigned *)FS_LoadMallocGroupFile(NULL, mod->publicname, &filesize, true); if (buf) Q_strncpyz(mod->name, mod->publicname, sizeof(mod->name)); else if (!buf) @@ -1682,7 +1682,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, Q_snprintfz(litname, sizeof(litname), litnames[best].pattern, litbase); else Q_snprintfz(litname, sizeof(litname), litnames[best].pattern, litbasep); - litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize); + litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize, false); } else { @@ -1832,7 +1832,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, Q_strncpyz(luxname, loadmodel->name, sizeof(luxname)); COM_StripExtension(loadmodel->name, luxname, sizeof(luxname)); COM_DefaultExtension(luxname, ".lux", sizeof(luxname)); - luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz); + luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz, false); luxtmp = false; } if (!luxdata) @@ -1841,14 +1841,14 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, COM_StripExtension(COM_SkipPath(loadmodel->name), luxname+5, sizeof(luxname)-5); Q_strncatz(luxname, ".lux", sizeof(luxname)); - luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz); + luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz, false); luxtmp = false; } if (!luxdata) //dp... { COM_StripExtension(loadmodel->name, luxname, sizeof(luxname)); COM_DefaultExtension(luxname, ".dlit", sizeof(luxname)); - luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz); + luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz, false); luxtmp = false; } //make sure the .lux has the correct size @@ -1974,8 +1974,8 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, overrides->stylesperface = size / (sizeof(*overrides->styles16)*loadmodel->numsurfaces); //rounding issues will be caught on the next line... if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles16)*overrides->stylesperface) overrides->styles16 = NULL; - else if (overrides->stylesperface > MAXQ1LIGHTMAPS) - Con_Printf(CON_WARNING "LMSTYLE16 lump provides %i styles, only the first %i will be used.\n", overrides->stylesperface, MAXQ1LIGHTMAPS); + else if (overrides->stylesperface > MAXCPULIGHTMAPS) + Con_Printf(CON_WARNING "LMSTYLE16 lump provides %i styles, only the first %i will be used.\n", overrides->stylesperface, MAXCPULIGHTMAPS); } if (!overrides->styles8 && !overrides->styles16) { //16bit per-face lightmap styles index @@ -1984,8 +1984,8 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, overrides->stylesperface = size / (sizeof(*overrides->styles8)*loadmodel->numsurfaces); //rounding issues will be caught on the next line... if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles8)*overrides->stylesperface) overrides->styles8 = NULL; - else if (overrides->stylesperface > MAXQ1LIGHTMAPS) - Con_Printf(CON_WARNING "LMSTYLE lump provides %i styles, only the first %i will be used.\n", overrides->stylesperface, MAXQ1LIGHTMAPS); + else if (overrides->stylesperface > MAXCPULIGHTMAPS) + Con_Printf(CON_WARNING "LMSTYLE lump provides %i styles, only the first %i will be used.\n", overrides->stylesperface, MAXCPULIGHTMAPS); } } diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 2c552a63..d7099dcb 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -254,7 +254,7 @@ typedef struct { void (*LightPointValues) (struct model_s *model, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); void (*StainNode) (struct mnode_s *node, float *parms); - void (*MarkLights) (struct dlight_s *light, int bit, struct mnode_s *node); + void (*MarkLights) (struct dlight_s *light, dlightbitmask_t bit, struct mnode_s *node); int (*ClusterForPoint) (struct model_s *model, const vec3_t point, int *areaout); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs). qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge); @@ -437,20 +437,22 @@ typedef struct msurface_s batch_t *sbatch; mtexinfo_t *texinfo; int visframe; // should be drawn when node is crossed +#ifdef RTLIGHTS int shadowframe; - int clipcount; +#endif +// int clipcount; // legacy lighting info + dlightbitmask_t dlightbits; int dlightframe; - int dlightbits; + qboolean cached_dlight; // true if dynamic light in cache //static lighting int lightmaptexturenums[MAXRLIGHTMAPS]; //rbsp+fbsp formats have multiple lightmaps - lightstyleindex_t styles[MAXQ1LIGHTMAPS]; + lightstyleindex_t styles[MAXCPULIGHTMAPS]; qbyte vlstyles[MAXRLIGHTMAPS]; - int cached_light[MAXQ1LIGHTMAPS]; // values currently used in lightmap - int cached_colour[MAXQ1LIGHTMAPS]; // values currently used in lightmap - qboolean cached_dlight; // true if dynamic light in cache + int cached_light[MAXCPULIGHTMAPS]; // values currently used in lightmap + int cached_colour[MAXCPULIGHTMAPS]; // values currently used in lightmap #ifndef NOSTAINS qboolean stained; #endif @@ -565,7 +567,7 @@ void Fragment_ClipPoly(fragmentdecal_t *dec, int numverts, float *inverts, shade size_t Fragment_ClipPlaneToBrush(vecV_t *points, size_t maxpoints, void *planes, size_t planestride, size_t numplanes, vec4_t face); void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangent2, float size, unsigned int surfflagmask, unsigned int surflagmatch, void (*callback)(void *ctx, vec3_t *fte_restrict points, size_t numpoints, shader_t *shader), void *ctx); -void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node); +void Q1BSP_MarkLights (dlight_t *light, dlightbitmask_t bit, mnode_t *node); void GLQ1BSP_LightPointValues(struct model_s *model, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); qboolean Q1BSP_RecursiveHullCheck (hull_t *hull, int num, const vec3_t p1, const vec3_t p2, unsigned int hitcontents, struct trace_s *trace); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index cd708d21..c6c7aca0 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -2521,7 +2521,7 @@ static int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) { case LM_E5BGR9: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { unsigned int l = *(unsigned int*)lightmap; scale = d_lightstylevalue[surf->styles[maps]]; @@ -2534,7 +2534,7 @@ static int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) break; case LM_RGB8: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; r += max3(lightmap[0],lightmap[1],lightmap[2]) * scale; @@ -2543,7 +2543,7 @@ static int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) break; case LM_L8: lightmap += dt * ((surf->extents[0]>>surf->lmshift)+1) + ds; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; r += *lightmap * scale; @@ -2695,7 +2695,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<4; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { unsigned int lm = *(unsigned int*)lightmap; scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -2720,7 +2720,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -2743,7 +2743,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds); deluxmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -2770,7 +2770,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t { case LM_E5BGR9: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)<<2; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { unsigned int lm = *(unsigned int*)lightmap; scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -2786,7 +2786,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t break; case LM_RGB8: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds)*3; - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; @@ -2800,7 +2800,7 @@ static float *GLRecursiveLightPoint3C (model_t *mod, mnode_t *node, const vec3_t break; case LM_L8: lightmap += (dt * ((surf->extents[0]>>surf->lmshift)+1) + ds); - for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) + for (maps = 0 ; maps < MAXCPULIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]*overbright; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index a753ddd8..04bb8533 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -217,7 +217,7 @@ static float Com_FloatArgument(const char *shadername, char *arg, size_t arglen, #define HASH_SIZE 128 #define SPF_DEFAULT 0u /*quake3/fte internal*/ -#define SPF_PROGRAMIFY (1u<<0) /*quake3/fte internal*/ +#define SPF_PROGRAMIFY (1u<<0) /*automatically replace known glsl, pulling in additional textures+effects from a single primary pass*/ #define SPF_DOOM3 (1u<<1) /*any commands, args, etc, should be interpretted according to doom3's norms*/ typedef struct shaderparsestate_s diff --git a/engine/gl/ltface.c b/engine/gl/ltface.c index 34c90272..2f93cfe7 100644 --- a/engine/gl/ltface.c +++ b/engine/gl/ltface.c @@ -308,8 +308,8 @@ typedef struct llightinfo_s { struct relight_ctx_s *ctx; //relight context, shared between threads. - vec3_t lightmaps[MAXQ1LIGHTMAPS][SINGLEMAP]; - vec3_t lightnorm[MAXQ1LIGHTMAPS][SINGLEMAP]; + vec3_t lightmaps[MAXCPULIGHTMAPS][SINGLEMAP]; + vec3_t lightnorm[MAXCPULIGHTMAPS][SINGLEMAP]; int numlightstyles; vec_t *light; vec_t facedist; @@ -325,7 +325,7 @@ typedef struct llightinfo_s vec_t exactmins[2], exactmaxs[2]; int texmins[2], texsize[2]; - int lightstyles[MAXQ1LIGHTMAPS]; + int lightstyles[MAXCPULIGHTMAPS]; } llightinfo_t; const size_t lightthreadctxsize = sizeof(llightinfo_t); @@ -628,7 +628,7 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l) if (mapnum == l->numlightstyles) { // init a new light map #ifdef UTILITY - if (mapnum == MAXQ1LIGHTMAPS) + if (mapnum == MAXCPULIGHTMAPS) { printf ("WARNING: Too many light styles on a face\n"); return; @@ -715,7 +715,7 @@ static void FixMinlight (llightinfo_t *l) } if (i == l->numlightstyles) { - if (l->numlightstyles == MAXQ1LIGHTMAPS) + if (l->numlightstyles == MAXCPULIGHTMAPS) return; // oh well.. for (j=0 ; jnumsurfpt ; j++) { @@ -771,7 +771,7 @@ static unsigned int PackE5BRG9(vec3_t rgb) LightFace ============ */ -void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, lightstyleindex_t surf_styles[MAXQ1LIGHTMAPS], unsigned int *surf_expsamples, qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale) +void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, lightstyleindex_t surf_styles[MAXCPULIGHTMAPS], unsigned int *surf_expsamples, qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale) { int s, t; int i,c,ch; @@ -820,7 +820,7 @@ void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, lightstylein i = 0; #ifndef UTILITY - for (; surf_styles[i] != INVALID_LIGHTSTYLE && i < MAXQ1LIGHTMAPS; i++) + for (; surf_styles[i] != INVALID_LIGHTSTYLE && i < MAXCPULIGHTMAPS; i++) { l->lightstyles[i] = surf_styles[i]; memset(&l->lightmaps[i], 0, sizeof(l->lightmaps[i][0])*l->numsurfpt); @@ -828,7 +828,7 @@ void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, lightstylein } #endif l->numlightstyles = i; - for ( ; ilightstyles[i] = INVALID_LIGHTSTYLE; // @@ -853,7 +853,7 @@ void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, lightstylein // // save out the values // - for (i=0 ; i lightstyles[i]; diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 119cddca..d7564f07 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -4921,7 +4921,7 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string)); // externs->Printf ("to build a clean data tree: qcc -copy \n"); // externs->Printf ("to build a clean pak file: qcc -pak \n"); // externs->Printf ("to bsp all bmodels: qcc -bspmodels \n"); - externs->Printf ("-Kwasm causes FTEQCC to dump all asm to qc.asm\n"); + externs->Printf ("-Fwasm causes FTEQCC to dump all asm to qc.asm\n"); externs->Printf ("-O0 to disable optimisations\n"); externs->Printf ("-O1 to optimise for size\n"); externs->Printf ("-O2 to optimise more - some behaviours may change\n"); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 698108fc..0f7db70e 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -8606,17 +8606,6 @@ static void QCBUILTIN PF_h2rain_go(pubprogfuncs_t *prinst, struct globalvars_s * SV_MulticastProtExt (NULL, MULTICAST_ALL, pr_global_struct->dimension_send, 0, 0); } -static void QCBUILTIN PF_h2StopSound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - int channel; - edict_t *entity; - - entity = G_EDICT(prinst, OFS_PARM0); - channel = G_FLOAT(OFS_PARM1); - - SVQ1_StartSound (NULL, (wedict_t*)entity, channel, NULL, 1, 0, 0, 0, CF_SV_RELIABLE); -} - static void QCBUILTIN PF_h2updatesoundpos(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { Con_DPrintf("FTE-H2 FIXME: updatesoundpos not implemented\n"); @@ -8639,6 +8628,13 @@ static void QCBUILTIN PF_h2getstring(pubprogfuncs_t *prinst, struct globalvars_s RETURN_PSTRING(s); } #endif +static void QCBUILTIN PF_StopSound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + edict_t *entity = G_EDICT(prinst, OFS_PARM0); + int channel = G_FLOAT(OFS_PARM1); + + SVQ1_StartSound (NULL, (wedict_t*)entity, channel, NULL, 1, 0, 0, 0, CF_SV_RELIABLE); +} static void QCBUILTIN PF_RegisterTEnt(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -10732,10 +10728,12 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"precache_file4", PF_precache_file, 0, 0, 103, 0}, {"dowhiteflash", PF_h2whiteflash, 0, 0, 104, 0}, {"updatesoundpos", PF_h2updatesoundpos,0, 0, 105, 0}, - {"stopsound", PF_h2StopSound, 0, 0, 106, 0}, + {"stopsound", PF_StopSound, 0, 0, 106, 0, D("void(entity ent, float channel)", "Terminates playback of sounds on the specified entity-channel. CHAN_AUTO should not be used.")}, {"precache_model4", PF_precache_model, 0, 0, 116, 0},//please don't use... {"precache_sound4", PF_precache_sound, 0, 0, 117, 0}, +#else + {"stopsound", PF_StopSound, 0, 0, 0, 0, D("void(entity ent, float channel)", "Terminates playback of sounds on the specified entity-channel. CHAN_AUTO should not be used.")}, #endif {"tracebox", PF_traceboxdp, 0, 0, 0, 90, D("void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent)", "Exactly like traceline, but a box instead of a uselessly thin point. Acceptable sizes are limited by bsp format, q1bsp has strict acceptable size values.")}, diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index d2171043..584148e4 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -47,6 +47,7 @@ oh, wait, ktx no longer supports those properly. 13: 2009/june gamecode no longer aware of edict_t data (just 'qc' fields). 14: 2017/march gamedata_t.maxentities added 15: 2017/june for-64bit string indirection changes. added GAME_CLEAR_EDICT. +16: wasted_edict_t_size is finally 0 */ #define GAME_API_VERSION 15 #define GAME_API_VERSION_MIN 8 @@ -2279,6 +2280,7 @@ qboolean PR_LoadQ1QVM(void) gd.maxedicts = MAX_Q1QVM_EDICTS; } gd.maxedicts = bound(1, pr_maxedicts.ival, gd.maxedicts); + gd.maxedicts = bound(1, gd.maxedicts, MAX_EDICTS); qvm_api_version = gd.APIversion; if (!(GAME_API_VERSION_MIN <= qvm_api_version && qvm_api_version <= GAME_API_VERSION)) diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index a1754e33..80df50bd 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -444,7 +444,9 @@ static int QDECL ShowMapListExt (const char *name, qofs_t flags, time_t mtime, v static void SV_MapList_f(void) { COM_EnumerateFiles("maps/*.bsp", ShowMapList, NULL); + COM_EnumerateFiles("maps/*.bsp.gz", ShowMapListExt, NULL); COM_EnumerateFiles("maps/*.map", ShowMapListExt, NULL); + COM_EnumerateFiles("maps/*.map.gz", ShowMapListExt, NULL); COM_EnumerateFiles("maps/*.cm", ShowMapList, NULL); COM_EnumerateFiles("maps/*.hmp", ShowMapList, NULL); } @@ -474,7 +476,9 @@ static void SV_Map_c(int argn, const char *partial, struct xcommandargcompletion if (argn == 1) { COM_EnumerateFiles(va("maps/%s*.bsp", partial), CompleteMapList, ctx); + COM_EnumerateFiles(va("maps/%s*.bsp.gz", partial), CompleteMapListExt, ctx); COM_EnumerateFiles(va("maps/%s*.map", partial), CompleteMapListExt, ctx); + COM_EnumerateFiles(va("maps/%s*.map.gz", partial), CompleteMapListExt, ctx); COM_EnumerateFiles(va("maps/%s*.cm", partial), CompleteMapList, ctx); COM_EnumerateFiles(va("maps/%s*.hmp", partial), CompleteMapList, ctx); } @@ -718,7 +722,7 @@ void SV_Map_f (void) else #endif { - char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ /*"maps/%s.ent",*/ NULL}; + char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.bsp.gz", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ /*"maps/%s.ent",*/ NULL}; int i, j; for (i = 0; exts[i]; i++) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 85951e50..a198ba29 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1002,7 +1002,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, { //.map is commented out because quite frankly, they're a bit annoying when the engine loads the gpled start.map when really you wanted to just play the damn game intead of take it apart. //if you want to load a .map, just use 'map foo.map' instead. - char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ NULL}; + char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", NULL}; int depth, bestdepth; flocation_t loc; time_t filetime; @@ -1244,7 +1244,6 @@ MSV_OpenUserDatabase(); else if (svs.gametype == GT_QUAKE2) { int subs; - extern int map_checksum; extern cvar_t sv_airaccelerate; sv.stringsalloced = true; @@ -1256,10 +1255,7 @@ MSV_OpenUserDatabase(); sv.strings.configstring[Q2CS_AIRACCEL] = Z_StrDup("0"); // init map checksum config string but only for Q2/Q3 maps - if (sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3) - sv.strings.configstring[Q2CS_MAPCHECKSUM] = Z_StrDup(va("%i", map_checksum)); - else - sv.strings.configstring[Q2CS_MAPCHECKSUM] = Z_StrDup("0"); + sv.strings.configstring[Q2CS_MAPCHECKSUM] = Z_StrDup(va("%i", sv.world.worldmodel->checksum)); subs = sv.world.worldmodel->numsubmodels; if (subs > MAX_PRECACHE_MODELS-1) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index fa743d90..1e9ab193 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -3510,11 +3510,13 @@ static qboolean Rcon_Validate (void) intptr_t timediff; qbyte b; + const hashfunc_t *hashfunc = &hash_sha1; + void *hashctx = alloca(hashfunc->contextsize); + const size_t digestsize = 20; size_t i, k; unsigned char digest[512]; const unsigned char **tokens = alloca(sizeof(*tokens)*(Cmd_Argc()*2+5)); //overallocation in case argc is 0. - size_t *toksizes = alloca(sizeof(*toksizes)*(Cmd_Argc()*2+5)); //overallocation in case argc is 0. if (strlen(pass) > digestsize*2) { for (i = 0; pass[digestsize*2+i] && i < sizeof(time_t)*2; i++) @@ -3539,20 +3541,20 @@ static qboolean Rcon_Validate (void) tokens[5+i*2+0] = Cmd_Argv(i+2); tokens[5+i*2+1] = " "; //a trailing space is required. } + hashfunc->init(hashctx); for (k = 0; k < 5+i*2; k++) - toksizes[k] = strlen(tokens[k]); - if (digestsize > 0 && digestsize == SHA1_m(digest, sizeof(digest), k, tokens, toksizes)) + hashfunc->process(hashctx, tokens[k], strlen(tokens[k])); + hashfunc->terminate(digest, hashctx); + + for (i = 0;;i++) { - for (i = 0;;i++) - { - if (i == digestsize) - return true; - if (!pass[i*2+0] || !pass[i*2+1]) - break; //premature termination - b = dehex(pass[i*2+0])*16+dehex(pass[i*2+1]); - if (b != digest[i]) - break; - } + if (i == digestsize) + return true; + if (!pass[i*2+0] || !pass[i*2+1]) + break; //premature termination + b = dehex(pass[i*2+0])*16+dehex(pass[i*2+1]); + if (b != digest[i]) + break; } } } diff --git a/engine/server/sv_master.c b/engine/server/sv_master.c index 4bc68f75..e0be829a 100644 --- a/engine/server/sv_master.c +++ b/engine/server/sv_master.c @@ -43,7 +43,7 @@ typedef struct svm_server_s { int protover; unsigned int clients; unsigned int maxclients; - qboolean needpass; + int needpass; char hostname[48]; //just for our own listings. char mapname[16]; //just for our own listings. char gamedir[16]; //again... @@ -551,7 +551,7 @@ vfsfile_t *SVM_GenerateIndex(const char *requesthost, const char *fname) if (server) { QuakeCharsToHTML(hostname, sizeof(hostname), server->hostname, false); - VFS_PRINTF(f, "%s%s%s%s%s%s%u/%u\n", server->game?server->game->name:"Unknown", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), server->needpass?"🔒":"", hostname, server->gamedir, server->mapname, server->clients, server->maxclients); + VFS_PRINTF(f, "%s%s%s%s%s%s%u/%u\n", server->game?server->game->name:"Unknown", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), (server->needpass&1)?"🔒":"", hostname, server->gamedir, server->mapname, server->clients, server->maxclients); } else VFS_PRINTF(f, "?%s????/?\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &adr[count])); @@ -567,7 +567,19 @@ vfsfile_t *SVM_GenerateIndex(const char *requesthost, const char *fname) VFS_PRINTF(f, "%s", master_css); if (!strcmp(gamename, "UNKNOWN")) - VFS_PRINTF(f, "

Firewalled/NATed/Unresponsive/Congested (Misconfigured) Servers

\n"); + { + VFS_PRINTF(f, "

Unresponsive Servers

\n"); + VFS_PRINTF(f, "These servers have sent a heartbeat but have failed to respond to an appropriate query from a different port. This can happen when:
    " + "
  • Server is firewalled and all inbound packets are dropped. Try reconfiguring your firewall to allow packets to that process or port.
  • " + "
  • An intermediate router implements an Address/Port-Dependant-Filtering NAT. Try setting up port forwarding.
  • " + "
  • Outgoing connections are asynchronous with regard to port forwarding. Such servers will show with arbitrary ephemerial ports. Docker: you can supposedly work around this with --net=host.
  • " + "
  • Plain and simple packet loss, servers in this state for less than 5 mins may still be fine.
  • " + "
  • Server crashed or was reconfigured before it could respond.
  • " + "
  • MTU limits with failed defragmentation.
  • " + "
  • Routing table misconfiguration.
  • " + "
  • Other.
  • " + "
\n"); + } else VFS_PRINTF(f, "

Servers for %s

\n", QuakeCharsToHTML(tmpbuf, sizeof(tmpbuf), gamename, true)); @@ -587,7 +599,7 @@ vfsfile_t *SVM_GenerateIndex(const char *requesthost, const char *fname) else url = NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr); QuakeCharsToHTML(hostname, sizeof(hostname), server->hostname, false); - VFS_PRINTF(f, "%s%s%s%s%s%u/%u\n", url, server->needpass?"🔒":"", hostname, server->gamedir, server->mapname, server->clients, server->maxclients); + VFS_PRINTF(f, "%s%s%s%s%s%u/%u\n", url, (server->needpass&1)?"🔒":"", hostname, server->gamedir, server->mapname, server->clients, server->maxclients); clients += server->clients; maxclients += server->maxclients; } @@ -607,7 +619,7 @@ vfsfile_t *SVM_GenerateIndex(const char *requesthost, const char *fname) for (server = (game?game->firstserver:NULL); server; server = server->next) { if (server->brokerid) - VFS_PRINTF(f, "rtc:///%s \\maxclients\\%u\\clients\\%u\\hostname\\%s\\modname\\%s\\mapname\\%s%s\n", server->brokerid, server->maxclients, server->clients, server->hostname, server->gamedir, server->mapname, server->needpass?"\\needpass\\1":""); + VFS_PRINTF(f, "rtc:///%s \\maxclients\\%u\\clients\\%u\\hostname\\%s\\modname\\%s\\mapname\\%s\\needpass\\%i\n", server->brokerid, server->maxclients, server->clients, server->hostname, server->gamedir, server->mapname, server->needpass); else VFS_PRINTF(f, "%s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr)); } @@ -724,7 +736,7 @@ static svm_server_t *SVM_Heartbeat(const char *gamename, netadr_t *adr, int numc if (server) { //it still exists, renew it, but don't otherwise care too much. server->expiretime = validuntil; - return NULL; + return server; } game = SVM_FindGame("UNKNOWN", true); } @@ -813,7 +825,7 @@ void SVM_GenChallenge(char *out, size_t outsize, netadr_t *foradr) } //switch net_from's reported connection, so we reply from a different udp socket from the one a packet was received from. -static void SVM_SwitchQuerySocket(void) +static qboolean SVM_SwitchQuerySocket(void) { size_t c; //switch the info query to our other udp socket, so any firewall/nat over the server blocks it. @@ -829,9 +841,10 @@ static void SVM_SwitchQuerySocket(void) (svm_sockets->conn[c]->addrtype[0] == net_from.type || svm_sockets->conn[c]->addrtype[1] == net_from.type)) { //okay, looks like we should be able to respond on this one. lets see if their firewall stops us from finding out more about them. net_from.connum = c+1; - break; + return true; } } + return false; } static void SVM_ProcessUDPPacket(void) @@ -877,7 +890,7 @@ static void SVM_ProcessUDPPacket(void) line = MSG_ReadStringLine(); s = COM_Parse(line); if (!strcmp(com_token, "getservers") || !strcmp(com_token, "getserversExt")) - { //q3 + { //q3/dpmaster sizebuf_t sb; int ver; char *eos; @@ -892,7 +905,7 @@ static void SVM_ProcessUDPPacket(void) s = COM_ParseOut(s, game, sizeof(game)); ver = strtol(game, &eos, 0); if (*eos) - { //not a number, must have been a game name. + { //not a number, must have been a dpmaster game name. s = COM_Parse(s); ver = strtol(com_token, NULL, 0); } @@ -955,13 +968,19 @@ static void SVM_ProcessUDPPacket(void) else { //dp/q3/etc are annoying, but we can query from an emphemerial socket to check NAT rules. sizebuf_t sb; + netadr_t a; + char ourchallenge[256]; SVM_GenChallenge(ourchallenge, sizeof(ourchallenge), &net_from); svm.total.queries++; //placeholder listing... - SVM_Heartbeat(NULL, &net_from, 0, svm.time + sv_heartbeattimeout.ival); - SVM_SwitchQuerySocket(); + if (SVM_Heartbeat(NULL, &net_from, 0, svm.time + sv_heartbeattimeout.ival)) + a = net_from; + else + a.type = NA_INVALID; + if (!SVM_SwitchQuerySocket()) + a.type = NA_INVALID; memset(&sb, 0, sizeof(sb)); sb.maxsize = sizeof(net_message_buffer); @@ -970,6 +989,17 @@ static void SVM_ProcessUDPPacket(void) MSG_WriteString(&sb, va("getinfo %s\n", ourchallenge)); sb.cursize--; NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from); + + if (a.type != NA_INVALID) + { //they were unknown... send a special getinfo, so we can get their hostname while leaving them as 'unknown' + memset(&sb, 0, sizeof(sb)); + sb.maxsize = sizeof(net_message_buffer); + sb.data = net_message_buffer; + MSG_WriteLong(&sb, -1); + MSG_WriteString(&sb, va("getinfo ?%s\n", ourchallenge)); + sb.cursize--; + NET_SendPacket(svm_sockets, sb.cursize, sb.data, &a); + } } } else if (!strcmp(com_token, "infoResponse")) @@ -978,9 +1008,12 @@ static void SVM_ProcessUDPPacket(void) int clients; const char *game, *chal; svm_server_t *srv; + qboolean unknownresp = false; s = MSG_ReadStringLine(); svm.total.heartbeats++; chal = Info_ValueForKey(s, "challenge"); + unknownresp = *chal=='?'; + chal += unknownresp?1:0; SVM_GenChallenge(ourchallenge, sizeof(ourchallenge), &net_from); if (!strcmp(chal, ourchallenge)) { @@ -988,14 +1021,18 @@ static void SVM_ProcessUDPPacket(void) game = Info_ValueForKey(s, "gamename"); if (!*game) game = QUAKE3PROTOCOLNAME; + if (unknownresp) + game = NULL; //ignore the gamename and classify it as unknown. this won't break anything if we've already has a proper heartbeat from them. srv = SVM_Heartbeat(game, &net_from, clients, svm.time + sv_heartbeattimeout.ival); if (srv) { if (developer.ival) Info_Print(s, "\t"); - srv->protover = atoi(Info_ValueForKey(s, "protocol")); + srv->clients = clients; + if (game) + srv->protover = atoi(Info_ValueForKey(s, "protocol")); srv->maxclients = atoi(Info_ValueForKey(s, "sv_maxclients")); - srv->needpass = !!atoi(Info_ValueForKey(s, "needpass")); + srv->needpass = atoi(Info_ValueForKey(s, "needpass")); Q_strncpyz(srv->hostname, Info_ValueForKey(s, "hostname"), sizeof(srv->hostname)); Q_strncpyz(srv->gamedir, Info_ValueForKey(s, "modname"), sizeof(srv->gamedir)); Q_strncpyz(srv->mapname, Info_ValueForKey(s, "mapname"), sizeof(srv->mapname)); @@ -1058,7 +1095,7 @@ static void SVM_ProcessUDPPacket(void) Info_Print(s, "\t"); srv->protover = 3;//atoi(Info_ValueForKey(s, "protocol")); srv->maxclients = atoi(Info_ValueForKey(s, "maxclients")); - srv->needpass = !!atoi(Info_ValueForKey(s, "needpass")); + srv->needpass = atoi(Info_ValueForKey(s, "needpass")); Q_strncpyz(srv->hostname, Info_ValueForKey(s, "hostname"), sizeof(srv->hostname)); Q_strncpyz(srv->gamedir, Info_ValueForKey(s, "*gamedir"), sizeof(srv->gamedir)); Q_strncpyz(srv->mapname, Info_ValueForKey(s, "map"), sizeof(srv->mapname)); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 6bba9049..f3b60b24 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -451,7 +451,7 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade int digest[5]; Q_snprintfz(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); - SHA1((char*)digest, sizeof(digest), hash, strlen(hash)); + CalcHash(&hash_sha1, (char*)digest, sizeof(digest), hash, strlen(hash)); Q_snprintfz(hash, sizeof(hash), "%08X%08X%08X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]); p->hasauthed = !strcmp(password, hash); } diff --git a/engine/shaders/makevulkanblob.c b/engine/shaders/makevulkanblob.c index d6a896a0..7e1352a4 100644 --- a/engine/shaders/makevulkanblob.c +++ b/engine/shaders/makevulkanblob.c @@ -495,7 +495,7 @@ int main(int argc, const char **argv) if (argc == 1) { - printf("%s input.glsl output.fvb\n"); + printf("%s input.glsl output.fvb\n", argv[0]); return 1; } diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 6c1b7dbb..8a40227d 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -4312,9 +4312,11 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre #ifdef VK_EXT_debug_report qboolean havedebugreport = false; #endif - vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); + if (VK_SUCCESS!=vkEnumerateInstanceExtensionProperties(NULL, &count, NULL)) + count = 0; ext = malloc(sizeof(*ext)*count); - vkEnumerateInstanceExtensionProperties(NULL, &count, ext); + if (!ext || VK_SUCCESS!=vkEnumerateInstanceExtensionProperties(NULL, &count, ext)) + count = 0; for (i = 0; i < count && extensions_count < countof(extensions); i++) { Con_DLPrintf(2, " vki: %s\n", ext[i].extensionName); diff --git a/fteqtv/httpsv.c b/fteqtv/httpsv.c index 910801b1..d00bd382 100644 --- a/fteqtv/httpsv.c +++ b/fteqtv/httpsv.c @@ -1078,7 +1078,7 @@ void HTTPSV_GetMethod(cluster_t *cluster, oproxy_t *pend) unsigned char sha1digest[20]; char padkey[512]; snprintf(padkey, sizeof(padkey), "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key); - tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), padkey, strlen(padkey))); + tobase64(acceptkey, sizeof(acceptkey), sha1digest, CalcHash(&hash_sha1, sha1digest, sizeof(sha1digest), padkey, strlen(padkey))); snprintf(padkey, sizeof(padkey), "HTTP/1.1 101 Switching Protocols\r\n" diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index ccfdc88b..311518e3 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -238,8 +238,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. size_t strlcpy(char *dst, const char *src, size_t siz); -#define SHA1 SHA1_quake -size_t SHA1(unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen); + +typedef struct +{ + unsigned int digestsize; + unsigned int contextsize; //you need to alloca(te) this much memory... + void (*init) (void *context); + void (*process) (void *context, const void *data, size_t datasize); + void (*terminate) (unsigned char *digest, void *context); +} hashfunc_t; +extern hashfunc_t hash_sha1; +/*extern hashfunc_t hash_sha224; +extern hashfunc_t hash_sha256; +extern hashfunc_t hash_sha384; +extern hashfunc_t hash_sha512;*/ +#define HMAC HMAC_quake //stop conflicts... +size_t CalcHash(hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen); +size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen); #ifdef LIBQTV diff --git a/fteqtv/source.c b/fteqtv/source.c index b9def7b0..b8996f4f 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -477,7 +477,7 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge) str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str); snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword); - SHA1((unsigned char*)digest, sizeof(digest), hash, strlen(hash)); + CalcHash(&hash_sha1, (unsigned char*)digest, sizeof(digest), hash, strlen(hash)); sprintf(hash, "%08X%08X%8X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]); str = hash; Net_QueueUpstream(qtv, strlen(str), str); diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 1c5fc375..71ea9bb1 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -1228,11 +1228,11 @@ static int sasl_scram_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize, ha } static int sasl_scramsha1minus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { - return sasl_scram_initial(ctx, buf, bufsize, SHA1_m, 20, false); + return sasl_scram_initial(ctx, buf, bufsize, &hash_sha1, 20, false); } static int sasl_scramsha1plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { - return sasl_scram_initial(ctx, buf, bufsize, SHA1_m, 20, true); + return sasl_scram_initial(ctx, buf, bufsize, &hash_sha1, 20, true); } static void buf_cat(buf_t *buf, char *data, int len) @@ -1347,7 +1347,7 @@ static int sasl_scram_challenge(struct sasl_ctx_s *ctx, char *in, int inlen, cha HMAC(func, clientkey, sizeof(clientkey), "Client Key", strlen("Client Key"), salted_password, digestsize); //Note: if we wanted to be fancy, we could store both clientkey and serverkey instead of salted_password, but I'm not sure there's all that much point. tmp = clientkey; - func(storedkey, sizeof(storedkey), 1, &tmp, &digestsize); + CalcHash(func, storedkey, sizeof(storedkey), tmp, digestsize); HMAC(func, clientsignature, sizeof(clientsignature), sigkey.buf, sigkey.len, storedkey, digestsize); for (i = 0; i < digestsize; i++) @@ -3621,7 +3621,7 @@ static qboolean JCL_BuddyVCardReply(jclient_t *jcl, xmltree_t *tree, struct iq_s free(bi->image); free(bi->imagehash); free(bi->imagemime); - SHA1(hash, sizeof(hash), photodata, photosize); + CalcHash(&hash_sha1, hash, sizeof(hash), photodata, photosize); for (i = 0, o = 0; i < sizeof(hash); i++) { hasha[o++] = hex[(hash[i]>>4) & 0xf]; @@ -3676,7 +3676,7 @@ static qboolean JCL_MyVCardReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *i else { int photosize = Base64_Decode(photodata, sizeof(photodata), photobinval->body, strlen(photobinval->body)); - SHA1(digest, sizeof(digest), photodata, photosize); + CalcHash(&hash_sha1, digest, sizeof(digest), photodata, photosize); if (jcl->vcardphotohashstatus != VCP_KNOWN || memcmp(jcl->vcardphotohash, digest, sizeof(jcl->vcardphotohash))) { memcpy(jcl->vcardphotohash, digest, sizeof(jcl->vcardphotohash)); @@ -3950,7 +3950,7 @@ char *buildcapshash(jclient_t *jcl) Q_strlcat(out, caps[i].name, outlen); Q_strlcat(out, "<", outlen); } - l = SHA1(digest, sizeof(digest), out, strlen(out)); + l = CalcHash(&hash_sha1, digest, sizeof(digest), out, strlen(out)); for (i = 0; i < l; i++) Base64_Byte(digest[i]); Base64_Finish(); diff --git a/plugins/jabber/sift.c b/plugins/jabber/sift.c index c80d2b7b..df1e8904 100644 --- a/plugins/jabber/sift.c +++ b/plugins/jabber/sift.c @@ -63,7 +63,7 @@ void XMPP_FT_Frame(jclient_t *jcl) //server has accepted us, woo. //sid+requester(them)+target(us) req = va("%s%s%s", ft->sid, ft->with, jcl->fulljid); - SHA1(digest, sizeof(digest), req, strlen(req)); + CalcHash(&hash_sha1, digest, sizeof(digest), req, strlen(req)); //in hex for (req = domain, j=0; j < 20; j++) {