Repository: incubator-guacamole-server Updated Branches: refs/heads/master 396eaa21f -> 5d2c9676f
GUACAMOLE-175: Move common core of guacd into libguacd utility library. Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/d7a604c8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/d7a604c8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/d7a604c8 Branch: refs/heads/master Commit: d7a604c8b29574be21002ad5c90ff27d76301824 Parents: a1886f5 Author: Michael Jumper <[email protected]> Authored: Fri Sep 9 10:44:16 2016 -0700 Committer: Michael Jumper <[email protected]> Committed: Tue Jan 24 15:44:51 2017 -0800 ---------------------------------------------------------------------- Makefile.am | 8 +- configure.ac | 5 ++ src/guacd/Makefile.am | 20 ++--- src/guacd/log.c | 168 ----------------------------------------- src/guacd/log.h | 80 -------------------- src/guacd/socket-ssl.c | 153 ------------------------------------- src/guacd/socket-ssl.h | 71 ----------------- src/guacd/user.c | 113 --------------------------- src/guacd/user.h | 98 ------------------------ src/libguacd/Makefile.am | 50 ++++++++++++ src/libguacd/log.c | 168 +++++++++++++++++++++++++++++++++++++++++ src/libguacd/log.h | 80 ++++++++++++++++++++ src/libguacd/socket-ssl.c | 153 +++++++++++++++++++++++++++++++++++++ src/libguacd/socket-ssl.h | 71 +++++++++++++++++ src/libguacd/user.c | 113 +++++++++++++++++++++++++++ src/libguacd/user.h | 98 ++++++++++++++++++++++++ 16 files changed, 749 insertions(+), 700 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/Makefile.am ---------------------------------------------------------------------- diff --git a/Makefile.am b/Makefile.am index 54899e9..78f76e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ ACLOCAL_AMFLAGS = -I m4 # Subprojects DIST_SUBDIRS = \ src/libguac \ + src/libguacd \ src/common \ src/common-ssh \ src/terminal \ @@ -33,9 +34,10 @@ DIST_SUBDIRS = \ src/protocols/vnc \ tests -SUBDIRS = \ - src/libguac \ - src/common \ +SUBDIRS = \ + src/libguac \ + src/common \ + src/libguacd \ tests if ENABLE_COMMON_SSH http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/configure.ac ---------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 4c43359..a763d6a 100644 --- a/configure.ac +++ b/configure.ac @@ -119,6 +119,10 @@ AC_SUBST([LIBGUAC_INCLUDE], '-I$(top_srcdir)/src/libguac') AC_SUBST([COMMON_LTLIB], '$(top_builddir)/src/common/libguac_common.la') AC_SUBST([COMMON_INCLUDE], '-I$(top_srcdir)/src/common') +# Common utility library for guacd implementations +AC_SUBST([LIBGUACD_LTLIB], '$(top_builddir)/src/libguacd/libguacd.la') +AC_SUBST([LIBGUACD_INCLUDE], '-I$(top_srcdir)/src/libguacd') + # Common base SSH client AC_SUBST([COMMON_SSH_LTLIB], '$(top_builddir)/src/common-ssh/libguac_common_ssh.la') AC_SUBST([COMMON_SSH_INCLUDE], '-I$(top_srcdir)/src/common-ssh') @@ -1101,6 +1105,7 @@ AC_CONFIG_FILES([Makefile src/common-ssh/Makefile src/terminal/Makefile src/libguac/Makefile + src/libguacd/Makefile src/guacd/Makefile src/guacenc/Makefile src/protocols/rdp/Makefile http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/Makefile.am ---------------------------------------------------------------------- diff --git a/src/guacd/Makefile.am b/src/guacd/Makefile.am index 51e5f87..e25a101 100644 --- a/src/guacd/Makefile.am +++ b/src/guacd/Makefile.am @@ -30,11 +30,9 @@ noinst_HEADERS = \ conf-file.h \ conf-parse.h \ connection.h \ - log.h \ move-fd.h \ proc.h \ - proc-map.h \ - user.h + proc-map.h guacd_SOURCES = \ conf-args.c \ @@ -42,19 +40,19 @@ guacd_SOURCES = \ conf-parse.c \ connection.c \ daemon.c \ - log.c \ move-fd.c \ proc.c \ - proc-map.c \ - user.c + proc-map.c guacd_CFLAGS = \ -Werror -Wall -pedantic \ @COMMON_INCLUDE@ \ + @LIBGUACD_INCLUDE@ \ @LIBGUAC_INCLUDE@ -guacd_LDADD = \ - @COMMON_LTLIB@ \ +guacd_LDADD = \ + @COMMON_LTLIB@ \ + @LIBGUACD_LTLIB@ \ @LIBGUAC_LTLIB@ guacd_LDFLAGS = \ @@ -68,12 +66,6 @@ EXTRA_DIST = \ CLEANFILES = $(init_SCRIPTS) -# SSL support -if ENABLE_SSL -noinst_HEADERS += socket-ssl.h -guacd_SOURCES += socket-ssl.c -endif - # Init script if ENABLE_INIT initdir = @init_dir@ http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/log.c ---------------------------------------------------------------------- diff --git a/src/guacd/log.c b/src/guacd/log.c deleted file mode 100644 index 229d2f9..0000000 --- a/src/guacd/log.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" -#include "log.h" - -#include <guacamole/client.h> -#include <guacamole/error.h> - -#include <stdarg.h> -#include <stdio.h> -#include <syslog.h> -#include <unistd.h> - -int guacd_log_level = GUAC_LOG_INFO; - -void vguacd_log(guac_client_log_level level, const char* format, - va_list args) { - - const char* priority_name; - int priority; - - char message[2048]; - - /* Don't bother if the log level is too high */ - if (level > guacd_log_level) - return; - - /* Copy log message into buffer */ - vsnprintf(message, sizeof(message), format, args); - - /* Convert log level to syslog priority */ - switch (level) { - - /* Error log level */ - case GUAC_LOG_ERROR: - priority = LOG_ERR; - priority_name = "ERROR"; - break; - - /* Warning log level */ - case GUAC_LOG_WARNING: - priority = LOG_WARNING; - priority_name = "WARNING"; - break; - - /* Informational log level */ - case GUAC_LOG_INFO: - priority = LOG_INFO; - priority_name = "INFO"; - break; - - /* Debug log level */ - case GUAC_LOG_DEBUG: - priority = LOG_DEBUG; - priority_name = "DEBUG"; - break; - - /* Any unknown/undefined log level */ - default: - priority = LOG_INFO; - priority_name = "UNKNOWN"; - break; - } - - /* Log to syslog */ - syslog(priority, "%s", message); - - /* Log to STDERR */ - fprintf(stderr, GUACD_LOG_NAME "[%i]: %s:\t%s\n", - getpid(), priority_name, message); - -} - -void guacd_log(guac_client_log_level level, const char* format, ...) { - va_list args; - va_start(args, format); - vguacd_log(level, format, args); - va_end(args); -} - -void guacd_client_log(guac_client* client, guac_client_log_level level, - const char* format, va_list args) { - vguacd_log(level, format, args); -} - -void guacd_log_guac_error(guac_client_log_level level, const char* message) { - - if (guac_error != GUAC_STATUS_SUCCESS) { - - /* If error message provided, include in log */ - if (guac_error_message != NULL) - guacd_log(level, "%s: %s", - message, - guac_error_message); - - /* Otherwise just log with standard status string */ - else - guacd_log(level, "%s: %s", - message, - guac_status_string(guac_error)); - - } - - /* Just log message if no status code */ - else - guacd_log(level, "%s", message); - -} - -void guacd_client_log_guac_error(guac_client* client, - guac_client_log_level level, const char* message) { - - if (guac_error != GUAC_STATUS_SUCCESS) { - - /* If error message provided, include in log */ - if (guac_error_message != NULL) - guac_client_log(client, level, "%s: %s", - message, - guac_error_message); - - /* Otherwise just log with standard status string */ - else - guac_client_log(client, level, "%s: %s", - message, - guac_status_string(guac_error)); - - } - - /* Just log message if no status code */ - else - guac_client_log(client, level, "%s", message); - -} - -void guacd_log_handshake_failure() { - - if (guac_error == GUAC_STATUS_CLOSED) - guacd_log(GUAC_LOG_INFO, - "Guacamole connection closed during handshake"); - else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR) - guacd_log(GUAC_LOG_ERROR, - "Guacamole protocol violation. Perhaps the version of " - "guacamole-client is incompatible with this version of " - "guacd?"); - else - guacd_log(GUAC_LOG_WARNING, - "Guacamole handshake failed: %s", - guac_status_string(guac_error)); - -} - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/log.h ---------------------------------------------------------------------- diff --git a/src/guacd/log.h b/src/guacd/log.h deleted file mode 100644 index 09fe152..0000000 --- a/src/guacd/log.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -#ifndef __GUACD_LOG_H -#define __GUACD_LOG_H - -#include "config.h" - -#include <guacamole/client.h> - -/** - * The maximum level at which to log messages. All other messages will be - * dropped. - */ -extern int guacd_log_level; - -/** - * The string to prepend to all log messages. - */ -#define GUACD_LOG_NAME "guacd" - -/** - * Writes a message to guacd's logs. This function takes a format and va_list, - * similar to vprintf. - */ -void vguacd_log(guac_client_log_level level, const char* format, va_list args); - -/** - * Writes a message to guacd's logs. This function accepts parameters - * identically to printf. - */ -void guacd_log(guac_client_log_level level, const char* format, ...); - -/** - * Writes a message using the logging facilities of the given client. This - * function accepts parameters identically to printf. - */ -void guacd_client_log(guac_client* client, guac_client_log_level level, - const char* format, va_list args); - -/** - * Prints an error message to guacd's logs, automatically including any - * information present in guac_error. This function accepts parameters - * identically to printf. - */ -void guacd_log_guac_error(guac_client_log_level level, const char* message); - -/** - * Prints an error message using the logging facilities of the given client, - * automatically including any information present in guac_error. This function - * accepts parameters identically to printf. - */ -void guacd_client_log_guac_error(guac_client* client, - guac_client_log_level level, const char* message); - -/** - * Logs a reasonable explanatory message regarding handshake failure based on - * the current value of guac_error. - */ -void guacd_log_handshake_failure(); - -#endif - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/socket-ssl.c ---------------------------------------------------------------------- diff --git a/src/guacd/socket-ssl.c b/src/guacd/socket-ssl.c deleted file mode 100644 index 4f19442..0000000 --- a/src/guacd/socket-ssl.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include "socket-ssl.h" - -#include <poll.h> -#include <stdlib.h> - -#include <guacamole/error.h> -#include <guacamole/socket.h> -#include <openssl/ssl.h> - -static ssize_t __guac_socket_ssl_read_handler(guac_socket* socket, - void* buf, size_t count) { - - /* Read from socket */ - guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; - int retval; - - retval = SSL_read(data->ssl, buf, count); - - /* Record errors in guac_error */ - if (retval <= 0) { - guac_error = GUAC_STATUS_SEE_ERRNO; - guac_error_message = "Error reading data from secure socket"; - } - - return retval; - -} - -static ssize_t __guac_socket_ssl_write_handler(guac_socket* socket, - const void* buf, size_t count) { - - /* Write data to socket */ - guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; - int retval; - - retval = SSL_write(data->ssl, buf, count); - - /* Record errors in guac_error */ - if (retval <= 0) { - guac_error = GUAC_STATUS_SEE_ERRNO; - guac_error_message = "Error writing data to secure socket"; - } - - return retval; - -} - -static int __guac_socket_ssl_select_handler(guac_socket* socket, int usec_timeout) { - - guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; - - int retval; - - /* Initialize with single underlying file descriptor */ - struct pollfd fds[1] = {{ - .fd = data->fd, - .events = POLLIN, - .revents = 0, - }}; - - /* No timeout if usec_timeout is negative */ - if (usec_timeout < 0) - retval = poll(fds, 1, -1); - - /* Handle timeout if specified, rounding up to poll()'s granularity */ - else - retval = poll(fds, 1, (usec_timeout + 999) / 1000); - - /* Properly set guac_error */ - if (retval < 0) { - guac_error = GUAC_STATUS_SEE_ERRNO; - guac_error_message = "Error while waiting for data on secure socket"; - } - - if (retval == 0) { - guac_error = GUAC_STATUS_TIMEOUT; - guac_error_message = "Timeout while waiting for data on secure socket"; - } - - return retval; - -} - -static int __guac_socket_ssl_free_handler(guac_socket* socket) { - - /* Shutdown SSL */ - guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; - SSL_shutdown(data->ssl); - - /* Close file descriptor */ - close(data->fd); - - free(data); - return 0; -} - -guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) { - - /* Allocate socket and associated data */ - guac_socket* socket = guac_socket_alloc(); - guac_socket_ssl_data* data = malloc(sizeof(guac_socket_ssl_data)); - - /* Init SSL */ - data->context = context; - data->ssl = SSL_new(context); - SSL_set_fd(data->ssl, fd); - - /* Accept SSL connection, handle errors */ - if (SSL_accept(data->ssl) <= 0) { - - guac_error = GUAC_STATUS_INTERNAL_ERROR; - guac_error_message = "SSL accept failed"; - - free(data); - guac_socket_free(socket); - return NULL; - } - - /* Store file descriptor as socket data */ - data->fd = fd; - socket->data = data; - - /* Set read/write handlers */ - socket->read_handler = __guac_socket_ssl_read_handler; - socket->write_handler = __guac_socket_ssl_write_handler; - socket->select_handler = __guac_socket_ssl_select_handler; - socket->free_handler = __guac_socket_ssl_free_handler; - - return socket; - -} - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/socket-ssl.h ---------------------------------------------------------------------- diff --git a/src/guacd/socket-ssl.h b/src/guacd/socket-ssl.h deleted file mode 100644 index e1a341e..0000000 --- a/src/guacd/socket-ssl.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -#ifndef __GUACD_SOCKET_SSL_H -#define __GUACD_SOCKET_SSL_H - -#include "config.h" - -#include <guacamole/socket.h> -#include <openssl/ssl.h> - -/** - * SSL socket-specific data. - */ -typedef struct guac_socket_ssl_data { - - /** - * The file descriptor that SSL communication will take place - * over. - */ - int fd; - - /** - * The current SSL context. - */ - SSL_CTX* context; - - /** - * The SSL connection, created automatically via - * guac_socket_open_secure(). - */ - SSL* ssl; - -} guac_socket_ssl_data; - -/** - * Creates a new guac_socket which will use SSL for all communication. Freeing - * this guac_socket will automatically close the associated file descriptor. - * - * @param context - * The SSL_CTX structure describing the desired SSL configuration. - * - * @param fd - * The file descriptor to use for the SSL connection underlying the - * created guac_socket. - * - * @return - * A newly-allocated guac_socket which will transparently use SSL for - * all communication. - */ -guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd); - -#endif - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/user.c ---------------------------------------------------------------------- diff --git a/src/guacd/user.c b/src/guacd/user.c deleted file mode 100644 index 0a37147..0000000 --- a/src/guacd/user.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include "log.h" -#include "user.h" - -#include <guacamole/client.h> -#include <guacamole/error.h> -#include <guacamole/parser.h> -#include <guacamole/protocol.h> -#include <guacamole/socket.h> -#include <guacamole/user.h> - -#include <pthread.h> -#include <stdlib.h> - -void* guacd_user_input_thread(void* data) { - - guacd_user_input_thread_params* params = (guacd_user_input_thread_params*) data; - guac_user* user = params->user; - guac_parser* parser = params->parser; - guac_client* client = user->client; - guac_socket* socket = user->socket; - - /* Guacamole user input loop */ - while (client->state == GUAC_CLIENT_RUNNING && user->active) { - - /* Read instruction, stop on error */ - if (guac_parser_read(parser, socket, GUACD_USEC_TIMEOUT)) { - - if (guac_error == GUAC_STATUS_TIMEOUT) - guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding."); - - else { - if (guac_error != GUAC_STATUS_CLOSED) - guacd_client_log_guac_error(client, GUAC_LOG_WARNING, - "Guacamole connection failure"); - guac_user_stop(user); - } - - return NULL; - } - - /* Reset guac_error and guac_error_message (user/client handlers are not - * guaranteed to set these) */ - guac_error = GUAC_STATUS_SUCCESS; - guac_error_message = NULL; - - /* Call handler, stop on error */ - if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) { - - /* Log error */ - guacd_client_log_guac_error(client, GUAC_LOG_WARNING, - "User connection aborted"); - - /* Log handler details */ - guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode); - - guac_user_stop(user); - return NULL; - } - - } - - return NULL; - -} - -int guacd_user_start(guac_parser* parser, guac_user* user) { - - guacd_user_input_thread_params params = { - .parser = parser, - .user = user - }; - - pthread_t input_thread; - - if (pthread_create(&input_thread, NULL, guacd_user_input_thread, (void*) ¶ms)) { - guac_user_log(user, GUAC_LOG_ERROR, "Unable to start input thread"); - guac_user_stop(user); - return -1; - } - - /* Wait for I/O threads */ - pthread_join(input_thread, NULL); - - /* Explicitly signal disconnect */ - guac_protocol_send_disconnect(user->socket); - guac_socket_flush(user->socket); - - /* Done */ - return 0; - -} - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/user.h ---------------------------------------------------------------------- diff --git a/src/guacd/user.h b/src/guacd/user.h deleted file mode 100644 index 65eef70..0000000 --- a/src/guacd/user.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -#ifndef _GUACD_USER_H -#define _GUACD_USER_H - -#include "config.h" - -#include <guacamole/parser.h> -#include <guacamole/socket.h> -#include <guacamole/user.h> - -/** - * The number of milliseconds to wait for messages in any phase before - * timing out and closing the connection with an error. - */ -#define GUACD_TIMEOUT 15000 - -/** - * The number of microseconds to wait for messages in any phase before - * timing out and closing the conncetion with an error. This is always - * equal to GUACD_TIMEOUT * 1000. - */ -#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000) - -/** - * The maximum number of concurrent connections to a single instance - * of guacd. - */ -#define GUACD_CLIENT_MAX_CONNECTIONS 65536 - -/** - * Parameters required by the user input thread. - */ -typedef struct guacd_user_input_thread_params { - - /** - * The parser which will be used throughout the user's session. - */ - guac_parser* parser; - - /** - * A reference to the connected user. - */ - guac_user* user; - -} guacd_user_input_thread_params; - -/** - * Starts the input/output threads of a new user. This function will block - * until the user disconnects. If an error prevents the input/output threads - * from starting, guac_user_stop() will be invoked on the given user. - * - * @param parser - * The guac_parser to use to handle all input from the given user. - * - * @param user - * The user whose associated I/O transfer threads should be started. - * - * @return - * Zero if the I/O threads started successfully and user has disconnected, - * or non-zero if the I/O threads could not be started. - */ -int guacd_user_start(guac_parser* parser, guac_user* user); - -/** - * The thread which handles all user input, calling event handlers for received - * instructions. - * - * @param data - * A pointer to a guacd_user_input_thread_params structure describing the - * user whose input is being handled and the guac_parser with which to - * handle it. - * - * @return - * Always NULL. - */ -void* guacd_user_input_thread(void* data); - -#endif - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/Makefile.am ---------------------------------------------------------------------- diff --git a/src/libguacd/Makefile.am b/src/libguacd/Makefile.am new file mode 100644 index 0000000..9e20cec --- /dev/null +++ b/src/libguacd/Makefile.am @@ -0,0 +1,50 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +AUTOMAKE_OPTIONS = foreign + +noinst_LTLIBRARIES = libguacd.la + +noinst_HEADERS = \ + log.h \ + user.h + +libguacd_la_SOURCES = \ + log.c \ + user.c + +libguacd_la_CFLAGS = \ + -Werror -Wall -pedantic \ + @COMMON_INCLUDE@ \ + @LIBGUAC_INCLUDE@ + +libguacd_la_LIBADD = \ + @COMMON_LTLIB@ \ + @LIBGUAC_LTLIB@ + +libguacd_la_LDFLAGS = \ + @PTHREAD_LIBS@ \ + @SSL_LIBS@ + +# SSL support +if ENABLE_SSL +noinst_HEADERS += socket-ssl.h +libguacd_la_SOURCES += socket-ssl.c +endif + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/log.c ---------------------------------------------------------------------- diff --git a/src/libguacd/log.c b/src/libguacd/log.c new file mode 100644 index 0000000..229d2f9 --- /dev/null +++ b/src/libguacd/log.c @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" +#include "log.h" + +#include <guacamole/client.h> +#include <guacamole/error.h> + +#include <stdarg.h> +#include <stdio.h> +#include <syslog.h> +#include <unistd.h> + +int guacd_log_level = GUAC_LOG_INFO; + +void vguacd_log(guac_client_log_level level, const char* format, + va_list args) { + + const char* priority_name; + int priority; + + char message[2048]; + + /* Don't bother if the log level is too high */ + if (level > guacd_log_level) + return; + + /* Copy log message into buffer */ + vsnprintf(message, sizeof(message), format, args); + + /* Convert log level to syslog priority */ + switch (level) { + + /* Error log level */ + case GUAC_LOG_ERROR: + priority = LOG_ERR; + priority_name = "ERROR"; + break; + + /* Warning log level */ + case GUAC_LOG_WARNING: + priority = LOG_WARNING; + priority_name = "WARNING"; + break; + + /* Informational log level */ + case GUAC_LOG_INFO: + priority = LOG_INFO; + priority_name = "INFO"; + break; + + /* Debug log level */ + case GUAC_LOG_DEBUG: + priority = LOG_DEBUG; + priority_name = "DEBUG"; + break; + + /* Any unknown/undefined log level */ + default: + priority = LOG_INFO; + priority_name = "UNKNOWN"; + break; + } + + /* Log to syslog */ + syslog(priority, "%s", message); + + /* Log to STDERR */ + fprintf(stderr, GUACD_LOG_NAME "[%i]: %s:\t%s\n", + getpid(), priority_name, message); + +} + +void guacd_log(guac_client_log_level level, const char* format, ...) { + va_list args; + va_start(args, format); + vguacd_log(level, format, args); + va_end(args); +} + +void guacd_client_log(guac_client* client, guac_client_log_level level, + const char* format, va_list args) { + vguacd_log(level, format, args); +} + +void guacd_log_guac_error(guac_client_log_level level, const char* message) { + + if (guac_error != GUAC_STATUS_SUCCESS) { + + /* If error message provided, include in log */ + if (guac_error_message != NULL) + guacd_log(level, "%s: %s", + message, + guac_error_message); + + /* Otherwise just log with standard status string */ + else + guacd_log(level, "%s: %s", + message, + guac_status_string(guac_error)); + + } + + /* Just log message if no status code */ + else + guacd_log(level, "%s", message); + +} + +void guacd_client_log_guac_error(guac_client* client, + guac_client_log_level level, const char* message) { + + if (guac_error != GUAC_STATUS_SUCCESS) { + + /* If error message provided, include in log */ + if (guac_error_message != NULL) + guac_client_log(client, level, "%s: %s", + message, + guac_error_message); + + /* Otherwise just log with standard status string */ + else + guac_client_log(client, level, "%s: %s", + message, + guac_status_string(guac_error)); + + } + + /* Just log message if no status code */ + else + guac_client_log(client, level, "%s", message); + +} + +void guacd_log_handshake_failure() { + + if (guac_error == GUAC_STATUS_CLOSED) + guacd_log(GUAC_LOG_INFO, + "Guacamole connection closed during handshake"); + else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR) + guacd_log(GUAC_LOG_ERROR, + "Guacamole protocol violation. Perhaps the version of " + "guacamole-client is incompatible with this version of " + "guacd?"); + else + guacd_log(GUAC_LOG_WARNING, + "Guacamole handshake failed: %s", + guac_status_string(guac_error)); + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/log.h ---------------------------------------------------------------------- diff --git a/src/libguacd/log.h b/src/libguacd/log.h new file mode 100644 index 0000000..09fe152 --- /dev/null +++ b/src/libguacd/log.h @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef __GUACD_LOG_H +#define __GUACD_LOG_H + +#include "config.h" + +#include <guacamole/client.h> + +/** + * The maximum level at which to log messages. All other messages will be + * dropped. + */ +extern int guacd_log_level; + +/** + * The string to prepend to all log messages. + */ +#define GUACD_LOG_NAME "guacd" + +/** + * Writes a message to guacd's logs. This function takes a format and va_list, + * similar to vprintf. + */ +void vguacd_log(guac_client_log_level level, const char* format, va_list args); + +/** + * Writes a message to guacd's logs. This function accepts parameters + * identically to printf. + */ +void guacd_log(guac_client_log_level level, const char* format, ...); + +/** + * Writes a message using the logging facilities of the given client. This + * function accepts parameters identically to printf. + */ +void guacd_client_log(guac_client* client, guac_client_log_level level, + const char* format, va_list args); + +/** + * Prints an error message to guacd's logs, automatically including any + * information present in guac_error. This function accepts parameters + * identically to printf. + */ +void guacd_log_guac_error(guac_client_log_level level, const char* message); + +/** + * Prints an error message using the logging facilities of the given client, + * automatically including any information present in guac_error. This function + * accepts parameters identically to printf. + */ +void guacd_client_log_guac_error(guac_client* client, + guac_client_log_level level, const char* message); + +/** + * Logs a reasonable explanatory message regarding handshake failure based on + * the current value of guac_error. + */ +void guacd_log_handshake_failure(); + +#endif + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/socket-ssl.c ---------------------------------------------------------------------- diff --git a/src/libguacd/socket-ssl.c b/src/libguacd/socket-ssl.c new file mode 100644 index 0000000..4f19442 --- /dev/null +++ b/src/libguacd/socket-ssl.c @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" + +#include "socket-ssl.h" + +#include <poll.h> +#include <stdlib.h> + +#include <guacamole/error.h> +#include <guacamole/socket.h> +#include <openssl/ssl.h> + +static ssize_t __guac_socket_ssl_read_handler(guac_socket* socket, + void* buf, size_t count) { + + /* Read from socket */ + guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; + int retval; + + retval = SSL_read(data->ssl, buf, count); + + /* Record errors in guac_error */ + if (retval <= 0) { + guac_error = GUAC_STATUS_SEE_ERRNO; + guac_error_message = "Error reading data from secure socket"; + } + + return retval; + +} + +static ssize_t __guac_socket_ssl_write_handler(guac_socket* socket, + const void* buf, size_t count) { + + /* Write data to socket */ + guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; + int retval; + + retval = SSL_write(data->ssl, buf, count); + + /* Record errors in guac_error */ + if (retval <= 0) { + guac_error = GUAC_STATUS_SEE_ERRNO; + guac_error_message = "Error writing data to secure socket"; + } + + return retval; + +} + +static int __guac_socket_ssl_select_handler(guac_socket* socket, int usec_timeout) { + + guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; + + int retval; + + /* Initialize with single underlying file descriptor */ + struct pollfd fds[1] = {{ + .fd = data->fd, + .events = POLLIN, + .revents = 0, + }}; + + /* No timeout if usec_timeout is negative */ + if (usec_timeout < 0) + retval = poll(fds, 1, -1); + + /* Handle timeout if specified, rounding up to poll()'s granularity */ + else + retval = poll(fds, 1, (usec_timeout + 999) / 1000); + + /* Properly set guac_error */ + if (retval < 0) { + guac_error = GUAC_STATUS_SEE_ERRNO; + guac_error_message = "Error while waiting for data on secure socket"; + } + + if (retval == 0) { + guac_error = GUAC_STATUS_TIMEOUT; + guac_error_message = "Timeout while waiting for data on secure socket"; + } + + return retval; + +} + +static int __guac_socket_ssl_free_handler(guac_socket* socket) { + + /* Shutdown SSL */ + guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data; + SSL_shutdown(data->ssl); + + /* Close file descriptor */ + close(data->fd); + + free(data); + return 0; +} + +guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) { + + /* Allocate socket and associated data */ + guac_socket* socket = guac_socket_alloc(); + guac_socket_ssl_data* data = malloc(sizeof(guac_socket_ssl_data)); + + /* Init SSL */ + data->context = context; + data->ssl = SSL_new(context); + SSL_set_fd(data->ssl, fd); + + /* Accept SSL connection, handle errors */ + if (SSL_accept(data->ssl) <= 0) { + + guac_error = GUAC_STATUS_INTERNAL_ERROR; + guac_error_message = "SSL accept failed"; + + free(data); + guac_socket_free(socket); + return NULL; + } + + /* Store file descriptor as socket data */ + data->fd = fd; + socket->data = data; + + /* Set read/write handlers */ + socket->read_handler = __guac_socket_ssl_read_handler; + socket->write_handler = __guac_socket_ssl_write_handler; + socket->select_handler = __guac_socket_ssl_select_handler; + socket->free_handler = __guac_socket_ssl_free_handler; + + return socket; + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/socket-ssl.h ---------------------------------------------------------------------- diff --git a/src/libguacd/socket-ssl.h b/src/libguacd/socket-ssl.h new file mode 100644 index 0000000..e1a341e --- /dev/null +++ b/src/libguacd/socket-ssl.h @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef __GUACD_SOCKET_SSL_H +#define __GUACD_SOCKET_SSL_H + +#include "config.h" + +#include <guacamole/socket.h> +#include <openssl/ssl.h> + +/** + * SSL socket-specific data. + */ +typedef struct guac_socket_ssl_data { + + /** + * The file descriptor that SSL communication will take place + * over. + */ + int fd; + + /** + * The current SSL context. + */ + SSL_CTX* context; + + /** + * The SSL connection, created automatically via + * guac_socket_open_secure(). + */ + SSL* ssl; + +} guac_socket_ssl_data; + +/** + * Creates a new guac_socket which will use SSL for all communication. Freeing + * this guac_socket will automatically close the associated file descriptor. + * + * @param context + * The SSL_CTX structure describing the desired SSL configuration. + * + * @param fd + * The file descriptor to use for the SSL connection underlying the + * created guac_socket. + * + * @return + * A newly-allocated guac_socket which will transparently use SSL for + * all communication. + */ +guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd); + +#endif + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/user.c ---------------------------------------------------------------------- diff --git a/src/libguacd/user.c b/src/libguacd/user.c new file mode 100644 index 0000000..0a37147 --- /dev/null +++ b/src/libguacd/user.c @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" + +#include "log.h" +#include "user.h" + +#include <guacamole/client.h> +#include <guacamole/error.h> +#include <guacamole/parser.h> +#include <guacamole/protocol.h> +#include <guacamole/socket.h> +#include <guacamole/user.h> + +#include <pthread.h> +#include <stdlib.h> + +void* guacd_user_input_thread(void* data) { + + guacd_user_input_thread_params* params = (guacd_user_input_thread_params*) data; + guac_user* user = params->user; + guac_parser* parser = params->parser; + guac_client* client = user->client; + guac_socket* socket = user->socket; + + /* Guacamole user input loop */ + while (client->state == GUAC_CLIENT_RUNNING && user->active) { + + /* Read instruction, stop on error */ + if (guac_parser_read(parser, socket, GUACD_USEC_TIMEOUT)) { + + if (guac_error == GUAC_STATUS_TIMEOUT) + guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding."); + + else { + if (guac_error != GUAC_STATUS_CLOSED) + guacd_client_log_guac_error(client, GUAC_LOG_WARNING, + "Guacamole connection failure"); + guac_user_stop(user); + } + + return NULL; + } + + /* Reset guac_error and guac_error_message (user/client handlers are not + * guaranteed to set these) */ + guac_error = GUAC_STATUS_SUCCESS; + guac_error_message = NULL; + + /* Call handler, stop on error */ + if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) { + + /* Log error */ + guacd_client_log_guac_error(client, GUAC_LOG_WARNING, + "User connection aborted"); + + /* Log handler details */ + guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode); + + guac_user_stop(user); + return NULL; + } + + } + + return NULL; + +} + +int guacd_user_start(guac_parser* parser, guac_user* user) { + + guacd_user_input_thread_params params = { + .parser = parser, + .user = user + }; + + pthread_t input_thread; + + if (pthread_create(&input_thread, NULL, guacd_user_input_thread, (void*) ¶ms)) { + guac_user_log(user, GUAC_LOG_ERROR, "Unable to start input thread"); + guac_user_stop(user); + return -1; + } + + /* Wait for I/O threads */ + pthread_join(input_thread, NULL); + + /* Explicitly signal disconnect */ + guac_protocol_send_disconnect(user->socket); + guac_socket_flush(user->socket); + + /* Done */ + return 0; + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/user.h ---------------------------------------------------------------------- diff --git a/src/libguacd/user.h b/src/libguacd/user.h new file mode 100644 index 0000000..65eef70 --- /dev/null +++ b/src/libguacd/user.h @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef _GUACD_USER_H +#define _GUACD_USER_H + +#include "config.h" + +#include <guacamole/parser.h> +#include <guacamole/socket.h> +#include <guacamole/user.h> + +/** + * The number of milliseconds to wait for messages in any phase before + * timing out and closing the connection with an error. + */ +#define GUACD_TIMEOUT 15000 + +/** + * The number of microseconds to wait for messages in any phase before + * timing out and closing the conncetion with an error. This is always + * equal to GUACD_TIMEOUT * 1000. + */ +#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000) + +/** + * The maximum number of concurrent connections to a single instance + * of guacd. + */ +#define GUACD_CLIENT_MAX_CONNECTIONS 65536 + +/** + * Parameters required by the user input thread. + */ +typedef struct guacd_user_input_thread_params { + + /** + * The parser which will be used throughout the user's session. + */ + guac_parser* parser; + + /** + * A reference to the connected user. + */ + guac_user* user; + +} guacd_user_input_thread_params; + +/** + * Starts the input/output threads of a new user. This function will block + * until the user disconnects. If an error prevents the input/output threads + * from starting, guac_user_stop() will be invoked on the given user. + * + * @param parser + * The guac_parser to use to handle all input from the given user. + * + * @param user + * The user whose associated I/O transfer threads should be started. + * + * @return + * Zero if the I/O threads started successfully and user has disconnected, + * or non-zero if the I/O threads could not be started. + */ +int guacd_user_start(guac_parser* parser, guac_user* user); + +/** + * The thread which handles all user input, calling event handlers for received + * instructions. + * + * @param data + * A pointer to a guacd_user_input_thread_params structure describing the + * user whose input is being handled and the guac_parser with which to + * handle it. + * + * @return + * Always NULL. + */ +void* guacd_user_input_thread(void* data); + +#endif +
