daemon.c (17727B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21 22#include "conf.h" 23#include "conf-args.h" 24#include "conf-file.h" 25#include "connection.h" 26#include "log.h" 27#include "proc-map.h" 28 29#include <guacamole/mem.h> 30 31#ifdef ENABLE_SSL 32#include <openssl/ssl.h> 33#endif 34 35#include <errno.h> 36#include <fcntl.h> 37#include <libgen.h> 38#include <netdb.h> 39#include <netinet/in.h> 40#include <signal.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <syslog.h> 45#include <sys/socket.h> 46#include <sys/stat.h> 47#include <sys/types.h> 48#include <sys/wait.h> 49#include <unistd.h> 50 51#define GUACD_DEV_NULL "/dev/null" 52#define GUACD_ROOT "/" 53 54/** 55 * Redirects the given file descriptor to /dev/null. The given flags must match 56 * the read/write flags of the file descriptor given (if the given file 57 * descriptor was opened write-only, flags here must be O_WRONLY, etc.). 58 * 59 * @param fd 60 * The file descriptor to redirect to /dev/null. 61 * 62 * @param flags 63 * The flags to use when opening /dev/null as the target for redirection. 64 * These flags must match the flags of the file descriptor given. 65 * 66 * @return 67 * Zero on success, non-zero if redirecting the file descriptor fails. 68 */ 69static int redirect_fd(int fd, int flags) { 70 71 /* Attempt to open bit bucket */ 72 int new_fd = open(GUACD_DEV_NULL, flags); 73 if (new_fd < 0) 74 return 1; 75 76 /* If descriptor is different, redirect old to new and close new */ 77 if (new_fd != fd) { 78 dup2(new_fd, fd); 79 close(new_fd); 80 } 81 82 return 0; 83 84} 85 86/** 87 * Turns the current process into a daemon through a series of fork() calls. 88 * The standard I/O file desriptors for STDIN, STDOUT, and STDERR will be 89 * redirected to /dev/null, and the working directory is changed to root. 90 * Execution within the caller of this function will terminate before this 91 * function returns, while execution within the daemonized child process will 92 * continue. 93 * 94 * @return 95 * Zero if the daemonization process succeeded and we are now in the 96 * daemonized child process, or non-zero if daemonization failed and we are 97 * still the original caller. This function does not return for the original 98 * caller if daemonization succeeds. 99 */ 100static int daemonize() { 101 102 pid_t pid; 103 104 /* Fork once to ensure we aren't the process group leader */ 105 pid = fork(); 106 if (pid < 0) { 107 guacd_log(GUAC_LOG_ERROR, "Could not fork() parent: %s", strerror(errno)); 108 return 1; 109 } 110 111 /* Exit if we are the parent */ 112 if (pid > 0) { 113 guacd_log(GUAC_LOG_DEBUG, "Exiting and passing control to PID %i", pid); 114 _exit(0); 115 } 116 117 /* Start a new session (if not already group leader) */ 118 setsid(); 119 120 /* Fork again so the session group leader exits */ 121 pid = fork(); 122 if (pid < 0) { 123 guacd_log(GUAC_LOG_ERROR, "Could not fork() group leader: %s", strerror(errno)); 124 return 1; 125 } 126 127 /* Exit if we are the parent */ 128 if (pid > 0) { 129 guacd_log(GUAC_LOG_DEBUG, "Exiting and passing control to PID %i", pid); 130 _exit(0); 131 } 132 133 /* Change to root directory */ 134 if (chdir(GUACD_ROOT) < 0) { 135 guacd_log(GUAC_LOG_ERROR, 136 "Unable to change working directory to " 137 GUACD_ROOT); 138 return 1; 139 } 140 141 /* Reopen the 3 stdxxx to /dev/null */ 142 143 if (redirect_fd(STDIN_FILENO, O_RDONLY) 144 || redirect_fd(STDOUT_FILENO, O_WRONLY) 145 || redirect_fd(STDERR_FILENO, O_WRONLY)) { 146 147 guacd_log(GUAC_LOG_ERROR, 148 "Unable to redirect standard file descriptors to " 149 GUACD_DEV_NULL); 150 return 1; 151 } 152 153 /* Success */ 154 return 0; 155 156} 157 158#ifdef ENABLE_SSL 159#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS 160/** 161 * Array of mutexes, used by OpenSSL. 162 */ 163static pthread_mutex_t* guacd_openssl_locks = NULL; 164 165/** 166 * Called by OpenSSL when locking or unlocking the Nth mutex. 167 * 168 * @param mode 169 * A bitmask denoting the action to be taken on the Nth lock, such as 170 * CRYPTO_LOCK or CRYPTO_UNLOCK. 171 * 172 * @param n 173 * The index of the lock to lock or unlock. 174 * 175 * @param file 176 * The filename of the function setting the lock, for debugging purposes. 177 * 178 * @param line 179 * The line number of the function setting the lock, for debugging 180 * purposes. 181 */ 182static void guacd_openssl_locking_callback(int mode, int n, 183 const char* file, int line){ 184 185 /* Lock given mutex upon request */ 186 if (mode & CRYPTO_LOCK) 187 pthread_mutex_lock(&(guacd_openssl_locks[n])); 188 189 /* Unlock given mutex upon request */ 190 else if (mode & CRYPTO_UNLOCK) 191 pthread_mutex_unlock(&(guacd_openssl_locks[n])); 192 193} 194 195/** 196 * Called by OpenSSL when determining the current thread ID. 197 * 198 * @return 199 * An ID which uniquely identifies the current thread. 200 */ 201static unsigned long guacd_openssl_id_callback() { 202 return (unsigned long) pthread_self(); 203} 204 205/** 206 * Creates the given number of mutexes, such that OpenSSL will have at least 207 * this number of mutexes at its disposal. 208 * 209 * @param count 210 * The number of mutexes (locks) to create. 211 */ 212static void guacd_openssl_init_locks(int count) { 213 214 int i; 215 216 /* Allocate required number of locks */ 217 guacd_openssl_locks = guac_mem_alloc(sizeof(pthread_mutex_t), count); 218 219 /* Initialize each lock */ 220 for (i=0; i < count; i++) 221 pthread_mutex_init(&(guacd_openssl_locks[i]), NULL); 222 223} 224 225/** 226 * Frees the given number of mutexes. 227 * 228 * @param count 229 * The number of mutexes (locks) to free. 230 */ 231static void guacd_openssl_free_locks(int count) { 232 233 int i; 234 235 /* SSL lock array was not initialized */ 236 if (guacd_openssl_locks == NULL) 237 return; 238 239 /* Free all locks */ 240 for (i=0; i < count; i++) 241 pthread_mutex_destroy(&(guacd_openssl_locks[i])); 242 243 /* Free lock array */ 244 guac_mem_free(guacd_openssl_locks); 245 246} 247#endif 248#endif 249 250/** 251 * A flag that, if non-zero, indicates that the daemon should immediately stop 252 * accepting new connections. 253 */ 254int stop_everything = 0; 255 256/** 257 * A signal handler that will set a flag telling the daemon to immediately stop 258 * accepting new connections. Note that the signal itself will cause any pending 259 * accept() calls to be interrupted, causing the daemon to unlock and begin 260 * cleaning up. 261 * 262 * @param signal 263 * The signal that was received. Unused in this function since only 264 * signals that should result in stopping the daemon should invoke this. 265 */ 266static void signal_stop_handler(int signal) { 267 268 /* Instruct the daemon to stop accepting new connections */ 269 stop_everything = 1; 270 271} 272 273/** 274 * A callback for guacd_proc_map_foreach which will stop every process in the 275 * map. 276 * 277 * @param proc 278 * The guacd process to stop. 279 * 280 * @param data 281 * Unused. 282 */ 283static void stop_process_callback(guacd_proc* proc, void* data) { 284 285 guacd_log(GUAC_LOG_DEBUG, 286 "Killing connection %s (%i)\n", 287 proc->client->connection_id, (int) proc->pid); 288 289 guacd_proc_stop(proc); 290 291} 292 293int main(int argc, char* argv[]) { 294 295 /* Server */ 296 int socket_fd; 297 struct addrinfo* addresses; 298 struct addrinfo* current_address; 299 char bound_address[1024]; 300 char bound_port[64]; 301 int opt_on = 1; 302 303 struct addrinfo hints = { 304 .ai_family = AF_UNSPEC, 305 .ai_socktype = SOCK_STREAM, 306 .ai_protocol = IPPROTO_TCP 307 }; 308 309 /* Client */ 310 struct sockaddr_in client_addr; 311 socklen_t client_addr_len; 312 int connected_socket_fd; 313 314#ifdef ENABLE_SSL 315 SSL_CTX* ssl_context = NULL; 316#endif 317 318 guacd_proc_map* map = guacd_proc_map_alloc(); 319 320 /* General */ 321 int retval; 322 323 /* Load configuration */ 324 guacd_config* config = guacd_conf_load(); 325 if (config == NULL || guacd_conf_parse_args(config, argc, argv)) 326 exit(EXIT_FAILURE); 327 328 /* If requested, simply print version and exit, without initializing the 329 * logging system, etc. */ 330 if (config->print_version) { 331 printf("Guacamole proxy daemon (guacd) version " VERSION "\n"); 332 exit(EXIT_SUCCESS); 333 } 334 335 /* Init logging as early as possible */ 336 guacd_log_level = config->max_log_level; 337 openlog(GUACD_LOG_NAME, LOG_PID, LOG_DAEMON); 338 339 /* Log start */ 340 guacd_log(GUAC_LOG_INFO, "Guacamole proxy daemon (guacd) version " VERSION " started"); 341 342 /* Get addresses for binding */ 343 if ((retval = getaddrinfo(config->bind_host, config->bind_port, 344 &hints, &addresses))) { 345 346 guacd_log(GUAC_LOG_ERROR, "Error parsing given address or port: %s", 347 gai_strerror(retval)); 348 exit(EXIT_FAILURE); 349 350 } 351 352 /* Attempt binding of each address until success */ 353 current_address = addresses; 354 while (current_address != NULL) { 355 356 int retval; 357 358 /* Resolve hostname */ 359 if ((retval = getnameinfo(current_address->ai_addr, 360 current_address->ai_addrlen, 361 bound_address, sizeof(bound_address), 362 bound_port, sizeof(bound_port), 363 NI_NUMERICHOST | NI_NUMERICSERV))) 364 guacd_log(GUAC_LOG_ERROR, "Unable to resolve host: %s", 365 gai_strerror(retval)); 366 367 /* Get socket */ 368 socket_fd = socket(current_address->ai_family, SOCK_STREAM, 0); 369 if (socket_fd < 0) { 370 guacd_log(GUAC_LOG_ERROR, "Error opening socket: %s", strerror(errno)); 371 372 /* Unable to get a socket for the resolved address family, try next */ 373 current_address = current_address->ai_next; 374 continue; 375 } 376 377 /* Allow socket reuse */ 378 if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, 379 (void*) &opt_on, sizeof(opt_on))) { 380 guacd_log(GUAC_LOG_WARNING, "Unable to set socket options for reuse: %s", 381 strerror(errno)); 382 } 383 384 /* Attempt to bind socket to address */ 385 if (bind(socket_fd, 386 current_address->ai_addr, 387 current_address->ai_addrlen) == 0) { 388 389 guacd_log(GUAC_LOG_DEBUG, "Successfully bound " 390 "%s socket to host %s, port %s", 391 (current_address->ai_family == AF_INET) ? "AF_INET" : "AF_INET6", 392 bound_address, bound_port); 393 394 /* Done if successful bind */ 395 break; 396 } 397 398 /* Otherwise log information regarding bind failure */ 399 close(socket_fd); 400 socket_fd = -1; 401 guacd_log(GUAC_LOG_DEBUG, "Unable to bind %s socket to " 402 "host %s, port %s: %s", 403 (current_address->ai_family == AF_INET) ? "AF_INET" : "AF_INET6", 404 bound_address, bound_port, strerror(errno)); 405 406 /* Try next address */ 407 current_address = current_address->ai_next; 408 } 409 410 /* If unable to bind to anything, fail */ 411 if (current_address == NULL) { 412 guacd_log(GUAC_LOG_ERROR, "Unable to bind socket to any addresses."); 413 exit(EXIT_FAILURE); 414 } 415 416#ifdef ENABLE_SSL 417 /* Init SSL if enabled */ 418 if (config->key_file != NULL || config->cert_file != NULL) { 419 420 guacd_log(GUAC_LOG_INFO, "Communication will require SSL/TLS."); 421 422#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS 423 /* Init threadsafety in OpenSSL */ 424 guacd_openssl_init_locks(CRYPTO_num_locks()); 425 CRYPTO_set_id_callback(guacd_openssl_id_callback); 426 CRYPTO_set_locking_callback(guacd_openssl_locking_callback); 427#endif 428 429 /* Init SSL */ 430 SSL_library_init(); 431 SSL_load_error_strings(); 432 ssl_context = SSL_CTX_new(SSLv23_server_method()); 433 434 /* Load key */ 435 if (config->key_file != NULL) { 436 guacd_log(GUAC_LOG_INFO, "Using PEM keyfile %s", config->key_file); 437 if (!SSL_CTX_use_PrivateKey_file(ssl_context, config->key_file, SSL_FILETYPE_PEM)) { 438 guacd_log(GUAC_LOG_ERROR, "Unable to load keyfile."); 439 exit(EXIT_FAILURE); 440 } 441 } 442 else 443 guacd_log(GUAC_LOG_WARNING, "No PEM keyfile given - SSL/TLS may not work."); 444 445 /* Load cert file if specified */ 446 if (config->cert_file != NULL) { 447 guacd_log(GUAC_LOG_INFO, "Using certificate file %s", config->cert_file); 448 if (!SSL_CTX_use_certificate_chain_file(ssl_context, config->cert_file)) { 449 guacd_log(GUAC_LOG_ERROR, "Unable to load certificate."); 450 exit(EXIT_FAILURE); 451 } 452 } 453 else 454 guacd_log(GUAC_LOG_WARNING, "No certificate file given - SSL/TLS may not work."); 455 456 } 457#endif 458 459 /* Daemonize if requested */ 460 if (!config->foreground) { 461 462 /* Attempt to daemonize process */ 463 if (daemonize()) { 464 guacd_log(GUAC_LOG_ERROR, "Could not become a daemon."); 465 exit(EXIT_FAILURE); 466 } 467 468 } 469 470 /* Write PID file if requested */ 471 if (config->pidfile != NULL) { 472 473 /* Attempt to open pidfile and write PID */ 474 FILE* pidf = fopen(config->pidfile, "w"); 475 if (pidf) { 476 fprintf(pidf, "%d\n", getpid()); 477 fclose(pidf); 478 } 479 480 /* Fail if could not write PID file*/ 481 else { 482 guacd_log(GUAC_LOG_ERROR, "Could not write PID file: %s", strerror(errno)); 483 exit(EXIT_FAILURE); 484 } 485 486 } 487 488 /* Ignore SIGPIPE */ 489 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 490 guacd_log(GUAC_LOG_INFO, "Could not set handler for SIGPIPE to ignore. " 491 "SIGPIPE may cause termination of the daemon."); 492 } 493 494 /* Ignore SIGCHLD (force automatic removal of children) */ 495 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 496 guacd_log(GUAC_LOG_INFO, "Could not set handler for SIGCHLD to ignore. " 497 "Child processes may pile up in the process table."); 498 } 499 500 /* Clean up and exit if SIGINT or SIGTERM signals are caught */ 501 struct sigaction signal_stop_action = { .sa_handler = signal_stop_handler }; 502 sigaction(SIGINT, &signal_stop_action, NULL); 503 sigaction(SIGTERM, &signal_stop_action, NULL); 504 505 /* Log listening status */ 506 guacd_log(GUAC_LOG_INFO, "Listening on host %s, port %s", bound_address, bound_port); 507 508 /* Free addresses */ 509 freeaddrinfo(addresses); 510 511 /* Listen for connections */ 512 if (listen(socket_fd, 5) < 0) { 513 guacd_log(GUAC_LOG_ERROR, "Could not listen on socket: %s", strerror(errno)); 514 return 3; 515 } 516 517 /* Daemon loop */ 518 while (!stop_everything) { 519 520 pthread_t child_thread; 521 522 /* Accept connection */ 523 client_addr_len = sizeof(client_addr); 524 connected_socket_fd = accept(socket_fd, 525 (struct sockaddr*) &client_addr, &client_addr_len); 526 527 if (connected_socket_fd < 0) { 528 if (errno == EINTR) 529 guacd_log(GUAC_LOG_DEBUG, "Accepting of further client connection(s) interrupted by signal."); 530 else 531 guacd_log(GUAC_LOG_ERROR, "Could not accept client connection: %s", strerror(errno)); 532 continue; 533 } 534 535 /* Create parameters for connection thread */ 536 guacd_connection_thread_params* params = guac_mem_alloc(sizeof(guacd_connection_thread_params)); 537 if (params == NULL) { 538 guacd_log(GUAC_LOG_ERROR, "Could not create connection thread: %s", strerror(errno)); 539 continue; 540 } 541 542 params->map = map; 543 params->connected_socket_fd = connected_socket_fd; 544 545#ifdef ENABLE_SSL 546 params->ssl_context = ssl_context; 547#endif 548 549 /* Spawn thread to handle connection */ 550 pthread_create(&child_thread, NULL, guacd_connection_thread, params); 551 pthread_detach(child_thread); 552 553 } 554 555 /* Stop all connections */ 556 if (map != NULL) { 557 558 guacd_proc_map_foreach(map, stop_process_callback, NULL); 559 560 /* 561 * FIXME: Clean up the proc map. This is not as straightforward as it 562 * might seem, since the detached connection threads will attempt to 563 * remove the connection proccesses from the map when they complete, 564 * which will also happen upon shutdown. So there's a good chance that 565 * this map cleanup will happen at the same time as the thread cleanup. 566 * The map _does_ have locking mechanisms in place for ensuring thread 567 * safety, but cleaning up the map also requires destroying those locks, 568 * making them unusable for this case. One potential fix could be to 569 * join every one of the connection threads instead of detaching them, 570 * but that does complicate the cleanup of thread resources. 571 */ 572 573 } 574 575 /* Close socket */ 576 if (close(socket_fd) < 0) { 577 guacd_log(GUAC_LOG_ERROR, "Could not close socket: %s", strerror(errno)); 578 return 3; 579 } 580 581#ifdef ENABLE_SSL 582 if (ssl_context != NULL) { 583#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS 584 guacd_openssl_free_locks(CRYPTO_num_locks()); 585#endif 586 SSL_CTX_free(ssl_context); 587 } 588#endif 589 590 return 0; 591 592} 593