GUAC-1305: Copy mimetypes into client structure. Instruction contents CANNOT be relied upon after new instruction data is read (the argv, etc. buffers are reused and shared).

This commit is contained in:
Michael Jumper 2015-09-24 12:30:56 -07:00
parent 9a3a1bdcde
commit 653751e2f5

View File

@ -79,6 +79,64 @@ static void guacd_log_handshake_failure() {
} }
/**
* Copies the given array of mimetypes (strings) into a newly-allocated NULL-
* terminated array of strings. Both the array and the strings within the array
* are newly-allocated and must be later freed via guacd_free_mimetypes().
*
* @param mimetypes
* The array of mimetypes to copy.
*
* @param count
* The number of mimetypes in the given array.
*
* @return
* A newly-allocated, NULL-terminated array containing newly-allocated
* copies of each of the mimetypes provided in the original mimetypes
* array.
*/
static char** guacd_copy_mimetypes(char** mimetypes, int count) {
int i;
/* Allocate sufficient space for NULL-terminated array of mimetypes */
char** mimetypes_copy = malloc(sizeof(char*) * (count+1));
/* Copy each provided mimetype */
for (i = 0; i < count; i++)
mimetypes_copy[i] = strdup(mimetypes[i]);
/* Terminate with NULL */
mimetypes_copy[count] = NULL;
return mimetypes_copy;
}
/**
* Frees the given array of mimetypes, including the space allocated to each
* mimetype string within the array. The provided array of mimetypes MUST have
* been allocated with guacd_copy_mimetypes().
*
* @param mimetypes
* The NULL-terminated array of mimetypes to free. This array MUST have
* been previously allocated with guacd_copy_mimetypes().
*/
static void guacd_free_mimetypes(char** mimetypes) {
char** current_mimetype = mimetypes;
/* Free all strings within NULL-terminated mimetype array */
while (*current_mimetype != NULL) {
free(*current_mimetype);
current_mimetype++;
}
/* Free the array itself, now that its contents have been freed */
free(mimetypes);
}
/** /**
* Creates a new guac_client for the connection on the given socket, adding * Creates a new guac_client for the connection on the given socket, adding
* it to the client map based on its ID. * it to the client map based on its ID.
@ -164,6 +222,14 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
return; return;
} }
/* Get client */
client = guac_client_alloc();
if (client == NULL) {
guacd_log_guac_error(GUAC_LOG_ERROR, "Unable to create client");
guac_socket_free(socket);
return;
}
/* Get optimal screen size */ /* Get optimal screen size */
size = guac_instruction_expect( size = guac_instruction_expect(
socket, GUACD_USEC_TIMEOUT, "size"); socket, GUACD_USEC_TIMEOUT, "size");
@ -174,10 +240,25 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"size\""); guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"size\"");
/* Free resources */ /* Free resources */
guac_client_free(client);
guac_socket_free(socket); guac_socket_free(socket);
return; return;
} }
/* Parse optimal screen dimensions from size instruction */
client->info.optimal_width = atoi(size->argv[0]);
client->info.optimal_height = atoi(size->argv[1]);
/* If DPI given, set the client resolution */
if (size->argc >= 3)
client->info.optimal_resolution = atoi(size->argv[2]);
/* Otherwise, use a safe default for rough backwards compatibility */
else
client->info.optimal_resolution = 96;
guac_instruction_free(size);
/* Get supported audio formats */ /* Get supported audio formats */
audio = guac_instruction_expect( audio = guac_instruction_expect(
socket, GUACD_USEC_TIMEOUT, "audio"); socket, GUACD_USEC_TIMEOUT, "audio");
@ -188,10 +269,17 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"audio\""); guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"audio\"");
/* Free resources */ /* Free resources */
guac_client_free(client);
guac_socket_free(socket); guac_socket_free(socket);
return; return;
} }
/* Store audio mimetypes */
client->info.audio_mimetypes =
guacd_copy_mimetypes(audio->argv, audio->argc);
guac_instruction_free(audio);
/* Get supported video formats */ /* Get supported video formats */
video = guac_instruction_expect( video = guac_instruction_expect(
socket, GUACD_USEC_TIMEOUT, "video"); socket, GUACD_USEC_TIMEOUT, "video");
@ -202,10 +290,17 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"video\""); guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"video\"");
/* Free resources */ /* Free resources */
guac_client_free(client);
guac_socket_free(socket); guac_socket_free(socket);
return; return;
} }
/* Store video mimetypes */
client->info.video_mimetypes =
guacd_copy_mimetypes(video->argv, video->argc);
guac_instruction_free(video);
/* Get supported image formats */ /* Get supported image formats */
image = guac_instruction_expect( image = guac_instruction_expect(
socket, GUACD_USEC_TIMEOUT, "image"); socket, GUACD_USEC_TIMEOUT, "image");
@ -216,10 +311,17 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"image\""); guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"image\"");
/* Free resources */ /* Free resources */
guac_client_free(client);
guac_socket_free(socket); guac_socket_free(socket);
return; return;
} }
/* Store image mimetypes */
client->info.image_mimetypes =
guacd_copy_mimetypes(image->argv, image->argc);
guac_instruction_free(image);
/* Get args from connect instruction */ /* Get args from connect instruction */
connect = guac_instruction_expect( connect = guac_instruction_expect(
socket, GUACD_USEC_TIMEOUT, "connect"); socket, GUACD_USEC_TIMEOUT, "connect");
@ -233,14 +335,7 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
guacd_log_guac_error(GUAC_LOG_WARNING, guacd_log_guac_error(GUAC_LOG_WARNING,
"Unable to close client plugin"); "Unable to close client plugin");
guac_socket_free(socket); guac_client_free(client);
return;
}
/* Get client */
client = guac_client_alloc();
if (client == NULL) {
guacd_log_guac_error(GUAC_LOG_ERROR, "Unable to create client");
guac_socket_free(socket); guac_socket_free(socket);
return; return;
} }
@ -248,36 +343,6 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
client->socket = socket; client->socket = socket;
client->log_handler = guacd_client_log; client->log_handler = guacd_client_log;
/* Parse optimal screen dimensions from size instruction */
client->info.optimal_width = atoi(size->argv[0]);
client->info.optimal_height = atoi(size->argv[1]);
/* If DPI given, set the client resolution */
if (size->argc >= 3)
client->info.optimal_resolution = atoi(size->argv[2]);
/* Otherwise, use a safe default for rough backwards compatibility */
else
client->info.optimal_resolution = 96;
/* Store audio mimetypes */
client->info.audio_mimetypes = malloc(sizeof(char*) * (audio->argc+1));
memcpy(client->info.audio_mimetypes, audio->argv,
sizeof(char*) * audio->argc);
client->info.audio_mimetypes[audio->argc] = NULL;
/* Store video mimetypes */
client->info.video_mimetypes = malloc(sizeof(char*) * (video->argc+1));
memcpy(client->info.video_mimetypes, video->argv,
sizeof(char*) * video->argc);
client->info.video_mimetypes[video->argc] = NULL;
/* Store image mimetypes */
client->info.image_mimetypes = malloc(sizeof(char*) * (image->argc+1));
memcpy(client->info.image_mimetypes, image->argv,
sizeof(char*) * image->argc);
client->info.image_mimetypes[image->argc] = NULL;
/* Store client */ /* Store client */
if (guacd_client_map_add(map, client)) if (guacd_client_map_add(map, client))
guacd_log(GUAC_LOG_ERROR, "Unable to add client. Internal client storage has failed"); guacd_log(GUAC_LOG_ERROR, "Unable to add client. Internal client storage has failed");
@ -319,15 +384,9 @@ static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket)
guacd_log(GUAC_LOG_ERROR, "Unable to remove client. Internal client storage has failed"); guacd_log(GUAC_LOG_ERROR, "Unable to remove client. Internal client storage has failed");
/* Free mimetype lists */ /* Free mimetype lists */
free(client->info.audio_mimetypes); guacd_free_mimetypes(client->info.audio_mimetypes);
free(client->info.video_mimetypes); guacd_free_mimetypes(client->info.video_mimetypes);
free(client->info.image_mimetypes); guacd_free_mimetypes(client->info.image_mimetypes);
/* Free remaining instructions */
guac_instruction_free(audio);
guac_instruction_free(video);
guac_instruction_free(image);
guac_instruction_free(size);
/* Clean up */ /* Clean up */
guac_client_free(client); guac_client_free(client);