GUAC-763: Adjust telnet login automation to accept a regex for the username parameter

This commit is contained in:
Felipe Weckx 2014-07-02 17:19:12 -03:00 committed by Michael Jumper
parent 8d99c35a86
commit 7784ebc8d3
4 changed files with 94 additions and 33 deletions

View File

@ -48,6 +48,7 @@ const char* GUAC_CLIENT_ARGS[] = {
"hostname", "hostname",
"port", "port",
"username", "username",
"username-regex",
"password", "password",
"password-regex", "password-regex",
"font-name", "font-name",
@ -72,6 +73,12 @@ enum __TELNET_ARGS_IDX {
*/ */
IDX_USERNAME, IDX_USERNAME,
/**
* The regular expression to use when searching for the username/login prompt.
* Optional
*/
IDX_USERNAME_REGEX,
/** /**
* The password to use when logging in. Optional. * The password to use when logging in. Optional.
*/ */
@ -96,6 +103,26 @@ enum __TELNET_ARGS_IDX {
TELNET_ARGS_COUNT TELNET_ARGS_COUNT
}; };
/**
* Compile a regular expression and checks it return value. Returns NULL if compilation fails
*/
static regex_t* __guac_telnet_compile_regext(guac_client* client, char* pattern) {
int compile_result;
regex_t* regex = malloc(sizeof(regex_t));
/* Compile regular expression */
compile_result = regcomp(regex, pattern,REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE);
/* Notify of failure to parse/compile */
if (compile_result != 0) {
guac_client_log_info(client, "Regular expression '%s' could not be compiled.", pattern);
free(regex);
return NULL;
}
return regex;
}
int guac_client_init(guac_client* client, int argc, char** argv) { int guac_client_init(guac_client* client, int argc, char** argv) {
guac_socket* socket = client->socket; guac_socket* socket = client->socket;
@ -124,29 +151,25 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
strcpy(client_data->username, argv[IDX_USERNAME]); strcpy(client_data->username, argv[IDX_USERNAME]);
strcpy(client_data->password, argv[IDX_PASSWORD]); strcpy(client_data->password, argv[IDX_PASSWORD]);
/* Set password regex, if needed */ /* Set username regex, if needed */
if (client_data->password[0] != 0) { if (client_data->username[0] != 0) {
int compile_result;
client_data->password_regex = malloc(sizeof(regex_t));
/* Compile regular expression */ /* Compile regular expression */
if (argv[IDX_PASSWORD_REGEX][0] != 0) if (argv[IDX_USERNAME_REGEX][0] != 0)
compile_result = regcomp(client_data->password_regex, argv[IDX_PASSWORD_REGEX], client_data->username_regex = __guac_telnet_compile_regext(client, argv[IDX_USERNAME_REGEX]);
REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
else else
compile_result = regcomp(client_data->password_regex, GUAC_TELNET_DEFAULT_REGEX, client_data->username_regex = __guac_telnet_compile_regext(client, GUAC_TELNET_DEFAULT_USERNAME_REGEX);
REG_EXTENDED | REG_NOSUB | REG_NEWLINE); }
else
/* Notify of failure to parse/compile */ client_data->username_regex = NULL;
if (compile_result != 0) {
guac_client_log_info(client, "Password regular expression could not be compiled. "
"Password must be entered manually.");
free(client_data->password_regex);
client_data->password_regex = NULL;
}
/* Set password regex, if needed */
if (client_data->password[0] != 0) {
/* Compile regular expression */
if (argv[IDX_PASSWORD_REGEX][0] != 0)
client_data->password_regex = __guac_telnet_compile_regext(client, argv[IDX_PASSWORD_REGEX]);
else
client_data->password_regex = __guac_telnet_compile_regext(client, GUAC_TELNET_DEFAULT_PASSWORD_REGEX);
} }
else else
client_data->password_regex = NULL; client_data->password_regex = NULL;

View File

@ -32,7 +32,8 @@
#include <libtelnet.h> #include <libtelnet.h>
#define GUAC_TELNET_DEFAULT_REGEX "^Password:" #define GUAC_TELNET_DEFAULT_USERNAME_REGEX "login:"
#define GUAC_TELNET_DEFAULT_PASSWORD_REGEX "password:"
/** /**
* Telnet-specific client data. * Telnet-specific client data.
@ -54,6 +55,13 @@ typedef struct guac_telnet_client_data {
*/ */
char username[1024]; char username[1024];
/**
* The regular expression to use when searching for the username
* prompt. This will be NULL unless the telnet client is currently
* searching for the username prompt.
*/
regex_t* username_regex;
/** /**
* The password to give when authenticating. * The password to give when authenticating.
*/ */

View File

@ -71,6 +71,17 @@ int guac_telnet_client_key_handler(guac_client* client, int keysym, int pressed)
} }
/* Stop searching for username */
if (client_data->username_regex != NULL) {
guac_client_log_info(client, "Stopping username prompt search due to user input.");
regfree(client_data->username_regex);
free(client_data->username_regex);
client_data->username_regex = NULL;
}
/* Send key */ /* Send key */
guac_terminal_send_key(term, keysym, pressed); guac_terminal_send_key(term, keysym, pressed);

View File

@ -87,9 +87,10 @@ 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 * Searches for a line matching the stored password regex, appending the given
* buffer to the internal pattern matching buffer. The internal pattern match * buffer to the internal pattern matching buffer. The internal pattern match
* buffer is cleared whenever a newline is read. * buffer is cleared whenever a newline is read. Returns TRUE if a match is found and the
* value is sent.
*/ */
static void __guac_telnet_password_search(guac_client* client, const char* buffer, int size) { 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 char line_buffer[1024] = {0};
static int length = 0; static int length = 0;
@ -110,7 +111,6 @@ static void __guac_telnet_password_search(guac_client* client, const char* buffe
size -= i; size -= i;
i = 0; i = 0;
} }
} }
/* Truncate if necessary */ /* Truncate if necessary */
@ -122,21 +122,26 @@ static void __guac_telnet_password_search(guac_client* client, const char* buffe
length += size; length += size;
line_buffer[length] = '\0'; line_buffer[length] = '\0';
/* Remove non-printable characters as they interfere with regex matching */
for (int i = 0; i < length; i++) {
if (line_buffer[i] <= 31 || (line_buffer[i] >= 128 && line_buffer[i] <= 255)) {
line_buffer[i] = ' ';
}
}
/* Send password upon match */ /* Send password upon match */
if (regexec(client_data->password_regex, line_buffer, 0, NULL, 0) == 0) { if (regexec(regex, line_buffer, 0, NULL, 0) == 0) {
/* Send password */ /* Send password */
guac_terminal_send_string(client_data->term, client_data->password); guac_terminal_send_string(client_data->term, value);
guac_terminal_send_key(client_data->term, 0xFF0D, 1); guac_terminal_send_key(client_data->term, 0xFF0D, 1);
guac_terminal_send_key(client_data->term, 0xFF0D, 0); guac_terminal_send_key(client_data->term, 0xFF0D, 0);
/* Stop searching for password */ /* Stop searching for password */
regfree(client_data->password_regex); return TRUE;
free(client_data->password_regex);
client_data->password_regex = NULL;
} }
return FALSE;
} }
/** /**
@ -155,10 +160,25 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event,
case TELNET_EV_DATA: case TELNET_EV_DATA:
guac_terminal_write_stdout(client_data->term, event->data.buffer, event->data.size); guac_terminal_write_stdout(client_data->term, event->data.buffer, event->data.size);
/* Continue search for password prompt */ /* Continue search for username prompt */
if (client_data->password_regex != NULL) if (client_data->username_regex != NULL) {
__guac_telnet_password_search(client, event->data.buffer, event->data.size); if (__guac_telnet_regex_search(client, client_data->username_regex, client_data->username,
event->data.buffer, event->data.size)) {
regfree(client_data->username_regex);
free(client_data->username_regex);
client_data->username_regex = NULL;
}
}
/* Continue search for password prompt */
if (client_data->password_regex != NULL) {
if (__guac_telnet_regex_search(client, client_data->password_regex, client_data->password,
event->data.buffer, event->data.size)) {
regfree(client_data->password_regex);
free(client_data->password_regex);
client_data->password_regex = NULL;
}
}
break; break;
/* Data destined for remote end */ /* Data destined for remote end */
@ -196,7 +216,6 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event,
/* Environment request */ /* Environment request */
case TELNET_EV_ENVIRON: case TELNET_EV_ENVIRON:
/* Only send USER if entire environment was requested */ /* Only send USER if entire environment was requested */
if (event->environ.size == 0) if (event->environ.size == 0)
guac_telnet_send_user(telnet, client_data->username); guac_telnet_send_user(telnet, client_data->username);