]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
rcon: rewrite variable expansion support, related fixes
authorbones_was_here <bones_was_here@xonotic.au>
Wed, 7 Feb 2024 16:21:51 +0000 (02:21 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Wed, 7 Feb 2024 18:37:46 +0000 (04:37 +1000)
Fixes https://gitlab.com/xonotic/darkplaces/-/issues/407
In 48d83538ef13596d4569d46ae66467b63b945546 I broke the return of the
rcon command output to the client.

Fixes unterminated string warnings on the server when the
rcon_password feature of multiple space-delimited passwords is used.
Fixes possibility of the cbuf to use more memory than its intended
maximum.

In the client you can send the variable such that the server will
expand it (not the client) like this: rcon echo $$sv_worldmessage

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
cmd.c
cmd.h
netconn.c

diff --git a/cmd.c b/cmd.c
index b12b13d61eaf7b698f1ec419fa08932e52575a4f..3e35b336b9c3d3914385336289152e111895a95d 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -348,13 +348,9 @@ Cbuf_Execute
 ============
 */
 extern qbool prvm_runawaycheck;
-static size_t Cmd_PreprocessString(cmd_state_t *cmd, const char *intext, char *outtext, unsigned maxoutlen, cmd_alias_t *alias);
 void Cbuf_Execute (cmd_buf_t *cbuf)
 {
        cmd_input_t *current;
-       char preprocessed[MAX_INPUTLINE];
-       size_t preprocessed_len;
-       char *firstchar;
        unsigned int i = 0;
 
        // LadyHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes
@@ -376,28 +372,11 @@ void Cbuf_Execute (cmd_buf_t *cbuf)
                 */
                current->pending = false;
 
+               Cmd_PreprocessAndExecuteString(current->source, current->text, current->length, src_local, false);
                cbuf->size -= current->length;
-
-               firstchar = current->text;
-               while(*firstchar && ISWHITESPACE(*firstchar))
-                       ++firstchar;
-               if((strncmp(firstchar, "alias", 5)   || !ISWHITESPACE(firstchar[5]))
-               && (strncmp(firstchar, "bind", 4)    || !ISWHITESPACE(firstchar[4]))
-               && (strncmp(firstchar, "in_bind", 7) || !ISWHITESPACE(firstchar[7])))
-               {
-                       if((preprocessed_len = Cmd_PreprocessString(current->source, current->text, preprocessed, sizeof(preprocessed), NULL)))
-                               Cmd_ExecuteString(current->source, preprocessed, preprocessed_len, src_local, false);
-               }
-               else
-               {
-                       Cmd_ExecuteString(current->source, current->text, current->length, src_local, false);
-               }
-
                // Recycle memory so using WASD doesn't cause a malloc and free
                List_Move_Tail(&current->list, &cbuf->free);
 
-               current = NULL;
-
                if (cbuf->wait)
                {
                        /*
@@ -1434,6 +1413,26 @@ static void Cmd_ExecuteAlias (cmd_state_t *cmd, cmd_alias_t *alias)
        Cbuf_InsertText(cmd, buffer2);
 }
 
+void Cmd_PreprocessAndExecuteString(cmd_state_t *cmd, const char *text, size_t textlen, cmd_source_t src, qbool lockmutex)
+{
+       char preprocessed[MAX_INPUTLINE];
+       size_t preprocessed_len;
+       const char *firstchar;
+
+       firstchar = text;
+       while(*firstchar && ISWHITESPACE(*firstchar))
+               ++firstchar;
+       if((strncmp(firstchar, "alias", 5)   || !ISWHITESPACE(firstchar[5]))
+       && (strncmp(firstchar, "bind", 4)    || !ISWHITESPACE(firstchar[4]))
+       && (strncmp(firstchar, "in_bind", 7) || !ISWHITESPACE(firstchar[7])))
+       {
+               if((preprocessed_len = Cmd_PreprocessString(cmd, text, preprocessed, sizeof(preprocessed), NULL)))
+                       Cmd_ExecuteString(cmd, preprocessed, preprocessed_len, src, lockmutex);
+       }
+       else
+               Cmd_ExecuteString(cmd, text, textlen, src, lockmutex);
+}
+
 /*
 ========
 Cmd_List
diff --git a/cmd.h b/cmd.h
index 97925042c24e27b0082bc9db91aac50b2bfd2035..a94ddb16665d9fe91623af7fea8a5f5b91e79bbc 100644 (file)
--- a/cmd.h
+++ b/cmd.h
@@ -268,6 +268,8 @@ int Cmd_CheckParm (cmd_state_t *cmd, const char *parm);
 /// Parses a single line of text into arguments and tries to execute it.
 /// The text can come from the command buffer, a remote client, or stdin.
 void Cmd_ExecuteString(cmd_state_t *cmd, const char *text, size_t textlen, cmd_source_t src, qbool lockmutex);
+/// Like Cmd_ExecuteString, but with variable expansion.
+void Cmd_PreprocessAndExecuteString(cmd_state_t *cmd, const char *text, size_t textlen, cmd_source_t src, qbool lockmutex);
 
 /// quotes a string so that it can be used as a command argument again;
 /// quoteset is a string that contains one or more of ", \, $ and specifies
index 801e6fc88810f6b832e1960a8164dfb8537e242b..b4dc5d5047afa454759d760846b0b854d11f7960 100644 (file)
--- a/netconn.c
+++ b/netconn.c
@@ -3013,7 +3013,7 @@ static const char *RCon_Authenticate(lhnetaddress_t *peeraddress, const char *pa
        while((userpass_end = strchr(userpass_start, ' ')))
        {
                have_usernames = true;
-               dp_strlcpy(buf, userpass_start, ((size_t)(userpass_end-userpass_start) >= sizeof(buf)) ? (int)(sizeof(buf)) : (int)(userpass_end-userpass_start+1));
+               dp_ustr2stp(buf, sizeof(buf), userpass_start, userpass_end - userpass_start);
                if(buf[0])  // Ignore empty entries due to leading/duplicate space.
                        if(comparator(peeraddress, buf, password, cs, cslen))
                                goto allow;
@@ -3032,7 +3032,7 @@ static const char *RCon_Authenticate(lhnetaddress_t *peeraddress, const char *pa
        while((userpass_end = strchr(userpass_start, ' ')))
        {
                have_usernames = true;
-               dp_strlcpy(buf, userpass_start, ((size_t)(userpass_end-userpass_start) >= sizeof(buf)) ? (int)(sizeof(buf)) : (int)(userpass_end-userpass_start+1));
+               dp_ustr2stp(buf, sizeof(buf), userpass_start, userpass_end - userpass_start);
                if(buf[0])  // Ignore empty entries due to leading/duplicate space.
                        if(comparator(peeraddress, buf, password, cs, cslen))
                                goto check;
@@ -3122,10 +3122,7 @@ static void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, c
                        if(l)
                        {
                                client_t *host_client_save = host_client;
-                               //Cmd_ExecuteString(cmd_local, s, src_local, true); // no variable expansion
-                               // bones_was_here: prepending allows a loop such as `alias foo "bar; wait; foo"; foo`
-                               // to be broken with an alias or unalias command
-                               Cbuf_InsertText(cmd_local, s);
+                               Cmd_PreprocessAndExecuteString(cmd_local, s, l, src_local, true);
                                host_client = host_client_save;
                                // in case it is a command that changes host_client (like restart)
                        }