GUAC-763: Adjust telnet login automation to accept a regex for the username parameter
This commit is contained in:
parent
8d99c35a86
commit
7784ebc8d3
@ -48,6 +48,7 @@ const char* GUAC_CLIENT_ARGS[] = {
|
||||
"hostname",
|
||||
"port",
|
||||
"username",
|
||||
"username-regex",
|
||||
"password",
|
||||
"password-regex",
|
||||
"font-name",
|
||||
@ -72,6 +73,12 @@ enum __TELNET_ARGS_IDX {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -96,6 +103,26 @@ enum __TELNET_ARGS_IDX {
|
||||
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) {
|
||||
|
||||
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->password, argv[IDX_PASSWORD]);
|
||||
|
||||
/* Set password regex, if needed */
|
||||
if (client_data->password[0] != 0) {
|
||||
|
||||
int compile_result;
|
||||
|
||||
client_data->password_regex = malloc(sizeof(regex_t));
|
||||
/* Set username regex, if needed */
|
||||
if (client_data->username[0] != 0) {
|
||||
|
||||
/* Compile regular expression */
|
||||
if (argv[IDX_PASSWORD_REGEX][0] != 0)
|
||||
compile_result = regcomp(client_data->password_regex, argv[IDX_PASSWORD_REGEX],
|
||||
REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
|
||||
if (argv[IDX_USERNAME_REGEX][0] != 0)
|
||||
client_data->username_regex = __guac_telnet_compile_regext(client, argv[IDX_USERNAME_REGEX]);
|
||||
else
|
||||
compile_result = regcomp(client_data->password_regex, GUAC_TELNET_DEFAULT_REGEX,
|
||||
REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
|
||||
|
||||
/* Notify of failure to parse/compile */
|
||||
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;
|
||||
}
|
||||
client_data->username_regex = __guac_telnet_compile_regext(client, GUAC_TELNET_DEFAULT_USERNAME_REGEX);
|
||||
}
|
||||
else
|
||||
client_data->username_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
|
||||
client_data->password_regex = NULL;
|
||||
|
@ -32,7 +32,8 @@
|
||||
|
||||
#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.
|
||||
@ -54,6 +55,13 @@ typedef struct guac_telnet_client_data {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
guac_terminal_send_key(term, keysym, pressed);
|
||||
|
||||
|
@ -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
|
||||
* 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 int length = 0;
|
||||
@ -110,7 +111,6 @@ static void __guac_telnet_password_search(guac_client* client, const char* buffe
|
||||
size -= i;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Truncate if necessary */
|
||||
@ -122,21 +122,26 @@ static void __guac_telnet_password_search(guac_client* client, const char* buffe
|
||||
length += size;
|
||||
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 */
|
||||
if (regexec(client_data->password_regex, line_buffer, 0, NULL, 0) == 0) {
|
||||
if (regexec(regex, line_buffer, 0, NULL, 0) == 0) {
|
||||
|
||||
/* 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, 0);
|
||||
|
||||
/* Stop searching for password */
|
||||
regfree(client_data->password_regex);
|
||||
free(client_data->password_regex);
|
||||
client_data->password_regex = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,10 +160,25 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event,
|
||||
case TELNET_EV_DATA:
|
||||
guac_terminal_write_stdout(client_data->term, event->data.buffer, event->data.size);
|
||||
|
||||
/* Continue search for password prompt */
|
||||
if (client_data->password_regex != NULL)
|
||||
__guac_telnet_password_search(client, event->data.buffer, event->data.size);
|
||||
/* Continue search for username prompt */
|
||||
if (client_data->username_regex != NULL) {
|
||||
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;
|
||||
|
||||
/* Data destined for remote end */
|
||||
@ -196,7 +216,6 @@ static void __guac_telnet_event_handler(telnet_t* telnet, telnet_event_t* event,
|
||||
|
||||
/* Environment request */
|
||||
case TELNET_EV_ENVIRON:
|
||||
|
||||
/* Only send USER if entire environment was requested */
|
||||
if (event->environ.size == 0)
|
||||
guac_telnet_send_user(telnet, client_data->username);
|
||||
|
Loading…
Reference in New Issue
Block a user