void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_socket* socket = client->socket; /* Allocate surface */ guac_layer* buffer = guac_client_alloc_buffer(client); guac_common_surface* surface = guac_common_surface_alloc(socket, buffer, bitmap->width, bitmap->height); /* Cache image data if present */ if (bitmap->data != NULL) { /* Create surface from image data */ cairo_surface_t* image = cairo_image_surface_create_for_data( bitmap->data, CAIRO_FORMAT_RGB24, bitmap->width, bitmap->height, 4*bitmap->width); /* Send surface to buffer */ guac_common_surface_draw(surface, 0, 0, image); /* Free surface */ cairo_surface_destroy(image); } /* Store buffer reference in bitmap */ ((guac_rdp_bitmap*) bitmap)->buffer = buffer; ((guac_rdp_bitmap*) bitmap)->surface = surface; }
guac_common_display_layer* guac_common_display_alloc_buffer( guac_common_display* display, int width, int height) { guac_layer* buffer; guac_common_surface* surface; /* Allocate Guacamole buffer */ buffer = guac_client_alloc_buffer(display->client); /* Allocate corresponding surface */ surface = guac_common_surface_alloc(display->client, display->client->socket, buffer, width, height); /* Add buffer and surface to list */ return guac_common_display_add_layer(&display->buffers, buffer, surface); }
guac_common_display* guac_common_display_alloc(guac_client* client, int width, int height) { /* Allocate display */ guac_common_display* display = malloc(sizeof(guac_common_display)); if (display == NULL) return NULL; /* Associate display with given client */ display->client = client; /* Allocate shared cursor */ display->cursor = guac_common_cursor_alloc(client); display->default_surface = guac_common_surface_alloc(client, client->socket, GUAC_DEFAULT_LAYER, width, height); /* No initial layers or buffers */ display->layers = NULL; display->buffers = NULL; return display; }
int guac_client_init(guac_client* client, int argc, char** argv) { rdp_guac_client_data* guac_client_data; guac_rdp_settings* settings; freerdp* rdp_inst; /* Validate number of arguments received */ if (argc != RDP_ARGS_COUNT) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Wrong argument count received."); return 1; } /* Allocate client data */ guac_client_data = malloc(sizeof(rdp_guac_client_data)); /* Init random number generator */ srandom(time(NULL)); /* Init client */ #ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT freerdp_channels_global_init(); #endif rdp_inst = freerdp_new(); rdp_inst->PreConnect = rdp_freerdp_pre_connect; rdp_inst->PostConnect = rdp_freerdp_post_connect; rdp_inst->Authenticate = rdp_freerdp_authenticate; rdp_inst->VerifyCertificate = rdp_freerdp_verify_certificate; rdp_inst->ReceiveChannelData = __guac_receive_channel_data; /* Allocate FreeRDP context */ #ifdef LEGACY_FREERDP rdp_inst->context_size = sizeof(rdp_freerdp_context); #else rdp_inst->ContextSize = sizeof(rdp_freerdp_context); #endif rdp_inst->ContextNew = (pContextNew) rdp_freerdp_context_new; rdp_inst->ContextFree = (pContextFree) rdp_freerdp_context_free; freerdp_context_new(rdp_inst); /* Set settings */ settings = &(guac_client_data->settings); /* Console */ settings->console = (strcmp(argv[IDX_CONSOLE], "true") == 0); settings->console_audio = (strcmp(argv[IDX_CONSOLE_AUDIO], "true") == 0); /* Certificate and auth */ settings->ignore_certificate = (strcmp(argv[IDX_IGNORE_CERT], "true") == 0); settings->disable_authentication = (strcmp(argv[IDX_DISABLE_AUTH], "true") == 0); /* NLA security */ if (strcmp(argv[IDX_SECURITY], "nla") == 0) { guac_client_log(client, GUAC_LOG_INFO, "Security mode: NLA"); settings->security_mode = GUAC_SECURITY_NLA; } /* TLS security */ else if (strcmp(argv[IDX_SECURITY], "tls") == 0) { guac_client_log(client, GUAC_LOG_INFO, "Security mode: TLS"); settings->security_mode = GUAC_SECURITY_TLS; } /* RDP security */ else if (strcmp(argv[IDX_SECURITY], "rdp") == 0) { guac_client_log(client, 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_client_log(client, GUAC_LOG_INFO, "Security mode: ANY"); settings->security_mode = GUAC_SECURITY_ANY; } /* If nothing given, default to RDP */ else { guac_client_log(client, GUAC_LOG_INFO, "No security mode specified. Defaulting to RDP."); settings->security_mode = GUAC_SECURITY_RDP; } /* Set hostname */ settings->hostname = strdup(argv[IDX_HOSTNAME]); /* If port specified, use it */ settings->port = RDP_DEFAULT_PORT; if (argv[IDX_PORT][0] != '\0') settings->port = atoi(argv[IDX_PORT]); guac_client_log(client, GUAC_LOG_DEBUG, "Client resolution is %ix%i at %i DPI", client->info.optimal_width, client->info.optimal_height, client->info.optimal_resolution); /* Use suggested resolution unless overridden */ settings->resolution = guac_rdp_suggest_resolution(client); if (argv[IDX_DPI][0] != '\0') settings->resolution = atoi(argv[IDX_DPI]); /* Use optimal width unless overridden */ settings->width = client->info.optimal_width * settings->resolution / client->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_client_log(client, 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 = client->info.optimal_height * settings->resolution / client->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_client_log(client, GUAC_LOG_ERROR, "Invalid height: \"%s\". Using default of %i.", argv[IDX_WIDTH], settings->height); } guac_client_log(client, GUAC_LOG_DEBUG, "Using resolution of %ix%i at %i DPI", settings->width, settings->height, settings->resolution); /* Domain */ settings->domain = NULL; if (argv[IDX_DOMAIN][0] != '\0') settings->domain = strdup(argv[IDX_DOMAIN]); /* Username */ settings->username = NULL; if (argv[IDX_USERNAME][0] != '\0') settings->username = strdup(argv[IDX_USERNAME]); /* Password */ settings->password = NULL; if (argv[IDX_PASSWORD][0] != '\0') settings->password = strdup(argv[IDX_PASSWORD]); /* Client name */ settings->client_name = NULL; if (argv[IDX_CLIENT_NAME][0] != '\0') settings->client_name = strdup(argv[IDX_CLIENT_NAME]); /* Initial program */ settings->initial_program = NULL; if (argv[IDX_INITIAL_PROGRAM][0] != '\0') settings->initial_program = strdup(argv[IDX_INITIAL_PROGRAM]); /* RemoteApp program */ settings->remote_app = NULL; if (argv[IDX_REMOTE_APP][0] != '\0') settings->remote_app = strdup(argv[IDX_REMOTE_APP]); /* RemoteApp working directory */ settings->remote_app_dir = NULL; if (argv[IDX_REMOTE_APP_DIR][0] != '\0') settings->remote_app_dir = strdup(argv[IDX_REMOTE_APP_DIR]); /* RemoteApp arguments */ settings->remote_app_args = NULL; if (argv[IDX_REMOTE_APP_ARGS][0] != '\0') settings->remote_app_args = strdup(argv[IDX_REMOTE_APP_ARGS]); /* 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 = (strcmp(argv[IDX_ENABLE_WALLPAPER], "true") == 0); settings->theming_enabled = (strcmp(argv[IDX_ENABLE_THEMING], "true") == 0); settings->font_smoothing_enabled = (strcmp(argv[IDX_ENABLE_FONT_SMOOTHING], "true") == 0); settings->full_window_drag_enabled = (strcmp(argv[IDX_ENABLE_FULL_WINDOW_DRAG], "true") == 0); settings->desktop_composition_enabled = (strcmp(argv[IDX_ENABLE_DESKTOP_COMPOSITION], "true") == 0); settings->menu_animations_enabled = (strcmp(argv[IDX_ENABLE_MENU_ANIMATIONS], "true") == 0); /* Session color depth */ settings->color_depth = RDP_DEFAULT_DEPTH; if (argv[IDX_COLOR_DEPTH][0] != '\0') settings->color_depth = atoi(argv[IDX_COLOR_DEPTH]); /* Use default depth if given depth is invalid. */ if (settings->color_depth == 0) { settings->color_depth = RDP_DEFAULT_DEPTH; guac_client_log(client, GUAC_LOG_ERROR, "Invalid color-depth: \"%s\". Using default of %i.", argv[IDX_WIDTH], settings->color_depth); } /* Audio enable/disable */ guac_client_data->settings.audio_enabled = (strcmp(argv[IDX_DISABLE_AUDIO], "true") != 0); /* Printing enable/disable */ guac_client_data->settings.printing_enabled = (strcmp(argv[IDX_ENABLE_PRINTING], "true") == 0); /* Drive enable/disable */ guac_client_data->settings.drive_enabled = (strcmp(argv[IDX_ENABLE_DRIVE], "true") == 0); guac_client_data->settings.drive_path = strdup(argv[IDX_DRIVE_PATH]); guac_client_data->settings.create_drive_path = (strcmp(argv[IDX_CREATE_DRIVE_PATH], "true") == 0); /* Store client data */ guac_client_data->rdp_inst = rdp_inst; guac_client_data->mouse_button_mask = 0; guac_client_data->clipboard = guac_common_clipboard_alloc(GUAC_RDP_CLIPBOARD_MAX_LENGTH); guac_client_data->requested_clipboard_format = CB_FORMAT_TEXT; guac_client_data->audio = NULL; guac_client_data->filesystem = NULL; guac_client_data->available_svc = guac_common_list_alloc(); /* Main socket needs to be threadsafe */ guac_socket_require_threadsafe(client->socket); /* Recursive attribute for locks */ pthread_mutexattr_init(&(guac_client_data->attributes)); pthread_mutexattr_settype(&(guac_client_data->attributes), PTHREAD_MUTEX_RECURSIVE); /* Init RDP lock */ pthread_mutex_init(&(guac_client_data->rdp_lock), &(guac_client_data->attributes)); /* Clear keysym state mapping and keymap */ memset(guac_client_data->keysym_state, 0, sizeof(guac_rdp_keysym_state_map)); memset(guac_client_data->keymap, 0, sizeof(guac_rdp_static_keymap)); client->data = guac_client_data; ((rdp_freerdp_context*) rdp_inst->context)->client = client; /* 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); /* Load keymap into client */ __guac_rdp_client_load_keymap(client, settings->server_layout); #ifdef ENABLE_COMMON_SSH guac_common_ssh_init(client); /* Connect via SSH if SFTP is enabled */ if (strcmp(argv[IDX_ENABLE_SFTP], "true") == 0) { guac_client_log(client, GUAC_LOG_DEBUG, "Connecting via SSH for SFTP filesystem access."); /* Parse username - use RDP username by default */ const char* sftp_username = argv[IDX_SFTP_USERNAME]; if (sftp_username[0] == '\0' && settings->username != NULL) sftp_username = settings->username; guac_client_data->sftp_user = guac_common_ssh_create_user(sftp_username); /* Import private key, if given */ if (argv[IDX_SFTP_PRIVATE_KEY][0] != '\0') { guac_client_log(client, GUAC_LOG_DEBUG, "Authenticating with private key."); /* Abort if private key cannot be read */ if (guac_common_ssh_user_import_key(guac_client_data->sftp_user, argv[IDX_SFTP_PRIVATE_KEY], argv[IDX_SFTP_PASSPHRASE])) { guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } } /* Otherwise, use specified password */ else { guac_client_log(client, GUAC_LOG_DEBUG, "Authenticating with password."); /* Parse password - use RDP password by default */ const char* sftp_password = argv[IDX_SFTP_PASSWORD]; if (sftp_password[0] == '\0' && settings->password != NULL) sftp_password = settings->password; guac_common_ssh_user_set_password(guac_client_data->sftp_user, sftp_password); } /* Parse hostname - use RDP hostname by default */ const char* sftp_hostname = argv[IDX_SFTP_HOSTNAME]; if (sftp_hostname[0] == '\0') sftp_hostname = settings->hostname; /* Parse port, defaulting to standard SSH port */ const char* sftp_port = argv[IDX_SFTP_PORT]; if (sftp_port[0] == '\0') sftp_port = "22"; /* Attempt SSH connection */ guac_client_data->sftp_session = guac_common_ssh_create_session(client, sftp_hostname, sftp_port, guac_client_data->sftp_user); /* Fail if SSH connection does not succeed */ if (guac_client_data->sftp_session == NULL) { /* Already aborted within guac_common_ssh_create_session() */ guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } /* Load and expose filesystem */ guac_client_data->sftp_filesystem = guac_common_ssh_create_sftp_filesystem( guac_client_data->sftp_session, "/"); /* Abort if SFTP connection fails */ if (guac_client_data->sftp_filesystem == NULL) { guac_common_ssh_destroy_session(guac_client_data->sftp_session); guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } /* Configure destination for basic uploads, if specified */ if (argv[IDX_SFTP_DIRECTORY][0] != '\0') { client->file_handler = guac_rdp_sftp_file_handler; guac_common_ssh_sftp_set_upload_path( guac_client_data->sftp_filesystem, argv[IDX_SFTP_DIRECTORY]); } /* Otherwise, use SFTP for basic uploads only if drive not enabled */ else if (!settings->drive_enabled) client->file_handler = guac_rdp_sftp_file_handler; guac_client_log(client, GUAC_LOG_DEBUG, "SFTP connection succeeded."); } #endif /* Create default surface */ guac_client_data->default_surface = guac_common_surface_alloc(client->socket, GUAC_DEFAULT_LAYER, settings->width, settings->height); guac_client_data->current_surface = guac_client_data->default_surface; /* Send connection name */ guac_protocol_send_name(client->socket, settings->hostname); /* Set default pointer */ guac_common_set_pointer_cursor(client); /* Push desired settings to FreeRDP */ guac_rdp_push_settings(settings, rdp_inst); /* Connect to RDP server */ if (!freerdp_connect(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Error connecting to RDP server"); return 1; } /* Success */ return 0; }
guac_terminal_display* guac_terminal_display_alloc(guac_client* client, const char* font_name, int font_size, int dpi, int foreground, int background) { PangoFontMap* font_map; PangoFont* font; PangoFontMetrics* metrics; PangoContext* context; /* Allocate display */ guac_terminal_display* display = malloc(sizeof(guac_terminal_display)); display->client = client; /* Create default surface */ display->display_layer = guac_client_alloc_layer(client); display->select_layer = guac_client_alloc_layer(client); display->display_surface = guac_common_surface_alloc(client, client->socket, display->display_layer, 0, 0); /* Select layer is a child of the display layer */ guac_protocol_send_move(client->socket, display->select_layer, display->display_layer, 0, 0, 0); /* Get font */ display->font_desc = pango_font_description_new(); pango_font_description_set_family(display->font_desc, font_name); pango_font_description_set_weight(display->font_desc, PANGO_WEIGHT_NORMAL); pango_font_description_set_size(display->font_desc, font_size * PANGO_SCALE * dpi / 96); font_map = pango_cairo_font_map_get_default(); context = pango_font_map_create_context(font_map); font = pango_font_map_load_font(font_map, context, display->font_desc); if (font == NULL) { guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to get font \"%s\"", font_name); return NULL; } metrics = pango_font_get_metrics(font, NULL); if (metrics == NULL) { guac_client_abort(display->client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to get font metrics for font \"%s\"", font_name); return NULL; } display->default_foreground = display->glyph_foreground = foreground; display->default_background = display->glyph_background = background; /* Calculate character dimensions */ display->char_width = pango_font_metrics_get_approximate_digit_width(metrics) / PANGO_SCALE; display->char_height = (pango_font_metrics_get_descent(metrics) + pango_font_metrics_get_ascent(metrics)) / PANGO_SCALE; /* Initially empty */ display->width = 0; display->height = 0; display->operations = NULL; /* Initially nothing selected */ display->text_selected = display->selection_committed = false; return display; }
int guac_client_init(guac_client* client, int argc, char** argv) { rfbClient* rfb_client; vnc_guac_client_data* guac_client_data; int retries_remaining; /* Set up libvncclient logging */ rfbClientLog = guac_vnc_client_log_info; rfbClientErr = guac_vnc_client_log_error; /*** PARSE ARGUMENTS ***/ if (argc != VNC_ARGS_COUNT) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Wrong argument count received."); return 1; } /* Alloc client data */ guac_client_data = malloc(sizeof(vnc_guac_client_data)); client->data = guac_client_data; guac_client_data->hostname = strdup(argv[IDX_HOSTNAME]); guac_client_data->port = atoi(argv[IDX_PORT]); guac_client_data->password = strdup(argv[IDX_PASSWORD]); /* NOTE: freed by libvncclient */ guac_client_data->default_surface = NULL; /* Set flags */ guac_client_data->remote_cursor = (strcmp(argv[IDX_CURSOR], "remote") == 0); guac_client_data->swap_red_blue = (strcmp(argv[IDX_SWAP_RED_BLUE], "true") == 0); guac_client_data->read_only = (strcmp(argv[IDX_READ_ONLY], "true") == 0); /* Parse color depth */ guac_client_data->color_depth = atoi(argv[IDX_COLOR_DEPTH]); #ifdef ENABLE_VNC_REPEATER /* Set repeater parameters if specified */ if (argv[IDX_DEST_HOST][0] != '\0') guac_client_data->dest_host = strdup(argv[IDX_DEST_HOST]); else guac_client_data->dest_host = NULL; if (argv[IDX_DEST_PORT][0] != '\0') guac_client_data->dest_port = atoi(argv[IDX_DEST_PORT]); #endif /* Set encodings if specified */ if (argv[IDX_ENCODINGS][0] != '\0') guac_client_data->encodings = strdup(argv[IDX_ENCODINGS]); else guac_client_data->encodings = NULL; /* Parse autoretry */ if (argv[IDX_AUTORETRY][0] != '\0') retries_remaining = atoi(argv[IDX_AUTORETRY]); else retries_remaining = 0; #ifdef ENABLE_VNC_LISTEN /* Set reverse-connection flag */ guac_client_data->reverse_connect = (strcmp(argv[IDX_REVERSE_CONNECT], "true") == 0); /* Parse listen timeout */ if (argv[IDX_LISTEN_TIMEOUT][0] != '\0') guac_client_data->listen_timeout = atoi(argv[IDX_LISTEN_TIMEOUT]); else guac_client_data->listen_timeout = 5000; #endif /* Init clipboard */ guac_client_data->clipboard = guac_common_clipboard_alloc(GUAC_VNC_CLIPBOARD_MAX_LENGTH); /* Configure clipboard encoding */ if (guac_vnc_set_clipboard_encoding(client, argv[IDX_CLIPBOARD_ENCODING])) guac_client_log(client, GUAC_LOG_INFO, "Using non-standard VNC clipboard encoding: '%s'.", argv[IDX_CLIPBOARD_ENCODING]); /* Ensure connection is kept alive during lengthy connects */ guac_socket_require_keep_alive(client->socket); /* Attempt connection */ rfb_client = __guac_vnc_get_client(client); /* If unsuccessful, retry as many times as specified */ while (!rfb_client && retries_remaining > 0) { struct timespec guac_vnc_connect_interval = { .tv_sec = GUAC_VNC_CONNECT_INTERVAL/1000, .tv_nsec = (GUAC_VNC_CONNECT_INTERVAL%1000)*1000000 }; guac_client_log(client, GUAC_LOG_INFO, "Connect failed. Waiting %ims before retrying...", GUAC_VNC_CONNECT_INTERVAL); /* Wait for given interval then retry */ nanosleep(&guac_vnc_connect_interval, NULL); rfb_client = __guac_vnc_get_client(client); retries_remaining--; } /* If the final connect attempt fails, return error */ if (!rfb_client) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to connect to VNC server."); return 1; } #ifdef ENABLE_PULSE guac_client_data->audio_enabled = (strcmp(argv[IDX_ENABLE_AUDIO], "true") == 0); /* If an encoding is available, load an audio stream */ if (guac_client_data->audio_enabled) { guac_client_data->audio = guac_audio_stream_alloc(client, NULL); /* Load servername if specified */ if (argv[IDX_AUDIO_SERVERNAME][0] != '\0') guac_client_data->pa_servername = strdup(argv[IDX_AUDIO_SERVERNAME]); else guac_client_data->pa_servername = NULL; /* If successful, init audio system */ if (guac_client_data->audio != NULL) { guac_client_log(client, GUAC_LOG_INFO, "Audio will be encoded as %s", guac_client_data->audio->encoder->mimetype); /* Require threadsafe sockets if audio enabled */ guac_socket_require_threadsafe(client->socket); /* Start audio stream */ guac_pa_start_stream(client); } /* Otherwise, audio loading failed */ else guac_client_log(client, GUAC_LOG_INFO, "No available audio encoding. Sound disabled."); } /* end if audio enabled */ #endif #ifdef ENABLE_COMMON_SSH guac_common_ssh_init(client); /* Connect via SSH if SFTP is enabled */ if (strcmp(argv[IDX_ENABLE_SFTP], "true") == 0) { guac_client_log(client, GUAC_LOG_DEBUG, "Connecting via SSH for SFTP filesystem access."); guac_client_data->sftp_user = guac_common_ssh_create_user(argv[IDX_SFTP_USERNAME]); /* Import private key, if given */ if (argv[IDX_SFTP_PRIVATE_KEY][0] != '\0') { guac_client_log(client, GUAC_LOG_DEBUG, "Authenticating with private key."); /* Abort if private key cannot be read */ if (guac_common_ssh_user_import_key(guac_client_data->sftp_user, argv[IDX_SFTP_PRIVATE_KEY], argv[IDX_SFTP_PASSPHRASE])) { guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } } /* Otherwise, use specified password */ else { guac_client_log(client, GUAC_LOG_DEBUG, "Authenticating with password."); guac_common_ssh_user_set_password(guac_client_data->sftp_user, argv[IDX_SFTP_PASSWORD]); } /* Parse hostname - use VNC hostname by default */ const char* sftp_hostname = argv[IDX_SFTP_HOSTNAME]; if (sftp_hostname[0] == '\0') sftp_hostname = guac_client_data->hostname; /* Parse port, defaulting to standard SSH port */ const char* sftp_port = argv[IDX_SFTP_PORT]; if (sftp_port[0] == '\0') sftp_port = "22"; /* Attempt SSH connection */ guac_client_data->sftp_session = guac_common_ssh_create_session(client, sftp_hostname, sftp_port, guac_client_data->sftp_user); /* Fail if SSH connection does not succeed */ if (guac_client_data->sftp_session == NULL) { /* Already aborted within guac_common_ssh_create_session() */ guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } /* Load and expose filesystem */ guac_client_data->sftp_filesystem = guac_common_ssh_create_sftp_filesystem( guac_client_data->sftp_session, "/"); /* Abort if SFTP connection fails */ if (guac_client_data->sftp_filesystem == NULL) { guac_common_ssh_destroy_session(guac_client_data->sftp_session); guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } /* Configure destination for basic uploads, if specified */ if (argv[IDX_SFTP_DIRECTORY][0] != '\0') guac_common_ssh_sftp_set_upload_path( guac_client_data->sftp_filesystem, argv[IDX_SFTP_DIRECTORY]); /* Set file handler for basic uploads */ client->file_handler = guac_vnc_sftp_file_handler; guac_client_log(client, GUAC_LOG_DEBUG, "SFTP connection succeeded."); } #endif /* Set remaining client data */ guac_client_data->rfb_client = rfb_client; guac_client_data->copy_rect_used = 0; guac_client_data->cursor = guac_client_alloc_buffer(client); /* Set handlers */ client->handle_messages = vnc_guac_client_handle_messages; client->free_handler = vnc_guac_client_free_handler; /* If not read-only, set input handlers and pointer */ if (guac_client_data->read_only == 0) { /* Only handle mouse/keyboard/clipboard if not read-only */ client->mouse_handler = vnc_guac_client_mouse_handler; client->key_handler = vnc_guac_client_key_handler; client->clipboard_handler = guac_vnc_clipboard_handler; /* If not read-only but cursor is remote, set a dot cursor */ if (guac_client_data->remote_cursor) guac_common_set_dot_cursor(client); /* Otherwise, set pointer until explicitly requested otherwise */ else guac_common_set_pointer_cursor(client); } /* Send name */ guac_protocol_send_name(client->socket, rfb_client->desktopName); /* Create default surface */ guac_client_data->default_surface = guac_common_surface_alloc(client->socket, GUAC_DEFAULT_LAYER, rfb_client->width, rfb_client->height); return 0; }