diff --git a/.gitignore b/.gitignore index 272f7b98b..415c5441b 100755 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ Release-* *.vcxproj.* *.vcproj *.vcproj.* +*.aps *.sdf *.sln *.suo diff --git a/CMakeLists.txt b/CMakeLists.txt index 70ed8455c..a8cb7701b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,24 +310,34 @@ if(ANDROID) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_DEBUG} -gdwarf-3") endif() set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -llog") - if (NOT FREERDP_ANDROID_EXTERNAL_SSL_PATH) - if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/openssl") - set(FREERDP_ANDROID_EXTERNAL_SSL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/openssl") + + if (NOT FREERDP_EXTERNAL_JPEG_PATH) + if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/jpeg8d") + set(FREERDP_EXTERNAL_JPEG_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/jpeg8d") else() - message(STATUS "FREERDP_ANDROID_EXTERNAL_SSL_PATH not set! - Needs to be set if openssl is not found in the android NDK (which usually isn't)") + message(STATUS "FREERDP_EXTERNAL_SSL_PATH not set! - Needs to be set if openssl is not found in the android NDK (which usually isn't)") + endif() + endif() + if (NOT FREERDP_EXTERNAL_SSL_PATH) + if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/openssl") + set(FREERDP_EXTERNAL_SSL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/openssl") + else() + message(STATUS "FREERDP_EXTERNAL_SSL_PATH not set! - Needs to be set if openssl is not found in the android NDK (which usually isn't)") endif() if(WITH_GPROF) - if (NOT FREERDP_ANDROID_EXTERNAL_PROFILER_PATH) + if (NOT FREERDP_EXTERNAL_PROFILER_PATH) if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/android-ndk-profiler") - set(FREERDP_ANDROID_EXTERNAL_PROFILER_PATH + set(FREERDP_EXTERNAL_PROFILER_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/android-ndk-profiler") else() - message(STATUS "FREERDP_ANDROID_EXTERNAL_PROFILER_PATH not set!") + message(STATUS "FREERDP_EXTERNAL_PROFILER_PATH not set!") endif() endif() endif() endif() - set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_ANDROID_EXTERNAL_SSL_PATH}) +set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_EXTERNAL_SSL_PATH} ${FREERDP_EXTERNAL_JPEG_PATH}) +set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_EXTERNAL_PROFILER_PATH}) + set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/client/Android/FreeRDPCore/jni/${ANDROID_ABI}) CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/scripts/regenerate_jni_headers.sh.cmake ${CMAKE_BINARY_DIR}/scripts/regenerate_jni_headers.sh @ONLY) @@ -349,6 +359,12 @@ if(NOT WIN32) list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) endif() +if(WITH_VALGRIND_MEMCHECK) + check_include_files(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) +else() + unset(HAVE_VALGRIND_MEMCHECK_H CACHE) +endif() + if(UNIX OR CYGWIN) check_include_files(sys/eventfd.h HAVE_AIO_H) check_include_files(sys/eventfd.h HAVE_EVENTFD_H) @@ -525,8 +541,8 @@ if(ANDROID) if(WITH_GPROF) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") set(PROFILER_LIBRARIES - "${FREERDP_ANDROID_EXTERNAL_PROFILER_PATH}/obj/local/${ANDROID_ABI}/libandroid-ndk-profiler.a") - include_directories("${FREERDP_ANDROID_EXTERNAL_PROFILER_PATH}") + "${FREERDP_EXTERNAL_PROFILER_PATH}/obj/local/${ANDROID_ABI}/libandroid-ndk-profiler.a") + include_directories("${FREERDP_EXTERNAL_PROFILER_PATH}") endif() endif() diff --git a/ci/cmake-preloads/config-android.txt b/ci/cmake-preloads/config-android.txt index 7e7e5048b..5f5e368bc 100644 --- a/ci/cmake-preloads/config-android.txt +++ b/ci/cmake-preloads/config-android.txt @@ -1,6 +1,6 @@ message("PRELOADING android cache") set(CMAKE_TOOLCHAIN_FILE "cmake/AndroidToolchain.cmake" CACHE PATH "ToolChain file") -set(FREERDP_ANDROID_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl") +set(FREERDP_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl") # ANDROID_NDK and ANDROID_SDK must be set as environment variable #set(ANDROID_NDK $ENV{ANDROID_SDK} CACHE PATH "Android NDK") #set(ANDROID_SDK "${ANDROID_NDK}" CACHE PATH "android SDK") diff --git a/client/Windows/wf_floatbar.c b/client/Windows/wf_floatbar.c index 87b161b41..a6e960166 100644 --- a/client/Windows/wf_floatbar.c +++ b/client/Windows/wf_floatbar.c @@ -192,9 +192,6 @@ static int floatbar_paint(FloatBar* floatbar, HDC hdc) { int i; - if (!floatbar->wfc->fullscreen) - return -1; - /* paint background */ SelectObject(floatbar->hdcmem, floatbar->background); StretchBlt(hdc, 0, 0, BACKGROUND_W, BACKGROUND_H, floatbar->hdcmem, 0, 0, BACKGROUND_W, BACKGROUND_H, SRCCOPY); @@ -421,12 +418,14 @@ static FloatBar* floatbar_create(wfContext* wfc) int floatbar_hide(FloatBar* floatbar) { + KillTimer(floatbar->hwnd, TIMER_HIDE); MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->height, floatbar->width, floatbar->height, TRUE); return 0; } int floatbar_show(FloatBar* floatbar) { + SetTimer(floatbar->hwnd, TIMER_HIDE, 3000, NULL); MoveWindow(floatbar->hwnd, floatbar->rect.left, floatbar->rect.top, floatbar->width, floatbar->height, TRUE); return 0; } diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 2a7daedc0..1c87072c4 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -481,7 +481,7 @@ void wf_gdi_line_to(wfContext* wfc, LINE_TO_ORDER* line_to) int x, y, w, h; UINT32 pen_color; - pen_color = freerdp_color_convert_bgr(line_to->penColor, wfc->srcBpp, wfc->dstBpp, wfc->clrconv); + pen_color = freerdp_color_convert_var_bgr(line_to->penColor, wfc->srcBpp, wfc->dstBpp, wfc->clrconv); pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color); @@ -512,7 +512,7 @@ void wf_gdi_polyline(wfContext* wfc, POLYLINE_ORDER* polyline) HPEN org_hpen; UINT32 pen_color; - pen_color = freerdp_color_convert_bgr(polyline->penColor, wfc->srcBpp, wfc->dstBpp, wfc->clrconv); + pen_color = freerdp_color_convert_var_bgr(polyline->penColor, wfc->srcBpp, wfc->dstBpp, wfc->clrconv); hpen = CreatePen(0, 1, pen_color); org_rop2 = wf_set_rop2(wfc->drawing->hdc, polyline->bRop2); diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_interface.c index 2e5c19be9..7efbac346 100644 --- a/client/Windows/wf_interface.c +++ b/client/Windows/wf_interface.c @@ -65,6 +65,8 @@ int wf_create_console(void) return 1; freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + fprintf(stderr, "Debug console created.\n"); return 0; @@ -619,6 +621,96 @@ static BOOL wf_auto_reconnect(freerdp* instance) return FALSE; } +void* wf_input_thread(void* arg) +{ + int status; + wMessage message; + wMessageQueue* queue; + freerdp* instance = (freerdp*) arg; + + assert( NULL != instance); + + status = 1; + queue = freerdp_get_message_queue(instance, + FREERDP_INPUT_MESSAGE_QUEUE); + + while (MessageQueue_Wait(queue)) + { + while (MessageQueue_Peek(queue, &message, TRUE)) + { + status = freerdp_message_queue_process_message(instance, + FREERDP_INPUT_MESSAGE_QUEUE, &message); + + if (!status) + break; + } + + if (!status) + break; + } + + ExitThread(0); + + return NULL; +} + +void* wf_update_thread(void* arg) +{ + int status; + wMessage message; + wMessageQueue* queue; + freerdp* instance = (freerdp*) arg; + + assert( NULL != instance); + + status = 1; + queue = freerdp_get_message_queue(instance, + FREERDP_UPDATE_MESSAGE_QUEUE); + + while (MessageQueue_Wait(queue)) + { + while (MessageQueue_Peek(queue, &message, TRUE)) + { + status = freerdp_message_queue_process_message(instance, + FREERDP_UPDATE_MESSAGE_QUEUE, &message); + + if (!status) + break; + } + + if (!status) + break; + } + + ExitThread(0); + + return NULL; +} + +void* wf_channels_thread(void* arg) +{ + int status; + HANDLE event; + rdpChannels* channels; + freerdp* instance = (freerdp*) arg; + assert(NULL != instance); + + channels = instance->context->channels; + event = freerdp_channels_get_event_handle(instance); + + while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) + { + status = freerdp_channels_process_pending_messages(instance); + if (!status) + break; + + wf_process_channel_event(channels, instance); + } + + ExitThread(0); + return NULL; +} + DWORD WINAPI wf_client_thread(LPVOID lpParam) { MSG msg; @@ -636,6 +728,15 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) wfContext* wfc; freerdp* instance; rdpChannels* channels; + rdpSettings* settings; + + BOOL async_update; + BOOL async_input; + BOOL async_channels; + BOOL async_transport; + HANDLE update_thread; + HANDLE input_thread; + HANDLE channels_thread; instance = (freerdp*) lpParam; assert(NULL != instance); @@ -650,28 +751,59 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) return 0; channels = instance->context->channels; + settings = instance->context->settings; + + async_update = settings->AsyncUpdate; + async_input = settings->AsyncInput; + async_channels = settings->AsyncChannels; + async_transport = settings->AsyncTransport; + + if (async_update) + { + update_thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) wf_update_thread, + instance, 0, NULL); + } + + if (async_input) + { + input_thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) wf_input_thread, + instance, 0, NULL); + } + + if (async_channels) + { + channels_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) wf_channels_thread, instance, 0, NULL); + } while (1) { rcount = 0; wcount = 0; - if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) + if (!async_transport) { - fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); - break; + if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) + { + fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); + break; + } } if (wf_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get wfreerdp file descriptor\n"); break; } - if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) - { - fprintf(stderr, "Failed to get channel manager file descriptor\n"); - break; - } + if (!async_channels) + { + if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) + { + fprintf(stderr, "Failed to get channel manager file descriptor\n"); + break; + } + } fds_count = 0; /* setup read fds */ for (index = 0; index < rcount; index++) @@ -687,7 +819,7 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) if (fds_count == 0) { fprintf(stderr, "wfreerdp_run: fds_count is zero\n"); - break; + //break; } /* do the wait */ @@ -697,13 +829,16 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) break; } - if (freerdp_check_fds(instance) != TRUE) + if (!async_transport) { - if (wf_auto_reconnect(instance)) - continue; + if (freerdp_check_fds(instance) != TRUE) + { + if (wf_auto_reconnect(instance)) + continue; - fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); - break; + fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); + break; + } } if (freerdp_shall_disconnect(instance)) { @@ -714,12 +849,17 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) fprintf(stderr, "Failed to check wfreerdp file descriptor\n"); break; } - if (freerdp_channels_check_fds(channels, instance) != TRUE) + + if (!async_channels) { - fprintf(stderr, "Failed to check channel manager file descriptor\n"); - break; + if (freerdp_channels_check_fds(channels, instance) != TRUE) + { + fprintf(stderr, "Failed to check channel manager file descriptor\n"); + break; + } + + wf_process_channel_event(channels, instance); } - wf_process_channel_event(channels, instance); quit_msg = FALSE; @@ -766,6 +906,35 @@ DWORD WINAPI wf_client_thread(LPVOID lpParam) /* cleanup */ freerdp_channels_close(channels, instance); + + if (async_update) + { + wMessageQueue* update_queue; + + update_queue = freerdp_get_message_queue(instance, + FREERDP_UPDATE_MESSAGE_QUEUE); + MessageQueue_PostQuit(update_queue, 0); + WaitForSingleObject(update_thread, INFINITE); + CloseHandle(update_thread); + } + + if (async_input) + { + wMessageQueue* input_queue; + + input_queue = freerdp_get_message_queue(instance, + FREERDP_INPUT_MESSAGE_QUEUE); + MessageQueue_PostQuit(input_queue, 0); + WaitForSingleObject(input_thread, INFINITE); + CloseHandle(input_thread); + } + + if (async_channels) + { + WaitForSingleObject(channels_thread, INFINITE); + CloseHandle(channels_thread); + } + freerdp_disconnect(instance); printf("Main thread exited.\n"); diff --git a/client/Windows/wfreerdp.aps b/client/Windows/wfreerdp.aps deleted file mode 100644 index 1edfc0fc3..000000000 Binary files a/client/Windows/wfreerdp.aps and /dev/null differ diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 109db3138..5e633c4e8 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -297,7 +297,6 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p if (count < 3) return -1; - settings->RedirectDrives = TRUE; settings->DeviceRedirection = TRUE; drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE)); @@ -1772,8 +1771,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { BYTE *base64; int length; - crypto_base64_decode((BYTE *) (arg->Value), - (int) strlen(arg->Value), &base64, &length); + crypto_base64_decode((const char *) (arg->Value), (int) strlen(arg->Value), + &base64, &length); if ((base64 != NULL) && (length == sizeof(ARC_SC_PRIVATE_PACKET))) { memcpy(settings->ServerAutoReconnectCookie, base64, length); diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 915d114d4..00ce2edb1 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -44,6 +44,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_COMPILER_IS_CLANG 1) endif() +if(NOT WIN32) + option(WITH_VALGRIND_MEMCHECK "Compile with valgrind helpers." OFF) +endif() + if(MSVC) option(WITH_NATIVE_SSPI "Use native SSPI modules" ON) option(WITH_WINMM "Use Windows Multimedia" ON) diff --git a/config.h.in b/config.h.in index aed1f6f09..043dae23d 100755 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,7 @@ #cmakedefine HAVE_TM_GMTOFF #cmakedefine HAVE_AIO_H #cmakedefine HAVE_PTHREAD_GNU_EXT +#cmakedefine HAVE_VALGRIND_MEMCHECK_H /* Options */ diff --git a/docs/README.android b/docs/README.android index 6896f8d89..7b0bf4fe2 100644 --- a/docs/README.android +++ b/docs/README.android @@ -31,10 +31,12 @@ Multiple source versions and builds of static openssl libraries are floating aro At the time of writing we have tested and used: https://github.com/bmiklautz/Android-external-openssl-ndk-static https://github.com/akallabeth/openssl-android -However, any other static build should work as well. -To build openssl: +For jpeg support https://github.com/akallabeth/jpeg8d has been tested and used. +However, any other static builds should work as well. +Build openssl and jpeg +====================== Set up ANDROID_NDK and ANDROID_SDK to the absolute paths on your machine. From the project root folder run './scripts/android_setup_build_env.sh' This will set up openssl and gprof helper libraries as required for FreeRDP. @@ -47,12 +49,13 @@ Integrated build ---------------- Run the following commands in the top level freerdp directory. Don't -forget to set ANDROID_NDK, ANDROID_SDK and FREERDP_ANDROID_EXTERNAL_SSL_PATH +forget to set ANDROID_NDK, ANDROID_SDK and FREERDP_EXTERNAL_SSL_PATH to the absolut paths on your machine: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/AndroidToolchain.cmake \ -DANDROID_NDK="_your_ndk_path_here_" \ --DFREERDP_ANDROID_EXTERNAL_SSL_PATH="_your_ssl_build_root_path_" \ +-DFREERDP_EXTERNAL_SSL_PATH="_your_ssl_build_root_path_" \ +-DFREERDP_EXTERNAL_JPEG_PATH="_your_jpeg_build_root_path_" \ -DANDROID_SDK="_your_sdk_path_here_" \ -DCMAKE_BUILD_TYPE=Debug make @@ -62,12 +65,13 @@ After that you should have a client/Android/bin/aFreeRDP-debug.apk. Manual ant builds ----------------- First run cmake to prepare the build and build JNI. -Don't forget to set ANDROID_NDK, ANDROID_SDK and FREERDP_ANDROID_EXTERNAL_SSL_PATH +Don't forget to set ANDROID_NDK, ANDROID_SDK and FREERDP_EXTERNAL_SSL_PATH to the absolut paths on your machine: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/AndroidToolchain.cmake \ -DANDROID_NDK="_your_ndk_path_here_" \ --DFREERDP_ANDROID_EXTERNAL_SSL_PATH="_your_ssl_build_root_path_" \ +-DFREERDP_EXTERNAL_SSL_PATH="_your_ssl_build_root_path_" \ +-DFREERDP_EXTERNAL_JPEG_PATH="_your_jpeg_build_root_path_" \ -DANDROID_SDK="_your_sdk_path_here_" -DANDROID_BUILD_JAVA=OFF \ -DCMAKE_BUILD_TYPE=Debug make @@ -85,7 +89,7 @@ the eclipse marketplace). cmake -DCMAKE_TOOLCHAIN_FILE=cmake/AndroidToolchain.cmake \ -DANDROID_NDK="_your_ndk_path_here_" \ --DFREERDP_ANDROID_EXTERNAL_SSL_PATH="_your_ssl_build_root_path_" \ +-DFREERDP_EXTERNAL_SSL_PATH="_your_ssl_build_root_path_" \ -DCMAKE_BUILD_TYPE=Debug -DANDROID_BUILD_JAVA=OFF make @@ -124,9 +128,12 @@ ANDROID_NDK (used from toolchain file) ANDROID_ABI (used from toolchain file) * Android ABI to build for (default is armeabi-v7a) -FREERDP_ANDROID_EXTERNAL_SSL_PATH (used by FindOpenSSL) +FREERDP_EXTERNAL_SSL_PATH (used by FindOpenSSL) * absolut root path to the prebuild static openssl libraries +FREERDP_EXTERNAL_JPEG_PATH (used by FindJPEG) +* absolute root path to the prebuild static jpeg libraries + WITH_DEBUG_ANDROID_JNI - enable debugging for JNI diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index a022dde85..e642debff 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -144,6 +144,6 @@ FREERDP_API void crypto_reverse(BYTE* data, int length); FREERDP_API void crypto_nonce(BYTE* nonce, int size); FREERDP_API char* crypto_base64_encode(const BYTE* data, int length); -FREERDP_API void crypto_base64_decode(const BYTE* enc_data, int length, BYTE** dec_data, int* res_length); +FREERDP_API void crypto_base64_decode(const char* enc_data, int length, BYTE** dec_data, int* res_length); #endif /* FREERDP_CRYPTO_H */ diff --git a/libfreerdp/codec/CMakeLists.txt b/libfreerdp/codec/CMakeLists.txt index f6e392f82..f0ba7f746 100644 --- a/libfreerdp/codec/CMakeLists.txt +++ b/libfreerdp/codec/CMakeLists.txt @@ -80,7 +80,8 @@ if(WITH_NEON) endif() if(WITH_JPEG) - set(FREERDP_JPEG_LIBS jpeg) + include_directories(${JPEG_INCLUDE_DIR}) + set(FREERDP_JPEG_LIBS ${JPEG_LIBRARIES}) endif() add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index 76e76d603..270dafbcf 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -106,7 +106,7 @@ int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc) goto out; ntlm_token_data = NULL; - crypto_base64_decode((BYTE*) token64, strlen(token64), &ntlm_token_data, &ntlm_token_length); + crypto_base64_decode(token64, strlen(token64), &ntlm_token_data, &ntlm_token_length); } ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; @@ -238,7 +238,7 @@ int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc) if (http_response && ListDictionary_Contains(http_response->Authenticates, "NTLM")) { char *token64 = ListDictionary_GetItemValue(http_response->Authenticates, "NTLM"); - crypto_base64_decode((BYTE*) token64, strlen(token64), &ntlm_token_data, &ntlm_token_length); + crypto_base64_decode(token64, strlen(token64), &ntlm_token_data, &ntlm_token_length); } ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; diff --git a/libfreerdp/core/gateway/rpc_bind.c b/libfreerdp/core/gateway/rpc_bind.c index 3360ec0b3..cf02a802a 100644 --- a/libfreerdp/core/gateway/rpc_bind.c +++ b/libfreerdp/core/gateway/rpc_bind.c @@ -300,27 +300,25 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc) auth_3_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX; auth_3_pdu->call_id = 2; - offset = 20; - auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag; auth_3_pdu->max_recv_frag = rpc->max_recv_frag; - offset += 4; + offset = 20; auth_3_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4); auth_3_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT; auth_3_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; auth_3_pdu->auth_verifier.auth_reserved = 0x00; auth_3_pdu->auth_verifier.auth_context_id = 0x00000000; + offset += (8 + auth_3_pdu->auth_length); - auth_3_pdu->frag_length = 20 + 4 + - auth_3_pdu->auth_verifier.auth_pad_length + auth_3_pdu->auth_length + 8; + auth_3_pdu->frag_length = offset; buffer = (BYTE*) malloc(auth_3_pdu->frag_length); - CopyMemory(buffer, auth_3_pdu, 24); + CopyMemory(buffer, auth_3_pdu, 20); - offset = 24; + offset = 20; rpc_offset_pad(&offset, auth_3_pdu->auth_verifier.auth_pad_length); CopyMemory(&buffer[offset], &auth_3_pdu->auth_verifier.auth_type, 8); diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 80e531ec4..ab2753a03 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -704,9 +704,19 @@ BOOL nego_send_negotiation_request(rdpNego* nego) if (nego->RoutingToken) { Stream_Write(s, nego->RoutingToken, nego->RoutingTokenLength); - Stream_Write_UINT8(s, 0x0D); /* CR */ - Stream_Write_UINT8(s, 0x0A); /* LF */ - length += nego->RoutingTokenLength + 2; + /* Ensure Routing Token is correctly terminated - may already be present in string */ + if (nego->RoutingTokenLength>2 && (nego->RoutingToken[nego->RoutingTokenLength-2]==0x0D && nego->RoutingToken[nego->RoutingTokenLength-1]==0x0A)) + { + DEBUG_NEGO("Routing token looks correctly terminated - use verbatim"); + length +=nego->RoutingTokenLength; + } + else + { + DEBUG_NEGO("Adding terminating CRLF to routing token"); + Stream_Write_UINT8(s, 0x0D); /* CR */ + Stream_Write_UINT8(s, 0x0A); /* LF */ + length += nego->RoutingTokenLength + 2; + } } else if (nego->cookie) { diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index d75091266..15c417616 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -40,6 +40,12 @@ #include #include +#ifdef __FreeBSD__ +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif +#endif + #ifdef __APPLE__ #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP diff --git a/libfreerdp/crypto/CMakeLists.txt b/libfreerdp/crypto/CMakeLists.txt index e0f93fc6e..e33200bec 100644 --- a/libfreerdp/crypto/CMakeLists.txt +++ b/libfreerdp/crypto/CMakeLists.txt @@ -71,3 +71,7 @@ else() endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/libfreerdp/crypto/base64.c b/libfreerdp/crypto/base64.c index 3f2b6170f..d492e8981 100644 --- a/libfreerdp/crypto/base64.c +++ b/libfreerdp/crypto/base64.c @@ -34,38 +34,56 @@ char* crypto_base64_encode(const BYTE* data, int length) char* p; char* ret; int i = 0; + int blocks; q = data; p = ret = (char*) malloc((length + 3) * 4 / 3 + 1); if (!p) return NULL; - while (i < length) + /* b1, b2, b3 are input bytes + * + * 0 1 2 + * 012345678901234567890123 + * | b1 | b2 | b3 | + * + * [ c1 ] [ c3 ] + * [ c2 ] [ c4 ] + * + * c1, c2, c3, c4 are output chars in base64 + */ + + /* first treat complete blocks */ + blocks = length - (length % 3); + for (i = 0; i < blocks; i += 3, q += 3) { - c = q[i++]; - - c <<= 8; - if (i < length) - c += q[i]; - i++; - - c <<= 8; - if (i < length) - c += q[i]; - i++; + c = (q[0] << 16) + (q[1] << 8) + q[2]; *p++ = base64[(c & 0x00FC0000) >> 18]; *p++ = base64[(c & 0x0003F000) >> 12]; + *p++ = base64[(c & 0x00000FC0) >> 6]; + *p++ = base64[c & 0x0000003F]; + } - if (i > length + 1) - *p++ = '='; - else - *p++ = base64[(c & 0x00000FC0) >> 6]; - - if (i > length) - *p++ = '='; - else - *p++ = base64[c & 0x0000003F]; + /* then remainder */ + switch (length % 3) + { + case 0: + break; + case 1: + c = (q[0] << 16); + *p++ = base64[(c & 0x00FC0000) >> 18]; + *p++ = base64[(c & 0x0003F000) >> 12]; + *p++ = '='; + *p++ = '='; + break; + case 2: + c = (q[0] << 16) + (q[1] << 8); + *p++ = base64[(c & 0x00FC0000) >> 18]; + *p++ = base64[(c & 0x0003F000) >> 12]; + *p++ = base64[(c & 0x00000FC0) >> 6]; + *p++ = '='; + break; } *p = 0; @@ -96,55 +114,82 @@ static int base64_decode_char(char c) return -1; } -static void* base64_decode(const BYTE* s, int length, int* data_len) +static void* base64_decode(const char* s, int length, int* data_len) { - char* p; int n[4]; BYTE* q; BYTE* data; + int nBlocks, i, outputLen; if (length % 4) return NULL; - n[0] = n[1] = n[2] = n[3] = 0; q = data = (BYTE*) malloc(length / 4 * 3); - for (p = (char*) s; *p; ) + /* first treat complete blocks */ + nBlocks = (length / 4); + outputLen = 0; + + for (i = 0; i < nBlocks-1; i++, q += 3) { - n[0] = base64_decode_char(*p++); - n[1] = base64_decode_char(*p++); - n[2] = base64_decode_char(*p++); - n[3] = base64_decode_char(*p++); + n[0] = base64_decode_char(*s++); + n[1] = base64_decode_char(*s++); + n[2] = base64_decode_char(*s++); + n[3] = base64_decode_char(*s++); - if ((n[0] == -1) || (n[1] == -1)) - { - free(data); - return NULL; - } - - if ((n[2] == -1) && (n[3] != -1)) - { - free(data); - return NULL; - } + if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1)) + goto out_free; q[0] = (n[0] << 2) + (n[1] >> 4); - - if (n[2] != -1) - q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); - - if (n[3] != -1) - q[2] = ((n[2] & 3) << 6) + n[3]; - - q += 3; + q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); + q[2] = ((n[2] & 3) << 6) + n[3]; + outputLen += 3; } - *data_len = q - data - (n[2] == -1) - (n[3] == -1); + /* treat last block */ + n[0] = base64_decode_char(*s++); + n[1] = base64_decode_char(*s++); + if ((n[0] == -1) || (n[1] == -1)) + goto out_free; + + n[2] = base64_decode_char(*s++); + n[3] = base64_decode_char(*s++); + + q[0] = (n[0] << 2) + (n[1] >> 4); + if (n[2] == -1) + { + /* XX== */ + outputLen += 1; + if (n[3] != -1) + goto out_free; + + q[1] = ((n[1] & 15) << 4); + } + else if (n[3] == -1) + { + /* yyy= */ + outputLen += 2; + q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); + q[2] = ((n[2] & 3) << 6); + } + else + { + /* XXXX */ + outputLen += 3; + q[0] = (n[0] << 2) + (n[1] >> 4); + q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); + q[2] = ((n[2] & 3) << 6) + n[3]; + } + + *data_len = outputLen; return data; +out_free: + free(data); + return NULL; } -void crypto_base64_decode(const BYTE* enc_data, int length, BYTE** dec_data, int* res_length) +void crypto_base64_decode(const char* enc_data, int length, BYTE** dec_data, int* res_length) { *dec_data = base64_decode(enc_data, length, res_length); } diff --git a/libfreerdp/crypto/test/CMakeLists.txt b/libfreerdp/crypto/test/CMakeLists.txt new file mode 100644 index 000000000..4333b010f --- /dev/null +++ b/libfreerdp/crypto/test/CMakeLists.txt @@ -0,0 +1,31 @@ + +set(MODULE_NAME "TestFreeRDPCrypto") +set(MODULE_PREFIX "TEST_FREERDP_CRYPTO") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestBase64.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-crypto) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + +foreach(test ${${MODULE_PREFIX}_TESTS}) + get_filename_component(TestName ${test} NAME_WE) + add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName}) +endforeach() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Test") + diff --git a/libfreerdp/crypto/test/TestBase64.c b/libfreerdp/crypto/test/TestBase64.c new file mode 100644 index 000000000..5c32ea422 --- /dev/null +++ b/libfreerdp/crypto/test/TestBase64.c @@ -0,0 +1,110 @@ +/** + * Copyright © 2014 Thincast Technologies GmbH + * Copyright © 2014 Hardening + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +struct Encode64test { + const char *input; + int len; + const char *output; +}; + +struct Encode64test encodeTests[] = { + {"\x00", 1, "AA=="}, + {"\x00\x00", 2, "AAA="}, + {"\x00\x00\x00", 3, "AAAA"}, + {"0123456", 7, "MDEyMzQ1Ng=="}, + {"90123456", 8, "OTAxMjM0NTY="}, + {"890123456", 9, "ODkwMTIzNDU2"}, + {"7890123456", 10, "Nzg5MDEyMzQ1Ng=="}, + + {NULL, -1, NULL}, /* /!\ last one /!\ */ +}; + + +int TestBase64(int argc, char* argv[]) +{ + int i, testNb = 0; + int outLen; + BYTE *decoded; + + testNb++; + fprintf(stderr, "%d:encode base64...", testNb); + + for (i = 0; encodeTests[i].input; i++) + { + char *encoded = crypto_base64_encode((const BYTE *)encodeTests[i].input, encodeTests[i].len); + + if (strcmp(encodeTests[i].output, encoded)) + { + fprintf(stderr, "ko, error for string %d\n", i); + return -1; + } + + free(encoded); + } + fprintf(stderr, "ok\n"); + + testNb++; + fprintf(stderr, "%d:decode base64...", testNb); + for (i = 0; encodeTests[i].input; i++) + { + crypto_base64_decode(encodeTests[i].output, strlen(encodeTests[i].output), &decoded, &outLen); + + if (!decoded || (outLen != encodeTests[i].len) || memcmp(encodeTests[i].input, decoded, outLen)) + { + fprintf(stderr, "ko, error for string %d\n", i); + return -1; + } + + free(decoded); + } + fprintf(stderr, "ok\n"); + + testNb++; + fprintf(stderr, "%d:decode base64 errors...", testNb); + crypto_base64_decode("000", 3, &decoded, &outLen); + if (decoded) + { + fprintf(stderr, "ko, badly padded string\n"); + return -1; + } + + crypto_base64_decode("0=00", 4, &decoded, &outLen); + if (decoded) + { + fprintf(stderr, "ko, = in a wrong place\n"); + return -1; + } + + crypto_base64_decode("00=0", 4, &decoded, &outLen); + if (decoded) + { + fprintf(stderr, "ko, = in a wrong place\n"); + return -1; + } + fprintf(stderr, "ok\n"); + + + return 0; +} diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 1c12a9459..52c217782 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -31,6 +31,10 @@ #include +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer) { CryptoCert cert; @@ -465,6 +469,10 @@ int tls_read(rdpTls* tls, BYTE* data, int length) } } +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(data, status); +#endif + return status; } diff --git a/libfreerdp/locale/timezone.c b/libfreerdp/locale/timezone.c index 3070f1fa6..b83471a82 100644 --- a/libfreerdp/locale/timezone.c +++ b/libfreerdp/locale/timezone.c @@ -1663,7 +1663,12 @@ void freerdp_time_zone_detect(TIME_ZONE_INFO* clientTimeZone) local_time = localtime(&t); #ifdef HAVE_TM_GMTOFF - clientTimeZone->bias = timezone / 60; + #if defined(__FreeBSD__) + /*not the best solution, but could not get the right tyepcast*/ + clientTimeZone->bias = 0; + #else + clientTimeZone->bias = timezone / 60; + #endif DEBUG_TIMEZONE("tzname[std]: %s, tzname[dst]: %s, timezone: %ld, Daylight: %d", tzname[0], tzname[1], timezone, daylight); #elif defined(sun) if (local_time->tm_isdst > 0) diff --git a/scripts/android_setup_build_env.sh b/scripts/android_setup_build_env.sh index d7f151d32..f60fca422 100755 --- a/scripts/android_setup_build_env.sh +++ b/scripts/android_setup_build_env.sh @@ -6,15 +6,19 @@ # Specifically these are: # - OpenSSL # - Android NDK Profiler +# - Jpeg library # # Usage: # android_setup_build_env.sh -OPENSSL_SCM=https://github.com/akallabeth/openssl-android -NDK_PROFILER_SCM=https://github.com/richq/android-ndk-profiler +OPENSSL_SCM=https://github.com/akallabeth/openssl-android.git +NDK_PROFILER_SCM=https://github.com/richq/android-ndk-profiler.git +JPEG_LIBRARY_SCM=https://github.com/akallabeth/jpeg8d.git SCRIPT_NAME=`basename $0` + if [ $# -ne 1 ]; then + echo "Missing command line argument, current directory as root." ROOT=`pwd` ROOT=$ROOT/external @@ -42,27 +46,30 @@ if [ $RETVAL -ne 0 ]; then echo "Failed to execute git command [$RETVAL]" exit -3 fi - cd $OPENSSL_SRC make clean # The makefile has a bug, which aborts during # first compilation. Rerun make to build the whole lib. make make +make RETVAL=0 # TODO: Check, why 2 is returned. if [ $RETVAL -ne 0 ]; then echo "Failed to execute make command [$RETVAL]" exit -4 fi - # Copy the created library to the default openssl directory, # so that CMake will detect it automatically. SSL_ROOT=`find $OPENSSL_SRC -type d -name "openssl-?.?.*"` +if [ -z "$SSL_ROOT" ]; then + echo "OpenSSL was not build successfully, aborting." + exit -42 +fi +mkdir -p $SSL_ROOT/lib +cp $SSL_ROOT/*.a $SSL_ROOT/lib/ + rm -f $ROOT/openssl ln -s $SSL_ROOT $ROOT/openssl -mkdir -p $ROOT/openssl/obj/local/armeabi/ -cp $ROOT/openssl/libssl.a $ROOT/openssl/obj/local/armeabi/ -cp $ROOT/openssl/libcrypto.a $ROOT/openssl/obj/local/armeabi/ echo "Preparing NDK profiler..." NDK_PROFILER_SRC=$ROOT/android-ndk-profiler @@ -87,5 +94,30 @@ if [ $RETVAL -ne 0 ]; then exit -6 fi +echo "Preparing JPEG library..." +JPEG_LIBRARY_SRC=$ROOT/jpeg8d +if [ -d $JPEG_LIBRARY_SRC ]; then + cd $JPEG_LIBRARY_SRC + git pull + RETVAL=$? +else + git clone $JPEG_LIBRARY_SCM $JPEG_LIBRARY_SRC + RETVAL=$? +fi +if [ $RETVAL -ne 0 ]; then + echo "Failed to execute git command [$RETVAL]" + exit -6 +fi +cd $JPEG_LIBRARY_SRC +ndk-build V=1 APP_ABI=armeabi-v7a clean +ndk-build V=1 APP_ABI=armeabi-v7a +RETVAL=$? +if [ $RETVAL -ne 0 ]; then + echo "Failed to execute ndk-build command [$RETVAL]" + exit -7 +fi +mkdir -p $JPEG_LIBRARY_SRC/lib +cp $JPEG_LIBRARY_SRC/obj/local/armeabi-v7a/*.a $JPEG_LIBRARY_SRC/lib/ + echo "Prepared external libraries, you can now build the application." exit 0 diff --git a/winpr/libwinpr/crt/alignment.c b/winpr/libwinpr/crt/alignment.c index bf01e6ba6..a172cad9c 100644 --- a/winpr/libwinpr/crt/alignment.c +++ b/winpr/libwinpr/crt/alignment.c @@ -31,6 +31,8 @@ #ifdef __APPLE__ #include +#elif __FreeBSD__ +#include #else #include #endif diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 7a4d32a0d..0272415ad 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -124,7 +124,12 @@ static int pthread_timedjoin_np(pthread_t td, void **res, return ETIMEDOUT; } -static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) +#if defined(__FreeBSD__) + /*the only way to get it work is to remove the static*/ + int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) +#else + static int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) +#endif { struct timespec timenow; struct timespec sleepytime; diff --git a/winpr/libwinpr/sysinfo/sysinfo.c b/winpr/libwinpr/sysinfo/sysinfo.c index e93de0bff..4de21f062 100644 --- a/winpr/libwinpr/sysinfo/sysinfo.c +++ b/winpr/libwinpr/sysinfo/sysinfo.c @@ -129,7 +129,11 @@ static DWORD GetNumberOfProcessors() size_t length = sizeof(numCPUs); mib[0] = CTL_HW; - mib[1] = HW_AVAILCPU; + #if defined(__FreeBSD__) + mib[1] = HW_NCPU; + #else + mib[1] = HW_AVAILCPU; + #endif sysctl(mib, 2, &numCPUs, &length, NULL, 0);