Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/libguac/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,25 @@ guac_stream* guac_client_alloc_stream(guac_client* client) {
allocd_stream->ack_handler = NULL;
allocd_stream->blob_handler = NULL;
allocd_stream->end_handler = NULL;
allocd_stream->free_handler = NULL;

return allocd_stream;

}

void guac_client_free_stream(guac_client* client, guac_stream* stream) {

/* Run the registered free handler for the stream's data, if any */
if (stream->free_handler != NULL)
stream->free_handler(stream->data);

/* Clean up any remaining dangling pointers before permitting reuse */
stream->data = NULL;
stream->ack_handler = NULL;
stream->blob_handler = NULL;
stream->end_handler = NULL;
stream->free_handler = NULL;

/* Mark stream as closed */
int freed_index = stream->index;
stream->index = GUAC_CLIENT_CLOSED_STREAM_INDEX;
Expand Down Expand Up @@ -289,6 +301,7 @@ guac_client* guac_client_alloc(void) {

for (i=0; i<GUAC_CLIENT_MAX_STREAMS; i++) {
client->__output_streams[i].index = GUAC_CLIENT_CLOSED_STREAM_INDEX;
client->__output_streams[i].free_handler = NULL;
}

/* Init locks */
Expand Down Expand Up @@ -344,6 +357,15 @@ void guac_client_free(guac_client* client) {
guac_pool_free(client->__buffer_pool);
guac_pool_free(client->__layer_pool);

/* Run any registered free handlers for streams still open at
* disconnect so their data pointers do not leak */
for (int i = 0; i < GUAC_CLIENT_MAX_STREAMS; i++) {
guac_stream* stream = &client->__output_streams[i];
if (stream->index != GUAC_CLIENT_CLOSED_STREAM_INDEX
&& stream->free_handler != NULL)
stream->free_handler(stream->data);
}

/* Free streams */
guac_mem_free(client->__output_streams);

Expand Down
32 changes: 32 additions & 0 deletions src/libguac/guacamole/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,38 @@ int guac_protocol_send_clipboard(guac_socket* socket, const guac_stream* stream,
*/
int guac_protocol_send_name(guac_socket* socket, const char* name);

/**
* Sends an auth-challenge instruction over the given guac_socket
* connection, announcing a stream carrying the challenge body for a
* pending authentication exchange. The peer responds via an
* auth-response instruction carrying the same challenge_id.
*
* The body is shipped on the given stream as blobs, terminated by an
* end, after this function returns. Callers are responsible for
* allocating and freeing the stream.
*
* @param socket
* The guac_socket connection to use.
*
* @param stream
* The stream along which the challenge body will be sent.
*
* @param mimetype
* The mimetype of the data that will be sent along the given stream.
* The mimetype identifies the auth flavor (e.g. WebAuthn create vs.
* get).
*
* @param challenge_id
* Opaque identifier carried by the auth-challenge. The peer's
* matching auth-response will reference this identifier.
*
* @return
* Zero on success, non-zero on error.
*/
int guac_protocol_send_auth_challenge(guac_socket* socket,
const guac_stream* stream, const char* mimetype,
const char* challenge_id);

/**
* Decodes the given base64-encoded string in-place. The base64 string must
* be NULL-terminated.
Expand Down
28 changes: 28 additions & 0 deletions src/libguac/guacamole/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,34 @@ struct guac_stream {
*/
guac_user_end_handler* end_handler;

/**
* Optional cleanup callback for whatever the stream's data pointer
* holds. Called from guac_user_free_stream when the stream is freed,
* and from guac_user_free for any streams still open when the user
* disconnects. NULL if no cleanup is needed.
*
* Example:
* @code
* static void my_data_free(void* data) {
* my_data* d = (my_data*) data;
* free(d->buffer);
* free(d);
* }
*
* int my_pipe_handler(guac_user* user, guac_stream* stream,
* char* mimetype, char* name) {
* my_data* d = malloc(sizeof(*d));
* d->buffer = NULL;
* stream->data = d;
* stream->blob_handler = my_blob_handler;
* stream->end_handler = my_end_handler;
* stream->free_handler = my_data_free;
* return 0;
* }
* @endcode
*/
guac_stream_free_handler* free_handler;

};

#endif
Expand Down
42 changes: 40 additions & 2 deletions src/libguac/guacamole/user-fntypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,18 @@ typedef int guac_user_ack_handler(guac_user* user, guac_stream* stream,
*/
typedef int guac_user_end_handler(guac_user* user, guac_stream* stream);

/**
* Optional cleanup callback installed on a guac_stream for whatever the
* stream's data pointer holds. Called from guac_user_free_stream and
* guac_client_free_stream when the stream is freed, and from
* guac_user_free and guac_client_free for any streams still open when
* the user or client is disposed.
*
* @param data
* The stream's data pointer at the time the stream is being freed.
*/
typedef void guac_stream_free_handler(void* data);

/**
* Handler for Guacamole join events. A join event is fired by the
* guac_client whenever a guac_user joins the connection. There is no
Expand Down Expand Up @@ -500,7 +512,7 @@ typedef int guac_user_put_handler(guac_user* user, guac_object* object,
guac_stream* stream, char* mimetype, char* name);

/**
* Handler for Guacamole USB connect events, invoked when a "usbconnect"
* Handler for Guacamole USB connect events, invoked when a "usbconnect"
* instruction has been received from a user. This indicates that the user
* has connected a USB device via WebUSB and it is available for redirection.
*
Expand Down Expand Up @@ -540,10 +552,36 @@ typedef int guac_user_put_handler(guac_user* user, guac_object* object,
* an error occurred.
*/
typedef int guac_user_usbconnect_handler(guac_user* user, const char* device_id,
int vendor_id, int product_id, const char* device_name,
int vendor_id, int product_id, const char* device_name,
const char* serial_number, int device_class, int device_subclass,
int device_protocol, const char* interface_data);

/**
* Handler for Guacamole "auth-response" events, invoked when an
* "auth-response" instruction has been received from a user. An
* auth-response announces a stream carrying the response body for a
* previously-issued auth-challenge identified by the same challenge_id.
*
* @param user
* The user that sent the auth-response.
*
* @param stream
* The stream along which the response body will be received.
*
* @param mimetype
* The mimetype of the data that will be received along the given
* stream.
*
* @param challenge_id
* The challenge identifier of the originating auth-challenge being
* responded to.
*
* @return
* Zero on success, non-zero on error.
*/
typedef int guac_user_auth_response_handler(guac_user* user,
guac_stream* stream, char* mimetype, char* challenge_id);

/**
* Handler for Guacamole USB data events, invoked when a "usbdata" instruction
* has been received from a user. This carries data from a client-side USB
Expand Down
18 changes: 18 additions & 0 deletions src/libguac/guacamole/user.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,24 @@ struct guac_user {
*/
guac_user_usbdisconnect_handler* usbdisconnect_handler;

/**
* Handler for "auth-response" events sent by the Guacamole web-client,
* carrying the response body for a previously-issued auth-challenge
* identified by the same challenge_id. The handler installs the blob
* and end handlers on the stream so the body can be consumed.
*
* Example:
* @code
* int auth_response_handler(guac_user* user, guac_stream* stream,
* char* mimetype, char* challenge_id);
*
* int guac_user_init(guac_user* user, int argc, char** argv) {
* user->auth_response_handler = auth_response_handler;
* }
* @endcode
*/
guac_user_auth_response_handler* auth_response_handler;

};

/**
Expand Down
23 changes: 22 additions & 1 deletion src/libguac/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1301,7 +1301,7 @@ int guac_protocol_send_video(guac_socket* socket, const guac_stream* stream,
int ret_val;

guac_socket_instruction_begin(socket);
ret_val =
ret_val =
guac_socket_write_string(socket, "5.video,")
|| __guac_socket_write_length_int(socket, stream->index)
|| guac_socket_write_string(socket, ",")
Expand All @@ -1315,6 +1315,27 @@ int guac_protocol_send_video(guac_socket* socket, const guac_stream* stream,

}

int guac_protocol_send_auth_challenge(guac_socket* socket,
const guac_stream* stream, const char* mimetype,
const char* challenge_id) {

int ret_val;

guac_socket_instruction_begin(socket);
ret_val =
guac_socket_write_string(socket, "14.auth-challenge,")
|| __guac_socket_write_length_int(socket, stream->index)
|| guac_socket_write_string(socket, ",")
|| __guac_socket_write_length_string(socket, mimetype)
|| guac_socket_write_string(socket, ",")
|| __guac_socket_write_length_string(socket, challenge_id)
|| guac_socket_write_string(socket, ";");
guac_socket_instruction_end(socket);

return ret_val;

}

/**
* Returns the value of a single base64 character.
*/
Expand Down
5 changes: 4 additions & 1 deletion src/libguac/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ noinst_HEADERS = \
test_libguac_SOURCES = \
client/buffer_pool.c \
client/layer_pool.c \
client/stream_free_handler.c \
fifo/fifo.c \
file/openat.c \
flag/flag.c \
Expand All @@ -59,6 +60,7 @@ test_libguac_SOURCES = \
pool/next_free.c \
protocol/base64_decode.c \
protocol/guac_protocol_version.c \
protocol/auth_send.c \
rect/align.c \
rect/constrain.c \
rect/extend.c \
Expand All @@ -74,7 +76,8 @@ test_libguac_SOURCES = \
unicode/charsize.c \
unicode/read.c \
unicode/strlen.c \
unicode/write.c
unicode/write.c \
user/auth_dispatch.c

test_libguac_CFLAGS = \
-Werror -Wall -pedantic \
Expand Down
Loading
Loading