settings.c (21229B)
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 "argv.h" 23#include "client.h" 24#include "common/defaults.h" 25#include "settings.h" 26 27#include <guacamole/mem.h> 28#include <guacamole/user.h> 29#include <guacamole/wol-constants.h> 30 31#include <stdbool.h> 32#include <stdlib.h> 33#include <string.h> 34#include <time.h> 35 36/* Client plugin arguments */ 37const char* GUAC_VNC_CLIENT_ARGS[] = { 38 "hostname", 39 "port", 40 "read-only", 41 "encodings", 42 GUAC_VNC_ARGV_USERNAME, 43 GUAC_VNC_ARGV_PASSWORD, 44 "swap-red-blue", 45 "color-depth", 46 "cursor", 47 "autoretry", 48 "clipboard-encoding", 49 50#ifdef ENABLE_VNC_REPEATER 51 "dest-host", 52 "dest-port", 53#endif 54 55#ifdef ENABLE_PULSE 56 "enable-audio", 57 "audio-servername", 58#endif 59 60#ifdef ENABLE_VNC_LISTEN 61 "reverse-connect", 62 "listen-timeout", 63#endif 64 65#ifdef ENABLE_COMMON_SSH 66 "enable-sftp", 67 "sftp-hostname", 68 "sftp-host-key", 69 "sftp-port", 70 "sftp-username", 71 "sftp-password", 72 "sftp-private-key", 73 "sftp-passphrase", 74 "sftp-directory", 75 "sftp-root-directory", 76 "sftp-server-alive-interval", 77 "sftp-disable-download", 78 "sftp-disable-upload", 79#endif 80 81 "recording-path", 82 "recording-name", 83 "recording-exclude-output", 84 "recording-exclude-mouse", 85 "recording-include-keys", 86 "create-recording-path", 87 "disable-copy", 88 "disable-paste", 89 90 "wol-send-packet", 91 "wol-mac-addr", 92 "wol-broadcast-addr", 93 "wol-udp-port", 94 "wol-wait-time", 95 96 "force-lossless", 97 NULL 98}; 99 100enum VNC_ARGS_IDX { 101 102 /** 103 * The hostname of the VNC server (or repeater) to connect to. 104 */ 105 IDX_HOSTNAME, 106 107 /** 108 * The port of the VNC server (or repeater) to connect to. 109 */ 110 IDX_PORT, 111 112 /** 113 * "true" if this connection should be read-only (user input should be 114 * dropped), "false" or blank otherwise. 115 */ 116 IDX_READ_ONLY, 117 118 /** 119 * Space-separated list of encodings to use within the VNC session. If not 120 * specified, this will be: 121 * 122 * "zrle ultra copyrect hextile zlib corre rre raw". 123 */ 124 IDX_ENCODINGS, 125 126 /** 127 * The username to send to the VNC server if authentication is requested. 128 */ 129 IDX_USERNAME, 130 131 /** 132 * The password to send to the VNC server if authentication is requested. 133 */ 134 IDX_PASSWORD, 135 136 /** 137 * "true" if the red and blue components of each color should be swapped, 138 * "false" or blank otherwise. This is mainly used for VNC servers that do 139 * not properly handle colors. 140 */ 141 IDX_SWAP_RED_BLUE, 142 143 /** 144 * The color depth to request, in bits. 145 */ 146 IDX_COLOR_DEPTH, 147 148 /** 149 * "remote" if the cursor should be rendered on the server instead of the 150 * client. All other values will default to local rendering. 151 */ 152 IDX_CURSOR, 153 154 /** 155 * The number of connection attempts to make before giving up. By default, 156 * this will be 0. 157 */ 158 IDX_AUTORETRY, 159 160 /** 161 * The encoding to use for clipboard data sent to the VNC server if we are 162 * going to be deviating from the standard (which mandates ISO 8829-1). 163 * Valid values are "ISO8829-1" (the only legal value with respect to the 164 * VNC standard), "UTF-8", "UTF-16", and "CP2252". 165 */ 166 IDX_CLIPBOARD_ENCODING, 167 168#ifdef ENABLE_VNC_REPEATER 169 /** 170 * The VNC host to connect to, if using a repeater. 171 */ 172 IDX_DEST_HOST, 173 174 /** 175 * The VNC port to connect to, if using a repeater. 176 */ 177 IDX_DEST_PORT, 178#endif 179 180#ifdef ENABLE_PULSE 181 /** 182 * "true" if audio should be enabled, "false" or blank otherwise. 183 */ 184 IDX_ENABLE_AUDIO, 185 186 /** 187 * The name of the PulseAudio server to connect to. If left blank, the 188 * default sink of the local machine will be used as the source for audio. 189 */ 190 IDX_AUDIO_SERVERNAME, 191#endif 192 193#ifdef ENABLE_VNC_LISTEN 194 /** 195 * "true" if not actually connecting to a VNC server, but rather listening 196 * for a connection from the VNC server (reverse connection), "false" or 197 * blank otherwise. 198 */ 199 IDX_REVERSE_CONNECT, 200 201 /** 202 * The maximum amount of time to wait when listening for connections, in 203 * milliseconds. If unspecified, this will default to 5000. 204 */ 205 IDX_LISTEN_TIMEOUT, 206#endif 207 208#ifdef ENABLE_COMMON_SSH 209 /** 210 * "true" if SFTP should be enabled for the VNC connection, "false" or 211 * blank otherwise. 212 */ 213 IDX_ENABLE_SFTP, 214 215 /** 216 * The hostname of the SSH server to connect to for SFTP. If blank, the 217 * hostname of the VNC server will be used. 218 */ 219 IDX_SFTP_HOSTNAME, 220 221 /** 222 * The public SSH host key to identify the SFTP server. 223 */ 224 IDX_SFTP_HOST_KEY, 225 226 /** 227 * The port of the SSH server to connect to for SFTP. If blank, the default 228 * SSH port of "22" will be used. 229 */ 230 IDX_SFTP_PORT, 231 232 /** 233 * The username to provide when authenticating with the SSH server for 234 * SFTP. 235 */ 236 IDX_SFTP_USERNAME, 237 238 /** 239 * The password to provide when authenticating with the SSH server for 240 * SFTP (if not using a private key). 241 */ 242 IDX_SFTP_PASSWORD, 243 244 /** 245 * The base64-encoded private key to use when authenticating with the SSH 246 * server for SFTP (if not using a password). 247 */ 248 IDX_SFTP_PRIVATE_KEY, 249 250 /** 251 * The passphrase to use to decrypt the provided base64-encoded private 252 * key. 253 */ 254 IDX_SFTP_PASSPHRASE, 255 256 /** 257 * The default location for file uploads within the SSH server. This will 258 * apply only to uploads which do not use the filesystem guac_object (where 259 * the destination directory is otherwise ambiguous). 260 */ 261 IDX_SFTP_DIRECTORY, 262 263 /** 264 * The path of the directory within the SSH server to expose as a 265 * filesystem guac_object. If omitted, "/" will be used by default. 266 */ 267 IDX_SFTP_ROOT_DIRECTORY, 268 269 /** 270 * The interval at which SSH keepalive messages are sent to the server for 271 * SFTP connections. The default is 0 (disabling keepalives), and a value 272 * of 1 is automatically incremented to 2 by libssh2 to avoid busy loop corner 273 * cases. 274 */ 275 IDX_SFTP_SERVER_ALIVE_INTERVAL, 276 277 /** 278 * If set to "true", file downloads over SFTP will be blocked. If set to 279 * "false" or not set, file downloads will be allowed. 280 */ 281 IDX_SFTP_DISABLE_DOWNLOAD, 282 283 /** 284 * If set to "true", file uploads over SFTP will be blocked. If set to 285 * "false" or not set, file uploads will be allowed. 286 */ 287 IDX_SFTP_DISABLE_UPLOAD, 288#endif 289 290 /** 291 * The full absolute path to the directory in which screen recordings 292 * should be written. 293 */ 294 IDX_RECORDING_PATH, 295 296 /** 297 * The name that should be given to screen recordings which are written in 298 * the given path. 299 */ 300 IDX_RECORDING_NAME, 301 302 /** 303 * Whether output which is broadcast to each connected client (graphics, 304 * streams, etc.) should NOT be included in the session recording. Output 305 * is included by default, as it is necessary for any recording which must 306 * later be viewable as video. 307 */ 308 IDX_RECORDING_EXCLUDE_OUTPUT, 309 310 /** 311 * Whether changes to mouse state, such as position and buttons pressed or 312 * released, should NOT be included in the session recording. Mouse state 313 * is included by default, as it is necessary for the mouse cursor to be 314 * rendered in any resulting video. 315 */ 316 IDX_RECORDING_EXCLUDE_MOUSE, 317 318 /** 319 * Whether keys pressed and released should be included in the session 320 * recording. Key events are NOT included by default within the recording, 321 * as doing so has privacy and security implications. Including key events 322 * may be necessary in certain auditing contexts, but should only be done 323 * with caution. Key events can easily contain sensitive information, such 324 * as passwords, credit card numbers, etc. 325 */ 326 IDX_RECORDING_INCLUDE_KEYS, 327 328 /** 329 * Whether the specified screen recording path should automatically be 330 * created if it does not yet exist. 331 */ 332 IDX_CREATE_RECORDING_PATH, 333 334 /** 335 * Whether outbound clipboard access should be blocked. If set to "true", 336 * it will not be possible to copy data from the remote desktop to the 337 * client using the clipboard. By default, clipboard access is not blocked. 338 */ 339 IDX_DISABLE_COPY, 340 341 /** 342 * Whether inbound clipboard access should be blocked. If set to "true", it 343 * will not be possible to paste data from the client to the remote desktop 344 * using the clipboard. By default, clipboard access is not blocked. 345 */ 346 IDX_DISABLE_PASTE, 347 348 /** 349 * Whether to send the magic Wake-on-LAN (WoL) packet to wake the remote 350 * host prior to attempting to connect. If set to "true" the packet will 351 * be sent. By default the packet will not be sent. 352 */ 353 IDX_WOL_SEND_PACKET, 354 355 /** 356 * The MAC address to place in the magic WoL packet to wake the remote host. 357 * If WoL is requested but this is not provided a warning will be logged 358 * and the WoL packet will not be sent. 359 */ 360 IDX_WOL_MAC_ADDR, 361 362 /** 363 * The broadcast packet to which to send the magic WoL packet. 364 */ 365 IDX_WOL_BROADCAST_ADDR, 366 367 /** 368 * The UDP port to use when sending the WoL packet. 369 */ 370 IDX_WOL_UDP_PORT, 371 372 /** 373 * The number of seconds to wait after sending the magic WoL packet before 374 * attempting to connect to the remote host. The default is not to wait 375 * at all (0 seconds). 376 */ 377 IDX_WOL_WAIT_TIME, 378 379 /** 380 * "true" if all graphical updates for this connection should use lossless 381 * compresion only, "false" or blank otherwise. 382 */ 383 IDX_FORCE_LOSSLESS, 384 385 VNC_ARGS_COUNT 386}; 387 388guac_vnc_settings* guac_vnc_parse_args(guac_user* user, 389 int argc, const char** argv) { 390 391 /* Validate arg count */ 392 if (argc != VNC_ARGS_COUNT) { 393 guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection " 394 "parameters provided: expected %i, got %i.", 395 VNC_ARGS_COUNT, argc); 396 return NULL; 397 } 398 399 guac_vnc_settings* settings = guac_mem_zalloc(sizeof(guac_vnc_settings)); 400 401 settings->hostname = 402 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 403 IDX_HOSTNAME, ""); 404 405 settings->port = 406 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 407 IDX_PORT, 0); 408 409 settings->username = 410 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 411 IDX_USERNAME, NULL); 412 413 settings->password = 414 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 415 IDX_PASSWORD, NULL); 416 417 /* Remote cursor */ 418 if (strcmp(argv[IDX_CURSOR], "remote") == 0) { 419 guac_user_log(user, GUAC_LOG_INFO, "Cursor rendering: remote"); 420 settings->remote_cursor = true; 421 } 422 423 /* Local cursor */ 424 else { 425 guac_user_log(user, GUAC_LOG_INFO, "Cursor rendering: local"); 426 settings->remote_cursor = false; 427 } 428 429 /* Swap red/blue (for buggy VNC servers) */ 430 settings->swap_red_blue = 431 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 432 IDX_SWAP_RED_BLUE, false); 433 434 /* Read-only mode */ 435 settings->read_only = 436 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 437 IDX_READ_ONLY, false); 438 439 /* Parse color depth */ 440 settings->color_depth = 441 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 442 IDX_COLOR_DEPTH, 0); 443 444 /* Lossless compression */ 445 settings->lossless = 446 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 447 IDX_FORCE_LOSSLESS, false); 448 449#ifdef ENABLE_VNC_REPEATER 450 /* Set repeater parameters if specified */ 451 settings->dest_host = 452 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 453 IDX_DEST_HOST, NULL); 454 455 /* VNC repeater port */ 456 settings->dest_port = 457 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 458 IDX_DEST_PORT, 0); 459#endif 460 461 /* Set encodings if specified */ 462 settings->encodings = 463 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 464 IDX_ENCODINGS, 465 "zrle ultra copyrect hextile zlib corre rre raw"); 466 467 /* Parse autoretry */ 468 settings->retries = 469 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 470 IDX_AUTORETRY, 0); 471 472#ifdef ENABLE_VNC_LISTEN 473 /* Set reverse-connection flag */ 474 settings->reverse_connect = 475 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 476 IDX_REVERSE_CONNECT, false); 477 478 /* Parse listen timeout */ 479 settings->listen_timeout = 480 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 481 IDX_LISTEN_TIMEOUT, 5000); 482#endif 483 484#ifdef ENABLE_PULSE 485 /* Audio enable/disable */ 486 settings->audio_enabled = 487 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 488 IDX_ENABLE_AUDIO, false); 489 490 /* Load servername if specified and applicable */ 491 if (settings->audio_enabled) 492 settings->pa_servername = 493 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 494 IDX_AUDIO_SERVERNAME, NULL); 495#endif 496 497 /* Set clipboard encoding if specified */ 498 settings->clipboard_encoding = 499 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 500 IDX_CLIPBOARD_ENCODING, NULL); 501 502#ifdef ENABLE_COMMON_SSH 503 /* SFTP enable/disable */ 504 settings->enable_sftp = 505 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 506 IDX_ENABLE_SFTP, false); 507 508 /* Hostname for SFTP connection */ 509 settings->sftp_hostname = 510 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 511 IDX_SFTP_HOSTNAME, settings->hostname); 512 513 /* The public SSH host key. */ 514 settings->sftp_host_key = 515 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 516 IDX_SFTP_HOST_KEY, NULL); 517 518 /* Port for SFTP connection */ 519 settings->sftp_port = 520 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 521 IDX_SFTP_PORT, "22"); 522 523 /* Username for SSH/SFTP authentication */ 524 settings->sftp_username = 525 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 526 IDX_SFTP_USERNAME, ""); 527 528 /* Password for SFTP (if not using private key) */ 529 settings->sftp_password = 530 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 531 IDX_SFTP_PASSWORD, ""); 532 533 /* Private key for SFTP (if not using password) */ 534 settings->sftp_private_key = 535 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 536 IDX_SFTP_PRIVATE_KEY, NULL); 537 538 /* Passphrase for decrypting the SFTP private key (if applicable */ 539 settings->sftp_passphrase = 540 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 541 IDX_SFTP_PASSPHRASE, ""); 542 543 /* Default upload directory */ 544 settings->sftp_directory = 545 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 546 IDX_SFTP_DIRECTORY, NULL); 547 548 /* SFTP root directory */ 549 settings->sftp_root_directory = 550 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 551 IDX_SFTP_ROOT_DIRECTORY, "/"); 552 553 /* Default keepalive value */ 554 settings->sftp_server_alive_interval = 555 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 556 IDX_SFTP_SERVER_ALIVE_INTERVAL, 0); 557 558 settings->sftp_disable_download = 559 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 560 IDX_SFTP_DISABLE_DOWNLOAD, false); 561 562 settings->sftp_disable_upload = 563 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 564 IDX_SFTP_DISABLE_UPLOAD, false); 565#endif 566 567 /* Read recording path */ 568 settings->recording_path = 569 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 570 IDX_RECORDING_PATH, NULL); 571 572 /* Read recording name */ 573 settings->recording_name = 574 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 575 IDX_RECORDING_NAME, GUAC_VNC_DEFAULT_RECORDING_NAME); 576 577 /* Parse output exclusion flag */ 578 settings->recording_exclude_output = 579 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 580 IDX_RECORDING_EXCLUDE_OUTPUT, false); 581 582 /* Parse mouse exclusion flag */ 583 settings->recording_exclude_mouse = 584 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 585 IDX_RECORDING_EXCLUDE_MOUSE, false); 586 587 /* Parse key event inclusion flag */ 588 settings->recording_include_keys = 589 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 590 IDX_RECORDING_INCLUDE_KEYS, false); 591 592 /* Parse path creation flag */ 593 settings->create_recording_path = 594 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 595 IDX_CREATE_RECORDING_PATH, false); 596 597 /* Parse clipboard copy disable flag */ 598 settings->disable_copy = 599 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 600 IDX_DISABLE_COPY, false); 601 602 /* Parse clipboard paste disable flag */ 603 settings->disable_paste = 604 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 605 IDX_DISABLE_PASTE, false); 606 607 /* Parse Wake-on-LAN (WoL) settings */ 608 settings->wol_send_packet = 609 guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, 610 IDX_WOL_SEND_PACKET, false); 611 612 if (settings->wol_send_packet) { 613 614 /* If WoL has been enabled but no MAC provided, log warning and disable. */ 615 if(strcmp(argv[IDX_WOL_MAC_ADDR], "") == 0) { 616 guac_user_log(user, GUAC_LOG_WARNING, "Wake on LAN was requested, ", 617 "but no MAC address was specified. WoL will not be sent."); 618 settings->wol_send_packet = false; 619 } 620 621 /* Parse the WoL MAC address. */ 622 settings->wol_mac_addr = 623 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 624 IDX_WOL_MAC_ADDR, NULL); 625 626 /* Parse the WoL broadcast address. */ 627 settings->wol_broadcast_addr = 628 guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, 629 IDX_WOL_BROADCAST_ADDR, GUAC_WOL_LOCAL_IPV4_BROADCAST); 630 631 /* Parse the WoL broadcast port. */ 632 settings->wol_udp_port = (unsigned short) 633 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 634 IDX_WOL_UDP_PORT, GUAC_WOL_PORT); 635 636 /* Parse the WoL wait time. */ 637 settings->wol_wait_time = 638 guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, 639 IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); 640 641 } 642 643 return settings; 644 645} 646 647void guac_vnc_settings_free(guac_vnc_settings* settings) { 648 649 /* Free settings strings */ 650 guac_mem_free(settings->clipboard_encoding); 651 guac_mem_free(settings->encodings); 652 guac_mem_free(settings->hostname); 653 guac_mem_free(settings->password); 654 guac_mem_free(settings->recording_name); 655 guac_mem_free(settings->recording_path); 656 guac_mem_free(settings->username); 657 658#ifdef ENABLE_VNC_REPEATER 659 /* Free VNC repeater settings */ 660 guac_mem_free(settings->dest_host); 661#endif 662 663#ifdef ENABLE_COMMON_SSH 664 /* Free SFTP settings */ 665 guac_mem_free(settings->sftp_directory); 666 guac_mem_free(settings->sftp_root_directory); 667 guac_mem_free(settings->sftp_host_key); 668 guac_mem_free(settings->sftp_hostname); 669 guac_mem_free(settings->sftp_passphrase); 670 guac_mem_free(settings->sftp_password); 671 guac_mem_free(settings->sftp_port); 672 guac_mem_free(settings->sftp_private_key); 673 guac_mem_free(settings->sftp_username); 674#endif 675 676#ifdef ENABLE_PULSE 677 /* Free PulseAudio settings */ 678 guac_mem_free(settings->pa_servername); 679#endif 680 681 /* Free Wake-on-LAN strings */ 682 guac_mem_free(settings->wol_mac_addr); 683 guac_mem_free(settings->wol_broadcast_addr); 684 685 /* Free settings structure */ 686 guac_mem_free(settings); 687 688} 689