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",
|
"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);
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
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
|
else
|
||||||
client_data->password_regex = NULL;
|
client_data->password_regex = NULL;
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user