cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

settings.c (55148B)


      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 "argv.h"
     21#include "common/defaults.h"
     22#include "common/string.h"
     23#include "config.h"
     24#include "resolution.h"
     25#include "settings.h"
     26
     27#include <freerdp/constants.h>
     28#include <freerdp/settings.h>
     29#include <freerdp/freerdp.h>
     30#include <guacamole/client.h>
     31#include <guacamole/mem.h>
     32#include <guacamole/fips.h>
     33#include <guacamole/string.h>
     34#include <guacamole/user.h>
     35#include <guacamole/wol-constants.h>
     36#include <winpr/crt.h>
     37#include <winpr/wtypes.h>
     38
     39#include <errno.h>
     40#include <stddef.h>
     41#include <stdlib.h>
     42#include <string.h>
     43
     44/**
     45 * A warning to log when NLA mode is selected while FIPS mode is active on the
     46 * guacd server.
     47 */
     48const char fips_nla_mode_warning[] = (
     49        "NLA security mode was selected, but is known to be currently incompatible "
     50        "with FIPS mode (see FreeRDP/FreeRDP#3412). Security negotiation with the "
     51        "RDP server may fail unless TLS security mode is selected instead."
     52);
     53
     54/* Client plugin arguments */
     55const char* GUAC_RDP_CLIENT_ARGS[] = {
     56    "hostname",
     57    "port",
     58    GUAC_RDP_ARGV_DOMAIN,
     59    GUAC_RDP_ARGV_USERNAME,
     60    GUAC_RDP_ARGV_PASSWORD,
     61    "width",
     62    "height",
     63    "dpi",
     64    "initial-program",
     65    "color-depth",
     66    "disable-audio",
     67    "enable-printing",
     68    "printer-name",
     69    "enable-drive",
     70    "drive-name",
     71    "drive-path",
     72    "create-drive-path",
     73    "disable-download",
     74    "disable-upload",
     75    "console",
     76    "console-audio",
     77    "server-layout",
     78    "security",
     79    "ignore-cert",
     80    "disable-auth",
     81    "remote-app",
     82    "remote-app-dir",
     83    "remote-app-args",
     84    "static-channels",
     85    "client-name",
     86    "enable-wallpaper",
     87    "enable-theming",
     88    "enable-font-smoothing",
     89    "enable-full-window-drag",
     90    "enable-desktop-composition",
     91    "enable-menu-animations",
     92    "disable-bitmap-caching",
     93    "disable-offscreen-caching",
     94    "disable-glyph-caching",
     95    "preconnection-id",
     96    "preconnection-blob",
     97    "timezone",
     98
     99#ifdef ENABLE_COMMON_SSH
    100    "enable-sftp",
    101    "sftp-hostname",
    102    "sftp-host-key",
    103    "sftp-port",
    104    "sftp-username",
    105    "sftp-password",
    106    "sftp-private-key",
    107    "sftp-passphrase",
    108    "sftp-directory",
    109    "sftp-root-directory",
    110    "sftp-server-alive-interval",
    111    "sftp-disable-download",
    112    "sftp-disable-upload",
    113#endif
    114
    115    "recording-path",
    116    "recording-name",
    117    "recording-exclude-output",
    118    "recording-exclude-mouse",
    119    "recording-exclude-touch",
    120    "recording-include-keys",
    121    "create-recording-path",
    122    "resize-method",
    123    "enable-audio-input",
    124    "enable-touch",
    125    "read-only",
    126
    127    "gateway-hostname",
    128    "gateway-port",
    129    "gateway-domain",
    130    "gateway-username",
    131    "gateway-password",
    132
    133    "load-balance-info",
    134
    135    "disable-copy",
    136    "disable-paste",
    137    
    138    "wol-send-packet",
    139    "wol-mac-addr",
    140    "wol-broadcast-addr",
    141    "wol-udp-port",
    142    "wol-wait-time",
    143
    144    "force-lossless",
    145    "normalize-clipboard",
    146    NULL
    147};
    148
    149enum RDP_ARGS_IDX {
    150    
    151    /**
    152     * The hostname to connect to.
    153     */
    154    IDX_HOSTNAME,
    155
    156    /**
    157     * The port to connect to. If omitted, the default RDP port of 3389 will be
    158     * used.
    159     */
    160    IDX_PORT,
    161
    162    /**
    163     * The domain of the user logging in.
    164     */
    165    IDX_DOMAIN,
    166
    167    /**
    168     * The username of the user logging in.
    169     */
    170    IDX_USERNAME,
    171
    172    /**
    173     * The password of the user logging in.
    174     */
    175    IDX_PASSWORD,
    176
    177    /**
    178     * The width of the display to request, in pixels. If omitted, a reasonable
    179     * value will be calculated based on the user's own display size and
    180     * resolution.
    181     */
    182    IDX_WIDTH,
    183
    184    /**
    185     * The height of the display to request, in pixels. If omitted, a
    186     * reasonable value will be calculated based on the user's own display
    187     * size and resolution.
    188     */
    189    IDX_HEIGHT,
    190
    191    /**
    192     * The resolution of the display to request, in DPI. If omitted, a
    193     * reasonable value will be calculated based on the user's own display
    194     * size and resolution.
    195     */
    196    IDX_DPI,
    197
    198    /**
    199     * The initial program to run, if any.
    200     */
    201    IDX_INITIAL_PROGRAM,
    202
    203    /**
    204     * The color depth of the display to request, in bits.
    205     */
    206    IDX_COLOR_DEPTH,
    207
    208    /**
    209     * "true" if audio should be disabled, "false" or blank to leave audio
    210     * enabled.
    211     */
    212    IDX_DISABLE_AUDIO,
    213
    214    /**
    215     * "true" if printing should be enabled, "false" or blank otherwise.
    216     */
    217    IDX_ENABLE_PRINTING,
    218
    219    /**
    220     * The name of the printer that will be passed through to the RDP server.
    221     */
    222    IDX_PRINTER_NAME,
    223
    224    /**
    225     * "true" if the virtual drive should be enabled, "false" or blank
    226     * otherwise.
    227     */
    228    IDX_ENABLE_DRIVE,
    229    
    230    /**
    231     * The name of the virtual driver that will be passed through to the
    232     * RDP connection.
    233     */
    234    IDX_DRIVE_NAME,
    235
    236    /**
    237     * The local system path which will be used to persist the
    238     * virtual drive. This must be specified if the virtual drive is enabled.
    239     */
    240    IDX_DRIVE_PATH,
    241
    242    /**
    243     * "true" to automatically create the local system path used by the virtual
    244     * drive if it does not yet exist, "false" or blank otherwise.
    245     */
    246    IDX_CREATE_DRIVE_PATH,
    247    
    248    /**
    249     * "true" to disable the ability to download files from a remote server to
    250     * the local client over RDP, "false" or blank otherwise.
    251     */
    252    IDX_DISABLE_DOWNLOAD,
    253    
    254    /**
    255     * "true" to disable the ability to upload files from the local client to
    256     * the remote server over RDP, "false" or blank otherwise.
    257     */
    258    IDX_DISABLE_UPLOAD,
    259
    260    /**
    261     * "true" if this session is a console session, "false" or blank otherwise.
    262     */
    263    IDX_CONSOLE,
    264
    265    /**
    266     * "true" if audio should be allowed in console sessions, "false" or blank
    267     * otherwise.
    268     */
    269    IDX_CONSOLE_AUDIO,
    270
    271    /**
    272     * The name of the keymap chosen as the layout of the server. Legal names
    273     * are defined within the *.keymap files in the "keymaps" directory of the
    274     * source for Guacamole's RDP support.
    275     */
    276    IDX_SERVER_LAYOUT,
    277
    278    /**
    279     * The type of security to use for the connection. Valid values are "rdp",
    280     * "tls", "nla", "nla-ext", "vmconnect", or "any". By default, the security
    281     * mode is negotiated ("any").
    282     */
    283    IDX_SECURITY,
    284
    285    /**
    286     * "true" if validity of the RDP server's certificate should be ignored,
    287     * "false" or blank if invalid certificates should result in a failure to
    288     * connect.
    289     */
    290    IDX_IGNORE_CERT,
    291
    292    /**
    293     * "true" if authentication should be disabled, "false" or blank otherwise.
    294     * This is different from the authentication that takes place when a user
    295     * provides their username and password. Authentication is required by
    296     * definition for NLA.
    297     */
    298    IDX_DISABLE_AUTH,
    299
    300    /**
    301     * The application to launch, if RemoteApp is in use.
    302     */
    303    IDX_REMOTE_APP,
    304
    305    /**
    306     * The working directory of the remote application, if RemoteApp is in use.
    307     */
    308    IDX_REMOTE_APP_DIR,
    309
    310    /**
    311     * The arguments to pass to the remote application, if RemoteApp is in use.
    312     */
    313    IDX_REMOTE_APP_ARGS,
    314
    315    /**
    316     * Comma-separated list of the names of all static virtual channels that
    317     * should be connected to and exposed as Guacamole pipe streams, or blank
    318     * if no static virtual channels should be used. 
    319     */
    320    IDX_STATIC_CHANNELS,
    321
    322    /**
    323     * The name of the client to submit to the RDP server upon connection.
    324     */
    325    IDX_CLIENT_NAME,
    326
    327    /**
    328     * "true" if the desktop wallpaper should be visible, "false" or blank if
    329     * the desktop wallpaper should be hidden.
    330     */
    331    IDX_ENABLE_WALLPAPER,
    332
    333    /**
    334     * "true" if desktop and window theming should be allowed, "false" or blank
    335     * if theming should be temporarily disabled on the desktop of the RDP
    336     * server for the sake of performance.
    337     */
    338    IDX_ENABLE_THEMING,
    339
    340    /**
    341     * "true" if glyphs should be smoothed with antialiasing (ClearType),
    342     * "false" or blank if glyphs should be rendered with sharp edges and using
    343     * single colors, effectively 1-bit images.
    344     */
    345    IDX_ENABLE_FONT_SMOOTHING,
    346
    347    /**
    348     * "true" if windows' contents should be shown as they are moved, "false"
    349     * or blank if only a window border should be shown during window move
    350     * operations.
    351     */
    352    IDX_ENABLE_FULL_WINDOW_DRAG,
    353
    354    /**
    355     * "true" if desktop composition (Aero) should be enabled during the
    356     * session, "false" or blank otherwise. As desktop composition provides
    357     * alpha blending and other special effects, this increases the amount of
    358     * bandwidth used.
    359     */
    360    IDX_ENABLE_DESKTOP_COMPOSITION,
    361
    362    /**
    363     * "true" if menu animations should be shown, "false" or blank menus should
    364     * not be animated.
    365     */
    366    IDX_ENABLE_MENU_ANIMATIONS,
    367
    368    /**
    369     * "true" if bitmap caching should be disabled, "false" if bitmap caching
    370     * should remain enabled.
    371     */
    372    IDX_DISABLE_BITMAP_CACHING,
    373
    374    /**
    375     * "true" if the offscreen caching should be disabled, false if offscreen
    376     * caching should remain enabled.
    377     */
    378    IDX_DISABLE_OFFSCREEN_CACHING,
    379
    380    /**
    381     * "true" if glyph caching should be disabled, false if glyph caching should
    382     * remain enabled.
    383     */
    384    IDX_DISABLE_GLYPH_CACHING,
    385
    386    /**
    387     * The preconnection ID to send within the preconnection PDU when
    388     * initiating an RDP connection, if any.
    389     */
    390    IDX_PRECONNECTION_ID,
    391
    392    /**
    393     * The preconnection BLOB (PCB) to send to the RDP server prior to full RDP
    394     * connection negotiation. This value is used by Hyper-V to select the
    395     * destination VM.
    396     */
    397    IDX_PRECONNECTION_BLOB,
    398
    399    /**
    400     * The timezone to pass through to the RDP connection, in IANA format, which
    401     * will be translated into Windows formats. See the following page for
    402     * information and list of valid values:
    403     * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
    404     */
    405    IDX_TIMEZONE,
    406
    407#ifdef ENABLE_COMMON_SSH
    408    /**
    409     * "true" if SFTP should be enabled for the RDP connection, "false" or
    410     * blank otherwise.
    411     */
    412    IDX_ENABLE_SFTP,
    413
    414    /**
    415     * The hostname of the SSH server to connect to for SFTP. If blank, the
    416     * hostname of the RDP server will be used.
    417     */
    418    IDX_SFTP_HOSTNAME,
    419
    420    /**
    421     * The public SSH host key of the SFTP server. Optional.
    422     */
    423    IDX_SFTP_HOST_KEY,
    424
    425    /**
    426     * The port of the SSH server to connect to for SFTP. If blank, the default
    427     * SSH port of "22" will be used.
    428     */
    429    IDX_SFTP_PORT,
    430
    431    /**
    432     * The username to provide when authenticating with the SSH server for
    433     * SFTP. If blank, the username provided for the RDP user will be used.
    434     */
    435    IDX_SFTP_USERNAME,
    436
    437    /**
    438     * The password to provide when authenticating with the SSH server for
    439     * SFTP (if not using a private key).
    440     */
    441    IDX_SFTP_PASSWORD,
    442
    443    /**
    444     * The base64-encoded private key to use when authenticating with the SSH
    445     * server for SFTP (if not using a password).
    446     */
    447    IDX_SFTP_PRIVATE_KEY,
    448
    449    /**
    450     * The passphrase to use to decrypt the provided base64-encoded private
    451     * key.
    452     */
    453    IDX_SFTP_PASSPHRASE,
    454
    455    /**
    456     * The default location for file uploads within the SSH server. This will
    457     * apply only to uploads which do not use the filesystem guac_object (where
    458     * the destination directory is otherwise ambiguous).
    459     */
    460    IDX_SFTP_DIRECTORY,
    461
    462    /**
    463     * The path of the directory within the SSH server to expose as a
    464     * filesystem guac_object. If omitted, "/" will be used by default.
    465     */
    466    IDX_SFTP_ROOT_DIRECTORY,
    467
    468    /**
    469     * The interval at which SSH keepalive messages are sent to the server for
    470     * SFTP connections. The default is 0 (disabling keepalives), and a value
    471     * of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
    472     * cases.
    473     */
    474    IDX_SFTP_SERVER_ALIVE_INTERVAL,
    475    
    476    /**
    477     * "true" to disable file download from the SFTP server to the local client
    478     * over the SFTP connection, if SFTP is configured and enabled.  "false" or
    479     * blank otherwise.
    480     */
    481    IDX_SFTP_DISABLE_DOWNLOAD,
    482    
    483    /**
    484     * "true" to disable file upload from the SFTP server to the local client
    485     * over the SFTP connection, if SFTP is configured and enabled.  "false" or
    486     * blank otherwise.
    487     */
    488    IDX_SFTP_DISABLE_UPLOAD,
    489#endif
    490
    491    /**
    492     * The full absolute path to the directory in which screen recordings
    493     * should be written.
    494     */
    495    IDX_RECORDING_PATH,
    496
    497    /**
    498     * The name that should be given to screen recordings which are written in
    499     * the given path.
    500     */
    501    IDX_RECORDING_NAME,
    502
    503    /**
    504     * Whether output which is broadcast to each connected client (graphics,
    505     * streams, etc.) should NOT be included in the session recording. Output
    506     * is included by default, as it is necessary for any recording which must
    507     * later be viewable as video.
    508     */
    509    IDX_RECORDING_EXCLUDE_OUTPUT,
    510
    511    /**
    512     * Whether changes to mouse state, such as position and buttons pressed or
    513     * released, should NOT be included in the session recording. Mouse state
    514     * is included by default, as it is necessary for the mouse cursor to be
    515     * rendered in any resulting video.
    516     */
    517    IDX_RECORDING_EXCLUDE_MOUSE,
    518
    519    /**
    520     * Whether changes to touch contact state should NOT be included in the
    521     * session recording. Touch state is included by default, as it may be
    522     * necessary for touch interactions to be rendered in any resulting video.
    523     */
    524    IDX_RECORDING_EXCLUDE_TOUCH,
    525
    526    /**
    527     * Whether keys pressed and released should be included in the session
    528     * recording. Key events are NOT included by default within the recording,
    529     * as doing so has privacy and security implications. Including key events
    530     * may be necessary in certain auditing contexts, but should only be done
    531     * with caution. Key events can easily contain sensitive information, such
    532     * as passwords, credit card numbers, etc.
    533     */
    534    IDX_RECORDING_INCLUDE_KEYS,
    535
    536    /**
    537     * Whether the specified screen recording path should automatically be
    538     * created if it does not yet exist.
    539     */
    540    IDX_CREATE_RECORDING_PATH,
    541
    542    /**
    543     * The method to use to apply screen size changes requested by the user.
    544     * Valid values are blank, "display-update", and "reconnect".
    545     */
    546    IDX_RESIZE_METHOD,
    547
    548    /**
    549     * "true" if audio input (microphone) should be enabled for the RDP
    550     * connection, "false" or blank otherwise.
    551     */
    552    IDX_ENABLE_AUDIO_INPUT,
    553
    554    /**
    555     * "true" if multi-touch support should be enabled for the RDP connection,
    556     * "false" or blank otherwise.
    557     */
    558    IDX_ENABLE_TOUCH,
    559
    560    /**
    561     * "true" if this connection should be read-only (user input should be
    562     * dropped), "false" or blank otherwise.
    563     */
    564    IDX_READ_ONLY,
    565
    566    /**
    567     * The hostname of the remote desktop gateway that should be used as an
    568     * intermediary for the remote desktop connection. If omitted, a gateway
    569     * will not be used.
    570     */
    571    IDX_GATEWAY_HOSTNAME,
    572
    573    /**
    574     * The port of the remote desktop gateway that should be used as an
    575     * intermediary for the remote desktop connection. By default, this will be
    576     * 443.
    577     *
    578     * NOTE: If using a version of FreeRDP prior to 1.2, this setting has no
    579     * effect. FreeRDP instead uses a hard-coded value of 443.
    580     */
    581    IDX_GATEWAY_PORT,
    582
    583    /**
    584     * The domain of the user authenticating with the remote desktop gateway,
    585     * if a gateway is being used. This is not necessarily the same as the
    586     * user actually using the remote desktop connection.
    587     */
    588    IDX_GATEWAY_DOMAIN,
    589
    590    /**
    591     * The username of the user authenticating with the remote desktop gateway,
    592     * if a gateway is being used. This is not necessarily the same as the
    593     * user actually using the remote desktop connection.
    594     */
    595    IDX_GATEWAY_USERNAME,
    596
    597    /**
    598     * The password to provide when authenticating with the remote desktop
    599     * gateway, if a gateway is being used.
    600     */
    601    IDX_GATEWAY_PASSWORD,
    602
    603    /**
    604     * The load balancing information/cookie which should be provided to
    605     * the connection broker, if a connection broker is being used.
    606     */
    607    IDX_LOAD_BALANCE_INFO,
    608
    609    /**
    610     * Whether outbound clipboard access should be blocked. If set to "true",
    611     * it will not be possible to copy data from the remote desktop to the
    612     * client using the clipboard. By default, clipboard access is not blocked.
    613     */
    614    IDX_DISABLE_COPY,
    615
    616    /**
    617     * Whether inbound clipboard access should be blocked. If set to "true", it
    618     * will not be possible to paste data from the client to the remote desktop
    619     * using the clipboard. By default, clipboard access is not blocked.
    620     */
    621    IDX_DISABLE_PASTE,
    622    
    623    /**
    624     * Whether or not to send the magic Wake-on-LAN (WoL) packet to the host
    625     * prior to attempting to connect.  Non-zero values will enable sending
    626     * the WoL packet, while zero will disable this functionality.  By default
    627     * the WoL packet is not sent.
    628     */
    629    IDX_WOL_SEND_PACKET,
    630    
    631    /**
    632     * The MAC address to put in the magic WoL packet for the host that should
    633     * be woken up.
    634     */
    635    IDX_WOL_MAC_ADDR,
    636    
    637    /**
    638     * The broadcast address to which to send the magic WoL packet to wake up
    639     * the remote host.
    640     */
    641    IDX_WOL_BROADCAST_ADDR,
    642    
    643    /**
    644     * The UDP port to use in the magic WoL packet.
    645     */
    646    IDX_WOL_UDP_PORT,
    647    
    648    /**
    649     * The amount of time, in seconds, to wait after sending the WoL packet
    650     * before attempting to connect to the host.  This should be a reasonable
    651     * amount of time to allow the remote host to fully boot and respond to
    652     * network connection requests.  The default is not to wait at all
    653     * (0 seconds).
    654     */
    655    IDX_WOL_WAIT_TIME,
    656
    657    /**
    658     * "true" if all graphical updates for this connection should use lossless
    659     * compresion only, "false" or blank otherwise.
    660     */
    661    IDX_FORCE_LOSSLESS,
    662
    663    /**
    664     * Controls whether the text content of the clipboard should be
    665     * automatically normalized to use a particular line ending format. Valid
    666     * values are "preserve", to preserve line endings verbatim, "windows" to
    667     * transform all line endings to Windows-style CRLF sequences, or "unix" to
    668     * transform all line endings to Unix-style newline characters ('\n'). By
    669     * default, line endings within the clipboard are preserved.
    670     */
    671    IDX_NORMALIZE_CLIPBOARD,
    672
    673    RDP_ARGS_COUNT
    674};
    675
    676guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
    677        int argc, const char** argv) {
    678
    679    /* Validate arg count */
    680    if (argc != RDP_ARGS_COUNT) {
    681        guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
    682                "parameters provided: expected %i, got %i.",
    683                RDP_ARGS_COUNT, argc);
    684        return NULL;
    685    }
    686
    687    guac_rdp_settings* settings = guac_mem_zalloc(sizeof(guac_rdp_settings));
    688
    689    /* Use console */
    690    settings->console =
    691        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    692                IDX_CONSOLE, 0);
    693
    694    /* Enable/disable console audio */
    695    settings->console_audio =
    696        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    697                IDX_CONSOLE_AUDIO, 0);
    698
    699    /* Ignore SSL/TLS certificate */
    700    settings->ignore_certificate =
    701        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    702                IDX_IGNORE_CERT, 0);
    703
    704    /* Disable authentication */
    705    settings->disable_authentication =
    706        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    707                IDX_DISABLE_AUTH, 0);
    708
    709    /* NLA security */
    710    if (strcmp(argv[IDX_SECURITY], "nla") == 0) {
    711        guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA");
    712        settings->security_mode = GUAC_SECURITY_NLA;
    713
    714        /*
    715         * NLA is known not to work with FIPS; allow the mode selection but
    716         * warn that it will not work.
    717         */
    718        if (guac_fips_enabled())
    719            guac_user_log(user, GUAC_LOG_WARNING, fips_nla_mode_warning);
    720
    721    }
    722
    723    /* Extended NLA security */
    724    else if (strcmp(argv[IDX_SECURITY], "nla-ext") == 0) {
    725        guac_user_log(user, GUAC_LOG_INFO, "Security mode: Extended NLA");
    726        settings->security_mode = GUAC_SECURITY_EXTENDED_NLA;
    727
    728        /*
    729         * NLA is known not to work with FIPS; allow the mode selection but
    730         * warn that it will not work.
    731         */
    732        if (guac_fips_enabled())
    733            guac_user_log(user, GUAC_LOG_WARNING, fips_nla_mode_warning);
    734    }
    735
    736    /* TLS security */
    737    else if (strcmp(argv[IDX_SECURITY], "tls") == 0) {
    738        guac_user_log(user, GUAC_LOG_INFO, "Security mode: TLS");
    739        settings->security_mode = GUAC_SECURITY_TLS;
    740    }
    741
    742    /* RDP security */
    743    else if (strcmp(argv[IDX_SECURITY], "rdp") == 0) {
    744        guac_user_log(user, GUAC_LOG_INFO, "Security mode: RDP");
    745        settings->security_mode = GUAC_SECURITY_RDP;
    746    }
    747
    748    /* Negotiate security supported by VMConnect */
    749    else if (strcmp(argv[IDX_SECURITY], "vmconnect") == 0) {
    750        guac_user_log(user, GUAC_LOG_INFO, "Security mode: Hyper-V / VMConnect");
    751        settings->security_mode = GUAC_SECURITY_VMCONNECT;
    752    }
    753
    754    /* Negotiate security (allow server to choose) */
    755    else if (strcmp(argv[IDX_SECURITY], "any") == 0) {
    756        guac_user_log(user, GUAC_LOG_INFO, "Security mode: Negotiate (ANY)");
    757        settings->security_mode = GUAC_SECURITY_ANY;
    758    }
    759
    760    /* If nothing given, default to RDP */
    761    else {
    762        guac_user_log(user, GUAC_LOG_INFO, "No security mode specified. Defaulting to security mode negotiation with server.");
    763        settings->security_mode = GUAC_SECURITY_ANY;
    764    }
    765
    766    /* Set hostname */
    767    settings->hostname =
    768        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    769                IDX_HOSTNAME, "");
    770
    771    /* If port specified, use it, otherwise use an appropriate default */
    772    settings->port =
    773        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_PORT,
    774                settings->security_mode == GUAC_SECURITY_VMCONNECT ? RDP_DEFAULT_VMCONNECT_PORT : RDP_DEFAULT_PORT);
    775
    776    guac_user_log(user, GUAC_LOG_DEBUG,
    777            "User resolution is %ix%i at %i DPI",
    778            user->info.optimal_width,
    779            user->info.optimal_height,
    780            user->info.optimal_resolution);
    781
    782    /* Use suggested resolution unless overridden */
    783    settings->resolution =
    784        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
    785                IDX_DPI, guac_rdp_suggest_resolution(user));
    786
    787    /* Use optimal width unless overridden */
    788    settings->width = user->info.optimal_width
    789                    * settings->resolution
    790                    / user->info.optimal_resolution;
    791
    792    if (argv[IDX_WIDTH][0] != '\0')
    793        settings->width = atoi(argv[IDX_WIDTH]);
    794
    795    /* Use default width if given width is invalid. */
    796    if (settings->width <= 0) {
    797        settings->width = RDP_DEFAULT_WIDTH;
    798        guac_user_log(user, GUAC_LOG_ERROR,
    799                "Invalid width: \"%s\". Using default of %i.",
    800                argv[IDX_WIDTH], settings->width);
    801    }
    802
    803    /* Round width down to nearest multiple of 4 */
    804    settings->width = settings->width & ~0x3;
    805
    806    /* Use optimal height unless overridden */
    807    settings->height = user->info.optimal_height
    808                     * settings->resolution
    809                     / user->info.optimal_resolution;
    810
    811    if (argv[IDX_HEIGHT][0] != '\0')
    812        settings->height = atoi(argv[IDX_HEIGHT]);
    813
    814    /* Use default height if given height is invalid. */
    815    if (settings->height <= 0) {
    816        settings->height = RDP_DEFAULT_HEIGHT;
    817        guac_user_log(user, GUAC_LOG_ERROR,
    818                "Invalid height: \"%s\". Using default of %i.",
    819                argv[IDX_WIDTH], settings->height);
    820    }
    821
    822    guac_user_log(user, GUAC_LOG_DEBUG,
    823            "Using resolution of %ix%i at %i DPI",
    824            settings->width,
    825            settings->height,
    826            settings->resolution);
    827
    828    /* Lossless compression */
    829    settings->lossless =
    830        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    831                IDX_FORCE_LOSSLESS, 0);
    832
    833    /* Domain */
    834    settings->domain =
    835        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    836                IDX_DOMAIN, NULL);
    837
    838    /* Username */
    839    settings->username =
    840        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    841                IDX_USERNAME, NULL);
    842
    843    /* Password */
    844    settings->password =
    845        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    846                IDX_PASSWORD, NULL);
    847
    848    /* Read-only mode */
    849    settings->read_only =
    850        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    851                IDX_READ_ONLY, 0);
    852
    853    /* Client name */
    854    settings->client_name =
    855        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    856                IDX_CLIENT_NAME, "Guacamole RDP");
    857
    858    /* Initial program */
    859    settings->initial_program =
    860        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    861                IDX_INITIAL_PROGRAM, NULL);
    862
    863    /* RemoteApp program */
    864    settings->remote_app =
    865        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    866                IDX_REMOTE_APP, NULL);
    867
    868    /* RemoteApp working directory */
    869    settings->remote_app_dir =
    870        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    871                IDX_REMOTE_APP_DIR, NULL);
    872
    873    /* RemoteApp arguments */
    874    settings->remote_app_args =
    875        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    876                IDX_REMOTE_APP_ARGS, NULL);
    877
    878    /* Static virtual channels */
    879    settings->svc_names = NULL;
    880    if (argv[IDX_STATIC_CHANNELS][0] != '\0')
    881        settings->svc_names = guac_split(argv[IDX_STATIC_CHANNELS], ',');
    882
    883    /*
    884     * Performance flags
    885     */
    886
    887    settings->wallpaper_enabled =
    888        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    889                IDX_ENABLE_WALLPAPER, 0);
    890
    891    settings->theming_enabled =
    892        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    893                IDX_ENABLE_THEMING, 0);
    894
    895    settings->font_smoothing_enabled =
    896        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    897                IDX_ENABLE_FONT_SMOOTHING, 0);
    898
    899    settings->full_window_drag_enabled =
    900        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    901                IDX_ENABLE_FULL_WINDOW_DRAG, 0);
    902
    903    settings->desktop_composition_enabled =
    904        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    905                IDX_ENABLE_DESKTOP_COMPOSITION, 0);
    906
    907    settings->menu_animations_enabled =
    908        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    909                IDX_ENABLE_MENU_ANIMATIONS, 0);
    910
    911    settings->disable_bitmap_caching =
    912        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    913                IDX_DISABLE_BITMAP_CACHING, 0);
    914
    915    settings->disable_offscreen_caching =
    916        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    917                IDX_DISABLE_OFFSCREEN_CACHING, 0);
    918
    919    /* FreeRDP does not consider the glyph cache implementation to be stable as
    920     * of 2.0.0, and it MUST NOT be used. Usage of the glyph cache results in
    921     * unexpected disconnects when using older versions of Windows and recent
    922     * versions of FreeRDP. See: https://issues.apache.org/jira/browse/GUACAMOLE-1191 */
    923    settings->disable_glyph_caching = 1;
    924
    925    /* In case the user expects glyph caching to be enabled, either explicitly
    926     * or by default, warn that this will not be the case as the glyph cache
    927     * is not considered stable. */
    928    if (!guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    929            IDX_DISABLE_GLYPH_CACHING, 0)) {
    930        guac_user_log(user, GUAC_LOG_DEBUG, "Glyph caching is currently "
    931                "universally disabled, regardless of the value of the \"%s\" "
    932                "parameter, as glyph caching support is not considered stable "
    933                "by FreeRDP as of the FreeRDP 2.0.0 release. See: "
    934                "https://issues.apache.org/jira/browse/GUACAMOLE-1191",
    935                GUAC_RDP_CLIENT_ARGS[IDX_DISABLE_GLYPH_CACHING]);
    936    }
    937
    938    /* Session color depth */
    939    settings->color_depth = 
    940        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
    941                IDX_COLOR_DEPTH, RDP_DEFAULT_DEPTH);
    942
    943    /* Preconnection ID */
    944    settings->preconnection_id = -1;
    945    if (argv[IDX_PRECONNECTION_ID][0] != '\0') {
    946
    947        /* Parse preconnection ID, warn if invalid */
    948        int preconnection_id = atoi(argv[IDX_PRECONNECTION_ID]);
    949        if (preconnection_id < 0)
    950            guac_user_log(user, GUAC_LOG_WARNING,
    951                    "Ignoring invalid preconnection ID: %i",
    952                    preconnection_id);
    953
    954        /* Otherwise, assign specified ID */
    955        else {
    956            settings->preconnection_id = preconnection_id;
    957            guac_user_log(user, GUAC_LOG_DEBUG,
    958                    "Preconnection ID: %i", settings->preconnection_id);
    959        }
    960
    961    }
    962
    963    /* Preconnection BLOB */
    964    settings->preconnection_blob = NULL;
    965    if (argv[IDX_PRECONNECTION_BLOB][0] != '\0') {
    966        settings->preconnection_blob = guac_strdup(argv[IDX_PRECONNECTION_BLOB]);
    967        guac_user_log(user, GUAC_LOG_DEBUG,
    968                "Preconnection BLOB: \"%s\"", settings->preconnection_blob);
    969    }
    970
    971    /* Audio enable/disable */
    972    settings->audio_enabled =
    973        !guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    974                IDX_DISABLE_AUDIO, 0);
    975
    976    /* Printing enable/disable */
    977    settings->printing_enabled =
    978        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    979                IDX_ENABLE_PRINTING, 0);
    980
    981    /* Name of redirected printer */
    982    settings->printer_name =
    983        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    984                IDX_PRINTER_NAME, "Guacamole Printer");
    985
    986    /* Drive enable/disable */
    987    settings->drive_enabled =
    988        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
    989                IDX_ENABLE_DRIVE, 0);
    990    
    991    /* Name of the drive being passed through */
    992    settings->drive_name =
    993        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    994                IDX_DRIVE_NAME, "Guacamole Filesystem");
    995
    996    /* The path on the server to connect the drive. */
    997    settings->drive_path =
    998        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
    999                IDX_DRIVE_PATH, "");
   1000
   1001    /* If the server path should be created if it doesn't already exist. */
   1002    settings->create_drive_path =
   1003        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1004                IDX_CREATE_DRIVE_PATH, 0);
   1005    
   1006    /* If file downloads over RDP should be disabled. */
   1007    settings->disable_download =
   1008        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1009                IDX_DISABLE_DOWNLOAD, 0);
   1010    
   1011    /* If file uploads over RDP should be disabled. */
   1012    settings->disable_upload =
   1013        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1014                IDX_DISABLE_UPLOAD, 0);
   1015
   1016    /* Pick keymap based on argument */
   1017    settings->server_layout = NULL;
   1018    if (argv[IDX_SERVER_LAYOUT][0] != '\0')
   1019        settings->server_layout =
   1020            guac_rdp_keymap_find(argv[IDX_SERVER_LAYOUT]);
   1021
   1022    /* If no keymap requested, use default */
   1023    if (settings->server_layout == NULL)
   1024        settings->server_layout = guac_rdp_keymap_find(GUAC_DEFAULT_KEYMAP);
   1025
   1026    /* Timezone if provided by client, or use handshake version */
   1027    settings->timezone =
   1028        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1029                IDX_TIMEZONE, user->info.timezone);
   1030
   1031#ifdef ENABLE_COMMON_SSH
   1032    /* SFTP enable/disable */
   1033    settings->enable_sftp =
   1034        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1035                IDX_ENABLE_SFTP, 0);
   1036
   1037    /* Hostname for SFTP connection */
   1038    settings->sftp_hostname =
   1039        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1040                IDX_SFTP_HOSTNAME, settings->hostname);
   1041
   1042    /* The public SSH host key. */
   1043    settings->sftp_host_key =
   1044        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1045                IDX_SFTP_HOST_KEY, NULL);
   1046
   1047    /* Port for SFTP connection */
   1048    settings->sftp_port =
   1049        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1050                IDX_SFTP_PORT, "22");
   1051
   1052    /* Username for SSH/SFTP authentication */
   1053    settings->sftp_username =
   1054        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1055                IDX_SFTP_USERNAME,
   1056                settings->username != NULL ? settings->username : "");
   1057
   1058    /* Password for SFTP (if not using private key) */
   1059    settings->sftp_password =
   1060        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1061                IDX_SFTP_PASSWORD, "");
   1062
   1063    /* Private key for SFTP (if not using password) */
   1064    settings->sftp_private_key =
   1065        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1066                IDX_SFTP_PRIVATE_KEY, NULL);
   1067
   1068    /* Passphrase for decrypting the SFTP private key (if applicable */
   1069    settings->sftp_passphrase =
   1070        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1071                IDX_SFTP_PASSPHRASE, "");
   1072
   1073    /* Default upload directory */
   1074    settings->sftp_directory =
   1075        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1076                IDX_SFTP_DIRECTORY, NULL);
   1077
   1078    /* SFTP root directory */
   1079    settings->sftp_root_directory =
   1080        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1081                IDX_SFTP_ROOT_DIRECTORY, "/");
   1082
   1083    /* Default keepalive value */
   1084    settings->sftp_server_alive_interval =
   1085        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
   1086                IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
   1087    
   1088    /* Whether or not to disable file download over SFTP. */
   1089    settings->sftp_disable_download =
   1090        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1091                IDX_SFTP_DISABLE_DOWNLOAD, 0);
   1092    
   1093    /* Whether or not to disable file upload over SFTP. */
   1094    settings->sftp_disable_upload =
   1095        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1096                IDX_SFTP_DISABLE_UPLOAD, 0);
   1097#endif
   1098
   1099    /* Read recording path */
   1100    settings->recording_path =
   1101        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1102                IDX_RECORDING_PATH, NULL);
   1103
   1104    /* Read recording name */
   1105    settings->recording_name =
   1106        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1107                IDX_RECORDING_NAME, GUAC_RDP_DEFAULT_RECORDING_NAME);
   1108
   1109    /* Parse output exclusion flag */
   1110    settings->recording_exclude_output =
   1111        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1112                IDX_RECORDING_EXCLUDE_OUTPUT, 0);
   1113
   1114    /* Parse mouse exclusion flag */
   1115    settings->recording_exclude_mouse =
   1116        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1117                IDX_RECORDING_EXCLUDE_MOUSE, 0);
   1118
   1119    /* Parse touch exclusion flag */
   1120    settings->recording_exclude_touch =
   1121        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1122                IDX_RECORDING_EXCLUDE_TOUCH, 0);
   1123
   1124    /* Parse key event inclusion flag */
   1125    settings->recording_include_keys =
   1126        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1127                IDX_RECORDING_INCLUDE_KEYS, 0);
   1128
   1129    /* Parse path creation flag */
   1130    settings->create_recording_path =
   1131        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1132                IDX_CREATE_RECORDING_PATH, 0);
   1133
   1134    /* No resize method */
   1135    if (strcmp(argv[IDX_RESIZE_METHOD], "") == 0) {
   1136        guac_user_log(user, GUAC_LOG_INFO, "Resize method: none");
   1137        settings->resize_method = GUAC_RESIZE_NONE;
   1138    }
   1139
   1140    /* Resize method: "reconnect" */
   1141    else if (strcmp(argv[IDX_RESIZE_METHOD], "reconnect") == 0) {
   1142        guac_user_log(user, GUAC_LOG_INFO, "Resize method: reconnect");
   1143        settings->resize_method = GUAC_RESIZE_RECONNECT;
   1144    }
   1145
   1146    /* Resize method: "display-update" */
   1147    else if (strcmp(argv[IDX_RESIZE_METHOD], "display-update") == 0) {
   1148        guac_user_log(user, GUAC_LOG_INFO, "Resize method: display-update");
   1149        settings->resize_method = GUAC_RESIZE_DISPLAY_UPDATE;
   1150    }
   1151
   1152    /* Default to no resize method if invalid */
   1153    else {
   1154        guac_user_log(user, GUAC_LOG_INFO, "Resize method \"%s\" invalid. ",
   1155                "Defaulting to no resize method.", argv[IDX_RESIZE_METHOD]);
   1156        settings->resize_method = GUAC_RESIZE_NONE;
   1157    }
   1158
   1159    /* Multi-touch input enable/disable */
   1160    settings->enable_touch =
   1161        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1162                IDX_ENABLE_TOUCH, 0);
   1163
   1164    /* Audio input enable/disable */
   1165    settings->enable_audio_input =
   1166        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1167                IDX_ENABLE_AUDIO_INPUT, 0);
   1168
   1169    /* Set gateway hostname */
   1170    settings->gateway_hostname =
   1171        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1172                IDX_GATEWAY_HOSTNAME, NULL);
   1173
   1174    /* If gateway port specified, use it */
   1175    settings->gateway_port =
   1176        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
   1177                IDX_GATEWAY_PORT, 443);
   1178
   1179    /* Set gateway domain */
   1180    settings->gateway_domain =
   1181        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1182                IDX_GATEWAY_DOMAIN, NULL);
   1183
   1184    /* Set gateway username */
   1185    settings->gateway_username =
   1186        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1187                IDX_GATEWAY_USERNAME, NULL);
   1188
   1189    /* Set gateway password */
   1190    settings->gateway_password =
   1191        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1192                IDX_GATEWAY_PASSWORD, NULL);
   1193
   1194    /* Set load balance info */
   1195    settings->load_balance_info =
   1196        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1197                IDX_LOAD_BALANCE_INFO, NULL);
   1198
   1199    /* Parse clipboard copy disable flag */
   1200    settings->disable_copy =
   1201        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1202                IDX_DISABLE_COPY, 0);
   1203
   1204    /* Parse clipboard paste disable flag */
   1205    settings->disable_paste =
   1206        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1207                IDX_DISABLE_PASTE, 0);
   1208
   1209    /* Normalize clipboard line endings to Unix format */
   1210    if (strcmp(argv[IDX_NORMALIZE_CLIPBOARD], "unix") == 0) {
   1211        guac_user_log(user, GUAC_LOG_INFO, "Clipboard line ending normalization: Unix (LF)");
   1212        settings->normalize_clipboard = 1;
   1213        settings->clipboard_crlf = 0;
   1214    }
   1215
   1216    /* Normalize clipboard line endings to Windows format */
   1217    else if (strcmp(argv[IDX_NORMALIZE_CLIPBOARD], "windows") == 0) {
   1218        guac_user_log(user, GUAC_LOG_INFO, "Clipboard line ending normalization: Windows (CRLF)");
   1219        settings->normalize_clipboard = 1;
   1220        settings->clipboard_crlf = 1;
   1221    }
   1222
   1223    /* Preserve clipboard line ending format */
   1224    else if (strcmp(argv[IDX_NORMALIZE_CLIPBOARD], "preserve") == 0) {
   1225        guac_user_log(user, GUAC_LOG_INFO, "Clipboard line ending normalization: Preserve (none)");
   1226        settings->normalize_clipboard = 0;
   1227        settings->clipboard_crlf = 0;
   1228    }
   1229
   1230    /* If nothing given, default to preserving line endings */
   1231    else {
   1232        guac_user_log(user, GUAC_LOG_INFO, "No clipboard line-ending normalization specified. Defaulting to preserving the format of all line endings.");
   1233        settings->normalize_clipboard = 0;
   1234        settings->clipboard_crlf = 0;
   1235    }
   1236
   1237
   1238    /* Parse Wake-on-LAN (WoL) settings */
   1239    settings->wol_send_packet =
   1240        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
   1241                IDX_WOL_SEND_PACKET, 0);
   1242    
   1243    if (settings->wol_send_packet) {
   1244        
   1245        /* If WoL has been requested but no MAC address given, log a warning. */
   1246        if(strcmp(argv[IDX_WOL_MAC_ADDR], "") == 0) {
   1247            guac_user_log(user, GUAC_LOG_WARNING, "WoL requested but no MAC ",
   1248                    "address specified.  WoL will not be sent.");
   1249            settings->wol_send_packet = 0;
   1250        }
   1251        
   1252        /* Parse the WoL MAC address. */
   1253        settings->wol_mac_addr = 
   1254            guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1255                IDX_WOL_MAC_ADDR, NULL);
   1256        
   1257        /* Parse the WoL broadcast address. */
   1258        settings->wol_broadcast_addr =
   1259            guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
   1260                IDX_WOL_BROADCAST_ADDR, GUAC_WOL_LOCAL_IPV4_BROADCAST);
   1261        
   1262        /* Parse the WoL broadcast port. */
   1263        settings->wol_udp_port = (unsigned short)
   1264            guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
   1265                IDX_WOL_UDP_PORT, GUAC_WOL_PORT);
   1266        
   1267        /* Parse the WoL wait time. */
   1268        settings->wol_wait_time =
   1269            guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
   1270                IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME);
   1271        
   1272    }
   1273
   1274    /* Success */
   1275    return settings;
   1276
   1277}
   1278
   1279void guac_rdp_settings_free(guac_rdp_settings* settings) {
   1280
   1281    /* Free settings strings */
   1282    guac_mem_free(settings->client_name);
   1283    guac_mem_free(settings->domain);
   1284    guac_mem_free(settings->drive_name);
   1285    guac_mem_free(settings->drive_path);
   1286    guac_mem_free(settings->hostname);
   1287    guac_mem_free(settings->initial_program);
   1288    guac_mem_free(settings->password);
   1289    guac_mem_free(settings->preconnection_blob);
   1290    guac_mem_free(settings->recording_name);
   1291    guac_mem_free(settings->recording_path);
   1292    guac_mem_free(settings->remote_app);
   1293    guac_mem_free(settings->remote_app_args);
   1294    guac_mem_free(settings->remote_app_dir);
   1295    guac_mem_free(settings->timezone);
   1296    guac_mem_free(settings->username);
   1297    guac_mem_free(settings->printer_name);
   1298
   1299    /* Free channel name array */
   1300    if (settings->svc_names != NULL) {
   1301
   1302        /* Free all elements of array */
   1303        char** current = &(settings->svc_names[0]);
   1304        while (*current != NULL) {
   1305            guac_mem_free(*current);
   1306            current++;
   1307        }
   1308
   1309        /* Free array itself */
   1310        guac_mem_free(settings->svc_names);
   1311
   1312    }
   1313
   1314#ifdef ENABLE_COMMON_SSH
   1315    /* Free SFTP settings */
   1316    guac_mem_free(settings->sftp_directory);
   1317    guac_mem_free(settings->sftp_root_directory);
   1318    guac_mem_free(settings->sftp_host_key);
   1319    guac_mem_free(settings->sftp_hostname);
   1320    guac_mem_free(settings->sftp_passphrase);
   1321    guac_mem_free(settings->sftp_password);
   1322    guac_mem_free(settings->sftp_port);
   1323    guac_mem_free(settings->sftp_private_key);
   1324    guac_mem_free(settings->sftp_username);
   1325#endif
   1326
   1327    /* Free RD gateway information */
   1328    guac_mem_free(settings->gateway_hostname);
   1329    guac_mem_free(settings->gateway_domain);
   1330    guac_mem_free(settings->gateway_username);
   1331    guac_mem_free(settings->gateway_password);
   1332
   1333    /* Free load balancer information string */
   1334    guac_mem_free(settings->load_balance_info);
   1335    
   1336    /* Free Wake-on-LAN strings */
   1337    guac_mem_free(settings->wol_mac_addr);
   1338    guac_mem_free(settings->wol_broadcast_addr);
   1339
   1340    /* Free settings structure */
   1341    guac_mem_free(settings);
   1342
   1343}
   1344
   1345int guac_rdp_get_width(freerdp* rdp) {
   1346    return rdp->settings->DesktopWidth;
   1347}
   1348
   1349int guac_rdp_get_height(freerdp* rdp) {
   1350    return rdp->settings->DesktopHeight;
   1351}
   1352
   1353int guac_rdp_get_depth(freerdp* rdp) {
   1354    return rdp->settings->ColorDepth;
   1355}
   1356
   1357/**
   1358 * Given the settings structure of the Guacamole RDP client, calculates the
   1359 * standard performance flag value to send to the RDP server. The value of
   1360 * these flags is dictated by the RDP standard.
   1361 *
   1362 * @param guac_settings
   1363 *     The settings structure to read performance settings from.
   1364 *
   1365 * @returns
   1366 *     The standard RDP performance flag value representing the union of all
   1367 *     performance settings within the given settings structure.
   1368 */
   1369static int guac_rdp_get_performance_flags(guac_rdp_settings* guac_settings) {
   1370
   1371    /* No performance flags initially */
   1372    int flags = PERF_FLAG_NONE;
   1373
   1374    /* Desktop wallpaper */
   1375    if (!guac_settings->wallpaper_enabled)
   1376        flags |= PERF_DISABLE_WALLPAPER;
   1377
   1378    /* Theming of desktop/windows */
   1379    if (!guac_settings->theming_enabled)
   1380        flags |= PERF_DISABLE_THEMING;
   1381
   1382    /* Font smoothing (ClearType) */
   1383    if (guac_settings->font_smoothing_enabled)
   1384        flags |= PERF_ENABLE_FONT_SMOOTHING;
   1385
   1386    /* Full-window drag */
   1387    if (!guac_settings->full_window_drag_enabled)
   1388        flags |= PERF_DISABLE_FULLWINDOWDRAG;
   1389
   1390    /* Desktop composition (Aero) */
   1391    if (guac_settings->desktop_composition_enabled)
   1392        flags |= PERF_ENABLE_DESKTOP_COMPOSITION;
   1393
   1394    /* Menu animations */
   1395    if (!guac_settings->menu_animations_enabled)
   1396        flags |= PERF_DISABLE_MENUANIMATIONS;
   1397
   1398    return flags;
   1399
   1400}
   1401
   1402void guac_rdp_push_settings(guac_client* client,
   1403        guac_rdp_settings* guac_settings, freerdp* rdp) {
   1404
   1405    rdpSettings* rdp_settings = rdp->settings;
   1406
   1407    /* Authentication */
   1408    rdp_settings->Domain = guac_strdup(guac_settings->domain);
   1409    rdp_settings->Username = guac_strdup(guac_settings->username);
   1410    rdp_settings->Password = guac_strdup(guac_settings->password);
   1411
   1412    /* Connection */
   1413    rdp_settings->ServerHostname = guac_strdup(guac_settings->hostname);
   1414    rdp_settings->ServerPort = guac_settings->port;
   1415
   1416    /* Session */
   1417    rdp_settings->ColorDepth = guac_settings->color_depth;
   1418    rdp_settings->DesktopWidth = guac_settings->width;
   1419    rdp_settings->DesktopHeight = guac_settings->height;
   1420    rdp_settings->AlternateShell = guac_strdup(guac_settings->initial_program);
   1421    rdp_settings->KeyboardLayout = guac_settings->server_layout->freerdp_keyboard_layout;
   1422
   1423    /* Performance flags */
   1424    /* Explicitly set flag value */
   1425    rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings);
   1426
   1427    /* Set individual flags - some FreeRDP versions overwrite the above */
   1428    rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled;
   1429    rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled;
   1430    rdp_settings->DisableFullWindowDrag = !guac_settings->full_window_drag_enabled;
   1431    rdp_settings->DisableMenuAnims = !guac_settings->menu_animations_enabled;
   1432    rdp_settings->DisableThemes = !guac_settings->theming_enabled;
   1433    rdp_settings->AllowDesktopComposition = guac_settings->desktop_composition_enabled;
   1434
   1435    /* Client name */
   1436    if (guac_settings->client_name != NULL) {
   1437        guac_strlcpy(rdp_settings->ClientHostname, guac_settings->client_name,
   1438                RDP_CLIENT_HOSTNAME_SIZE);
   1439    }
   1440
   1441    /* Console */
   1442    rdp_settings->ConsoleSession = guac_settings->console;
   1443    rdp_settings->RemoteConsoleAudio = guac_settings->console_audio;
   1444
   1445    /* Audio */
   1446    rdp_settings->AudioPlayback = guac_settings->audio_enabled;
   1447
   1448    /* Audio capture */
   1449    rdp_settings->AudioCapture = guac_settings->enable_audio_input;
   1450
   1451    /* Display Update channel */
   1452    rdp_settings->SupportDisplayControl =
   1453        (guac_settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE);
   1454
   1455    /* Timezone redirection */
   1456    if (guac_settings->timezone) {
   1457        if (setenv("TZ", guac_settings->timezone, 1)) {
   1458            guac_client_log(client, GUAC_LOG_WARNING,
   1459                "Unable to forward timezone: TZ environment variable "
   1460                "could not be set: %s", strerror(errno));
   1461        }
   1462    }
   1463
   1464    /* Device redirection */
   1465    rdp_settings->DeviceRedirection =  guac_settings->audio_enabled
   1466                                    || guac_settings->drive_enabled
   1467                                    || guac_settings->printing_enabled;
   1468
   1469    /* Security */
   1470    switch (guac_settings->security_mode) {
   1471
   1472        /* Legacy RDP encryption */
   1473        case GUAC_SECURITY_RDP:
   1474            rdp_settings->RdpSecurity = TRUE;
   1475            rdp_settings->TlsSecurity = FALSE;
   1476            rdp_settings->NlaSecurity = FALSE;
   1477            rdp_settings->ExtSecurity = FALSE;
   1478            rdp_settings->UseRdpSecurityLayer = TRUE;
   1479            rdp_settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
   1480            rdp_settings->EncryptionMethods =
   1481                  ENCRYPTION_METHOD_40BIT
   1482                | ENCRYPTION_METHOD_128BIT 
   1483                | ENCRYPTION_METHOD_FIPS;
   1484            break;
   1485
   1486        /* TLS encryption */
   1487        case GUAC_SECURITY_TLS:
   1488            rdp_settings->RdpSecurity = FALSE;
   1489            rdp_settings->TlsSecurity = TRUE;
   1490            rdp_settings->NlaSecurity = FALSE;
   1491            rdp_settings->ExtSecurity = FALSE;
   1492            break;
   1493
   1494        /* Network level authentication */
   1495        case GUAC_SECURITY_NLA:
   1496            rdp_settings->RdpSecurity = FALSE;
   1497            rdp_settings->TlsSecurity = FALSE;
   1498            rdp_settings->NlaSecurity = TRUE;
   1499            rdp_settings->ExtSecurity = FALSE;
   1500            break;
   1501
   1502        /* Extended network level authentication */
   1503        case GUAC_SECURITY_EXTENDED_NLA:
   1504            rdp_settings->RdpSecurity = FALSE;
   1505            rdp_settings->TlsSecurity = FALSE;
   1506            rdp_settings->NlaSecurity = FALSE;
   1507            rdp_settings->ExtSecurity = TRUE;
   1508            break;
   1509
   1510        /* Hyper-V "VMConnect" negotiation mode */
   1511        case GUAC_SECURITY_VMCONNECT:
   1512            rdp_settings->RdpSecurity = FALSE;
   1513            rdp_settings->TlsSecurity = TRUE;
   1514            rdp_settings->NlaSecurity = TRUE;
   1515            rdp_settings->ExtSecurity = FALSE;
   1516            rdp_settings->VmConnectMode = TRUE;
   1517            break;
   1518
   1519        /* All security types */
   1520        case GUAC_SECURITY_ANY:
   1521            rdp_settings->RdpSecurity = TRUE;
   1522            rdp_settings->TlsSecurity = TRUE;
   1523
   1524            /* Explicitly disable NLA if FIPS mode is enabled - it won't work */
   1525            if (guac_fips_enabled()) {
   1526
   1527                guac_client_log(client, GUAC_LOG_INFO,
   1528                        "FIPS mode is enabled. Excluding NLA security mode from security negotiation "
   1529                        "(see: https://github.com/FreeRDP/FreeRDP/issues/3412).");
   1530                rdp_settings->NlaSecurity = FALSE;
   1531
   1532            }
   1533
   1534            /* NLA mode is allowed if FIPS is not enabled */
   1535            else
   1536                rdp_settings->NlaSecurity = TRUE;
   1537
   1538            rdp_settings->ExtSecurity = FALSE;
   1539            break;
   1540
   1541    }
   1542
   1543    /* Authentication */
   1544    rdp_settings->Authentication = !guac_settings->disable_authentication;
   1545    rdp_settings->IgnoreCertificate = guac_settings->ignore_certificate;
   1546
   1547    /* RemoteApp */
   1548    if (guac_settings->remote_app != NULL) {
   1549        rdp_settings->Workarea = TRUE;
   1550        rdp_settings->RemoteApplicationMode = TRUE;
   1551        rdp_settings->RemoteAppLanguageBarSupported = TRUE;
   1552        rdp_settings->RemoteApplicationProgram = guac_strdup(guac_settings->remote_app);
   1553        rdp_settings->ShellWorkingDirectory = guac_strdup(guac_settings->remote_app_dir);
   1554        rdp_settings->RemoteApplicationCmdLine = guac_strdup(guac_settings->remote_app_args);
   1555    }
   1556
   1557    /* Preconnection ID */
   1558    if (guac_settings->preconnection_id != -1) {
   1559        rdp_settings->NegotiateSecurityLayer = FALSE;
   1560        rdp_settings->SendPreconnectionPdu = TRUE;
   1561        rdp_settings->PreconnectionId = guac_settings->preconnection_id;
   1562    }
   1563
   1564    /* Preconnection BLOB */
   1565    if (guac_settings->preconnection_blob != NULL) {
   1566        rdp_settings->NegotiateSecurityLayer = FALSE;
   1567        rdp_settings->SendPreconnectionPdu = TRUE;
   1568        rdp_settings->PreconnectionBlob = guac_strdup(guac_settings->preconnection_blob);
   1569    }
   1570
   1571    /* Enable use of RD gateway if a gateway hostname is provided */
   1572    if (guac_settings->gateway_hostname != NULL) {
   1573
   1574        /* Enable RD gateway */
   1575        rdp_settings->GatewayEnabled = TRUE;
   1576
   1577        /* RD gateway connection details */
   1578        rdp_settings->GatewayHostname = guac_strdup(guac_settings->gateway_hostname);
   1579        rdp_settings->GatewayPort = guac_settings->gateway_port;
   1580
   1581        /* RD gateway credentials */
   1582        rdp_settings->GatewayUseSameCredentials = FALSE;
   1583        rdp_settings->GatewayDomain = guac_strdup(guac_settings->gateway_domain);
   1584        rdp_settings->GatewayUsername = guac_strdup(guac_settings->gateway_username);
   1585        rdp_settings->GatewayPassword = guac_strdup(guac_settings->gateway_password);
   1586
   1587    }
   1588
   1589    /* Store load balance info (and calculate length) if provided */
   1590    if (guac_settings->load_balance_info != NULL) {
   1591        rdp_settings->LoadBalanceInfo = (BYTE*) guac_strdup(guac_settings->load_balance_info);
   1592        rdp_settings->LoadBalanceInfoLength = strlen(guac_settings->load_balance_info);
   1593    }
   1594
   1595    rdp_settings->BitmapCacheEnabled = !guac_settings->disable_bitmap_caching;
   1596    rdp_settings->OffscreenSupportLevel = !guac_settings->disable_offscreen_caching;
   1597    rdp_settings->GlyphSupportLevel = !guac_settings->disable_glyph_caching ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE;
   1598    rdp_settings->OsMajorType = OSMAJORTYPE_UNSPECIFIED;
   1599    rdp_settings->OsMinorType = OSMINORTYPE_UNSPECIFIED;
   1600    rdp_settings->DesktopResize = TRUE;
   1601
   1602    /* Claim support only for specific updates, independent of FreeRDP defaults */
   1603    ZeroMemory(rdp_settings->OrderSupport, GUAC_RDP_ORDER_SUPPORT_LENGTH);
   1604    rdp_settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
   1605    rdp_settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
   1606    rdp_settings->OrderSupport[NEG_MEMBLT_INDEX] = !guac_settings->disable_bitmap_caching;
   1607    rdp_settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = !guac_settings->disable_bitmap_caching;
   1608    rdp_settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
   1609    rdp_settings->OrderSupport[NEG_FAST_INDEX_INDEX] = !guac_settings->disable_glyph_caching;
   1610    rdp_settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = !guac_settings->disable_glyph_caching;
   1611
   1612#ifdef HAVE_RDPSETTINGS_ALLOWUNANOUNCEDORDERSFROMSERVER
   1613    /* Do not consider server use of unannounced orders to be a fatal error */
   1614    rdp_settings->AllowUnanouncedOrdersFromServer = TRUE;
   1615#endif
   1616
   1617}
   1618