int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data;

    /* Connect via VNC if owner */
    if (user->owner) {

        /* Parse arguments into client */
        guac_vnc_settings* settings = vnc_client->settings =
            guac_vnc_parse_args(user, argc, (const char**) argv);

        /* Fail if settings cannot be parsed */
        if (settings == NULL) {
            guac_user_log(user, GUAC_LOG_INFO,
                    "Badly formatted client arguments.");
            return 1;
        }

        /* Start client thread */
        if (pthread_create(&vnc_client->client_thread, NULL, guac_vnc_client_thread, user->client)) {
            guac_user_log(user, GUAC_LOG_ERROR, "Unable to start VNC client thread.");
            return 1;
        }

    }

    /* If not owner, synchronize with current state */
    else {

#ifdef ENABLE_PULSE
        /* Synchronize an audio stream */
        if (vnc_client->audio)
            guac_audio_stream_add_user(vnc_client->audio, user);
#endif

        /* Synchronize with current display */
        guac_common_display_dup(vnc_client->display, user, user->socket);
        guac_socket_flush(user->socket);

    }

    /* Only handle events if not read-only */
    if (vnc_client->settings->read_only == 0) {

        /* General mouse/keyboard/clipboard events */
        user->mouse_handler     = guac_vnc_user_mouse_handler;
        user->key_handler       = guac_vnc_user_key_handler;
        user->clipboard_handler = guac_vnc_clipboard_handler;

#ifdef ENABLE_COMMON_SSH
        /* Set generic (non-filesystem) file upload handler */
        user->file_handler = guac_vnc_sftp_file_handler;
#endif

    }

    return 0;

}
Exemple #2
0
int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_rdp_client* rdp_client = (guac_rdp_client*) user->client->data;

    /* Connect via RDP if owner */
    if (user->owner) {

        /* Parse arguments into client */
        guac_rdp_settings* settings = rdp_client->settings =
            guac_rdp_parse_args(user, argc, (const char**) argv);

        /* Fail if settings cannot be parsed */
        if (settings == NULL) {
            guac_user_log(user, GUAC_LOG_INFO,
                    "Badly formatted client arguments.");
            return 1;
        }

        /* Start client thread */
        if (pthread_create(&rdp_client->client_thread, NULL,
                    guac_rdp_client_thread, user->client)) {
            guac_user_log(user, GUAC_LOG_ERROR,
                    "Unable to start VNC client thread.");
            return 1;
        }

    }

    /* If not owner, synchronize with current state */
    else {

        /* Synchronize any audio stream */
        if (rdp_client->audio)
            guac_audio_stream_add_user(rdp_client->audio, user);

        /* Bring user up to date with any registered static channels */
        guac_rdp_svc_send_pipes(user);

        /* Synchronize with current display */
        guac_common_display_dup(rdp_client->display, user, user->socket);
        guac_socket_flush(user->socket);

    }

    user->file_handler = guac_rdp_user_file_handler;
    user->mouse_handler = guac_rdp_user_mouse_handler;
    user->key_handler = guac_rdp_user_key_handler;
    user->size_handler = guac_rdp_user_size_handler;
    user->pipe_handler = guac_rdp_svc_pipe_handler;
    user->clipboard_handler = guac_rdp_clipboard_handler;

    return 0;

}
/**
 * Logs a reasonable explanatory message regarding handshake failure based on
 * the current value of guac_error.
 *
 * @param user
 *     The guac_user associated with the failed Guacamole protocol handshake.
 */
static void guac_user_log_handshake_failure(guac_user* user) {

    if (guac_error == GUAC_STATUS_CLOSED)
        guac_user_log(user, GUAC_LOG_INFO,
                "Guacamole connection closed during handshake");
    else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR)
        guac_user_log(user, GUAC_LOG_ERROR,
                "Guacamole protocol violation. Perhaps the version of "
                "guacamole-client is incompatible with this version of "
                "libguac?");
    else
        guac_user_log(user, GUAC_LOG_WARNING,
                "Guacamole handshake failed: %s",
                guac_status_string(guac_error));

}
/**
 * Callback for guac_client_foreach_user() which sends clipboard data to each
 * connected client.
 *
 * @param user
 *     The user to send the clipboard data to.
 *
 * @param
 *     A pointer to the guac_common_clipboard structure containing the
 *     clipboard data that should be sent to the given user.
 *
 * @return
 *     Always NULL.
 */
static void* __send_user_clipboard(guac_user* user, void* data) {

    guac_common_clipboard* clipboard = (guac_common_clipboard*) data;

    char* current = clipboard->buffer;
    int remaining = clipboard->length;

    /* Begin stream */
    guac_stream* stream = guac_user_alloc_stream(user);
    guac_protocol_send_clipboard(user->socket, stream, clipboard->mimetype);

    guac_user_log(user, GUAC_LOG_DEBUG,
            "Created stream %i for %s clipboard data.",
            stream->index, clipboard->mimetype);

    /* Split clipboard into chunks */
    while (remaining > 0) {

        /* Calculate size of next block */
        int block_size = GUAC_COMMON_CLIPBOARD_BLOCK_SIZE;
        if (remaining < block_size)
            block_size = remaining; 

        /* Send block */
        guac_protocol_send_blob(user->socket, stream, current, block_size);
        guac_user_log(user, GUAC_LOG_DEBUG,
                "Sent %i bytes of clipboard data on stream %i.",
                block_size, stream->index);

        /* Next block */
        remaining -= block_size;
        current += block_size;

    }

    guac_user_log(user, GUAC_LOG_DEBUG,
            "Clipboard stream %i complete.",
            stream->index);

    /* End stream */
    guac_protocol_send_end(user->socket, stream);
    guac_user_free_stream(user, stream);

    return NULL;

}
/**
 * The thread which handles all user input, calling event handlers for received
 * instructions.
 *
 * @param data
 *     A pointer to a guac_user_input_thread_params structure describing the
 *     user whose input is being handled and the guac_parser with which to
 *     handle it.
 *
 * @return
 *     Always NULL.
 */
static void* guac_user_input_thread(void* data) {

    guac_user_input_thread_params* params =
        (guac_user_input_thread_params*) data;

    int usec_timeout = params->usec_timeout;
    guac_user* user = params->user;
    guac_parser* parser = params->parser;
    guac_client* client = user->client;
    guac_socket* socket = user->socket;

    /* Guacamole user input loop */
    while (client->state == GUAC_CLIENT_RUNNING && user->active) {

        /* Read instruction, stop on error */
        if (guac_parser_read(parser, socket, usec_timeout)) {

            if (guac_error == GUAC_STATUS_TIMEOUT)
                guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding.");

            else {
                if (guac_error != GUAC_STATUS_CLOSED)
                    guac_user_log_guac_error(user, GUAC_LOG_WARNING,
                            "Guacamole connection failure");
                guac_user_stop(user);
            }

            return NULL;
        }

        /* Reset guac_error and guac_error_message (user/client handlers are not
         * guaranteed to set these) */
        guac_error = GUAC_STATUS_SUCCESS;
        guac_error_message = NULL;

        /* Call handler, stop on error */
        if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) {

            /* Log error */
            guac_user_log_guac_error(user, GUAC_LOG_WARNING,
                    "User connection aborted");

            /* Log handler details */
            guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode);

            guac_user_stop(user);
            return NULL;
        }

    }

    return NULL;

}
/**
 * Prints an error message using the logging facilities of the given user,
 * automatically including any information present in guac_error.
 *
 * @param user
 *     The guac_user associated with the error that occurred.
 *
 * @param level
 *     The level at which to log this message.
 *
 * @param message
 *     The message to log.
 */
static void guac_user_log_guac_error(guac_user* user,
        guac_client_log_level level, const char* message) {

    if (guac_error != GUAC_STATUS_SUCCESS) {

        /* If error message provided, include in log */
        if (guac_error_message != NULL)
            guac_user_log(user, level, "%s: %s", message,
                    guac_error_message);

        /* Otherwise just log with standard status string */
        else
            guac_user_log(user, level, "%s: %s", message,
                    guac_status_string(guac_error));

    }

    /* Just log message if no status code */
    else
        guac_user_log(user, level, "%s", message);

}
int guac_ssh_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_client* client = user->client;
    guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;

    /* Connect via SSH if owner */
    if (user->owner) {

        /* Parse arguments into client */
        guac_ssh_settings* settings = ssh_client->settings =
            guac_ssh_parse_args(user, argc, (const char**) argv);

        /* Fail if settings cannot be parsed */
        if (settings == NULL) {
            guac_user_log(user, GUAC_LOG_INFO,
                    "Badly formatted client arguments.");
            return 1;
        }

        /* Start client thread */
        if (pthread_create(&(ssh_client->client_thread), NULL,
                    ssh_client_thread, (void*) client)) {
            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                    "Unable to start SSH client thread");
            return 1;
        }

    }

    /* If not owner, synchronize with current display */
    else {
        guac_terminal_dup(ssh_client->term, user, user->socket);
        guac_socket_flush(user->socket);
    }

    /* Set per-user event handlers */
    user->key_handler       = guac_ssh_user_key_handler;
    user->mouse_handler     = guac_ssh_user_mouse_handler;
    user->size_handler      = guac_ssh_user_size_handler;
    user->clipboard_handler = guac_ssh_clipboard_handler;

    /* Set generic (non-filesystem) file upload handler */
    user->file_handler = guac_sftp_file_handler;

    return 0;

}
guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
        int argc, const char** argv) {

    /* Validate arg count */
    if (argc != SSH_ARGS_COUNT) {
        guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
                "parameters provided: expected %i, got %i.",
                SSH_ARGS_COUNT, argc);
        return NULL;
    }

    guac_ssh_settings* settings = calloc(1, sizeof(guac_ssh_settings));

    /* Read parameters */
    settings->hostname =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_HOSTNAME, "");

    settings->username =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_USERNAME, NULL);

    settings->password =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_PASSWORD, NULL);

    /* Init public key auth information */
    settings->key_base64 =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_PRIVATE_KEY, NULL);

    settings->key_passphrase =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_PASSPHRASE, NULL);

    /* Read font name */
    settings->font_name =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_FONT_NAME, GUAC_SSH_DEFAULT_FONT_NAME);

    /* Read font size */
    settings->font_size =
        guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_FONT_SIZE, GUAC_SSH_DEFAULT_FONT_SIZE);

    /* Copy requested color scheme */
    settings->color_scheme =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_COLOR_SCHEME, "");

    /* Pull width/height/resolution directly from user */
    settings->width      = user->info.optimal_width;
    settings->height     = user->info.optimal_height;
    settings->resolution = user->info.optimal_resolution;

    /* Parse SFTP enable */
    settings->enable_sftp =
        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_ENABLE_SFTP, false);

    /* SFTP root directory */
    settings->sftp_root_directory =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_SFTP_ROOT_DIRECTORY, "/");

#ifdef ENABLE_SSH_AGENT
    settings->enable_agent =
        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_ENABLE_AGENT, false);
#endif

    /* Read port */
    settings->port =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_PORT, GUAC_SSH_DEFAULT_PORT);

    /* Read-only mode */
    settings->read_only =
        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_READ_ONLY, false);

    /* Read command, if any */
    settings->command =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_COMMAND, NULL);

    /* Read typescript path */
    settings->typescript_path =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_TYPESCRIPT_PATH, NULL);

    /* Read typescript name */
    settings->typescript_name =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_TYPESCRIPT_NAME, GUAC_SSH_DEFAULT_TYPESCRIPT_NAME);

    /* Parse path creation flag */
    settings->create_typescript_path =
        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_CREATE_TYPESCRIPT_PATH, false);

    /* Read recording path */
    settings->recording_path =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_RECORDING_PATH, NULL);

    /* Read recording name */
    settings->recording_name =
        guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_RECORDING_NAME, GUAC_SSH_DEFAULT_RECORDING_NAME);

    /* Parse path creation flag */
    settings->create_recording_path =
        guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_CREATE_RECORDING_PATH, false);

    /* Parse server alive interval */
    settings->server_alive_interval =
        guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
                IDX_SERVER_ALIVE_INTERVAL, 0);

    /* Parsing was successful */
    return settings;

}
int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_rdp_client* rdp_client = (guac_rdp_client*) user->client->data;

    /* Parse provided arguments */
    guac_rdp_settings* settings = guac_rdp_parse_args(user,
            argc, (const char**) argv);

    /* Fail if settings cannot be parsed */
    if (settings == NULL) {
        guac_user_log(user, GUAC_LOG_INFO,
                "Badly formatted client arguments.");
        return 1;
    }

    /* Store settings at user level */
    user->data = settings;

    /* Connect via RDP if owner */
    if (user->owner) {

        /* Store owner's settings at client level */
        rdp_client->settings = settings;

        /* Start client thread */
        if (pthread_create(&rdp_client->client_thread, NULL,
                    guac_rdp_client_thread, user->client)) {
            guac_user_log(user, GUAC_LOG_ERROR,
                    "Unable to start VNC client thread.");
            return 1;
        }

        /* Handle inbound audio streams if audio input is enabled */
        if (settings->enable_audio_input)
            user->audio_handler = guac_rdp_audio_handler;

    }

    /* If not owner, synchronize with current state */
    else {

        /* Synchronize any audio stream */
        if (rdp_client->audio)
            guac_audio_stream_add_user(rdp_client->audio, user);

        /* Bring user up to date with any registered static channels */
        guac_rdp_svc_send_pipes(user);

        /* Synchronize with current display */
        guac_common_display_dup(rdp_client->display, user, user->socket);
        guac_socket_flush(user->socket);

    }

    /* Only handle events if not read-only */
    if (!settings->read_only) {

        /* General mouse/keyboard/clipboard events */
        user->mouse_handler     = guac_rdp_user_mouse_handler;
        user->key_handler       = guac_rdp_user_key_handler;
        user->clipboard_handler = guac_rdp_clipboard_handler;

        /* Display size change events */
        user->size_handler = guac_rdp_user_size_handler;

        /* Set generic (non-filesystem) file upload handler */
        user->file_handler = guac_rdp_user_file_handler;

        /* Inbound arbitrary named pipes */
        user->pipe_handler = guac_rdp_svc_pipe_handler;

    }

    return 0;

}
guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
        int argc, const char** argv) {

    /* Validate arg count */
    if (argc != KUBERNETES_ARGS_COUNT) {
        guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
                "parameters provided: expected %i, got %i.",
                KUBERNETES_ARGS_COUNT, argc);
        return NULL;
    }

    guac_kubernetes_settings* settings =
        calloc(1, sizeof(guac_kubernetes_settings));

    /* Read hostname */
    settings->hostname =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_HOSTNAME, "");

    /* Read port */
    settings->port =
        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_PORT, GUAC_KUBERNETES_DEFAULT_PORT);

    /* Read Kubernetes namespace */
    settings->kubernetes_namespace =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_NAMESPACE, GUAC_KUBERNETES_DEFAULT_NAMESPACE);

    /* Read name of Kubernetes pod (required) */
    settings->kubernetes_pod =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_POD, NULL);

    /* Read container of pod (optional) */
    settings->kubernetes_container =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_CONTAINER, NULL);

    /* Parse whether SSL should be used */
    settings->use_ssl =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_USE_SSL, false);

    /* Read SSL/TLS connection details only if enabled */
    if (settings->use_ssl) {

        settings->client_cert =
            guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
                    argv, IDX_CLIENT_CERT, NULL);

        settings->client_key =
            guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
                    argv, IDX_CLIENT_KEY, NULL);

        settings->ca_cert =
            guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
                    argv, IDX_CA_CERT, NULL);

        settings->ignore_cert =
            guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
                    argv, IDX_IGNORE_CERT, false);

    }

    /* Read-only mode */
    settings->read_only =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_READ_ONLY, false);

    /* Read maximum scrollback size */
    settings->max_scrollback =
        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_SCROLLBACK, GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK);

    /* Read font name */
    settings->font_name =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_FONT_NAME, GUAC_KUBERNETES_DEFAULT_FONT_NAME);

    /* Read font size */
    settings->font_size =
        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_FONT_SIZE, GUAC_KUBERNETES_DEFAULT_FONT_SIZE);

    /* Copy requested color scheme */
    settings->color_scheme =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_COLOR_SCHEME, "");

    /* Pull width/height/resolution directly from user */
    settings->width      = user->info.optimal_width;
    settings->height     = user->info.optimal_height;
    settings->resolution = user->info.optimal_resolution;

    /* Read typescript path */
    settings->typescript_path =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_TYPESCRIPT_PATH, NULL);

    /* Read typescript name */
    settings->typescript_name =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_TYPESCRIPT_NAME, GUAC_KUBERNETES_DEFAULT_TYPESCRIPT_NAME);

    /* Parse path creation flag */
    settings->create_typescript_path =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_CREATE_TYPESCRIPT_PATH, false);

    /* Read recording path */
    settings->recording_path =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_RECORDING_PATH, NULL);

    /* Read recording name */
    settings->recording_name =
        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_RECORDING_NAME, GUAC_KUBERNETES_DEFAULT_RECORDING_NAME);

    /* Parse output exclusion flag */
    settings->recording_exclude_output =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_RECORDING_EXCLUDE_OUTPUT, false);

    /* Parse mouse exclusion flag */
    settings->recording_exclude_mouse =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_RECORDING_EXCLUDE_MOUSE, false);

    /* Parse key event inclusion flag */
    settings->recording_include_keys =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_RECORDING_INCLUDE_KEYS, false);

    /* Parse path creation flag */
    settings->create_recording_path =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_CREATE_RECORDING_PATH, false);

    /* Parse backspace key code */
    settings->backspace =
        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_BACKSPACE, 127);

    /* Parse clipboard copy disable flag */
    settings->disable_copy =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_DISABLE_COPY, false);

    /* Parse clipboard paste disable flag */
    settings->disable_paste =
        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                IDX_DISABLE_PASTE, false);

    /* Parsing was successful */
    return settings;

}
guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
        int argc, const char** argv) {

    /* Validate arg count */
    if (argc != RDP_ARGS_COUNT) {
        guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
                "parameters provided: expected %i, got %i.",
                RDP_ARGS_COUNT, argc);
        return NULL;
    }

    guac_rdp_settings* settings = calloc(1, sizeof(guac_rdp_settings));

    /* Use console */
    settings->console =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_CONSOLE, 0);

    /* Enable/disable console audio */
    settings->console_audio =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_CONSOLE_AUDIO, 0);

    /* Ignore SSL/TLS certificate */
    settings->ignore_certificate =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_IGNORE_CERT, 0);

    /* Disable authentication */
    settings->disable_authentication =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_DISABLE_AUTH, 0);

    /* NLA security */
    if (strcmp(argv[IDX_SECURITY], "nla") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Security mode: NLA");
        settings->security_mode = GUAC_SECURITY_NLA;
    }

    /* TLS security */
    else if (strcmp(argv[IDX_SECURITY], "tls") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Security mode: TLS");
        settings->security_mode = GUAC_SECURITY_TLS;
    }

    /* RDP security */
    else if (strcmp(argv[IDX_SECURITY], "rdp") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Security mode: RDP");
        settings->security_mode = GUAC_SECURITY_RDP;
    }

    /* ANY security (allow server to choose) */
    else if (strcmp(argv[IDX_SECURITY], "any") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Security mode: ANY");
        settings->security_mode = GUAC_SECURITY_ANY;
    }

    /* If nothing given, default to RDP */
    else {
        guac_user_log(user, GUAC_LOG_INFO, "No security mode specified. Defaulting to RDP.");
        settings->security_mode = GUAC_SECURITY_RDP;
    }

    /* Set hostname */
    settings->hostname =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_HOSTNAME, "");

    /* If port specified, use it */
    settings->port =
        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_PORT, RDP_DEFAULT_PORT);

    guac_user_log(user, GUAC_LOG_DEBUG,
            "User resolution is %ix%i at %i DPI",
            user->info.optimal_width,
            user->info.optimal_height,
            user->info.optimal_resolution);

    /* Use suggested resolution unless overridden */
    settings->resolution =
        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_DPI, guac_rdp_suggest_resolution(user));

    /* Use optimal width unless overridden */
    settings->width = user->info.optimal_width
                    * settings->resolution
                    / user->info.optimal_resolution;

    if (argv[IDX_WIDTH][0] != '\0')
        settings->width = atoi(argv[IDX_WIDTH]);

    /* Use default width if given width is invalid. */
    if (settings->width <= 0) {
        settings->width = RDP_DEFAULT_WIDTH;
        guac_user_log(user, GUAC_LOG_ERROR,
                "Invalid width: \"%s\". Using default of %i.",
                argv[IDX_WIDTH], settings->width);
    }

    /* Round width down to nearest multiple of 4 */
    settings->width = settings->width & ~0x3;

    /* Use optimal height unless overridden */
    settings->height = user->info.optimal_height
                     * settings->resolution
                     / user->info.optimal_resolution;

    if (argv[IDX_HEIGHT][0] != '\0')
        settings->height = atoi(argv[IDX_HEIGHT]);

    /* Use default height if given height is invalid. */
    if (settings->height <= 0) {
        settings->height = RDP_DEFAULT_HEIGHT;
        guac_user_log(user, GUAC_LOG_ERROR,
                "Invalid height: \"%s\". Using default of %i.",
                argv[IDX_WIDTH], settings->height);
    }

    guac_user_log(user, GUAC_LOG_DEBUG,
            "Using resolution of %ix%i at %i DPI",
            settings->width,
            settings->height,
            settings->resolution);

    /* Domain */
    settings->domain =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_DOMAIN, NULL);

    /* Username */
    settings->username =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_USERNAME, NULL);

    /* Password */
    settings->password =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_PASSWORD, NULL);

    /* Read-only mode */
    settings->read_only =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_READ_ONLY, 0);

    /* Client name */
    settings->client_name =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_CLIENT_NAME, NULL);

    /* Initial program */
    settings->initial_program =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_INITIAL_PROGRAM, NULL);

    /* RemoteApp program */
    settings->remote_app =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_REMOTE_APP, NULL);

    /* RemoteApp working directory */
    settings->remote_app_dir =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_REMOTE_APP_DIR, NULL);

    /* RemoteApp arguments */
    settings->remote_app_args =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_REMOTE_APP_ARGS, NULL);

    /* Static virtual channels */
    settings->svc_names = NULL;
    if (argv[IDX_STATIC_CHANNELS][0] != '\0')
        settings->svc_names = guac_split(argv[IDX_STATIC_CHANNELS], ',');

    /*
     * Performance flags
     */

    settings->wallpaper_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_WALLPAPER, 0);

    settings->theming_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_THEMING, 0);

    settings->font_smoothing_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_FONT_SMOOTHING, 0);

    settings->full_window_drag_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_FULL_WINDOW_DRAG, 0);

    settings->desktop_composition_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_DESKTOP_COMPOSITION, 0);

    settings->menu_animations_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_MENU_ANIMATIONS, 0);

    /* Session color depth */
    settings->color_depth = 
        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_COLOR_DEPTH, RDP_DEFAULT_DEPTH);

    /* Preconnection ID */
    settings->preconnection_id = -1;
    if (argv[IDX_PRECONNECTION_ID][0] != '\0') {

        /* Parse preconnection ID, warn if invalid */
        int preconnection_id = atoi(argv[IDX_PRECONNECTION_ID]);
        if (preconnection_id < 0)
            guac_user_log(user, GUAC_LOG_WARNING,
                    "Ignoring invalid preconnection ID: %i",
                    preconnection_id);

        /* Otherwise, assign specified ID */
        else {
            settings->preconnection_id = preconnection_id;
            guac_user_log(user, GUAC_LOG_DEBUG,
                    "Preconnection ID: %i", settings->preconnection_id);
        }

    }

    /* Preconnection BLOB */
    settings->preconnection_blob = NULL;
    if (argv[IDX_PRECONNECTION_BLOB][0] != '\0') {
        settings->preconnection_blob = strdup(argv[IDX_PRECONNECTION_BLOB]);
        guac_user_log(user, GUAC_LOG_DEBUG,
                "Preconnection BLOB: \"%s\"", settings->preconnection_blob);
    }

#ifndef HAVE_RDPSETTINGS_SENDPRECONNECTIONPDU
    /* Warn if support for the preconnection BLOB / ID is absent */
    if (settings->preconnection_blob != NULL
            || settings->preconnection_id != -1) {
        guac_user_log(user, GUAC_LOG_WARNING,
                "Installed version of FreeRDP lacks support for the "
                "preconnection PDU. The specified preconnection BLOB and/or "
                "ID will be ignored.");
    }
#endif

    /* Audio enable/disable */
    settings->audio_enabled =
        !guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_DISABLE_AUDIO, 0);

    /* Printing enable/disable */
    settings->printing_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_PRINTING, 0);

    /* Drive enable/disable */
    settings->drive_enabled =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_DRIVE, 0);

    settings->drive_path =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_DRIVE_PATH, "");

    settings->create_drive_path =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_CREATE_DRIVE_PATH, 0);

    /* Pick keymap based on argument */
    settings->server_layout = NULL;
    if (argv[IDX_SERVER_LAYOUT][0] != '\0')
        settings->server_layout =
            guac_rdp_keymap_find(argv[IDX_SERVER_LAYOUT]);

    /* If no keymap requested, use default */
    if (settings->server_layout == NULL)
        settings->server_layout = guac_rdp_keymap_find(GUAC_DEFAULT_KEYMAP);

#ifdef ENABLE_COMMON_SSH
    /* SFTP enable/disable */
    settings->enable_sftp =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_SFTP, 0);

    /* Hostname for SFTP connection */
    settings->sftp_hostname =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_HOSTNAME, settings->hostname);

    /* Port for SFTP connection */
    settings->sftp_port =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_PORT, "22");

    /* Username for SSH/SFTP authentication */
    settings->sftp_username =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_USERNAME,
                settings->username != NULL ? settings->username : "");

    /* Password for SFTP (if not using private key) */
    settings->sftp_password =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_PASSWORD, "");

    /* Private key for SFTP (if not using password) */
    settings->sftp_private_key =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_PRIVATE_KEY, NULL);

    /* Passphrase for decrypting the SFTP private key (if applicable */
    settings->sftp_passphrase =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_PASSPHRASE, "");

    /* Default upload directory */
    settings->sftp_directory =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_DIRECTORY, NULL);

    /* SFTP root directory */
    settings->sftp_root_directory =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_ROOT_DIRECTORY, "/");

    /* Default keepalive value */
    settings->sftp_server_alive_interval =
        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
#endif

    /* Read recording path */
    settings->recording_path =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_RECORDING_PATH, NULL);

    /* Read recording name */
    settings->recording_name =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_RECORDING_NAME, GUAC_RDP_DEFAULT_RECORDING_NAME);

    /* Parse path creation flag */
    settings->create_recording_path =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_CREATE_RECORDING_PATH, 0);

    /* No resize method */
    if (strcmp(argv[IDX_RESIZE_METHOD], "") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Resize method: none");
        settings->resize_method = GUAC_RESIZE_NONE;
    }

    /* Resize method: "reconnect" */
    else if (strcmp(argv[IDX_RESIZE_METHOD], "reconnect") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Resize method: reconnect");
        settings->resize_method = GUAC_RESIZE_RECONNECT;
    }

    /* Resize method: "display-update" */
    else if (strcmp(argv[IDX_RESIZE_METHOD], "display-update") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Resize method: display-update");
        settings->resize_method = GUAC_RESIZE_DISPLAY_UPDATE;
    }

    /* Default to no resize method if invalid */
    else {
        guac_user_log(user, GUAC_LOG_INFO, "Resize method \"%s\" invalid. ",
                "Defaulting to no resize method.", argv[IDX_RESIZE_METHOD]);
        settings->resize_method = GUAC_RESIZE_NONE;
    }

    /* Audio input enable/disable */
    settings->enable_audio_input =
        guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_ENABLE_AUDIO_INPUT, 0);

#ifdef HAVE_FREERDP_GATEWAY_SUPPORT
    /* Set gateway hostname */
    settings->gateway_hostname =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_GATEWAY_HOSTNAME, NULL);

    /* If gateway port specified, use it */
    settings->gateway_port =
        guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_GATEWAY_PORT, 443);

    /* Set gateway domain */
    settings->gateway_domain =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_GATEWAY_DOMAIN, NULL);

    /* Set gateway username */
    settings->gateway_username =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_GATEWAY_USERNAME, NULL);

    /* Set gateway password */
    settings->gateway_password =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_GATEWAY_PASSWORD, NULL);
#endif

#ifdef HAVE_FREERDP_LOAD_BALANCER_SUPPORT
    /* Set load balance info */
    settings->load_balance_info =
        guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
                IDX_LOAD_BALANCE_INFO, NULL);
#endif

    /* Success */
    return settings;

}
Exemple #12
0
guac_vnc_settings* guac_vnc_parse_args(guac_user* user,
        int argc, const char** argv) {

    /* Validate arg count */
    if (argc != VNC_ARGS_COUNT) {
        guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
                "parameters provided: expected %i, got %i.",
                VNC_ARGS_COUNT, argc);
        return NULL;
    }

    guac_vnc_settings* settings = calloc(1, sizeof(guac_vnc_settings));

    settings->hostname =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_HOSTNAME, "");

    settings->port =
        guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_PORT, 0);

    settings->password =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_PASSWORD, ""); /* NOTE: freed by libvncclient */

    /* Remote cursor */
    if (strcmp(argv[IDX_CURSOR], "remote") == 0) {
        guac_user_log(user, GUAC_LOG_INFO, "Cursor rendering: remote");
        settings->remote_cursor = true;
    }

    /* Local cursor */
    else {
        guac_user_log(user, GUAC_LOG_INFO, "Cursor rendering: local");
        settings->remote_cursor = false;
    }

    /* Swap red/blue (for buggy VNC servers) */
    settings->swap_red_blue =
        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SWAP_RED_BLUE, false);

    /* Read-only mode */
    settings->read_only =
        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_READ_ONLY, false);

    /* Parse color depth */
    settings->color_depth =
        guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_COLOR_DEPTH, 0);

#ifdef ENABLE_VNC_REPEATER
    /* Set repeater parameters if specified */
    settings->dest_host =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_DEST_HOST, NULL);

    /* VNC repeater port */
    settings->dest_port =
        guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_DEST_PORT, 0);
#endif

    /* Set encodings if specified */
    settings->encodings =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_ENCODINGS,
                "zrle ultra copyrect hextile zlib corre rre raw");

    /* Parse autoretry */
    settings->retries =
        guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_AUTORETRY, 0);

#ifdef ENABLE_VNC_LISTEN
    /* Set reverse-connection flag */
    settings->reverse_connect =
        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_REVERSE_CONNECT, false);

    /* Parse listen timeout */
    settings->listen_timeout =
        guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_LISTEN_TIMEOUT, 5000);
#endif

#ifdef ENABLE_PULSE
    /* Audio enable/disable */
    settings->audio_enabled =
        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_ENABLE_AUDIO, false);

    /* Load servername if specified and applicable */
    if (settings->audio_enabled)
        settings->pa_servername =
            guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                    IDX_AUDIO_SERVERNAME, NULL);
#endif

    /* Set clipboard encoding if specified */
    settings->clipboard_encoding =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_CLIPBOARD_ENCODING, NULL);

#ifdef ENABLE_COMMON_SSH
    /* SFTP enable/disable */
    settings->enable_sftp =
        guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_ENABLE_SFTP, false);

    /* Hostname for SFTP connection */
    settings->sftp_hostname =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_HOSTNAME, settings->hostname);

    /* Port for SFTP connection */
    settings->sftp_port =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_PORT, "22");

    /* Username for SSH/SFTP authentication */
    settings->sftp_username =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_USERNAME, "");

    /* Password for SFTP (if not using private key) */
    settings->sftp_password =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_PASSWORD, "");

    /* Private key for SFTP (if not using password) */
    settings->sftp_private_key =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_PRIVATE_KEY, NULL);

    /* Passphrase for decrypting the SFTP private key (if applicable */
    settings->sftp_passphrase =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_PASSPHRASE, "");

    /* Default upload directory */
    settings->sftp_directory =
        guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
                IDX_SFTP_DIRECTORY, NULL);
#endif


    return settings;

}