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 */