From 0ec47fd7d8c7ffbf962b3e5105f26bc677a639a3 Mon Sep 17 00:00:00 2001 From: /dev/humancontroller Date: Sat, 16 Sep 2017 21:05:30 +0200 Subject: implement !control --- src/game/g_client.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 267 insertions(+), 14 deletions(-) (limited to 'src/game/g_client.c') diff --git a/src/game/g_client.c b/src/game/g_client.c index 3325289..78e1c4f 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1395,7 +1395,7 @@ to the server machine, but qfalse on map changes and tournement restarts. ============ */ -const char *ClientConnect( int clientNum, qboolean firstTime ) +const char *ClientConnect( int clientNum, qboolean firstTime, qboolean isPlaceholder ) { char *value; gclient_t *client; @@ -1408,8 +1408,22 @@ const char *ClientConnect( int clientNum, qboolean firstTime ) ent = &g_entities[ clientNum ]; + if (ent->client && ent->client->pers.connected != CON_DISCONNECTED) + ClientDisconnect(clientNum); + trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); + if (isPlaceholder) + { + const char *invalidity = review_placeholder_client_userinfo(userinfo); + if (invalidity) + return invalidity; + trap_SetUserinfo(clientNum, userinfo); + + inject_placeholder_client(userinfo, clientNum, firstTime); + return NULL; + } + value = Info_ValueForKey( userinfo, "cl_guid" ); Q_strncpyz( guid, value, sizeof( guid ) ); @@ -1476,6 +1490,31 @@ const char *ClientConnect( int clientNum, qboolean firstTime ) strcmp( g_password.string, value ) != 0 ) return "Invalid password"; + schachtmeisterJudgement_t *smj = NULL; + + if (!(G_admin_permission_guid(guid, ADMF_NOAUTOBAHN) + || G_admin_permission_guid(guid, ADMF_IMMUNITY))) + { + extern g_admin_namelog_t *g_admin_namelog[128]; + for (i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[i]; ++i) + { + if (!Q_stricmp(g_admin_namelog[i]->ip, ip) + || !Q_stricmp(g_admin_namelog[i]->guid, guid)) + { + schachtmeisterJudgement_t *j = &g_admin_namelog[i]->smj; + if (j->ratingTime) + { + if (j->rating >= g_schachtmeisterClearThreshold.integer) + break; + else if (j->rating <= g_schachtmeisterAutobahnThreshold.integer) + return g_schachtmeisterAutobahnMessage.string; + smj = j; + } + break; + } + } + } + // they can connect ent->client = level.clients + clientNum; client = ent->client; @@ -1551,35 +1590,243 @@ const char *ClientConnect( int clientNum, qboolean firstTime ) G_admin_namelog_update( client, qfalse ); } + if (smj) + G_AdminsPrintf( "%s^7 (#%d) has rating %d\n", client->pers.netname, clientNum, smj->rating ); + // if this is after !restart keepteams or !restart switchteams, apply said selection if ( client->sess.restartTeam != PTE_NONE ) { G_ChangeTeam( ent, client->sess.restartTeam ); client->sess.restartTeam = PTE_NONE; } - if( !( G_admin_permission( ent, ADMF_NOAUTOBAHN ) || - G_admin_permission( ent, ADMF_IMMUNITY ) ) ) + return NULL; +} + +const char *review_placeholder_client_userinfo(char *ui) +{ { - extern g_admin_namelog_t *g_admin_namelog[ 128 ]; - for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) + const char *ipa = Info_ValueForKey(ui, "ip"); + unsigned o[4]; + + if (*ipa) { - if( !Q_stricmp( ip, g_admin_namelog[ i ]->ip ) || !Q_stricmp( guid, g_admin_namelog[ i ]->guid ) ) + for (int i = 0; ipa[i]; ++i) + { + if (!isdigit(ipa[i]) && ipa[i] != '.') + return "malformed IPv4 address"; + } + + if (sscanf(ipa, "%u.%u.%u.%u", &o[0], &o[1], &o[2], &o[3]) != 4 + || o[0] > 255 || o[1] > 255 || o[2] > 255 || o[3] > 255) + { + return "malformed IPv4 address"; + } + + if (o[0] == 0 || o[0] == 127 || o[0] == 10 || o[0] >= 224) + return "reserved IP address"; + + if (o[1] == 0 || o[1] == 255 + || o[2] == 0 || o[2] == 255 + || o[3] == 0 || o[3] == 255) + { + return "weird IP address"; + } + } + else + { + o[0] = 1 + rand() % 221; + if (o[0] == 127) + o[0] = 222; + else if (o[0] == 10) + o[0] = 223; + o[1] = 1 + rand() % 254; + o[2] = 1 + rand() % 254; + o[3] = 1 + rand() % 254; + } + + char ipa2[16]; + Com_sprintf(ipa2, sizeof(ipa2), "%u.%u.%u.%u", o[0], o[1], o[2], o[3]); + Info_SetValueForKey(ui, "ip", ipa2); + } + + { + const char *name = Info_ValueForKey(ui, "name"); + if (strlen(name) >= MAX_NAME_LENGTH) + return "overly long name"; + else if (!*name) + Info_SetValueForKey(ui, "name", "UnnamedPlayer"); + } + + if (!Info_Validate(ui)) + return "malformed userinfo"; + + return NULL; +} + +void inject_placeholder_client(const char *const ui, const int sl, qboolean first_time) +{ + { + char reason[MAX_STRING_CHARS]; + if (G_admin_ban_check(ui, reason, sizeof(reason))) + Com_Printf("inject_placeholder_client: warning: would be denied by the admin subsystem: %s\n", reason); + } + + const char *ipa = Info_ValueForKey(ui, "ip"); + + if (G_FilterPacket(ipa)) + Com_Printf("inject_placeholder_client: warning: would be denied by the filter subsystem\n"); + + if (g_maxGhosts.integer > 1) + { + const char *ipa = Info_ValueForKey(ui, "ip"); + int count = 0; + + for (int i = 0; i < level.maxclients; ++i) + { + const gclient_t *other = &g_clients[i]; + if (other->pers.connected >= CON_CONNECTING && !strcmp(ipa, other->pers.ip)) + ++count; + } + + if (count + 1 > g_maxGhosts.integer) + Com_Printf("inject_placeholder_client: warning: would be denied by the max-ghosts subsystem\n"); + } + + if (*g_password.string && Q_stricmp(g_password.string, "none") + && strcmp(Info_ValueForKey(ui, "password"), g_password.string)) + { + Com_Printf("inject_placeholder_client: warning: would be denied by the password subsystem\n"); + } + + const char *guid = Info_ValueForKey(ui, "cl_guid"); + + if (!(G_admin_permission_guid(guid, ADMF_NOAUTOBAHN) + || G_admin_permission_guid(guid, ADMF_IMMUNITY))) + { + extern g_admin_namelog_t *g_admin_namelog[128]; + for (int i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[i]; ++i) + { + if (!Q_stricmp(g_admin_namelog[i]->ip, ipa) + || !Q_stricmp(g_admin_namelog[i]->guid, guid)) { schachtmeisterJudgement_t *j = &g_admin_namelog[i]->smj; - if( j->ratingTime ) + if (j->ratingTime) { - if( j->rating >= g_schachtmeisterClearThreshold.integer ) + if (j->rating >= g_schachtmeisterClearThreshold.integer) break; - else if( j->rating <= g_schachtmeisterAutobahnThreshold.integer ) - return g_schachtmeisterAutobahnMessage.string; - G_AdminsPrintf( "%s^7 (#%d) has rating %d\n", ent->client->pers.netname, ent - g_entities, j->rating ); + else if (j->rating <= g_schachtmeisterAutobahnThreshold.integer) + Com_Printf("inject_placeholder_client: warning: would be denied by der Schachtmeister\n"); } break; } } } - - return NULL; + + gentity_t *ent = &g_entities[sl]; + gclient_t *cl = &g_clients[sl]; + clientPersistant_t *per = &cl->pers; + + memset(cl, 0, sizeof(*cl)); + + per->connected = CON_CONNECTING; + per->isPlaceholder = qtrue; + + per->firstConnect = qfalse; + + strcpy(per->ip, ipa); + Q_strncpyz(per->guid, *guid ? guid : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", sizeof(per->guid)); + + per->adminLevel = G_admin_level(ent); + + G_InitSessionData(cl, ui); + G_ReadSessionData(cl); + + ClientUserinfoChanged(sl, qfalse); + + G_admin_set_adminname(ent); + + if (g_decolourLogfiles.integer) + { + char decoloured[MAX_STRING_CHARS] = ""; + if (g_decolourLogfiles.integer == 1) + { + Com_sprintf(decoloured, sizeof(decoloured), " (\"%s^7\")", per->netname); + G_DecolorString(decoloured, decoloured); + G_LogPrintfColoured("PlaceholderClientConnect: %i [%s] (%s) \"%s^7\"%s\n", + sl, per->ip, per->guid, per->netname, decoloured); + } + else + { + G_LogPrintf("PlaceholderClientConnect: %i [%s] (%s) \"%s^7\"%s\n", + sl, per->ip, per->guid, per->netname, decoloured); + } + } + else + { + G_LogPrintf("PlaceholderClientConnect: %i [%s] (%s) \"%s^7\"\n", + sl, per->ip, per->guid, per->netname); + } + + if (per->adminLevel) + { + G_LogPrintf("PlaceholderClientAuth: %i [%s] \"%s^7\" authenticated to admin level %i using GUID %s (^7%s)\n", + sl, per->ip, per->netname, per->adminLevel, per->guid, per->adminName); + } + + if (cl->sess.invisible != qtrue) + { + if (first_time) + trap_SendServerCommand(-1, va("print \"%s" S_COLOR_WHITE " connected\n\"", per->netname)); + + CalculateRanks(); + G_admin_namelog_update(cl, qfalse); + } + + if (cl->sess.restartTeam != PTE_NONE) + { + G_ChangeTeam(ent, cl->sess.restartTeam); + cl->sess.restartTeam = PTE_NONE; + } + + if (ent->r.linked) + trap_UnlinkEntity(ent); + + G_InitGentity(ent); + ent->touch = 0; + ent->pain = 0; + ent->client = cl; + + per->connected = CON_CONNECTED; + per->enterTime = level.time; + per->teamState.state = TEAM_BEGIN; + per->classSelection = PCL_NONE; + + int flags = cl->ps.eFlags; + memset(&cl->ps, 0, sizeof(cl->ps)); + memset(&cl->pmext, 0, sizeof(cl->pmext)); + cl->ps.eFlags = flags; + + ClientSpawn(ent, NULL, NULL, NULL); + + if (cl->sess.invisible != qtrue) + { + trap_SendServerCommand(-1, va("print \"%s" S_COLOR_WHITE " entered the game\n\"", per->netname)); + + G_admin_namelog_update(cl, qfalse); + + G_admin_chat_sync(ent); + + G_admin_report_check(sl); + } + + if (G_admin_permission(ent, ADMF_NO_CHAT)) + { + per->muted = qtrue; + } + + G_LogPrintf("PlaceholderClientBegin: %i\n", sl); + + CalculateRanks(); } /* @@ -1958,7 +2205,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles // the respawned flag will be cleared after the attack and jump keys come up client->ps.pm_flags |= PMF_RESPAWNED; - trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); + trap_GetUsercmd(client - level.clients, client->pers.control < 0 ? &g_clients[-client->pers.control - 1].pers.cmd : &client->pers.cmd); G_SetClientViewAngle( ent, spawn_angles ); if( !( client->sess.sessionTeam == TEAM_SPECTATOR ) ) @@ -2057,6 +2304,12 @@ void ClientDisconnect( int clientNum ) if( !ent->client ) return; + if (ent->client->pers.control) + { + g_clients[abs(ent->client->pers.control) - 1].pers.control = 0; + ent->client->pers.control = 0; + } + // look through the bhist and readjust it if the referenced ent has left for( ptr = level.buildHistory; ptr; ptr = ptr->next ) { -- cgit