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; }
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; }
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; }