diff --git a/src/guacd/Makefile.am b/src/guacd/Makefile.am index f56e37e1..1833fbaf 100644 --- a/src/guacd/Makefile.am +++ b/src/guacd/Makefile.am @@ -30,6 +30,7 @@ man_MANS = man/guacd.8 noinst_HEADERS = \ client.h \ client-map.h \ + conf-args.h \ conf-file.h \ conf-parse.h \ log.h @@ -38,6 +39,7 @@ guacd_SOURCES = \ daemon.c \ client.c \ client-map.c \ + conf-args.c \ conf-file.c \ conf-parse.c \ log.c diff --git a/src/guacd/conf-args.c b/src/guacd/conf-args.c new file mode 100644 index 00000000..1b9382a6 --- /dev/null +++ b/src/guacd/conf-args.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config.h" + +#include "conf-args.h" +#include "conf-file.h" + +#include +#include +#include +#include + +int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) { + + /* Parse arguments */ + int opt; + while ((opt = getopt(argc, argv, "l:b:p:C:K:f")) != -1) { + + /* -l: Bind port */ + if (opt == 'l') { + free(config->bind_port); + config->bind_port = strdup(optarg); + } + + /* -b: Bind host */ + else if (opt == 'b') { + free(config->bind_host); + config->bind_host = strdup(optarg); + } + + /* -f: Run in foreground */ + else if (opt == 'f') { + config->foreground = 1; + } + + /* -p: PID file */ + else if (opt == 'p') { + free(config->pidfile); + config->pidfile = strdup(optarg); + } + +#ifdef ENABLE_SSL + /* -C SSL certificate */ + else if (opt == 'C') { + free(config->cert_file); + config->cert_file = strdup(optarg); + } + + /* -K SSL key */ + else if (opt == 'K') { + free(config->key_file); + config->key_file = strdup(optarg); + } +#else + else if (opt == 'C' || opt == 'K') { + fprintf(stderr, + "This guacd does not have SSL/TLS support compiled in.\n\n" + + "If you wish to enable support for the -%c option, please install libssl and\n" + "recompile guacd.\n", + opt); + return 1; + } +#endif + else { + + fprintf(stderr, "USAGE: %s" + " [-l LISTENPORT]" + " [-b LISTENADDRESS]" + " [-p PIDFILE]" +#ifdef ENABLE_SSL + " [-C CERTIFICATE_FILE]" + " [-K PEM_FILE]" +#endif + " [-f]\n", argv[0]); + + return 1; + } + } + + /* Success */ + return 0; + +} + diff --git a/src/guacd/conf-args.h b/src/guacd/conf-args.h new file mode 100644 index 00000000..6cb97d4e --- /dev/null +++ b/src/guacd/conf-args.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _GUACD_CONF_ARGS_H +#define _GUACD_CONF_ARGS_H + +#include "config.h" + +#include "conf-file.h" + +/** + * Parses the given arguments into the given configuration. Zero is returned on + * success, and non-zero is returned if arguments cannot be parsed. + */ +int guacd_conf_parse_args(guacd_config* config, int argc, char** argv); + +#endif + diff --git a/src/guacd/conf-file.c b/src/guacd/conf-file.c index ac9b41e9..002e883c 100644 --- a/src/guacd/conf-file.c +++ b/src/guacd/conf-file.c @@ -25,12 +25,33 @@ #include "conf-file.h" #include "conf-parse.h" -int guacd_conf_parse_file(guacd_config* conf, int fd) { +#include +#include - /* Load defaults */ - conf->bind_port = 4822; +int guacd_conf_parse_file(guacd_config* conf, int fd) { /* STUB */ return 0; } +guacd_config* guacd_conf_load() { + + guacd_config* conf = malloc(sizeof(guacd_config)); + if (conf == NULL) + return NULL; + + /* Load defaults */ + conf->bind_host = NULL; + conf->bind_port = strdup("4822"); + conf->pidfile = NULL; + conf->foreground = 0; + +#ifdef ENABLE_SSL + conf->cert_file = NULL; + conf->key_file = NULL; +#endif + + return conf; + +} + diff --git a/src/guacd/conf-file.h b/src/guacd/conf-file.h index d7f6ea55..ae8744c7 100644 --- a/src/guacd/conf-file.h +++ b/src/guacd/conf-file.h @@ -30,10 +30,37 @@ */ typedef struct guacd_config { + /** + * The host to bind on. + */ + char* bind_host; + /** * The port to bind on. */ - int bind_port; + char* bind_port; + + /** + * The file to write the PID in, if any. + */ + char* pidfile; + + /** + * Whether guacd should run in the foreground. + */ + int foreground; + +#ifdef ENABLE_SSL + /** + * SSL certificate file. + */ + char* cert_file; + + /** + * SSL private key file. + */ + char* key_file; +#endif } guacd_config; @@ -44,5 +71,11 @@ typedef struct guacd_config { */ int guacd_conf_parse_file(guacd_config* conf, int fd); +/** + * Loads the configuration from any of several default locations, if found. If + * parsing fails, NULL is returned, and an error message is printed to stderr. + */ +guacd_config* guacd_conf_load(); + #endif diff --git a/src/guacd/daemon.c b/src/guacd/daemon.c index 7265af60..2aac4237 100644 --- a/src/guacd/daemon.c +++ b/src/guacd/daemon.c @@ -24,6 +24,8 @@ #include "client.h" #include "client-map.h" +#include "conf-args.h" +#include "conf-file.h" #include "log.h" #include @@ -40,7 +42,6 @@ #include #include -#include #include #include #include @@ -375,17 +376,7 @@ int main(int argc, char* argv[]) { socklen_t client_addr_len; int connected_socket_fd; - /* Arguments */ - char* listen_address = NULL; /* Default address of INADDR_ANY */ - char* listen_port = "4822"; /* Default port */ - char* pidfile = NULL; - int opt; - int foreground = 0; - #ifdef ENABLE_SSL - /* SSL */ - char* cert_file = NULL; - char* key_file = NULL; SSL_CTX* ssl_context = NULL; #endif @@ -394,53 +385,10 @@ int main(int argc, char* argv[]) { /* General */ int retval; - /* Parse arguments */ - while ((opt = getopt(argc, argv, "l:b:p:C:K:f")) != -1) { - if (opt == 'l') { - listen_port = strdup(optarg); - } - else if (opt == 'b') { - listen_address = strdup(optarg); - } - else if (opt == 'f') { - foreground = 1; - } - else if (opt == 'p') { - pidfile = strdup(optarg); - } -#ifdef ENABLE_SSL - else if (opt == 'C') { - cert_file = strdup(optarg); - } - else if (opt == 'K') { - key_file = strdup(optarg); - } -#else - else if (opt == 'C' || opt == 'K') { - fprintf(stderr, - "This guacd does not have SSL/TLS support compiled in.\n\n" - - "If you wish to enable support for the -%c option, please install libssl and\n" - "recompile guacd.\n", - opt); - exit(EXIT_FAILURE); - } -#endif - else { - - fprintf(stderr, "USAGE: %s" - " [-l LISTENPORT]" - " [-b LISTENADDRESS]" - " [-p PIDFILE]" -#ifdef ENABLE_SSL - " [-C CERTIFICATE_FILE]" - " [-K PEM_FILE]" -#endif - " [-f]\n", argv[0]); - - exit(EXIT_FAILURE); - } - } + /* Load configuration */ + guacd_config* config = guacd_conf_load(); + if (config == NULL || guacd_conf_parse_args(config, argc, argv)) + exit(EXIT_FAILURE); /* Set up logging prefix */ strncpy(log_prefix, basename(argv[0]), sizeof(log_prefix)); @@ -452,7 +400,7 @@ int main(int argc, char* argv[]) { guacd_log_info("Guacamole proxy daemon (guacd) version " VERSION); /* Get addresses for binding */ - if ((retval = getaddrinfo(listen_address, listen_port, + if ((retval = getaddrinfo(config->bind_host, config->bind_port, &hints, &addresses))) { guacd_log_error("Error parsing given address or port: %s", @@ -521,7 +469,7 @@ int main(int argc, char* argv[]) { #ifdef ENABLE_SSL /* Init SSL if enabled */ - if (key_file != NULL || cert_file != NULL) { + if (config->key_file != NULL || config->cert_file != NULL) { /* Init SSL */ guacd_log_info("Communication will require SSL/TLS."); @@ -530,9 +478,9 @@ int main(int argc, char* argv[]) { ssl_context = SSL_CTX_new(SSLv23_server_method()); /* Load key */ - if (key_file != NULL) { - guacd_log_info("Using PEM keyfile %s", key_file); - if (!SSL_CTX_use_PrivateKey_file(ssl_context, key_file, SSL_FILETYPE_PEM)) { + if (config->key_file != NULL) { + guacd_log_info("Using PEM keyfile %s", config->key_file); + if (!SSL_CTX_use_PrivateKey_file(ssl_context, config->key_file, SSL_FILETYPE_PEM)) { guacd_log_error("Unable to load keyfile."); exit(EXIT_FAILURE); } @@ -541,9 +489,9 @@ int main(int argc, char* argv[]) { guacd_log_info("No PEM keyfile given - SSL/TLS may not work."); /* Load cert file if specified */ - if (cert_file != NULL) { - guacd_log_info("Using certificate file %s", cert_file); - if (!SSL_CTX_use_certificate_chain_file(ssl_context, cert_file)) { + if (config->cert_file != NULL) { + guacd_log_info("Using certificate file %s", config->cert_file); + if (!SSL_CTX_use_certificate_chain_file(ssl_context, config->cert_file)) { guacd_log_error("Unable to load certificate."); exit(EXIT_FAILURE); } @@ -555,7 +503,7 @@ int main(int argc, char* argv[]) { #endif /* Daemonize if requested */ - if (!foreground) { + if (!config->foreground) { /* Attempt to daemonize process */ if (daemonize()) { @@ -566,10 +514,10 @@ int main(int argc, char* argv[]) { } /* Write PID file if requested */ - if (pidfile != NULL) { + if (config->pidfile != NULL) { /* Attempt to open pidfile and write PID */ - FILE* pidf = fopen(pidfile, "w"); + FILE* pidf = fopen(config->pidfile, "w"); if (pidf) { fprintf(pidf, "%d\n", getpid()); fclose(pidf);