static void remmina_rdp_init(RemminaProtocolWidget* gp) { freerdp* instance; rfContext* rfi; instance = freerdp_new(); instance->PreConnect = remmina_rdp_pre_connect; instance->PostConnect = remmina_rdp_post_connect; instance->Authenticate = remmina_rdp_authenticate; instance->VerifyCertificate = remmina_rdp_verify_certificate; instance->VerifyChangedCertificate = remmina_rdp_verify_changed_certificate; instance->ReceiveChannelData = remmina_rdp_receive_channel_data; instance->ContextSize = sizeof(rfContext); freerdp_context_new(instance); rfi = (rfContext*) instance->context; g_object_set_data_full(G_OBJECT(gp), "plugin-data", rfi, free); rfi->protocol_widget = gp; rfi->instance = instance; rfi->settings = instance->settings; rfi->channels = freerdp_channels_new(); pthread_mutex_init(&rfi->mutex, NULL); rfi->gmutex = g_mutex_new(); rfi->gcond = g_cond_new(); remmina_rdp_event_init(gp); }
int main(int argc, char* argv[]) { int status; HANDLE thread; freerdp* instance; rdpChannels* channels; instance = freerdp_new(); instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; instance->ContextSize = sizeof(tfContext); instance->ContextNew = tf_context_new; instance->ContextFree = tf_context_free; freerdp_context_new(instance); channels = instance->context->channels; status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv); if (status < 0) { exit(0); } freerdp_client_load_addins(instance->context->channels, instance->settings); thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tf_client_thread_proc, instance, 0, NULL); WaitForSingleObject(thread, INFINITE); return 0; }
int main(int argc, char* argv[]) { int status; freerdp* instance; instance = freerdp_new(); instance->PreConnect = wl_pre_connect; instance->PostConnect = wl_post_connect; instance->ContextSize = sizeof(struct wl_context); instance->ContextNew = wl_context_new; instance->ContextFree = wl_context_free; freerdp_context_new(instance); status = freerdp_client_settings_parse_command_line_arguments(instance->settings, argc, argv); status = freerdp_client_settings_command_line_status_print(instance->settings, status, argc, argv); if (status) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); wlfreerdp_run(instance); return 0; }
JNIEXPORT jint JNICALL jni_freerdp_new(JNIEnv *env, jclass cls) { freerdp* instance; #if defined(WITH_GPROF) monstartup("libfreerdp-android.so"); #endif // create instance instance = freerdp_new(); instance->PreConnect = android_pre_connect; instance->PostConnect = android_post_connect; instance->Authenticate = android_authenticate; instance->VerifyCertificate = android_verify_certificate; instance->VerifyChangedCertificate = android_verify_changed_certificate; instance->ReceiveChannelData = android_receive_channel_data; // create context instance->ContextSize = sizeof(androidContext); instance->ContextNew = android_context_new; instance->ContextFree = android_context_free; freerdp_context_new(instance); return (jint) instance; }
JNIEXPORT jint JNICALL jni_freerdp_new(JNIEnv *env, jclass cls) { freerdp* instance; #if defined(WITH_GPROF) setenv("CPUPROFILE_FREQUENCY", "200", 1); monstartup("libfreerdp-android.so"); #endif // create instance if (!(instance = freerdp_new())) return (jint)NULL; instance->PreConnect = android_pre_connect; instance->PostConnect = android_post_connect; instance->PostDisconnect = android_post_disconnect; instance->Authenticate = android_authenticate; instance->VerifyCertificate = android_verify_certificate; instance->VerifyChangedCertificate = android_verify_changed_certificate; // create context instance->ContextSize = sizeof(androidContext); instance->ContextNew = android_context_new; instance->ContextFree = android_context_free; if (!freerdp_context_new(instance)) { freerdp_free(instance); instance = NULL; } return (jint) instance; }
int main(int argc, char* argv[]) { int status; pthread_t thread; freerdp* instance; dfContext* context; rdpChannels* channels; struct thread_data* data; setlocale(LC_ALL, ""); freerdp_channels_global_init(); g_sem = CreateSemaphore(NULL, 0, 1, NULL); instance = freerdp_new(); instance->PreConnect = df_pre_connect; instance->PostConnect = df_post_connect; instance->VerifyCertificate = df_verify_certificate; instance->ReceiveChannelData = df_receive_channel_data; instance->ContextSize = sizeof(dfContext); instance->ContextNew = df_context_new; instance->ContextFree = df_context_free; freerdp_context_new(instance); context = (dfContext*) instance->context; channels = instance->context->channels; DirectFBInit(&argc, &argv); instance->context->argc = argc; instance->context->argv = argv; status = freerdp_client_parse_command_line_arguments(argc, argv, instance->settings); if (status < 0) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); data = (struct thread_data*) malloc(sizeof(struct thread_data)); ZeroMemory(data, sizeof(sizeof(struct thread_data))); data->instance = instance; g_thread_count++; pthread_create(&thread, 0, thread_func, data); while (g_thread_count > 0) { WaitForSingleObject(g_sem, INFINITE); } freerdp_channels_global_uninit(); return 0; }
int main(int argc, char* argv[]) { int status; HANDLE thread; freerdp* instance; instance = freerdp_new(); if (!instance) { WLog_ERR(TAG, "Couldn't create instance"); return 1; } instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; instance->ContextSize = sizeof(tfContext); instance->ContextNew = tf_context_new; instance->ContextFree = tf_context_free; freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); if (!freerdp_context_new(instance)) { WLog_ERR(TAG, "Couldn't create context"); return 1; } status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv, FALSE); if (status < 0) { return 0; } if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) return -1; if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL))) { WLog_ERR(TAG, "Failed to create client thread"); } else { WaitForSingleObject(thread, INFINITE); } freerdp_context_free(instance); freerdp_free(instance); return 0; }
int main(int argc, char* argv[]) { int status; pthread_t thread; freerdp* instance; rdpChannels* channels; struct thread_data* data; freerdp_channels_global_init(); g_sem = CreateSemaphore(NULL, 0, 1, NULL); instance = freerdp_new(); instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; instance->ReceiveChannelData = tf_receive_channel_data; instance->ContextSize = sizeof(tfContext); instance->ContextNew = tf_context_new; instance->ContextFree = tf_context_free; freerdp_context_new(instance); channels = instance->context->channels; status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv); if (status < 0) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); data = (struct thread_data*) malloc(sizeof(struct thread_data)); ZeroMemory(data, sizeof(sizeof(struct thread_data))); data->instance = instance; g_thread_count++; pthread_create(&thread, 0, thread_func, data); while (g_thread_count > 0) { WaitForSingleObject(g_sem, INFINITE); } freerdp_channels_global_uninit(); return 0; }
wfInfo* wf_new(HINSTANCE hInstance, HWND hWndParent, int argc, char** argv) { wfInfo* wfi; freerdp* instance; if (!hInstance) hInstance = GetModuleHandle(NULL); instance = freerdp_new(); instance->PreConnect = wf_pre_connect; instance->PostConnect = wf_post_connect; instance->Authenticate = wf_authenticate; instance->VerifyCertificate = wf_verify_certificate; instance->ReceiveChannelData = wf_receive_channel_data; instance->context_size = sizeof(wfContext); instance->ContextNew = wf_context_new; instance->ContextFree = wf_context_free; freerdp_context_new(instance); wfi = ((wfContext*) (instance->context))->wfi; wfi->instance = instance; instance->context->argc = argc; instance->context->argv = argv; wfi->hWndParent = hWndParent; wfi->hInstance = hInstance; wfi->cursor = LoadCursor(NULL, IDC_ARROW); wfi->icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1)); wfi->wndClassName = _tcsdup(_T("FreeRDP")); wfi->wndClass.cbSize = sizeof(WNDCLASSEX); wfi->wndClass.style = CS_HREDRAW | CS_VREDRAW; wfi->wndClass.lpfnWndProc = wf_event_proc; wfi->wndClass.cbClsExtra = 0; wfi->wndClass.cbWndExtra = 0; wfi->wndClass.hCursor = wfi->cursor; wfi->wndClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); wfi->wndClass.lpszMenuName = NULL; wfi->wndClass.lpszClassName = wfi->wndClassName; wfi->wndClass.hInstance = hInstance; wfi->wndClass.hIcon = wfi->icon; wfi->wndClass.hIconSm = wfi->icon; RegisterClassEx(&(wfi->wndClass)); return wfi; }
int main(int argc, char* argv[]) { UwacReturnCode status; freerdp* instance; g_display = UwacOpenDisplay(NULL, &status); if (!g_display) exit(1); g_displayHandle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, UwacDisplayGetFd(g_display), WINPR_FD_READ); if (!g_displayHandle) exit(1); //if (!handle_uwac_events(NULL, g_display)) // exit(1); instance = freerdp_new(); instance->PreConnect = wl_pre_connect; instance->PostConnect = wl_post_connect; instance->PostDisconnect = wl_post_disconnect; instance->Authenticate = client_cli_authenticate; instance->GatewayAuthenticate = client_cli_gw_authenticate; instance->VerifyCertificate = client_cli_verify_certificate; instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; instance->ContextSize = sizeof(wlfContext); instance->ContextNew = wl_context_new; instance->ContextFree = wl_context_free; freerdp_context_new(instance); status = freerdp_client_settings_parse_command_line_arguments(instance->settings, argc, argv, FALSE); status = freerdp_client_settings_command_line_status_print(instance->settings, status, argc, argv); if (status) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); wlfreerdp_run(instance); freerdp_context_free(instance); freerdp_free(instance); return 0; }
int main(int argc, char* argv[]) { pthread_t thread; freerdp* instance; dfContext* context; rdpChannels* channels; struct thread_data* data; setlocale(LC_ALL, ""); freerdp_channels_global_init(); g_sem = freerdp_sem_new(1); instance = freerdp_new(); instance->PreConnect = df_pre_connect; instance->PostConnect = df_post_connect; instance->VerifyCertificate = df_verify_certificate; instance->ReceiveChannelData = df_receive_channel_data; instance->context_size = sizeof(dfContext); instance->ContextNew = df_context_new; instance->ContextFree = df_context_free; freerdp_context_new(instance); context = (dfContext*) instance->context; channels = instance->context->channels; DirectFBInit(&argc, &argv); freerdp_parse_args(instance->settings, argc, argv, df_process_plugin_args, channels, NULL, NULL); data = (struct thread_data*) xzalloc(sizeof(struct thread_data)); data->instance = instance; g_thread_count++; pthread_create(&thread, 0, thread_func, data); while (g_thread_count > 0) { freerdp_sem_wait(g_sem); } freerdp_channels_global_uninit(); return 0; }
rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) { freerdp* instance; rdpContext* context; if (!pEntryPoints) return NULL; IFCALL(pEntryPoints->GlobalInit); instance = freerdp_new(); if (!instance) return NULL; instance->settings = pEntryPoints->settings; instance->ContextSize = pEntryPoints->ContextSize; instance->ContextNew = freerdp_client_common_new; instance->ContextFree = freerdp_client_common_free; instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*) malloc( pEntryPoints->Size); if (!instance->pClientEntryPoints) goto out_fail; CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size); if (!freerdp_context_new(instance)) goto out_fail2; context = instance->context; context->instance = instance; context->settings = instance->settings; if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) != CHANNEL_RC_OK) goto out_fail2; return context; out_fail2: free(instance->pClientEntryPoints); out_fail: freerdp_free(instance); return NULL; }
static int runInstance(int argc, char* argv[], freerdp** inst) { int rc = -1; freerdp* instance = freerdp_new(); if (!instance) goto finish; if (inst) *inst = instance; if (!freerdp_context_new(instance)) goto finish; if (freerdp_client_settings_parse_command_line(instance->settings, argc, argv, FALSE) < 0) goto finish; if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) goto finish; if (s_sync) { if (!SetEvent(s_sync)) goto finish; } rc = 1; if (!freerdp_connect(instance)) goto finish; rc = 2; if (!freerdp_disconnect(instance)) goto finish; rc = 0; finish: freerdp_context_free(instance); freerdp_free(instance); return rc; }
int main(int argc, char* argv[]) { pthread_t thread; freerdp* instance; tfContext* context; struct thread_data* data; rdpChannels* channels; freerdp_channels_global_init(); g_sem = freerdp_sem_new(1); instance = freerdp_new(); instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; instance->ReceiveChannelData = tf_receive_channel_data; instance->ContextSize = (pcContextSize) tf_context_size; instance->ContextNew = (pcContextNew) tf_context_new; instance->ContextFree = (pcContextFree) tf_context_free; freerdp_context_new(instance); context = (tfContext*) instance->context; channels = context->channels; freerdp_parse_args(instance->settings, argc, argv, tf_process_plugin_args, channels, NULL, NULL); data = (struct thread_data*) xzalloc(sizeof(struct thread_data)); data->instance = instance; g_thread_count++; pthread_create(&thread, 0, thread_func, data); while (g_thread_count > 0) { freerdp_sem_wait(g_sem); } freerdp_channels_global_uninit(); return 0; }
rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) { freerdp* instance; rdpContext* context; pEntryPoints->GlobalInit(); instance = freerdp_new(); instance->ContextSize = pEntryPoints->ContextSize; instance->ContextNew = freerdp_client_common_new; instance->ContextFree = freerdp_client_common_free; instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*) malloc(pEntryPoints->Size); CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size); freerdp_context_new(instance); context = instance->context; context->instance = instance; context->settings = instance->settings; return context; }
rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) { freerdp* instance; rdpContext* context; pEntryPoints->GlobalInit(); instance = freerdp_new(); instance->ContextSize = pEntryPoints->ContextSize; instance->ContextNew = freerdp_client_common_new; instance->ContextFree = freerdp_client_common_free; instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*) malloc(pEntryPoints->Size); CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size); freerdp_context_new(instance); context = instance->context; context->instance = instance; context->settings = instance->settings; freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); return context; }
int main(int argc, char* argv[]) { int status; freerdp* instance; instance = freerdp_new(); instance->PreConnect = wl_pre_connect; instance->PostConnect = wl_post_connect; instance->PostDisconnect = wl_post_disconnect; instance->Authenticate = client_cli_authenticate; instance->GatewayAuthenticate = client_cli_gw_authenticate; instance->VerifyCertificate = client_cli_verify_certificate; instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; instance->ContextSize = sizeof(wlfContext); instance->ContextNew = wl_context_new; instance->ContextFree = wl_context_free; freerdp_context_new(instance); status = freerdp_client_settings_parse_command_line_arguments(instance->settings, argc, argv, FALSE); status = freerdp_client_settings_command_line_status_print(instance->settings, status, argc, argv); if (status) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); wlfreerdp_run(instance); freerdp_context_free(instance); freerdp_free(instance); return 0; }
/***************************************************************************** * Open: *****************************************************************************/ static int Open( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; if (p_demux->out == NULL) return VLC_EGENERIC; p_sys = vlc_obj_calloc( p_this, 1, sizeof(demux_sys_t) ); if( !p_sys ) return VLC_ENOMEM; p_sys->f_fps = var_InheritFloat( p_demux, CFG_PREFIX "fps" ); if ( p_sys->f_fps <= 0 ) p_sys->f_fps = 1.0; p_sys->i_frame_interval = CLOCK_FREQ / p_sys->f_fps; #if FREERDP_VERSION_MAJOR == 1 && FREERDP_VERSION_MINOR < 2 freerdp_channels_global_init(); #endif p_sys->p_instance = freerdp_new(); if ( !p_sys->p_instance ) { msg_Err( p_demux, "rdp instantiation error" ); return VLC_EGENERIC; } p_demux->p_sys = p_sys; p_sys->p_instance->PreConnect = preConnectHandler; p_sys->p_instance->PostConnect = postConnectHandler; p_sys->p_instance->Authenticate = authenticateHandler; /* Set up context handlers and let it be allocated */ p_sys->p_instance->ContextSize = sizeof( vlcrdp_context_t ); freerdp_context_new( p_sys->p_instance ); vlcrdp_context_t * p_vlccontext = (vlcrdp_context_t *) p_sys->p_instance->context; p_vlccontext->p_demux = p_demux; /* Parse uri params for pre-connect */ vlc_url_t url; vlc_UrlParse( &url, p_demux->psz_location ); if ( !EMPTY_STR(url.psz_host) ) p_sys->psz_hostname = strdup( url.psz_host ); else p_sys->psz_hostname = strdup( "localhost" ); p_sys->i_port = ( url.i_port > 0 ) ? url.i_port : 3389; vlc_UrlClean( &url ); if ( ! freerdp_connect( p_sys->p_instance ) ) { msg_Err( p_demux, "can't connect to rdp server" ); goto error; } if ( vlc_clone( &p_sys->thread, DemuxThread, p_demux, VLC_THREAD_PRIORITY_INPUT ) != VLC_SUCCESS ) { msg_Err( p_demux, "can't spawn thread" ); freerdp_disconnect( p_sys->p_instance ); goto error; } p_demux->pf_demux = NULL; p_demux->pf_control = Control; return VLC_SUCCESS; error: freerdp_free( p_sys->p_instance ); free( p_sys->psz_hostname ); return VLC_EGENERIC; }
/** * Waits for messages from the RDP server for the given number of microseconds. * * @param client * The client associated with the current RDP session. * * @param timeout_usecs * The maximum amount of time to wait, in microseconds. * * @return * A positive value if messages are ready, zero if the specified timeout * period elapsed, or a negative value if an error occurs. */ static int rdp_guac_client_wait_for_messages(guac_client* client, int timeout_usecs) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; freerdp* rdp_inst = rdp_client->rdp_inst; rdpChannels* channels = rdp_inst->context->channels; int result; int index; int max_fd, fd; void* read_fds[32]; void* write_fds[32]; int read_count = 0; int write_count = 0; fd_set rfds, wfds; struct timeval timeout = { .tv_sec = 0, .tv_usec = timeout_usecs }; /* Get RDP fds */ if (!freerdp_get_fds(rdp_inst, read_fds, &read_count, write_fds, &write_count)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to read RDP file descriptors."); return -1; } /* Get channel fds */ if (!freerdp_channels_get_fds(channels, rdp_inst, read_fds, &read_count, write_fds, &write_count)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to read RDP channel file descriptors."); return -1; } /* Construct read fd_set */ max_fd = 0; FD_ZERO(&rfds); for (index = 0; index < read_count; index++) { fd = (int)(long) (read_fds[index]); if (fd > max_fd) max_fd = fd; FD_SET(fd, &rfds); } /* Construct write fd_set */ FD_ZERO(&wfds); for (index = 0; index < write_count; index++) { fd = (int)(long) (write_fds[index]); if (fd > max_fd) max_fd = fd; FD_SET(fd, &wfds); } /* If no file descriptors, error */ if (max_fd == 0) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "No file descriptors associated with RDP connection."); return -1; } /* Wait for all RDP file descriptors */ result = select(max_fd + 1, &rfds, &wfds, NULL, &timeout); if (result < 0) { /* If error ignorable, pretend timout occurred */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EINTR) return 0; /* Otherwise, return as error */ guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error waiting for file descriptor."); return -1; } /* Return wait result */ return result; } /** * Connects to an RDP server as described by the guac_rdp_settings structure * associated with the given client, allocating and freeing all objects * directly related to the RDP connection. It is expected that all objects * which are independent of FreeRDP's state (the clipboard, display update * management, etc.) will already be allocated and associated with the * guac_rdp_client associated with the given guac_client. This function blocks * for the duration of the RDP session, returning only after the session has * completely disconnected. * * @param client * The guac_client associated with the RDP settings describing the * connection that should be established. * * @return * Zero if the connection successfully terminated and a reconnect is * desired, non-zero if an error occurs or the connection was disconnected * and a reconnect is NOT desired. */ static int guac_rdp_handle_connection(guac_client* client) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; /* Init random number generator */ srandom(time(NULL)); /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); } /* Create display */ rdp_client->display = guac_common_display_alloc(client, rdp_client->settings->width, rdp_client->settings->height); rdp_client->current_surface = rdp_client->display->default_surface; rdp_client->requested_clipboard_format = CB_FORMAT_TEXT; rdp_client->available_svc = guac_common_list_alloc(); #ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT freerdp_channels_global_init(); #endif /* Init client */ freerdp* 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); ((rdp_freerdp_context*) rdp_inst->context)->client = client; /* Load keymap into client */ __guac_rdp_client_load_keymap(client, settings->server_layout); /* Send connection name */ guac_protocol_send_name(client->socket, settings->hostname); /* Set default pointer */ guac_common_cursor_set_pointer(rdp_client->display->cursor); /* 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; } /* Connection complete */ rdp_client->rdp_inst = rdp_inst; rdpChannels* channels = rdp_inst->context->channels; guac_timestamp last_frame_end = guac_timestamp_current(); /* Signal that reconnect has been completed */ guac_rdp_disp_reconnect_complete(rdp_client->disp); /* Handle messages from RDP server while client is running */ while (client->state == GUAC_CLIENT_RUNNING && !guac_rdp_disp_reconnect_needed(rdp_client->disp)) { /* Update remote display size */ pthread_mutex_lock(&(rdp_client->rdp_lock)); guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst); pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Wait for data and construct a reasonable frame */ int wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_START_TIMEOUT); if (wait_result > 0) { int processing_lag = guac_client_get_processing_lag(client); guac_timestamp frame_start = guac_timestamp_current(); /* Read server messages until frame is built */ do { guac_timestamp frame_end; int frame_remaining; pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Check the libfreerdp fds */ if (!freerdp_check_fds(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check channel fds */ if (!freerdp_channels_check_fds(channels, rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP channel file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check for channel events */ wMessage* event = freerdp_channels_pop_event(channels); if (event) { /* Handle channel events (clipboard and RAIL) */ #ifdef LEGACY_EVENT if (event->event_class == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (event->event_class == RailChannel_Class) guac_rdp_process_rail_event(client, event); #else if (GetMessageClass(event->id) == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (GetMessageClass(event->id) == RailChannel_Class) guac_rdp_process_rail_event(client, event); #endif freerdp_event_free(event); } /* Handle RDP disconnect */ if (freerdp_shall_disconnect(rdp_inst)) { guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "RDP server closed connection"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Calculate time remaining in frame */ frame_end = guac_timestamp_current(); frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION - frame_end; /* Calculate time that client needs to catch up */ int time_elapsed = frame_end - last_frame_end; int required_wait = processing_lag - time_elapsed; /* Increase the duration of this frame if client is lagging */ if (required_wait > GUAC_RDP_FRAME_TIMEOUT) wait_result = rdp_guac_client_wait_for_messages(client, required_wait*1000); /* Wait again if frame remaining */ else if (frame_remaining > 0) wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_TIMEOUT*1000); else break; } while (wait_result > 0); } /* If an error occurred, fail */ if (wait_result < 0) guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Connection closed."); /* End of frame */ guac_common_display_flush(rdp_client->display); guac_client_end_frame(client); guac_socket_flush(client->socket); /* Record end of frame */ last_frame_end = guac_timestamp_current(); } /* Kill client and finish connection */ guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected"); pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Disconnect client and channels */ freerdp_channels_close(channels, rdp_inst); freerdp_channels_free(channels); freerdp_disconnect(rdp_inst); /* Clean up RDP client context */ freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv); cache_free(rdp_inst->context->cache); freerdp_context_free(rdp_inst); /* Clean up RDP client */ freerdp_free(rdp_inst); rdp_client->rdp_inst = NULL; /* Free SVC list */ guac_common_list_free(rdp_client->available_svc); /* Free display */ guac_common_display_free(rdp_client->display); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 0; }
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; }
/** * Connects to an RDP server as described by the guac_rdp_settings structure * associated with the given client, allocating and freeing all objects * directly related to the RDP connection. It is expected that all objects * which are independent of FreeRDP's state (the clipboard, display update * management, etc.) will already be allocated and associated with the * guac_rdp_client associated with the given guac_client. This function blocks * for the duration of the RDP session, returning only after the session has * completely disconnected. * * @param client * The guac_client associated with the RDP settings describing the * connection that should be established. * * @return * Zero if the connection successfully terminated and a reconnect is * desired, non-zero if an error occurs or the connection was disconnected * and a reconnect is NOT desired. */ static int guac_rdp_handle_connection(guac_client* client) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; /* Init random number generator */ srandom(time(NULL)); /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); } /* Create display */ rdp_client->display = guac_common_display_alloc(client, rdp_client->settings->width, rdp_client->settings->height); rdp_client->current_surface = rdp_client->display->default_surface; rdp_client->requested_clipboard_format = CB_FORMAT_TEXT; rdp_client->available_svc = guac_common_list_alloc(); #ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT freerdp_channels_global_init(); #endif /* Init client */ freerdp* 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); ((rdp_freerdp_context*) rdp_inst->context)->client = client; /* Load keymap into client */ rdp_client->keyboard = guac_rdp_keyboard_alloc(client, settings->server_layout); /* Send connection name */ guac_protocol_send_name(client->socket, settings->hostname); /* Set default pointer */ guac_common_cursor_set_pointer(rdp_client->display->cursor); /* 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; } /* Connection complete */ rdp_client->rdp_inst = rdp_inst; rdpChannels* channels = rdp_inst->context->channels; guac_timestamp last_frame_end = guac_timestamp_current(); /* Signal that reconnect has been completed */ guac_rdp_disp_reconnect_complete(rdp_client->disp); /* Handle messages from RDP server while client is running */ while (client->state == GUAC_CLIENT_RUNNING && !guac_rdp_disp_reconnect_needed(rdp_client->disp)) { /* Update remote display size */ pthread_mutex_lock(&(rdp_client->rdp_lock)); guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst); pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Wait for data and construct a reasonable frame */ int wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_START_TIMEOUT); if (wait_result > 0) { int processing_lag = guac_client_get_processing_lag(client); guac_timestamp frame_start = guac_timestamp_current(); /* Read server messages until frame is built */ do { guac_timestamp frame_end; int frame_remaining; pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Check the libfreerdp fds */ if (!freerdp_check_fds(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check channel fds */ if (!freerdp_channels_check_fds(channels, rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP channel file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check for channel events */ wMessage* event = freerdp_channels_pop_event(channels); if (event) { /* Handle channel events (clipboard and RAIL) */ #ifdef LEGACY_EVENT if (event->event_class == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (event->event_class == RailChannel_Class) guac_rdp_process_rail_event(client, event); #else if (GetMessageClass(event->id) == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (GetMessageClass(event->id) == RailChannel_Class) guac_rdp_process_rail_event(client, event); #endif freerdp_event_free(event); } /* Handle RDP disconnect */ if (freerdp_shall_disconnect(rdp_inst)) { guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "RDP server closed connection"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Calculate time remaining in frame */ frame_end = guac_timestamp_current(); frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION - frame_end; /* Calculate time that client needs to catch up */ int time_elapsed = frame_end - last_frame_end; int required_wait = processing_lag - time_elapsed; /* Increase the duration of this frame if client is lagging */ if (required_wait > GUAC_RDP_FRAME_TIMEOUT) wait_result = rdp_guac_client_wait_for_messages(client, required_wait); /* Wait again if frame remaining */ else if (frame_remaining > 0) wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_TIMEOUT); else break; } while (wait_result > 0); /* Record end of frame, excluding server-side rendering time (we * assume server-side rendering time will be consistent between any * two subsequent frames, and that this time should thus be * excluded from the required wait period of the next frame). */ last_frame_end = frame_start; } /* If an error occurred, fail */ if (wait_result < 0) guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Connection closed."); /* Flush frame */ guac_common_display_flush(rdp_client->display); guac_client_end_frame(client); guac_socket_flush(client->socket); } pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Disconnect client and channels */ freerdp_channels_close(channels, rdp_inst); freerdp_channels_free(channels); freerdp_disconnect(rdp_inst); /* Clean up RDP client context */ freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv); cache_free(rdp_inst->context->cache); freerdp_context_free(rdp_inst); /* Clean up RDP client */ freerdp_free(rdp_inst); rdp_client->rdp_inst = NULL; /* Free SVC list */ guac_common_list_free(rdp_client->available_svc); /* Free RDP keyboard state */ guac_rdp_keyboard_free(rdp_client->keyboard); /* Free display */ guac_common_display_free(rdp_client->display); pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Client is now disconnected */ guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected"); return 0; }
int guac_client_init(guac_client* client, int argc, char** argv) { rdp_guac_client_data* guac_client_data; freerdp* rdp_inst; rdpSettings* settings; char* hostname; int port = RDP_DEFAULT_PORT; boolean bitmap_cache; /** * Selected server-side keymap. Client will be assumed to also use this * keymap. Keys will be sent to server based on client input on a * best-effort basis. */ const guac_rdp_keymap* chosen_keymap; if (argc < RDP_ARGS_COUNT) { guac_protocol_send_error(client->socket, "Wrong argument count received."); guac_socket_flush(client->socket); guac_error = GUAC_STATUS_BAD_ARGUMENT; guac_error_message = "Wrong argument count received"; return 1; } /* If port specified, use it */ if (argv[IDX_PORT][0] != '\0') port = atoi(argv[IDX_PORT]); hostname = argv[IDX_HOSTNAME]; /* Allocate client data */ guac_client_data = malloc(sizeof(rdp_guac_client_data)); /* Init random number generator */ srandom(time(NULL)); /* Init client */ freerdp_channels_global_init(); rdp_inst = freerdp_new(); rdp_inst->PreConnect = rdp_freerdp_pre_connect; rdp_inst->PostConnect = rdp_freerdp_post_connect; rdp_inst->ReceiveChannelData = __guac_receive_channel_data; /* Allocate FreeRDP context */ rdp_inst->context_size = sizeof(rdp_freerdp_context); rdp_inst->ContextNew = (pContextNew) rdp_freerdp_context_new; rdp_inst->ContextFree = (pContextFree) rdp_freerdp_context_free; freerdp_context_new(rdp_inst); /* Set settings */ settings = rdp_inst->settings; /* Console */ settings->console_session = (strcmp(argv[IDX_CONSOLE], "true") == 0); settings->console_audio = (strcmp(argv[IDX_CONSOLE_AUDIO], "true") == 0); /* --no-auth */ settings->authentication = false; /* --sec rdp */ settings->rdp_security = true; settings->tls_security = false; settings->nla_security = false; settings->encryption = true; settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS; settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE; /* Use optimal width unless overridden */ settings->width = client->info.optimal_width; 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_error(client, "Invalid width: \"%s\". Using default of %i.", argv[IDX_WIDTH], settings->width); } /* Round width up to nearest multiple of 4 */ settings->width = (settings->width + 3) & ~0x3; /* Use optimal height unless overridden */ settings->height = client->info.optimal_height; 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_error(client, "Invalid height: \"%s\". Using default of %i.", argv[IDX_WIDTH], settings->height); } /* Set hostname */ settings->hostname = strdup(hostname); settings->port = port; settings->window_title = strdup(hostname); /* Domain */ if (argv[IDX_DOMAIN][0] != '\0') settings->domain = strdup(argv[IDX_DOMAIN]); /* Username */ if (argv[IDX_USERNAME][0] != '\0') settings->username = strdup(argv[IDX_USERNAME]); /* Password */ if (argv[IDX_PASSWORD][0] != '\0') { settings->password = strdup(argv[IDX_PASSWORD]); settings->autologon = 1; } /* Initial program */ if (argv[IDX_INITIAL_PROGRAM][0] != '\0') settings->shell = strdup(argv[IDX_INITIAL_PROGRAM]); /* 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_error(client, "Invalid color-depth: \"%s\". Using default of %i.", argv[IDX_WIDTH], settings->color_depth); } /* Audio enable/disable */ guac_client_data->audio_enabled = (strcmp(argv[IDX_DISABLE_AUDIO], "true") != 0); /* Printing enable/disable */ guac_client_data->printing_enabled = (strcmp(argv[IDX_ENABLE_PRINTING], "true") == 0); /* Order support */ bitmap_cache = settings->bitmap_cache; settings->os_major_type = OSMAJORTYPE_UNSPECIFIED; settings->os_minor_type = OSMINORTYPE_UNSPECIFIED; settings->order_support[NEG_DSTBLT_INDEX] = true; settings->order_support[NEG_PATBLT_INDEX] = false; /* PATBLT not yet supported */ settings->order_support[NEG_SCRBLT_INDEX] = true; settings->order_support[NEG_OPAQUE_RECT_INDEX] = true; settings->order_support[NEG_DRAWNINEGRID_INDEX] = false; settings->order_support[NEG_MULTIDSTBLT_INDEX] = false; settings->order_support[NEG_MULTIPATBLT_INDEX] = false; settings->order_support[NEG_MULTISCRBLT_INDEX] = false; settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false; settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false; settings->order_support[NEG_LINETO_INDEX] = false; settings->order_support[NEG_POLYLINE_INDEX] = false; settings->order_support[NEG_MEMBLT_INDEX] = bitmap_cache; settings->order_support[NEG_MEM3BLT_INDEX] = false; settings->order_support[NEG_MEMBLT_V2_INDEX] = bitmap_cache; settings->order_support[NEG_MEM3BLT_V2_INDEX] = false; settings->order_support[NEG_SAVEBITMAP_INDEX] = false; settings->order_support[NEG_GLYPH_INDEX_INDEX] = true; settings->order_support[NEG_FAST_INDEX_INDEX] = true; settings->order_support[NEG_FAST_GLYPH_INDEX] = true; settings->order_support[NEG_POLYGON_SC_INDEX] = false; settings->order_support[NEG_POLYGON_CB_INDEX] = false; settings->order_support[NEG_ELLIPSE_SC_INDEX] = false; settings->order_support[NEG_ELLIPSE_CB_INDEX] = false; /* Store client data */ guac_client_data->rdp_inst = rdp_inst; guac_client_data->bounded = false; guac_client_data->mouse_button_mask = 0; guac_client_data->current_surface = GUAC_DEFAULT_LAYER; guac_client_data->clipboard = NULL; guac_client_data->audio = NULL; /* 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 */ if (argv[IDX_SERVER_LAYOUT][0] != '\0') { /* US English Qwerty */ if (strcmp("en-us-qwerty", argv[IDX_SERVER_LAYOUT]) == 0) chosen_keymap = &guac_rdp_keymap_en_us; /* German Qwertz */ else if (strcmp("de-de-qwertz", argv[IDX_SERVER_LAYOUT]) == 0) chosen_keymap = &guac_rdp_keymap_de_de; /* French Azerty */ else if (strcmp("fr-fr-azerty", argv[IDX_SERVER_LAYOUT]) == 0) chosen_keymap = &guac_rdp_keymap_fr_fr; /* Failsafe (Unicode) keymap */ else if (strcmp("failsafe", argv[IDX_SERVER_LAYOUT]) == 0) chosen_keymap = &guac_rdp_keymap_failsafe; /* If keymap unknown, resort to failsafe */ else { guac_client_log_error(client, "Unknown layout \"%s\". Using the failsafe layout instead.", argv[IDX_SERVER_LAYOUT]); chosen_keymap = &guac_rdp_keymap_failsafe; } } /* If no keymap requested, assume US */ else chosen_keymap = &guac_rdp_keymap_en_us; /* Load keymap into client */ __guac_rdp_client_load_keymap(client, chosen_keymap); /* Set server-side keymap */ settings->kbd_layout = chosen_keymap->freerdp_keyboard_layout; /* Connect to RDP server */ if (!freerdp_connect(rdp_inst)) { guac_protocol_send_error(client->socket, "Error connecting to RDP server"); guac_socket_flush(client->socket); guac_error = GUAC_STATUS_BAD_STATE; guac_error_message = "Error connecting to RDP server"; return 1; } /* Send connection name */ guac_protocol_send_name(client->socket, settings->window_title); /* Send size */ guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, settings->width, settings->height); /* Create glyph surfaces */ guac_client_data->opaque_glyph_surface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, settings->width, settings->height); guac_client_data->trans_glyph_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, settings->width, settings->height); /* Set default pointer */ guac_rdp_set_default_pointer(client); /* Success */ return 0; }
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { freerdp* instance; thread_data* data; WSADATA wsa_data; WNDCLASSEX wnd_cls; if (NULL == getenv("HOME")) { char home[MAX_PATH * 2] = "HOME="; strcat(home, getenv("HOMEDRIVE")); strcat(home, getenv("HOMEPATH")); _putenv(home); } if (WSAStartup(0x101, &wsa_data) != 0) return 1; g_done_event = CreateEvent(0, 1, 0, 0); #if defined(WITH_DEBUG) || defined(_DEBUG) wf_create_console(); #endif g_default_cursor = LoadCursor(NULL, IDC_ARROW); wnd_cls.cbSize = sizeof(WNDCLASSEX); wnd_cls.style = CS_HREDRAW | CS_VREDRAW; wnd_cls.lpfnWndProc = wf_event_proc; wnd_cls.cbClsExtra = 0; wnd_cls.cbWndExtra = 0; wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd_cls.hCursor = g_default_cursor; wnd_cls.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wnd_cls.lpszMenuName = NULL; wnd_cls.lpszClassName = g_wnd_class_name; wnd_cls.hInstance = hInstance; wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wnd_cls); g_hInstance = hInstance; freerdp_channels_global_init(); instance = freerdp_new(); instance->PreConnect = wf_pre_connect; instance->PostConnect = wf_post_connect; instance->VerifyCertificate = wf_verify_certificate; instance->ReceiveChannelData = wf_receive_channel_data; instance->context_size = sizeof(wfContext); instance->ContextNew = wf_context_new; instance->ContextFree = wf_context_free; freerdp_context_new(instance); instance->context->argc = __argc; instance->context->argv = __argv; if (!CreateThread(NULL, 0, kbd_thread_func, NULL, 0, NULL)) printf("error creating keyboard handler thread"); //while (1) { int arg_parse_result; data = (thread_data*) xzalloc(sizeof(thread_data)); data->instance = instance; arg_parse_result = freerdp_parse_args(instance->settings, __argc, __argv, wf_process_plugin_args, instance->context->channels, wf_process_client_args, NULL); if (arg_parse_result < 0) { if (arg_parse_result == FREERDP_ARGS_PARSE_FAILURE) printf("failed to parse arguments.\n"); #ifdef _DEBUG system("pause"); #endif exit(-1); } if (CreateThread(NULL, 0, thread_func, data, 0, NULL) != 0) g_thread_count++; } if (g_thread_count > 0) WaitForSingleObject(g_done_event, INFINITE); else MessageBox(GetConsoleWindow(), L"Failed to start wfreerdp.\n\nPlease check the debug output.", L"FreeRDP Error", MB_ICONSTOP); WSACleanup(); #ifdef _DEBUG system("pause"); #endif return 0; }
int initModule(sLogin* psLogin, _MODULE_DATA *_psSessionData) { enum MODULE_STATE nState = MSTATE_NEW; sCredentialSet *psCredSet = NULL; freerdp* instance; /* Retrieve next available credential set to test */ psCredSet = malloc( sizeof(sCredentialSet) ); memset(psCredSet, 0, sizeof(sCredentialSet)); if (getNextCredSet(psLogin, psCredSet) == FAILURE) { writeError(ERR_ERROR, "[%s] Error retrieving next credential set to test.", MODULE_NAME); nState = MSTATE_COMPLETE; } else if (psCredSet->psUser) { writeError(ERR_DEBUG_MODULE, "[%s] module started for host: %s user: %s", MODULE_NAME, psLogin->psServer->pHostIP, psCredSet->psUser->pUser); } else { writeError(ERR_DEBUG_MODULE, "[%s] module started for host: %s - no more available users to test.", MODULE_NAME, psLogin->psServer->pHostIP); nState = MSTATE_COMPLETE; } while (nState != MSTATE_COMPLETE) { switch (nState) { case MSTATE_NEW: #ifdef HAVE_LIBFREERDP12 initWLog(); #else freerdp_channels_global_init(); #endif instance = freerdp_new(); instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; instance->ReceiveChannelData = tf_receive_channel_data; instance->ContextNew = (pContextNew)tf_context_new; instance->ContextFree = tf_context_free; freerdp_context_new(instance); #ifdef HAVE_LIBFREERDP10 instance->settings->ignore_certificate = TRUE; instance->settings->authentication_only = TRUE; instance->settings->hostname = psLogin->psServer->pHostIP; #else instance->settings->IgnoreCertificate = TRUE; instance->settings->AuthenticationOnly = TRUE; instance->settings->ServerHostname = psLogin->psServer->pHostIP; #endif if (psLogin->psServer->psAudit->iPortOverride > 0) #ifdef HAVE_LIBFREERDP10 instance->settings->port = psLogin->psServer->psAudit->iPortOverride; #else instance->settings->ServerPort = psLogin->psServer->psAudit->iPortOverride; #endif else #ifdef HAVE_LIBFREERDP10 instance->settings->port = PORT_RDP; #else instance->settings->ServerPort = PORT_RDP; #endif writeError(ERR_DEBUG_MODULE, "Id: %d initialized FreeRDP instance.", psLogin->iId); nState = MSTATE_RUNNING; break; case MSTATE_RUNNING: nState = tryLogin(_psSessionData, &psLogin, instance, psCredSet->psUser->pUser, psCredSet->pPass); if (getNextCredSet(psLogin, psCredSet) == FAILURE) { writeError(ERR_ERROR, "[%s] Error retrieving next credential set to test.", MODULE_NAME); nState = MSTATE_EXITING; } else { if (psCredSet->iStatus == CREDENTIAL_DONE) { writeError(ERR_DEBUG_MODULE, "[%s] No more available credential sets to test.", MODULE_NAME); nState = MSTATE_EXITING; } else if (psCredSet->iStatus == CREDENTIAL_NEW_USER) { writeError(ERR_DEBUG_MODULE, "[%s] Starting testing for new user: %s.", MODULE_NAME, psCredSet->psUser->pUser); nState = MSTATE_NEW; } else writeError(ERR_DEBUG_MODULE, "[%s] Next credential set - user: %s password: %s", MODULE_NAME, psCredSet->psUser->pUser, psCredSet->pPass); } break; case MSTATE_EXITING: #ifdef HAVE_LIBFREERDP12 freerdp_free(instance); #else freerdp_channels_global_uninit(); #endif nState = MSTATE_COMPLETE; break; default: writeError(ERR_CRITICAL, "Unknown %s module state %d", MODULE_NAME, nState); #ifdef HAVE_LIBFREERDP12 freerdp_free(instance); #else freerdp_channels_global_uninit(); #endif psLogin->iResult = LOGIN_RESULT_UNKNOWN; return FAILURE; } }