summaryrefslogtreecommitdiff
path: root/src/game/g_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/g_client.c')
-rw-r--r--src/game/g_client.c281
1 files changed, 267 insertions, 14 deletions
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 )
{