You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/09/22 00:27:31 UTC

[7/8] guacamole-server git commit: GUACAMOLE-622: Match each line against all regexes.

GUACAMOLE-622: Match each line against all regexes.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-server/commit/462d494e
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-server/tree/462d494e
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-server/diff/462d494e

Branch: refs/heads/master
Commit: 462d494ed865a0fd47ef6cb22d23089d12f2b1ac
Parents: 442b1d5
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 2 22:59:18 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Fri Sep 21 14:29:01 2018 -0700

----------------------------------------------------------------------
 src/protocols/telnet/telnet.c | 240 +++++++++++++++++++++----------------
 1 file changed, 137 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/462d494e/src/protocols/telnet/telnet.c
----------------------------------------------------------------------
diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c
index 36e4cac..17abd68 100644
--- a/src/protocols/telnet/telnet.c
+++ b/src/protocols/telnet/telnet.c
@@ -83,65 +83,31 @@ static int __guac_telnet_write_all(int fd, const char* buffer, int size) {
 }
 
 /**
- * Searches for a line matching the stored password regex, appending the given
- * buffer to the internal pattern matching buffer. The internal pattern match
- * buffer is cleared whenever a newline is read. Returns true if a match is
- * found and the value is sent. An enter keypress is automatically sent after
- * the value is sent.
+ * Matches the given line against the given regex, returning true and sending
+ * the given value if a match is found. An enter keypress is automatically
+ * sent after the value is sent.
  *
  * @param client
  *     The guac_client associated with the telnet session.
  *
  * @param regex
- *     The regex to search for within the output of the telnet session
- *     associated with the given client.
+ *     The regex to search for within the given line buffer.
  *
  * @param value
- *     The string value to send once a match is found, or NULL if no value
- *     should be sent.
+ *     The string value to send through STDIN of the telnet session if a
+ *     match is found, or NULL if no value should be sent.
  *
- * @param buffer
- *     The buffer of received data to search through.
- *
- * @param size
- *     The size of the given buffer, in bytes.
+ * @param line_buffer
+ *     The line of character data to test.
  *
  * @return
  *     true if a match is found, false otherwise.
  */
-static bool __guac_telnet_regex_search(guac_client* client, regex_t* regex,
-        char* value, const char* buffer, int size) {
-
-    static char line_buffer[1024] = {0};
-    static int length = 0;
+static bool guac_telnet_regex_exec(guac_client* client, regex_t* regex,
+        const char* value, const char* line_buffer) {
 
     guac_telnet_client* telnet_client = (guac_telnet_client*) client->data;
 
-    int i;
-    const char* current;
-
-    /* Ensure line buffer contains only the most recent line */
-    current = buffer;
-    for (i = 0; i < size; i++) {
-
-        /* Reset line buffer and shift input buffer for each newline */
-        if (*(current++) == '\n') {
-            length = 0;
-            buffer += i;
-            size -= i;
-            i = 0;
-        }
-    }
-
-    /* Truncate if necessary */
-    if (size + length + 1 > sizeof(line_buffer))
-        size = sizeof(line_buffer) - length - 1;
-
-    /* Append to line */
-    memcpy(&(line_buffer[length]), buffer, size);
-    length += size;
-    line_buffer[length] = '\0';
-
     /* Send value upon match */
     if (regexec(regex, line_buffer, 0, NULL, 0) == 0) {
 
@@ -157,89 +123,157 @@ static bool __guac_telnet_regex_search(guac_client* client, regex_t* regex,
     }
 
     return false;
+
 }
 
 /**
- * Event handler, as defined by libtelnet. This function is passed to
- * telnet_init() and will be called for every event fired by libtelnet,
- * including feature enable/disable and receipt/transmission of data.
+ * Matches the given line against the various stored regexes, automatically
+ * sending the configured username, password, or reporting login
+ * success/failure depending on context. If no search is in progress, either
+ * because no regexes have been defined or because all applicable searches have
+ * completed, this function has no effect.
+ *
+ * @param client
+ *     The guac_client associated with the telnet session.
+ *
+ * @param line_buffer
+ *     The line of character data to test.
  */
-static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event, void* data) {
+static void guac_telnet_search_line(guac_client* client, const char* line_buffer) {
 
-    guac_client* client = (guac_client*) data;
     guac_telnet_client* telnet_client = (guac_telnet_client*) client->data;
     guac_telnet_settings* settings = telnet_client->settings;
 
-    switch (event->type) {
+    /* Continue search for username prompt */
+    if (settings->username_regex != NULL) {
+        if (guac_telnet_regex_exec(client, settings->username_regex,
+                    settings->username, line_buffer)) {
+            guac_client_log(client, GUAC_LOG_DEBUG, "Username sent");
+            guac_telnet_regex_free(&settings->username_regex);
+        }
+    }
 
-        /* Terminal output received */
-        case TELNET_EV_DATA:
-            guac_terminal_write(telnet_client->term, event->data.buffer, event->data.size);
+    /* Continue search for password prompt */
+    if (settings->password_regex != NULL) {
+        if (guac_telnet_regex_exec(client, settings->password_regex,
+                    settings->password, line_buffer)) {
 
-            /* Continue search for username prompt */
-            if (settings->username_regex != NULL) {
-                if (__guac_telnet_regex_search(client,
-                            settings->username_regex, settings->username,
-                            event->data.buffer, event->data.size)) {
-                    guac_client_log(client, GUAC_LOG_DEBUG, "Username sent");
-                    guac_telnet_regex_free(&settings->username_regex);
-                }
-            }
+            guac_client_log(client, GUAC_LOG_DEBUG, "Password sent");
 
-            /* Continue search for password prompt */
-            if (settings->password_regex != NULL) {
-                if (__guac_telnet_regex_search(client,
-                            settings->password_regex, settings->password,
-                            event->data.buffer, event->data.size)) {
+            /* Do not continue searching for username/password once password is sent */
+            guac_telnet_regex_free(&settings->username_regex);
+            guac_telnet_regex_free(&settings->password_regex);
 
-                    guac_client_log(client, GUAC_LOG_DEBUG, "Password sent");
+        }
+    }
 
-                    /* Do not continue searching for username/password once password is sent */
-                    guac_telnet_regex_free(&settings->username_regex);
-                    guac_telnet_regex_free(&settings->password_regex);
+    /* Continue search for login success */
+    if (settings->login_success_regex != NULL) {
+        if (guac_telnet_regex_exec(client, settings->login_success_regex,
+                    NULL, line_buffer)) {
 
-                }
-            }
+            /* Allow terminal to render now that login has been deemed successful */
+            guac_client_log(client, GUAC_LOG_DEBUG, "Login successful");
+            guac_terminal_start(telnet_client->term);
+
+            /* Stop all searches */
+            guac_telnet_regex_free(&settings->username_regex);
+            guac_telnet_regex_free(&settings->password_regex);
+            guac_telnet_regex_free(&settings->login_success_regex);
+            guac_telnet_regex_free(&settings->login_failure_regex);
 
-            /* Continue search for login success */
-            if (settings->login_success_regex != NULL) {
-                if (__guac_telnet_regex_search(client,
-                            settings->login_success_regex, NULL,
-                            event->data.buffer, event->data.size)) {
+        }
+    }
 
-                    /* Allow terminal to render now that login has been deemed successful */
-                    guac_client_log(client, GUAC_LOG_DEBUG, "Login successful");
-                    guac_terminal_start(telnet_client->term);
+    /* Continue search for login failure */
+    if (settings->login_failure_regex != NULL) {
+        if (guac_telnet_regex_exec(client, settings->login_failure_regex,
+                    NULL, line_buffer)) {
 
-                    /* Stop all searches */
-                    guac_telnet_regex_free(&settings->username_regex);
-                    guac_telnet_regex_free(&settings->password_regex);
-                    guac_telnet_regex_free(&settings->login_success_regex);
-                    guac_telnet_regex_free(&settings->login_failure_regex);
+            /* Advise that login has failed and connection should be closed */
+            guac_client_abort(client,
+                    GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
+                    "Login failed");
 
-                }
-            }
+            /* Stop all searches */
+            guac_telnet_regex_free(&settings->username_regex);
+            guac_telnet_regex_free(&settings->password_regex);
+            guac_telnet_regex_free(&settings->login_success_regex);
+            guac_telnet_regex_free(&settings->login_failure_regex);
+
+        }
+    }
 
-            /* Continue search for login failure */
-            if (settings->login_failure_regex != NULL) {
-                if (__guac_telnet_regex_search(client,
-                            settings->login_failure_regex, NULL,
-                            event->data.buffer, event->data.size)) {
+}
 
-                    /* Advise that login has failed and connection should be closed */
-                    guac_client_abort(client,
-                            GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
-                            "Login failed");
+/**
+ * Searches for a line matching the various stored regexes, automatically
+ * sending the configured username, password, or reporting login
+ * success/failure depending on context. If no search is in progress, either
+ * because no regexes have been defined or because all applicable searches
+ * have completed, this function has no effect.
+ *
+ * @param client
+ *     The guac_client associated with the telnet session.
+ *
+ * @param buffer
+ *     The buffer of received data to search through.
+ *
+ * @param size
+ *     The size of the given buffer, in bytes.
+ */
+static void guac_telnet_search(guac_client* client, const char* buffer, int size) {
+
+    static char line_buffer[1024] = {0};
+    static int length = 0;
 
-                    /* Stop all searches */
-                    guac_telnet_regex_free(&settings->username_regex);
-                    guac_telnet_regex_free(&settings->password_regex);
-                    guac_telnet_regex_free(&settings->login_success_regex);
-                    guac_telnet_regex_free(&settings->login_failure_regex);
+    /* Append all characters in buffer to current line */
+    const char* current = buffer;
+    for (int i = 0; i < size; i++) {
 
-                }
+        char c = *(current++);
+
+        /* Attempt pattern match and clear buffer upon reading newline */
+        if (c == '\n') {
+            if (length > 0) {
+                line_buffer[length] = '\0';
+                guac_telnet_search_line(client, line_buffer);
+                length = 0;
             }
+        }
+
+        /* Append all non-newline characters to line buffer as long as space
+         * remains */
+        else if (length < sizeof(line_buffer) - 1)
+            line_buffer[length++] = c;
+
+    }
 
+    /* Attempt pattern match if an unfinished line remains (may be a prompt) */
+    if (length > 0) {
+        line_buffer[length] = '\0';
+        guac_telnet_search_line(client, line_buffer);
+    }
+
+}
+
+/**
+ * Event handler, as defined by libtelnet. This function is passed to
+ * telnet_init() and will be called for every event fired by libtelnet,
+ * including feature enable/disable and receipt/transmission of data.
+ */
+static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event, void* data) {
+
+    guac_client* client = (guac_client*) data;
+    guac_telnet_client* telnet_client = (guac_telnet_client*) client->data;
+    guac_telnet_settings* settings = telnet_client->settings;
+
+    switch (event->type) {
+
+        /* Terminal output received */
+        case TELNET_EV_DATA:
+            guac_terminal_write(telnet_client->term, event->data.buffer, event->data.size);
+            guac_telnet_search(client, event->data.buffer, event->data.size);
             break;
 
         /* Data destined for remote end */