GUACAMOLE-221: Add support for sending multiple params in required.
This commit is contained in:
parent
21a5d9ee62
commit
7369bed22c
@ -803,12 +803,12 @@ int guac_protocol_send_rect(guac_socket* socket, const guac_layer* layer,
|
||||
* The guac_socket connection to use.
|
||||
*
|
||||
* @param required
|
||||
* The name of the parameter that is required.
|
||||
* A NULL-terminated array of required parameters.
|
||||
*
|
||||
* @return
|
||||
* Zero on success, non-zero on error.
|
||||
*/
|
||||
int guac_protocol_send_required(guac_socket* socket, const char* required);
|
||||
int guac_protocol_send_required(guac_socket* socket, const char** required);
|
||||
|
||||
/**
|
||||
* Sends a reset instruction over the given guac_socket connection.
|
||||
|
@ -961,17 +961,33 @@ int guac_protocol_send_rect(guac_socket* socket,
|
||||
|
||||
}
|
||||
|
||||
int guac_protocol_send_required(guac_socket* socket, const char* required) {
|
||||
static int __guac_protocol_send_required(guac_socket* socket,
|
||||
const char** required) {
|
||||
|
||||
if (guac_socket_write_string(socket, "8.required")) return -1;
|
||||
|
||||
for (int i=0; required[i] != NULL; i++) {
|
||||
|
||||
if (guac_socket_write_string(socket, ","))
|
||||
return -1;
|
||||
|
||||
if (__guac_socket_write_length_string(socket, required[i]))
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return guac_socket_write_string(socket, ";");
|
||||
|
||||
}
|
||||
|
||||
int guac_protocol_send_required(guac_socket* socket, const char** required) {
|
||||
|
||||
int ret_val;
|
||||
|
||||
guac_socket_instruction_begin(socket);
|
||||
ret_val =
|
||||
guac_socket_write_string(socket, "8.required,")
|
||||
|| __guac_socket_write_length_string(socket, required)
|
||||
|| guac_socket_write_string(socket, ";");
|
||||
|
||||
ret_val = __guac_protocol_send_required(socket, required);
|
||||
guac_socket_instruction_end(socket);
|
||||
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ typedef enum guac_rdp_argv_setting {
|
||||
/**
|
||||
* The domain to use for connection authentication.
|
||||
*/
|
||||
GUAC_RDP_ARGV_SETTING_DOMAIN
|
||||
|
||||
GUAC_RDP_ARGV_SETTING_DOMAIN,
|
||||
|
||||
} guac_rdp_argv_setting;
|
||||
|
||||
/**
|
||||
@ -125,24 +125,27 @@ static int guac_rdp_argv_end_handler(guac_user* user,
|
||||
free(settings->username);
|
||||
settings->username = malloc(strlen(argv->buffer) * sizeof(char));
|
||||
strcpy(settings->username, argv->buffer);
|
||||
pthread_cond_broadcast(&(rdp_client->rdp_cond));
|
||||
rdp_client->rdp_cond_flags ^= GUAC_RDP_COND_FLAG_USERNAME;
|
||||
break;
|
||||
|
||||
case GUAC_RDP_ARGV_SETTING_PASSWORD:
|
||||
free(settings->password);
|
||||
settings->password = malloc(strlen(argv->buffer) * sizeof(char));
|
||||
strcpy(settings->password, argv->buffer);
|
||||
pthread_cond_broadcast(&(rdp_client->rdp_cond));
|
||||
rdp_client->rdp_cond_flags ^= GUAC_RDP_COND_FLAG_PASSWORD;
|
||||
break;
|
||||
|
||||
case GUAC_RDP_ARGV_SETTING_DOMAIN:
|
||||
free(settings->domain);
|
||||
settings->domain = malloc(strlen(argv->buffer) * sizeof(char));
|
||||
strcpy(settings->domain, argv->buffer);
|
||||
pthread_cond_broadcast(&(rdp_client->rdp_cond));
|
||||
rdp_client->rdp_cond_flags ^= GUAC_RDP_COND_FLAG_DOMAIN;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (!rdp_client->rdp_cond_flags)
|
||||
pthread_cond_signal(&(rdp_client->rdp_cond));
|
||||
|
||||
free(argv);
|
||||
return 0;
|
||||
|
@ -161,6 +161,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
||||
/* Init RDP credential lock and condition */
|
||||
pthread_mutex_init(&(rdp_client->rdp_credential_lock), &(rdp_client->attributes));
|
||||
pthread_cond_init(&(rdp_client->rdp_credential_cond), NULL);;
|
||||
rdp_client->rdp_credential_flags = 0;
|
||||
|
||||
/* Set handlers */
|
||||
client->join_handler = guac_rdp_user_join_handler;
|
||||
|
@ -230,32 +230,51 @@ static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username,
|
||||
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||
guac_rdp_settings* settings = rdp_client->settings;
|
||||
char* params[4] = {};
|
||||
int i = 0;
|
||||
|
||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||
if (settings->username == NULL || strcmp(settings->username, "") == 0) {
|
||||
params[i] = "username";
|
||||
rdp_client->rdp_cond_flags |= GUAC_RDP_COND_FLAG_USERNAME;
|
||||
i++;
|
||||
}
|
||||
|
||||
while (settings->username == NULL || strcmp(settings->username, "") == 0) {
|
||||
guac_protocol_send_required(client->socket, "username");
|
||||
if (settings->password == NULL || strcmp(settings->password, "") == 0) {
|
||||
params[i] = "password";
|
||||
rdp_client->rdp_cond_flags |= GUAC_RDP_COND_FLAG_PASSWORD;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (settings->domain == NULL || strcmp(settings->domain, "") == 0) {
|
||||
params[i] = "domain";
|
||||
rdp_client->rdp_cond_flags |= GUAC_RDP_COND_FLAG_DOMAIN;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* NULL-terminate the array. */
|
||||
params[i] = NULL;
|
||||
|
||||
if (i > 0) {
|
||||
/* Lock the client thread. */
|
||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||
|
||||
/* Send require params and flush socket. */
|
||||
guac_protocol_send_required(client->socket, (const char**) params);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
/* Wait for condition. */
|
||||
pthread_cond_wait(&(rdp_client->rdp_cond), &(rdp_client->rdp_lock));
|
||||
|
||||
/* Get new values from settings. */
|
||||
*username = settings->username;
|
||||
}
|
||||
|
||||
while (settings->password == NULL || strcmp(settings->password, "") == 0) {
|
||||
guac_protocol_send_required(client->socket, "password");
|
||||
guac_socket_flush(client->socket);
|
||||
pthread_cond_wait(&(rdp_client->rdp_cond), &(rdp_client->rdp_lock));
|
||||
*password = settings->password;
|
||||
}
|
||||
|
||||
while (settings->domain == NULL || strcmp(settings->domain, "") == 0) {
|
||||
guac_protocol_send_required(client->socket, "domain");
|
||||
guac_socket_flush(client->socket);
|
||||
pthread_cond_wait(&(rdp_client->rdp_cond), &(rdp_client->rdp_lock));
|
||||
*domain = settings->domain;
|
||||
|
||||
/* Unlock the thread. */
|
||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||
|
||||
/* Always return TRUE allowing connection to retry. */
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
@ -49,6 +49,21 @@
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* A flag for tracking if we are waiting conditionally on a username.
|
||||
*/
|
||||
#define GUAC_RDP_COND_FLAG_USERNAME 1
|
||||
|
||||
/**
|
||||
* A flag for tracking if we are waiting conditionally on a password.
|
||||
*/
|
||||
#define GUAC_RDP_COND_FLAG_PASSWORD 2
|
||||
|
||||
/**
|
||||
* A flag for tracking if we are waiting conditionally on a domain.
|
||||
*/
|
||||
#define GUAC_RDP_COND_FLAG_DOMAIN 3
|
||||
|
||||
/**
|
||||
* RDP-specific client data.
|
||||
*/
|
||||
@ -164,6 +179,12 @@ typedef struct guac_rdp_client {
|
||||
* particular credential to be provided.
|
||||
*/
|
||||
pthread_cond_t rdp_credential_cond;
|
||||
|
||||
/**
|
||||
* Flags for tracking events related to the rdp_credential_cond
|
||||
* pthread condition.
|
||||
*/
|
||||
unsigned rdp_credential_flags;
|
||||
|
||||
/**
|
||||
* Common attributes for locks.
|
||||
|
@ -75,7 +75,7 @@ static void guac_ssh_get_credential(guac_client *client, char* cred_name) {
|
||||
|
||||
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
||||
|
||||
guac_protocol_send_required(client->socket, cred_name);
|
||||
guac_protocol_send_required(client->socket, (const char* []) {cred_name, NULL});
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
pthread_cond_wait(&(ssh_client->ssh_cond), &(ssh_client->term_channel_lock));
|
||||
|
@ -35,6 +35,11 @@
|
||||
*/
|
||||
typedef enum guac_vnc_argv_setting {
|
||||
|
||||
/**
|
||||
* The username for the connection.
|
||||
*/
|
||||
GUAC_VNC_ARGV_SETTING_USERNAME,
|
||||
|
||||
/**
|
||||
* The password for the connection.
|
||||
*/
|
||||
@ -109,6 +114,19 @@ static int guac_vnc_argv_end_handler(guac_user* user, guac_stream* stream) {
|
||||
/* Apply changes to chosen setting */
|
||||
switch (argv->setting) {
|
||||
|
||||
/* Update username */
|
||||
case GUAC_VNC_ARGV_SETTING_USERNAME:
|
||||
|
||||
/* Update username in settings. */
|
||||
if (settings->username != NULL)
|
||||
free(settings->username);
|
||||
settings->username = malloc(strlen(argv->buffer) * sizeof(char));
|
||||
strcpy(settings->username, argv->buffer);
|
||||
|
||||
/* Remove the username conditional flag. */
|
||||
vnc_client->argv_cond_flags ^= GUAC_VNC_COND_FLAG_USERNAME;
|
||||
break;
|
||||
|
||||
/* Update password */
|
||||
case GUAC_VNC_ARGV_SETTING_PASSWORD:
|
||||
|
||||
@ -118,10 +136,15 @@ static int guac_vnc_argv_end_handler(guac_user* user, guac_stream* stream) {
|
||||
settings->password = malloc(strlen(argv->buffer) * sizeof(char));
|
||||
strcpy(settings->password, argv->buffer);
|
||||
|
||||
pthread_cond_broadcast(&(vnc_client->argv_cond));
|
||||
/* Remove the password conditional flag. */
|
||||
vnc_client->argv_cond_flags ^= GUAC_VNC_COND_FLAG_PASSWORD;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* If no flags are set, signal the conditional. */
|
||||
if (!vnc_client->argv_cond_flags)
|
||||
pthread_cond_broadcast(&(vnc_client->argv_cond));
|
||||
|
||||
free(argv);
|
||||
return 0;
|
||||
@ -134,7 +157,9 @@ int guac_vnc_argv_handler(guac_user* user, guac_stream* stream, char* mimetype,
|
||||
guac_vnc_argv_setting setting;
|
||||
|
||||
/* Allow users to update authentication information */
|
||||
if (strcmp(name, "password") == 0)
|
||||
if (strcmp(name, "username") == 0)
|
||||
setting = GUAC_VNC_ARGV_SETTING_USERNAME;
|
||||
else if (strcmp(name, "password") == 0)
|
||||
setting = GUAC_VNC_ARGV_SETTING_PASSWORD;
|
||||
|
||||
/* No other connection parameters may be updated */
|
||||
|
@ -36,11 +36,23 @@ char* guac_vnc_get_password(rfbClient* client) {
|
||||
guac_vnc_client* vnc_client = ((guac_vnc_client*) gc->data);
|
||||
guac_vnc_settings* settings = vnc_client->settings;
|
||||
|
||||
/* If password isn't around, prompt for it. */
|
||||
if (settings->password == NULL || strcmp(settings->password, "") == 0) {
|
||||
/* Lock the thread. */
|
||||
pthread_mutex_lock(&(vnc_client->argv_lock));
|
||||
guac_protocol_send_required(gc->socket, "password");
|
||||
|
||||
/* Send the request for password and flush the socket. */
|
||||
guac_protocol_send_required(gc->socket,
|
||||
(const char* []) {"password", NULL});
|
||||
guac_socket_flush(gc->socket);
|
||||
|
||||
/* Set the conditional flag. */
|
||||
vnc_client->argv_cond_flags |= GUAC_VNC_COND_FLAG_PASSWORD;
|
||||
|
||||
/* Wait for the condition. */
|
||||
pthread_cond_wait(&(vnc_client->argv_cond), &(vnc_client->argv_lock));
|
||||
|
||||
/* Unlock the thread. */
|
||||
pthread_mutex_unlock(&(vnc_client->argv_lock));
|
||||
}
|
||||
|
||||
@ -50,13 +62,52 @@ char* guac_vnc_get_password(rfbClient* client) {
|
||||
|
||||
rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType) {
|
||||
guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
|
||||
guac_vnc_settings* settings = ((guac_vnc_client*) gc->data)->settings;
|
||||
|
||||
guac_vnc_client* vnc_client = ((guac_vnc_client*) gc->data);
|
||||
guac_vnc_settings* settings = vnc_client->settings;
|
||||
|
||||
/* Handle request for Username/Password credentials */
|
||||
if (credentialType == rfbCredentialTypeUser) {
|
||||
rfbCredential *creds = malloc(sizeof(rfbCredential));
|
||||
creds->userCredential.username = settings->username;
|
||||
creds->userCredential.password = settings->password;
|
||||
return creds;
|
||||
char* params[2] = {NULL};
|
||||
int i = 0;
|
||||
|
||||
/* Check if username is null or empty. */
|
||||
if (settings->username == NULL || strcmp(settings->username, "") == 0) {
|
||||
params[i] = "username";
|
||||
i++;
|
||||
vnc_client->argv_cond_flags |= GUAC_VNC_COND_FLAG_USERNAME;
|
||||
}
|
||||
|
||||
/* Check if password is null or empty. */
|
||||
if (settings->password == NULL || strcmp(settings->password, "") == 0) {
|
||||
params[i] = "password";
|
||||
i++;
|
||||
vnc_client->argv_cond_flags |= GUAC_VNC_COND_FLAG_PASSWORD;
|
||||
}
|
||||
|
||||
/* If we have empty parameters, request them. */
|
||||
if (i > 0) {
|
||||
/* Lock the thread. */
|
||||
pthread_mutex_lock(&(vnc_client->argv_lock));
|
||||
|
||||
/* Send required parameters to client and flush the socket. */
|
||||
guac_protocol_send_required(gc->socket, (const char**) params);
|
||||
guac_socket_flush(gc->socket);
|
||||
|
||||
/* Wait for the parameters to be returned. */
|
||||
pthread_cond_wait(&(vnc_client->argv_cond), &(vnc_client->argv_lock));
|
||||
|
||||
/* Pull the credentials from updated settings. */
|
||||
creds->userCredential.username = settings->username;
|
||||
creds->userCredential.password = settings->password;
|
||||
|
||||
/* Unlock the thread. */
|
||||
pthread_mutex_unlock(&(vnc_client->argv_lock));
|
||||
|
||||
return creds;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
guac_client_abort(gc, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
|
@ -57,6 +57,7 @@ int guac_client_init(guac_client* client) {
|
||||
/* Initialize argv lock and condition */
|
||||
pthread_mutex_init(&(vnc_client->argv_lock), NULL);
|
||||
pthread_cond_init(&(vnc_client->argv_cond), NULL);
|
||||
vnc_client->argv_cond_flags = 0;
|
||||
|
||||
/* Init clipboard */
|
||||
vnc_client->clipboard = guac_common_clipboard_alloc(GUAC_VNC_CLIPBOARD_MAX_LENGTH);
|
||||
|
@ -45,6 +45,16 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* A flag for tracking status of requesting username from client.
|
||||
*/
|
||||
#define GUAC_VNC_COND_FLAG_USERNAME 1
|
||||
|
||||
/**
|
||||
* A flag for tracking status of requesting password from client.
|
||||
*/
|
||||
#define GUAC_VNC_COND_FLAG_PASSWORD 2
|
||||
|
||||
/**
|
||||
* VNC-specific client data.
|
||||
*/
|
||||
@ -71,6 +81,11 @@ typedef struct guac_vnc_client {
|
||||
* The condition for signaling argv updates.
|
||||
*/
|
||||
pthread_cond_t argv_cond;
|
||||
|
||||
/**
|
||||
* Flags for conditional signaling for argv updates;
|
||||
*/
|
||||
unsigned argv_cond_flags;
|
||||
|
||||
/**
|
||||
* The underlying VNC client.
|
||||
|
Loading…
Reference in New Issue
Block a user