diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c2e83ac5..79a465735 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,8 +122,10 @@ if(NOT DEFINED BUILD_SHARED_LIBS) endif() endif() -if(NOT DEFINED EXPORT_ALL_SYMBOLS) - set(EXPORT_ALL_SYMBOLS TRUE) +if(BUILD_TESTING) + set(EXPORT_ALL_SYMBOLS TRUE) +elseif(NOT DEFINED EXPORT_ALL_SYMBOLS) + set(EXPORT_ALL_SYMBOLS FALSE) endif() # BSD @@ -698,17 +700,17 @@ if (TARGET_ARCH MATCHES "sparc") endif() # Path to put FreeRDP data -set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp") +set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp${FREERDP_VERSION_MAJOR}") # Path to put plugins set(FREERDP_LIBRARY_PATH "${CMAKE_INSTALL_LIBDIR}") -set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_LIBDIR}/freerdp") +set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}") set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}") # Path to put extensions -set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp/extensions") +set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}/extensions") # Include directories include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -789,6 +791,10 @@ include_directories("${CMAKE_BINARY_DIR}/rdtk/include") add_subdirectory(rdtk) +if(WAYLAND_FOUND) + add_subdirectory(uwac) +endif() + if(BSD) if(IS_DIRECTORY /usr/local/include) include_directories(/usr/local/include) diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index a3a7b3a02..e49a1cc97 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -522,6 +522,8 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* arg #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 373ae86dc..8601a2de0 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -82,7 +82,7 @@ struct _AUDIN_PLUGIN /* Parsed plugin data */ UINT16 fixed_format; - UINT16 fixed_channel; + UINT16 fixed_channel; UINT32 fixed_rate; char* subsystem; char* device_name; @@ -93,6 +93,8 @@ struct _AUDIN_PLUGIN rdpContext* rdpcontext; }; +static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); + /** * Function description * @@ -639,8 +641,12 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI { PFREERDP_AUDIN_DEVICE_ENTRY entry; FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; UINT error; + if (!audin_process_addin_args(audin, args)) + return CHANNEL_RC_INITIALIZATION_ERROR; + entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0); if (entry == NULL) @@ -660,6 +666,7 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI return error; } + WLog_INFO(TAG, "Loaded %s backend for audin", name); return CHANNEL_RC_OK; } @@ -707,18 +714,19 @@ static COMMAND_LINE_ARGUMENT_A audin_args[] = { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; -static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) +BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; UINT error; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_args, flags, audin, NULL, NULL); + if (status != 0) + return FALSE; arg = audin_args; @@ -771,6 +779,8 @@ static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) #ifdef STATIC_CHANNELS #define DVCPluginEntry audin_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -786,7 +796,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) char *device; }; - UINT error = CHANNEL_RC_OK; + UINT error = CHANNEL_RC_INITIALIZATION_ERROR; ADDIN_ARGV* args; AUDIN_PLUGIN* audin; struct SubsystemEntry entries[] = @@ -837,31 +847,53 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) args = pEntryPoints->GetPluginData(pEntryPoints); audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context; - while (entry && entry->subsystem && !audin->device) + if (args) { - if ((error = audin_set_subsystem(audin, entry->subsystem))) - { - WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %lu!", - entry->subsystem, error); - } - else if ((error = audin_set_device_name(audin, entry->device))) - { - WLog_ERR(TAG, "audin_set_device_name for %s failed with error %lu!", - entry->subsystem, error); - } - else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) + if (!audin_process_addin_args(audin, args)) + goto out; + } + + if (audin->subsystem) + { + if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %lu!", - entry->subsystem, error); + audin->subsystem, error); + goto out; } + } + else + { + while (entry && entry->subsystem && !audin->device) + { + if ((error = audin_set_subsystem(audin, entry->subsystem))) + { + WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %lu!", + entry->subsystem, error); + } + else if ((error = audin_set_device_name(audin, entry->device))) + { + WLog_ERR(TAG, "audin_set_device_name for %s failed with error %lu!", + entry->subsystem, error); + } + else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) + { + WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %lu!", + entry->subsystem, error); + } - entry++; + entry++; + } } if (audin->device == NULL) - { WLog_ERR(TAG, "no sound device."); - } + + error = CHANNEL_RC_OK; + +out: + if (error != CHANNEL_RC_OK) + audin_plugin_terminated((IWTSPlugin*)audin); return error; } diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.c index 38c51f265..4604bcd36 100644 --- a/channels/audin/client/mac/audin_mac.c +++ b/channels/audin/client/mac/audin_mac.c @@ -405,6 +405,8 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 51917e4a3..cd0d3999d 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -218,8 +218,6 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* f switch (format->wFormatTag) { - /* TODO: Deactivated, untested */ -#if 0 case WAVE_FORMAT_PCM: /* PCM */ if (format->cbSize == 0 && (format->nSamplesPerSec <= 48000) && @@ -229,7 +227,6 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* f return TRUE; } break; -#endif /* TODO: Deactivated format, does not work, find out why */ // case WAVE_FORMAT_ADPCM: /* IMA ADPCM */ case WAVE_FORMAT_DVI_ADPCM: @@ -479,6 +476,9 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry \ opensles_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry \ + FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index e79937a37..753298bb2 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -485,6 +485,8 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args) #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index 829e50503..ad2f480fc 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -525,6 +525,8 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 5f7c6d9b8..e59a84ed6 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -393,6 +393,8 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a #ifdef STATIC_CHANNELS #define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index e686a7c29..a7afae579 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -102,16 +102,25 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data formats[index].formatName = NULL; + /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing + * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters + * or 16 Unicode characters)" + * However, both Windows RDSH and mstsc violate this specs as seen in the following + * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] + * These are 16 unicode charaters - *without* terminating null ! + */ + if (asciiNames) { szFormatName = (char*) Stream_Pointer(s); if (szFormatName[0]) { + /* ensure null termination */ formats[index].formatName = (char*) malloc(32 + 1); if (!formats[index].formatName) { - WLog_ERR(TAG, "calloc failed!"); + WLog_ERR(TAG, "malloc failed!"); error = CHANNEL_RC_NO_MEMORY; goto error_out; } @@ -125,8 +134,16 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data if (wszFormatName[0]) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - 16, &(formats[index].formatName), 0, NULL, NULL); + /* ConvertFromUnicode always returns a null-terminated + * string on success, even if the source string isn't. + */ + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert short clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } } } @@ -185,8 +202,13 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data if (formatNameLength) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - -1, &(formats[index].formatName), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert long clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } } Stream_Seek(s, (formatNameLength + 1) * 2); diff --git a/channels/cliprdr/client/module.def b/channels/cliprdr/client/module.def deleted file mode 100644 index 7336368ec..000000000 --- a/channels/cliprdr/client/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "cliprdr" -EXPORTS - VirtualChannelEntry @1 diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 24a34c57f..ed981706f 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -597,8 +597,12 @@ static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* con free(cliprdr->temporaryDirectory); cliprdr->temporaryDirectory = NULL; - ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, - &(cliprdr->temporaryDirectory), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, + &(cliprdr->temporaryDirectory), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert temporary directory name"); + return ERROR_INVALID_DATA; + } length = strlen(cliprdr->temporaryDirectory); @@ -680,12 +684,21 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS formats[index].formatName = NULL; + /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing + * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters + * or 16 Unicode characters)" + * However, both Windows RDSH and mstsc violate this specs as seen in the following + * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] + * These are 16 unicode charaters - *without* terminating null ! + */ + if (asciiNames) { szFormatName = (char*) Stream_Pointer(s); if (szFormatName[0]) { + /* ensure null termination */ formats[index].formatName = (char*) malloc(32 + 1); CopyMemory(formats[index].formatName, szFormatName, 32); formats[index].formatName[32] = '\0'; @@ -697,8 +710,16 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS if (wszFormatName[0]) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - 16, &(formats[index].formatName), 0, NULL, NULL); + /* ConvertFromUnicode always returns a null-terminated + * string on success, even if the source string isn't. + */ + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert short clipboard format name"); + error = ERROR_INVALID_DATA; + goto out; + } } } @@ -757,8 +778,13 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS if (formatNameLength) { - ConvertFromUnicode(CP_UTF8, 0, wszFormatName, - -1, &(formats[index].formatName), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert long clipboard format name"); + error = ERROR_INVALID_DATA; + goto out; + } } Stream_Seek(s, (formatNameLength + 1) * 2); @@ -775,6 +801,7 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS if (error) WLog_ERR(TAG, "ClientFormatList failed with error %lu!", error); +out: for (index = 0; index < formatList.numFormats; index++) { free(formatList.formats[index].formatName); diff --git a/channels/disp/client/disp_main.c b/channels/disp/client/disp_main.c index d70f61964..fb23d8b5e 100644 --- a/channels/disp/client/disp_main.c +++ b/channels/disp/client/disp_main.c @@ -340,6 +340,8 @@ UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, DI #ifdef STATIC_CHANNELS #define DVCPluginEntry disp_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 29111fde8..676dfb960 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -958,8 +958,8 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int c Stream_Write_UINT8(data_out, 0x10 | cbChId); Stream_SetPosition(s, 1); - Stream_Copy(data_out, s, pos - 1); - + Stream_Copy(s, data_out, pos - 1); + if (channel_status == CHANNEL_RC_OK) { WLog_DBG(TAG, "channel created"); diff --git a/channels/drive/client/dirent.h b/channels/drive/client/dirent.h index 9a293daa1..d9efa36a9 100644 --- a/channels/drive/client/dirent.h +++ b/channels/drive/client/dirent.h @@ -286,7 +286,7 @@ static struct dirent *readdir(DIR *dirp) return NULL; } if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) { - /* the very last entry has been processed or an error occured */ + /* the very last entry has been processed or an error occurred */ FindClose (dirp->search_handle); dirp->search_handle = INVALID_HANDLE_VALUE; return NULL; diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index 7aec1c280..f1ad8bfc6 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -7,6 +7,8 @@ * Copyright 2012 Gerald Richter * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +61,8 @@ #ifdef _WIN32 #pragma comment(lib, "Shlwapi.lib") #include +#else +#include #endif #include "drive_file.h" @@ -507,18 +511,23 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN { char* s = NULL; mode_t m; - UINT64 size; + INT64 size; int status; char* fullpath; - struct STAT st; -#if defined(__linux__) && !defined(ANDROID) || defined(sun) - struct timespec tv[2]; -#else - struct timeval tv[2]; -#endif - UINT64 LastWriteTime; + ULARGE_INTEGER liCreationTime; + ULARGE_INTEGER liLastAccessTime; + ULARGE_INTEGER liLastWriteTime; + ULARGE_INTEGER liChangeTime; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + FILETIME* pftCreationTime = NULL; + FILETIME* pftLastAccessTime = NULL; + FILETIME* pftLastWriteTime = NULL; UINT32 FileAttributes; UINT32 FileNameLength; + HANDLE hFd; + LARGE_INTEGER liSize; m = 0; @@ -526,55 +535,73 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN { case FileBasicInformation: /* http://msdn.microsoft.com/en-us/library/cc232094.aspx */ - Stream_Seek_UINT64(input); /* CreationTime */ - Stream_Seek_UINT64(input); /* LastAccessTime */ - Stream_Read_UINT64(input, LastWriteTime); - Stream_Seek_UINT64(input); /* ChangeTime */ + Stream_Read_UINT64(input, liCreationTime.QuadPart); + Stream_Read_UINT64(input, liLastAccessTime.QuadPart); + Stream_Read_UINT64(input, liLastWriteTime.QuadPart); + Stream_Read_UINT64(input, liChangeTime.QuadPart); Stream_Read_UINT32(input, FileAttributes); - if (FSTAT(file->fd, &st) != 0) + if (!PathFileExistsA(file->fullpath)) return FALSE; - - tv[0].tv_sec = st.st_atime; - tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); -#ifndef WIN32 - /* TODO on win32 */ -#ifdef ANDROID - tv[0].tv_usec = 0; - tv[1].tv_usec = 0; - utimes(file->fullpath, tv); -#elif defined (__linux__) || defined (sun) - tv[0].tv_nsec = 0; - tv[1].tv_nsec = 0; - futimens(file->fd, tv); -#else - tv[0].tv_usec = 0; - tv[1].tv_usec = 0; - futimes(file->fd, tv); -#endif - - if (FileAttributes > 0) + hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFd == INVALID_HANDLE_VALUE) { - m = st.st_mode; - if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0) - m |= S_IWUSR; - else - m &= ~S_IWUSR; - if (m != st.st_mode) - fchmod(file->fd, st.st_mode); + WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath); + return FALSE; } -#endif + if (liCreationTime.QuadPart != 0) + { + ftCreationTime.dwHighDateTime = liCreationTime.HighPart; + ftCreationTime.dwLowDateTime = liCreationTime.LowPart; + pftCreationTime = &ftCreationTime; + } + if (liLastAccessTime.QuadPart != 0) + { + ftLastAccessTime.dwHighDateTime = liLastAccessTime.HighPart; + ftLastAccessTime.dwLowDateTime = liLastAccessTime.LowPart; + pftLastAccessTime = &ftLastAccessTime; + } + if (liLastWriteTime.QuadPart != 0) + { + ftLastWriteTime.dwHighDateTime = liLastWriteTime.HighPart; + ftLastWriteTime.dwLowDateTime = liLastWriteTime.LowPart; + pftLastWriteTime = &ftLastWriteTime; + } + if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart) + { + ftLastWriteTime.dwHighDateTime = liChangeTime.HighPart; + ftLastWriteTime.dwLowDateTime = liChangeTime.LowPart; + pftLastWriteTime = &ftLastWriteTime; + } + if (!SetFileTime(hFd, pftCreationTime, pftLastAccessTime, pftLastWriteTime)) + { + WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath); + CloseHandle(hFd); + return FALSE; + } + CloseHandle(hFd); break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ - Stream_Read_UINT64(input, size); -#ifndef _WIN32 - if (ftruncate(file->fd, size) != 0) + Stream_Read_INT64(input, size); + + hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFd == INVALID_HANDLE_VALUE) + { + WLog_ERR(TAG, "Unable to truncate %s to %d", file->fullpath, size); return FALSE; -#endif + } + liSize.QuadPart = size; + if (SetFilePointerEx(hFd, liSize, NULL, FILE_BEGIN) == 0) + { + WLog_ERR(TAG, "Unable to truncate %s to %d", file->fullpath, size); + CloseHandle(hFd); + return FALSE; + } + CloseHandle(hFd); break; case FileDispositionInformation: diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index b5bd14118..d287eb4ee 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -7,6 +7,8 @@ * Copyright 2012 Gerald Richter * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,8 +86,6 @@ typedef UINT32 mode_t; #define FILE_TIME_SYSTEM_TO_RDP(_t) \ (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL) -#define FILE_TIME_RDP_TO_SYSTEM(_t) \ - (((_t) == 0LL || (_t) == (UINT64)(-1LL)) ? 0 : (time_t)((_t) / 10000000LL - EPOCH_DIFF)) #define FILE_ATTR_SYSTEM_TO_RDP(_f, _st) ( \ (S_ISDIR(_st.st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) | \ diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index e2a5a39ab..39ed054b9 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -859,6 +859,8 @@ out_error: #ifdef STATIC_CHANNELS #define DeviceServiceEntry drive_DeviceServiceEntry +#else +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif UINT sys_code_page = 0; diff --git a/channels/drive/client/module.def b/channels/drive/client/module.def deleted file mode 100644 index 82b96df27..000000000 --- a/channels/drive/client/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "drive" -EXPORTS - DeviceServiceEntry @1 diff --git a/channels/drive/client/statvfs.c b/channels/drive/client/statvfs.c index 60722a535..e92a97557 100644 --- a/channels/drive/client/statvfs.c +++ b/channels/drive/client/statvfs.c @@ -3,6 +3,8 @@ * statvfs emulation for Windows * * Copyright 2012 Gerald Richter + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,17 +31,18 @@ int statvfs(const char *path, struct statvfs *buf) { BOOL res; int len; - LPWSTR unicodestr; + LPWSTR unicodestr = NULL; DWORD lpSectorsPerCluster; DWORD lpBytesPerSector; DWORD lpNumberOfFreeClusters; DWORD lpTotalNumberOfClusters; - len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); - unicodestr = (LPWSTR) malloc(len); - MultiByteToWideChar(CP_ACP, 0, path, -1, unicodestr, len); + len = ConvertToUnicode(CP_ACP, 0, path, -1, &unicodestr, 0); + if (len <= 0) + return -1; - res = GetDiskFreeSpace(unicodestr, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters, &lpTotalNumberOfClusters); + res = GetDiskFreeSpaceW(unicodestr, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters, &lpTotalNumberOfClusters); + free(unicodestr); buf->f_bsize = lpBytesPerSector; /* file system block size */ buf->f_frsize = 0; /* fragment size */ diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c index fe2d3631c..ba50aaaad 100644 --- a/channels/echo/client/echo_main.c +++ b/channels/echo/client/echo_main.c @@ -162,6 +162,8 @@ static UINT echo_plugin_terminated(IWTSPlugin* pPlugin) #ifdef STATIC_CHANNELS #define DVCPluginEntry echo_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** diff --git a/channels/echo/server/echo_main.c b/channels/echo/server/echo_main.c index 58cc81261..8c7f92191 100644 --- a/channels/echo/server/echo_main.c +++ b/channels/echo/server/echo_main.c @@ -116,12 +116,15 @@ static void* echo_server_thread_func(void* arg) DWORD BytesReturned = 0; echo_server* echo = (echo_server*) arg; UINT error; - DWORD status; + DWORD status; if ((error = echo_server_open_channel(echo))) { - IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); + UINT error2 = 0; WLog_ERR(TAG, "echo_server_open_channel failed with error %lu!", error); + IFCALLRET(echo->context.OpenResult, error2, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); + if (error2) + WLog_ERR(TAG, "echo server's OpenResult callback failed with error %lu", error2); goto out; } @@ -145,14 +148,14 @@ static void* echo_server_thread_func(void* arg) while (1) { - status = WaitForMultipleObjects(nCount, events, FALSE, 100); + status = WaitForMultipleObjects(nCount, events, FALSE, 100); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); + break; + } if (status == WAIT_OBJECT_0) { diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index 2bd90f242..58bc9c2b1 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -394,6 +394,8 @@ static UINT parallel_free(DEVICE* device) #ifdef STATIC_CHANNELS #define DeviceServiceEntry parallel_DeviceServiceEntry +#else +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif /** diff --git a/channels/printer/client/printer_cups.c b/channels/printer/client/printer_cups.c index d498ff6f6..9586f027f 100644 --- a/channels/printer/client/printer_cups.c +++ b/channels/printer/client/printer_cups.c @@ -5,6 +5,7 @@ * Copyright 2010-2011 Vic Lee * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -229,10 +230,12 @@ static void printer_cups_free_printer(rdpPrinter* printer) cups_printer->printjob->printjob.Close((rdpPrintJob*) cups_printer->printjob); free(printer->name); + free(printer->driver); free(printer); } -static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, const char* name, BOOL is_default) +static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, + const char* name, const char* driverName, BOOL is_default) { rdpCupsPrinter* cups_printer; @@ -247,8 +250,17 @@ static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, c free(cups_printer); return NULL; } - /* This is a generic PostScript printer driver developed by MS, so it should be good in most cases */ - cups_printer->printer.driver = "MS Publisher Imagesetter"; + + if (driverName) + cups_printer->printer.driver = _strdup(driverName); + else + cups_printer->printer.driver = _strdup("MS Publisher Imagesetter"); + if (!cups_printer->printer.driver) + { + free(cups_printer->printer.name); + free(cups_printer); + return NULL; + } cups_printer->printer.is_default = is_default; cups_printer->printer.CreatePrintJob = printer_cups_create_printjob; @@ -279,7 +291,7 @@ static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver) if (dest->instance == NULL) { printers[num_printers++] = printer_cups_new_printer((rdpCupsPrinterDriver*) driver, - dest->name, dest->is_default); + dest->name, NULL, dest->is_default); } } cupsFreeDests(num_dests, dests); @@ -287,11 +299,13 @@ static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver) return printers; } -static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, const char* name) +static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, + const char* name, const char* driverName) { rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*) driver; - return printer_cups_new_printer(cups_driver, name, cups_driver->id_sequence == 1 ? TRUE : FALSE); + return printer_cups_new_printer(cups_driver, name, driverName, + cups_driver->id_sequence == 1 ? TRUE : FALSE); } static rdpCupsPrinterDriver* cups_driver = NULL; diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 561c253f7..18d4db8a9 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -5,6 +5,7 @@ * Copyright 2010-2011 Vic Lee * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +37,8 @@ #include +#include "../printer.h" + #ifdef WITH_CUPS #include "printer_cups.h" #endif @@ -449,6 +452,8 @@ error_out: #ifdef STATIC_CHANNELS #define DeviceServiceEntry printer_DeviceServiceEntry +#else +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif /** @@ -487,7 +492,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if (name && name[0]) { - printer = driver->GetPrinter(driver, name); + printer = driver->GetPrinter(driver, name, driver_name); if (!printer) { @@ -495,9 +500,6 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) return CHANNEL_RC_INITIALIZATION_ERROR; } - if (driver_name && driver_name[0]) - printer->driver = driver_name; - if ((error = printer_register(pEntryPoints, printer))) { WLog_ERR(TAG, "printer_register failed with error %lu!", error); diff --git a/channels/printer/client/printer_main.h b/channels/printer/client/printer_main.h index 8a2c85082..3d9b75a9d 100644 --- a/channels/printer/client/printer_main.h +++ b/channels/printer/client/printer_main.h @@ -5,6 +5,7 @@ * Copyright 2010-2011 Vic Lee * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,25 +25,12 @@ #include -/* SERVER_PRINTER_CACHE_EVENT.cachedata */ -#define RDPDR_ADD_PRINTER_EVENT 0x00000001 -#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002 -#define RDPDR_DELETE_PRINTER_EVENT 0x00000003 -#define RDPDR_RENAME_PRINTER_EVENT 0x00000004 - -/* DR_PRN_DEVICE_ANNOUNCE.Flags */ -#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010 - typedef struct rdp_printer_driver rdpPrinterDriver; typedef struct rdp_printer rdpPrinter; typedef struct rdp_print_job rdpPrintJob; typedef rdpPrinter** (*pcEnumPrinters) (rdpPrinterDriver* driver); -typedef rdpPrinter* (*pcGetPrinter) (rdpPrinterDriver* driver, const char* name); +typedef rdpPrinter* (*pcGetPrinter) (rdpPrinterDriver* driver, const char* name, const char* driverName); struct rdp_printer_driver { diff --git a/channels/printer/client/printer_win.c b/channels/printer/client/printer_win.c index f30beebab..dc3664252 100644 --- a/channels/printer/client/printer_win.c +++ b/channels/printer/client/printer_win.c @@ -5,6 +5,7 @@ * Copyright 2012 Gerald Richter * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -175,10 +176,12 @@ static void printer_win_free_printer(rdpPrinter* printer) win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob); free(printer->name); + free(printer->driver); free(printer); } -static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const char* name, const wchar_t* drivername, BOOL is_default) +static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, + const char* name, const WCHAR* drivername, BOOL is_default) { rdpWinPrinter* win_printer; wchar_t wname[256]; @@ -216,7 +219,10 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons } GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, needed, &needed); - win_printer->printer.driver = malloc(1000); + if (drivername) + win_printer->printer.driver = _wcsdup(drivername); + else + win_printer->printer.driver = _wcsdup(prninfo->pDriverName); if (!win_printer->printer.driver) { GlobalFree(prninfo); @@ -224,7 +230,6 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons free(win_printer); return NULL; } - wcstombs_s(&charsConverted, win_printer->printer.driver, 1000, prninfo->pDriverName, _TRUNCATE); return (rdpPrinter*)win_printer; } @@ -274,13 +279,24 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver) return printers; } -static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name) +static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, + const char* name, const char* driverName) { + WCHAR* driverNameW = NULL; rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver; rdpPrinter *myPrinter = NULL; - myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? TRUE : FALSE); - + if (driverName) + { + ConvertToUnicode(CP_UTF8, 0, driverName, -1, &driverNameW, 0); + if (!driverNameW) + return NULL; + } + + myPrinter = printer_win_new_printer(win_driver, name, driverNameW, + win_driver->id_sequence == 1 ? TRUE : FALSE); + free(driverNameW); + return myPrinter; } diff --git a/channels/printer/printer.h b/channels/printer/printer.h new file mode 100644 index 000000000..237313009 --- /dev/null +++ b/channels/printer/printer.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Definition for the printer channel + * + * Copyright 2016 David Fort + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CHANNELS_PRINTER_PRINTER_H_ +#define __CHANNELS_PRINTER_PRINTER_H_ + +/* SERVER_PRINTER_CACHE_EVENT.cachedata */ +#define RDPDR_ADD_PRINTER_EVENT 0x00000001 +#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002 +#define RDPDR_DELETE_PRINTER_EVENT 0x00000003 +#define RDPDR_RENAME_PRINTER_EVENT 0x00000004 + +/* DR_PRN_DEVICE_ANNOUNCE.Flags */ +#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010 + + +#endif /* __CHANNELS_PRINTER_PRINTER_H_ */ diff --git a/channels/rdpdr/client/CMakeLists.txt b/channels/rdpdr/client/CMakeLists.txt index 488c174c2..4074eb6f4 100644 --- a/channels/rdpdr/client/CMakeLists.txt +++ b/channels/rdpdr/client/CMakeLists.txt @@ -2,6 +2,8 @@ # FreeRDP cmake build script # # Copyright 2012 Marc-Andre Moreau +# Copyright 2016 Inuvika Inc. +# Copyright 2016 David PHAM-VAN # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,6 +34,10 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} winpr freerdp) +if(APPLE AND (NOT IOS)) + find_library(CORESERVICES_LIBRARY CoreServices) + target_link_libraries(${MODULE_NAME} ${CORESERVICES_LIBRARY}) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 87ee6fbdb..d18cc5b1b 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -46,6 +46,15 @@ #include #endif +#ifdef __MACOSX__ +#include +#include +#include +#include +#include +#include +#endif + #ifdef HAVE_UNISTD_H #include #endif @@ -103,6 +112,45 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou #ifdef _WIN32 +BOOL check_path(char* path) +{ + UINT type = GetDriveTypeA(path); + if (!(type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE)) + return FALSE; + return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0); +} + +void first_hotplug(rdpdrPlugin *rdpdr) +{ + int i; + char drive_path[5] = { 'c', ':', '\\', '\0' }; + + DWORD unitmask = GetLogicalDrives(); + + for (i = 0; i < 26; i++) + { + if (unitmask & 0x01) + { + RDPDR_DRIVE* drive; + + drive_path[0] = 'A' + i; + drive_path[1] = ':'; + + if (check_path(drive_path)) + { + drive = (RDPDR_DRIVE*)malloc(sizeof(RDPDR_DRIVE)); + ZeroMemory(drive, sizeof(RDPDR_DRIVE)); + drive->Type = RDPDR_DTYP_FILESYSTEM; + drive->Path = _strdup(drive_path); + drive_path[1] = '\0'; + drive->Name = _strdup(drive_path); + devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext); + } + } + unitmask = unitmask >> 1; + } +} + LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { rdpdrPlugin *rdpdr; @@ -131,17 +179,21 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) RDPDR_DRIVE* drive; drive_path[0] = 'A' + i; + drive_path[1] = ':'; - drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); - ZeroMemory(drive, sizeof(RDPDR_DRIVE)); + if (check_path(drive_path)) + { + drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); + ZeroMemory(drive, sizeof(RDPDR_DRIVE)); - drive->Type = RDPDR_DTYP_FILESYSTEM; + drive->Type = RDPDR_DTYP_FILESYSTEM; - drive->Path = _strdup(drive_path); - drive_path[1] = '\0'; - drive->Name = _strdup(drive_path); - devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext); - rdpdr_send_device_list_announce_request(rdpdr, TRUE); + drive->Path = _strdup(drive_path); + drive_path[1] = '\0'; + drive->Name = _strdup(drive_path); + devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext); + rdpdr_send_device_list_announce_request(rdpdr, TRUE); + } } unitmask = unitmask >> 1; } @@ -275,6 +327,242 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) return error; } +#elif __MACOSX__ + +#define MAX_USB_DEVICES 100 + +typedef struct _hotplug_dev +{ + char* path; + BOOL to_add; +} hotplug_dev; + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT handle_hotplug(rdpdrPlugin* rdpdr) +{ + struct dirent *pDirent; + DIR *pDir; + char fullpath[PATH_MAX]; + char* szdir = (char*)"/Volumes"; + struct stat buf; + hotplug_dev dev_array[MAX_USB_DEVICES]; + int count; + DEVICE_DRIVE_EXT *device_ext; + ULONG_PTR *keys; + int i, j; + int size = 0; + UINT error; + UINT32 ids[1]; + + pDir = opendir (szdir); + if (pDir == NULL) + { + printf ("Cannot open directory\n"); + return ERROR_OPEN_FAILED; + } + + while ((pDirent = readdir(pDir)) != NULL) + { + if (pDirent->d_name[0] != '.') + { + sprintf(fullpath, "%s/%s", szdir, pDirent->d_name); + lstat(fullpath, &buf); + if(S_ISDIR(buf.st_mode)) + { + dev_array[size].path = _strdup(fullpath); + if (!dev_array[size].path) + { + closedir (pDir); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + dev_array[size++].to_add = TRUE; + } + } + } + closedir (pDir); + + /* delete removed devices */ + count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys); + + for (j = 0; j < count; j++) + { + BOOL dev_found = FALSE; + + device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]); + if (!device_ext) + continue; + + if (device_ext->path == NULL) + continue; + + /* not plugable device */ + if (strstr(device_ext->path, "/Volumes/") == NULL) + continue; + + for (i = 0; i < size; i++) + { + if (strstr(device_ext->path, dev_array[i].path) != NULL) + { + dev_found = TRUE; + dev_array[i].to_add = FALSE; + break; + } + } + + if (!dev_found) + { + devman_unregister_device(rdpdr->devman, (void *)keys[j]); + ids[0] = keys[j]; + if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) + { + WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %lu!", error); + goto cleanup; + } + } + } + + /* add new devices */ + for (i = 0; i < size; i++) + { + RDPDR_DRIVE* drive; + + if (dev_array[i].to_add) + { + char* name; + + drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE)); + if (!drive) + { + WLog_ERR(TAG, "calloc failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + + drive->Type = RDPDR_DTYP_FILESYSTEM; + + drive->Path = dev_array[i].path; + dev_array[i].path = NULL; + + name = strrchr(drive->Path, '/') + 1; + drive->Name = _strdup(name); + if (!drive->Name) + { + WLog_ERR(TAG, "_strdup failed!"); + free(drive->Path); + free(drive); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext))) + { + WLog_ERR(TAG, "devman_load_device_service failed!"); + free(drive->Path); + free(drive->Name); + free(drive); + error = CHANNEL_RC_NO_MEMORY; + goto cleanup; + } + } + } + +cleanup: + for (i = 0; i < size; i++) + free (dev_array[i].path); + + return error; + } + + +static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, + size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) +{ + rdpdrPlugin* rdpdr; + int i; + UINT error; + char **paths = (char**)eventPaths; + + rdpdr = (rdpdrPlugin*) clientCallBackInfo; + + for (i=0; irunLoop = CFRunLoopGetCurrent(); + FSEventStreamScheduleWithRunLoop(fsev, rdpdr->runLoop, kCFRunLoopDefaultMode); + FSEventStreamStart(fsev); + CFRunLoopRun(); + FSEventStreamStop(fsev); + FSEventStreamRelease(fsev); + + ExitThread(CHANNEL_RC_OK); + return NULL; +} + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) +{ + UINT error; + if (rdpdr->hotplugThread) + { + CFRunLoopStop(rdpdr->runLoop); + + if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + return error; + } + rdpdr->hotplugThread = NULL; + } + return CHANNEL_RC_OK; +} + #else #define MAX_USB_DEVICES 100 @@ -506,7 +794,16 @@ cleanup: for (i = 0; i < size; i++) free (dev_array[i].path); - return error ? error : rdpdr_send_device_list_announce_request(rdpdr, TRUE); + return error; +} + +void first_hotplug(rdpdrPlugin *rdpdr) +{ + UINT error; + if ((error = handle_hotplug(rdpdr))) + { + WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); + } } static void* drive_hotplug_thread_func(void* arg) @@ -516,7 +813,7 @@ static void* drive_hotplug_thread_func(void* arg) fd_set rfds; struct timeval tv; int rv; - UINT error; + UINT error = 0; DWORD status; rdpdr = (rdpdrPlugin*) arg; @@ -542,12 +839,6 @@ static void* drive_hotplug_thread_func(void* arg) tv.tv_sec = 1; tv.tv_usec = 0; - if ((error = handle_hotplug(rdpdr))) - { - WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); - goto out; - } - while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0) { status = WaitForSingleObject(rdpdr->stopEvent, 0); @@ -568,6 +859,8 @@ static void* drive_hotplug_thread_func(void* arg) WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); goto out; } + else + rdpdr_send_device_list_announce_request(rdpdr, TRUE); } FD_ZERO(&rfds); @@ -643,6 +936,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) if (device->Name && (strcmp(device->Name, "*") == 0)) { + first_hotplug(rdpdr); if (!(rdpdr->hotplugThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL))) { diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index 7f93acbd3..6ecb945cd 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -6,6 +6,8 @@ * Copyright 2010-2012 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +38,10 @@ #include #include +#ifdef __MACOSX__ +#include +#endif + #define TAG CHANNELS_TAG("rdpdr.client") typedef struct rdpdr_plugin rdpdrPlugin; @@ -64,6 +70,8 @@ struct rdpdr_plugin HANDLE hotplugThread; #ifdef _WIN32 HWND hotplug_wnd; +#elif __MACOSX__ + CFRunLoopRef runLoop; #else HANDLE stopEvent; #endif diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c index 074d3e4fe..b29182fa6 100644 --- a/channels/rdpdr/server/rdpdr_main.c +++ b/channels/rdpdr/server/rdpdr_main.c @@ -152,9 +152,10 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */ Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */ - if (Stream_GetRemainingLength(s) < ComputerNameLen) + + if (UnicodeFlag > 1) /* must be 0x00000000 or 0x00000001 */ { - WLog_ERR(TAG, "not enough data in stream!"); + WLog_ERR(TAG, "invalid UnicodeFlag value: 0x%08X", UnicodeFlag); return ERROR_INVALID_DATA; } @@ -164,6 +165,39 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context * not in characters, including the NULL terminator! */ + if (UnicodeFlag) + { + if ((ComputerNameLen % 2) || ComputerNameLen > 512 || ComputerNameLen < 2) + { + WLog_ERR(TAG, "invalid unicode computer name length: %u", ComputerNameLen); + return ERROR_INVALID_DATA; + } + } + else + { + if (ComputerNameLen > 256 || ComputerNameLen < 1) + { + WLog_ERR(TAG, "invalid ascii computer name length: %u", ComputerNameLen); + return ERROR_INVALID_DATA; + } + } + + if (Stream_GetRemainingLength(s) < ComputerNameLen) + { + WLog_ERR(TAG, "not enough data in stream!"); + return ERROR_INVALID_DATA; + } + + /* ComputerName must be null terminated, check if it really is */ + + if (Stream_Pointer(s)[ComputerNameLen-1] || + (UnicodeFlag && Stream_Pointer(s)[ComputerNameLen-2])) + { + WLog_ERR(TAG, "computer name must be null terminated"); + return ERROR_INVALID_DATA; + } + + if (context->priv->ClientComputerName) { free(context->priv->ClientComputerName); @@ -172,12 +206,21 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context if (UnicodeFlag) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), - -1, &(context->priv->ClientComputerName), 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, + &(context->priv->ClientComputerName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client computer name"); + return ERROR_INVALID_DATA; + } } else { context->priv->ClientComputerName = _strdup((char*) Stream_Pointer(s)); + if (!context->priv->ClientComputerName) + { + WLog_ERR(TAG, "failed to duplicate client computer name"); + return CHANNEL_RC_NO_MEMORY; + } } Stream_Seek(s, ComputerNameLen); diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index d1cbb7c07..6acfcc739 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -957,6 +957,8 @@ UINT rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y, #ifdef STATIC_CHANNELS #define DVCPluginEntry rdpei_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 7da8c9fd2..07ec66cc5 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -1515,6 +1515,8 @@ void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot) #ifdef STATIC_CHANNELS #define DVCPluginEntry rdpgfx_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 36f821440..ea4230d28 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -649,6 +649,8 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry alsa_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/ios/rdpsnd_ios.c b/channels/rdpsnd/client/ios/rdpsnd_ios.c index f307b2318..148c846a8 100644 --- a/channels/rdpsnd/client/ios/rdpsnd_ios.c +++ b/channels/rdpsnd/client/ios/rdpsnd_ios.c @@ -281,6 +281,8 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device) #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry ios_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index 14af6f609..72cfbe83c 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -348,6 +348,8 @@ static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry mac_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index c42f1b207..8c8b34e0d 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -407,6 +407,9 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry \ opensles_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry \ + FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/oss/rdpsnd_oss.c b/channels/rdpsnd/client/oss/rdpsnd_oss.c index df01ec008..2a6d3651b 100644 --- a/channels/rdpsnd/client/oss/rdpsnd_oss.c +++ b/channels/rdpsnd/client/oss/rdpsnd_oss.c @@ -477,6 +477,8 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry oss_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 13899ec00..5181d0d07 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -636,6 +636,8 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry pulse_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index 5e143635a..7eb1a5f88 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -346,6 +346,8 @@ static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV #ifdef STATIC_CHANNELS #define freerdp_rdpsnd_client_subsystem_entry winmm_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 548fa5675..b9650a9e5 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -813,6 +813,8 @@ static UINT serial_free(DEVICE* device) #ifdef STATIC_CHANNELS #define DeviceServiceEntry serial_DeviceServiceEntry +#else +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif /** diff --git a/channels/smartcard/client/smartcard_pack.c b/channels/smartcard/client/smartcard_pack.c index 421cc618d..766648bfe 100644 --- a/channels/smartcard/client/smartcard_pack.c +++ b/channels/smartcard/client/smartcard_pack.c @@ -707,7 +707,12 @@ void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, ListReader if (unicode) { length = ret->cBytes / 2; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->msz, (int)length, &mszA, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->msz, (int)length, + &mszA, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "ConvertFromUnicode failed"); + return; + } } else { @@ -1767,7 +1772,12 @@ void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, Status_Return* r if (unicode) { length = ret->cBytes / 2; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int)length, &mszReaderNamesA, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int)length, + &mszReaderNamesA, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "ConvertFromUnicode failed"); + return; + } } else { diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index 91af225a8..078c7d8f1 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -233,6 +233,8 @@ static void tsmf_alsa_free(ITSMFAudioDevice *audio) #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry +#else +#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index e1b9f83ef..4e5beff8f 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -543,6 +543,8 @@ static BOOL initialized = FALSE; #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry +#else +#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry #endif ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 0e35f73fa..466dd7d24 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -1012,6 +1012,8 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void *), void *stream #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry +#else +#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry #endif ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) diff --git a/channels/tsmf/client/oss/tsmf_oss.c b/channels/tsmf/client/oss/tsmf_oss.c index fe9785128..da792bea9 100644 --- a/channels/tsmf/client/oss/tsmf_oss.c +++ b/channels/tsmf/client/oss/tsmf_oss.c @@ -238,6 +238,8 @@ static void tsmf_oss_free(ITSMFAudioDevice* audio) #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_audio_subsystem_entry oss_freerdp_tsmf_client_audio_subsystem_entry +#else +#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index c0d6caaf3..5a8c90d8c 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -360,6 +360,8 @@ static void tsmf_pulse_free(ITSMFAudioDevice *audio) #ifdef STATIC_CHANNELS #define freerdp_tsmf_client_audio_subsystem_entry pulse_freerdp_tsmf_client_audio_subsystem_entry +#else +#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index b4a84dfdb..4c9da7421 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -79,7 +79,7 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman) if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4)) return ERROR_OUTOFMEMORY; pos = Stream_GetPosition(ifman->output); - Stream_Copy(ifman->output, ifman->input, ifman->input_size); + Stream_Copy(ifman->input, ifman->output, ifman->input_size); Stream_SetPosition(ifman->output, pos); if (Stream_GetRemainingLength(ifman->output) < 4) diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index 6e373ecb9..bc202ead9 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -527,6 +527,8 @@ static UINT tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args) #ifdef STATIC_CHANNELS #define DVCPluginEntry tsmf_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 7dfa505f2..b8af3a4c7 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -579,6 +579,8 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) #ifdef STATIC_CHANNELS #define freerdp_urbdrc_client_subsystem_entry libusb_freerdp_urbdrc_client_subsystem_entry +#else +#define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry #endif int freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints) diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index 78cd77da0..cbb937996 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -1026,7 +1026,7 @@ static void* urbdrc_search_usb_device(void* arg) } else { - WLog_ERR(TAG, "No Device from receive_device(). An error occured."); + WLog_ERR(TAG, "No Device from receive_device(). An error occurred."); } } } @@ -1541,6 +1541,8 @@ static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) #ifdef STATIC_CHANNELS #define DVCPluginEntry urbdrc_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** diff --git a/ci/cmake-preloads/config-windows.txt b/ci/cmake-preloads/config-windows.txt index 980bcb2cb..0a84d883d 100644 --- a/ci/cmake-preloads/config-windows.txt +++ b/ci/cmake-preloads/config-windows.txt @@ -1,3 +1,4 @@ message("PRELOADING windows cache") set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") +set(WITH_SERVER "ON" CACHE BOOL "Build server binaries") #set (BUILD_TESTING ON CACHE BOOL "build testing") diff --git a/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml index cebe55dfe..7860018ae 100644 --- a/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml +++ b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml @@ -16,7 +16,6 @@ - Auf Client abspielen - 0 - 1 2 + 1 + 0 Mikrophon umleiten Sicherheit diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml index 161629954..74ef6fe4e 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml @@ -122,9 +122,9 @@ Play on Device - 0 - 1 2 + 1 + 0 Redirect Microphone Seguridad diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-fr/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-fr/strings.xml index be4be240c..abb6636f5 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values-fr/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-fr/strings.xml @@ -121,9 +121,9 @@ Play on Device - 0 - 1 2 + 1 + 0 Redirect Microphone "Securité" diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml index 6167cb12f..3f23c0e3a 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml @@ -122,9 +122,9 @@ Play on Device - 0 - 1 2 + 1 + 0 Redirect Microphone Beveiliging diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml index bb98f94c9..3b57c00d8 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml @@ -119,9 +119,9 @@ 在此设备上播放 - 0 - 1 2 + 1 + 0 麦克风重定向 连接协议 diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml index 495c9b85c..611382f02 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml @@ -122,9 +122,9 @@ Play on Device - 0 - 1 2 + 1 + 0 Redirect Microphone Security diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 2baf0f4a2..8253f30d7 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -417,37 +417,64 @@ static BOOL android_authenticate(freerdp* instance, char** username, return ((res == JNI_TRUE) ? TRUE : FALSE); } -static BOOL android_verify_certificate(freerdp* instance, char* subject, - char* issuer, char* fingerprint) +static DWORD android_verify_certificate( + freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, BOOL host_mismatch) { - JNIEnv* env; - jboolean attached = jni_attach_thread(&env); - jstring jstr1 = (*env)->NewStringUTF(env, subject); - jstring jstr2 = (*env)->NewStringUTF(env, issuer); - jstring jstr3 = (*env)->NewStringUTF(env, fingerprint); - jboolean res; + WLog_DBG(TAG, "Certificate details:"); + WLog_DBG(TAG, "\tSubject: %s", subject); + WLog_DBG(TAG, "\tIssuer: %s", issuer); + WLog_DBG(TAG, "\tThumbprint: %s", fingerprint); + WLog_DBG(TAG, "The above X.509 certificate could not be verified, possibly because you do not have " + "the CA certificate in your certificate store, or the certificate has expired." + "Please look at the documentation on how to create local certificate store for a private CA.\n"); - res = freerdp_callback_bool_result( - "OnVerifyCertificate", - "(ILjava/lang/String;" - "Ljava/lang/String;" - "Ljava/lang/String;)Z", - instance, jstr1, jstr2, jstr3); + JNIEnv* env; + jboolean attached = jni_attach_thread(&env); + jstring jstr0 = (*env)->NewStringUTF(env, common_name); + jstring jstr1 = (*env)->NewStringUTF(env, subject); + jstring jstr2 = (*env)->NewStringUTF(env, issuer); + jstring jstr3 = (*env)->NewStringUTF(env, fingerprint); - if (attached == JNI_TRUE) - jni_detach_thread(); + jint res = freerdp_callback_int_result("OnVerifyCertificate", + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I", + instance, jstr0, jstr1, jstr2, jstr3, host_mismatch); - return ((res == JNI_TRUE) ? TRUE : FALSE); + if (attached == JNI_TRUE) + jni_detach_thread(); + + return res; } -static BOOL android_verify_changed_certificate( - freerdp* instance, char* subject, char* issuer, - char* new_fingerprint, char* old_subject, - char* old_issuer, char* old_fingerprint) +static DWORD android_verify_changed_certificate(freerdp* instance, + const char* common_name, + const char* subject, + const char* issuer, + const char* new_fingerprint, + const char* old_subject, + const char* old_issuer, + const char* old_fingerprint) { - return android_verify_certificate( - instance, subject, issuer, - new_fingerprint); + JNIEnv* env; + jboolean attached = jni_attach_thread(&env); + jstring jstr0 = (*env)->NewStringUTF(env, common_name); + jstring jstr1 = (*env)->NewStringUTF(env, subject); + jstring jstr2 = (*env)->NewStringUTF(env, issuer); + jstring jstr3 = (*env)->NewStringUTF(env, new_fingerprint); + jstring jstr4 = (*env)->NewStringUTF(env, old_subject); + jstring jstr5 = (*env)->NewStringUTF(env, old_issuer); + jstring jstr6 = (*env)->NewStringUTF(env, old_fingerprint); + + jint res = freerdp_callback_int_result("OnVerifyChangedCertificate", + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", + instance, jstr0, jstr1, jstr2, jstr3, jstr4, jstr5, jstr6); + + if (attached == JNI_TRUE) + jni_detach_thread(); + + return res; } static void* jni_input_thread(void* arg) diff --git a/client/Android/android_jni_callback.c b/client/Android/android_jni_callback.c index ee4869601..64985d600 100644 --- a/client/Android/android_jni_callback.c +++ b/client/Android/android_jni_callback.c @@ -172,6 +172,45 @@ finish: return res; } +/* callback with int result */ +jint java_callback_int(jobject obj, const char * callback, const char* signature, va_list args) +{ + jclass jObjClass; + jmethodID jCallback; + jboolean attached; + jint res = -1; + JNIEnv *env; + + WLog_DBG(TAG, "java_callback: %s (%s)", callback, signature); + + attached = jni_attach_thread(&env); + + jObjClass = (*env)->GetObjectClass(env, obj); + + if (!jObjClass) + { + WLog_ERR(TAG, "android_java_callback: failed to get class reference"); + goto finish; + } + + jCallback = (*env)->GetStaticMethodID(env, jObjClass, callback, signature); + + if (!jCallback) + { + WLog_ERR(TAG, "android_java_callback: failed to get method id"); + goto finish; + } + + res = (*env)->CallStaticIntMethodV(env, jObjClass, jCallback, args); + +finish: + if(attached == JNI_TRUE) + jni_detach_thread(); + + return res; +} + + /* callback to freerdp class */ void freerdp_callback(const char * callback, const char * signature, ...) { @@ -189,3 +228,12 @@ jboolean freerdp_callback_bool_result(const char * callback, const char * signat va_end(vl); return res; } + +jint freerdp_callback_int_result(const char * callback, const char * signature, ...) +{ + va_list vl; + va_start(vl, signature); + jint res = java_callback_int(jLibFreeRDPObject, callback, signature, vl); + va_end(vl); + return res; +} diff --git a/client/Android/android_jni_callback.h b/client/Android/android_jni_callback.h index dbe172e72..95d0336ee 100644 --- a/client/Android/android_jni_callback.h +++ b/client/Android/android_jni_callback.h @@ -21,6 +21,7 @@ jboolean jni_attach_thread(JNIEnv** env); void jni_detach_thread(void); void freerdp_callback(const char * callback, const char * signature, ...); jboolean freerdp_callback_bool_result(const char * callback, const char * signature, ...); +jint freerdp_callback_int_result(const char * callback, const char * signature, ...); #endif /* FREERDP_ANDROID_JNI_CALLBACK_H */ diff --git a/client/Wayland/CMakeLists.txt b/client/Wayland/CMakeLists.txt index 66cb0d18b..25c69a281 100644 --- a/client/Wayland/CMakeLists.txt +++ b/client/Wayland/CMakeLists.txt @@ -2,6 +2,7 @@ # FreeRDP Wayland Client cmake build script # # Copyright 2014 Manuel Bachmann +# Copyright 2015 David Fort # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,22 +19,20 @@ set(MODULE_NAME "wlfreerdp") set(MODULE_PREFIX "FREERDP_CLIENT_WAYLAND") -include_directories(${WAYLAND_INCLUDE_DIRS}) +include_directories(${WAYLAND_INCLUDE_DIR}) +include_directories(${CMAKE_SOURCE_DIR}/uwac/include) set(${MODULE_PREFIX}_SRCS - wlf_display.c - wlf_display.h - wlf_window.c - wlf_window.h + wlfreerdp.c + wlfreerdp.h wlf_input.c wlf_input.h - wlfreerdp.c - wlfreerdp.h) + ) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMAKE_DL_LIBS}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${WAYLAND_LIBRARIES} freerdp-client freerdp) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp uwac) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) diff --git a/client/Wayland/wlf_display.c b/client/Wayland/wlf_display.c deleted file mode 100644 index 4ab971284..000000000 --- a/client/Wayland/wlf_display.c +++ /dev/null @@ -1,112 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Wayland Displays - * - * Copyright 2014 Manuel Bachmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "wlf_display.h" - -static void wl_registry_handle_global(void* data, struct wl_registry* registry, uint32_t id, const char *interface, uint32_t version) -{ - wlfDisplay* display = data; - - if (strcmp(interface, "wl_compositor") == 0) - display->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1); - else if (strcmp(interface, "wl_shell") == 0) - display->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1); - else if (strcmp(interface, "wl_shm") == 0) - display->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); - else if (strcmp(interface, "wl_seat") == 0) - display->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); -} - -static void wl_registry_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name) -{ - -} - -static const struct wl_registry_listener wl_registry_listener = -{ - wl_registry_handle_global, - wl_registry_handle_global_remove -}; - - -wlfDisplay* wlf_CreateDisplay(void) -{ - wlfDisplay* display; - - display = (wlfDisplay*) calloc(1, sizeof(wlfDisplay)); - - if (display) - { - display->display = wl_display_connect(NULL); - - if (!display->display) - { - WLog_ERR(TAG, "wl_pre_connect: failed to connect to Wayland compositor"); - WLog_ERR(TAG, "Please check that the XDG_RUNTIME_DIR environment variable is properly set."); - free(display); - return NULL; - } - - display->registry = wl_display_get_registry(display->display); - wl_registry_add_listener(display->registry, &wl_registry_listener, display); - wl_display_roundtrip(display->display); - - if (!display->compositor || !display->shell || !display->shm) - { - WLog_ERR(TAG, "wl_pre_connect: failed to find needed compositor interfaces"); - free(display); - return NULL; - } - } - - return display; -} - -BOOL wlf_RefreshDisplay(wlfDisplay* display) -{ - if (wl_display_dispatch(display->display) == -1) - return FALSE; - return TRUE; -} - -void wlf_DestroyDisplay(wlfContext* wlfc, wlfDisplay* display) -{ - if (display == NULL) - return; - - if (wlfc->display == display) - wlfc->display = NULL; - - if (display->seat) - wl_seat_destroy(display->seat); - if (display->shm) - wl_shm_destroy(display->shm); - if (display->shell) - wl_shell_destroy(display->shell); - if (display->compositor) - wl_compositor_destroy(display->compositor); - if (display->registry) - wl_registry_destroy(display->registry); - wl_display_disconnect(display->display); - - free(display); -} diff --git a/client/Wayland/wlf_display.h b/client/Wayland/wlf_display.h deleted file mode 100644 index d92d8991d..000000000 --- a/client/Wayland/wlf_display.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Wayland Displays - * - * Copyright 2014 Manuel Bachmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __WLF_DISPLAY_H -#define __WLF_DISPLAY_H - -#include - -typedef struct wlf_display wlfDisplay; - -#include "wlfreerdp.h" - -struct wlf_display -{ - struct wl_display* display; - struct wl_registry* registry; - struct wl_compositor* compositor; - struct wl_shell* shell; - struct wl_shm* shm; - struct wl_seat* seat; -}; - -wlfDisplay* wlf_CreateDisplay(void); -BOOL wlf_RefreshDisplay(wlfDisplay* display); -void wlf_DestroyDisplay(wlfContext* wlfc, wlfDisplay* display); - -#endif /* __WLF_DISPLAY_H */ diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index 76ab5552a..00435ffff 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -3,6 +3,7 @@ * Wayland Input * * Copyright 2014 Manuel Bachmann + * Copyright 2015 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,50 +25,30 @@ #include "wlf_input.h" -static void wl_pointer_enter(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t sx_w, wl_fixed_t sy_w) -{ +BOOL wlf_handle_pointer_enter(freerdp *instance, UwacPointerEnterLeaveEvent *ev) { + rdpInput* input = instance->input; + return input->MouseEvent(input, PTR_FLAGS_MOVE, ev->x, ev->y); } -static void wl_pointer_leave(void* data, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surface) -{ - +BOOL wlf_handle_pointer_motion(freerdp *instance, UwacPointerMotionEvent *ev) { + rdpInput* input = instance->input; + + return input->MouseEvent(input, PTR_FLAGS_MOVE, ev->x, ev->y); } -static void wl_pointer_motion(void* data, struct wl_pointer* pointer, uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) -{ - wlfInput* input_w = data; +BOOL wlf_handle_pointer_buttons(freerdp *instance, UwacPointerButtonEvent *ev) { rdpInput* input; - UINT16 x; - UINT16 y; - - input = input_w->input; - - x = (UINT16) wl_fixed_to_int(sx_w); - y = (UINT16) wl_fixed_to_int(sy_w); - - input->MouseEvent(input, PTR_FLAGS_MOVE, x, y); - - input_w->last_x = x; - input_w->last_y = y; -} - -static void wl_pointer_button(void* data, struct wl_pointer* pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) -{ - wlfInput* input_w = data; - rdpInput* input; - UINT16 x; - UINT16 y; UINT16 flags; - input = input_w->input; + input = instance->input; - if (state == WL_POINTER_BUTTON_STATE_PRESSED) + if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED) flags = PTR_FLAGS_DOWN; else flags = 0; - switch (button) + switch (ev->button) { case BTN_LEFT: flags |= PTR_FLAGS_BUTTON1; @@ -79,175 +60,50 @@ static void wl_pointer_button(void* data, struct wl_pointer* pointer, uint32_t s flags |= PTR_FLAGS_BUTTON3; break; default: - return; + return TRUE; } - x = input_w->last_x; - y = input_w->last_y; - - input->MouseEvent(input, flags, x, y); + return input->MouseEvent(input, flags, ev->x, ev->y); } -static void wl_pointer_axis(void* data, struct wl_pointer* pointer, uint32_t time, uint32_t axis, wl_fixed_t value) -{ - wlfInput* input_w = data; + +BOOL wlf_handle_pointer_axis(freerdp *instance, UwacPointerAxisEvent *ev) { rdpInput* input; UINT16 flags; int direction; - input = input_w->input; + input = instance->input; flags = PTR_FLAGS_WHEEL; - if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + if (ev->axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - direction = wl_fixed_to_int(value); + direction = wl_fixed_to_int(ev->value); if (direction < 0) flags |= 0x0078; else flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; } - input->MouseEvent(input, flags, 0, 0); + return input->MouseEvent(input, flags, ev->x, ev->y); } -static const struct wl_pointer_listener wl_pointer_listener = -{ - wl_pointer_enter, - wl_pointer_leave, - wl_pointer_motion, - wl_pointer_button, - wl_pointer_axis -}; - -static void wl_keyboard_keymap(void* data, struct wl_keyboard* keyboard, uint32_t format, int fd, uint32_t size) -{ - -} - -static void wl_keyboard_enter(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface, struct wl_array* keys) -{ - wlfInput* input_w = data; - rdpInput* input; - UINT16 x; - UINT16 y; - - input = input_w->input; - - x = input_w->last_x; - y = input_w->last_y; - - input->FocusInEvent(input, 0); - input->MouseEvent(input, PTR_FLAGS_MOVE, x, y); -} - -static void wl_keyboard_leave(void* data, struct wl_keyboard* keyboard, uint32_t serial, struct wl_surface* surface) -{ - -} - -static void wl_keyboard_key(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) -{ - wlfInput* input_w = data; - rdpInput* input; - BOOL key_down; +BOOL wlf_handle_key(freerdp *instance, UwacKeyEvent *ev) { + rdpInput* input = instance->input; DWORD rdp_scancode; - input = input_w->input; - - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) - key_down = TRUE; - else - key_down = FALSE; - - rdp_scancode = (DWORD) key; + rdp_scancode = (DWORD) ev->raw_key; if (rdp_scancode == RDP_SCANCODE_UNKNOWN) - return; + return TRUE; - freerdp_input_send_keyboard_event_ex(input, key_down, rdp_scancode); + return freerdp_input_send_keyboard_event_ex(input, ev->pressed, rdp_scancode); } -static void wl_keyboard_modifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t mods_depr, uint32_t mods_latch, uint32_t mods_lock, uint32_t group) -{ +BOOL wlf_keyboard_enter(freerdp *instance, UwacKeyboardEnterLeaveEvent *ev) { + rdpInput* input = instance->input; + + return input->FocusInEvent(input, 0) && + input->MouseEvent(input, PTR_FLAGS_MOVE, 0, 0); } - -static const struct wl_keyboard_listener wl_keyboard_listener = -{ - wl_keyboard_keymap, - wl_keyboard_enter, - wl_keyboard_leave, - wl_keyboard_key, - wl_keyboard_modifiers -}; - -static void wl_seat_handle_capabilities(void* data, struct wl_seat* seat, enum wl_seat_capability capabilities) -{ - wlfInput* input = data; - struct wl_pointer* pointer; - struct wl_keyboard* keyboard; - - if (capabilities & WL_SEAT_CAPABILITY_POINTER) - { - pointer = wl_seat_get_pointer(seat); - - input->pointer = pointer; - wl_pointer_add_listener(pointer, &wl_pointer_listener, input); - } - - if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) - { - keyboard = wl_seat_get_keyboard(seat); - - input->keyboard = keyboard; - wl_keyboard_add_listener(keyboard, &wl_keyboard_listener, input); - } - -} - -static const struct wl_seat_listener wl_seat_listener = { - wl_seat_handle_capabilities -}; - - -wlfInput* wlf_CreateInput(wlfContext* wlfc) -{ - wlfInput* input; - struct wl_seat* seat; - - if (!wlfc->display) - return NULL; - if (!wlfc->display->seat) - return NULL; - seat = wlfc->display->seat; - - input = (wlfInput*) calloc(1, sizeof(wlfInput)); - - if (input) - { - input->input = wlfc->context.input; - input->last_x = 0; - input->last_y = 0; - - wl_seat_add_listener(seat, &wl_seat_listener, input); - } - - return input; -} - -void wlf_DestroyInput(wlfContext* wlfc, wlfInput* input) -{ - if (input == NULL) - return; - - if (wlfc->input == input) - wlfc->input = NULL; - - if (input->pointer) - wl_pointer_release(input->pointer); - if (input->keyboard) - wl_keyboard_release(input->keyboard); - - free(input); -} diff --git a/client/Wayland/wlf_input.h b/client/Wayland/wlf_input.h index 46f2447d7..0529f0179 100644 --- a/client/Wayland/wlf_input.h +++ b/client/Wayland/wlf_input.h @@ -3,6 +3,7 @@ * Wayland Input * * Copyright 2014 Manuel Bachmann + * Copyright 2015 David Fort * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,23 +21,15 @@ #ifndef __WLF_INPUT_H #define __WLF_INPUT_H -#include +#include +#include -typedef struct wlf_input wlfInput; +BOOL wlf_handle_pointer_enter(freerdp* instance, UwacPointerEnterLeaveEvent *ev); +BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent *ev); +BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent *ev); +BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent *ev); -#include "wlfreerdp.h" - -struct wlf_input -{ - rdpInput* input; - UINT16 last_x; - UINT16 last_y; - - struct wl_pointer* pointer; - struct wl_keyboard* keyboard; -}; - -wlfInput* wlf_CreateInput(wlfContext* wlfc); -void wlf_DestroyInput(wlfContext* wlfc, wlfInput* input); +BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent *ev); +BOOL wlf_keyboard_enter(freerdp *instance, UwacKeyboardEnterLeaveEvent *ev); #endif /* __WLF_INPUT_H */ diff --git a/client/Wayland/wlf_window.c b/client/Wayland/wlf_window.c deleted file mode 100644 index 72b57eaf3..000000000 --- a/client/Wayland/wlf_window.c +++ /dev/null @@ -1,220 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Wayland Windows - * - * Copyright 2014 Manuel Bachmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#include "wlf_window.h" - -static void wl_shell_surface_handle_ping(void* data, struct wl_shell_surface* shell_surface, uint32_t serial) -{ - wl_shell_surface_pong(shell_surface, serial); -} - -static void wl_shell_surface_handle_configure(void* data, struct wl_shell_surface* shell_surface, unsigned int edges, int32_t width, int32_t height) -{ - wlfWindow* window = data; - - window->width = width; - window->height = height; -} - -static const struct wl_shell_surface_listener wl_shell_surface_listener = -{ - wl_shell_surface_handle_ping, - wl_shell_surface_handle_configure, - NULL -}; - -static void wl_buffer_release(void* data, struct wl_buffer* wl_buffer) -{ - wlfBuffer* buffer = data; - - buffer->busy = FALSE; -} - -static const struct wl_buffer_listener wl_buffer_listener = -{ - wl_buffer_release -}; - -static const struct wl_callback_listener wl_callback_listener; - -static void wl_callback_done(void* data, struct wl_callback* callback, uint32_t time) -{ - wlfWindow* window = data; - wlfBuffer* buffer; - struct wl_shm_pool* shm_pool; - void* shm_data; - void* free_data; - int fd; - int fdt; - - if (!window->buffers[0].busy) - buffer = &window->buffers[0]; - else if (!window->buffers[1].busy) - buffer = &window->buffers[1]; - else - return; - - if (!buffer->buffer) { - fd = shm_open("/wlfreerdp_shm", O_CREAT | O_RDWR, 0666); - fdt = ftruncate(fd, window->width * window->height * 4); - if (fdt != 0) - { - WLog_ERR(TAG, "window_redraw: could not allocate memory"); - close(fd); - return; - } - - shm_data = mmap(NULL, window->width * window->height * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (shm_data == MAP_FAILED) - { - WLog_ERR(TAG, "window_redraw: failed to memory map buffer"); - close(fd); - return; - } - - shm_pool = wl_shm_create_pool(window->display->shm, fd, window->width * window->height * 4); - buffer->buffer = wl_shm_pool_create_buffer(shm_pool, 0, window->width, window->height, window->width* 4, WL_SHM_FORMAT_XRGB8888); - wl_buffer_add_listener(buffer->buffer, &wl_buffer_listener, buffer); - wl_shm_pool_destroy(shm_pool); - shm_unlink("/wlfreerdp_shm"); - close(fd); - - free_data = buffer->shm_data; - buffer->shm_data = shm_data; - munmap(free_data, window->width * window->height * 4); - } - - /* this is the real surface data */ - memcpy(buffer->shm_data, (void*) window->data, window->width * window->height * 4); - wl_surface_attach(window->surface, buffer->buffer, 0, 0); - wl_surface_damage(window->surface, 0, 0, window->width, window->height); - - if (callback) wl_callback_destroy(callback); - window->callback = wl_surface_frame(window->surface); - wl_callback_add_listener(window->callback, &wl_callback_listener, window); - wl_surface_commit(window->surface); - - buffer->busy = TRUE; -} - -static const struct wl_callback_listener wl_callback_listener = -{ - wl_callback_done -}; - - -wlfWindow* wlf_CreateDesktopWindow(wlfContext* wlfc, char* name, int width, int height, BOOL decorations) -{ - wlfWindow* window; - - window = (wlfWindow*) calloc(1, sizeof(wlfWindow)); - - if (window) - { - window->width = width; - window->height = height; - window->fullscreen = FALSE; - window->buffers[0].busy = FALSE; - window->buffers[1].busy = FALSE; - window->callback = NULL; - window->display = wlfc->display; - - window->surface = wl_compositor_create_surface(window->display->compositor); - window->shell_surface = wl_shell_get_shell_surface(window->display->shell, window->surface); - wl_shell_surface_add_listener(window->shell_surface, &wl_shell_surface_listener, window); - wl_shell_surface_set_toplevel(window->shell_surface); - - wlf_ResizeDesktopWindow(wlfc, window, width, height); - - wl_surface_damage(window->surface, 0, 0, window->width, window->height); - - wlf_SetWindowText(wlfc, window, name); - } - - return window; -} - -void wlf_ResizeDesktopWindow(wlfContext* wlfc, wlfWindow* window, int width, int height) -{ - window->width = width; - window->height = height; -} - -void wlf_SetWindowText(wlfContext* wlfc, wlfWindow* window, char* name) -{ - wl_shell_surface_set_title(window->shell_surface, name); -} - -void wlf_SetWindowFullscreen(wlfContext* wlfc, wlfWindow* window, BOOL fullscreen) -{ - if (fullscreen) - { - wl_shell_surface_set_fullscreen(window->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL); - window->fullscreen = TRUE; - } -} - -void wlf_ShowWindow(wlfContext* wlfc, wlfWindow* window, BYTE state) -{ - switch (state) - { - case WINDOW_HIDE: - case WINDOW_SHOW_MINIMIZED: - /* xdg_surface_set_minimized(window->xdg_surface); */ - break; - case WINDOW_SHOW_MAXIMIZED: - wl_shell_surface_set_maximized(window->shell_surface, NULL); - break; - case WINDOW_SHOW: - wl_shell_surface_set_toplevel(window->shell_surface); - break; - } -} - -void wlf_UpdateWindowArea(wlfContext* wlfc, wlfWindow* window, int x, int y, int width, int height) -{ - wl_callback_done(window, NULL, 0); -} - -void wlf_DestroyWindow(wlfContext* wlfc, wlfWindow* window) -{ - if (window == NULL) - return; - - if (wlfc->window == window) - wlfc->window = NULL; - - if (window->buffers[0].buffer) - wl_buffer_destroy(window->buffers[0].buffer); - if (window->buffers[1].buffer) - wl_buffer_destroy(window->buffers[1].buffer); - if (window->shell_surface) - wl_shell_surface_destroy(window->shell_surface); - if (window->surface) - wl_surface_destroy(window->surface); - - free(window->data); - free(window); -} diff --git a/client/Wayland/wlf_window.h b/client/Wayland/wlf_window.h deleted file mode 100644 index df3628909..000000000 --- a/client/Wayland/wlf_window.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Wayland Windows - * - * Copyright 2014 Manuel Bachmann - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __WLF_WINDOW_H -#define __WLF_WINDOW_H - -#include - -typedef struct wlf_window wlfWindow; - -#include "wlfreerdp.h" - -struct wlf_buffer -{ - struct wl_buffer* buffer; - void* shm_data; - BOOL busy; -}; -typedef struct wlf_buffer wlfBuffer; - -struct wlf_window -{ - int width; - int height; - struct wl_surface* surface; - struct wl_shell_surface* shell_surface; - struct wl_callback* callback; - wlfBuffer buffers[2]; - wlfDisplay* display; - void* data; - BOOL fullscreen; -}; - -wlfWindow* wlf_CreateDesktopWindow(wlfContext* wlfc, char* name, int width, int height, BOOL decorations); -void wlf_ResizeDesktopWindow(wlfContext* wlfc, wlfWindow* window, int width, int height); -void wlf_SetWindowText(wlfContext* wlfc, wlfWindow* window, char* name); -void wlf_SetWindowFullscreen(wlfContext* wlfc, wlfWindow* window, BOOL fullscree); -void wlf_ShowWindow(wlfContext* wlfc, wlfWindow* window, BYTE state); -void wlf_UpdateWindowArea(wlfContext* wlfc, wlfWindow* window, int x, int y, int width, int height); -void wlf_DestroyWindow(wlfContext* wlfc, wlfWindow* window); - -#endif /* __WLF_WINDOW_H */ diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index 456e64ac1..308147cab 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -23,8 +23,13 @@ #include #include #include +#include #include "wlfreerdp.h" +#include "wlf_input.h" + +UwacDisplay *g_display; +HANDLE g_displayHandle; static BOOL wl_context_new(freerdp* instance, rdpContext* context) { @@ -44,6 +49,18 @@ static void wl_context_free(freerdp* instance, rdpContext* context) } } +BOOL wl_update_content(wlfContext *context_w) +{ + if (!context_w->waitingFrameDone && context_w->haveDamage) + { + UwacWindowSubmitBuffer(context_w->window, true); + context_w->waitingFrameDone = TRUE; + context_w->haveDamage = FALSE; + } + + return TRUE; +} + static BOOL wl_begin_paint(rdpContext* context) { rdpGdi* gdi; @@ -53,12 +70,12 @@ static BOOL wl_begin_paint(rdpContext* context) return TRUE; } + static BOOL wl_end_paint(rdpContext* context) { rdpGdi* gdi; - wlfDisplay* display; - wlfWindow* window; - wlfContext* context_w; + char *data; + wlfContext *context_w; INT32 x, y; UINT32 w, h; int i; @@ -73,21 +90,28 @@ static BOOL wl_end_paint(rdpContext* context) h = gdi->primary->hdc->hwnd->invalid->h; context_w = (wlfContext*) context; - display = context_w->display; - window = context_w->window; + + data = UwacWindowGetDrawingBuffer(context_w->window); + if (!data) + return FALSE; for (i = 0; i < h; i++) - memcpy(window->data + ((i+y)*(gdi->width*4)) + x*4, + { + memcpy(data + ((i+y)*(gdi->width*4)) + x*4, gdi->primary_buffer + ((i+y)*(gdi->width*4)) + x*4, w*4); + } - return wlf_RefreshDisplay(display); + if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS) + return FALSE; + + context_w->haveDamage = TRUE; + return wl_update_content(context_w); } + static BOOL wl_pre_connect(freerdp* instance) { - wlfDisplay* display; - wlfInput* input; wlfContext* context; if (freerdp_channels_pre_connect(instance->context->channels, instance)) @@ -97,17 +121,7 @@ static BOOL wl_pre_connect(freerdp* instance) if (!context) return FALSE; - display = wlf_CreateDisplay(); - if (!display) - return FALSE; - - context->display = display; - - input = wlf_CreateInput(context); - if (!input) - return FALSE; - - context->input = input; + context->display = g_display; return TRUE; } @@ -115,7 +129,7 @@ static BOOL wl_pre_connect(freerdp* instance) static BOOL wl_post_connect(freerdp* instance) { rdpGdi* gdi; - wlfWindow* window; + UwacWindow* window; wlfContext* context; if (!gdi_init(instance, CLRCONV_ALPHA | CLRBUF_32BPP, NULL)) @@ -126,28 +140,23 @@ static BOOL wl_post_connect(freerdp* instance) return FALSE; context = (wlfContext*) instance->context; - window = wlf_CreateDesktopWindow(context, "FreeRDP", gdi->width, gdi->height, FALSE); + context->window = window = UwacCreateWindowShm(context->display, gdi->width, gdi->height, WL_SHM_FORMAT_XRGB8888); if (!window) return FALSE; - /* fill buffer with first image here */ - window->data = malloc (gdi->width * gdi->height *4); - if (!window->data) - return FALSE; + UwacWindowSetTitle(window, "FreeRDP"); - memcpy(window->data, (void*) gdi->primary_buffer, gdi->width * gdi->height * 4); instance->update->BeginPaint = wl_begin_paint; instance->update->EndPaint = wl_end_paint; - /* put Wayland data in the context here */ - context->window = window; - if (freerdp_channels_post_connect(instance->context->channels, instance) < 0) return FALSE; - wlf_UpdateWindowArea(context, window, 0, 0, gdi->width, gdi->height); - return TRUE; + memcpy(UwacWindowGetDrawingBuffer(context->window), gdi->primary_buffer, gdi->width * gdi->height * 4); + UwacWindowAddDamage(context->window, 0, 0, gdi->width, gdi->height); + context->haveDamage = TRUE; + return wl_update_content(context); } static void wl_post_disconnect(freerdp* instance) @@ -161,55 +170,67 @@ static void wl_post_disconnect(freerdp* instance) context = (wlfContext*) instance->context; - if (context->display) - wlf_DestroyDisplay(context, context->display); - - if (context->input) - wlf_DestroyInput(context, context->input); - gdi_free(instance); if (context->window) - wlf_DestroyWindow(context, context->window); + UwacDestroyWindow(&context->window); + + if (context->display) + UwacCloseDisplay(&context->display); + } -static BOOL wl_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) -{ - char answer; +static BOOL handle_uwac_events(freerdp* instance, UwacDisplay *display) { + UwacEvent event; + wlfContext *context; - printf("Certificate details:\n"); - printf("\tSubject: %s\n", subject); - printf("\tIssuer: %s\n", issuer); - printf("\tThumbprint: %s\n", fingerprint); - printf("The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA.\n"); + if (UwacDisplayDispatch(display, 1) < 0) + return FALSE; - while (1) + while (UwacHasEvent(display)) { - printf("Do you trust the above certificate? (Y/N) "); - answer = fgetc(stdin); - - if (feof(stdin)) - { - printf("\nError: Could not read answer from stdin."); - if (instance->settings->CredentialsFromStdin) - printf(" - Run without parameter \"--from-stdin\" to set trust."); - printf("\n"); + if (UwacNextEvent(display, &event) != UWAC_SUCCESS) return FALSE; - } - if (answer == 'y' || answer == 'Y') - { - return TRUE; - } - else if (answer == 'n' || answer == 'N') - { + /*printf("UWAC event type %d\n", event.type);*/ + switch (event.type) { + case UWAC_EVENT_FRAME_DONE: + if (!instance) + continue; + + context = (wlfContext *)instance->context; + context->waitingFrameDone = FALSE; + if (context->haveDamage && !wl_end_paint(instance->context)) + return FALSE; + break; + case UWAC_EVENT_POINTER_ENTER: + if (!wlf_handle_pointer_enter(instance, &event.mouse_enter_leave)) + return FALSE; + break; + case UWAC_EVENT_POINTER_MOTION: + if (!wlf_handle_pointer_motion(instance, &event.mouse_motion)) + return FALSE; + break; + case UWAC_EVENT_POINTER_BUTTONS: + if (!wlf_handle_pointer_buttons(instance, &event.mouse_button)) + return FALSE; + break; + case UWAC_EVENT_POINTER_AXIS: + if (!wlf_handle_pointer_axis(instance, &event.mouse_axis)) + return FALSE; + break; + case UWAC_EVENT_KEY: + if (!wlf_handle_key(instance, &event.key)) + return FALSE; + break; + case UWAC_EVENT_KEYBOARD_ENTER: + if (!wlf_keyboard_enter(instance, &event.keyboard_enter_leave)) + return FALSE; + break; + default: break; } - printf("\n"); } - - return FALSE; + return TRUE; } static int wlfreerdp_run(freerdp* instance) @@ -224,27 +245,39 @@ static int wlfreerdp_run(freerdp* instance) return -1; } + handle_uwac_events(instance, g_display); + while (!freerdp_shall_disconnect(instance)) { - count = freerdp_get_event_handles(instance->context, handles, 64); + handles[0] = g_displayHandle; + + count = freerdp_get_event_handles(instance->context, &handles[1], 63); if (!count) { printf("Failed to get FreeRDP file descriptor\n"); break; } - status = WaitForMultipleObjects(count, handles, FALSE, INFINITE); + status = WaitForMultipleObjects(count+1, handles, FALSE, INFINITE); if (WAIT_FAILED == status) { printf("%s: WaitForMultipleObjects failed\n", __FUNCTION__); break; } - if (freerdp_check_event_handles(instance->context) != TRUE) - { - printf("Failed to check FreeRDP file descriptor\n"); + if (!handle_uwac_events(instance, g_display)) { + printf("error handling UWAC events\n"); break; } + + //if (WaitForMultipleObjects(count, &handles[1], FALSE, INFINITE)) { + if (freerdp_check_event_handles(instance->context) != TRUE) + { + printf("Failed to check FreeRDP file descriptor\n"); + break; + } + //} + } freerdp_channels_disconnect(instance->context->channels, instance); @@ -255,14 +288,28 @@ static int wlfreerdp_run(freerdp* instance) int main(int argc, char* argv[]) { - int status; + 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->VerifyCertificate = wl_verify_certificate; + 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; diff --git a/client/Wayland/wlfreerdp.h b/client/Wayland/wlfreerdp.h index bf4da6faf..575d7e46b 100644 --- a/client/Wayland/wlfreerdp.h +++ b/client/Wayland/wlfreerdp.h @@ -23,22 +23,22 @@ #include #include #include +#include #define TAG CLIENT_TAG("wayland") typedef struct wlf_context wlfContext; -#include "wlf_display.h" -#include "wlf_window.h" -#include "wlf_input.h" struct wlf_context { rdpContext context; - wlfDisplay* display; - wlfWindow* window; - wlfInput* input; + UwacDisplay *display; + UwacWindow *window; + + BOOL waitingFrameDone; + BOOL haveDamage; }; #endif /* __WLFREERDP_H */ diff --git a/client/Windows/cli/wfreerdp.c b/client/Windows/cli/wfreerdp.c index a9b3c1730..dd9ea55fa 100644 --- a/client/Windows/cli/wfreerdp.c +++ b/client/Windows/cli/wfreerdp.c @@ -40,9 +40,10 @@ #include "wf_client.h" +#include + INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { - int index; int status; HANDLE thread; wfContext* wfc; @@ -50,7 +51,11 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine rdpContext* context; rdpSettings* settings; RDP_CLIENT_ENTRY_POINTS clientEntryPoints; - int ret = 0; + int ret = 1; + int argc = 0, i; + LPWSTR* args; + LPWSTR cmd; + char** argv; ZeroMemory(&clientEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS); @@ -59,56 +64,71 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine RdpClientEntry(&clientEntryPoints); context = freerdp_client_context_new(&clientEntryPoints); + if (!context) + return -1; + + cmd = GetCommandLineW(); + if (!cmd) + goto out; + + args = CommandLineToArgvW(cmd, &argc); + if (!args) + goto out; + + argv = calloc(argc, sizeof(char*)); + if (!argv) + goto out; + + for (i=0; isettings; wfc = (wfContext*) context; - - settings->SoftwareGdi = TRUE; - - context->argc = __argc; - context->argv = (char**) malloc(sizeof(char*) * __argc); - if (!context->argv) - { - ret = 1; + if (!settings || !wfc) goto out; - } - - for (index = 0; index < context->argc; index++) - { - context->argv[index] = _strdup(__argv[index]); - if (!context->argv[index]) - { - ret = 1; - for (--index; index >= 0; --index) - free(context->argv[index]); - free(context->argv); - context->argv = NULL; - goto out; - } - - } - - status = freerdp_client_settings_parse_command_line(settings, context->argc, context->argv, FALSE); - - status = freerdp_client_settings_command_line_status_print(settings, status, context->argc, context->argv); + status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE); if (status) - { - freerdp_client_context_free(context); - return 0; - } + { + freerdp_client_settings_command_line_status_print(settings, status, argc, argv); + goto out; + } - freerdp_client_start(context); + if (freerdp_client_start(context) != 0) + goto out; thread = freerdp_client_get_thread(context); + if (thread) + { + if (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0) + { + GetExitCodeThread(thread, &dwExitCode); + ret = dwExitCode; + } + } - WaitForSingleObject(thread, INFINITE); + if (freerdp_client_stop(context) != 0) + goto out; - GetExitCodeThread(thread, &dwExitCode); - - freerdp_client_stop(context); out: freerdp_client_context_free(context); + if (argv) + { + for (i=0; icontext; @@ -1081,6 +1106,7 @@ BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context) instance->Authenticate = wf_authenticate; instance->GatewayAuthenticate = wf_gw_authenticate; instance->VerifyCertificate = wf_verify_certificate; + instance->VerifyChangedCertificate = wf_verify_changed_certificate; wfc->instance = instance; wfc->settings = instance->settings; diff --git a/client/Windows/wf_rail.c b/client/Windows/wf_rail.c index c00a465ac..9ee65ce75 100644 --- a/client/Windows/wf_rail.c +++ b/client/Windows/wf_rail.c @@ -456,14 +456,33 @@ static BOOL wf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI { char* title = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); + if (windowState->titleInfo.length == 0) + { + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); + /* error handled below */ + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); + /* error handled below */ + } railWindow->title = title; } else { - railWindow->title = _strdup("RdpRailWindow"); + if (!(railWindow->title = _strdup("RdpRailWindow"))) + WLog_ERR(TAG, "failed to duplicate default window title string"); + } + + if (!railWindow->title) + { + free(railWindow); + return FALSE; } ConvertToUnicode(CP_UTF8, 0, railWindow->title, -1, &titleW, 0); @@ -569,8 +588,20 @@ static BOOL wf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI char* title = NULL; WCHAR* titleW = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); + if (windowState->titleInfo.length == 0) + { + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); + return FALSE; + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); + return FALSE; + } free(railWindow->title); railWindow->title = title; diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 8a885cf63..baaf7e75b 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -102,8 +102,6 @@ #include #define TAG CLIENT_TAG("x11") -static const size_t password_size = 512; - static int (*_def_error_handler)(Display*, XErrorEvent*); static int _xf_error_handler(Display* d, XErrorEvent* ev); static void xf_check_extensions(xfContext* context); @@ -1357,158 +1355,6 @@ static void xf_post_disconnect(freerdp* instance) xf_keyboard_free(xfc); } -/** Callback set in the rdp_freerdp structure, and used to get the user's password, - * if required to establish the connection. - * This function is actually called in credssp_ntlmssp_client_init() - * @see rdp_server_accept_nego() and rdp_check_fds() - * @param instance - pointer to the rdp_freerdp structure that contains the connection settings - * @param username - unused - * @param password - on return: pointer to a character string that will be filled by the password entered by the user. - * Note that this character string will be allocated inside the function, and needs to be deallocated by the caller - * using free(), even in case this function fails. - * @param domain - unused - * @return TRUE if a password was successfully entered. See freerdp_passphrase_read() for more details. - */ -static BOOL xf_authenticate_raw(freerdp* instance, BOOL gateway, char** username, - char** password, char** domain) -{ - const char* auth[] = - { - "Username: ", - "Domain: ", - "Password: " - }; - const char* gw[] = - { - "GatewayUsername: ", - "GatewayDomain: ", - "GatewayPassword: " - }; - const char** prompt = (gateway) ? gw : auth; - - if (!username || !password || !domain) - return FALSE; - - if (!*username) - { - size_t username_size = 0; - printf("%s", prompt[0]); - if (getline(username, &username_size, stdin) < 0) - { - WLog_ERR(TAG, "getline returned %s [%d]", strerror(errno), errno); - goto fail; - } - - if (*username) - { - *username = StrSep(username, "\r"); - *username = StrSep(username, "\n"); - } - } - - if (!*domain) - { - size_t domain_size = 0; - printf("%s", prompt[1]); - if (getline(domain, &domain_size, stdin) < 0) - { - WLog_ERR(TAG, "getline returned %s [%d]", strerror(errno), errno); - goto fail; - } - - if (*domain) - { - *domain = StrSep(domain, "\r"); - *domain = StrSep(domain, "\n"); - } - } - - if (!*password) - { - *password = calloc(password_size, sizeof(char)); - if (!*password) - goto fail; - - if (freerdp_passphrase_read(prompt[2], *password, password_size, - instance->settings->CredentialsFromStdin) == NULL) - goto fail; - } - - return TRUE; - -fail: - free(*username); - free(*domain); - free(*password); - - *username = NULL; - *domain = NULL; - *password = NULL; - - return FALSE; -} - -static BOOL xf_authenticate(freerdp* instance, char** username, char** password, char** domain) -{ - return xf_authenticate_raw(instance, FALSE, username, password, domain); -} - -static BOOL xf_gw_authenticate(freerdp* instance, char** username, char** password, char** domain) -{ - return xf_authenticate_raw(instance, TRUE, username, password, domain); -} - -/** Callback set in the rdp_freerdp structure, and used to make a certificate validation - * when the connection requires it. - * This function will actually be called by tls_verify_certificate(). - * @see rdp_client_connect() and tls_connect() - * @param instance - pointer to the rdp_freerdp structure that contains the connection settings - * @param subject - * @param issuer - * @param fingerprint - * @return TRUE if the certificate is trusted. FALSE otherwise. - */ -BOOL xf_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) -{ - char answer; - - WLog_INFO(TAG, "Certificate details:"); - WLog_INFO(TAG, "\tSubject: %s", subject); - WLog_INFO(TAG, "\tIssuer: %s", issuer); - WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); - WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired. " - "Please look at the documentation on how to create local certificate store for a private CA."); - - while (1) - { - WLog_INFO(TAG, "Do you trust the above certificate? (Y/N) "); - answer = fgetc(stdin); - - if (feof(stdin)) - { - WLog_INFO(TAG, "Error: Could not read answer from stdin."); - if (instance->settings->CredentialsFromStdin) - WLog_INFO(TAG, " - Run without parameter \"--from-stdin\" to set trust."); - WLog_INFO(TAG, ""); - return FALSE; - } - - if (answer == 'y' || answer == 'Y') - { - return TRUE; - } - else if (answer == 'n' || answer == 'N') - { - break; - } - - WLog_INFO(TAG, ""); - } - - return FALSE; -} - int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) { xfContext* xfc = (xfContext*) instance->context; @@ -1956,9 +1802,10 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) instance->PreConnect = xf_pre_connect; instance->PostConnect = xf_post_connect; instance->PostDisconnect = xf_post_disconnect; - instance->Authenticate = xf_authenticate; - instance->GatewayAuthenticate = xf_gw_authenticate; - instance->VerifyCertificate = xf_verify_certificate; + 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->LogonErrorInfo = xf_logon_error_info; settings = instance->settings; diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index c474e743e..569f4484e 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -44,6 +44,8 @@ #define TAG CLIENT_TAG("x11") +#define MAX_CLIPBOARD_FORMATS 255 + struct xf_cliprdr_format { Atom atom; @@ -64,6 +66,9 @@ struct xf_clipboard Atom clipboard_atom; Atom property_atom; + Atom raw_transfer_atom; + Atom raw_format_list_atom; + int numClientFormats; xfCliprdrFormat clientFormats[20]; @@ -76,8 +81,9 @@ struct xf_clipboard int requestedFormatId; BYTE* data; - UINT32 data_format; - UINT32 data_alt_format; + BOOL data_raw_format; + UINT32 data_format_id; + const char* data_format_name; int data_length; XEvent* respond; @@ -122,9 +128,70 @@ static BOOL xf_cliprdr_is_self_owned(xfClipboard* clipboard) return XGetSelectionOwner(xfc->display, clipboard->clipboard_atom) == xfc->drawable; } -static xfCliprdrFormat* xf_cliprdr_get_format_by_id(xfClipboard* clipboard, UINT32 formatId) +static void xf_cliprdr_set_raw_transfer_enabled(xfClipboard* clipboard, BOOL enabled) { - UINT32 index; + UINT32 data = enabled; + xfContext* xfc = clipboard->xfc; + + XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_transfer_atom, + XA_INTEGER, 32, PropModeReplace, (BYTE*) &data, 1); +} + +static BOOL xf_cliprdr_is_raw_transfer_available(xfClipboard* clipboard) +{ + Atom type; + int format; + int result = 0; + unsigned long length; + unsigned long bytes_left; + UINT32* data = NULL; + UINT32 is_enabled = 0; + Window owner = None; + xfContext* xfc = clipboard->xfc; + + owner = XGetSelectionOwner(xfc->display, clipboard->clipboard_atom); + + if (owner != None) + { + result = XGetWindowProperty(xfc->display, owner, + clipboard->raw_transfer_atom, 0, 4, 0, XA_INTEGER, + &type, &format, &length, &bytes_left, (BYTE**) &data); + } + + if (data) + { + is_enabled = *data; + XFree(data); + } + + if ((owner == None) || (owner == xfc->drawable)) + return FALSE; + + if (result != Success) + return FALSE; + + return is_enabled ? TRUE : FALSE; +} + +static BOOL xf_cliprdr_formats_equal(const CLIPRDR_FORMAT* server, const xfCliprdrFormat* client) +{ + if (server->formatName && client->formatName) + { + /* The server may be using short format names while we store them in full form. */ + return (0 == strncmp(server->formatName, client->formatName, strlen(server->formatName))); + } + + if (!server->formatName && !client->formatName) + { + return (server->formatId == client->formatId); + } + + return FALSE; +} + +static xfCliprdrFormat* xf_cliprdr_get_client_format_by_id(xfClipboard* clipboard, UINT32 formatId) +{ + int index; xfCliprdrFormat* format; for (index = 0; index < clipboard->numClientFormats; index++) @@ -138,25 +205,41 @@ static xfCliprdrFormat* xf_cliprdr_get_format_by_id(xfClipboard* clipboard, UINT return NULL; } -static xfCliprdrFormat* xf_cliprdr_get_format_by_atom(xfClipboard* clipboard, Atom atom) +static xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom(xfClipboard* clipboard, Atom atom) { - int i, j; + int i; xfCliprdrFormat* format; for (i = 0; i < clipboard->numClientFormats; i++) { format = &(clipboard->clientFormats[i]); - if (format->atom != atom) - continue; - - if (format->formatId == 0) + if (format->atom == atom) return format; + } - for (j = 0; j < clipboard->numServerFormats; j++) + return NULL; +} + +static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom(xfClipboard* clipboard, Atom atom) +{ + int i, j; + xfCliprdrFormat* client_format; + CLIPRDR_FORMAT* server_format; + + for (i = 0; i < clipboard->numClientFormats; i++) + { + client_format = &(clipboard->clientFormats[i]); + + if (client_format->atom == atom) { - if (clipboard->serverFormats[j].formatId == format->formatId) - return format; + for (j = 0; j < clipboard->numServerFormats; j++) + { + server_format = &(clipboard->serverFormats[j]); + + if (xf_cliprdr_formats_equal(server_format, client_format)) + return server_format; + } } } @@ -190,14 +273,170 @@ static UINT xf_cliprdr_send_data_response(xfClipboard* clipboard, BYTE* data, in ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); - response.msgFlags = CB_RESPONSE_OK; + response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; response.dataLen = size; response.requestedFormatData = data; return clipboard->context->ClientFormatDataResponse(clipboard->context, &response); } -static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) +static wStream* xf_cliprdr_serialize_server_format_list(xfClipboard* clipboard) +{ + UINT32 i; + UINT32 formatCount; + wStream* s = NULL; + + /* Typical MS Word format list is about 80 bytes long. */ + if (!(s = Stream_New(NULL, 128))) + { + WLog_ERR(TAG, "failed to allocate serialized format list"); + goto error; + } + + /* If present, the last format is always synthetic CF_RAW. Do not include it. */ + formatCount = (clipboard->numServerFormats > 0) ? clipboard->numServerFormats - 1 : 0; + + Stream_Write_UINT32(s, formatCount); + + for (i = 0; i < formatCount; i++) + { + CLIPRDR_FORMAT* format = &clipboard->serverFormats[i]; + size_t name_length = format->formatName ? strlen(format->formatName) : 0; + + if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32) + name_length + 1)) + { + WLog_ERR(TAG, "failed to expand serialized format list"); + goto error; + } + + Stream_Write_UINT32(s, format->formatId); + Stream_Write(s, format->formatName, name_length); + Stream_Write_UINT8(s, '\0'); + } + + Stream_SealLength(s); + + return s; + +error: + Stream_Free(s, TRUE); + return NULL; +} + +static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data, size_t length, UINT32* numFormats) +{ + UINT32 i; + wStream* s = NULL; + CLIPRDR_FORMAT* formats = NULL; + + if (!(s = Stream_New(data, length))) + { + WLog_ERR(TAG, "failed to allocate stream for parsing serialized format list"); + goto error; + } + + if (Stream_GetRemainingLength(s) < sizeof(UINT32)) + { + WLog_ERR(TAG, "too short serialized format list"); + goto error; + } + + Stream_Read_UINT32(s, *numFormats); + + if (*numFormats > MAX_CLIPBOARD_FORMATS) + { + WLog_ERR(TAG, "unexpectedly large number of formats: %u", *numFormats); + goto error; + } + + if (!(formats = (CLIPRDR_FORMAT*) calloc(*numFormats, sizeof(CLIPRDR_FORMAT)))) + { + WLog_ERR(TAG, "failed to allocate format list"); + goto error; + } + + for (i = 0; i < *numFormats; i++) + { + const char* formatName = NULL; + size_t formatNameLength = 0; + + if (Stream_GetRemainingLength(s) < sizeof(UINT32)) + { + WLog_ERR(TAG, "unexpected end of serialized format list"); + goto error; + } + + Stream_Read_UINT32(s, formats[i].formatId); + + formatName = (const char*) Stream_Pointer(s); + formatNameLength = strnlen(formatName, Stream_GetRemainingLength(s)); + + if (formatNameLength == Stream_GetRemainingLength(s)) + { + WLog_ERR(TAG, "missing terminating null byte, %zu bytes left to read", formatNameLength); + goto error; + } + + formats[i].formatName = strndup(formatName, formatNameLength); + Stream_Seek(s, formatNameLength + 1); + } + + Stream_Free(s, FALSE); + + return formats; + +error: + Stream_Free(s, FALSE); + free(formats); + *numFormats = 0; + return NULL; +} + +static void xf_cliprdr_free_formats(CLIPRDR_FORMAT* formats, UINT32 numFormats) +{ + UINT32 i; + + for (i = 0; i < numFormats; i++) + { + free(formats[i].formatName); + } + + free(formats); +} + +static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard, UINT32* numFormats) +{ + Atom type = None; + int format = 0; + unsigned long length = 0; + unsigned long remaining; + BYTE* data = NULL; + CLIPRDR_FORMAT* formats = NULL; + xfContext* xfc = clipboard->xfc; + + *numFormats = 0; + + XGetWindowProperty(xfc->display, clipboard->owner, clipboard->raw_format_list_atom, + 0, 4096, False, clipboard->raw_format_list_atom, &type, &format, + &length, &remaining, &data); + + if (data && length > 0 && format == 8 && type == clipboard->raw_format_list_atom) + { + formats = xf_cliprdr_parse_server_format_list(data, length, numFormats); + } + else + { + WLog_ERR(TAG, "failed to retrieve raw format list: data=%p, length=%lu, format=%d, type=%d (expected=%d)", + data, length, format, type, clipboard->raw_format_list_atom); + } + + if (data) + XFree(data); + + return formats; +} + +static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets(xfClipboard* clipboard, UINT32* numFormats) { int i; Atom atom; @@ -205,14 +444,11 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) int format_property; unsigned long length; unsigned long bytes_left; - UINT32 numFormats = 0; - CLIPRDR_FORMAT_LIST formatList; xfCliprdrFormat* format = NULL; CLIPRDR_FORMAT* formats = NULL; xfContext* xfc = clipboard->xfc; - if (!clipboard->numServerFormats) - return; /* server format list was not yet received */ + *numFormats = 0; XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, 0, 200, 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data); @@ -235,16 +471,73 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) { atom = ((Atom*) data)[i]; - format = xf_cliprdr_get_format_by_atom(clipboard, atom); + format = xf_cliprdr_get_client_format_by_atom(clipboard, atom); if (format) { - formats[numFormats].formatId = format->formatId; - formats[numFormats].formatName = format->formatName; - numFormats++; + formats[*numFormats].formatId = format->formatId; + formats[*numFormats].formatName = _strdup(format->formatName); + *numFormats += 1; } } +out: + if (data) + XFree(data); + + return formats; +} + +static CLIPRDR_FORMAT* xf_cliprdr_get_client_formats(xfClipboard* clipboard, UINT32* numFormats) +{ + CLIPRDR_FORMAT* formats = NULL; + + *numFormats = 0; + + if (xf_cliprdr_is_raw_transfer_available(clipboard)) + { + formats = xf_cliprdr_get_raw_server_formats(clipboard, numFormats); + } + + if (*numFormats == 0) + { + xf_cliprdr_free_formats(formats, *numFormats); + + formats = xf_cliprdr_get_formats_from_targets(clipboard, numFormats); + } + + return formats; +} + +static void xf_cliprdr_provide_server_format_list(xfClipboard* clipboard) +{ + wStream* formats = NULL; + xfContext* xfc = clipboard->xfc; + + formats = xf_cliprdr_serialize_server_format_list(clipboard); + + if (formats) + { + XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_format_list_atom, + clipboard->raw_format_list_atom, 8, PropModeReplace, + Stream_Buffer(formats), Stream_Length(formats)); + } + else + { + XDeleteProperty(xfc->display, xfc->drawable, clipboard->raw_format_list_atom); + } + + Stream_Free(formats, TRUE); +} + +static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) +{ + UINT32 numFormats = 0; + CLIPRDR_FORMAT* formats = NULL; + CLIPRDR_FORMAT_LIST formatList; + + formats = xf_cliprdr_get_client_formats(clipboard, &numFormats); + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); formatList.msgFlags = CB_RESPONSE_OK; @@ -253,10 +546,7 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard) clipboard->context->ClientFormatList(clipboard->context, &formatList); -out: - if (data) - XFree(data); - free(formats); + xf_cliprdr_free_formats(formats, numFormats); } static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, int size) @@ -264,8 +554,8 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa BOOL bSuccess; UINT32 SrcSize; UINT32 DstSize; - UINT32 formatId; - UINT32 altFormatId; + UINT32 srcFormatId; + UINT32 dstFormatId; BYTE* pSrcData = NULL; BYTE* pDstData = NULL; xfCliprdrFormat* format; @@ -273,7 +563,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa if (clipboard->incr_starts && hasData) return; - format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (!hasData || !data || !format) { @@ -281,25 +571,29 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa return; } - formatId = 0; - altFormatId = 0; + srcFormatId = 0; + dstFormatId = 0; switch (format->formatId) { + case CF_RAW: + srcFormatId = CF_RAW; + break; + case CF_TEXT: case CF_OEMTEXT: case CF_UNICODETEXT: size = strlen((char*) data) + 1; - formatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); + srcFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; case CF_DIB: - formatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); + srcFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; case CB_FORMAT_HTML: size = strlen((char*) data) + 1; - formatId = ClipboardGetFormatId(clipboard->system, "text/html"); + srcFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); break; } @@ -311,17 +605,24 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasDa CopyMemory(pSrcData, data, SrcSize); - bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); + bSuccess = ClipboardSetData(clipboard->system, srcFormatId, (void*) pSrcData, SrcSize); if (!bSuccess) free(pSrcData); - altFormatId = clipboard->requestedFormatId; + if (format->formatName) + { + dstFormatId = ClipboardGetFormatId(clipboard->system, format->formatName); + } + else + { + dstFormatId = format->formatId; + } - if (bSuccess && altFormatId) + if (bSuccess) { DstSize = 0; - pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); + pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); } if (!pDstData) @@ -346,7 +647,7 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) xfCliprdrFormat* format; xfContext* xfc = clipboard->xfc; - format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (!format || (format->atom != target)) { @@ -495,13 +796,14 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent* int fmt; Atom type; UINT32 formatId; + const char* formatName; XEvent* respond; - UINT32 altFormatId; BYTE* data = NULL; BOOL delayRespond; + BOOL rawTransfer; unsigned long length; unsigned long bytes_left; - xfCliprdrFormat* format; + CLIPRDR_FORMAT* format; xfContext* xfc = clipboard->xfc; if (xevent->xselectionrequest.owner != xfc->drawable) @@ -535,14 +837,15 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent* } else { - format = xf_cliprdr_get_format_by_atom(clipboard, xevent->xselectionrequest.target); + format = xf_cliprdr_get_server_format_by_atom(clipboard, xevent->xselectionrequest.target); if (format && (xevent->xselectionrequest.requestor != xfc->drawable)) { formatId = format->formatId; - altFormatId = formatId; + formatName = format->formatName; + rawTransfer = FALSE; - if (formatId == 0) + if (formatId == CF_RAW) { if (XGetWindowProperty(xfc->display, xevent->xselectionrequest.requestor, clipboard->property_atom, 0, 4, 0, XA_INTEGER, @@ -553,12 +856,13 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent* if (data) { - CopyMemory(&altFormatId, data, 4); + rawTransfer = TRUE; + CopyMemory(&formatId, data, 4); XFree(data); } } - if ((clipboard->data != 0) && (formatId == clipboard->data_format) && (altFormatId == clipboard->data_alt_format)) + if ((clipboard->data != 0) && (formatId == clipboard->data_format_id) && (formatName == clipboard->data_format_name)) { /* Cached clipboard data available. Send it now */ respond->xselection.property = xevent->xselectionrequest.property; @@ -582,11 +886,12 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, XEvent* respond->xselection.property = xevent->xselectionrequest.property; clipboard->respond = respond; - clipboard->data_format = formatId; - clipboard->data_alt_format = altFormatId; + clipboard->data_format_id = formatId; + clipboard->data_format_name = formatName; + clipboard->data_raw_format = rawTransfer; delayRespond = TRUE; - xf_cliprdr_send_data_request(clipboard, altFormatId); + xf_cliprdr_send_data_request(clipboard, formatId); } } } @@ -631,7 +936,7 @@ static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, XEvent* x else if ((xevent->xproperty.window == xfc->drawable) && (xevent->xproperty.state == PropertyNewValue) && clipboard->incr_starts) { - format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (format) xf_cliprdr_get_requested_data(clipboard, format->atom); @@ -787,24 +1092,6 @@ UINT xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard, BOOL st return clipboard->context->ClientFormatListResponse(clipboard->context, &formatListResponse); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -int xf_cliprdr_send_client_format_data_request(xfClipboard* clipboard, UINT32 formatId) -{ - CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; - - formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; - formatDataRequest.msgFlags = CB_RESPONSE_OK; - - formatDataRequest.requestedFormatId = formatId; - clipboard->requestedFormatId = formatId; - - return clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); -} - /** * Function description * @@ -856,6 +1143,9 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR clipboard->data = NULL; } + clipboard->data_format_id = -1; + clipboard->data_format_name = NULL; + if (clipboard->serverFormats) { for (i = 0; i < clipboard->numServerFormats; i++) @@ -867,14 +1157,11 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR clipboard->numServerFormats = 0; } - clipboard->numServerFormats = formatList->numFormats; + clipboard->numServerFormats = formatList->numFormats + 1; /* +1 for CF_RAW */ - if (clipboard->numServerFormats) - { - if (!(clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc(clipboard->numServerFormats, sizeof(CLIPRDR_FORMAT)))) { - WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs", clipboard->numServerFormats); - return CHANNEL_RC_NO_MEMORY; - } + if (!(clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc(clipboard->numServerFormats, sizeof(CLIPRDR_FORMAT)))) { + WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs", clipboard->numServerFormats); + return CHANNEL_RC_NO_MEMORY; } for (i = 0; i < formatList->numFormats; i++) @@ -897,6 +1184,13 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR } } + /* CF_RAW is always implicitly supported by the server */ + format = &clipboard->serverFormats[formatList->numFormats]; + format->formatId = CF_RAW; + format->formatName = NULL; + + xf_cliprdr_provide_server_format_list(clipboard); + clipboard->numTargets = 2; for (i = 0; i < formatList->numFormats; i++) @@ -905,7 +1199,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, CLIPRDR for (j = 0; j < clipboard->numClientFormats; j++) { - if (format->formatId == clipboard->clientFormats[j].formatId) + if (xf_cliprdr_formats_equal(format, &clipboard->clientFormats[j])) { xf_cliprdr_append_target(clipboard, clipboard->clientFormats[j].atom); } @@ -940,25 +1234,28 @@ static UINT xf_cliprdr_server_format_list_response(CliprdrClientContext* context */ static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { + BOOL rawTransfer; xfCliprdrFormat* format = NULL; UINT32 formatId = formatDataRequest->requestedFormatId; xfClipboard* clipboard = (xfClipboard*) context->custom; xfContext* xfc = clipboard->xfc; - if (xf_cliprdr_is_self_owned(clipboard)) + rawTransfer = xf_cliprdr_is_raw_transfer_available(clipboard); + + if (rawTransfer) { - format = xf_cliprdr_get_format_by_id(clipboard, 0); + format = xf_cliprdr_get_client_format_by_id(clipboard, CF_RAW); XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom, XA_INTEGER, 32, PropModeReplace, (BYTE*) &formatId, 1); } else - format = xf_cliprdr_get_format_by_id(clipboard, formatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, formatId); if (!format) return xf_cliprdr_send_data_response(clipboard, NULL, 0); - clipboard->requestedFormatId = formatId; + clipboard->requestedFormatId = rawTransfer ? CF_RAW : formatId; XConvertSelection(xfc->display, clipboard->clipboard_atom, format->atom, clipboard->property_atom, xfc->drawable, CurrentTime); @@ -982,9 +1279,8 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* context BYTE* pDstData; UINT32 DstSize; UINT32 SrcSize; - UINT32 formatId; - UINT32 altFormatId; - xfCliprdrFormat* format; + UINT32 srcFormatId; + UINT32 dstFormatId; BOOL nullTerminated = FALSE; UINT32 size = formatDataResponse->dataLen; BYTE* data = formatDataResponse->requestedFormatData; @@ -994,8 +1290,6 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* context if (!clipboard->respond) return CHANNEL_RC_OK; - format = xf_cliprdr_get_format_by_id(clipboard, clipboard->requestedFormatId); - if (clipboard->data) { free(clipboard->data); @@ -1005,39 +1299,50 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* context pDstData = NULL; DstSize = 0; - formatId = 0; - altFormatId = 0; + srcFormatId = 0; + dstFormatId = 0; - switch (clipboard->data_format) + if (clipboard->data_raw_format) { + srcFormatId = CF_RAW; + dstFormatId = CF_RAW; + } + else if (clipboard->data_format_name) + { + if (strcmp(clipboard->data_format_name, "HTML Format") == 0) + { + srcFormatId = ClipboardGetFormatId(clipboard->system, "HTML Format"); + dstFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); + nullTerminated = TRUE; + } + } + else + { + switch (clipboard->data_format_id) + { case CF_TEXT: - formatId = CF_TEXT; - altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); + srcFormatId = CF_TEXT; + dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_OEMTEXT: - formatId = CF_OEMTEXT; - altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); + srcFormatId = CF_OEMTEXT; + dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_UNICODETEXT: - formatId = CF_UNICODETEXT; - altFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); + srcFormatId = CF_UNICODETEXT; + dstFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); nullTerminated = TRUE; break; case CF_DIB: - formatId = CF_DIB; - altFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); - break; - - case CB_FORMAT_HTML: - formatId = ClipboardGetFormatId(clipboard->system, "HTML Format"); - altFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); - nullTerminated = TRUE; + srcFormatId = CF_DIB; + dstFormatId = ClipboardGetFormatId(clipboard->system, "image/bmp"); break; + } } SrcSize = (UINT32) size; @@ -1048,18 +1353,21 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* context CopyMemory(pSrcData, data, SrcSize); - bSuccess = ClipboardSetData(clipboard->system, formatId, (void*) pSrcData, SrcSize); + bSuccess = ClipboardSetData(clipboard->system, srcFormatId, (void*) pSrcData, SrcSize); if (!bSuccess) free (pSrcData); - if (bSuccess && altFormatId) + if (bSuccess) { DstSize = 0; - pDstData = (BYTE*) ClipboardGetData(clipboard->system, altFormatId, &DstSize); + pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); - if ((DstSize > 1) && nullTerminated) - DstSize--; + if (nullTerminated) + { + while (DstSize > 0 && pDstData[DstSize - 1] == '\0') + DstSize--; + } } clipboard->data = pDstData; @@ -1111,6 +1419,11 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) clipboard->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE); + clipboard->raw_transfer_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_RAW", FALSE); + clipboard->raw_format_list_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_FORMATS", FALSE); + + xf_cliprdr_set_raw_transfer_enabled(clipboard, TRUE); + XSelectInput(xfc->display, clipboard->root_window, PropertyChangeMask); #ifdef WITH_XFIXES @@ -1140,7 +1453,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) n = 0; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "_FREERDP_RAW", False); - clipboard->clientFormats[n].formatId = 0; + clipboard->clientFormats[n].formatId = CF_RAW; n++; clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "UTF8_STRING", False); diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 22a941c53..6b49d5684 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -290,15 +290,29 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI { char* title = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); + if (windowState->titleInfo.length == 0) + { + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); + /* error handled below */ + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); + /* error handled below */ + } appWindow->title = title; } else { - appWindow->title = _strdup("RdpRailWindow"); + if (!(appWindow->title = _strdup("RdpRailWindow"))) + WLog_ERR(TAG, "failed to duplicate default window title string"); } + if (!appWindow->title) { free(appWindow); @@ -365,9 +379,20 @@ static BOOL xf_rail_window_common(rdpContext* context, WINDOW_ORDER_INFO* orderI { char* title = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL); - + if (windowState->titleInfo.length == 0) + { + if (!(title = _strdup(""))) + { + WLog_ERR(TAG, "failed to duplicate empty window title string"); + return FALSE; + } + } + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert window title"); + return FALSE; + } free(appWindow->title); appWindow->title = title; } diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index 5502696d9..95c8e98e0 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -39,7 +39,7 @@ foreach(FREERDP_CHANNELS_CLIENT_SRC ${FREERDP_CHANNELS_CLIENT_SRCS}) endforeach() if(MSVC) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}) endif() # On windows create dll version information. diff --git a/client/common/client.c b/client/common/client.c index 4da191912..a847c9b34 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -21,14 +21,21 @@ #include "config.h" #endif +#include +#include + #include #include #include #include +#include #include #include +#include +#define TAG CLIENT_TAG("common") + static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context) { RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints; @@ -296,3 +303,213 @@ int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const c return 0; } +/** Callback set in the rdp_freerdp structure, and used to get the user's password, + * if required to establish the connection. + * This function is actually called in credssp_ntlmssp_client_init() + * @see rdp_server_accept_nego() and rdp_check_fds() + * @param instance - pointer to the rdp_freerdp structure that contains the connection settings + * @param username - unused + * @param password - on return: pointer to a character string that will be filled by the password entered by the user. + * Note that this character string will be allocated inside the function, and needs to be deallocated by the caller + * using free(), even in case this function fails. + * @param domain - unused + * @return TRUE if a password was successfully entered. See freerdp_passphrase_read() for more details. + */ +static BOOL client_cli_authenticate_raw(freerdp* instance, BOOL gateway, char** username, + char** password, char** domain) +{ + static const size_t password_size = 512; + const char* auth[] = + { + "Username: ", + "Domain: ", + "Password: " + }; + const char* gw[] = + { + "GatewayUsername: ", + "GatewayDomain: ", + "GatewayPassword: " + }; + const char** prompt = (gateway) ? gw : auth; + + if (!username || !password || !domain) + return FALSE; + + if (!*username) + { + size_t username_size = 0; + printf("%s", prompt[0]); + if (GetLine(username, &username_size, stdin) < 0) + { + WLog_ERR(TAG, "GetLine returned %s [%d]", strerror(errno), errno); + goto fail; + } + + if (*username) + { + *username = StrSep(username, "\r"); + *username = StrSep(username, "\n"); + } + } + + if (!*domain) + { + size_t domain_size = 0; + printf("%s", prompt[1]); + if (GetLine(domain, &domain_size, stdin) < 0) + { + WLog_ERR(TAG, "GetLine returned %s [%d]", strerror(errno), errno); + goto fail; + } + + if (*domain) + { + *domain = StrSep(domain, "\r"); + *domain = StrSep(domain, "\n"); + } + } + + if (!*password) + { + *password = calloc(password_size, sizeof(char)); + if (!*password) + goto fail; + + if (freerdp_passphrase_read(prompt[2], *password, password_size, + instance->settings->CredentialsFromStdin) == NULL) + goto fail; + } + + return TRUE; + +fail: + free(*username); + free(*domain); + free(*password); + + *username = NULL; + *domain = NULL; + *password = NULL; + + return FALSE; +} + +BOOL client_cli_authenticate(freerdp* instance, char** username, char** password, char** domain) +{ + return client_cli_authenticate_raw(instance, FALSE, username, password, domain); +} + +BOOL client_cli_gw_authenticate(freerdp* instance, char** username, char** password, char** domain) +{ + return client_cli_authenticate_raw(instance, TRUE, username, password, domain); +} + +static DWORD client_cli_accept_certificate(rdpSettings* settings) +{ + char answer; + + if (settings->CredentialsFromStdin) + return 0; + + while (1) + { + printf("Do you trust the above certificate? (Y/T/N) "); + answer = fgetc(stdin); + + if (feof(stdin)) + { + printf("\nError: Could not read answer from stdin."); + if (settings->CredentialsFromStdin) + printf(" - Run without parameter \"--from-stdin\" to set trust."); + printf("\n"); + return 0; + } + + switch(answer) + { + case 'y': + case 'Y': + return 1; + case 't': + case 'T': + return 2; + case 'n': + case 'N': + return 0; + default: + break; + } + printf("\n"); + } + + return 0; +} + +/** Callback set in the rdp_freerdp structure, and used to make a certificate validation + * when the connection requires it. + * This function will actually be called by tls_verify_certificate(). + * @see rdp_client_connect() and tls_connect() + * @param instance - pointer to the rdp_freerdp structure that contains the connection settings + * @param common_name + * @param subject + * @param issuer + * @param fingerprint + * @param host_mismatch Indicates the certificate host does not match. + * @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise. + */ +DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, BOOL host_mismatch) +{ + printf("Certificate details:\n"); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fingerprint); + printf("The above X.509 certificate could not be verified, possibly because you do not have\n" + "the CA certificate in your certificate store, or the certificate has expired.\n" + "Please look at the documentation on how to create local certificate store for a private CA.\n"); + + return client_cli_accept_certificate(instance->settings); +} + +/** Callback set in the rdp_freerdp structure, and used to make a certificate validation + * when a stored certificate does not match the remote counterpart. + * This function will actually be called by tls_verify_certificate(). + * @see rdp_client_connect() and tls_connect() + * @param instance - pointer to the rdp_freerdp structure that contains the connection settings + * @param common_name + * @param subject + * @param issuer + * @param fingerprint + * @param old_subject + * @param old_issuer + * @param old_fingerprint + * @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise. + */ +DWORD client_cli_verify_changed_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, + const char* old_subject, const char* old_issuer, + const char* old_fingerprint) +{ + printf("!!! Certificate has changed !!!\n"); + printf("\n"); + printf("New Certificate details:\n"); + printf("\tSubject: %s\n", subject); + printf("\tIssuer: %s\n", issuer); + printf("\tThumbprint: %s\n", fingerprint); + printf("\n"); + printf("Old Certificate details:\n"); + printf("\tSubject: %s\n", old_subject); + printf("\tIssuer: %s\n", old_issuer); + printf("\tThumbprint: %s\n", old_fingerprint); + printf("\n"); + printf("The above X.509 certificate does not match the certificate used for previous connections.\n" + "This may indicate that the certificate has been tampered with.\n" + "Please contact the administrator of the RDP server and clarify.\n"); + + return client_cli_accept_certificate(instance->settings); +} + + diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 756ae1f3a..76a5b8dee 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -4,6 +4,7 @@ * * Copyright 2012 Marc-Andre Moreau * Copyright 2014 Norbert Federa + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -175,6 +176,12 @@ static COMMAND_LINE_ARGUMENT_A args[] = { "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, NULL, NULL, NULL, -1, NULL, "print the build configuration" }, { "log-level", COMMAND_LINE_VALUE_REQUIRED, "[OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE]", NULL, NULL, -1, NULL, "Set the default log level" }, { "log-filters", COMMAND_LINE_VALUE_REQUIRED, ":[, :][, ...]]", NULL, NULL, -1, NULL, "Set logger filters" }, + { "pwidth", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Physical width of display (in millimeters)" }, + { "pheight", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Physical height of display (in millimeters)" }, + { "orientation", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Orientation of display in degrees (0, 90, 180, 270)" }, + { "scale", COMMAND_LINE_VALUE_REQUIRED, "", "100", NULL, -1, NULL, "Scaling factor of the display (value of 100, 140, or 180)" }, + { "scale-desktop", COMMAND_LINE_VALUE_REQUIRED, "", "100", NULL, -1, NULL, "Scaling factor for desktop applications (value between 100 and 500)" }, + { "scale-device", COMMAND_LINE_VALUE_REQUIRED, "", "100", NULL, -1, NULL, "Scaling factor for app store applications (100, 140, or 180)" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -1305,7 +1312,7 @@ int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, } static BOOL freerdp_client_detect_command_line(int argc, char** argv, - DWORD* flags, BOOL ignoreUnknown) + DWORD* flags, BOOL ignoreUnknown) { int old_cli_status; int old_cli_count; @@ -1678,7 +1685,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { id = (unsigned long int) freerdp_map_keyboard_layout_name_to_id(arg->Value); if (id == -1) - WLog_ERR(TAG, "A problem occured while mapping the layout name to id"); + WLog_ERR(TAG, "A problem occurred while mapping the layout name to id"); else if (id == 0) { WLog_ERR(TAG, "Could not identify keyboard layout: %s", arg->Value); @@ -2289,6 +2296,55 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!(settings->RemoteAssistancePassword = _strdup(arg->Value))) return COMMAND_LINE_ERROR_MEMORY; } + CommandLineSwitchCase(arg, "pwidth") + { + settings->DesktopPhysicalWidth = atoi(arg->Value); + } + CommandLineSwitchCase(arg, "pheight") + { + settings->DesktopPhysicalHeight = atoi(arg->Value); + } + CommandLineSwitchCase(arg, "orientation") + { + settings->DesktopOrientation = atoi(arg->Value); + } + CommandLineSwitchCase(arg, "scale") + { + int scaleFactor = atoi(arg->Value); + if (scaleFactor == 100 || scaleFactor == 140 || scaleFactor == 180) { + settings->DesktopScaleFactor = scaleFactor; + settings->DeviceScaleFactor = scaleFactor; + } else { + WLog_ERR(TAG, "scale: invalid scale factor (%d)", scaleFactor); + return COMMAND_LINE_ERROR; + } + } + CommandLineSwitchCase(arg, "scale-desktop") + { + int desktopScaleFactor = atoi(arg->Value); + if (desktopScaleFactor >= 100 && desktopScaleFactor <= 500) + { + settings->DesktopScaleFactor = desktopScaleFactor; + } + else + { + WLog_ERR(TAG, "scale: invalid desktop scale factor (%d)", desktopScaleFactor); + return COMMAND_LINE_ERROR; + } + } + CommandLineSwitchCase(arg, "scale-device") + { + int deviceScaleFactor = atoi(arg->Value); + if (deviceScaleFactor == 100 || deviceScaleFactor == 140 || deviceScaleFactor == 180) + { + settings->DeviceScaleFactor = deviceScaleFactor; + } + else + { + WLog_ERR(TAG, "scale: invalid device scale factor (%d)", deviceScaleFactor); + return COMMAND_LINE_ERROR; + } + } CommandLineSwitchDefault(arg) { } @@ -2453,28 +2509,34 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) { RDPDR_SMARTCARD* smartcard; - smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD)); + if (!freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD)) + { + smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD)); - if (!smartcard) - return FALSE; + if (!smartcard) + return FALSE; - smartcard->Type = RDPDR_DTYP_SMARTCARD; - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) smartcard)) - return FALSE; + smartcard->Type = RDPDR_DTYP_SMARTCARD; + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) smartcard)) + return FALSE; + } } if (settings->RedirectPrinters) { RDPDR_PRINTER* printer; - printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER)); + if (!freerdp_device_collection_find_type(settings, RDPDR_DTYP_PRINT)) + { + printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER)); - if (!printer) - return FALSE; + if (!printer) + return FALSE; - printer->Type = RDPDR_DTYP_PRINT; - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) printer)) - return FALSE; + printer->Type = RDPDR_DTYP_PRINT; + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) printer)) + return FALSE; + } } if (settings->RedirectClipboard) diff --git a/client/common/module.def b/client/common/module.def deleted file mode 100644 index f54443e02..000000000 --- a/client/common/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "freerdp-client" -EXPORTS - diff --git a/client/iOS/FreeRDP/ios_freerdp_ui.h b/client/iOS/FreeRDP/ios_freerdp_ui.h index 9da8748e6..91389ddf9 100644 --- a/client/iOS/FreeRDP/ios_freerdp_ui.h +++ b/client/iOS/FreeRDP/ios_freerdp_ui.h @@ -14,8 +14,15 @@ BOOL ios_ui_end_paint(rdpContext * context); BOOL ios_ui_resize_window(rdpContext * context); BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, char** domain); -BOOL ios_ui_check_certificate(freerdp * instance, char * subject, char * issuer, char * fingerprint); -BOOL ios_ui_check_changed_certificate(freerdp * instance, char * subject, char * issuer, char * new_fingerprint, char * old_fingerprint); +DWORD ios_ui_check_certificate(freerdp * instance, const char* common_name, + const char * subject, const char * issuer, + const char * fingerprint, BOOL host_mismatch); +DWORD ios_ui_check_changed_certificate(freerdp * instance, + const char* common_name, + const char * subject, + const char * issuer, + const char * new_fingerprint, + const char * old_fingerprint); void ios_allocate_display_buffer(mfInfo* mfi); void ios_resize_display_buffer(mfInfo* mfi); diff --git a/client/iOS/FreeRDP/ios_freerdp_ui.m b/client/iOS/FreeRDP/ios_freerdp_ui.m index 191b25ec2..cd17da0bc 100644 --- a/client/iOS/FreeRDP/ios_freerdp_ui.m +++ b/client/iOS/FreeRDP/ios_freerdp_ui.m @@ -63,39 +63,47 @@ BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, c return TRUE; } -BOOL ios_ui_check_certificate(freerdp * instance, char * subject, char * issuer, char * fingerprint) +DWORD ios_ui_check_certificate(freerdp * instance, const char* common_name, + const char * subject, const char * issuer, + const char * fingerprint, BOOL host_mismatch) { - // check whether we accept all certificates - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"] == YES) - return TRUE; - + // check whether we accept all certificates + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"] == YES) + return 2; + mfInfo* mfi = MFI_FROM_INSTANCE(instance); NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys: - (subject) ? [NSString stringWithUTF8String:subject] : @"", @"subject", - (issuer) ? [NSString stringWithUTF8String:issuer] : @"", @"issuer", - (fingerprint) ? [NSString stringWithUTF8String:subject] : @"", @"fingerprint", - nil]; - - // request certificate verification UI - [mfi->session performSelectorOnMainThread:@selector(sessionVerifyCertificateWithParams:) withObject:params waitUntilDone:YES]; - - // wait for UI request to be completed - [[mfi->session uiRequestCompleted] lock]; - [[mfi->session uiRequestCompleted] wait]; - [[mfi->session uiRequestCompleted] unlock]; - + (subject) ? [NSString stringWithUTF8String:subject] : @"", @"subject", + (issuer) ? [NSString stringWithUTF8String:issuer] : @"", @"issuer", + (fingerprint) ? [NSString stringWithUTF8String:subject] : @"", @"fingerprint", + nil]; + + // request certificate verification UI + [mfi->session performSelectorOnMainThread:@selector(sessionVerifyCertificateWithParams:) withObject:params waitUntilDone:YES]; + + // wait for UI request to be completed + [[mfi->session uiRequestCompleted] lock]; + [[mfi->session uiRequestCompleted] wait]; + [[mfi->session uiRequestCompleted] unlock]; + if (![[params valueForKey:@"result"] boolValue]) { mfi->unwanted = YES; - return FALSE; + return 0; } - - return TRUE; + + return 1; } -BOOL ios_ui_check_changed_certificate(freerdp * instance, char * subject, char * issuer, char * new_fingerprint, char * old_fingerprint) +DWORD ios_ui_check_changed_certificate(freerdp * instance, + const char * common_name, + const char * subject, + const char * issuer, + const char * new_fingerprint, + const char * old_fingerprint) { - return ios_ui_check_certificate(instance, subject, issuer, new_fingerprint); + return ios_ui_check_certificate(instance, common_name, subject, issuer, + new_fingerprint, FALSE); } diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake index a34fdb2d5..ee217f61d 100644 --- a/cmake/FindWayland.cmake +++ b/cmake/FindWayland.cmake @@ -1,19 +1,16 @@ -# - Find Wayland -# Find the Wayland libraries +# - Finds Wayland +# Find the Wayland libraries that are needed for UWAC # # This module defines the following variables: -# WAYLAND_FOUND - true if WAYLAND_INCLUDE_DIR & WAYLAND_LIBRARY are found -# WAYLAND_LIBRARIES - Set when WAYLAND_LIBRARY is found -# WAYLAND_INCLUDE_DIRS - Set when WAYLAND_INCLUDE_DIR is found -# -# WAYLAND_INCLUDE_DIR - where to find wayland-client.h, etc. -# WAYLAND_LIBRARY - the Wayland client library -# WAYLAND_VERSION - wayland client version if found and pkg-config was used +# WAYLAND_FOUND - true if UWAC has been found +# WAYLAND_LIBS - Set to the full path to wayland client libraries +# WAYLAND_INCLUDE_DIR - Set to the include directories for wayland +# XKBCOMMON_LIBS - Set to the full path to xkbcommon libraries +# XKBCOMMON_INCLUDE_DIR - Set to the include directories for xkbcommon # #============================================================================= -# Copyright 2014 Manuel Bachmann -# Copyright 2015 Bernhard Miklautz +# Copyright 2015 David Fort # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,38 +25,35 @@ # limitations under the License. #============================================================================= -set(REQUIRED_WAYLAND_CLIENT_VERSION 1.3.0) include(FindPkgConfig) if(PKG_CONFIG_FOUND) - pkg_check_modules(WAYLAND wayland-client) + pkg_check_modules(WAYLAND_SCANNER_PC wayland-scanner) + pkg_check_modules(WAYLAND_CLIENT_PC wayland-client) + pkg_check_modules(XKBCOMMON_PC xkbcommon) endif() -find_path(WAYLAND_INCLUDE_DIR NAMES wayland-client.h - PATHS ${WAYLAND_INCLUDE_DIRS} - DOC "The Wayland include directory" +find_program(WAYLAND_SCANNER wayland-scanner + HINTS "${WAYLAND_SCANNER_PC_PREFIX}/bin" ) -find_library(WAYLAND_LIBRARY NAMES wayland-client - PATHS ${WAYLAND_LIBRARY_DIRS} - DOC "The Wayland client library" +find_path(WAYLAND_INCLUDE_DIR wayland-client.h + HINTS ${WAYLAND_CLIENT_PC_INCLUDE_DIRS} +) + +find_library(WAYLAND_LIBS + NAMES "wayland-client" + HINTS "${WAYLAND_CLIENT_PC_LIBRARY_DIRS}" +) + +find_path(XKBCOMMON_INCLUDE_DIR xkbcommon/xkbcommon.h + HINTS ${XKBCOMMON_PC_INCLUDE_DIRS} +) + +find_library(XKBCOMMON_LIBS + NAMES xkbcommon + HINTS "${XKBCOMMON_PC_LIBRARY_DIRS}" ) include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARY WAYLAND_INCLUDE_DIR) - -if(WAYLAND_VERSION) - if (${WAYLAND_VERSION} VERSION_LESS ${REQUIRED_WAYLAND_CLIENT_VERSION}) - message(WARNING "Installed wayland version ${WAYLAND_VERSION} is too old - minimum required version ${REQUIRED_WAYLAND_CLIENT_VERSION}") - set(WAYLAND_FOUND FALSE) - endif() -else() - message(WARNING "Couldn't detect wayland version - no version check is done") -endif() - -if(WAYLAND_FOUND) - set(WAYLAND_LIBRARIES ${WAYLAND_LIBRARY}) - set(WAYLAND_INCLUDE_DIRS ${WAYLAND_INCLUDE_DIR}) -endif() - -mark_as_advanced(WAYLAND_INCLUDE_DIR WAYLAND_LIBRARY WAYLAND_VERSION) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_SCANNER WAYLAND_INCLUDE_DIR WAYLAND_LIBS XKBCOMMON_INCLUDE_DIR XKBCOMMON_LIBS) diff --git a/cmake/WindowsDLLVersion.rc.in b/cmake/WindowsDLLVersion.rc.in index cebd5f22a..5a0da5eae 100644 --- a/cmake/WindowsDLLVersion.rc.in +++ b/cmake/WindowsDLLVersion.rc.in @@ -19,7 +19,7 @@ BEGIN BEGIN VALUE "CompanyName", "@RC_VERSION_VENDOR@" VALUE "FileDescription", "@RC_VERSION_DESCRIPTION@" - VALUE "FileVersion", "@RC_VERSION_MAJOR@,@RC_VERSION_MINOR@,@RC_VERSION_BUILD@,@RC_VERSION_PATCH@" + VALUE "FileVersion", "@RC_VERSION_MAJOR@,@RC_VERSION_MINOR@,@RC_VERSION_PATCH@,@RC_VERSION_BUILD@" VALUE "InternalName", "@RC_VERSION_FILE@" VALUE "LegalCopyright", "Copyright (C) 2011-@RC_VERSION_YEAR@" VALUE "OriginalFilename", "@RC_VERSION_FILE@" diff --git a/include/freerdp/client.h b/include/freerdp/client.h index 39708c77e..f807b2fc2 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -94,6 +94,18 @@ FREERDP_API int freerdp_client_settings_write_connection_file(const rdpSettings* FREERDP_API int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, const char* filename); +FREERDP_API BOOL client_cli_authenticate(freerdp* instance, char** username, char** password, char** domain); +FREERDP_API BOOL client_cli_gw_authenticate(freerdp* instance, char** username, char** password, char** domain); + +FREERDP_API DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, BOOL host_mismatch); + +FREERDP_API DWORD client_cli_verify_changed_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, + const char* old_subject, const char* old_issuer, + const char* old_fingerprint); #ifdef __cplusplus } #endif diff --git a/include/freerdp/codec/region.h b/include/freerdp/codec/region.h index bced79140..18b947c2c 100644 --- a/include/freerdp/codec/region.h +++ b/include/freerdp/codec/region.h @@ -73,10 +73,10 @@ FREERDP_API void region16_init(REGION16 *region); /** @return the number of rectangles of this region16 */ FREERDP_API int region16_n_rects(const REGION16 *region); -/** returns a pointer on rectangles and the number of rectangles in this region. - * nbRect can be set to NULL if not interested by the numnber of rectangles. +/** returns a pointer to rectangles and the number of rectangles in this region. + * nbRects can be set to NULL if not interested in the number of rectangles. * @param region the input region - * @param nbRects a pointer that will be filled with the number of rectangles + * @param nbRects if non-NULL returns the number of rectangles * @return a pointer on the rectangles */ FREERDP_API const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRects); diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index 25d98bde3..bcd5ee60a 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -25,13 +25,8 @@ #include #include -#include -#include -#include -#include #include #include -#include #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) #define D2I_X509_CONST const @@ -43,31 +38,7 @@ #include #include - -struct crypto_sha1_struct -{ - SHA_CTX sha_ctx; -}; - -struct crypto_md5_struct -{ - MD5_CTX md5_ctx; -}; - -struct crypto_rc4_struct -{ - RC4_KEY rc4_key; -}; - -struct crypto_des3_struct -{ - EVP_CIPHER_CTX des3_ctx; -}; - -struct crypto_hmac_struct -{ - HMAC_CTX hmac_ctx; -}; +#include struct crypto_cert_struct { @@ -79,47 +50,8 @@ struct crypto_cert_struct extern "C" { #endif -#define CRYPTO_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH -typedef struct crypto_sha1_struct* CryptoSha1; - -FREERDP_API CryptoSha1 crypto_sha1_init(void); -FREERDP_API void crypto_sha1_update(CryptoSha1 sha1, const BYTE* data, UINT32 length); -FREERDP_API void crypto_sha1_final(CryptoSha1 sha1, BYTE* out_data); - -#define CRYPTO_MD5_DIGEST_LENGTH MD5_DIGEST_LENGTH -typedef struct crypto_md5_struct* CryptoMd5; - -FREERDP_API CryptoMd5 crypto_md5_init(void); -FREERDP_API void crypto_md5_update(CryptoMd5 md5, const BYTE* data, UINT32 length); -FREERDP_API void crypto_md5_final(CryptoMd5 md5, BYTE* out_data); - -typedef struct crypto_rc4_struct* CryptoRc4; - -FREERDP_API CryptoRc4 crypto_rc4_init(const BYTE* key, UINT32 length); -FREERDP_API void crypto_rc4(CryptoRc4 rc4, UINT32 length, const BYTE* in_data, BYTE* out_data); -FREERDP_API void crypto_rc4_free(CryptoRc4 rc4); - -typedef struct crypto_des3_struct* CryptoDes3; - -FREERDP_API CryptoDes3 crypto_des3_encrypt_init(const BYTE* key, const BYTE* ivec); -FREERDP_API CryptoDes3 crypto_des3_decrypt_init(const BYTE* key, const BYTE* ivec); -FREERDP_API BOOL crypto_des3_encrypt(CryptoDes3 des3, UINT32 length, const BYTE *in_data, BYTE *out_data); -FREERDP_API BOOL crypto_des3_decrypt(CryptoDes3 des3, UINT32 length, const BYTE *in_data, BYTE* out_data); -FREERDP_API void crypto_des3_free(CryptoDes3 des3); - -typedef struct crypto_hmac_struct* CryptoHmac; - -FREERDP_API CryptoHmac crypto_hmac_new(void); -FREERDP_API BOOL crypto_hmac_sha1_init(CryptoHmac hmac, const BYTE *data, UINT32 length); -FREERDP_API BOOL crypto_hmac_md5_init(CryptoHmac hmac, const BYTE *data, UINT32 length); -FREERDP_API void crypto_hmac_update(CryptoHmac hmac, const BYTE *data, UINT32 length); -FREERDP_API void crypto_hmac_final(CryptoHmac hmac, BYTE *out_data, UINT32 length); -FREERDP_API void crypto_hmac_free(CryptoHmac hmac); - typedef struct crypto_cert_struct* CryptoCert; -#include - FREERDP_API CryptoCert crypto_cert_read(BYTE* data, UINT32 length); FREERDP_API char* crypto_cert_fingerprint(X509* xcert); FREERDP_API char* crypto_cert_subject(X509* xcert); @@ -146,7 +78,6 @@ FREERDP_API int crypto_rsa_public_decrypt(const BYTE* input, int length, UINT32 FREERDP_API int crypto_rsa_private_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output); FREERDP_API int crypto_rsa_private_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output); 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 char* enc_data, int length, BYTE** dec_data, int* res_length); diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index cbc539887..22b2b3502 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -65,13 +65,55 @@ typedef void (*pContextFree)(freerdp* instance, rdpContext* context); typedef BOOL (*pPreConnect)(freerdp* instance); typedef BOOL (*pPostConnect)(freerdp* instance); typedef void (*pPostDisconnect)(freerdp* instance); -typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, char** password, char** domain); -typedef BOOL (*pVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint); -typedef BOOL (*pVerifyChangedCertificate)(freerdp* instance, char* subject, - char* issuer, char* new_fingerprint, - char* old_subject, char* old_issuer, - char* old_fingerprint); -typedef int (*pVerifyX509Certificate)(freerdp* instance, BYTE* data, int length, const char* hostname, int port, DWORD flags); +typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, + char** password, char** domain); + +/** @brief Callback used if user interaction is required to accept + * an unknown certificate. + * + * @param common_name The certificate registered hostname. + * @param subject The common name of the certificate. + * @param issuer The issuer of the certificate. + * @param fingerprint The fingerprint of the certificate. + * @param host_mismatch A flag indicating the certificate + * subject does not match the host connecting to. + * + * @return 1 to accept and store a certificate, 2 to accept + * a certificate only for this session, 0 otherwise. + */ +typedef DWORD (*pVerifyCertificate)(freerdp* instance, + const char* common_name, + const char* subject, + const char* issuer, + const char* fingerprint, + BOOL host_mismatch); + +/** @brief Callback used if user interaction is required to accept + * a changed certificate. + * + * @param common_name The certificate registered hostname. + * @param subject The common name of the new certificate. + * @param issuer The issuer of the new certificate. + * @param fingerprint The fingerprint of the new certificate. + * @param old_subject The common name of the old certificate. + * @param old_issuer The issuer of the new certificate. + * @param old_fingerprint The fingerprint of the old certificate. + * + * @return 1 to accept and store a certificate, 2 to accept + * a certificate only for this session, 0 otherwise. + */ + +typedef DWORD (*pVerifyChangedCertificate)(freerdp* instance, + const char* common_name, + const char* subject, + const char* issuer, + const char* new_fingerprint, + const char* old_subject, + const char* old_issuer, + const char* old_fingerprint); +typedef int (*pVerifyX509Certificate)(freerdp* instance, BYTE* data, + int length, const char* hostname, + int port, DWORD flags); typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type); diff --git a/include/freerdp/locale/timezone.h b/include/freerdp/locale/timezone.h deleted file mode 100644 index 1d062c8f1..000000000 --- a/include/freerdp/locale/timezone.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Time Zone Redirection - * - * Copyright 2012 Marc-Andre Moreau - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FREERDP_LOCALE_TIMEZONE_H -#define FREERDP_LOCALE_TIMEZONE_H - -#include -#include -#include - -#ifdef __cplusplus - extern "C" { -#endif - -FREERDP_API void freerdp_time_zone_detect(TIME_ZONE_INFO* clientTimeZone); - -#ifdef __cplusplus - } -#endif - -#endif /* FREERDP_LOCALE_TIMEZONE_H */ diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index 5e8c71bf6..49bd0564a 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -277,7 +277,9 @@ typedef struct _SHADOW_MSG_OUT_AUDIO_OUT_VOLUME SHADOW_MSG_OUT_AUDIO_OUT_VOLUME; extern "C" { #endif +FREERDP_API void shadow_subsystem_set_entry_builtin(const char* name); FREERDP_API void shadow_subsystem_set_entry(pfnShadowSubsystemEntry pEntry); + FREERDP_API int shadow_subsystem_pointer_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied, UINT32 width, UINT32 height, SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* pointerColor); diff --git a/include/freerdp/session.h b/include/freerdp/session.h new file mode 100644 index 000000000..9d7ed5198 --- /dev/null +++ b/include/freerdp/session.h @@ -0,0 +1,48 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Client Session Info + * + * Copyright 2016 David FORT + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __FREERDP_SESSION_H__ +#define __FREERDP_SESSION_H__ + +#include + +/* Logon Information Types */ +#define INFO_TYPE_LOGON 0x00000000 +#define INFO_TYPE_LOGON_LONG 0x00000001 +#define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002 +#define INFO_TYPE_LOGON_EXTENDED_INF 0x00000003 + +struct rdp_logon_info { + UINT32 sessionId; + char *username; + char *domain; +}; +typedef struct rdp_logon_info logon_info; + +struct rdp_logon_info_ex { + BOOL haveCookie; + UINT32 LogonId; + BYTE ArcRandomBits[16]; + + BOOL haveErrorInfo; + UINT32 ErrorNotificationType; + UINT32 ErrorNotificationData; +}; +typedef struct rdp_logon_info_ex logon_info_ex; + +#endif /* __FREERDP_SESSION_H__ */ diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 268c6351e..210e7112c 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -4,6 +4,7 @@ * * Copyright 2009-2011 Jay Sorg * Copyright 2010-2012 Marc-Andre Moreau + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +22,8 @@ #ifndef FREERDP_SETTINGS_H #define FREERDP_SETTINGS_H +#include + #include #include @@ -269,32 +272,6 @@ typedef struct _TARGET_NET_ADDRESS TARGET_NET_ADDRESS; #define ORIENTATION_LANDSCAPE_FLIPPED 180 #define ORIENTATION_PORTRAIT_FLIPPED 270 -/* SYSTEM_TIME */ -typedef struct -{ - UINT16 wYear; - UINT16 wMonth; - UINT16 wDayOfWeek; - UINT16 wDay; - UINT16 wHour; - UINT16 wMinute; - UINT16 wSecond; - UINT16 wMilliseconds; -} SYSTEM_TIME; - -/* TIME_ZONE_INFORMATION */ -struct _TIME_ZONE_INFO -{ - UINT32 bias; - char standardName[32]; - SYSTEM_TIME standardDate; - UINT32 standardBias; - char daylightName[32]; - SYSTEM_TIME daylightDate; - UINT32 daylightBias; -}; -typedef struct _TIME_ZONE_INFO TIME_ZONE_INFO; - /* ARC_CS_PRIVATE_PACKET */ typedef struct { @@ -977,7 +954,7 @@ struct rdp_settings UINT64 padding0896[896 - 837]; /* 837 */ /* Client Info (Time Zone) */ - ALIGN64 TIME_ZONE_INFO* ClientTimeZone; /* 896 */ + ALIGN64 LPTIME_ZONE_INFORMATION ClientTimeZone; /* 896 */ ALIGN64 char* DynamicDSTTimeZoneKeyName; /* 897 */ ALIGN64 BOOL DynamicDaylightTimeDisabled; /* 898 */ UINT64 padding0960[960 - 899]; /* 899 */ @@ -1459,6 +1436,7 @@ FREERDP_API int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, char* pre FREERDP_API BOOL freerdp_device_collection_add(rdpSettings* settings, RDPDR_DEVICE* device); FREERDP_API RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char* name); +FREERDP_API RDPDR_DEVICE* freerdp_device_collection_find_type(rdpSettings* settings, UINT32 type); FREERDP_API RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device); FREERDP_API void freerdp_device_collection_free(rdpSettings* settings); diff --git a/include/freerdp/update.h b/include/freerdp/update.h index 16829b167..3847d7ab3 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -156,6 +156,8 @@ typedef BOOL (*pSurfaceFrameMarker)(rdpContext* context, SURFACE_FRAME_MARKER* s typedef BOOL (*pSurfaceFrameBits)(rdpContext* context, SURFACE_BITS_COMMAND* cmd, BOOL first, BOOL last, UINT32 frameId); typedef BOOL (*pSurfaceFrameAcknowledge)(rdpContext* context, UINT32 frameId); +typedef BOOL (*pSaveSessionInfo)(rdpContext *context, UINT32 type, void *data); + struct rdp_update { rdpContext* context; /* 0 */ @@ -189,7 +191,8 @@ struct rdp_update pSurfaceFrameMarker SurfaceFrameMarker; /* 66 */ pSurfaceFrameBits SurfaceFrameBits; /* 67 */ pSurfaceFrameAcknowledge SurfaceFrameAcknowledge; /* 68 */ - UINT32 paddingE[80 - 69]; /* 69 */ + pSaveSessionInfo SaveSessionInfo; /* 69 */ + UINT32 paddingE[80 - 70]; /* 70 */ /* internal */ diff --git a/libfreerdp/cache/glyph.c b/libfreerdp/cache/glyph.c index 0157d40bc..412c1146c 100644 --- a/libfreerdp/cache/glyph.c +++ b/libfreerdp/cache/glyph.c @@ -57,7 +57,7 @@ void update_process_glyph(rdpContext* context, BYTE* data, int* index, if (offset & 0x80) { - offset = data[*index + 1] | ((int)((char)data[*index + 2]) << 8); + offset = data[*index + 1] | ((int)((signed char)data[*index + 2]) << 8); (*index)++; (*index)++; } diff --git a/libfreerdp/codec/region.c b/libfreerdp/codec/region.c index be023b5d7..b3f32af76 100644 --- a/libfreerdp/codec/region.c +++ b/libfreerdp/codec/region.c @@ -94,17 +94,17 @@ const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRects) REGION16_DATA *data; assert(region); - assert(region->data); data = region->data; if (!data) { if (nbRects) *nbRects = 0; - return 0; + return NULL; } - *nbRects = data->nbRects; + if (nbRects) + *nbRects = data->nbRects; return (RECTANGLE_16 *)(data + 1); } diff --git a/libfreerdp/common/CMakeLists.txt b/libfreerdp/common/CMakeLists.txt index 05cadf43c..1683f449d 100644 --- a/libfreerdp/common/CMakeLists.txt +++ b/libfreerdp/common/CMakeLists.txt @@ -25,10 +25,9 @@ set(${MODULE_PREFIX}_SRCS freerdp_module_add(${${MODULE_PREFIX}_SRCS}) -freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR}) freerdp_include_directory_add(${ZLIB_INCLUDE_DIRS}) -freerdp_library_add(${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES}) +freerdp_library_add(${ZLIB_LIBRARIES}) if(BUILD_TESTING) add_subdirectory(test) diff --git a/libfreerdp/common/assistance.c b/libfreerdp/common/assistance.c index 9e4702e7c..9f231be2d 100644 --- a/libfreerdp/common/assistance.c +++ b/libfreerdp/common/assistance.c @@ -22,18 +22,10 @@ #endif #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include @@ -80,11 +72,12 @@ int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* key, int keyLength) { + int rc = -1; int i; BYTE* buffer; BYTE pad1[64]; BYTE pad2[64]; - SHA_CTX hashCtx; + WINPR_SHA1_CTX hashCtx; memset(pad1, 0x36, 64); memset(pad2, 0x5C, 64); @@ -98,21 +91,29 @@ int freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, int hashLength, BYTE* k buffer = (BYTE*) calloc(1, hashLength * 2); if (!buffer) - return -1; + goto fail; - SHA1_Init(&hashCtx); - SHA1_Update(&hashCtx, pad1, 64); - SHA1_Final((void*) buffer, &hashCtx); + if (!winpr_SHA1_Init(&hashCtx)) + goto fail; + if (!winpr_SHA1_Update(&hashCtx, pad1, 64)) + goto fail; + if (!winpr_SHA1_Final(&hashCtx, buffer, hashLength)) + goto fail; - SHA1_Init(&hashCtx); - SHA1_Update(&hashCtx, pad2, 64); - SHA1_Final((void*) &buffer[hashLength], &hashCtx); + if (!winpr_SHA1_Init(&hashCtx)) + goto fail; + if (!winpr_SHA1_Update(&hashCtx, pad2, 64)) + goto fail; + if (!winpr_SHA1_Final(&hashCtx, &buffer[hashLength], hashLength)) + goto fail; CopyMemory(key, buffer, keyLength); + rc = 1; +fail: free(buffer); - return 1; + return rc; } int freerdp_assistance_parse_address_list(rdpAssistanceFile* file, char* list) @@ -523,7 +524,7 @@ char* freerdp_assistance_generate_pass_stub(DWORD flags) * Example: WB^6HsrIaFmEpi */ - RAND_bytes((BYTE*) nums, sizeof(nums)); + winpr_RAND((BYTE*) nums, sizeof(nums)); passStub[0] = set1[nums[0] % sizeof(set1)]; /* character 0 */ passStub[1] = set2[nums[1] % sizeof(set2)]; /* character 1 */ @@ -546,15 +547,16 @@ char* freerdp_assistance_generate_pass_stub(DWORD flags) BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub, int* pEncryptedSize) { + BOOL rc; int status; - MD5_CTX md5Ctx; + WINPR_MD5_CTX md5Ctx; int cbPasswordW; int cbPassStubW; int EncryptedSize; - BYTE PasswordHash[16]; - EVP_CIPHER_CTX rc4Ctx; + BYTE PasswordHash[WINPR_MD5_DIGEST_LENGTH]; + WINPR_CIPHER_CTX* rc4Ctx; BYTE* pbIn, *pbOut; - int cbOut, cbIn, cbFinal; + size_t cbOut, cbIn, cbFinal; WCHAR* PasswordW = NULL; WCHAR* PassStubW = NULL; @@ -565,14 +567,29 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas cbPasswordW = (status - 1) * 2; - MD5_Init(&md5Ctx); - MD5_Update(&md5Ctx, PasswordW, cbPasswordW); - MD5_Final((void*) PasswordHash, &md5Ctx); + if (!winpr_MD5_Init(&md5Ctx)) + { + free (PasswordW); + return NULL; + } + if (!winpr_MD5_Update(&md5Ctx, (BYTE*)PasswordW, cbPasswordW)) + { + free (PasswordW); + return NULL; + } + if (!winpr_MD5_Final(&md5Ctx, (BYTE*) PasswordHash, sizeof(PasswordHash))) + { + free (PasswordW); + return NULL; + } status = ConvertToUnicode(CP_UTF8, 0, passStub, -1, &PassStubW, 0); if (status <= 0) + { + free (PasswordW); return NULL; + } cbPassStubW = (status - 1) * 2; @@ -605,21 +622,9 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas free(PasswordW); free(PassStubW); - EVP_CIPHER_CTX_init(&rc4Ctx); - - status = EVP_EncryptInit_ex(&rc4Ctx, EVP_rc4(), NULL, NULL, NULL); - - if (!status) - { - WLog_ERR(TAG, "EVP_CipherInit_ex failure"); - free (pbOut); - free (pbIn); - return NULL; - } - - status = EVP_EncryptInit_ex(&rc4Ctx, NULL, NULL, PasswordHash, NULL); - - if (!status) + rc4Ctx = winpr_Cipher_New(WINPR_CIPHER_ARC4_128, WINPR_ENCRYPT, + PasswordHash, NULL); + if (!rc4Ctx) { WLog_ERR(TAG, "EVP_CipherInit_ex failure"); free (pbOut); @@ -630,26 +635,26 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas cbOut = cbFinal = 0; cbIn = EncryptedSize; - status = EVP_EncryptUpdate(&rc4Ctx, pbOut, &cbOut, pbIn, cbIn); + rc = winpr_Cipher_Update(rc4Ctx, pbIn, cbIn, pbOut, &cbOut); free(pbIn); - if (!status) + if (!rc) { WLog_ERR(TAG, "EVP_CipherUpdate failure"); + winpr_Cipher_Free(rc4Ctx); free (pbOut); return NULL; } - status = EVP_EncryptFinal_ex(&rc4Ctx, pbOut + cbOut, &cbFinal); - - if (!status) + if (!winpr_Cipher_Final(rc4Ctx, pbOut + cbOut, &cbFinal)) { WLog_ERR(TAG, "EVP_CipherFinal_ex failure"); + winpr_Cipher_Free(rc4Ctx); free (pbOut); return NULL; } - EVP_CIPHER_CTX_cleanup(&rc4Ctx); + winpr_Cipher_Free(rc4Ctx); *pEncryptedSize = EncryptedSize; @@ -659,17 +664,17 @@ BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* pas int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) { int status; - SHA_CTX shaCtx; + WINPR_SHA1_CTX shaCtx; int cbPasswordW; int cchOutW = 0; WCHAR* pbOutW = NULL; - EVP_CIPHER_CTX aesDec; + WINPR_CIPHER_CTX* aesDec; WCHAR* PasswordW = NULL; BYTE* pbIn, *pbOut; - int cbOut, cbIn, cbFinal; - BYTE DerivedKey[AES_BLOCK_SIZE]; - BYTE InitializationVector[AES_BLOCK_SIZE]; - BYTE PasswordHash[SHA_DIGEST_LENGTH]; + size_t cbOut, cbIn, cbFinal; + BYTE DerivedKey[WINPR_AES_BLOCK_SIZE]; + BYTE InitializationVector[WINPR_AES_BLOCK_SIZE]; + BYTE PasswordHash[WINPR_SHA1_DIGEST_LENGTH]; status = ConvertToUnicode(CP_UTF8, 0, password, -1, &PasswordW, 0); @@ -678,9 +683,13 @@ int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) cbPasswordW = (status - 1) * 2; - SHA1_Init(&shaCtx); - SHA1_Update(&shaCtx, PasswordW, cbPasswordW); - SHA1_Final((void*) PasswordHash, &shaCtx); + if (!winpr_SHA1_Init(&shaCtx) || + !winpr_SHA1_Update(&shaCtx, (BYTE*)PasswordW, cbPasswordW) || + !winpr_SHA1_Final(&shaCtx, PasswordHash, sizeof(PasswordHash))) + { + free (PasswordW); + return -1; + } status = freerdp_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), DerivedKey, sizeof(DerivedKey)); @@ -693,22 +702,9 @@ int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) ZeroMemory(InitializationVector, sizeof(InitializationVector)); - EVP_CIPHER_CTX_init(&aesDec); - - status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, NULL, NULL); - - if (status != 1) - { - free(PasswordW); - return -1; - } - - EVP_CIPHER_CTX_set_key_length(&aesDec, (128 / 8)); - EVP_CIPHER_CTX_set_padding(&aesDec, 0); - - status = EVP_DecryptInit_ex(&aesDec, EVP_aes_128_cbc(), NULL, DerivedKey, InitializationVector); - - if (status != 1) + aesDec = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, + DerivedKey, InitializationVector); + if (!aesDec) { free(PasswordW); return -1; @@ -717,34 +713,33 @@ int freerdp_assistance_decrypt2(rdpAssistanceFile* file, const char* password) cbOut = cbFinal = 0; cbIn = file->EncryptedLHTicketLength; pbIn = (BYTE*) file->EncryptedLHTicket; - pbOut = (BYTE*) calloc(1, cbIn + AES_BLOCK_SIZE + 2); + pbOut = (BYTE*) calloc(1, cbIn + WINPR_AES_BLOCK_SIZE + 2); if (!pbOut) { + winpr_Cipher_Free(aesDec); free(PasswordW); return -1; } - status = EVP_DecryptUpdate(&aesDec, pbOut, &cbOut, pbIn, cbIn); - - if (status != 1) + if (!winpr_Cipher_Update(aesDec, pbIn, cbIn, pbOut, &cbOut)) { + winpr_Cipher_Free(aesDec); free(PasswordW); free(pbOut); return -1; } - status = EVP_DecryptFinal_ex(&aesDec, pbOut + cbOut, &cbFinal); - - if (status != 1) + if (!winpr_Cipher_Final(aesDec, pbOut + cbOut, &cbFinal)) { WLog_ERR(TAG, "EVP_DecryptFinal_ex failure"); + winpr_Cipher_Free(aesDec); free(PasswordW); free(pbOut); return -1; } - EVP_CIPHER_CTX_cleanup(&aesDec); + winpr_Cipher_Free(aesDec); cbOut += cbFinal; cbFinal = 0; diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 859357a2a..bded9d0ec 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -3,6 +3,7 @@ * Settings Management * * Copyright 2012 Marc-Andre Moreau + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -208,6 +209,22 @@ RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char* return NULL; } +RDPDR_DEVICE* freerdp_device_collection_find_type(rdpSettings* settings, UINT32 type) +{ + UINT32 index; + RDPDR_DEVICE* device; + + for (index = 0; index < settings->DeviceCount; index++) + { + device = (RDPDR_DEVICE*) settings->DeviceArray[index]; + + if (device->Type == type) + return device; + } + + return NULL; +} + RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device) { if (device->Type == RDPDR_DTYP_FILESYSTEM) diff --git a/libfreerdp/core/autodetect.c b/libfreerdp/core/autodetect.c index 1a89737c6..178e989ce 100644 --- a/libfreerdp/core/autodetect.c +++ b/libfreerdp/core/autodetect.c @@ -21,6 +21,8 @@ #include "config.h" #endif +#include + #include "autodetect.h" #define RDP_RTT_REQUEST_TYPE_CONTINUOUS 0x0001 @@ -173,7 +175,7 @@ BOOL autodetect_send_bandwidth_measure_payload(rdpContext* context, UINT16 paylo return FALSE; } - RAND_bytes(buffer, payloadLength); + winpr_RAND(buffer, payloadLength); Stream_Write(s, buffer, payloadLength); bResult = rdp_send_message_channel_pdu(context->rdp, s, SEC_AUTODETECT_REQ); @@ -225,7 +227,7 @@ static BOOL autodetect_send_bandwidth_measure_stop(rdpContext* context, UINT16 p return FALSE; } - RAND_bytes(buffer, payloadLength); + winpr_RAND(buffer, payloadLength); Stream_Write(s, buffer, payloadLength); } } diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 114cfd2ee..d6e46e810 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -3392,10 +3392,10 @@ BOOL rdp_print_capability_sets(wStream* s, UINT16 numberCapabilities, BOOL recei break; } - if (s->pointer != em) + if (Stream_Pointer(s) != em) { WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", - type, (int)(s->pointer - bm), (int)(em - bm)); + type, (int)(Stream_Pointer(s) - bm), (int)(em - bm)); } Stream_SetPointer(s, em); @@ -3617,10 +3617,10 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa } } - if (s->pointer != em) + if (Stream_Pointer(s) != em) { WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", - type, (int)(s->pointer - bm), (int)(em - bm)); + type, (int)(Stream_Pointer(s) - bm), (int)(em - bm)); } Stream_SetPointer(s, em); diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c index a793af831..9ce68f355 100644 --- a/libfreerdp/core/certificate.c +++ b/libfreerdp/core/certificate.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -398,18 +399,17 @@ static BOOL certificate_process_server_public_signature(rdpCertificate* certific const BYTE* sigdata, int sigdatalen, wStream* s, UINT32 siglen) { int i, sum; - CryptoMd5 md5ctx; + WINPR_MD5_CTX md5ctx; BYTE sig[TSSK_KEY_LENGTH]; BYTE encsig[TSSK_KEY_LENGTH + 8]; - BYTE md5hash[CRYPTO_MD5_DIGEST_LENGTH]; + BYTE md5hash[WINPR_MD5_DIGEST_LENGTH]; - md5ctx = crypto_md5_init(); - - if (!md5ctx) - return FALSE; - - crypto_md5_update(md5ctx, sigdata, sigdatalen); - crypto_md5_final(md5ctx, md5hash); + if (!winpr_MD5_Init(&md5ctx)) + return FALSE; + if (!winpr_MD5_Update(&md5ctx, sigdata, sigdatalen)) + return FALSE; + if (!winpr_MD5_Final(&md5ctx, md5hash, sizeof(md5hash))) + return FALSE; Stream_Read(s, encsig, siglen); /* Last 8 bytes shall be all zero. */ diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 5047aadfe..99b2e59f3 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -31,6 +31,7 @@ #include "transport.h" #include +#include #include #include @@ -312,8 +313,6 @@ BOOL rdp_client_disconnect(rdpRdp* rdp) { BOOL status; - ResetEvent(rdp->context->abortEvent); - if (rdp->settingsCopy) { freerdp_settings_free(rdp->settingsCopy); @@ -438,7 +437,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) if (!settings->ClientRandom) return FALSE; - crypto_nonce(settings->ClientRandom, settings->ClientRandomLength); + winpr_RAND(settings->ClientRandom, settings->ClientRandomLength); key_len = settings->RdpServerCertificate->cert_info.ModulusLength; mod = settings->RdpServerCertificate->cert_info.Modulus; exp = settings->RdpServerCertificate->cert_info.exponent; @@ -491,20 +490,26 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { - rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec); + rdp->fips_encrypt = winpr_Cipher_New( WINPR_CIPHER_DES_EDE3_CBC, + WINPR_ENCRYPT, + rdp->fips_encrypt_key, + fips_ivec); if (!rdp->fips_encrypt) { WLog_ERR(TAG, "unable to allocate des3 encrypt key"); goto end; } - rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec); + rdp->fips_decrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, + WINPR_DECRYPT, + rdp->fips_decrypt_key, + fips_ivec); if (!rdp->fips_decrypt) { WLog_ERR(TAG, "unable to allocate des3 decrypt key"); goto end; } - rdp->fips_hmac = crypto_hmac_new(); + rdp->fips_hmac = calloc(1, sizeof(WINPR_HMAC_CTX)); if (!rdp->fips_hmac) { WLog_ERR(TAG, "unable to allocate fips hmac"); @@ -514,22 +519,27 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) goto end; } - rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); - if (!rdp->rc4_decrypt_key) - { - WLog_ERR(TAG, "unable to allocate rc4 decrypt key"); + rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); + rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); + if (!rdp->rc4_decrypt_key || !rdp->rc4_encrypt_key) goto end; - } - rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); - if (!rdp->rc4_encrypt_key) - { - WLog_ERR(TAG, "unable to allocate rc4 encrypt key"); - goto end; - } ret = TRUE; end: free(crypt_client_random); + if (!ret) + { + winpr_Cipher_Free(rdp->fips_decrypt); + winpr_Cipher_Free(rdp->fips_encrypt); + winpr_RC4_Free(rdp->rc4_decrypt_key); + winpr_RC4_Free(rdp->rc4_encrypt_key); + + rdp->fips_decrypt = NULL; + rdp->fips_encrypt = NULL; + rdp->rc4_decrypt_key = NULL; + rdp->rc4_encrypt_key = NULL; + } + return ret; } @@ -586,12 +596,12 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) if (rand_len != key_len + 8) { WLog_ERR(TAG, "invalid encrypted client random length"); - goto end2; + goto end; } crypt_client_random = calloc(1, rand_len); if (!crypt_client_random) - goto end2; + goto end; Stream_Read(s, crypt_client_random, rand_len); mod = rdp->settings->RdpServerRsaKey->Modulus; @@ -600,29 +610,33 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) /* now calculate encrypt / decrypt and update keys */ if (!security_establish_keys(client_random, rdp)) - { goto end; - } rdp->do_crypt = TRUE; if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { - rdp->fips_encrypt = crypto_des3_encrypt_init(rdp->fips_encrypt_key, fips_ivec); + rdp->fips_encrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, + WINPR_ENCRYPT, + rdp->fips_encrypt_key, + fips_ivec); if (!rdp->fips_encrypt) { WLog_ERR(TAG, "unable to allocate des3 encrypt key"); goto end; } - rdp->fips_decrypt = crypto_des3_decrypt_init(rdp->fips_decrypt_key, fips_ivec); + rdp->fips_decrypt = winpr_Cipher_New(WINPR_CIPHER_DES_EDE3_CBC, + WINPR_DECRYPT, + rdp->fips_decrypt_key, + fips_ivec); if (!rdp->fips_decrypt) { WLog_ERR(TAG, "unable to allocate des3 decrypt key"); goto end; } - rdp->fips_hmac = crypto_hmac_new(); + rdp->fips_hmac = calloc(1, sizeof(WINPR_HMAC_CTX)); if (!rdp->fips_hmac) { WLog_ERR(TAG, "unable to allocate fips hmac"); @@ -632,25 +646,28 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) goto end; } - rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); - if (!rdp->rc4_decrypt_key) - { - WLog_ERR(TAG, "unable to allocate rc4 decrypt key"); + rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); + rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); + if (!rdp->rc4_decrypt_key || rdp->rc4_encrypt_key) goto end; - } - rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); - if (!rdp->rc4_encrypt_key) - { - WLog_ERR(TAG, "unable to allocate rc4 encrypt key"); - goto end; - } ret = TRUE; end: free(crypt_client_random); -end2: free(client_random); + if (!ret) + { + winpr_Cipher_Free(rdp->fips_encrypt); + winpr_Cipher_Free(rdp->fips_decrypt); + winpr_RC4_Free(rdp->rc4_encrypt_key); + winpr_RC4_Free(rdp->rc4_decrypt_key); + + rdp->fips_encrypt = NULL; + rdp->fips_decrypt = NULL; + rdp->rc4_encrypt_key = NULL; + rdp->rc4_decrypt_key = NULL; + } return ret; } diff --git a/libfreerdp/core/errconnect.c b/libfreerdp/core/errconnect.c index a52912b08..cd983b464 100644 --- a/libfreerdp/core/errconnect.c +++ b/libfreerdp/core/errconnect.c @@ -38,7 +38,7 @@ "A configuration error prevented a connection to be established." #define ERRCONNECT_CONNECT_UNDEFINED_STRING \ - "A undefined connection error occured." + "A undefined connection error occurred." #define ERRCONNECT_POST_CONNECT_FAILED_STRING \ "The connection attempt was aborted due to post connect configuration errors." diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 79fa00d6e..411d0e960 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -45,7 +45,7 @@ * Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises * server output packets from the first byte with the goal of improving * bandwidth. - * + * * Slow-Path packet always starts with TPKT header, which has the first * byte 0x03, while Fast-Path packet starts with 2 zero bits in the first * two less significant bits of the first byte. @@ -282,7 +282,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s if (!fastpath_recv_update_synchronize(fastpath, s)) WLog_ERR(TAG, "fastpath_recv_update_synchronize failure but we continue"); else - IFCALL(update->Synchronize, context); + IFCALL(update->Synchronize, context); break; case FASTPATH_UPDATETYPE_SURFCMDS: @@ -463,7 +463,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) Stream_SetPosition(fastpath->updateData, 0); - Stream_Copy(fastpath->updateData, cs, size); + Stream_Copy(cs, fastpath->updateData, size); } else if (fragmentation == FASTPATH_FRAGMENT_NEXT) { @@ -491,7 +491,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) goto out_fail; } - Stream_Copy(fastpath->updateData, cs, size); + Stream_Copy(cs, fastpath->updateData, size); } else if (fragmentation == FASTPATH_FRAGMENT_LAST) { @@ -519,7 +519,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) goto out_fail; } - Stream_Copy(fastpath->updateData, cs, size); + Stream_Copy(cs, fastpath->updateData, size); Stream_SealLength(fastpath->updateData); Stream_SetPosition(fastpath->updateData, 0); @@ -546,7 +546,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) out_fail: if (cs != s) { - Stream_Release(cs); + Stream_Release(cs); } return -1; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 91eae992d..0f45f1284 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -383,6 +383,7 @@ BOOL freerdp_reconnect(freerdp* instance) BOOL status; rdpRdp* rdp = instance->context->rdp; + ResetEvent(instance->context->abortEvent); status = rdp_client_reconnect(rdp); return status; @@ -397,7 +398,7 @@ BOOL freerdp_shall_disconnect(freerdp* instance) return TRUE; } -FREERDP_API BOOL freerdp_focus_required(freerdp* instance) +BOOL freerdp_focus_required(freerdp* instance) { rdpRdp* rdp; BOOL bRetCode = FALSE; @@ -777,19 +778,19 @@ void freerdp_free(freerdp* instance) free(instance); } -FREERDP_API ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount) { +ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount) { ULONG written = context->rdp->transport->written; if (resetCount) context->rdp->transport->written = 0; return written; } -FREERDP_API HANDLE getChannelErrorEventHandle(rdpContext* context) +HANDLE getChannelErrorEventHandle(rdpContext* context) { return context->channelErrorEvent; } -FREERDP_API BOOL checkChannelErrorEvent(rdpContext* context) +BOOL checkChannelErrorEvent(rdpContext* context) { if (WaitForSingleObject( context->channelErrorEvent, 0) == WAIT_OBJECT_0) { @@ -804,24 +805,24 @@ FREERDP_API BOOL checkChannelErrorEvent(rdpContext* context) * * @return 0 on success, otherwise a Win32 error code */ -FREERDP_API UINT getChannelError(rdpContext* context) +UINT getChannelError(rdpContext* context) { return context->channelErrorNum; } -FREERDP_API const char* getChannelErrorDescription(rdpContext* context) +const char* getChannelErrorDescription(rdpContext* context) { return context->errorDescription; } -FREERDP_API void clearChannelError(rdpContext* context) +void clearChannelError(rdpContext* context) { context->channelErrorNum = 0; memset(context->errorDescription, 0, 500); ResetEvent(context->channelErrorEvent); } -FREERDP_API void setChannelError(rdpContext* context, UINT errorNum, char* description) +void setChannelError(rdpContext* context, UINT errorNum, char* description) { context->channelErrorNum = errorNum; strncpy(context->errorDescription, description, 499); diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c index f12423f93..a3d5da350 100644 --- a/libfreerdp/core/gateway/http.c +++ b/libfreerdp/core/gateway/http.c @@ -407,7 +407,7 @@ wStream* http_request_write(HttpContext* context, HttpRequest* request) free(lines); Stream_Write(s, "\0", 1); /* append null terminator */ Stream_Rewind(s, 1); /* don't include null terminator in length */ - Stream_Length(s) = Stream_GetPosition(s); + Stream_SetLength(s, Stream_GetPosition(s)); return s; out_free: diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index 175aab3c3..f6f680118 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -29,8 +29,6 @@ #include #include -#include - #define TAG FREERDP_TAG("core.gateway.ntlm") wStream* rpc_ntlm_http_request(rdpRpc* rpc, HttpContext* http, const char* method, int contentLength, SecBuffer* ntlmToken) diff --git a/libfreerdp/core/gateway/ntlm.c b/libfreerdp/core/gateway/ntlm.c index c9795b648..ce6925bbd 100644 --- a/libfreerdp/core/gateway/ntlm.c +++ b/libfreerdp/core/gateway/ntlm.c @@ -28,7 +28,6 @@ #include #include -#include #include "http.h" diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 3f3bab8ec..474ed85ad 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -206,7 +206,7 @@ BOOL rdg_send_tunnel_authorization(rdpRdg* rdg) if (!clientName) return FALSE; - packetSize = 12 + clientNameLen * 2 + sizeof(WCHAR); + packetSize = 12 + clientNameLen * sizeof(WCHAR); s = Stream_New(NULL, packetSize); if (!s) @@ -225,8 +225,6 @@ BOOL rdg_send_tunnel_authorization(rdpRdg* rdg) for (i = 0; i < clientNameLen; i++) Stream_Write_UINT16(s, clientName[i]); - Stream_Write_UINT16(s, 0); - Stream_SealLength(s); status = rdg_write_packet(rdg, s); diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index 16f4af1eb..d7309b957 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -30,7 +30,6 @@ #include -#include #include #ifdef HAVE_VALGRIND_MEMCHECK_H diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index 31edc8676..df939b9d8 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -422,7 +423,7 @@ int rts_ping_traffic_sent_notify_command_write(BYTE* buffer, UINT32 PingTrafficS void rts_generate_cookie(BYTE* cookie) { - RAND_pseudo_bytes(cookie, 16); + winpr_RAND(cookie, 16); } /* CONN/A Sequence */ diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index c2354423e..e19e01937 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -24,6 +24,7 @@ #endif #include +#include #include @@ -225,7 +226,7 @@ void gcc_write_conference_create_request(wStream* s, wStream* userData) per_write_octet_string(s, h221_cs_key, 4, 4); /* h221NonStandard, client-to-server H.221 key, "Duca" */ /* userData::value (OCTET_STRING) */ - per_write_octet_string(s, userData->buffer, Stream_GetPosition(userData), 0); /* array of client data blocks */ + per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData), 0); /* array of client data blocks */ } BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs) @@ -319,7 +320,7 @@ void gcc_write_conference_create_response(wStream* s, wStream* userData) per_write_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */ /* userData (OCTET_STRING) */ - per_write_octet_string(s, userData->buffer, Stream_GetPosition(userData), 0); /* array of server data blocks */ + per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData), 0); /* array of server data blocks */ } BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length) @@ -508,7 +509,7 @@ BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length) break; } offset += blockLength; - Stream_Pointer(s) = holdp + blockLength; + Stream_SetPointer(s, holdp + blockLength); } return TRUE; @@ -589,7 +590,12 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */ /* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */ - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, + &str, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client host name"); + return FALSE; + } Stream_Seek(s, 32); free(settings->ClientHostname); settings->ClientHostname = str; @@ -643,10 +649,17 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) settings->EarlyCapabilityFlags = (UINT32) earlyCapabilityFlags; blockLength -= 2; + /* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */ + if (blockLength < 64) break; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, + &str, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert the client product identifier"); + return FALSE; + } Stream_Seek(s, 64); /* clientDigProductId (64 bytes) */ free(settings->ClientProductId); settings->ClientProductId = str; @@ -1178,7 +1191,7 @@ const BYTE tssk_exponent[] = BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs) { - CryptoMd5 md5; + WINPR_MD5_CTX md5; BYTE* sigData; int expLen, keyLen, sigDataLen; BYTE encryptedSignature[TSSK_KEY_LENGTH]; @@ -1348,7 +1361,7 @@ BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs) settings->ServerRandomLength = serverRandomLen; settings->ServerRandom = (BYTE*) malloc(serverRandomLen); - crypto_nonce(settings->ServerRandom, serverRandomLen); + winpr_RAND(settings->ServerRandom, serverRandomLen); Stream_Write(s, settings->ServerRandom, serverRandomLen); sigData = Stream_Pointer(s); @@ -1375,15 +1388,12 @@ BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs) memcpy(signature, initial_signature, sizeof(initial_signature)); - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, sigData, sigDataLen)) + return FALSE; + if (!winpr_MD5_Final(&md5, signature, sizeof(signature))) return FALSE; - } - - crypto_md5_update(md5, sigData, sigDataLen); - crypto_md5_final(md5, signature); crypto_rsa_private_encrypt(signature, sizeof(signature), TSSK_KEY_LENGTH, tssk_modulus, tssk_privateExponent, encryptedSignature); diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 6fbff79da..57d1894c9 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "timezone.h" @@ -44,7 +45,7 @@ static const char* const INFO_TYPE_LOGON_STRINGS[4] = BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) { - CryptoHmac hmac; + WINPR_HMAC_CTX hmac; BYTE ClientRandom[32]; BYTE AutoReconnectRandom[32]; ARC_SC_PRIVATE_PACKET* serverCookie; @@ -67,18 +68,14 @@ BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) if (settings->SelectedProtocol == PROTOCOL_RDP) CopyMemory(ClientRandom, settings->ClientRandom, settings->ClientRandomLength); - hmac = crypto_hmac_new(); - - if (!hmac) - return FALSE; - /* SecurityVerifier = HMAC_MD5(AutoReconnectRandom, ClientRandom) */ - if (!crypto_hmac_md5_init(hmac, AutoReconnectRandom, 16)) + if (!winpr_HMAC_Init(&hmac, WINPR_MD_MD5, AutoReconnectRandom, 16)) + return FALSE; + if (!winpr_HMAC_Update(&hmac, ClientRandom, 32)) + return FALSE; + if (!winpr_HMAC_Final(&hmac, clientCookie->securityVerifier, 16)) return FALSE; - crypto_hmac_update(hmac, ClientRandom, 32); - crypto_hmac_final(hmac, clientCookie->securityVerifier, 16); - crypto_hmac_free(hmac); return TRUE; } @@ -90,7 +87,7 @@ BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) * @param settings settings */ -BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) +BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s, logon_info_ex *info) { BYTE* p; ARC_SC_PRIVATE_PACKET* autoReconnectCookie; @@ -102,16 +99,16 @@ BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ - Stream_Read_UINT32(s, autoReconnectCookie->version); /* Version (4 bytes) */ - Stream_Read_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ - Stream_Read(s, autoReconnectCookie->arcRandomBits, 16); /* ArcRandomBits (16 bytes) */ - if (autoReconnectCookie->cbLen != 28) { WLog_ERR(TAG, "ServerAutoReconnectCookie.cbLen != 28"); return FALSE; } + Stream_Read_UINT32(s, autoReconnectCookie->version); /* Version (4 bytes) */ + Stream_Read_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ + Stream_Read(s, autoReconnectCookie->arcRandomBits, 16); /* ArcRandomBits (16 bytes) */ + p = autoReconnectCookie->arcRandomBits; WLog_DBG(TAG, "ServerAutoReconnectCookie: Version: %d LogonId: %d SecurityVerifier: " @@ -120,6 +117,9 @@ BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); + info->LogonId = autoReconnectCookie->logonId; + CopyMemory(info->ArcRandomBits, p, 16); + if ((settings->PrintReconnectCookie) && (autoReconnectCookie->cbLen > 0)) { char* base64; @@ -199,6 +199,7 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) UINT16 cbClientDir; UINT16 cbAutoReconnectLen; rdpSettings* settings = rdp->settings; + WCHAR* wstr; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -206,6 +207,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ + /* cbClientAddress is the size in bytes of the character data in the clientAddress field. + * This size includes the length of the mandatory null terminator. + * The maximum allowed value is 80 bytes + */ + + if ((cbClientAddress % 2) || cbClientAddress < 2 || cbClientAddress > 80) + { + WLog_ERR(TAG, "protocol error: invalid cbClientAddress value: %u", cbClientAddress); + return FALSE; + } + settings->IPv6Enabled = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? TRUE : FALSE); if (Stream_GetRemainingLength(s) < cbClientAddress) @@ -217,7 +229,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) settings->ClientAddress = NULL; } - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbClientAddress / 2, &settings->ClientAddress, 0, NULL, NULL); + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbClientAddress / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: clientAddress must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ClientAddress, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client address"); + return FALSE; + } Stream_Seek(s, cbClientAddress); if (Stream_GetRemainingLength(s) < 2) @@ -225,6 +247,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, cbClientDir); /* cbClientDir (2 bytes) */ + /* cbClientDir is the size in bytes of the character data in the clientDir field. + * This size includes the length of the mandatory null terminator. + * The maximum allowed value is 512 bytes + */ + + if ((cbClientDir % 2) || cbClientDir < 2 || cbClientDir > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbClientDir value: %u", cbClientDir); + return FALSE; + } + if (Stream_GetRemainingLength(s) < cbClientDir) return FALSE; @@ -234,7 +267,17 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) settings->ClientDir = NULL; } - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbClientDir / 2, &settings->ClientDir, 0, NULL, NULL); + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbClientDir / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: clientDir must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, &settings->ClientDir, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert client directory"); + return FALSE; + } Stream_Seek(s, cbClientDir); if (!rdp_read_client_time_zone(s, settings)) @@ -337,6 +380,7 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) UINT16 cbWorkingDir; UINT32 CompressionLevel; rdpSettings* settings = rdp->settings; + WCHAR* wstr; if (Stream_GetRemainingLength(s) < 18) return FALSE; @@ -357,6 +401,12 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) settings->CompressionLevel = CompressionLevel; } + if (!(flags & INFO_UNICODE)) + { + WLog_ERR(TAG, "Client without INFO_UNICODE flag: this is currently not supported"); + return FALSE; + } + Stream_Read_UINT16(s, cbDomain); /* cbDomain (2 bytes) */ Stream_Read_UINT16(s, cbUserName); /* cbUserName (2 bytes) */ Stream_Read_UINT16(s, cbPassword); /* cbPassword (2 bytes) */ @@ -368,7 +418,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbDomain > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbDomain / 2, &settings->Domain, 0, NULL, NULL); + /* cbDomain is the size in bytes of the character data in the Domain field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbDomain % 2) || cbDomain > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbDomain value: %u", cbDomain); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2]) + { + WLog_ERR(TAG, "protocol error: Domain must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Domain, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert Domain string"); + return FALSE; + } Stream_Seek(s, cbDomain); } Stream_Seek(s, 2); @@ -378,7 +447,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbUserName > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbUserName / 2, &settings->Username, 0, NULL, NULL); + /* cbUserName is the size in bytes of the character data in the UserName field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbUserName % 2) || cbUserName > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbUserName value: %u", cbUserName); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2]) + { + WLog_ERR(TAG, "protocol error: UserName must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Username, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert UserName string"); + return FALSE; + } Stream_Seek(s, cbUserName); } Stream_Seek(s, 2); @@ -388,7 +476,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbPassword > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbPassword / 2, &settings->Password, 0, NULL, NULL); + /* cbPassword is the size in bytes of the character data in the Password field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbPassword % 2) || cbPassword > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbPassword value: %u", cbPassword); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbPassword / 2]) + { + WLog_ERR(TAG, "protocol error: Password must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Password, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert Password string"); + return FALSE; + } Stream_Seek(s, cbPassword); } Stream_Seek(s, 2); @@ -398,7 +505,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbAlternateShell > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbAlternateShell / 2, &settings->AlternateShell, 0, NULL, NULL); + /* cbAlternateShell is the size in bytes of the character data in the AlternateShell field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbAlternateShell % 2) || cbAlternateShell > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbAlternateShell value: %u", cbAlternateShell); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbAlternateShell / 2]) + { + WLog_ERR(TAG, "protocol error: AlternateShell must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->AlternateShell, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert AlternateShell string"); + return FALSE; + } Stream_Seek(s, cbAlternateShell); } Stream_Seek(s, 2); @@ -408,7 +534,26 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) if (cbWorkingDir > 0) { - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), cbWorkingDir / 2, &settings->ShellWorkingDirectory, 0, NULL, NULL); + /* cbWorkingDir is the size in bytes of the character data in the WorkingDir field. + * This size excludes (!) the length of the mandatory null terminator. + * Maximum value including the mandatory null terminator: 512 + */ + if ((cbWorkingDir % 2) || cbWorkingDir > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbWorkingDir value: %u", cbWorkingDir); + return FALSE; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbWorkingDir / 2]) + { + WLog_ERR(TAG, "protocol error: WorkingDir must be null terminated"); + return FALSE; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ShellWorkingDirectory, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert AlternateShell string"); + return FALSE; + } Stream_Seek(s, cbWorkingDir); } Stream_Seek(s, 2); @@ -660,53 +805,181 @@ BOOL rdp_send_client_info(rdpRdp* rdp) return status; } -BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s) +BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s, logon_info *info) { UINT32 cbDomain; UINT32 cbUserName; - UINT32 SessionId; + WCHAR* wstr; + + ZeroMemory(info, sizeof(*info)); if (Stream_GetRemainingLength(s) < 576) return FALSE; Stream_Read_UINT32(s, cbDomain); /* cbDomain (4 bytes) */ - Stream_Seek(s, 52); /* domain (52 bytes) */ - Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ - Stream_Seek(s, 512); /* userName (512 bytes) */ - Stream_Read_UINT32(s, SessionId); /* SessionId (4 bytes) */ - WLog_DBG(TAG, "LogonInfoV1: SessionId: 0x%04X", SessionId); + /* cbDomain is the size of the Unicode character data (including the mandatory + * null terminator) in bytes present in the fixed-length (52 bytes) Domain field + */ + if (cbDomain) + { + if ((cbDomain % 2) || cbDomain > 52) + { + WLog_ERR(TAG, "protocol error: invalid cbDomain value: %lu", cbDomain); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: Domain must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->domain, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the Domain string"); + goto fail; + } + } + Stream_Seek(s, 52); /* domain (52 bytes) */ + + + Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ + + /* cbUserName is the size of the Unicode character data (including the mandatory + * null terminator) in bytes present in the fixed-length (512 bytes) UserName field. + */ + if (cbUserName) + { + if ((cbUserName % 2) || cbUserName > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbUserName value: %lu", cbUserName); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: UserName must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->username, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the UserName string"); + goto fail; + } + } + Stream_Seek(s, 512); /* userName (512 bytes) */ + + Stream_Read_UINT32(s, info->sessionId); /* SessionId (4 bytes) */ + + WLog_DBG(TAG, "LogonInfoV1: SessionId: 0x%04X UserName: [%s] Domain: [%s]", + info->sessionId, info->username, info->domain); return TRUE; + +fail: + free(info->username); + info->username = NULL; + free(info->domain); + info->domain = NULL; + return FALSE; } -BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s) +BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) { UINT16 Version; UINT32 Size; - UINT32 SessionId; UINT32 cbDomain; UINT32 cbUserName; + WCHAR* wstr; + + ZeroMemory(info, sizeof(*info)); if (Stream_GetRemainingLength(s) < 576) return FALSE; Stream_Read_UINT16(s, Version); /* Version (2 bytes) */ Stream_Read_UINT32(s, Size); /* Size (4 bytes) */ - Stream_Read_UINT32(s, SessionId); /* SessionId (4 bytes) */ + Stream_Read_UINT32(s, info->sessionId); /* SessionId (4 bytes) */ Stream_Read_UINT32(s, cbDomain); /* cbDomain (4 bytes) */ Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ Stream_Seek(s, 558); /* pad (558 bytes) */ - if (Stream_GetRemainingLength(s) < (cbDomain + cbUserName)) - return FALSE; + /* cbDomain is the size in bytes of the Unicode character data in the Domain field. + * The size of the mandatory null terminator is include in this value. + * Note: Since MS-RDPBCGR 2.2.10.1.1.2 does not mention any size limits we assume + * that the maximum value is 52 bytes, according to the fixed size of the + * Domain field in the Logon Info Version 1 (TS_LOGON_INFO) structure. + */ + if (cbDomain) + { + if ((cbDomain % 2) || cbDomain > 52) + { + WLog_ERR(TAG, "protocol error: invalid cbDomain value: %lu", cbDomain); + goto fail; + } + if (Stream_GetRemainingLength(s) < (size_t) cbDomain) + { + WLog_ERR(TAG, "insufficient remaining stream length"); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: Domain field must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->domain, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the Domain string"); + goto fail; + } + } Stream_Seek(s, cbDomain); /* domain */ + + /* cbUserName is the size in bytes of the Unicode character data in the UserName field. + * The size of the mandatory null terminator is include in this value. + * Note: Since MS-RDPBCGR 2.2.10.1.1.2 does not mention any size limits we assume + * that the maximum value is 512 bytes, according to the fixed size of the + * Username field in the Logon Info Version 1 (TS_LOGON_INFO) structure. + */ + if (cbUserName) + { + if ((cbUserName % 2) || cbUserName < 2 || cbUserName > 512) + { + WLog_ERR(TAG, "protocol error: invalid cbUserName value: %lu", cbUserName); + goto fail; + } + if (Stream_GetRemainingLength(s) < (size_t) cbUserName) + { + WLog_ERR(TAG, "insufficient remaining stream length"); + goto fail; + } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2 - 1]) + { + WLog_ERR(TAG, "protocol error: UserName field must be null terminated"); + goto fail; + } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->username, 0, NULL, FALSE) < 1) + { + WLog_ERR(TAG, "failed to convert the Domain string"); + goto fail; + } + } Stream_Seek(s, cbUserName); /* userName */ - WLog_DBG(TAG, "LogonInfoV2: SessionId: 0x%04X", SessionId); + WLog_DBG(TAG, "LogonInfoV2: SessionId: 0x%04X UserName: [%s] Domain: [%s]", + info->sessionId, info->username, info->domain); return TRUE; + +fail: + free(info->username); + info->username = NULL; + free(info->domain); + info->domain = NULL; + return FALSE; } BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp, wStream* s) @@ -721,7 +994,7 @@ BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp, wStream* s) return TRUE; } -BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s) +BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s, logon_info_ex *info) { UINT32 errorNotificationType; UINT32 errorNotificationData; @@ -737,10 +1010,12 @@ BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s) IFCALL(rdp->instance->LogonErrorInfo, rdp->instance, errorNotificationData, errorNotificationType); + info->ErrorNotificationType = errorNotificationType; + info->ErrorNotificationData = errorNotificationData; return TRUE; } -BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) +BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s, logon_info_ex *info) { UINT32 cbFieldData; UINT32 fieldsPresent; @@ -752,7 +1027,7 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, Length); /* Length (2 bytes) */ Stream_Read_UINT32(s, fieldsPresent); /* fieldsPresent (4 bytes) */ - if (Stream_GetRemainingLength(s) < (Length - 6)) + if ((Length < 6) || (Stream_GetRemainingLength(s) < (Length - 6))) return FALSE; WLog_DBG(TAG, "LogonInfoExtended: fieldsPresent: 0x%04X", fieldsPresent); @@ -764,20 +1039,28 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) if (Stream_GetRemainingLength(s) < 4) return FALSE; + info->haveCookie = TRUE; Stream_Read_UINT32(s, cbFieldData); /* cbFieldData (4 bytes) */ - if (!rdp_read_server_auto_reconnect_cookie(rdp, s)) + if (Stream_GetRemainingLength(s) < cbFieldData) + return FALSE; + + if (!rdp_read_server_auto_reconnect_cookie(rdp, s, info)) return FALSE; } if (fieldsPresent & LOGON_EX_LOGONERRORS) { + info->haveErrorInfo = TRUE; if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, cbFieldData); /* cbFieldData (4 bytes) */ - if (!rdp_recv_logon_error_info(rdp, s)) + if (Stream_GetRemainingLength(s) < cbFieldData) + return FALSE; + + if (!rdp_recv_logon_error_info(rdp, s, info)) return FALSE; } @@ -792,7 +1075,11 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) { UINT32 infoType; - BOOL status = FALSE; + BOOL status; + logon_info logonInfo; + logon_info_ex logonInfoEx; + rdpContext *context = rdp->context; + rdpUpdate *update = rdp->context->update; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -802,22 +1089,39 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) switch (infoType) { case INFO_TYPE_LOGON: - status = rdp_recv_logon_info_v1(rdp, s); + ZeroMemory(&logonInfo, sizeof(logonInfo)); + status = rdp_recv_logon_info_v1(rdp, s, &logonInfo); + if (status && update->SaveSessionInfo) + status = update->SaveSessionInfo(context, infoType, &logonInfo); + free(logonInfo.domain); + free(logonInfo.username); break; case INFO_TYPE_LOGON_LONG: - status = rdp_recv_logon_info_v2(rdp, s); + ZeroMemory(&logonInfo, sizeof(logonInfo)); + status = rdp_recv_logon_info_v2(rdp, s, &logonInfo); + if (status && update->SaveSessionInfo) + status = update->SaveSessionInfo(context, infoType, &logonInfo); + free(logonInfo.domain); + free(logonInfo.username); break; case INFO_TYPE_LOGON_PLAIN_NOTIFY: status = rdp_recv_logon_plain_notify(rdp, s); + if (status && update->SaveSessionInfo) + status = update->SaveSessionInfo(context, infoType, NULL); break; case INFO_TYPE_LOGON_EXTENDED_INF: - status = rdp_recv_logon_info_extended(rdp, s); + ZeroMemory(&logonInfoEx, sizeof(logonInfoEx)); + status = rdp_recv_logon_info_extended(rdp, s, &logonInfoEx); + if (status && update->SaveSessionInfo) + status = update->SaveSessionInfo(context, infoType, &logonInfoEx); break; default: + WLog_ERR(TAG, "Unhandled saveSessionInfo type 0x%x", infoType); + status = TRUE; break; } @@ -830,3 +1134,174 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) return status; } +static BOOL rdp_write_logon_info_v1(wStream *s, logon_info *info) +{ + int sz = 4 + 52 + 4 + 512 + 4; + int len; + WCHAR *wString = NULL; + + if (!Stream_EnsureRemainingCapacity(s, sz)) + return FALSE; + + /* domain */ + len = ConvertToUnicode(CP_UTF8, 0, info->domain, -1, &wString, 0); + if (len < 0) + return FALSE; + len *= 2; + if (len > 52) + return FALSE; + + Stream_Write_UINT32(s, len); + Stream_Write(s, wString, len); + Stream_Seek(s, 52 - len); + free(wString); + + /* username */ + len = ConvertToUnicode(CP_UTF8, 0, info->username, -1, &wString, 0); + if (len < 0) + return FALSE; + + len *= 2; + if (len > 512) + return FALSE; + + Stream_Write_UINT32(s, len); + Stream_Write(s, wString, len); + Stream_Seek(s, 512 - len); + free(wString); + + /* sessionId */ + Stream_Write_UINT32(s, info->sessionId); + + return TRUE; +} + +static BOOL rdp_write_logon_info_v2(wStream *s, logon_info *info) +{ + int Size = 2 + 4 + 4 + 4 + 4 + 558; + int domainLen, usernameLen, len; + WCHAR *wString; + + if (!Stream_EnsureRemainingCapacity(s, Size)) + return FALSE; + + Stream_Write_UINT16(s, SAVE_SESSION_PDU_VERSION_ONE); + Stream_Write_UINT32(s, Size); + Stream_Write_UINT32(s, info->sessionId); + + domainLen = strlen(info->domain); + Stream_Write_UINT32(s, (domainLen + 1) * 2); + + usernameLen = strlen(info->username); + Stream_Write_UINT32(s, (usernameLen + 1) * 2); + + Stream_Seek(s, 558); + + len = ConvertToUnicode(CP_UTF8, 0, info->domain, -1, &wString, 0); + if (len < 0) + return FALSE; + + Stream_Write(s, wString, len * 2); + free(wString); + + len = ConvertToUnicode(CP_UTF8, 0, info->username, -1, &wString, 0); + if (len < 0) + return FALSE; + + Stream_Write(s, wString, len * 2); + free(wString); + return TRUE; +} + +static BOOL rdp_write_logon_info_plain(wStream *s) +{ + if (!Stream_EnsureRemainingCapacity(s, 576)) + return FALSE; + + Stream_Seek(s, 576); + return TRUE; +} + +static BOOL rdp_write_logon_info_ex(wStream *s, logon_info_ex *info) +{ + UINT32 FieldsPresent = 0; + UINT16 Size = 2 + 4 + 570; + + if (info->haveCookie) + { + FieldsPresent |= LOGON_EX_AUTORECONNECTCOOKIE; + Size += 28; + } + + if (info->haveErrorInfo) + { + FieldsPresent |= LOGON_EX_LOGONERRORS; + Size += 8; + } + + if (!Stream_EnsureRemainingCapacity(s, Size)) + return FALSE; + + Stream_Write_UINT16(s, Size); + Stream_Write_UINT32(s, FieldsPresent); + + if (info->haveCookie) + { + Stream_Write_UINT32(s, 28); /* cbFieldData (4 bytes) */ + + Stream_Write_UINT32(s, 28); /* cbLen (4 bytes) */ + Stream_Write_UINT32(s, AUTO_RECONNECT_VERSION_1); /* Version (4 bytes) */ + Stream_Write_UINT32(s, info->LogonId); /* LogonId (4 bytes) */ + Stream_Write(s, info->ArcRandomBits, 16); /* ArcRandomBits (16 bytes) */ + } + + if (info->haveErrorInfo) + { + Stream_Write_UINT32(s, 8); /* cbFieldData (4 bytes) */ + + Stream_Write_UINT32(s, info->ErrorNotificationType); /* ErrorNotificationType (4 bytes) */ + Stream_Write_UINT32(s, info->ErrorNotificationData); /* ErrorNotificationData (4 bytes) */ + } + + Stream_Seek(s, 570); + return TRUE; +} + +BOOL rdp_send_save_session_info(rdpContext *context, UINT32 type, void *data) +{ + wStream *s; + BOOL status; + rdpRdp *rdp = context->rdp; + + s = rdp_data_pdu_init(rdp); + if (!s) + return FALSE; + + Stream_Write_UINT32(s, type); + + switch (type) + { + case INFO_TYPE_LOGON: + status = rdp_write_logon_info_v1(s, (logon_info *)data); + break; + case INFO_TYPE_LOGON_LONG: + status = rdp_write_logon_info_v2(s, (logon_info *)data); + break; + case INFO_TYPE_LOGON_PLAIN_NOTIFY: + status = rdp_write_logon_info_plain(s); + break; + case INFO_TYPE_LOGON_EXTENDED_INF: + status = rdp_write_logon_info_ex(s, (logon_info_ex *)data); + break; + default: + WLog_ERR(TAG, "saveSessionInfo type 0x%x not handled", type); + status = FALSE; + break; + } + + if (status) + status = rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SAVE_SESSION_INFO, rdp->mcs->userId); + else + Stream_Free(s, TRUE); + return status; +} diff --git a/libfreerdp/core/info.h b/libfreerdp/core/info.h index 82bc9dac2..631fbc71c 100644 --- a/libfreerdp/core/info.h +++ b/libfreerdp/core/info.h @@ -26,11 +26,6 @@ #include -#define INFO_TYPE_LOGON 0x00000000 -#define INFO_TYPE_LOGON_LONG 0x00000001 -#define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002 -#define INFO_TYPE_LOGON_EXTENDED_INF 0x00000003 - /* Client Address Family */ #define ADDRESS_FAMILY_INET 0x0002 #define ADDRESS_FAMILY_INET6 0x0017 @@ -56,23 +51,13 @@ #define INFO_VIDEO_DISABLE 0x00400000 #define INFO_HIDEF_RAIL_SUPPORTED 0x02000000 -/* Logon Information Types */ -#define INFO_TYPE_LOGON 0x00000000 -#define INFO_TYPE_LOGON_LONG 0x00000001 -#define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002 -#define INFO_TYPE_LOGON_EXTENDED_INF 0x00000003 - /* Extended Logon Info */ #define LOGON_EX_AUTORECONNECTCOOKIE 0x00000001 #define LOGON_EX_LOGONERRORS 0x00000002 -/* Logon Error Info */ -#define LOGON_FAILED_BAD_PASSWORD 0x00000000 -#define LOGON_FAILED_UPDATE_PASSWORD 0x00000001 -#define LOGON_FAILED_OTHER 0x00000002 -#define LOGON_WARNING 0x00000003 +#define SAVE_SESSION_PDU_VERSION_ONE 0x0001 + -BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); void rdp_write_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); @@ -83,5 +68,6 @@ void rdp_write_info_packet(rdpRdp* rdp, wStream* s); BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s); BOOL rdp_send_client_info(rdpRdp* rdp); BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s); +BOOL rdp_send_save_session_info(rdpContext *context, UINT32 type, void *data); #endif /* __INFO_H */ diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index 23de184bb..055a2dc3e 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -23,6 +23,7 @@ #endif #include +#include #include #include "redirection.h" @@ -328,10 +329,10 @@ void license_generate_randoms(rdpLicense* license) ZeroMemory(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ ZeroMemory(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ #ifndef LICENSE_NULL_CLIENT_RANDOM - crypto_nonce(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ + winpr_RAND(license->ClientRandom, CLIENT_RANDOM_LENGTH); /* ClientRandom */ #endif #ifndef LICENSE_NULL_PREMASTER_SECRET - crypto_nonce(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ + winpr_RAND(license->PremasterSecret, PREMASTER_SECRET_LENGTH); /* PremasterSecret */ #endif } @@ -384,22 +385,19 @@ BOOL license_generate_keys(rdpLicense* license) BOOL license_generate_hwid(rdpLicense* license) { - CryptoMd5 md5; + WINPR_MD5_CTX md5; BYTE macAddress[6]; ZeroMemory(macAddress, sizeof(macAddress)); ZeroMemory(license->HardwareId, HWID_LENGTH); - md5 = crypto_md5_init(); - - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, macAddress, sizeof(macAddress))) + return FALSE; + if (!winpr_MD5_Final(&md5, &license->HardwareId[HWID_PLATFORM_ID_LENGTH], WINPR_MD5_DIGEST_LENGTH)) return FALSE; - } - crypto_md5_update(md5, macAddress, sizeof(macAddress)); - crypto_md5_final(md5, &license->HardwareId[HWID_PLATFORM_ID_LENGTH]); return TRUE; } @@ -460,28 +458,23 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license) BOOL license_decrypt_platform_challenge(rdpLicense* license) { - CryptoRc4 rc4; + BOOL rc; + WINPR_RC4_CTX* rc4; license->PlatformChallenge->data = (BYTE *)malloc(license->EncryptedPlatformChallenge->length); if (!license->PlatformChallenge->data) return FALSE; license->PlatformChallenge->length = license->EncryptedPlatformChallenge->length; - rc4 = crypto_rc4_init(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); - if (!rc4) - { - WLog_ERR(TAG, "unable to allocate a rc4"); - free(license->PlatformChallenge->data); - license->PlatformChallenge->data = NULL; + if ((rc4 = winpr_RC4_New(license->LicensingEncryptionKey, + LICENSING_ENCRYPTION_KEY_LENGTH)) == NULL) return FALSE; - } - - crypto_rc4(rc4, license->EncryptedPlatformChallenge->length, + rc = winpr_RC4_Update(rc4, license->EncryptedPlatformChallenge->length, license->EncryptedPlatformChallenge->data, license->PlatformChallenge->data); - crypto_rc4_free(rc4); - return TRUE; + winpr_RC4_Free(rc4); + return rc; } /** @@ -1025,7 +1018,7 @@ BOOL license_send_platform_challenge_response_packet(rdpLicense* license) wStream* s; int length; BYTE* buffer; - CryptoRc4 rc4; + WINPR_RC4_CTX* rc4; BYTE mac_data[16]; BOOL status; @@ -1046,19 +1039,23 @@ BOOL license_send_platform_challenge_response_packet(rdpLicense* license) if (!status) return FALSE; - rc4 = crypto_rc4_init(license->LicensingEncryptionKey, LICENSING_ENCRYPTION_KEY_LENGTH); + rc4 = winpr_RC4_New(license->LicensingEncryptionKey, + LICENSING_ENCRYPTION_KEY_LENGTH); if (!rc4) - { - WLog_ERR(TAG, "unable to allocate a rc4"); return FALSE; - } buffer = (BYTE*) malloc(HWID_LENGTH); if (!buffer) return FALSE; - crypto_rc4(rc4, HWID_LENGTH, license->HardwareId, buffer); - crypto_rc4_free(rc4); + status = winpr_RC4_Update(rc4, HWID_LENGTH, license->HardwareId, buffer); + winpr_RC4_Free(rc4); + if (!status) + { + free(buffer); + return FALSE; + } + license->EncryptedHardwareId->type = BB_DATA_BLOB; license->EncryptedHardwareId->data = buffer; license->EncryptedHardwareId->length = HWID_LENGTH; diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index 8d082b155..27c9126c6 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -571,7 +571,7 @@ BOOL mcs_write_connect_initial(wStream* s, rdpMcs* mcs, wStream* userData) goto out; /* userData (OCTET_STRING) */ - ber_write_octet_string(tmps, userData->buffer, Stream_GetPosition(userData)); + ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)); length = Stream_GetPosition(tmps); /* Connect-Initial (APPLICATION 101, IMPLICIT SEQUENCE) */ @@ -608,7 +608,7 @@ BOOL mcs_write_connect_response(wStream* s, rdpMcs* mcs, wStream* userData) if (!mcs_write_domain_parameters(tmps, &(mcs->domainParameters))) goto out; /* userData (OCTET_STRING) */ - ber_write_octet_string(tmps, userData->buffer, Stream_GetPosition(userData)); + ber_write_octet_string(tmps, Stream_Buffer(userData), Stream_GetPosition(userData)); length = Stream_GetPosition(tmps); ber_write_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, length); diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index adc0e0f49..a56d1b58d 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -188,19 +188,12 @@ static BOOL update_message_SurfaceCommand(rdpContext* context, wStream* s) { wStream* wParam; - wParam = (wStream*) malloc(sizeof(wStream)); + wParam = Stream_New(NULL, Stream_GetRemainingLength(s)); if (!wParam) return FALSE; - wParam->capacity = Stream_Capacity(s); - wParam->buffer = (BYTE*) malloc(wParam->capacity); - if (!wParam->buffer) - { - free(wParam); - return FALSE; - } - - wParam->pointer = wParam->buffer; + Stream_Copy(s, wParam, Stream_GetRemainingLength(s)); + Stream_SetPosition(wParam, 0); return MessageQueue_Post(context->update->queue, (void*) context, MakeMessageId(Update, SurfaceCommand), (void*) wParam, NULL); @@ -2058,7 +2051,7 @@ int update_message_free_pointer_update_class(wMessage* msg, int type) free(wParam); } break; - + case PointerUpdate_PointerNew: { POINTER_NEW_UPDATE* wParam = (POINTER_NEW_UPDATE*) msg->wParam; @@ -2091,11 +2084,11 @@ static int update_message_process_pointer_update_class(rdpUpdateProxy* proxy, wM break; case PointerUpdate_PointerColor: - IFCALL(proxy->PointerColor, msg->context, (POINTER_COLOR_UPDATE*) msg->wParam); + IFCALL(proxy->PointerColor, msg->context, (POINTER_COLOR_UPDATE*) msg->wParam); break; case PointerUpdate_PointerNew: - IFCALL(proxy->PointerNew, msg->context, (POINTER_NEW_UPDATE*) msg->wParam); + IFCALL(proxy->PointerNew, msg->context, (POINTER_NEW_UPDATE*) msg->wParam); break; case PointerUpdate_PointerCached: @@ -2220,7 +2213,7 @@ int update_message_queue_free_message(wMessage *message) int msgType; assert(message); - + if (message->id == WMQ_QUIT) return 0; diff --git a/libfreerdp/core/nla.h b/libfreerdp/core/nla.h index 774bcc985..b1afeba85 100644 --- a/libfreerdp/core/nla.h +++ b/libfreerdp/core/nla.h @@ -27,6 +27,7 @@ typedef struct rdp_nla rdpNla; #include #include +#include #include #include @@ -75,7 +76,7 @@ struct rdp_nla SecBuffer authInfo; SecBuffer PublicKey; SecBuffer tsCredentials; - CryptoRc4 rc4SealState; + WINPR_RC4_CTX rc4SealState; LPTSTR ServicePrincipalName; SEC_WINNT_AUTH_IDENTITY* identity; PSecurityFunctionTable table; diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 60aed90b8..49df89add 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -1728,7 +1728,7 @@ BOOL update_read_fast_glyph_order(wStream* s, ORDER_INFO* orderInfo, FAST_GLYPH_ } } - Stream_Pointer(s) = phold + fastGlyph->cbData; + Stream_SetPointer(s, phold + fastGlyph->cbData); } return TRUE; @@ -3546,7 +3546,7 @@ BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, BYTE flags) break; } - Stream_Pointer(s) = next; + Stream_SetPointer(s, next); return TRUE; } diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 2675a22f5..b433566f7 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -204,8 +204,7 @@ static int rdp_security_stream_init(rdpRdp* rdp, wStream* s, BOOL sec_header) int rdp_init_stream(rdpRdp* rdp, wStream* s) { Stream_Seek(s, RDP_PACKET_HEADER_MAX_LENGTH); - rdp_security_stream_init(rdp, s, FALSE); - return 0; + return rdp_security_stream_init(rdp, s, FALSE); } wStream* rdp_send_stream_init(rdpRdp* rdp) @@ -340,10 +339,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) return FALSE; if (!rdp->instance) - { - freerdp_abort_connect(rdp->instance); return FALSE; - } context = rdp->instance->context; @@ -671,8 +667,7 @@ BOOL rdp_recv_set_error_info_data_pdu(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, errorInfo); /* errorInfo (4 bytes) */ - rdp_set_error_info(rdp, errorInfo); - return TRUE; + return rdp_set_error_info(rdp, errorInfo); } BOOL rdp_recv_server_auto_reconnect_status_pdu(rdpRdp* rdp, wStream* s) @@ -1061,7 +1056,7 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, int length, UINT16 securityFlags) return FALSE; /* TODO */ } - Stream_Length(s) -= pad; + Stream_SetLength(s, Stream_Length(s) - pad); return TRUE; } @@ -1415,6 +1410,8 @@ BOOL rdp_send_error_info(rdpRdp* rdp) return TRUE; s = rdp_data_pdu_init(rdp); + if (!s) + return FALSE; Stream_Write_UINT32(s, rdp->errorInfo); /* error id (4 bytes) */ @@ -1593,31 +1590,31 @@ void rdp_reset(rdpRdp* rdp) if (rdp->rc4_decrypt_key) { - crypto_rc4_free(rdp->rc4_decrypt_key); + winpr_RC4_Free(rdp->rc4_decrypt_key); rdp->rc4_decrypt_key = NULL; } if (rdp->rc4_encrypt_key) { - crypto_rc4_free(rdp->rc4_encrypt_key); + winpr_RC4_Free(rdp->rc4_encrypt_key); rdp->rc4_encrypt_key = NULL; } if (rdp->fips_encrypt) { - crypto_des3_free(rdp->fips_encrypt); + winpr_Cipher_Free(rdp->fips_encrypt); rdp->fips_encrypt = NULL; } if (rdp->fips_decrypt) { - crypto_des3_free(rdp->fips_decrypt); + winpr_Cipher_Free(rdp->fips_decrypt); rdp->fips_decrypt = NULL; } if (rdp->fips_hmac) { - crypto_hmac_free(rdp->fips_hmac); + free(rdp->fips_hmac); rdp->fips_hmac = NULL; } @@ -1664,11 +1661,11 @@ void rdp_free(rdpRdp* rdp) { if (rdp) { - crypto_rc4_free(rdp->rc4_decrypt_key); - crypto_rc4_free(rdp->rc4_encrypt_key); - crypto_des3_free(rdp->fips_encrypt); - crypto_des3_free(rdp->fips_decrypt); - crypto_hmac_free(rdp->fips_hmac); + winpr_RC4_Free(rdp->rc4_decrypt_key); + winpr_RC4_Free(rdp->rc4_encrypt_key); + winpr_Cipher_Free(rdp->fips_encrypt); + winpr_Cipher_Free(rdp->fips_decrypt); + free(rdp->fips_hmac); freerdp_settings_free(rdp->settings); freerdp_settings_free(rdp->settingsCopy); transport_free(rdp->transport); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index ad24bd4f1..ef8e0dc4a 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -51,6 +51,7 @@ #include #include +#include /* Security Header Flags */ #define SEC_EXCHANGE_PKT 0x0001 @@ -147,15 +148,15 @@ struct rdp_rdp rdpAutoDetect* autodetect; rdpHeartbeat* heartbeat; rdpMultitransport* multitransport; - struct crypto_rc4_struct* rc4_decrypt_key; + WINPR_RC4_CTX* rc4_decrypt_key; int decrypt_use_count; int decrypt_checksum_use_count; - struct crypto_rc4_struct* rc4_encrypt_key; + WINPR_RC4_CTX* rc4_encrypt_key; int encrypt_use_count; int encrypt_checksum_use_count; - struct crypto_des3_struct* fips_encrypt; - struct crypto_des3_struct* fips_decrypt; - struct crypto_hmac_struct* fips_hmac; + WINPR_CIPHER_CTX* fips_encrypt; + WINPR_CIPHER_CTX* fips_decrypt; + WINPR_HMAC_CTX* fips_hmac; UINT32 sec_flags; BOOL do_crypt; BOOL do_crypt_license; diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 6d3125749..092290215 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -30,7 +30,7 @@ #define TAG FREERDP_TAG("core.redirection") -void rdp_print_redirection_flags(UINT32 flags) +static void rdp_print_redirection_flags(UINT32 flags) { WLog_DBG(TAG, "redirectionFlags = {"); @@ -76,9 +76,10 @@ void rdp_print_redirection_flags(UINT32 flags) WLog_DBG(TAG, "}"); } -BOOL rdp_redirection_read_string(wStream* s, char** str) +static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t maxLength) { UINT32 length; + WCHAR* wstr = NULL; if (Stream_GetRemainingLength(s) < 4) { @@ -88,13 +89,31 @@ BOOL rdp_redirection_read_string(wStream* s, char** str) Stream_Read_UINT32(s, length); - if (Stream_GetRemainingLength(s) < length) + if ((length % 2) || length < 2 || length > maxLength) { - WLog_ERR(TAG, "rdp_redirection_read_string failure: incorrect length %d", length); + WLog_ERR(TAG, "rdp_redirection_read_string failure: invalid unicode string length: %lu", length); return FALSE; } - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), length / 2, str, 0, NULL, NULL); + if (Stream_GetRemainingLength(s) < length) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: insufficient stream length (%lu bytes required)", length); + return FALSE; + } + + wstr = (WCHAR*) Stream_Pointer(s); + + if (wstr[length / 2 - 1]) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: unterminated unicode string"); + return FALSE; + } + + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, str, 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: string conversion failed"); + return FALSE; + } Stream_Seek(s, length); return TRUE; } @@ -173,7 +192,10 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) /* Password may be a cookie without a null terminator */ free(settings->RedirectionPassword); settings->RedirectionPasswordLength = redirection->PasswordLength; - settings->RedirectionPassword = (BYTE*) malloc(settings->RedirectionPasswordLength); + /* For security reasons we'll allocate an additional zero WCHAR at the + * end of the buffer that is not included in RedirectionPasswordLength + */ + settings->RedirectionPassword = (BYTE*) calloc(1, settings->RedirectionPasswordLength + sizeof(WCHAR)); if (!settings->RedirectionPassword) return -1; CopyMemory(settings->RedirectionPassword, redirection->Password, settings->RedirectionPasswordLength); @@ -219,7 +241,7 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) return 0; } -BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) +static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { UINT16 flags; UINT16 length; @@ -238,14 +260,33 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) rdp_print_redirection_flags(redirection->flags); + /* Although MS-RDPBCGR does not mention any length constraints limits for the + * variable length null-terminated unicode strings in the RDP_SERVER_REDIRECTION_PACKET + * structure we will use the following limits in bytes including the null terminator: + * + * TargetNetAddress: 80 bytes + * UserName: 512 bytes + * Domain: 52 bytes + * Password(Cookie): 512 bytes + * TargetFQDN: 512 bytes + * TargetNetBiosName: 32 bytes + */ + if (redirection->flags & LB_TARGET_NET_ADDRESS) { - if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddress))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80)) return -1; } if (redirection->flags & LB_LOAD_BALANCE_INFO) { + /* See [MSFT-SDLBTS] (a.k.a. TS_Session_Directory.doc) + * load balance info example data: + * 0000 43 6f 6f 6b 69 65 3a 20 6d 73 74 73 3d 32 31 33 Cookie: msts=213 + * 0010 34 30 32 36 34 33 32 2e 31 35 36 32 39 2e 30 30 4026432.15629.00 + * 0020 30 30 0d 0a 00.. + */ + if (Stream_GetRemainingLength(s) < 4) return -1; @@ -265,7 +306,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_USERNAME) { - if (!rdp_redirection_read_string(s, &(redirection->Username))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512)) return -1; WLog_DBG(TAG, "Username: %s", redirection->Username); @@ -273,7 +314,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_DOMAIN) { - if (!rdp_redirection_read_string(s, &(redirection->Domain))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52)) return FALSE; WLog_DBG(TAG, "Domain: %s", redirection->Domain); @@ -281,12 +322,45 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_PASSWORD) { - /* Note: length (hopefully) includes double zero termination */ + /* Note: Password is a variable-length array of bytes containing the + * password used by the user in Unicode format, including a null-terminator + * or (!) or a cookie value that MUST be passed to the target server on + * successful connection. + * Since the format of the password cookie (probably some salted hash) is + * currently unknown we'll treat it as opaque data. All cookies seen so far + * are 120 bytes including \0\0 termination. + * Here is an observed example of a redirection password cookie: + * + * 0000 02 00 00 80 44 53 48 4c 60 ab 69 2f 07 d6 9e 2d ....DSHL`.i/...- + * 0010 f0 3a 97 3b a9 c5 ec 7e 66 bd b3 84 6c b1 ef b9 .:.;...~f...l... + * 0020 b6 82 4e cc 3a df 64 b7 7b 25 04 54 c2 58 98 f8 ..N.:.d.{%.T.X.. + * 0030 97 87 d4 93 c7 c1 e1 5b c2 85 f8 22 49 1f 81 88 .......[..."I... + * 0040 43 44 83 f6 9a 72 40 24 dc 4d 43 cb d9 92 3c 8f CD...r@$.MC...<. + * 0050 3a 37 5c 77 13 a0 72 3c 72 08 64 2a 29 fb dc eb :7\w..rPasswordLength); - redirection->Password = (BYTE*) malloc(redirection->PasswordLength); + + /* [MS-RDPBCGR] specifies 512 bytes as the upper limit for the password length + * including the null terminatior(s). This should also be enough for the unknown + * password cookie format (see previous comment). + */ + + if (Stream_GetRemainingLength(s) < redirection->PasswordLength) + return -1; + + if (redirection->PasswordLength > 512) + return -1; + + redirection->Password = (BYTE*) calloc(1, redirection->PasswordLength + sizeof(WCHAR)); if (!redirection->Password) return -1; Stream_Read(s, redirection->Password, redirection->PasswordLength); @@ -297,7 +371,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_FQDN) { - if (!rdp_redirection_read_string(s, &(redirection->TargetFQDN))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512)) return -1; WLog_DBG(TAG, "TargetFQDN: %s", redirection->TargetFQDN); @@ -305,7 +379,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_NETBIOS_NAME) { - if (!rdp_redirection_read_string(s, &(redirection->TargetNetBiosName))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32)) return -1; WLog_DBG(TAG, "TargetNetBiosName: %s", redirection->TargetNetBiosName); @@ -352,7 +426,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) for (i = 0; i < (int) count; i++) { - if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddresses[i]))) + if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80)) return FALSE; WLog_DBG(TAG, "TargetNetAddresses[%d]: %s", i, redirection->TargetNetAddresses[i]); @@ -371,13 +445,6 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) return 1; } -int rdp_recv_redirection_packet(rdpRdp* rdp, wStream* s) -{ - int status = 0; - status = rdp_recv_server_redirection_pdu(rdp, s); - return status; -} - int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s) { int status = 0; diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index 44c7190f9..e41578687 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -25,6 +25,7 @@ #include "security.h" #include +#include #define TAG FREERDP_TAG("core") @@ -126,35 +127,35 @@ fips_oddparity_table[256] = static BOOL security_salted_hash(const BYTE* salt, const BYTE* input, int length, const BYTE* salt1, const BYTE* salt2, BYTE* output) { - CryptoMd5 md5; - CryptoSha1 sha1; - BYTE sha1_digest[CRYPTO_SHA1_DIGEST_LENGTH]; + WINPR_MD5_CTX md5; + WINPR_SHA1_CTX sha1; + BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH]; /* SaltedHash(Salt, Input, Salt1, Salt2) = MD5(S + SHA1(Input + Salt + Salt1 + Salt2)) */ /* SHA1_Digest = SHA1(Input + Salt + Salt1 + Salt2) */ - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, input, length)) /* Input */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, salt, 48)) /* Salt (48 bytes) */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, salt1, 32)) /* Salt1 (32 bytes) */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, salt2, 32)) /* Salt2 (32 bytes) */ + return FALSE; + if (!winpr_SHA1_Final(&sha1, sha1_digest, sizeof(sha1_digest))) return FALSE; - } - crypto_sha1_update(sha1, input, length); /* Input */ - crypto_sha1_update(sha1, salt, 48); /* Salt (48 bytes) */ - crypto_sha1_update(sha1, salt1, 32); /* Salt1 (32 bytes) */ - crypto_sha1_update(sha1, salt2, 32); /* Salt2 (32 bytes) */ - crypto_sha1_final(sha1, sha1_digest); /* SaltedHash(Salt, Input, Salt1, Salt2) = MD5(S + SHA1_Digest) */ - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, salt, 48)) /* Salt (48 bytes) */ + return FALSE; + if (!winpr_MD5_Update(&md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */ + return FALSE; + if (!winpr_MD5_Final(&md5, output, WINPR_MD5_DIGEST_LENGTH)) return FALSE; - } - crypto_md5_update(md5, salt, 48); /* Salt (48 bytes) */ - crypto_md5_update(md5, sha1_digest, sizeof(sha1_digest)); /* SHA1_Digest */ - crypto_md5_final(md5, output); return TRUE; } @@ -199,18 +200,18 @@ void security_mac_salt_key(const BYTE* session_key_blob, const BYTE* client_rand BOOL security_md5_16_32_32(const BYTE* in0, const BYTE* in1, const BYTE* in2, BYTE* output) { - CryptoMd5 md5; + WINPR_MD5_CTX md5; - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, in0, 16)) + return FALSE; + if (!winpr_MD5_Update(&md5, in1, 32)) + return FALSE; + if (!winpr_MD5_Update(&md5, in2, 32)) + return FALSE; + if (!winpr_MD5_Final(&md5, output, WINPR_MD5_DIGEST_LENGTH)) return FALSE; - } - crypto_md5_update(md5, in0, 16); - crypto_md5_update(md5, in1, 32); - crypto_md5_update(md5, in2, 32); - crypto_md5_final(md5, output); return TRUE; } @@ -232,76 +233,78 @@ void security_UINT32_le(BYTE* output, UINT32 value) BOOL security_mac_data(const BYTE* mac_salt_key, const BYTE* data, UINT32 length, BYTE* output) { - CryptoMd5 md5; - CryptoSha1 sha1; + WINPR_MD5_CTX md5; + WINPR_SHA1_CTX sha1; BYTE length_le[4]; - BYTE sha1_digest[CRYPTO_SHA1_DIGEST_LENGTH]; + BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH]; /* MacData = MD5(MacSaltKey + pad2 + SHA1(MacSaltKey + pad1 + length + data)) */ security_UINT32_le(length_le, length); /* length must be little-endian */ /* SHA1_Digest = SHA1(MacSaltKey + pad1 + length + data) */ - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, mac_salt_key, 16)) /* MacSaltKey */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, pad1, sizeof(pad1))) /* pad1 */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, length_le, sizeof(length_le))) /* length */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, data, length)) /* data */ + return FALSE; + if (!winpr_SHA1_Final(&sha1, sha1_digest, sizeof(sha1_digest))) return FALSE; - } - crypto_sha1_update(sha1, mac_salt_key, 16); /* MacSaltKey */ - crypto_sha1_update(sha1, pad1, sizeof(pad1)); /* pad1 */ - crypto_sha1_update(sha1, length_le, sizeof(length_le)); /* length */ - crypto_sha1_update(sha1, data, length); /* data */ - crypto_sha1_final(sha1, sha1_digest); /* MacData = MD5(MacSaltKey + pad2 + SHA1_Digest) */ - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, mac_salt_key, 16)) /* MacSaltKey */ + return FALSE; + if (!winpr_MD5_Update(&md5, pad2, sizeof(pad2))) /* pad2 */ + return FALSE; + if (!winpr_MD5_Update(&md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */ + return FALSE; + if (!winpr_MD5_Final(&md5, output, WINPR_MD5_DIGEST_LENGTH)) return FALSE; - } - crypto_md5_update(md5, mac_salt_key, 16); /* MacSaltKey */ - crypto_md5_update(md5, pad2, sizeof(pad2)); /* pad2 */ - crypto_md5_update(md5, sha1_digest, sizeof(sha1_digest)); /* SHA1_Digest */ - crypto_md5_final(md5, output); return TRUE; } BOOL security_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BYTE* output) { - CryptoMd5 md5; - CryptoSha1 sha1; + WINPR_MD5_CTX md5; + WINPR_SHA1_CTX sha1; BYTE length_le[4]; - BYTE md5_digest[CRYPTO_MD5_DIGEST_LENGTH]; - BYTE sha1_digest[CRYPTO_SHA1_DIGEST_LENGTH]; + BYTE md5_digest[WINPR_MD5_DIGEST_LENGTH]; + BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH]; security_UINT32_le(length_le, length); /* length must be little-endian */ /* SHA1_Digest = SHA1(MACKeyN + pad1 + length + data) */ - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, pad1, sizeof(pad1))) /* pad1 */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, length_le, sizeof(length_le))) /* length */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, data, length)) /* data */ + return FALSE; + if (!winpr_SHA1_Final(&sha1, sha1_digest, sizeof(sha1_digest))) return FALSE; - } - crypto_sha1_update(sha1, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ - crypto_sha1_update(sha1, pad1, sizeof(pad1)); /* pad1 */ - crypto_sha1_update(sha1, length_le, sizeof(length_le)); /* length */ - crypto_sha1_update(sha1, data, length); /* data */ - crypto_sha1_final(sha1, sha1_digest); /* MACSignature = First64Bits(MD5(MACKeyN + pad2 + SHA1_Digest)) */ - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */ + return FALSE; + if (!winpr_MD5_Update(&md5, pad2, sizeof(pad2))) /* pad2 */ + return FALSE; + if (!winpr_MD5_Update(&md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */ + return FALSE; + if (!winpr_MD5_Final(&md5, md5_digest, sizeof(md5_digest))) return FALSE; - } - crypto_md5_update(md5, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ - crypto_md5_update(md5, pad2, sizeof(pad2)); /* pad2 */ - crypto_md5_update(md5, sha1_digest, sizeof(sha1_digest)); /* SHA1_Digest */ - crypto_md5_final(md5, md5_digest); memcpy(output, md5_digest, 8); return TRUE; @@ -310,12 +313,12 @@ BOOL security_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BYTE* BOOL security_salted_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, BOOL encryption, BYTE* output) { - CryptoMd5 md5; - CryptoSha1 sha1; + WINPR_MD5_CTX md5; + WINPR_SHA1_CTX sha1; BYTE length_le[4]; BYTE use_count_le[4]; - BYTE md5_digest[CRYPTO_MD5_DIGEST_LENGTH]; - BYTE sha1_digest[CRYPTO_SHA1_DIGEST_LENGTH]; + BYTE md5_digest[WINPR_MD5_DIGEST_LENGTH]; + BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH]; security_UINT32_le(length_le, length); /* length must be little-endian */ @@ -333,30 +336,32 @@ BOOL security_salted_mac_signature(rdpRdp *rdp, const BYTE* data, UINT32 length, } /* SHA1_Digest = SHA1(MACKeyN + pad1 + length + data) */ - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, pad1, sizeof(pad1))) /* pad1 */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, length_le, sizeof(length_le))) /* length */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, data, length)) /* data */ + return FALSE; + if (!winpr_SHA1_Update(&sha1, use_count_le, sizeof(use_count_le))) /* encryptionCount */ + return FALSE; + if (!winpr_SHA1_Final(&sha1, sha1_digest, sizeof(sha1_digest))) return FALSE; - } - crypto_sha1_update(sha1, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ - crypto_sha1_update(sha1, pad1, sizeof(pad1)); /* pad1 */ - crypto_sha1_update(sha1, length_le, sizeof(length_le)); /* length */ - crypto_sha1_update(sha1, data, length); /* data */ - crypto_sha1_update(sha1, use_count_le, sizeof(use_count_le)); /* encryptionCount */ - crypto_sha1_final(sha1, sha1_digest); /* MACSignature = First64Bits(MD5(MACKeyN + pad2 + SHA1_Digest)) */ - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, rdp->sign_key, rdp->rc4_key_len)) /* MacKeyN */ + return FALSE; + if (!winpr_MD5_Update(&md5, pad2, sizeof(pad2))) /* pad2 */ + return FALSE; + if (!winpr_MD5_Update(&md5, sha1_digest, sizeof(sha1_digest))) /* SHA1_Digest */ + return FALSE; + if (!winpr_MD5_Final(&md5, md5_digest, sizeof(md5_digest))) return FALSE; - } - crypto_md5_update(md5, rdp->sign_key, rdp->rc4_key_len); /* MacKeyN */ - crypto_md5_update(md5, pad2, sizeof(pad2)); /* pad2 */ - crypto_md5_update(md5, sha1_digest, sizeof(sha1_digest)); /* SHA1_Digest */ - crypto_md5_final(md5, md5_digest); memcpy(output, md5_digest, 8); return TRUE; @@ -428,40 +433,38 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS) { - CryptoSha1 sha1; - BYTE client_encrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1]; - BYTE client_decrypt_key_t[CRYPTO_SHA1_DIGEST_LENGTH + 1]; - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + WINPR_SHA1_CTX sha1; + BYTE client_encrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1]; + BYTE client_decrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1]; + + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, client_random + 16, 16)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, server_random + 16, 16)) + return FALSE; + if (!winpr_SHA1_Final(&sha1, client_encrypt_key_t, sizeof(client_encrypt_key_t))) return FALSE; - } - crypto_sha1_update(sha1, client_random + 16, 16); - crypto_sha1_update(sha1, server_random + 16, 16); - crypto_sha1_final(sha1, client_encrypt_key_t); client_encrypt_key_t[20] = client_encrypt_key_t[0]; - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, client_random, 16)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, server_random, 16)) + return FALSE; + if (!winpr_SHA1_Final(&sha1, client_decrypt_key_t, sizeof(client_decrypt_key_t))) return FALSE; - } - crypto_sha1_update(sha1, client_random, 16); - crypto_sha1_update(sha1, server_random, 16); - crypto_sha1_final(sha1, client_decrypt_key_t); client_decrypt_key_t[20] = client_decrypt_key_t[0]; - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, client_decrypt_key_t, WINPR_SHA1_DIGEST_LENGTH)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, client_encrypt_key_t, WINPR_SHA1_DIGEST_LENGTH)) + return FALSE; + if (!winpr_SHA1_Final(&sha1, rdp->fips_sign_key, WINPR_SHA1_DIGEST_LENGTH)) return FALSE; - } - crypto_sha1_update(sha1, client_decrypt_key_t, 20); - crypto_sha1_update(sha1, client_encrypt_key_t, 20); - crypto_sha1_final(sha1, rdp->fips_sign_key); if (rdp->settings->ServerMode) { @@ -532,42 +535,42 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp) BOOL security_key_update(BYTE* key, BYTE* update_key, int key_len, rdpRdp* rdp) { - BYTE sha1h[CRYPTO_SHA1_DIGEST_LENGTH]; - CryptoMd5 md5; - CryptoSha1 sha1; - CryptoRc4 rc4; + BYTE sha1h[WINPR_SHA1_DIGEST_LENGTH]; + WINPR_MD5_CTX md5; + WINPR_SHA1_CTX sha1; + WINPR_RC4_CTX* rc4; + BOOL rc; BYTE salt[] = { 0xD1, 0x26, 0x9E }; /* 40 bits: 3 bytes, 56 bits: 1 byte */ - sha1 = crypto_sha1_init(); - if (!sha1) - { - WLog_ERR(TAG, "unable to allocate a sha1"); + if (!winpr_SHA1_Init(&sha1)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, update_key, key_len)) + return FALSE; + if (!winpr_SHA1_Update(&sha1, pad1, sizeof(pad1))) + return FALSE; + if (!winpr_SHA1_Update(&sha1, key, key_len)) + return FALSE; + if (!winpr_SHA1_Final(&sha1, sha1h, sizeof(sha1h))) return FALSE; - } - crypto_sha1_update(sha1, update_key, key_len); - crypto_sha1_update(sha1, pad1, sizeof(pad1)); - crypto_sha1_update(sha1, key, key_len); - crypto_sha1_final(sha1, sha1h); - md5 = crypto_md5_init(); - if (!md5) - { - WLog_ERR(TAG, "unable to allocate a md5"); + if (!winpr_MD5_Init(&md5)) + return FALSE; + if (!winpr_MD5_Update(&md5, update_key, key_len)) + return FALSE; + if (!winpr_MD5_Update(&md5, pad2, sizeof(pad2))) + return FALSE; + if (!winpr_MD5_Update(&md5, sha1h, sizeof(sha1h))) + return FALSE; + if (!winpr_MD5_Final(&md5, key, WINPR_MD5_DIGEST_LENGTH)) return FALSE; - } - crypto_md5_update(md5, update_key, key_len); - crypto_md5_update(md5, pad2, sizeof(pad2)); - crypto_md5_update(md5, sha1h, sizeof(sha1h)); - crypto_md5_final(md5, key); - rc4 = crypto_rc4_init(key, key_len); - if (!rc4) - { - WLog_ERR(TAG, "unable to allocate a rc4"); + if ((rc4 = winpr_RC4_New(key, key_len)) == NULL) + return FALSE; + rc = winpr_RC4_Update(rc4, key_len, key, key); + winpr_RC4_Free(rc4); + + if (!rc) return FALSE; - } - crypto_rc4(rc4, key_len, key, key); - crypto_rc4_free(rc4); if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT) memcpy(key, salt, 3); @@ -584,17 +587,16 @@ BOOL security_encrypt(BYTE* data, int length, rdpRdp* rdp) if (!security_key_update(rdp->encrypt_key, rdp->encrypt_update_key, rdp->rc4_key_len, rdp)) return FALSE; - crypto_rc4_free(rdp->rc4_encrypt_key); - rdp->rc4_encrypt_key = crypto_rc4_init(rdp->encrypt_key, rdp->rc4_key_len); + winpr_RC4_Free(rdp->rc4_encrypt_key); + rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); if (!rdp->rc4_encrypt_key) - { - WLog_ERR(TAG, "unable to allocate rc4 encrypt key"); return FALSE; - } + rdp->encrypt_use_count = 0; } - crypto_rc4(rdp->rc4_encrypt_key, length, data, data); + if (!winpr_RC4_Update(rdp->rc4_encrypt_key, length, data, data)) + return FALSE; rdp->encrypt_use_count++; rdp->encrypt_checksum_use_count++; return TRUE; @@ -609,17 +611,16 @@ BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp) { if (!security_key_update(rdp->decrypt_key, rdp->decrypt_update_key, rdp->rc4_key_len, rdp)) return FALSE; - crypto_rc4_free(rdp->rc4_decrypt_key); - rdp->rc4_decrypt_key = crypto_rc4_init(rdp->decrypt_key, rdp->rc4_key_len); + winpr_RC4_Free(rdp->rc4_decrypt_key); + rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, + rdp->rc4_key_len); if (!rdp->rc4_decrypt_key) - { - WLog_ERR(TAG, "unable to allocate rc4 decrypt key"); return FALSE; - } rdp->decrypt_use_count = 0; } - crypto_rc4(rdp->rc4_decrypt_key, length, data, data); + if (!winpr_RC4_Update(rdp->rc4_decrypt_key, length, data, data)) + return FALSE; rdp->decrypt_use_count += 1; rdp->decrypt_checksum_use_count++; return TRUE; @@ -627,17 +628,20 @@ BOOL security_decrypt(BYTE* data, int length, rdpRdp* rdp) BOOL security_hmac_signature(const BYTE* data, int length, BYTE* output, rdpRdp* rdp) { - BYTE buf[20]; + BYTE buf[WINPR_SHA1_DIGEST_LENGTH]; BYTE use_count_le[4]; security_UINT32_le(use_count_le, rdp->encrypt_use_count); - if (!crypto_hmac_sha1_init(rdp->fips_hmac, rdp->fips_sign_key, 20)) + if (!winpr_HMAC_Init(rdp->fips_hmac, WINPR_MD_SHA1, + rdp->fips_sign_key, WINPR_SHA1_DIGEST_LENGTH)) + return FALSE; + if (!winpr_HMAC_Update(rdp->fips_hmac, data, length)) + return FALSE; + if (!winpr_HMAC_Update(rdp->fips_hmac, use_count_le, 4)) + return FALSE; + if (!winpr_HMAC_Final(rdp->fips_hmac, buf, WINPR_SHA1_DIGEST_LENGTH)) return FALSE; - - crypto_hmac_update(rdp->fips_hmac, data, length); - crypto_hmac_update(rdp->fips_hmac, use_count_le, 4); - crypto_hmac_final(rdp->fips_hmac, buf, 20); memmove(output, buf, 8); return TRUE; @@ -645,7 +649,9 @@ BOOL security_hmac_signature(const BYTE* data, int length, BYTE* output, rdpRdp* BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp) { - if (!crypto_des3_encrypt(rdp->fips_encrypt, length, data, data)) + size_t olen; + + if (!winpr_Cipher_Update(rdp->fips_encrypt, data, length, data, &olen)) return FALSE; rdp->encrypt_use_count++; return TRUE; @@ -653,21 +659,29 @@ BOOL security_fips_encrypt(BYTE* data, int length, rdpRdp* rdp) BOOL security_fips_decrypt(BYTE* data, int length, rdpRdp* rdp) { - return crypto_des3_decrypt(rdp->fips_decrypt, length, data, data); + size_t olen; + + if (!winpr_Cipher_Update(rdp->fips_decrypt, data, length, data, &olen)) + return FALSE; + return TRUE; } BOOL security_fips_check_signature(const BYTE* data, int length, const BYTE* sig, rdpRdp* rdp) { - BYTE buf[20]; + BYTE buf[WINPR_SHA1_DIGEST_LENGTH]; BYTE use_count_le[4]; security_UINT32_le(use_count_le, rdp->decrypt_use_count); - if (!crypto_hmac_sha1_init(rdp->fips_hmac, rdp->fips_sign_key, 20)) + if (!winpr_HMAC_Init(rdp->fips_hmac, WINPR_MD_SHA1, + rdp->fips_sign_key, WINPR_SHA1_DIGEST_LENGTH)) + return FALSE; + if (!winpr_HMAC_Update(rdp->fips_hmac, data, length)) + return FALSE; + if (!winpr_HMAC_Update(rdp->fips_hmac, use_count_le, 4)) + return FALSE; + if (!winpr_HMAC_Final(rdp->fips_hmac, buf, WINPR_SHA1_DIGEST_LENGTH)) return FALSE; - crypto_hmac_update(rdp->fips_hmac, data, length); - crypto_hmac_update(rdp->fips_hmac, use_count_le, 4); - crypto_hmac_final(rdp->fips_hmac, buf, 20); rdp->decrypt_use_count++; diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index c7d4b30ff..1002d1770 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -472,7 +472,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->ServerAutoReconnectCookie) goto out_fail; - settings->ClientTimeZone = (TIME_ZONE_INFO*) calloc(1,sizeof(TIME_ZONE_INFO)); + settings->ClientTimeZone = (LPTIME_ZONE_INFORMATION) calloc(1,sizeof(TIME_ZONE_INFORMATION)); if (!settings->ClientTimeZone) goto out_fail; @@ -762,10 +762,10 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) CopyMemory(_settings->ClientAutoReconnectCookie, settings->ClientAutoReconnectCookie, sizeof(ARC_CS_PRIVATE_PACKET)); CopyMemory(_settings->ServerAutoReconnectCookie, settings->ServerAutoReconnectCookie, sizeof(ARC_SC_PRIVATE_PACKET)); - _settings->ClientTimeZone = (TIME_ZONE_INFO*) malloc(sizeof(TIME_ZONE_INFO)); + _settings->ClientTimeZone = (LPTIME_ZONE_INFORMATION) malloc(sizeof(TIME_ZONE_INFORMATION)); if (!_settings->ClientTimeZone) goto out_fail; - CopyMemory(_settings->ClientTimeZone, settings->ClientTimeZone, sizeof(TIME_ZONE_INFO)); + CopyMemory(_settings->ClientTimeZone, settings->ClientTimeZone, sizeof(TIME_ZONE_INFORMATION)); _settings->TargetNetAddressCount = settings->TargetNetAddressCount; @@ -815,7 +815,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) goto out_fail; } - if (_settings->DeviceArraySize < _settings->DeviceCount) + if (_settings->DeviceArraySize < _settings->DeviceCount) { _settings->DeviceCount = 0; _settings->DeviceArraySize = 0; diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 24bbcd05d..7be7a411d 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -489,7 +489,7 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) */ if (buf && num && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*) buf, num)) { - WLog_ERR(TAG, "an error occured when writing (num: %d)", num); + WLog_ERR(TAG, "an error occurred when writing (num: %d)", num); return -1; } @@ -1027,7 +1027,7 @@ BOOL freerdp_tcp_set_keep_alive_mode(int sockfd) #endif #ifdef TCP_USER_TIMEOUT - optval = 4000; + optval = 9000; optlen = sizeof(optval); if (setsockopt(sockfd, SOL_TCP, TCP_USER_TIMEOUT, (void*) &optval, optlen) < 0) diff --git a/libfreerdp/core/timezone.c b/libfreerdp/core/timezone.c index 95f06a356..48374fe58 100644 --- a/libfreerdp/core/timezone.c +++ b/libfreerdp/core/timezone.c @@ -22,9 +22,13 @@ #endif #include +#include #include "timezone.h" +static void rdp_read_system_time(wStream* s, SYSTEMTIME* system_time); +static void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time); + /** * Read SYSTEM_TIME structure (TS_SYSTEMTIME).\n * @msdn{cc240478} @@ -32,7 +36,7 @@ * @param system_time system time structure */ -void rdp_read_system_time(wStream* s, SYSTEM_TIME* system_time) +void rdp_read_system_time(wStream* s, SYSTEMTIME* system_time) { Stream_Read_UINT16(s, system_time->wYear); /* wYear, must be set to 0 */ Stream_Read_UINT16(s, system_time->wMonth); /* wMonth */ @@ -51,7 +55,7 @@ void rdp_read_system_time(wStream* s, SYSTEM_TIME* system_time) * @param system_time system time structure */ -void rdp_write_system_time(wStream* s, SYSTEM_TIME* system_time) +void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time) { Stream_Write_UINT16(s, system_time->wYear); /* wYear, must be set to 0 */ Stream_Write_UINT16(s, system_time->wMonth); /* wMonth */ @@ -76,34 +80,31 @@ void rdp_write_system_time(wStream* s, SYSTEM_TIME* system_time) BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings) { - char* str = NULL; - TIME_ZONE_INFO* clientTimeZone; + LPTIME_ZONE_INFORMATION tz; + + if (!s || !settings) + return FALSE; if (Stream_GetRemainingLength(s) < 172) return FALSE; - clientTimeZone = settings->ClientTimeZone; + tz = settings->ClientTimeZone; + if (!tz) + return FALSE; - Stream_Read_UINT32(s, clientTimeZone->bias); /* Bias */ + Stream_Read_UINT32(s, tz->Bias); /* Bias */ /* standardName (64 bytes) */ - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); - Stream_Seek(s, 64); - strncpy(clientTimeZone->standardName, str, sizeof(clientTimeZone->standardName)); - free(str); - str = NULL; + Stream_Read(s, tz->StandardName, sizeof(tz->StandardName)); - rdp_read_system_time(s, &clientTimeZone->standardDate); /* StandardDate */ - Stream_Read_UINT32(s, clientTimeZone->standardBias); /* StandardBias */ + rdp_read_system_time(s, &tz->StandardDate); /* StandardDate */ + Stream_Read_UINT32(s, tz->StandardBias); /* StandardBias */ /* daylightName (64 bytes) */ - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL); - Stream_Seek(s, 64); - strncpy(clientTimeZone->daylightName, str, sizeof(clientTimeZone->daylightName)); - free(str); + Stream_Read(s, tz->DaylightName, sizeof(tz->DaylightName)); - rdp_read_system_time(s, &clientTimeZone->daylightDate); /* DaylightDate */ - Stream_Read_UINT32(s, clientTimeZone->daylightBias); /* DaylightBias */ + rdp_read_system_time(s, &tz->DaylightDate); /* DaylightDate */ + Stream_Read_UINT32(s, tz->DaylightBias); /* DaylightBias */ return TRUE; } @@ -115,55 +116,45 @@ BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings) * @param settings settings */ -void rdp_write_client_time_zone(wStream* s, rdpSettings* settings) +BOOL rdp_write_client_time_zone(wStream* s, rdpSettings* settings) { - WCHAR* standardName = NULL; - WCHAR* daylightName = NULL; - int standardNameLength; - int daylightNameLength; - TIME_ZONE_INFO* clientTimeZone; + LPTIME_ZONE_INFORMATION tz; + DWORD rc; - clientTimeZone = settings->ClientTimeZone; - freerdp_time_zone_detect(clientTimeZone); + tz = settings->ClientTimeZone; + if (!tz) + return FALSE; - standardNameLength = ConvertToUnicode(CP_UTF8, 0, clientTimeZone->standardName, -1, &standardName, 0) * 2; - daylightNameLength = ConvertToUnicode(CP_UTF8, 0, clientTimeZone->daylightName, -1, &daylightName, 0) * 2; + rc = GetTimeZoneInformation(tz); - if (standardNameLength > 62) - standardNameLength = 62; - - if (daylightNameLength > 62) - daylightNameLength = 62; - - /* Bias */ - Stream_Write_UINT32(s, clientTimeZone->bias); + /* Bias */ + Stream_Write_UINT32(s, tz->Bias); /* standardName (64 bytes) */ - Stream_Write(s, standardName, standardNameLength); - Stream_Zero(s, 64 - standardNameLength); + Stream_Write(s, tz->StandardName, sizeof(tz->StandardName)); - /* StandardDate */ - rdp_write_system_time(s, &clientTimeZone->standardDate); + /* StandardDate */ + rdp_write_system_time(s, &tz->StandardDate); - DEBUG_TIMEZONE("bias=%d stdName='%s' dlName='%s'", clientTimeZone->bias, clientTimeZone->standardName, clientTimeZone->daylightName); + DEBUG_TIMEZONE("bias=%d stdName='%s' dlName='%s'", tz->Bias, + tz->StandardName, tz->DaylightName); /* Note that StandardBias is ignored if no valid standardDate is provided. */ - /* StandardBias */ - Stream_Write_UINT32(s, clientTimeZone->standardBias); - DEBUG_TIMEZONE("StandardBias=%d", clientTimeZone->standardBias); + /* StandardBias */ + Stream_Write_UINT32(s, tz->StandardBias); + DEBUG_TIMEZONE("StandardBias=%d", tz->StandardBias); /* daylightName (64 bytes) */ - Stream_Write(s, daylightName, daylightNameLength); - Stream_Zero(s, 64 - daylightNameLength); + Stream_Write(s, tz->DaylightName, sizeof(tz->DaylightName)); - /* DaylightDate */ - rdp_write_system_time(s, &clientTimeZone->daylightDate); + /* DaylightDate */ + rdp_write_system_time(s, &tz->DaylightDate); /* Note that DaylightBias is ignored if no valid daylightDate is provided. */ - /* DaylightBias */ - Stream_Write_UINT32(s, clientTimeZone->daylightBias); - DEBUG_TIMEZONE("DaylightBias=%d", clientTimeZone->daylightBias); + /* DaylightBias */ + Stream_Write_UINT32(s, tz->DaylightBias); + DEBUG_TIMEZONE("DaylightBias=%d", tz->DaylightBias); - free(standardName); - free(daylightName); + return TRUE; } + diff --git a/libfreerdp/core/timezone.h b/libfreerdp/core/timezone.h index a45cd4437..92b2c7af1 100644 --- a/libfreerdp/core/timezone.h +++ b/libfreerdp/core/timezone.h @@ -28,15 +28,11 @@ #include #include -#include #include -void rdp_read_system_time(wStream* s, SYSTEM_TIME* system_time); -void rdp_write_system_time(wStream* s, SYSTEM_TIME* system_time); -void rdp_get_client_time_zone(wStream* s, rdpSettings* settings); BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings); -void rdp_write_client_time_zone(wStream* s, rdpSettings* settings); +BOOL rdp_write_client_time_zone(wStream* s, rdpSettings* settings); #define TIMEZONE_TAG FREERDP_TAG("core.timezone") #ifdef WITH_DEBUG_TIMEZONE diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 6f928cca1..147913f82 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -733,8 +733,7 @@ out_cleanup: transport->layer = TRANSPORT_LAYER_CLOSED; } - if (s->pool) - Stream_Release(s); + Stream_Release(s); LeaveCriticalSection(&(transport->WriteLock)); return status; diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 90e183e1c..f8b2dad02 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -30,11 +30,13 @@ #include "update.h" #include "surface.h" #include "message.h" +#include "info.h" #include #include #include + #define TAG FREERDP_TAG("core.update") const char* const UPDATE_TYPE_STRINGS[] = @@ -1905,6 +1907,7 @@ void update_register_server_callbacks(rdpUpdate* update) update->SurfaceFrameBits = update_send_surface_frame_bits; update->PlaySound = update_send_play_sound; update->SetKeyboardIndicators = update_send_set_keyboard_indicators; + update->SaveSessionInfo = rdp_send_save_session_info; update->primary->DstBlt = update_send_dstblt; update->primary->PatBlt = update_send_patblt; update->primary->ScrBlt = update_send_scrblt; diff --git a/libfreerdp/core/window.c b/libfreerdp/core/window.c index e31fe4582..e197b76e4 100644 --- a/libfreerdp/core/window.c +++ b/libfreerdp/core/window.c @@ -371,6 +371,7 @@ BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_I { rdpContext* context = update->context; rdpWindowUpdate* window = update->window; + BOOL result = TRUE; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -382,20 +383,20 @@ BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_I if (!update_read_window_icon_order(s, orderInfo, &window->window_icon)) return FALSE; WLog_Print(update->log, WLOG_DEBUG, "WindowIcon"); - IFCALL(window->WindowIcon, context, orderInfo, &window->window_icon); + IFCALLRET(window->WindowIcon, result, context, orderInfo, &window->window_icon); } else if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON) { if (!update_read_window_cached_icon_order(s, orderInfo, &window->window_cached_icon)) return FALSE; WLog_Print(update->log, WLOG_DEBUG, "WindowCachedIcon"); - IFCALL(window->WindowCachedIcon, context, orderInfo, &window->window_cached_icon); + IFCALLRET(window->WindowCachedIcon, result, context, orderInfo, &window->window_cached_icon); } else if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_DELETED) { update_read_window_delete_order(s, orderInfo); WLog_Print(update->log, WLOG_DEBUG, "WindowDelete"); - IFCALL(window->WindowDelete, context, orderInfo); + IFCALLRET(window->WindowDelete, result, context, orderInfo); } else { @@ -405,16 +406,16 @@ BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_I if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW) { WLog_Print(update->log, WLOG_DEBUG, "WindowCreate"); - IFCALL(window->WindowCreate, context, orderInfo, &window->window_state); + IFCALLRET(window->WindowCreate, result, context, orderInfo, &window->window_state); } else { WLog_Print(update->log, WLOG_DEBUG, "WindowUpdate"); - IFCALL(window->WindowUpdate, context, orderInfo, &window->window_state); + IFCALLRET(window->WindowUpdate, result, context, orderInfo, &window->window_state); } } - return TRUE; + return result; } BOOL update_read_notification_icon_state_order(wStream* s, WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notify_icon_state) @@ -470,6 +471,7 @@ BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s, WIN { rdpContext* context = update->context; rdpWindowUpdate* window = update->window; + BOOL result = TRUE; if (Stream_GetRemainingLength(s) < 8) return FALSE; @@ -481,7 +483,7 @@ BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s, WIN { update_read_notification_icon_delete_order(s, orderInfo); WLog_Print(update->log, WLOG_DEBUG, "NotifyIconDelete"); - IFCALL(window->NotifyIconDelete, context, orderInfo); + IFCALLRET(window->NotifyIconDelete, result, context, orderInfo); } else { @@ -491,16 +493,16 @@ BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s, WIN if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW) { WLog_Print(update->log, WLOG_DEBUG, "NotifyIconCreate"); - IFCALL(window->NotifyIconCreate, context, orderInfo, &window->notify_icon_state); + IFCALLRET(window->NotifyIconCreate, result, context, orderInfo, &window->notify_icon_state); } else { WLog_Print(update->log, WLOG_DEBUG, "NotifyIconUpdate"); - IFCALL(window->NotifyIconUpdate, context, orderInfo, &window->notify_icon_state); + IFCALLRET(window->NotifyIconUpdate, result, context, orderInfo, &window->notify_icon_state); } } - return TRUE; + return result; } BOOL update_read_desktop_actively_monitored_order(wStream* s, WINDOW_ORDER_INFO* orderInfo, MONITORED_DESKTOP_ORDER* monitored_desktop) @@ -560,22 +562,23 @@ BOOL update_recv_desktop_info_order(rdpUpdate* update, wStream* s, WINDOW_ORDER_ { rdpContext* context = update->context; rdpWindowUpdate* window = update->window; + BOOL result = TRUE; if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_NONE) { update_read_desktop_non_monitored_order(s, orderInfo); WLog_Print(update->log, WLOG_DEBUG, "NonMonitoredDesktop"); - IFCALL(window->NonMonitoredDesktop, context, orderInfo); + IFCALLRET(window->NonMonitoredDesktop, result, context, orderInfo); } else { if (!update_read_desktop_actively_monitored_order(s, orderInfo, &window->monitored_desktop)) return FALSE; WLog_Print(update->log, WLOG_DEBUG, "ActivelyMonitoredDesktop"); - IFCALL(window->MonitoredDesktop, context, orderInfo, &window->monitored_desktop); + IFCALLRET(window->MonitoredDesktop, result, context, orderInfo, &window->monitored_desktop); } - return TRUE; + return result; } BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s) diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index 26c69fdaf..85a28b8c6 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -22,168 +22,13 @@ #endif #include +#include #include #include #define TAG FREERDP_TAG("crypto") -CryptoSha1 crypto_sha1_init(void) -{ - CryptoSha1 sha1 = malloc(sizeof(*sha1)); - if (!sha1) - return NULL; - SHA1_Init(&sha1->sha_ctx); - return sha1; -} - -void crypto_sha1_update(CryptoSha1 sha1, const BYTE* data, UINT32 length) -{ - SHA1_Update(&sha1->sha_ctx, data, length); -} - -void crypto_sha1_final(CryptoSha1 sha1, BYTE* out_data) -{ - SHA1_Final(out_data, &sha1->sha_ctx); - free(sha1); -} - -CryptoMd5 crypto_md5_init(void) -{ - CryptoMd5 md5 = malloc(sizeof(*md5)); - if (!md5) - return NULL; - MD5_Init(&md5->md5_ctx); - return md5; -} - -void crypto_md5_update(CryptoMd5 md5, const BYTE* data, UINT32 length) -{ - MD5_Update(&md5->md5_ctx, data, length); -} - -void crypto_md5_final(CryptoMd5 md5, BYTE* out_data) -{ - MD5_Final(out_data, &md5->md5_ctx); - free(md5); -} - -CryptoRc4 crypto_rc4_init(const BYTE* key, UINT32 length) -{ - CryptoRc4 rc4 = malloc(sizeof(*rc4)); - if (!rc4) - return NULL; - RC4_set_key(&rc4->rc4_key, length, key); - return rc4; -} - -void crypto_rc4(CryptoRc4 rc4, UINT32 length, const BYTE* in_data, BYTE* out_data) -{ - RC4(&rc4->rc4_key, length, in_data, out_data); -} - -void crypto_rc4_free(CryptoRc4 rc4) -{ - free(rc4); -} - -CryptoDes3 crypto_des3_encrypt_init(const BYTE* key, const BYTE* ivec) -{ - CryptoDes3 des3 = malloc(sizeof(*des3)); - if (!des3) - return NULL; - - EVP_CIPHER_CTX_init(&des3->des3_ctx); - EVP_EncryptInit_ex(&des3->des3_ctx, EVP_des_ede3_cbc(), NULL, key, ivec); - EVP_CIPHER_CTX_set_padding(&des3->des3_ctx, 0); - return des3; -} - -CryptoDes3 crypto_des3_decrypt_init(const BYTE* key, const BYTE* ivec) -{ - CryptoDes3 des3 = malloc(sizeof(*des3)); - if (!des3) - return NULL; - - EVP_CIPHER_CTX_init(&des3->des3_ctx); - EVP_DecryptInit_ex(&des3->des3_ctx, EVP_des_ede3_cbc(), NULL, key, ivec); - EVP_CIPHER_CTX_set_padding(&des3->des3_ctx, 0); - return des3; -} - -BOOL crypto_des3_encrypt(CryptoDes3 des3, UINT32 length, const BYTE* in_data, BYTE* out_data) -{ - int len; - return EVP_EncryptUpdate(&des3->des3_ctx, out_data, &len, in_data, length) == 1; -} - -BOOL crypto_des3_decrypt(CryptoDes3 des3, UINT32 length, const BYTE* in_data, BYTE* out_data) -{ - int len; - int ret = EVP_DecryptUpdate(&des3->des3_ctx, out_data, &len, in_data, length); - - if (length != len) - abort(); /* TODO */ - return ret == 1; -} - -void crypto_des3_free(CryptoDes3 des3) -{ - if (des3 == NULL) - return; - EVP_CIPHER_CTX_cleanup(&des3->des3_ctx); - free(des3); -} - -CryptoHmac crypto_hmac_new(void) -{ - CryptoHmac hmac = malloc(sizeof(*hmac)); - if (!hmac) - return NULL; - - HMAC_CTX_init(&hmac->hmac_ctx); - return hmac; -} - -BOOL crypto_hmac_sha1_init(CryptoHmac hmac, const BYTE* data, UINT32 length) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x00909000) - return HMAC_Init_ex(&hmac->hmac_ctx, data, length, EVP_sha1(), NULL) == 1; -#else - HMAC_Init_ex(&hmac->hmac_ctx, data, length, EVP_sha1(), NULL); - return TRUE; -#endif -} - -BOOL crypto_hmac_md5_init(CryptoHmac hmac, const BYTE* data, UINT32 length) -{ -#if (OPENSSL_VERSION_NUMBER >= 0x00909000) - return HMAC_Init_ex(&hmac->hmac_ctx, data, length, EVP_md5(), NULL) == 1; -#else - HMAC_Init_ex(&hmac->hmac_ctx, data, length, EVP_md5(), NULL); - return TRUE; -#endif -} - -void crypto_hmac_update(CryptoHmac hmac, const BYTE* data, UINT32 length) -{ - HMAC_Update(&hmac->hmac_ctx, data, length); -} - -void crypto_hmac_final(CryptoHmac hmac, BYTE* out_data, UINT32 length) -{ - HMAC_Final(&hmac->hmac_ctx, out_data, &length); -} - -void crypto_hmac_free(CryptoHmac hmac) -{ - if (hmac == NULL) - return; - - HMAC_CTX_cleanup(&hmac->hmac_ctx); - free(hmac); -} - CryptoCert crypto_cert_read(BYTE* data, UINT32 length) { CryptoCert cert = malloc(sizeof(*cert)); @@ -347,11 +192,6 @@ void crypto_reverse(BYTE* data, int length) } } -void crypto_nonce(BYTE* nonce, int size) -{ - RAND_bytes((void*) nonce, size); -} - char* crypto_cert_fingerprint(X509* xcert) { int i = 0; @@ -404,7 +244,8 @@ char* crypto_cert_subject(X509* xcert) char* crypto_cert_subject_common_name(X509* xcert, int* length) { int index; - BYTE* common_name; + BYTE* common_name_raw; + char* common_name; X509_NAME* subject_name; X509_NAME_ENTRY* entry; ASN1_STRING* entry_data; @@ -429,15 +270,18 @@ char* crypto_cert_subject_common_name(X509* xcert, int* length) if (entry_data == NULL) return NULL; - *length = ASN1_STRING_to_UTF8(&common_name, entry_data); + *length = ASN1_STRING_to_UTF8(&common_name_raw, entry_data); if (*length < 0) return NULL; + common_name = _strdup((char*)common_name_raw); + OPENSSL_free(common_name_raw); + return (char*) common_name; } -FREERDP_API void crypto_cert_subject_alt_name_free(int count, int *lengths, +void crypto_cert_subject_alt_name_free(int count, int *lengths, char** alt_name) { int i; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index e8627e41e..ba10e0db1 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -589,11 +589,10 @@ out_free: return NULL; } - -#if defined(__APPLE__) -BOOL tls_prepare(rdpTls* tls, BIO* underlying, SSL_METHOD* method, int options, BOOL clientMode) +#if OPENSSL_VERSION_NUMBER >= 0x010000000L +static BOOL tls_prepare(rdpTls* tls, BIO* underlying, const SSL_METHOD* method, int options, BOOL clientMode) #else -BOOL tls_prepare(rdpTls* tls, BIO* underlying, const SSL_METHOD* method, int options, BOOL clientMode) +static BOOL tls_prepare(rdpTls* tls, BIO* underlying, SSL_METHOD* method, int options, BOOL clientMode) #endif { rdpSettings* settings = tls->settings; @@ -1247,31 +1246,16 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por /* if the certificate is valid and the certificate name matches, verification succeeds */ if (certificate_status && hostname_match) - { - if (common_name) - { - free(common_name); - common_name = NULL; - } - verification_status = TRUE; /* success! */ - } - - /* if the certificate is valid but the certificate name does not match, warn user, do not accept */ - if (certificate_status && !hostname_match) - tls_print_certificate_name_mismatch_error(hostname, port, - common_name, alt_names, - alt_names_count); /* verification could not succeed with OpenSSL, use known_hosts file and prompt user for manual verification */ - - if (!certificate_status) + if (!certificate_status || !hostname_match) { char* issuer; char* subject; char* fingerprint; freerdp* instance = (freerdp*) tls->settings->instance; - BOOL accept_certificate = FALSE; + DWORD accept_certificate = 0; issuer = crypto_cert_issuer(cert->px509); subject = crypto_cert_subject(cert->px509); @@ -1290,19 +1274,23 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por alt_names_count); if (instance->VerifyCertificate) - { - accept_certificate = instance->VerifyCertificate(instance, subject, issuer, fingerprint); - } + accept_certificate = instance->VerifyCertificate(instance, common_name, + subject, issuer, fingerprint, !hostname_match); - if (!accept_certificate) + switch(accept_certificate) { - /* user did not accept, abort and do not add entry in known_hosts file */ - verification_status = FALSE; /* failure! */ - } - else - { - /* user accepted certificate, add entry in known_hosts file */ - verification_status = certificate_data_print(tls->certificate_store, certificate_data); + case 1: + /* user accepted certificate, add entry in known_hosts file */ + verification_status = certificate_data_print(tls->certificate_store, certificate_data); + break; + case 2: + /* user did accept temporaty, do not add to known hosts file */ + verification_status = TRUE; + break; + default: + /* user did not accept, abort and do not add entry in known_hosts file */ + verification_status = FALSE; /* failure! */ + break; } } else if (match == -1) @@ -1324,28 +1312,31 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (instance->VerifyChangedCertificate) { accept_certificate = instance->VerifyChangedCertificate( - instance, subject, issuer, + instance, common_name, subject, issuer, fingerprint, old_subject, old_issuer, old_fingerprint); } free(old_fingerprint); - if (!accept_certificate) + switch(accept_certificate) { - /* user did not accept, abort and do not change known_hosts file */ - verification_status = FALSE; /* failure! */ - } - else - { - /* user accepted new certificate, add replace fingerprint for this host in known_hosts file */ - verification_status = certificate_data_replace(tls->certificate_store, certificate_data); + case 1: + /* user accepted certificate, add entry in known_hosts file */ + verification_status = certificate_data_replace(tls->certificate_store, certificate_data); + break; + case 2: + /* user did accept temporaty, do not add to known hosts file */ + verification_status = TRUE; + break; + default: + /* user did not accept, abort and do not add entry in known_hosts file */ + verification_status = FALSE; /* failure! */ + break; } } else if (match == 0) - { verification_status = TRUE; /* success! */ - } free(issuer); free(subject); @@ -1354,9 +1345,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por certificate_data_free(certificate_data); -#ifndef _WIN32 free(common_name); -#endif if (alt_names) crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths, diff --git a/libfreerdp/locale/CMakeLists.txt b/libfreerdp/locale/CMakeLists.txt index f6bdf73f8..e418e0c9f 100644 --- a/libfreerdp/locale/CMakeLists.txt +++ b/libfreerdp/locale/CMakeLists.txt @@ -22,7 +22,6 @@ set(${MODULE_PREFIX}_SRCS keyboard_layout.c keyboard.c locale.c - timezone.c liblocale.h) set(${MODULE_PREFIX}_X11_SRCS diff --git a/libfreerdp/locale/timezone.c b/libfreerdp/locale/timezone.c deleted file mode 100644 index 573504956..000000000 --- a/libfreerdp/locale/timezone.c +++ /dev/null @@ -1,1770 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Time Zone Redirection - * - * Copyright 2012 Marc-Andre Moreau - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#define __USE_XOPEN -#include - -#ifndef _WIN32 -#include -#endif - -#include "liblocale.h" - -#include -#include - -#define TAG FREERDP_TAG("locale") - -/* Time Zone Redirection table generated with TimeZones.cs script */ - - -struct _SYSTEM_TIME_ENTRY -{ - UINT16 wYear; - UINT16 wMonth; - UINT16 wDayOfWeek; - UINT16 wDay; - UINT16 wHour; - UINT16 wMinute; - UINT16 wSecond; - UINT16 wMilliseconds; -}; -typedef struct _SYSTEM_TIME_ENTRY SYSTEM_TIME_ENTRY; - -struct _TIME_ZONE_RULE_ENTRY -{ - UINT64 TicksStart; - UINT64 TicksEnd; - INT32 DaylightDelta; - SYSTEM_TIME_ENTRY StandardDate; - SYSTEM_TIME_ENTRY DaylightDate; -}; -typedef struct _TIME_ZONE_RULE_ENTRY TIME_ZONE_RULE_ENTRY; - -struct _TIME_ZONE_ENTRY -{ - const char* Id; - UINT32 Bias; - BOOL SupportsDST; - const char* DisplayName; - const char* StandardName; - const char* DaylightName; - TIME_ZONE_RULE_ENTRY* RuleTable; - UINT32 RuleTableCount; -}; -typedef struct _TIME_ZONE_ENTRY TIME_ZONE_ENTRY; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_3[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_4[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_5[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_7[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_8[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_10[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_11[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_14[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_15[] = -{ - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_17[] = -{ - { 633662964000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 9, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_18[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_19[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 1, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 0, 1, 0, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_21[] = -{ - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 5, 6, 1, 23, 59 }, { 0, 8, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_22[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 0, 1 }, { 0, 4, 0, 1, 0, 1 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 0, 1 }, }, - { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_23[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 1, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 0, 1, 0, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_24[] = -{ - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 1, 1, 1, 0, 0 }, { 0, 12, 0, 1, 0, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 1, 4, 1, 0, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_26[] = -{ - { 633662964000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, - { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_27[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 9, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_28[] = -{ - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_30[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_31[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_33[] = -{ - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 0, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 5, 0, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 8, 6, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 7, 6, 1, 23, 59 }, { 0, 4, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_35[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 0, 1, 1, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_37[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_38[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_39[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_40[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_42[] = -{ - { 634293684000000000ULL, 180000000000ULL, -60, { 0, 9, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 2, 0 }, { 0, 9, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_43[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 5, 1, 1, 0 }, { 0, 3, 4, 1, 0, 0 }, }, - { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 10, 5, 1, 1, 0 }, { 0, 3, 4, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_44[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_45[] = -{ - { 633978324000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 0, 0 }, { 0, 3, 0, 1, 0, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_46[] = -{ - { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 5, 1, 0, 0 }, }, - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 5, 1, 0, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_47[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 3, 1, 23, 59 }, { 0, 3, 5, 1, 23, 59 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 3155378292000000000ULL, 636188436000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_49[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_50[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 1, 1, 3, 0 }, }, - { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_51[] = -{ - { 632716020000000000ULL, 632401524000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, - { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, - { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_52[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_53[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 4, 0, 1, 3, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 10, 1, 1, 4, 0 }, { 0, 4, 0, 1, 3, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_54[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_57[] = -{ - { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 2, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 9, 6, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, - { 3155378292000000000ULL, 633663828000000000ULL, 60, { 0, 9, 1, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_59[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 5, 0 }, { 0, 3, 0, 1, 4, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_60[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_61[] = -{ - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 1, 2, 1, 0, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 1, 4, 1, 0, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_63[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_65[] = -{ - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 4, 2, 1, 23, 59 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_71[] = -{ - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 12, 4, 1, 23, 59 }, { 0, 6, 5, 1, 23, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_72[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_75[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_77[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_79[] = -{ - { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 1, 0, 1, 0, 0 }, { 0, 12, 0, 1, 2, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 1, 4, 1, 0, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_82[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_85[] = -{ - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_88[] = -{ - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_90[] = -{ - { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_91[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_93[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_94[] = -{ - { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 9, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 9, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_96[] = -{ - { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 1, 4, 1, 0, 0 }, { 0, 11, 0, 1, 2, 0 }, }, - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 1, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, - { 3155378292000000000ULL, 634926132000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_97[] = -{ - { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_98[] = -{ - { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } -}; - -static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_100[] = -{ - { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 1, 5, 1, 0, 0 }, { 0, 9, 6, 1, 23, 59 }, }, - { 3155378292000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 1, 0 }, { 0, 9, 0, 1, 0, 0 }, } -}; - -static const TIME_ZONE_ENTRY TimeZoneTable[] = -{ - { - "Dateline Standard Time", 720, FALSE, "(UTC-12:00) International Date Line West", - "Dateline Standard Time", "Dateline Daylight Time", - NULL, 0 - }, - { - "UTC-11", 780, FALSE, "(UTC-11:00) Coordinated Universal Time-11", - "UTC-11", "UTC-11", - NULL, 0 - }, - { - "Hawaiian Standard Time", 840, FALSE, "(UTC-10:00) Hawaii", - "Hawaiian Standard Time", "Hawaiian Daylight Time", - NULL, 0 - }, - { - "Alaskan Standard Time", 900, TRUE, "(UTC-09:00) Alaska", - "Alaskan Standard Time", "Alaskan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_3, 2 - }, - { - "Pacific Standard Time (Mexico)", 960, TRUE, "(UTC-08:00) Baja California", - "Pacific Standard Time (Mexico)", "Pacific Daylight Time (Mexico)", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_4, 1 - }, - { - "Pacific Standard Time", 960, TRUE, "(UTC-08:00) Pacific Time (US & Canada)", - "Pacific Standard Time", "Pacific Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_5, 2 - }, - { - "US Mountain Standard Time", 1020, FALSE, "(UTC-07:00) Arizona", - "US Mountain Standard Time", "US Mountain Daylight Time", - NULL, 0 - }, - { - "Mountain Standard Time (Mexico)", 1020, TRUE, "(UTC-07:00) Chihuahua, La Paz, Mazatlan", - "Mountain Standard Time (Mexico)", "Mountain Daylight Time (Mexico)", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_7, 1 - }, - { - "Mountain Standard Time", 1020, TRUE, "(UTC-07:00) Mountain Time (US & Canada)", - "Mountain Standard Time", "Mountain Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_8, 2 - }, - { - "Central America Standard Time", 1080, FALSE, "(UTC-06:00) Central America", - "Central America Standard Time", "Central America Daylight Time", - NULL, 0 - }, - { - "Central Standard Time", 1080, TRUE, "(UTC-06:00) Central Time (US & Canada)", - "Central Standard Time", "Central Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_10, 2 - }, - { - "Central Standard Time (Mexico)", 1080, TRUE, "(UTC-06:00) Guadalajara, Mexico City, Monterrey", - "Central Standard Time (Mexico)", "Central Daylight Time (Mexico)", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_11, 1 - }, - { - "Canada Central Standard Time", 1080, FALSE, "(UTC-06:00) Saskatchewan", - "Canada Central Standard Time", "Canada Central Daylight Time", - NULL, 0 - }, - { - "SA Pacific Standard Time", 1140, FALSE, "(UTC-05:00) Bogota, Lima, Quito", - "SA Pacific Standard Time", "SA Pacific Daylight Time", - NULL, 0 - }, - { - "Eastern Standard Time", 1140, TRUE, "(UTC-05:00) Eastern Time (US & Canada)", - "Eastern Standard Time", "Eastern Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_14, 2 - }, - { - "US Eastern Standard Time", 1140, TRUE, "(UTC-05:00) Indiana (East)", - "US Eastern Standard Time", "US Eastern Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_15, 2 - }, - { - "Venezuela Standard Time", 1170, FALSE, "(UTC-04:30) Caracas", - "Venezuela Standard Time", "Venezuela Daylight Time", - NULL, 0 - }, - { - "Paraguay Standard Time", 1200, TRUE, "(UTC-04:00) Asuncion", - "Paraguay Standard Time", "Paraguay Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_17, 14 - }, - { - "Atlantic Standard Time", 1200, TRUE, "(UTC-04:00) Atlantic Time (Canada)", - "Atlantic Standard Time", "Atlantic Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_18, 2 - }, - { - "Central Brazilian Standard Time", 1200, TRUE, "(UTC-04:00) Cuiaba", - "Central Brazilian Standard Time", "Central Brazilian Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_19, 35 - }, - { - "SA Western Standard Time", 1200, FALSE, "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan", - "SA Western Standard Time", "SA Western Daylight Time", - NULL, 0 - }, - { - "Pacific SA Standard Time", 1200, TRUE, "(UTC-04:00) Santiago", - "Pacific SA Standard Time", "Pacific SA Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_21, 6 - }, - { - "Newfoundland Standard Time", 1230, TRUE, "(UTC-03:30) Newfoundland", - "Newfoundland Standard Time", "Newfoundland Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_22, 7 - }, - { - "E. South America Standard Time", 1260, TRUE, "(UTC-03:00) Brasilia", - "E. South America Standard Time", "E. South America Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_23, 35 - }, - { - "Argentina Standard Time", 1260, TRUE, "(UTC-03:00) Buenos Aires", - "Argentina Standard Time", "Argentina Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_24, 3 - }, - { - "SA Eastern Standard Time", 1260, FALSE, "(UTC-03:00) Cayenne, Fortaleza", - "SA Eastern Standard Time", "SA Eastern Daylight Time", - NULL, 0 - }, - { - "Greenland Standard Time", 1260, TRUE, "(UTC-03:00) Greenland", - "Greenland Standard Time", "Greenland Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_26, 14 - }, - { - "Montevideo Standard Time", 1260, TRUE, "(UTC-03:00) Montevideo", - "Montevideo Standard Time", "Montevideo Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_27, 2 - }, - { - "Bahia Standard Time", 1260, TRUE, "(UTC-03:00) Salvador", - "Bahia Standard Time", "Bahia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_28, 30 - }, - { - "UTC-02", 1320, FALSE, "(UTC-02:00) Coordinated Universal Time-02", - "UTC-02", "UTC-02", - NULL, 0 - }, - { - "Mid-Atlantic Standard Time", 1320, TRUE, "(UTC-02:00) Mid-Atlantic", - "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_30, 1 - }, - { - "Azores Standard Time", 1380, TRUE, "(UTC-01:00) Azores", - "Azores Standard Time", "Azores Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_31, 1 - }, - { - "Cape Verde Standard Time", 1380, FALSE, "(UTC-01:00) Cape Verde Is.", - "Cape Verde Standard Time", "Cape Verde Daylight Time", - NULL, 0 - }, - { - "Morocco Standard Time", 0, TRUE, "(UTC) Casablanca", - "Morocco Standard Time", "Morocco Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_33, 4 - }, - { - "UTC", 0, FALSE, "(UTC) Coordinated Universal Time", - "Coordinated Universal Time", "Coordinated Universal Time", - NULL, 0 - }, - { - "GMT Standard Time", 0, TRUE, "(UTC) Dublin, Edinburgh, Lisbon, London", - "GMT Standard Time", "GMT Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_35, 1 - }, - { - "Greenwich Standard Time", 0, FALSE, "(UTC) Monrovia, Reykjavik", - "Greenwich Standard Time", "Greenwich Daylight Time", - NULL, 0 - }, - { - "W. Europe Standard Time", 60, TRUE, "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", - "W. Europe Standard Time", "W. Europe Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_37, 1 - }, - { - "Central Europe Standard Time", 60, TRUE, "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague", - "Central Europe Standard Time", "Central Europe Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_38, 1 - }, - { - "Romance Standard Time", 60, TRUE, "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", - "Romance Standard Time", "Romance Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_39, 1 - }, - { - "Central European Standard Time", 60, TRUE, "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", - "Central European Standard Time", "Central European Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_40, 1 - }, - { - "W. Central Africa Standard Time", 60, FALSE, "(UTC+01:00) West Central Africa", - "W. Central Africa Standard Time", "W. Central Africa Daylight Time", - NULL, 0 - }, - { - "Namibia Standard Time", 60, TRUE, "(UTC+01:00) Windhoek", - "Namibia Standard Time", "Namibia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_42, 2 - }, - { - "Jordan Standard Time", 120, TRUE, "(UTC+02:00) Amman", - "Jordan Standard Time", "Jordan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_43, 2 - }, - { - "GTB Standard Time", 120, TRUE, "(UTC+02:00) Athens, Bucharest, Istanbul", - "GTB Standard Time", "GTB Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_44, 1 - }, - { - "Middle East Standard Time", 120, TRUE, "(UTC+02:00) Beirut", - "Middle East Standard Time", "Middle East Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_45, 13 - }, - { - "Egypt Standard Time", 120, TRUE, "(UTC+02:00) Cairo", - "Egypt Standard Time", "Egypt Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_46, 6 - }, - { - "Syria Standard Time", 120, TRUE, "(UTC+02:00) Damascus", - "Syria Standard Time", "Syria Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_47, 12 - }, - { - "South Africa Standard Time", 120, FALSE, "(UTC+02:00) Harare, Pretoria", - "South Africa Standard Time", "South Africa Daylight Time", - NULL, 0 - }, - { - "FLE Standard Time", 120, TRUE, "(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", - "FLE Standard Time", "FLE Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_49, 1 - }, - { - "Turkey Standard Time", 120, TRUE, "(UTC+02:00) Istanbul", - "Turkey Standard Time", "Turkey Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_50, 3 - }, - { - "Israel Standard Time", 120, TRUE, "(UTC+02:00) Jerusalem", - "Jerusalem Standard Time", "Jerusalem Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_51, 18 - }, - { - "E. Europe Standard Time", 120, TRUE, "(UTC+02:00) Nicosia", - "E. Europe Standard Time", "E. Europe Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_52, 1 - }, - { - "Arabic Standard Time", 180, TRUE, "(UTC+03:00) Baghdad", - "Arabic Standard Time", "Arabic Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_53, 2 - }, - { - "Kaliningrad Standard Time", 180, TRUE, "(UTC+03:00) Kaliningrad, Minsk", - "Kaliningrad Standard Time", "Kaliningrad Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_54, 1 - }, - { - "Arab Standard Time", 180, FALSE, "(UTC+03:00) Kuwait, Riyadh", - "Arab Standard Time", "Arab Daylight Time", - NULL, 0 - }, - { - "E. Africa Standard Time", 180, FALSE, "(UTC+03:00) Nairobi", - "E. Africa Standard Time", "E. Africa Daylight Time", - NULL, 0 - }, - { - "Iran Standard Time", 210, TRUE, "(UTC+03:30) Tehran", - "Iran Standard Time", "Iran Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_57, 3 - }, - { - "Arabian Standard Time", 240, FALSE, "(UTC+04:00) Abu Dhabi, Muscat", - "Arabian Standard Time", "Arabian Daylight Time", - NULL, 0 - }, - { - "Azerbaijan Standard Time", 240, TRUE, "(UTC+04:00) Baku", - "Azerbaijan Standard Time", "Azerbaijan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_59, 1 - }, - { - "Russian Standard Time", 240, TRUE, "(UTC+04:00) Moscow, St. Petersburg, Volgograd", - "Russian Standard Time", "Russian Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_60, 1 - }, - { - "Mauritius Standard Time", 240, TRUE, "(UTC+04:00) Port Louis", - "Mauritius Standard Time", "Mauritius Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_61, 2 - }, - { - "Georgian Standard Time", 240, FALSE, "(UTC+04:00) Tbilisi", - "Georgian Standard Time", "Georgian Daylight Time", - NULL, 0 - }, - { - "Caucasus Standard Time", 240, TRUE, "(UTC+04:00) Yerevan", - "Caucasus Standard Time", "Caucasus Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_63, 1 - }, - { - "Afghanistan Standard Time", 270, FALSE, "(UTC+04:30) Kabul", - "Afghanistan Standard Time", "Afghanistan Daylight Time", - NULL, 0 - }, - { - "Pakistan Standard Time", 300, TRUE, "(UTC+05:00) Islamabad, Karachi", - "Pakistan Standard Time", "Pakistan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_65, 2 - }, - { - "West Asia Standard Time", 300, FALSE, "(UTC+05:00) Tashkent", - "West Asia Standard Time", "West Asia Daylight Time", - NULL, 0 - }, - { - "India Standard Time", 330, FALSE, "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", - "India Standard Time", "India Daylight Time", - NULL, 0 - }, - { - "Sri Lanka Standard Time", 330, FALSE, "(UTC+05:30) Sri Jayawardenepura", - "Sri Lanka Standard Time", "Sri Lanka Daylight Time", - NULL, 0 - }, - { - "Nepal Standard Time", 345, FALSE, "(UTC+05:45) Kathmandu", - "Nepal Standard Time", "Nepal Daylight Time", - NULL, 0 - }, - { - "Central Asia Standard Time", 360, FALSE, "(UTC+06:00) Astana", - "Central Asia Standard Time", "Central Asia Daylight Time", - NULL, 0 - }, - { - "Bangladesh Standard Time", 360, TRUE, "(UTC+06:00) Dhaka", - "Bangladesh Standard Time", "Bangladesh Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_71, 1 - }, - { - "Ekaterinburg Standard Time", 360, TRUE, "(UTC+06:00) Ekaterinburg", - "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_72, 1 - }, - { - "Myanmar Standard Time", 390, FALSE, "(UTC+06:30) Yangon (Rangoon)", - "Myanmar Standard Time", "Myanmar Daylight Time", - NULL, 0 - }, - { - "SE Asia Standard Time", 420, FALSE, "(UTC+07:00) Bangkok, Hanoi, Jakarta", - "SE Asia Standard Time", "SE Asia Daylight Time", - NULL, 0 - }, - { - "N. Central Asia Standard Time", 420, TRUE, "(UTC+07:00) Novosibirsk", - "N. Central Asia Standard Time", "N. Central Asia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_75, 1 - }, - { - "China Standard Time", 480, FALSE, "(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", - "China Standard Time", "China Daylight Time", - NULL, 0 - }, - { - "North Asia Standard Time", 480, TRUE, "(UTC+08:00) Krasnoyarsk", - "North Asia Standard Time", "North Asia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_77, 1 - }, - { - "Singapore Standard Time", 480, FALSE, "(UTC+08:00) Kuala Lumpur, Singapore", - "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", - NULL, 0 - }, - { - "W. Australia Standard Time", 480, TRUE, "(UTC+08:00) Perth", - "W. Australia Standard Time", "W. Australia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_79, 4 - }, - { - "Taipei Standard Time", 480, FALSE, "(UTC+08:00) Taipei", - "Taipei Standard Time", "Taipei Daylight Time", - NULL, 0 - }, - { - "Ulaanbaatar Standard Time", 480, FALSE, "(UTC+08:00) Ulaanbaatar", - "Ulaanbaatar Standard Time", "Ulaanbaatar Daylight Time", - NULL, 0 - }, - { - "North Asia East Standard Time", 540, TRUE, "(UTC+09:00) Irkutsk", - "North Asia East Standard Time", "North Asia East Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_82, 1 - }, - { - "Tokyo Standard Time", 540, FALSE, "(UTC+09:00) Osaka, Sapporo, Tokyo", - "Tokyo Standard Time", "Tokyo Daylight Time", - NULL, 0 - }, - { - "Korea Standard Time", 540, FALSE, "(UTC+09:00) Seoul", - "Korea Standard Time", "Korea Daylight Time", - NULL, 0 - }, - { - "Cen. Australia Standard Time", 570, TRUE, "(UTC+09:30) Adelaide", - "Cen. Australia Standard Time", "Cen. Australia Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_85, 2 - }, - { - "AUS Central Standard Time", 570, FALSE, "(UTC+09:30) Darwin", - "AUS Central Standard Time", "AUS Central Daylight Time", - NULL, 0 - }, - { - "E. Australia Standard Time", 600, FALSE, "(UTC+10:00) Brisbane", - "E. Australia Standard Time", "E. Australia Daylight Time", - NULL, 0 - }, - { - "AUS Eastern Standard Time", 600, TRUE, "(UTC+10:00) Canberra, Melbourne, Sydney", - "AUS Eastern Standard Time", "AUS Eastern Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_88, 2 - }, - { - "West Pacific Standard Time", 600, FALSE, "(UTC+10:00) Guam, Port Moresby", - "West Pacific Standard Time", "West Pacific Daylight Time", - NULL, 0 - }, - { - "Tasmania Standard Time", 600, TRUE, "(UTC+10:00) Hobart", - "Tasmania Standard Time", "Tasmania Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_90, 2 - }, - { - "Yakutsk Standard Time", 600, TRUE, "(UTC+10:00) Yakutsk", - "Yakutsk Standard Time", "Yakutsk Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_91, 1 - }, - { - "Central Pacific Standard Time", 660, FALSE, "(UTC+11:00) Solomon Is., New Caledonia", - "Central Pacific Standard Time", "Central Pacific Daylight Time", - NULL, 0 - }, - { - "Vladivostok Standard Time", 660, TRUE, "(UTC+11:00) Vladivostok", - "Vladivostok Standard Time", "Vladivostok Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_93, 1 - }, - { - "New Zealand Standard Time", 720, TRUE, "(UTC+12:00) Auckland, Wellington", - "New Zealand Standard Time", "New Zealand Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_94, 3 - }, - { - "UTC+12", 720, FALSE, "(UTC+12:00) Coordinated Universal Time+12", - "UTC+12", "UTC+12", - NULL, 0 - }, - { - "Fiji Standard Time", 720, TRUE, "(UTC+12:00) Fiji", - "Fiji Standard Time", "Fiji Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_96, 5 - }, - { - "Magadan Standard Time", 720, TRUE, "(UTC+12:00) Magadan", - "Magadan Standard Time", "Magadan Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_97, 1 - }, - { - "Kamchatka Standard Time", 720, TRUE, "(UTC+12:00) Petropavlovsk-Kamchatsky - Old", - "Kamchatka Standard Time", "Kamchatka Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_98, 1 - }, - { - "Tonga Standard Time", 780, FALSE, "(UTC+13:00) Nuku'alofa", - "Tonga Standard Time", "Tonga Daylight Time", - NULL, 0 - }, - { - "Samoa Standard Time", 780, TRUE, "(UTC+13:00) Samoa", - "Samoa Standard Time", "Samoa Daylight Time", - (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_100, 2 - } -}; - -/* Table generated with WindowsZones.cs */ - -struct _WINDOWS_TZID_ENTRY -{ - const char* windows; - const char* tzid; -}; -typedef struct _WINDOWS_TZID_ENTRY WINDOWS_TZID_ENTRY; - -const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = -{ - { "Afghanistan Standard Time", "Asia/Kabul" }, - { "Alaskan Standard Time", "America/Anchorage America/Juneau " - "America/Nome America/Sitka America/Yakutat" }, - { "Alaskan Standard Time", "America/Anchorage" }, - { "Arab Standard Time", "Asia/Aden" }, - { "Arab Standard Time", "Asia/Bahrain" }, - { "Arab Standard Time", "Asia/Kuwait" }, - { "Arab Standard Time", "Asia/Qatar" }, - { "Arab Standard Time", "Asia/Riyadh" }, - { "Arabian Standard Time", "Asia/Dubai" }, - { "Arabian Standard Time", "Asia/Muscat" }, - { "Arabian Standard Time", "Etc/GMT-4" }, - { "Arabic Standard Time", "Asia/Baghdad" }, - { "Argentina Standard Time", "America/Buenos_Aires America/Argentina/La_Rioja " - "America/Argentina/Rio_Gallegos America/Argentina/Salta " - "America/Argentina/San_Juan America/Argentina/San_Luis " - "America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca " - "America/Cordoba America/Jujuy America/Mendoza" }, - { "Argentina Standard Time", "America/Buenos_Aires" }, - { "Atlantic Standard Time", "America/Halifax America/Glace_Bay " - "America/Goose_Bay America/Moncton" }, - { "Atlantic Standard Time", "America/Halifax" }, - { "Atlantic Standard Time", "America/Thule" }, - { "Atlantic Standard Time", "Atlantic/Bermuda" }, - { "AUS Central Standard Time", "Australia/Darwin" }, - { "AUS Eastern Standard Time", "Australia/Sydney Australia/Melbourne" }, - { "AUS Eastern Standard Time", "Australia/Sydney" }, - { "Azerbaijan Standard Time", "Asia/Baku" }, - { "Azores Standard Time", "America/Scoresbysund" }, - { "Azores Standard Time", "Atlantic/Azores" }, - { "Bahia Standard Time", "America/Bahia" }, - { "Bangladesh Standard Time", "Asia/Dhaka" }, - { "Bangladesh Standard Time", "Asia/Thimphu" }, - { "Canada Central Standard Time", "America/Regina America/Swift_Current" }, - { "Canada Central Standard Time", "America/Regina" }, - { "Cape Verde Standard Time", "Atlantic/Cape_Verde" }, - { "Cape Verde Standard Time", "Etc/GMT+1" }, - { "Caucasus Standard Time", "Asia/Yerevan" }, - { "Cen. Australia Standard Time", "Australia/Adelaide Australia/Broken_Hill" }, - { "Cen. Australia Standard Time", "Australia/Adelaide" }, - { "Central America Standard Time", "America/Belize" }, - { "Central America Standard Time", "America/Costa_Rica" }, - { "Central America Standard Time", "America/El_Salvador" }, - { "Central America Standard Time", "America/Guatemala" }, - { "Central America Standard Time", "America/Managua" }, - { "Central America Standard Time", "America/Tegucigalpa" }, - { "Central America Standard Time", "Etc/GMT+6" }, - { "Central America Standard Time", "Pacific/Galapagos" }, - { "Central Asia Standard Time", "Antarctica/Vostok" }, - { "Central Asia Standard Time", "Asia/Almaty Asia/Qyzylorda" }, - { "Central Asia Standard Time", "Asia/Almaty" }, - { "Central Asia Standard Time", "Asia/Bishkek" }, - { "Central Asia Standard Time", "Etc/GMT-6" }, - { "Central Asia Standard Time", "Indian/Chagos" }, - { "Central Brazilian Standard Time", "America/Cuiaba America/Campo_Grande" }, - { "Central Brazilian Standard Time", "America/Cuiaba" }, - { "Central Europe Standard Time", "Europe/Belgrade" }, - { "Central Europe Standard Time", "Europe/Bratislava" }, - { "Central Europe Standard Time", "Europe/Budapest" }, - { "Central Europe Standard Time", "Europe/Ljubljana" }, - { "Central Europe Standard Time", "Europe/Podgorica" }, - { "Central Europe Standard Time", "Europe/Prague" }, - { "Central Europe Standard Time", "Europe/Tirane" }, - { "Central European Standard Time", "Europe/Sarajevo" }, - { "Central European Standard Time", "Europe/Skopje" }, - { "Central European Standard Time", "Europe/Warsaw" }, - { "Central European Standard Time", "Europe/Zagreb" }, - { "Central Pacific Standard Time", "Antarctica/Macquarie" }, - { "Central Pacific Standard Time", "Etc/GMT-11" }, - { "Central Pacific Standard Time", "Pacific/Efate" }, - { "Central Pacific Standard Time", "Pacific/Guadalcanal" }, - { "Central Pacific Standard Time", "Pacific/Noumea" }, - { "Central Pacific Standard Time", "Pacific/Ponape Pacific/Kosrae" }, - { "Central Standard Time (Mexico)", "America/Mexico_City America/Bahia_Banderas " - "America/Cancun America/Merida America/Monterrey" }, - { "Central Standard Time (Mexico)", "America/Mexico_City" }, - { "Central Standard Time", "America/Chicago America/Indiana/Knox " - "America/Indiana/Tell_City America/Menominee " - "America/North_Dakota/Beulah America/North_Dakota/Center " - "America/North_Dakota/New_Salem" }, - { "Central Standard Time", "America/Chicago" }, - { "Central Standard Time", "America/Matamoros" }, - { "Central Standard Time", "America/Winnipeg America/Rainy_River " - "America/Rankin_Inlet America/Resolute" }, - { "Central Standard Time", "CST6CDT" }, - { "China Standard Time", "Asia/Hong_Kong" }, - { "China Standard Time", "Asia/Macau" }, - { "China Standard Time", "Asia/Shanghai Asia/Chongqing Asia/Harbin Asia/Kashgar Asia/Urumqi" }, - { "China Standard Time", "Asia/Shanghai" }, - { "Dateline Standard Time", "Etc/GMT+12" }, - { "E. Africa Standard Time", "Africa/Addis_Ababa" }, - { "E. Africa Standard Time", "Africa/Asmera" }, - { "E. Africa Standard Time", "Africa/Dar_es_Salaam" }, - { "E. Africa Standard Time", "Africa/Djibouti" }, - { "E. Africa Standard Time", "Africa/Juba" }, - { "E. Africa Standard Time", "Africa/Kampala" }, - { "E. Africa Standard Time", "Africa/Khartoum" }, - { "E. Africa Standard Time", "Africa/Mogadishu" }, - { "E. Africa Standard Time", "Africa/Nairobi" }, - { "E. Africa Standard Time", "Antarctica/Syowa" }, - { "E. Africa Standard Time", "Etc/GMT-3" }, - { "E. Africa Standard Time", "Indian/Antananarivo" }, - { "E. Africa Standard Time", "Indian/Comoro" }, - { "E. Africa Standard Time", "Indian/Mayotte" }, - { "E. Australia Standard Time", "Australia/Brisbane Australia/Lindeman" }, - { "E. Australia Standard Time", "Australia/Brisbane" }, - { "E. Europe Standard Time", "Asia/Nicosia" }, - { "E. South America Standard Time", "America/Sao_Paulo" }, - { "Eastern Standard Time", "America/Grand_Turk" }, - { "Eastern Standard Time", "America/Nassau" }, - { "Eastern Standard Time", "America/New_York America/Detroit " - "America/Indiana/Petersburg America/Indiana/Vincennes " - "America/Indiana/Winamac America/Kentucky/Monticello America/Louisville" }, - { "Eastern Standard Time", "America/New_York" }, - { "Eastern Standard Time", "America/Toronto America/Iqaluit America/Montreal " - "America/Nipigon America/Pangnirtung America/Thunder_Bay" }, - { "Eastern Standard Time", "EST5EDT" }, - { "Egypt Standard Time", "Africa/Cairo" }, - { "Egypt Standard Time", "Asia/Gaza Asia/Hebron" }, - { "Ekaterinburg Standard Time", "Asia/Yekaterinburg" }, - { "Fiji Standard Time", "Pacific/Fiji" }, - { "FLE Standard Time", "Europe/Helsinki" }, - { "FLE Standard Time", "Europe/Kiev Europe/Simferopol Europe/Uzhgorod Europe/Zaporozhye" }, - { "FLE Standard Time", "Europe/Kiev" }, - { "FLE Standard Time", "Europe/Mariehamn" }, - { "FLE Standard Time", "Europe/Riga" }, - { "FLE Standard Time", "Europe/Sofia" }, - { "FLE Standard Time", "Europe/Tallinn" }, - { "FLE Standard Time", "Europe/Vilnius" }, - { "Georgian Standard Time", "Asia/Tbilisi" }, - { "GMT Standard Time", "Atlantic/Canary" }, - { "GMT Standard Time", "Atlantic/Faeroe" }, - { "GMT Standard Time", "Europe/Dublin" }, - { "GMT Standard Time", "Europe/Guernsey" }, - { "GMT Standard Time", "Europe/Isle_of_Man" }, - { "GMT Standard Time", "Europe/Jersey" }, - { "GMT Standard Time", "Europe/Lisbon Atlantic/Madeira" }, - { "GMT Standard Time", "Europe/London" }, - { "Greenland Standard Time", "America/Godthab" }, - { "Greenwich Standard Time", "Africa/Abidjan" }, - { "Greenwich Standard Time", "Africa/Accra" }, - { "Greenwich Standard Time", "Africa/Bamako" }, - { "Greenwich Standard Time", "Africa/Banjul" }, - { "Greenwich Standard Time", "Africa/Bissau" }, - { "Greenwich Standard Time", "Africa/Conakry" }, - { "Greenwich Standard Time", "Africa/Dakar" }, - { "Greenwich Standard Time", "Africa/El_Aaiun" }, - { "Greenwich Standard Time", "Africa/Freetown" }, - { "Greenwich Standard Time", "Africa/Lome" }, - { "Greenwich Standard Time", "Africa/Monrovia" }, - { "Greenwich Standard Time", "Africa/Nouakchott" }, - { "Greenwich Standard Time", "Africa/Ouagadougou" }, - { "Greenwich Standard Time", "Africa/Sao_Tome" }, - { "Greenwich Standard Time", "Atlantic/Reykjavik" }, - { "Greenwich Standard Time", "Atlantic/St_Helena" }, - { "GTB Standard Time", "Europe/Athens" }, - { "GTB Standard Time", "Europe/Bucharest" }, - { "GTB Standard Time", "Europe/Chisinau" }, - { "GTB Standard Time", "Europe/Istanbul" }, - { "Hawaiian Standard Time", "Etc/GMT+10" }, - { "Hawaiian Standard Time", "Pacific/Fakaofo" }, - { "Hawaiian Standard Time", "Pacific/Honolulu" }, - { "Hawaiian Standard Time", "Pacific/Johnston" }, - { "Hawaiian Standard Time", "Pacific/Rarotonga" }, - { "Hawaiian Standard Time", "Pacific/Tahiti" }, - { "India Standard Time", "Asia/Calcutta Asia/Kolkata" }, - { "Iran Standard Time", "Asia/Tehran" }, - { "Israel Standard Time", "Asia/Jerusalem" }, - { "Jordan Standard Time", "Asia/Amman" }, - { "Kaliningrad Standard Time", "Europe/Kaliningrad" }, - { "Kaliningrad Standard Time", "Europe/Minsk" }, - { "Korea Standard Time", "Asia/Pyongyang" }, - { "Korea Standard Time", "Asia/Seoul" }, - { "Magadan Standard Time", "Asia/Magadan Asia/Anadyr Asia/Kamchatka" }, - { "Magadan Standard Time", "Asia/Magadan" }, - { "Mauritius Standard Time", "Indian/Mahe" }, - { "Mauritius Standard Time", "Indian/Mauritius" }, - { "Mauritius Standard Time", "Indian/Reunion" }, - { "Middle East Standard Time", "Asia/Beirut" }, - { "Montevideo Standard Time", "America/Montevideo" }, - { "Morocco Standard Time", "Africa/Casablanca" }, - { "Mountain Standard Time (Mexico)", "America/Chihuahua America/Mazatlan" }, - { "Mountain Standard Time (Mexico)", "America/Chihuahua" }, - { "Mountain Standard Time", "America/Denver America/Boise America/Shiprock" }, - { "Mountain Standard Time", "America/Denver" }, - { "Mountain Standard Time", "America/Edmonton " - "America/Cambridge_Bay America/Inuvik America/Yellowknife" }, - { "Mountain Standard Time", "America/Ojinaga" }, - { "Mountain Standard Time", "MST7MDT" }, - { "Myanmar Standard Time", "Asia/Rangoon" }, - { "Myanmar Standard Time", "Indian/Cocos" }, - { "N. Central Asia Standard Time", "Asia/Novosibirsk Asia/Novokuznetsk Asia/Omsk" }, - { "N. Central Asia Standard Time", "Asia/Novosibirsk" }, - { "Namibia Standard Time", "Africa/Windhoek" }, - { "Nepal Standard Time", "Asia/Katmandu Asia/Kathmandu" }, - { "New Zealand Standard Time", "Antarctica/South_Pole Antarctica/McMurdo" }, - { "New Zealand Standard Time", "Pacific/Auckland" }, - { "Newfoundland Standard Time", "America/St_Johns" }, - { "North Asia East Standard Time", "Asia/Irkutsk" }, - { "North Asia Standard Time", "Asia/Krasnoyarsk" }, - { "Pacific SA Standard Time", "America/Santiago" }, - { "Pacific SA Standard Time", "Antarctica/Palmer" }, - { "Pacific Standard Time (Mexico)", "America/Santa_Isabel" }, - { "Pacific Standard Time", "America/Los_Angeles" }, - { "Pacific Standard Time", "America/Tijuana America/Ensenada" }, - { "Pacific Standard Time", "America/Vancouver America/Dawson America/Whitehorse" }, - { "Pacific Standard Time", "PST8PDT" }, - { "Pakistan Standard Time", "Asia/Karachi" }, - { "Paraguay Standard Time", "America/Asuncion" }, - { "Romance Standard Time", "Europe/Brussels" }, - { "Romance Standard Time", "Europe/Copenhagen" }, - { "Romance Standard Time", "Europe/Madrid Africa/Ceuta" }, - { "Romance Standard Time", "Europe/Paris" }, - { "Russian Standard Time", "Europe/Moscow Europe/Samara Europe/Volgograd" }, - { "Russian Standard Time", "Europe/Moscow" }, - { "SA Eastern Standard Time", "America/Cayenne" }, - { "SA Eastern Standard Time", "America/Fortaleza America/Araguaina " - "America/Belem America/Maceio America/Recife America/Santarem" }, - { "SA Eastern Standard Time", "America/Paramaribo" }, - { "SA Eastern Standard Time", "Antarctica/Rothera" }, - { "SA Eastern Standard Time", "Etc/GMT+3" }, - { "SA Pacific Standard Time", "America/Bogota" }, - { "SA Pacific Standard Time", "America/Cayman" }, - { "SA Pacific Standard Time", "America/Coral_Harbour" }, - { "SA Pacific Standard Time", "America/Guayaquil" }, - { "SA Pacific Standard Time", "America/Jamaica" }, - { "SA Pacific Standard Time", "America/Lima" }, - { "SA Pacific Standard Time", "America/Panama" }, - { "SA Pacific Standard Time", "America/Port-au-Prince" }, - { "SA Pacific Standard Time", "Etc/GMT+5" }, - { "SA Western Standard Time", "America/Anguilla" }, - { "SA Western Standard Time", "America/Antigua" }, - { "SA Western Standard Time", "America/Aruba" }, - { "SA Western Standard Time", "America/Barbados" }, - { "SA Western Standard Time", "America/Blanc-Sablon" }, - { "SA Western Standard Time", "America/Curacao" }, - { "SA Western Standard Time", "America/Dominica" }, - { "SA Western Standard Time", "America/Grenada" }, - { "SA Western Standard Time", "America/Guadeloupe" }, - { "SA Western Standard Time", "America/Guyana" }, - { "SA Western Standard Time", "America/La_Paz" }, - { "SA Western Standard Time", "America/Manaus America/Boa_Vista " - "America/Eirunepe America/Porto_Velho America/Rio_Branco" }, - { "SA Western Standard Time", "America/Marigot" }, - { "SA Western Standard Time", "America/Martinique" }, - { "SA Western Standard Time", "America/Montserrat" }, - { "SA Western Standard Time", "America/Port_of_Spain" }, - { "SA Western Standard Time", "America/Puerto_Rico" }, - { "SA Western Standard Time", "America/Santo_Domingo" }, - { "SA Western Standard Time", "America/St_Barthelemy" }, - { "SA Western Standard Time", "America/St_Kitts" }, - { "SA Western Standard Time", "America/St_Lucia" }, - { "SA Western Standard Time", "America/St_Thomas" }, - { "SA Western Standard Time", "America/St_Vincent" }, - { "SA Western Standard Time", "America/Tortola" }, - { "SA Western Standard Time", "Etc/GMT+4" }, - { "Samoa Standard Time", "Pacific/Apia Pacific/Samoa" }, - { "SE Asia Standard Time", "Antarctica/Davis" }, - { "SE Asia Standard Time", "Asia/Bangkok" }, - { "SE Asia Standard Time", "Asia/Hovd" }, - { "SE Asia Standard Time", "Asia/Jakarta Asia/Pontianak" }, - { "SE Asia Standard Time", "Asia/Phnom_Penh" }, - { "SE Asia Standard Time", "Asia/Saigon Asia/Ho_Chi_Minh" }, - { "SE Asia Standard Time", "Asia/Vientiane" }, - { "SE Asia Standard Time", "Etc/GMT-7" }, - { "SE Asia Standard Time", "Indian/Christmas" }, - { "Singapore Standard Time", "Asia/Brunei" }, - { "Singapore Standard Time", "Asia/Kuala_Lumpur Asia/Kuching" }, - { "Singapore Standard Time", "Asia/Makassar" }, - { "Singapore Standard Time", "Asia/Manila" }, - { "Singapore Standard Time", "Asia/Singapore" }, - { "Singapore Standard Time", "Etc/GMT-8" }, - { "South Africa Standard Time", "Africa/Blantyre" }, - { "South Africa Standard Time", "Africa/Bujumbura" }, - { "South Africa Standard Time", "Africa/Gaborone" }, - { "South Africa Standard Time", "Africa/Harare" }, - { "South Africa Standard Time", "Africa/Johannesburg" }, - { "South Africa Standard Time", "Africa/Kigali" }, - { "South Africa Standard Time", "Africa/Lubumbashi" }, - { "South Africa Standard Time", "Africa/Lusaka" }, - { "South Africa Standard Time", "Africa/Maputo" }, - { "South Africa Standard Time", "Africa/Maseru" }, - { "South Africa Standard Time", "Africa/Mbabane" }, - { "South Africa Standard Time", "Africa/Tripoli" }, - { "South Africa Standard Time", "Etc/GMT-2" }, - { "Sri Lanka Standard Time", "Asia/Colombo" }, - { "Syria Standard Time", "Asia/Damascus" }, - { "Taipei Standard Time", "Asia/Taipei" }, - { "Tasmania Standard Time", "Australia/Hobart Australia/Currie" }, - { "Tasmania Standard Time", "Australia/Hobart" }, - { "Tokyo Standard Time", "Asia/Dili" }, - { "Tokyo Standard Time", "Asia/Jayapura" }, - { "Tokyo Standard Time", "Asia/Tokyo" }, - { "Tokyo Standard Time", "Etc/GMT-9" }, - { "Tokyo Standard Time", "Pacific/Palau" }, - { "Tonga Standard Time", "Etc/GMT-13" }, - { "Tonga Standard Time", "Pacific/Enderbury" }, - { "Tonga Standard Time", "Pacific/Tongatapu" }, - /* { "Turkey Standard Time", "Europe/Istanbul" }, */ - { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar Asia/Choibalsan" }, - { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar" }, - { "US Eastern Standard Time", "America/Indianapolis " - "America/Indiana/Marengo America/Indiana/Vevay" }, - { "US Eastern Standard Time", "America/Indianapolis" }, - { "US Mountain Standard Time", "America/Dawson_Creek" }, - { "US Mountain Standard Time", "America/Hermosillo" }, - { "US Mountain Standard Time", "America/Phoenix" }, - { "US Mountain Standard Time", "Etc/GMT+7" }, - { "UTC", "America/Danmarkshavn" }, - { "UTC", "Etc/GMT" }, - { "UTC+12", "Etc/GMT-12" }, - { "UTC+12", "Pacific/Funafuti" }, - { "UTC+12", "Pacific/Majuro Pacific/Kwajalein" }, - { "UTC+12", "Pacific/Nauru" }, - { "UTC+12", "Pacific/Tarawa" }, - { "UTC+12", "Pacific/Wake" }, - { "UTC+12", "Pacific/Wallis" }, - { "UTC-02", "America/Noronha" }, - { "UTC-02", "Atlantic/South_Georgia" }, - { "UTC-02", "Etc/GMT+2" }, - { "UTC-11", "Etc/GMT+11" }, - { "UTC-11", "Pacific/Midway" }, - { "UTC-11", "Pacific/Niue" }, - { "UTC-11", "Pacific/Pago_Pago" }, - { "Venezuela Standard Time", "America/Caracas" }, - { "Vladivostok Standard Time", "Asia/Vladivostok Asia/Sakhalin" }, - { "Vladivostok Standard Time", "Asia/Vladivostok" }, - { "W. Australia Standard Time", "Antarctica/Casey" }, - { "W. Australia Standard Time", "Australia/Perth" }, - { "W. Central Africa Standard Time", "Africa/Algiers" }, - { "W. Central Africa Standard Time", "Africa/Bangui" }, - { "W. Central Africa Standard Time", "Africa/Brazzaville" }, - { "W. Central Africa Standard Time", "Africa/Douala" }, - { "W. Central Africa Standard Time", "Africa/Kinshasa" }, - { "W. Central Africa Standard Time", "Africa/Lagos" }, - { "W. Central Africa Standard Time", "Africa/Libreville" }, - { "W. Central Africa Standard Time", "Africa/Luanda" }, - { "W. Central Africa Standard Time", "Africa/Malabo" }, - { "W. Central Africa Standard Time", "Africa/Ndjamena" }, - { "W. Central Africa Standard Time", "Africa/Niamey" }, - { "W. Central Africa Standard Time", "Africa/Porto-Novo" }, - { "W. Central Africa Standard Time", "Africa/Tunis" }, - { "W. Central Africa Standard Time", "Etc/GMT-1" }, - { "W. Europe Standard Time", "Arctic/Longyearbyen" }, - { "W. Europe Standard Time", "Europe/Amsterdam" }, - { "W. Europe Standard Time", "Europe/Andorra" }, - { "W. Europe Standard Time", "Europe/Berlin" }, - { "W. Europe Standard Time", "Europe/Gibraltar" }, - { "W. Europe Standard Time", "Europe/Luxembourg" }, - { "W. Europe Standard Time", "Europe/Malta" }, - { "W. Europe Standard Time", "Europe/Monaco" }, - { "W. Europe Standard Time", "Europe/Oslo" }, - { "W. Europe Standard Time", "Europe/Rome" }, - { "W. Europe Standard Time", "Europe/San_Marino" }, - { "W. Europe Standard Time", "Europe/Stockholm" }, - { "W. Europe Standard Time", "Europe/Vaduz" }, - { "W. Europe Standard Time", "Europe/Vatican" }, - { "W. Europe Standard Time", "Europe/Vienna" }, - { "W. Europe Standard Time", "Europe/Zurich" }, - { "West Asia Standard Time", "Antarctica/Mawson" }, - { "West Asia Standard Time", "Asia/Ashgabat" }, - { "West Asia Standard Time", "Asia/Dushanbe" }, - { "West Asia Standard Time", "Asia/Oral Asia/Aqtau Asia/Aqtobe" }, - { "West Asia Standard Time", "Asia/Tashkent Asia/Samarkand" }, - { "West Asia Standard Time", "Asia/Tashkent" }, - { "West Asia Standard Time", "Etc/GMT-5" }, - { "West Asia Standard Time", "Indian/Kerguelen" }, - { "West Asia Standard Time", "Indian/Maldives" }, - { "West Pacific Standard Time", "Antarctica/DumontDUrville" }, - { "West Pacific Standard Time", "Etc/GMT-10" }, - { "West Pacific Standard Time", "Pacific/Guam" }, - { "West Pacific Standard Time", "Pacific/Port_Moresby" }, - { "West Pacific Standard Time", "Pacific/Saipan" }, - { "West Pacific Standard Time", "Pacific/Truk" }, - { "Yakutsk Standard Time", "Asia/Yakutsk" } -}; - -static UINT64 freerdp_windows_gmtime() -{ - time_t unix_time; - UINT64 windows_time; - - time(&unix_time); - windows_time = unix_time; - windows_time *= 10000000; - windows_time += 621355968000000000ULL; - - return windows_time; -} - -char* freerdp_get_unix_timezone_identifier() -{ -#ifndef _WIN32 - FILE* fp; - ssize_t len; - char* tz_env; - size_t length; - char* tzid = NULL; - char buf[1024]; - - tz_env = getenv("TZ"); - - if (tz_env != NULL) - { - tzid = _strdup(tz_env); - return tzid; - } - -#if defined(__FreeBSD__) || defined(__OpenBSD__) - fp = fopen("/var/db/zoneinfo", "r"); -#else - fp = fopen("/etc/timezone", "r"); -#endif - if (fp != NULL) - { - fseek(fp, 0, SEEK_END); - length = ftell(fp); - fseek(fp, 0, SEEK_SET); - - if (length < 2) - { - fclose(fp) ; - return NULL; - } - - tzid = (char*) malloc(length + 1); - if (!tzid) - { - fclose(fp); - return NULL; - } - - if (fread(tzid, length, 1, fp) != 1) - { - free(tzid); - fclose(fp); - return NULL; - } - tzid[length] = '\0'; - - if (tzid[length - 1] == '\n') - tzid[length - 1] = '\0'; - - fclose(fp); - - return tzid; - } - - /* - * On linux distros such as Redhat or Archlinux, a symlink at /etc/localtime - * will point to /usr/share/zoneinfo/region/place where region/place could be - * America/Montreal for example. - */ - - if ((len = readlink("/etc/localtime", buf, sizeof(buf) - 1)) != -1) - { - int num = 0; - int pos = len; - - buf[len] = '\0'; - - /* find the position of the 2nd to last "/" */ - - while (num < 2) - { - if (pos == 0) - break; - - pos -= 1; - - if (buf[pos] == '/') - num++; - } - - tzid = (char*) malloc(len - pos + 1); - if (!tzid) - return NULL; - - strncpy(tzid, buf + pos + 1, len - pos); - - return tzid; - } - - WLog_ERR(TAG, "Unable to detect time zone"); - return tzid; -#else - return 0; -#endif -} - -BOOL freerdp_match_unix_timezone_identifier_with_list(const char* tzid, const char* list) -{ - char* p; - char* list_copy; - - list_copy = _strdup(list); - if (!list_copy) - return FALSE; - - p = strtok(list_copy, " "); - - while (p != NULL) - { - if (strcmp(p, tzid) == 0) - { - free(list_copy); - return TRUE; - } - - p = strtok(NULL, " "); - } - - free(list_copy); - - return FALSE; -} - -TIME_ZONE_ENTRY* freerdp_detect_windows_time_zone(UINT32 bias) -{ - int i, j; - char* tzid; - TIME_ZONE_ENTRY* timezone; - - tzid = freerdp_get_unix_timezone_identifier(); - - if (tzid == NULL) - return NULL; - - for (i = 0; i < ARRAYSIZE(TimeZoneTable); i++) - { - for (j = 0; j < ARRAYSIZE(WindowsTimeZoneIdTable); j++) - { - if (strcmp(TimeZoneTable[i].Id, WindowsTimeZoneIdTable[j].windows) != 0) - continue; - - if (freerdp_match_unix_timezone_identifier_with_list(tzid, WindowsTimeZoneIdTable[j].tzid)) - { - free(tzid); - - timezone = (TIME_ZONE_ENTRY*) malloc(sizeof(TIME_ZONE_ENTRY)); - if (!timezone) - return NULL; - memcpy((void*) timezone, (void*) &TimeZoneTable[i], sizeof(TIME_ZONE_ENTRY)); - timezone->Bias = bias; - return timezone; - } - } - } - - WLog_ERR(TAG, "Unable to find a match for unix timezone: %s", tzid); - free(tzid); - return NULL; -} - -TIME_ZONE_RULE_ENTRY* freerdp_get_current_time_zone_rule(TIME_ZONE_RULE_ENTRY* rules, UINT32 count) -{ - int i; - UINT64 windows_time; - - windows_time = freerdp_windows_gmtime(); - - for (i = 0; i < (int) count; i++) - { - if ((rules[i].TicksStart >= windows_time) && (windows_time >= rules[i].TicksEnd)) - { - /*WLog_ERR(TAG, "Got rule %d from table at %p with count %u", i, rules, count);*/ - return &rules[i]; - } - } - - WLog_ERR(TAG, "Unable to get current timezone rule"); - return NULL; -} - -void freerdp_time_zone_detect(TIME_ZONE_INFO* clientTimeZone) -{ - time_t t; - TIME_ZONE_ENTRY* tz; - struct tm* local_time; - - clientTimeZone->standardBias = 0; - - time(&t); - local_time = localtime(&t); - -#ifdef HAVE_TM_GMTOFF - #if defined(__FreeBSD__) || defined(__OpenBSD__) - if (local_time->tm_gmtoff >= 0) - clientTimeZone->bias = (UINT32) (local_time->tm_gmtoff / 60); - else - clientTimeZone->bias = (UINT32) (1440 + (INT32) (local_time->tm_gmtoff / 60)); - #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) - clientTimeZone->bias = (UINT32) (altzone / 3600); - else - clientTimeZone->bias = (UINT32) (timezone / 3600); -#else - clientTimeZone->bias = 0; -#endif - - tz = freerdp_detect_windows_time_zone(clientTimeZone->bias); - - if (tz!= NULL) - { - DEBUG_TIMEZONE("tz: Id='%s' Bias=%d DST=%d dn='%s' sn='%s' dln='%s'", - tz->Id, tz->Bias, tz->SupportsDST, tz->DisplayName, - tz->StandardName, tz->DaylightName); - - sprintf(clientTimeZone->standardName, "%s", tz->StandardName); - sprintf(clientTimeZone->daylightName, "%s", tz->DaylightName); - - if ((tz->SupportsDST) && (tz->RuleTableCount > 0)) - { - TIME_ZONE_RULE_ENTRY* rule; - rule = freerdp_get_current_time_zone_rule(tz->RuleTable, tz->RuleTableCount); - - if (rule != NULL) - { - clientTimeZone->daylightBias = -rule->DaylightDelta; - - clientTimeZone->standardDate.wYear = rule->StandardDate.wYear; - clientTimeZone->standardDate.wMonth = rule->StandardDate.wMonth; - clientTimeZone->standardDate.wDayOfWeek = rule->StandardDate.wDayOfWeek; - clientTimeZone->standardDate.wDay = rule->StandardDate.wDay; - clientTimeZone->standardDate.wHour = rule->StandardDate.wHour; - clientTimeZone->standardDate.wMinute = rule->StandardDate.wMinute; - clientTimeZone->standardDate.wSecond = rule->StandardDate.wSecond; - clientTimeZone->standardDate.wMilliseconds = rule->StandardDate.wMilliseconds; - - clientTimeZone->daylightDate.wYear = rule->DaylightDate.wYear; - clientTimeZone->daylightDate.wMonth = rule->DaylightDate.wMonth; - clientTimeZone->daylightDate.wDayOfWeek = rule->DaylightDate.wDayOfWeek; - clientTimeZone->daylightDate.wDay = rule->DaylightDate.wDay; - clientTimeZone->daylightDate.wHour = rule->DaylightDate.wHour; - clientTimeZone->daylightDate.wMinute = rule->DaylightDate.wMinute; - clientTimeZone->daylightDate.wSecond = rule->DaylightDate.wSecond; - clientTimeZone->daylightDate.wMilliseconds = rule->DaylightDate.wMilliseconds; - } - } - free(tz); - } - else - { - /* could not detect timezone, fallback to using GMT */ - DEBUG_TIMEZONE("tz not found, using GMT."); - sprintf(clientTimeZone->standardName, "%s", "GMT Standard Time"); - sprintf(clientTimeZone->daylightName, "%s", "GMT Daylight Time"); - } -} diff --git a/rdtk/librdtk/CMakeLists.txt b/rdtk/librdtk/CMakeLists.txt index e12f162b6..b6caf80c4 100644 --- a/rdtk/librdtk/CMakeLists.txt +++ b/rdtk/librdtk/CMakeLists.txt @@ -65,7 +65,7 @@ endif() target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT RdTkTargets) -if (MSVC AND BUILD_SHARED_LIBS) +if (WITH_DEBUG_SYMBOLS AND MSVC AND BUILD_SHARED_LIBS) install(FILES ${CMAKE_PDB_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT symbols) endif() diff --git a/scripts/TimeZones.cs b/scripts/TimeZones.cs index d8b0d9edd..80a1550d9 100644 --- a/scripts/TimeZones.cs +++ b/scripts/TimeZones.cs @@ -141,7 +141,7 @@ namespace TimeZones tzr.StandardDate.wYear = (UInt16)0; tzr.StandardDate.wMonth = (UInt16)transition.Month; tzr.StandardDate.wDayOfWeek = (UInt16)transition.DayOfWeek; - tzr.StandardDate.wDay = (UInt16)transition.Day; + tzr.StandardDate.wDay = (UInt16)transition.Week; tzr.StandardDate.wHour = (UInt16)time.Hour; tzr.StandardDate.wMinute = (UInt16)time.Minute; tzr.StandardDate.wSecond = (UInt16)time.Second; @@ -153,7 +153,7 @@ namespace TimeZones tzr.DaylightDate.wYear = (UInt16)0; tzr.DaylightDate.wMonth = (UInt16)transition.Month; tzr.DaylightDate.wDayOfWeek = (UInt16)transition.DayOfWeek; - tzr.DaylightDate.wDay = (UInt16)transition.Day; + tzr.DaylightDate.wDay = (UInt16)transition.Week; tzr.DaylightDate.wHour = (UInt16)time.Hour; tzr.DaylightDate.wMinute = (UInt16)time.Minute; tzr.DaylightDate.wSecond = (UInt16)time.Second; diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index a522f868f..73ce02114 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -80,6 +80,7 @@ fi common_run mkdir -p $BUILD_SRC CMAKE_CMD_ARGS="-DANDROID_NDK=$ANDROID_NDK \ + -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \ -DCMAKE_TOOLCHAIN_FILE=$SRC_DIR/cmake/AndroidToolchain.cmake \ -DCMAKE_INSTALL_PREFIX=$BUILD_DST \ -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ diff --git a/scripts/android-build.conf b/scripts/android-build.conf index 4d26f9407..df5191211 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -4,10 +4,11 @@ SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") SCRIPT_PATH=$(realpath "$SCRIPT_PATH") -WITH_JPEG=1 +WITH_JPEG=0 WITH_OPENH264=1 WITH_OPENSSL=1 BUILD_DEPS=1 +ANDROID_NATIVE_API_LEVEL=android-12 JPEG_TAG=master OPENH264_TAG=v1.5.0 @@ -19,4 +20,4 @@ BUILD_SRC=$SRC_DIR/build CMAKE_BUILD_TYPE=Debug -BUILD_ARCH="armeabi armeabi-v7a x86 mips" +BUILD_ARCH="armeabi armeabi-v7a x86" diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index ba2cf9ecc..9095f4aa0 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -441,20 +441,16 @@ BOOL tf_peer_dump_rfx(freerdp_peer* client) while (pcap_has_next_record(pcap_rfx)) { - BYTE* tmp = NULL; if (!pcap_get_next_record_header(pcap_rfx, &record)) break; - tmp = realloc(Stream_Buffer(s), record.length); - if (!tmp) + if (!Stream_EnsureCapacity(s, record.length)) break; - Stream_Buffer(s) = tmp; record.data = Stream_Buffer(s); - Stream_Capacity(s) = record.length; pcap_get_next_record_content(pcap_rfx, &record); - Stream_Pointer(s) = Stream_Buffer(s) + Stream_Capacity(s); + Stream_SetPointer(s, Stream_Buffer(s) + Stream_Capacity(s)); if (test_dump_rfx_realtime && test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec, record.header.ts_usec) == FALSE) break; diff --git a/server/Windows/wf_interface.c b/server/Windows/wf_interface.c index 0dc8defd0..6a158b140 100644 --- a/server/Windows/wf_interface.c +++ b/server/Windows/wf_interface.c @@ -212,7 +212,7 @@ void wfreerdp_server_free(wfServer* server) WSACleanup(); } -FREERDP_API BOOL wfreerdp_server_is_running(wfServer* server) +BOOL wfreerdp_server_is_running(wfServer* server) { DWORD tStatus; BOOL bRet; @@ -229,7 +229,7 @@ FREERDP_API BOOL wfreerdp_server_is_running(wfServer* server) return FALSE; } -FREERDP_API UINT32 wfreerdp_server_num_peers() +UINT32 wfreerdp_server_num_peers() { wfInfo* wfi; @@ -239,7 +239,7 @@ FREERDP_API UINT32 wfreerdp_server_num_peers() return wfi->peerCount; } -FREERDP_API UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t * dstStr) +UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t * dstStr) { wfInfo* wfi; freerdp_peer* peer; @@ -264,7 +264,7 @@ FREERDP_API UINT32 wfreerdp_server_get_peer_hostname(int pId, wchar_t * dstStr) } } -FREERDP_API BOOL wfreerdp_server_peer_is_local(int pId) +BOOL wfreerdp_server_peer_is_local(int pId) { wfInfo* wfi; freerdp_peer* peer; @@ -284,7 +284,7 @@ FREERDP_API BOOL wfreerdp_server_peer_is_local(int pId) } } -FREERDP_API BOOL wfreerdp_server_peer_is_connected(int pId) +BOOL wfreerdp_server_peer_is_connected(int pId) { wfInfo* wfi; freerdp_peer* peer; @@ -305,7 +305,7 @@ FREERDP_API BOOL wfreerdp_server_peer_is_connected(int pId) } } -FREERDP_API BOOL wfreerdp_server_peer_is_activated(int pId) +BOOL wfreerdp_server_peer_is_activated(int pId) { wfInfo* wfi; freerdp_peer* peer; @@ -325,7 +325,7 @@ FREERDP_API BOOL wfreerdp_server_peer_is_activated(int pId) } } -FREERDP_API BOOL wfreerdp_server_peer_is_authenticated(int pId) +BOOL wfreerdp_server_peer_is_authenticated(int pId) { wfInfo* wfi; freerdp_peer* peer; @@ -345,7 +345,7 @@ FREERDP_API BOOL wfreerdp_server_peer_is_authenticated(int pId) } } -FREERDP_API void wfreerdp_server_register_callback_event(cbCallback cb) +void wfreerdp_server_register_callback_event(cbCallback cb) { cbEvent = cb; } diff --git a/server/common/CMakeLists.txt b/server/common/CMakeLists.txt index d5b990610..009d5662a 100644 --- a/server/common/CMakeLists.txt +++ b/server/common/CMakeLists.txt @@ -33,7 +33,7 @@ foreach(FREERDP_CHANNELS_SERVER_SRC ${FREERDP_CHANNELS_SERVER_SRCS}) endforeach() if(MSVC) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}) endif() diff --git a/server/common/module.def b/server/common/module.def deleted file mode 100644 index 17f147374..000000000 --- a/server/common/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "freerdp-server" -EXPORTS - diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt index 421d4bd82..3eb741d6a 100644 --- a/server/shadow/CMakeLists.txt +++ b/server/shadow/CMakeLists.txt @@ -15,11 +15,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +# freerdp-shadow library + set(MODULE_NAME "freerdp-shadow") set(MODULE_PREFIX "FREERDP_SERVER_SHADOW") -include_directories(${OPENSSL_INCLUDE_DIR}) - set(${MODULE_PREFIX}_SRCS shadow_client.c shadow_client.h @@ -75,7 +75,6 @@ list(APPEND ${MODULE_PREFIX}_LIBS freerdp) list(APPEND ${MODULE_PREFIX}_LIBS freerdp-server) list(APPEND ${MODULE_PREFIX}_LIBS winpr) list(APPEND ${MODULE_PREFIX}_LIBS winpr-makecert-tool) - list(APPEND ${MODULE_PREFIX}_LIBS rdtk) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) @@ -84,7 +83,7 @@ if (WITH_LIBRARY_VERSIONING) set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) endif() -install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT server) +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT server EXPORT FreeRDP-ShadowTargets) if (WITH_DEBUG_SYMBOLS AND MSVC) install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT symbols) @@ -92,10 +91,13 @@ endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow") -# command-line executable +# subsystem library -set(MODULE_NAME "freerdp-shadow-cli") -set(MODULE_PREFIX "FREERDP_SERVER_SHADOW_CLI") +set(MODULE_NAME "freerdp-shadow-subsystem") +set(MODULE_PREFIX "FREERDP_SERVER_SHADOW_SUBSYSTEM") + +set(${MODULE_PREFIX}_SRCS + shadow_subsystem_builtin.c) if(WIN32) set(WITH_SHADOW_WIN 1) @@ -105,6 +107,20 @@ elseif(APPLE AND NOT IOS) set(WITH_SHADOW_MAC 1) endif() +if (WIN32) + set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR}) + set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR}) + set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION}) + set (RC_VERSION_FILE "${MODULE_NAME}${CMAKE_EXECUTABLE_SUFFIX}" ) + + configure_file( + ${CMAKE_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/version.rc + @ONLY) + + set ( ${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + # Authentication if(WITH_SHADOW_X11 OR WITH_SHADOW_MAC) @@ -216,18 +232,15 @@ if(WITH_SHADOW_X11) include_directories(${XRANDR_INCLUDE_DIRS}) list(APPEND ${MODULE_PREFIX}_X11_LIBS ${XRANDR_LIBRARIES}) endif() -endif() - -if(WITH_SHADOW_MAC) +elseif(WITH_SHADOW_MAC) find_library(IOKIT IOKit) find_library(IOSURFACE IOSurface) find_library(CARBON Carbon) list(APPEND ${MODULE_PREFIX}_MAC_LIBS ${IOKIT} ${IOSURFACE} ${CARBON}) +elseif(WITH_SHADOW_WIN) + list(APPEND ${MODULE_PREFIX}_WIN_LIBS freerdp-client) endif() -set(${MODULE_PREFIX}_SRCS - shadow.c) - set(${MODULE_PREFIX}_WIN_SRCS Win/win_rdp.c Win/win_rdp.h @@ -262,7 +275,34 @@ endif() list(APPEND ${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_AUTH_LIBS}) - # On windows create dll version information. +add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-shadow) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION}) +endif() + +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT server EXPORT FreeRDP-ShadowTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT symbols) +endif() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow") + +# command-line executable + +set(MODULE_NAME "freerdp-shadow-cli") +set(MODULE_PREFIX "FREERDP_SERVER_SHADOW_CLI") + +set(${MODULE_PREFIX}_SRCS + shadow.c) + +# On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt if (WIN32) set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR}) @@ -280,7 +320,7 @@ endif() add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-shadow) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-shadow-subsystem) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) @@ -291,3 +331,25 @@ if (WITH_DEBUG_SYMBOLS AND MSVC) endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Server/shadow") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp-shadow.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp-shadow${FREERDP_VERSION_MAJOR}.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp-shadow${FREERDP_VERSION_MAJOR}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") + + export(PACKAGE freerdp-shadow) + + set(FREERDP_SERVER_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP-Shadow${FREERDP_VERSION_MAJOR}") + + configure_package_config_file(FreeRDP-ShadowConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfig.cmake + INSTALL_DESTINATION ${FREERDP_SERVER_CMAKE_INSTALL_DIR} + PATH_VARS FREERDP_INCLUDE_DIR) + + write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfigVersion.cmake + VERSION ${FREERDP_VERSION} COMPATIBILITY SameMajorVersion) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/FreeRDP-ShadowConfigVersion.cmake + DESTINATION ${FREERDP_SERVER_CMAKE_INSTALL_DIR}) + + install(EXPORT FreeRDP-ShadowTargets DESTINATION ${FREERDP_SERVER_CMAKE_INSTALL_DIR}) +endif() diff --git a/server/shadow/FreeRDP-ShadowConfig.cmake.in b/server/shadow/FreeRDP-ShadowConfig.cmake.in new file mode 100644 index 000000000..1eb11e0f5 --- /dev/null +++ b/server/shadow/FreeRDP-ShadowConfig.cmake.in @@ -0,0 +1,10 @@ + +@PACKAGE_INIT@ + +set(FreeRDP-Shadow_VERSION_MAJOR "@FREERDP_VERSION_MAJOR@") +set(FreeRDP-Shadow_VERSION_MINOR "@FREERDP_VERSION_MINOR@") +set(FreeRDP-Shadow_VERSION_REVISION "@FREERDP_VERSION_REVISION@") + +set_and_check(FreeRDP-Shadow_INCLUDE_DIR "@PACKAGE_FREERDP_INCLUDE_DIR@") + +include("${CMAKE_CURRENT_LIST_DIR}/FreeRDP-ShadowTargets.cmake") diff --git a/server/shadow/Mac/mac_shadow.c b/server/shadow/Mac/mac_shadow.c index 2fd5f96d4..10508c9fe 100644 --- a/server/shadow/Mac/mac_shadow.c +++ b/server/shadow/Mac/mac_shadow.c @@ -660,7 +660,7 @@ macShadowSubsystem* mac_shadow_subsystem_new() return subsystem; } -int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +FREERDP_API int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) { pEntryPoints->New = (pfnShadowSubsystemNew) mac_shadow_subsystem_new; pEntryPoints->Free = (pfnShadowSubsystemFree) mac_shadow_subsystem_free; diff --git a/server/shadow/Win/win_rdp.c b/server/shadow/Win/win_rdp.c index d9e0b34bb..b254f2aec 100644 --- a/server/shadow/Win/win_rdp.c +++ b/server/shadow/Win/win_rdp.c @@ -99,9 +99,11 @@ BOOL shw_authenticate(freerdp* instance, char** username, char** password, char* return TRUE; } -BOOL shw_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) +static DWORD shw_verify_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, BOOL host_mismatch) { - return TRUE; + return 1; } int shw_verify_x509_certificate(freerdp* instance, BYTE* data, int length, const char* hostname, int port, DWORD flags) diff --git a/server/shadow/Win/win_shadow.c b/server/shadow/Win/win_shadow.c index d1dbc5888..0f23b9c05 100644 --- a/server/shadow/Win/win_shadow.c +++ b/server/shadow/Win/win_shadow.c @@ -519,7 +519,7 @@ winShadowSubsystem* win_shadow_subsystem_new() return subsystem; } -int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +FREERDP_API int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) { pEntryPoints->New = (pfnShadowSubsystemNew) win_shadow_subsystem_new; pEntryPoints->Free = (pfnShadowSubsystemFree) win_shadow_subsystem_free; diff --git a/server/shadow/Win/win_wds.c b/server/shadow/Win/win_wds.c index 44a12d286..2bfc4231a 100644 --- a/server/shadow/Win/win_wds.c +++ b/server/shadow/Win/win_wds.c @@ -744,7 +744,7 @@ int win_shadow_wds_init(winShadowSubsystem* subsystem) return -1; } - subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation, &bstrConnectionString); + hr = subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation, &bstrConnectionString); if (FAILED(hr)) { @@ -752,10 +752,24 @@ int win_shadow_wds_init(winShadowSubsystem* subsystem) return -1; } + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) bstrConnectionString, + ((UINT32*) bstrConnectionString)[-1], &(file->ConnectionString2), 0, NULL, NULL); + + SysFreeString(bstrConnectionString); + + if (status < 1) + { + WLog_ERR(TAG, "failed to convert connection string"); + return -1; + } + file = subsystem->pAssistanceFile = freerdp_assistance_file_new(); - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) bstrConnectionString, - ((UINT32*) bstrConnectionString)[-1], &(file->ConnectionString2), 0, NULL, NULL); + if (!file) + { + WLog_ERR(TAG, "freerdp_assistance_file_new() failed"); + return -1; + } status = freerdp_assistance_parse_connection_string2(file); diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 9a16662a9..7abb218ec 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -1437,7 +1437,7 @@ void x11_shadow_subsystem_free(x11ShadowSubsystem* subsystem) free(subsystem); } -int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) +FREERDP_API int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints) { pEntryPoints->New = (pfnShadowSubsystemNew) x11_shadow_subsystem_new; pEntryPoints->Free = (pfnShadowSubsystemFree) x11_shadow_subsystem_free; diff --git a/server/shadow/freerdp-shadow.pc.in b/server/shadow/freerdp-shadow.pc.in new file mode 100644 index 000000000..5c8c4629c --- /dev/null +++ b/server/shadow/freerdp-shadow.pc.in @@ -0,0 +1,15 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=${prefix}/@FREERDP_INCLUDE_DIR@ +libs=-lfreerdp-shadow -lfreerdp-shadow-subsystem + +Name: FreeRDP shadow +Description: FreeRDP: A Remote Desktop Protocol Implementation +URL: http://www.freerdp.com/ +Version: @FREERDP_VERSION@ +Requires: +Requires.private: @WINPR_PKG_CONFIG_FILENAME@ freerdp@FREERDP_VERSION_MAJOR@ +Libs: -L${libdir} ${libs} +Libs.private: -ldl -lpthread +Cflags: -I${includedir} diff --git a/server/shadow/shadow.c b/server/shadow/shadow.c index 83a834bc0..bc985192e 100644 --- a/server/shadow/shadow.c +++ b/server/shadow/shadow.c @@ -37,18 +37,6 @@ static BOOL g_MessagePump = FALSE; #include -#ifdef WITH_SHADOW_X11 -extern int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); -#endif - -#ifdef WITH_SHADOW_MAC -extern int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); -#endif - -#ifdef WITH_SHADOW_WIN -extern int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); -#endif - int main(int argc, char** argv) { MSG msg; @@ -56,17 +44,7 @@ int main(int argc, char** argv) DWORD dwExitCode; rdpShadowServer* server; -#ifdef WITH_SHADOW_X11 - shadow_subsystem_set_entry(X11_ShadowSubsystemEntry); -#endif - -#ifdef WITH_SHADOW_MAC - shadow_subsystem_set_entry(Mac_ShadowSubsystemEntry); -#endif - -#ifdef WITH_SHADOW_WIN - shadow_subsystem_set_entry(Win_ShadowSubsystemEntry); -#endif + shadow_subsystem_set_entry_builtin(NULL); server = shadow_server_new(); diff --git a/server/shadow/shadow_subsystem_builtin.c b/server/shadow/shadow_subsystem_builtin.c new file mode 100644 index 000000000..be143d731 --- /dev/null +++ b/server/shadow/shadow_subsystem_builtin.c @@ -0,0 +1,96 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2016 Jiang Zihao + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +struct _RDP_SHADOW_SUBSYSTEM +{ + const char* name; + pfnShadowSubsystemEntry entry; +}; +typedef struct _RDP_SHADOW_SUBSYSTEM RDP_SHADOW_SUBSYSTEM; + +#ifdef WITH_SHADOW_X11 +extern int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); +#endif + +#ifdef WITH_SHADOW_MAC +extern int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); +#endif + +#ifdef WITH_SHADOW_WIN +extern int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints); +#endif + +static RDP_SHADOW_SUBSYSTEM g_Subsystems[] = +{ + +#ifdef WITH_SHADOW_X11 + { "X11", X11_ShadowSubsystemEntry }, +#endif + +#ifdef WITH_SHADOW_MAC + { "Mac", Mac_ShadowSubsystemEntry }, +#endif + +#ifdef WITH_SHADOW_WIN + { "Win", Win_ShadowSubsystemEntry }, +#endif + + { "", NULL } +}; + +static int g_SubsystemCount = (sizeof(g_Subsystems) / sizeof(g_Subsystems[0])); + +static pfnShadowSubsystemEntry shadow_subsystem_load_static_entry(const char* name) +{ + int index; + + if (!name) + { + for (index = 0; index < g_SubsystemCount; index++) + { + if (g_Subsystems[index].name) + return g_Subsystems[index].entry; + } + } + + for (index = 0; index < g_SubsystemCount; index++) + { + if (strcmp(name, g_Subsystems[index].name) == 0) + return g_Subsystems[index].entry; + } + + return NULL; +} + +void shadow_subsystem_set_entry_builtin(const char* name) +{ + pfnShadowSubsystemEntry entry; + + entry = shadow_subsystem_load_static_entry(name); + + if (entry) + shadow_subsystem_set_entry(entry); + + return; +} diff --git a/uwac/CMakeLists.txt b/uwac/CMakeLists.txt new file mode 100644 index 000000000..369ba2ded --- /dev/null +++ b/uwac/CMakeLists.txt @@ -0,0 +1,52 @@ +# UWAC: Using Wayland As Client +# cmake build script +# +# Copyright 2015 David FORT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Soname versioning +set(UWAC_VERSION_MAJOR "0") +set(UWAC_VERSION_MINOR "0") +set(UWAC_VERSION_REVISION "1") +set(UWAC_VERSION "${UWAC_VERSION_MAJOR}.${UWAC_VERSION_MINOR}.${UWAC_VERSION_REVISION}") +set(UWAC_VERSION_FULL "${UWAC_VERSION}") +set(UWAC_API_VERSION "${UWAC_VERSION_MAJOR}") + +add_subdirectory(include) +add_subdirectory(libuwac) + +set(UWAC_INCLUDE_DIR "include/uwac${UWAC_VERSION_MAJOR}") +# cmake package +if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") + + export(PACKAGE uwac) + + set(UWAC_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/uwac${UWAC_VERSION_MAJOR}") + + + configure_package_config_file(uwacConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/uwacConfig.cmake + INSTALL_DESTINATION ${UWAC_CMAKE_INSTALL_DIR} + PATH_VARS UWAC_INCLUDE_DIR) + + write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/uwacConfigVersion.cmake + VERSION ${UWAC_VERSION} COMPATIBILITY SameMajorVersion) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/uwacConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/uwacConfigVersion.cmake + DESTINATION ${UWAC_CMAKE_INSTALL_DIR}) + + install(EXPORT uwac DESTINATION ${UWAC_CMAKE_INSTALL_DIR}) +endif() + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uwac.pc.in ${CMAKE_CURRENT_BINARY_DIR}/uwac${UWAC_VERSION_MAJOR}.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/uwac${UWAC_VERSION_MAJOR}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) diff --git a/uwac/include/CMakeLists.txt b/uwac/include/CMakeLists.txt new file mode 100644 index 000000000..68587284e --- /dev/null +++ b/uwac/include/CMakeLists.txt @@ -0,0 +1,19 @@ +# UWAC: Using Wayland As Client +# cmake build script +# +# Copyright 2015 David FORT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +file(GLOB UWAC_HEADERS "uwac/*.h") +install(FILES ${UWAC_HEADERS} DESTINATION include/uwac${UWAC_API_VERSION}/uwac COMPONENT headers) diff --git a/uwac/include/uwac/uwac-tools.h b/uwac/include/uwac/uwac-tools.h new file mode 100644 index 000000000..07813fbd5 --- /dev/null +++ b/uwac/include/uwac/uwac-tools.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2015 David FORT + * + * 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. + */ + +#ifndef __UWAC_TOOLS_H_ +#define __UWAC_TOOLS_H_ + +#include +#include + +/** @brief */ +struct uwac_touch_point { + uint32_t id; + wl_fixed_t x, y; +}; +typedef struct uwac_touch_point UwacTouchPoint; + +struct uwac_touch_automata; +typedef struct uwac_touch_automata UwacTouchAutomata; + +/** + * + * @param automata + */ +UWAC_API void UwacTouchAutomataInit(UwacTouchAutomata *automata); + +/** + * + * @param automata + */ +UWAC_API void UwacTouchAutomataReset(UwacTouchAutomata *automata); + + +/** + * + * @param automata + * @param event + * @return + */ +UWAC_API bool UwacTouchAutomataInjectEvent(UwacTouchAutomata *automata, UwacEvent *event); + +#endif /* __UWAC_TOOLS_H_ */ diff --git a/uwac/include/uwac/uwac.h b/uwac/include/uwac/uwac.h new file mode 100644 index 000000000..fd422f4b5 --- /dev/null +++ b/uwac/include/uwac/uwac.h @@ -0,0 +1,486 @@ +/* + * Copyright © 2014-2015 David FORT + * + * 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. + */ + +#ifndef __UWAC_H_ +#define __UWAC_H_ + +#include +#include + +#if __GNUC__ >= 4 + #define UWAC_API __attribute__ ((visibility("default"))) +#else + #define UWAC_API +#endif + +typedef struct uwac_size UwacSize; +typedef struct uwac_display UwacDisplay; +typedef struct uwac_output UwacOutput; +typedef struct uwac_window UwacWindow; +typedef struct uwac_seat UwacSeat; + + +/** @brief error codes */ +typedef enum { + UWAC_SUCCESS = 0, + UWAC_ERROR_NOMEMORY, + UWAC_ERROR_UNABLE_TO_CONNECT, + UWAC_ERROR_INVALID_DISPLAY, + UWAC_NOT_ENOUGH_RESOURCES, + UWAC_TIMEDOUT, + UWAC_NOT_FOUND, + UWAC_ERROR_CLOSED, + UWAC_ERROR_INTERNAL, + + UWAC_ERROR_LAST, +} UwacReturnCode; + +/** @brief input modifiers */ +enum { + UWAC_MOD_SHIFT_MASK = 0x01, + UWAC_MOD_ALT_MASK = 0x02, + UWAC_MOD_CONTROL_MASK = 0x04, +}; + +/** @brief a rectangle size measure */ +struct uwac_size { + int width; + int height; +}; + + +/** @brief event types */ +enum { + UWAC_EVENT_NEW_SEAT = 0, + UWAC_EVENT_REMOVED_SEAT, + UWAC_EVENT_NEW_OUTPUT, + UWAC_EVENT_CONFIGURE, + UWAC_EVENT_POINTER_ENTER, + UWAC_EVENT_POINTER_LEAVE, + UWAC_EVENT_POINTER_MOTION, + UWAC_EVENT_POINTER_BUTTONS, + UWAC_EVENT_POINTER_AXIS, + UWAC_EVENT_KEYBOARD_ENTER, + UWAC_EVENT_KEY, + UWAC_EVENT_TOUCH_FRAME_BEGIN, + UWAC_EVENT_TOUCH_UP, + UWAC_EVENT_TOUCH_DOWN, + UWAC_EVENT_TOUCH_MOTION, + UWAC_EVENT_TOUCH_CANCEL, + UWAC_EVENT_TOUCH_FRAME_END, + UWAC_EVENT_FRAME_DONE, + UWAC_EVENT_CLOSE, +}; + +/** @brief window states */ +enum { + UWAC_WINDOW_MAXIMIZED = 0x1, + UWAC_WINDOW_RESIZING = 0x2, + UWAC_WINDOW_FULLSCREEN = 0x4, + UWAC_WINDOW_ACTIVATED = 0x8, +}; + +struct uwac_new_output_event { + int type; + UwacOutput *output; +}; +typedef struct uwac_new_output_event UwacOutputNewEvent; + +struct uwac_new_seat_event { + int type; + UwacSeat *seat; +}; +typedef struct uwac_new_seat_event UwacSeatNewEvent; + +typedef struct uwac_new_seat_event UwacSeatRemovedEvent; + +struct uwac_keyboard_enter_event { + int type; + UwacWindow *window; + UwacSeat *seat; +}; +typedef struct uwac_keyboard_enter_event UwacKeyboardEnterLeaveEvent; + +struct uwac_pointer_enter_event { + int type; + UwacWindow *window; + UwacSeat *seat; + uint32_t x, y; +}; +typedef struct uwac_pointer_enter_event UwacPointerEnterLeaveEvent; + +struct uwac_pointer_motion_event { + int type; + UwacWindow *window; + UwacSeat *seat; + uint32_t x, y; +}; +typedef struct uwac_pointer_motion_event UwacPointerMotionEvent; + +struct uwac_pointer_button_event { + int type; + UwacWindow *window; + UwacSeat *seat; + uint32_t x, y; + uint32_t button; + enum wl_pointer_button_state state; +}; +typedef struct uwac_pointer_button_event UwacPointerButtonEvent; + +struct uwac_pointer_axis_event { + int type; + UwacWindow *window; + UwacSeat *seat; + uint32_t x, y; + uint32_t axis; + wl_fixed_t value; +}; +typedef struct uwac_pointer_axis_event UwacPointerAxisEvent; + +struct uwac_touch_frame_event { + int type; + UwacWindow *window; + UwacSeat *seat; +}; +typedef struct uwac_touch_frame_event UwacTouchFrameBegin; +typedef struct uwac_touch_frame_event UwacTouchFrameEnd; +typedef struct uwac_touch_frame_event UwacTouchCancel; + +struct uwac_touch_data { + int type; + UwacWindow *window; + UwacSeat *seat; + int32_t id; + wl_fixed_t x; + wl_fixed_t y; +}; +typedef struct uwac_touch_data UwacTouchUp; +typedef struct uwac_touch_data UwacTouchDown; +typedef struct uwac_touch_data UwacTouchMotion; + +struct uwac_frame_done_event { + int type; + UwacWindow *window; +}; +typedef struct uwac_frame_done_event UwacFrameDoneEvent; + +struct uwac_configure_event { + int type; + UwacWindow *window; + int32_t width; + int32_t height; + int states; +}; +typedef struct uwac_configure_event UwacConfigureEvent; + +struct uwac_key_event { + int type; + UwacWindow *window; + uint32_t raw_key; + uint32_t sym; + bool pressed; +}; +typedef struct uwac_key_event UwacKeyEvent; + +struct uwac_close_event { + int type; + UwacWindow *window; +}; +typedef struct uwac_close_event UwacCloseEvent; + + +/** @brief */ +union uwac_event { + int type; + UwacOutputNewEvent output_new; + UwacSeatNewEvent seat_new; + UwacPointerEnterLeaveEvent mouse_enter_leave; + UwacPointerMotionEvent mouse_motion; + UwacPointerButtonEvent mouse_button; + UwacPointerAxisEvent mouse_axis; + UwacKeyboardEnterLeaveEvent keyboard_enter_leave; + UwacKeyEvent key; + UwacTouchFrameBegin touchFrameBegin; + UwacTouchUp touchUp; + UwacTouchDown touchDown; + UwacTouchMotion touchMotion; + UwacTouchFrameEnd touchFrameEnd; + UwacTouchCancel touchCancel; + UwacFrameDoneEvent frame_done; + UwacConfigureEvent configure; + UwacCloseEvent close; +}; +typedef union uwac_event UwacEvent; + +typedef bool (*UwacErrorHandler)(UwacDisplay *d, UwacReturnCode code, const char *msg, ...); + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * install a handler that will be called when UWAC encounter internal errors. The + * handler is supposed to answer if the execution can continue. I can also be used + * to log things. + * + * @param handler + */ +UWAC_API void UwacInstallErrorHandler(UwacErrorHandler handler); + + +/** + * Opens the corresponding wayland display, using NULL you will open the default + * display. + * + * @param name the name of the display to open + * @return the created UwacDisplay object + */ +UWAC_API UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err); + +/** + * closes the corresponding UwacDisplay + * + * @param pdisplay a pointer on the display to close + * @return UWAC_SUCCESS if the operation was successful, the corresponding error otherwise + */ +UWAC_API UwacReturnCode UwacCloseDisplay(UwacDisplay **pdisplay); + +/** + * Returns the file descriptor associated with the UwacDisplay, this is useful when + * you want to poll that file descriptor for activity. + * + * @param display an opened UwacDisplay + * @return the corresponding descriptor + */ +UWAC_API int UwacDisplayGetFd(UwacDisplay *display); + +/** + * Returns a human readable form of a Uwac error code + * + * @param error the error number + * @return the associated string + */ +UWAC_API const char *UwacErrorString(UwacReturnCode error); + +/** + * returns the last error that occurred on a display + * + * @param display the display + * @return the last error that have been set for this display + */ +UWAC_API UwacReturnCode UwacDisplayGetLastError(const UwacDisplay *display); + +/** + * retrieves the version of a given interface + * + * @param display the display connection + * @param name the name of the interface + * @param version the output variable for the version + * @return UWAC_SUCCESS if the interface was found, UWAC_NOT_FOUND otherwise + */ +UWAC_API UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay *display, const char *name, uint32_t *version); + +/** + * returns the number SHM formats that have been reported by the compositor + * + * @param display a connected UwacDisplay + * @return the number of SHM formats supported + */ +UWAC_API uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay *display); + +/** + * returns the supported ShmFormats + * + * @param display a connected UwacDisplay + * @param formats a pointer on an array of wl_shm_format with enough place for formats_size items + * @param formats_size the size of the formats array + * @param filled the number of filled entries in the formats array + * @return UWAC_SUCCESS on success, an error otherwise + */ +UWAC_API UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay *display, enum wl_shm_format *formats, int formats_size, int *filled); + +/** + * returns the number of registered outputs + * + * @param display the display to query + * @return the number of outputs + */ +UWAC_API uint32_t UwacDisplayGetNbOutputs(UwacDisplay *display); + +/** + * retrieve a particular UwacOutput object + * + * @param display the display to query + * @param index index of the output + * @return the given UwacOutput, NULL if something failed (so you should query UwacDisplayGetLastError() to have the reason) + */ +UWAC_API UwacOutput *UwacDisplayGetOutput(UwacDisplay *display, int index); + +/** + * retrieve the resolution of a given UwacOutput + * + * @param output the UwacOutput + * @param resolution a pointer on the + * @return UWAC_SUCCESS on success + */ +UWAC_API UwacReturnCode UwacOutputGetResolution(UwacOutput *output, UwacSize *resolution); + + +/** + * creates a window using a SHM surface + * + * @param display the display to attach the window to + * @param width the width of the window + * @param height the heigh of the window + * @param format format to use for the SHM surface + * @return the created UwacWindow, NULL if something failed (use UwacDisplayGetLastError() to know more about this) + */ +UWAC_API UwacWindow *UwacCreateWindowShm(UwacDisplay *display, uint32_t width, uint32_t height, enum wl_shm_format format); + +/** + * destroys the corresponding UwacWindow + * + * @param window a pointer on the UwacWindow to destroy + * @return if the operation completed successfully + */ +UWAC_API UwacReturnCode UwacDestroyWindow(UwacWindow **window); + +/** + * Sets the region that should be considered opaque to the compositor. + * + * @param window the UwacWindow + * @param x + * @param y + * @param width + * @param height + * @return UWAC_SUCCESS on success, an error otherwise + */ +UWAC_API UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + +/** + * Sets the region of the window that can trigger input events + * + * @param window the UwacWindow + * @param x + * @param y + * @param width + * @param height + * @return + */ +UWAC_API UwacReturnCode UwacWindowSetInputRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + +/** + * retrieves a pointer on the current window content to draw a frame + * @param window the UwacWindow + * @return a pointer on the current window content + */ +UWAC_API void *UwacWindowGetDrawingBuffer(UwacWindow *window); + +/** + * sets a rectangle as dirty for the next frame of a window + * + * @param window the UwacWindow + * @param x left coordinate + * @param y top coordinate + * @param width the width of the dirty rectangle + * @param height the height of the dirty rectangle + * @return UWAC_SUCCESS on success, an Uwac error otherwise + */ +UWAC_API UwacReturnCode UwacWindowAddDamage(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + +/** + * Sends a frame to the compositor with the content of the drawing buffer + * + * @param window the UwacWindow to refresh + * @param copyContentForNextFrame if true the content to display is copied in the next drawing buffer + * @return UWAC_SUCCESS if the operation was successful + */ +UWAC_API UwacReturnCode UwacWindowSubmitBuffer(UwacWindow *window, bool copyContentForNextFrame); + +/** + * returns the geometry of the given UwacWindows + * + * @param window the UwacWindow + * @param geometry the geometry to fill + * @return UWAC_SUCCESS on success, an Uwac error otherwise + */ +UWAC_API UwacReturnCode UwacWindowGetGeometry(UwacWindow *window, UwacSize *geometry); + +/** + * Sets or unset the fact that the window is set fullscreen. After this call the + * application should get prepared to receive a configure event. The output is used + * only when going fullscreen, it is optional and not used when exiting fullscreen. + * + * @param window the UwacWindow + * @param output an optional UwacOutput to put the window fullscreen on + * @param isFullscreen set or unset fullscreen + * @return UWAC_SUCCESS if the operation was a success + */ +UWAC_API UwacReturnCode UwacWindowSetFullscreenState(UwacWindow *window, UwacOutput *output, bool isFullscreen); + +/** + * When possible (depending on the shell) sets the title of the UwacWindow + * + * @param window the UwacWindow + * @param name title + */ +UWAC_API void UwacWindowSetTitle(UwacWindow *window, const char *name); + +/** + * + * @param display + * @param timeout + * @return + */ +UWAC_API int UwacDisplayDispatch(UwacDisplay *display, int timeout); + +/** + * Returns if you have some pending events, and you can UwacNextEvent() without blocking + * + * @param display the UwacDisplay + * @return if there's some pending events + */ +UWAC_API bool UwacHasEvent(UwacDisplay *display); + +/** Waits until an event occurs, and when it's there copy the event from the queue to + * event. + * + * @param display the Uwac display + * @param event the event to fill + * @return if the operation completed successfully + */ +UWAC_API UwacReturnCode UwacNextEvent(UwacDisplay *display, UwacEvent *event); + + +/** + * returns the name of the given UwacSeat + * + * @param seat the UwacSeat + * @return the name of the seat + */ +UWAC_API const char *UwacSeatGetName(const UwacSeat *seat); + +#ifdef __cplusplus +} +#endif + +#endif /* __UWAC_H_ */ diff --git a/uwac/libuwac/.gitignore b/uwac/libuwac/.gitignore new file mode 100644 index 000000000..11b3543b4 --- /dev/null +++ b/uwac/libuwac/.gitignore @@ -0,0 +1,7 @@ +fullscreen-shell-client-protocol.h +fullscreen-shell-protocol.c +ivi-application-client-protocol.h +ivi-application-protocol.c +xdg-shell-client-protocol.h +xdg-shell-protocol.c + diff --git a/uwac/libuwac/CMakeLists.txt b/uwac/libuwac/CMakeLists.txt new file mode 100644 index 000000000..4de932519 --- /dev/null +++ b/uwac/libuwac/CMakeLists.txt @@ -0,0 +1,80 @@ +# UWAC: Using Wayland As Client +# +# Copyright 2015 David FORT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(MODULE_NAME "uwac") +set(MODULE_PREFIX "UWAC") + + +set(GENERATED_SOURCES "") +macro(generate_protocol_file PROTO) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROTO}-protocol.c" + COMMAND ${WAYLAND_SCANNER} code < ${CMAKE_SOURCE_DIR}/uwac/protocols/${PROTO}.xml > ${CMAKE_CURRENT_BINARY_DIR}/${PROTO}-protocol.c + DEPENDS ${CMAKE_SOURCE_DIR}/uwac/protocols/${PROTO}.xml + ) + + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROTO}-client-protocol.h" + COMMAND ${WAYLAND_SCANNER} client-header < ${CMAKE_SOURCE_DIR}/uwac/protocols/${PROTO}.xml > ${CMAKE_CURRENT_BINARY_DIR}/${PROTO}-client-protocol.h + DEPENDS ${CMAKE_SOURCE_DIR}/uwac/protocols/${PROTO}.xml + ) + + list(APPEND GENERATED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${PROTO}-client-protocol.h) + list(APPEND GENERATED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${PROTO}-protocol.c) +endmacro() + +generate_protocol_file(xdg-shell) +generate_protocol_file(ivi-application) +generate_protocol_file(fullscreen-shell) + +include_directories(${WAYLAND_INCLUDE_DIR}) +include_directories(${XKBCOMMON_INCLUDE_DIR}) +include_directories("${CMAKE_SOURCE_DIR}/uwac/include") +include_directories("${CMAKE_BINARY_DIR}/uwac/include") +include_directories("${CMAKE_BINARY_DIR}/uwac/libuwac") + +add_definitions(-DBUILD_IVI -DBUILD_FULLSCREEN_SHELL -DENABLE_XKBCOMMON) + +set(${MODULE_PREFIX}_SRCS + ${GENERATED_SOURCES} + uwac-display.c + uwac-input.c + uwac-os.c + uwac-os.h + uwac-output.c + uwac-priv.h + uwac-tools.c + uwac-utils.c + uwac-window.c) + + +add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + + +if (WITH_LIBRARY_VERSIONING) + set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${UWAC_VERSION} SOVERSION ${UWAC_API_VERSION}) +endif() + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} ${WAYLAND_LIBS} ${XKBCOMMON_LIBS} freerdp) + +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT uwac) + + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "uwac") + +if(BUILD_TESTING) +# add_subdirectory(test) +endif() diff --git a/uwac/libuwac/uwac-display.c b/uwac/libuwac/uwac-display.c new file mode 100644 index 000000000..2fa20b490 --- /dev/null +++ b/uwac/libuwac/uwac-display.c @@ -0,0 +1,631 @@ +/* + * Copyright © 2014 David FORT + * + * 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 "uwac-priv.h" +#include "uwac-utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uwac-os.h" + +#define TARGET_COMPOSITOR_INTERFACE 3 +#define TARGET_SHM_INTERFACE 1 +#define TARGET_SHELL_INTERFACE 1 +#define TARGET_DDM_INTERFACE 1 +#define TARGET_SEAT_INTERFACE 5 +#define TARGET_XDG_VERSION 5 /* The version of xdg-shell that we implement */ + +static const char *event_names[] = { + "new seat", + "removed seat", + "new output", + "configure", + "pointer enter", + "pointer leave", + "pointer motion", + "pointer buttons", + "pointer axis", + "keyboard enter", + "key", + "touch frame begin", + "touch up", + "touch down", + "touch motion", + "touch cancel", + "touch frame end", + "frame done", + "close", + NULL +}; + +bool uwac_default_error_handler(UwacDisplay *display, UwacReturnCode code, const char *msg, ...) { + va_list args; + va_start(args, msg); + + vfprintf(stderr, "%s", args); + return false; +} + +UwacErrorHandler uwacErrorHandler = uwac_default_error_handler; + +void UwacInstallErrorHandler(UwacErrorHandler handler) { + if (handler) + uwacErrorHandler = handler; + else + uwacErrorHandler = uwac_default_error_handler; +} + + +static void cb_shm_format(void *data, struct wl_shm *wl_shm, uint32_t format) +{ + UwacDisplay *d = data; + + if (format == WL_SHM_FORMAT_RGB565) + d->has_rgb565 = true; + + d->shm_formats_nb++; + d->shm_formats = xrealloc((void *)d->shm_formats, sizeof(enum wl_shm_format) * d->shm_formats_nb); + d->shm_formats[d->shm_formats_nb - 1] = format; +} + + +struct wl_shm_listener shm_listener = { + cb_shm_format +}; + +static void xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial) +{ + xdg_shell_pong(shell, serial); +} + +static const struct xdg_shell_listener xdg_shell_listener = { + xdg_shell_ping, +}; + +#ifdef BUILD_FULLSCREEN_SHELL +static void fullscreen_capability(void *data, struct _wl_fullscreen_shell *_wl_fullscreen_shell, + uint32_t capabilty) +{ +} + +static const struct _wl_fullscreen_shell_listener fullscreen_shell_listener = { + fullscreen_capability, +}; +#endif + + +static UwacSeat *display_destroy_seat(UwacDisplay *d, uint32_t name) +{ + UwacSeat *seat; + + wl_list_for_each(seat, &d->seats, link) { + if (seat->seat_id == name) { + UwacSeatDestroy(seat); + return seat; + } + } + + return NULL; +} + +static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t id, + const char *interface, uint32_t version) +{ + UwacDisplay *d = data; + UwacGlobal *global; + + global = xmalloc(sizeof *global); + global->name = id; + global->interface = xstrdup(interface); + global->version = version; + wl_list_insert(d->globals.prev, &global->link); + + if (strcmp(interface, "wl_compositor") == 0) { + d->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, min(TARGET_COMPOSITOR_INTERFACE, version)); + } else if (strcmp(interface, "wl_shm") == 0) { + d->shm = wl_registry_bind(registry, id, &wl_shm_interface, min(TARGET_SHM_INTERFACE, version)); + wl_shm_add_listener(d->shm, &shm_listener, d); + } else if (strcmp(interface, "wl_output") == 0) { + UwacOutput *output; + UwacOutputNewEvent *ev; + + output = UwacCreateOutput(d, id, version); + if (!output) { + assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create output\n")); + return; + } + + ev = (UwacOutputNewEvent *)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_OUTPUT); + if (ev) + ev->output = output; + + } else if (strcmp(interface, "wl_seat") == 0) { + UwacSeatNewEvent *ev; + UwacSeat *seat; + + seat = UwacSeatNew(d, id, min(version, TARGET_SEAT_INTERFACE)); + if (!seat) { + assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat\n")); + return; + } + + ev = (UwacSeatNewEvent *)UwacDisplayNewEvent(d, UWAC_EVENT_NEW_SEAT); + if (!ev) { + assert(uwacErrorHandler(d, UWAC_ERROR_NOMEMORY, "unable to create new seat event\n")); + return; + } + + ev->seat = seat; + } else if (strcmp(interface, "wl_data_device_manager") == 0) { + d->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, min(TARGET_DDM_INTERFACE, version)); + } else if (strcmp(interface, "wl_shell") == 0) { + d->shell = wl_registry_bind(registry, id, &wl_shell_interface, min(TARGET_SHELL_INTERFACE, version)); + } else if (strcmp(interface, "xdg_shell") == 0) { + d->xdg_shell = wl_registry_bind(registry, id, &xdg_shell_interface, 1); + xdg_shell_use_unstable_version(d->xdg_shell, TARGET_XDG_VERSION); + xdg_shell_add_listener(d->xdg_shell, &xdg_shell_listener, d); +#if BUILD_IVI + } else if (strcmp(interface, "ivi_application") == 0) { + d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1); +#endif +#if BUILD_FULLSCREEN_SHELL + } else if (strcmp(interface, "_wl_fullscreen_shell") == 0) { + d->fullscreen_shell = wl_registry_bind(registry, id, &_wl_fullscreen_shell_interface, 1); + _wl_fullscreen_shell_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d); +#endif +#if 0 + } else if (strcmp(interface, "text_cursor_position") == 0) { + d->text_cursor_position = wl_registry_bind(registry, id, &text_cursor_position_interface, 1); + } else if (strcmp(interface, "workspace_manager") == 0) { + //init_workspace_manager(d, id); + } else if (strcmp(interface, "wl_subcompositor") == 0) { + d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); +#endif + } +} + +static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { + UwacDisplay *d = data; + UwacGlobal *global; + UwacGlobal *tmp; + + wl_list_for_each_safe(global, tmp, &d->globals, link) { + if (global->name != name) + continue; + +#if 0 + if (strcmp(global->interface, "wl_output") == 0) + display_destroy_output(d, name); +#endif + + if (strcmp(global->interface, "wl_seat") == 0) { + UwacSeatRemovedEvent *ev; + UwacSeat *seat; + + seat = display_destroy_seat(d, name); + ev = (UwacSeatRemovedEvent *)UwacDisplayNewEvent(d, UWAC_EVENT_REMOVED_SEAT); + if (ev) + ev->seat = seat; + } + + + wl_list_remove(&global->link); + free(global->interface); + free(global); + } +} + +void UwacDestroyGlobal(UwacGlobal *global) { + free(global->interface); + wl_list_remove(&global->link); + free(global); +} + +void *display_bind(UwacDisplay *display, uint32_t name, const struct wl_interface *interface, uint32_t version) { + return wl_registry_bind(display->registry, name, interface, version); +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + + +int UwacDisplayWatchFd(UwacDisplay *display, int fd, uint32_t events, UwacTask *task) { + struct epoll_event ep; + + ep.events = events; + ep.data.ptr = task; + return epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep); +} + +void UwacDisplayUnwatchFd(UwacDisplay *display, int fd) { + epoll_ctl(display->epoll_fd, EPOLL_CTL_DEL, fd, NULL); +} + +static void display_exit(UwacDisplay *display) { + display->running = false; +} + +static void display_dispatch_events(UwacTask *task, uint32_t events) +{ + UwacDisplay *display = container_of(task, UwacDisplay, dispatch_fd_task); + struct epoll_event ep; + int ret; + + display->display_fd_events = events; + + if ((events & EPOLLERR) || (events & EPOLLHUP)) { + display_exit(display); + return; + } + + if (events & EPOLLIN) { + ret = wl_display_dispatch(display->display); + if (ret == -1) { + display_exit(display); + return; + } + } + + if (events & EPOLLOUT) { + ret = wl_display_flush(display->display); + if (ret == 0) { + ep.events = EPOLLIN | EPOLLERR | EPOLLHUP; + ep.data.ptr = &display->dispatch_fd_task; + epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep); + } else if (ret == -1 && errno != EAGAIN) { + display_exit(display); + return; + } + } +} + + +UwacDisplay *UwacOpenDisplay(const char *name, UwacReturnCode *err) { + UwacDisplay *ret; + + ret = (UwacDisplay *)calloc(1, sizeof(*ret)); + if (!ret) { + *err = UWAC_ERROR_NOMEMORY; + return NULL; + } + + wl_list_init(&ret->globals); + wl_list_init(&ret->seats); + wl_list_init(&ret->outputs); + wl_list_init(&ret->windows); + + ret->display = wl_display_connect(name); + if (ret->display == NULL) { + fprintf(stderr, "failed to connect to Wayland display %s: %m\n", name); + *err = UWAC_ERROR_UNABLE_TO_CONNECT; + goto out_free; + } + + ret->epoll_fd = uwac_os_epoll_create_cloexec(); + if (ret->epoll_fd < 0) { + *err = UWAC_NOT_ENOUGH_RESOURCES; + goto out_disconnect; + } + + ret->display_fd = wl_display_get_fd(ret->display); + + ret->registry = wl_display_get_registry(ret->display); + if (!ret->registry) { + *err = UWAC_ERROR_NOMEMORY; + goto out_close_epoll; + } + + wl_registry_add_listener(ret->registry, ®istry_listener, ret); + + if ((wl_display_roundtrip(ret->display) < 0) || (wl_display_roundtrip(ret->display) < 0)) { + uwacErrorHandler(ret, UWAC_ERROR_UNABLE_TO_CONNECT, "Failed to process Wayland connection: %m\n"); + *err = UWAC_ERROR_UNABLE_TO_CONNECT; + goto out_free_registry; + } + + ret->dispatch_fd_task.run = display_dispatch_events; + if (UwacDisplayWatchFd(ret, ret->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP, &ret->dispatch_fd_task) < 0) { + uwacErrorHandler(ret, UWAC_ERROR_INTERNAL, "unable to watch display fd: %m\n"); + *err = UWAC_ERROR_INTERNAL; + goto out_free_registry; + } + + ret->running = true; + ret->last_error = *err = UWAC_SUCCESS; + return ret; + +out_free_registry: + wl_registry_destroy(ret->registry); +out_close_epoll: + close(ret->epoll_fd); +out_disconnect: + wl_display_disconnect(ret->display); +out_free: + free(ret); + return NULL; +} + +int UwacDisplayDispatch(UwacDisplay *display, int timeout) { + int ret, count, i; + UwacTask *task; + struct epoll_event ep[16]; + + wl_display_dispatch_pending(display->display); + + if (!display->running) + return 0; + + ret = wl_display_flush(display->display); + if (ret < 0 && errno == EAGAIN) { + ep[0].events = (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP); + ep[0].data.ptr = &display->dispatch_fd_task; + + epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, display->display_fd, &ep[0]); + } else if (ret < 0) { + return -1; + } + + count = epoll_wait(display->epoll_fd, ep, ARRAY_LENGTH(ep), timeout); + for (i = 0; i < count; i++) { + task = ep[i].data.ptr; + task->run(task, ep[i].events); + } + + return 1; +} + + + +UwacReturnCode UwacDisplayGetLastError(const UwacDisplay *display) { + return display->last_error; +} + +UwacReturnCode UwacCloseDisplay(UwacDisplay **pdisplay) { + UwacDisplay *display; + UwacSeat *seat, *tmpSeat; + UwacWindow *window, *tmpWindow; + UwacOutput *output, *tmpOutput; + UwacGlobal *global, *tmpGlobal; + + assert(pdisplay); + display = *pdisplay; + if (!display) + return UWAC_ERROR_INVALID_DISPLAY; + + /* destroy windows */ + wl_list_for_each_safe(window, tmpWindow, &display->windows, link) { + UwacDestroyWindow(&window); + } + + /* destroy seats */ + wl_list_for_each_safe(seat, tmpSeat, &display->seats, link) { + UwacSeatDestroy(seat); + } + + /* destroy output */ + wl_list_for_each_safe(output, tmpOutput, &display->outputs, link) { + UwacDestroyOutput(output); + } + + /* destroy globals */ + wl_list_for_each_safe(global, tmpGlobal, &display->globals, link) { + UwacDestroyGlobal(global); + } + + if (display->compositor) + wl_compositor_destroy(display->compositor); +#ifdef BUILD_FULLSCREEN_SHELL + if (display->fullscreen_shell) + _wl_fullscreen_shell_destroy(display->fullscreen_shell); +#endif +#ifdef BUILD_IVI + if (display->ivi_application) + ivi_application_destroy(display->ivi_application); +#endif + if (display->xdg_shell) + xdg_shell_destroy(display->xdg_shell); + if (display->shell) + wl_shell_destroy(display->shell); + if (display->shm) + wl_shm_destroy(display->shm); + if (display->subcompositor) + wl_subcompositor_destroy(display->subcompositor); + if (display->data_device_manager) + wl_data_device_manager_destroy(display->data_device_manager); + + free(display->shm_formats); + wl_registry_destroy(display->registry); + + close(display->epoll_fd); + + wl_display_disconnect(display->display); + + /* cleanup the event queue */ + while (display->push_queue) { + UwacEventListItem *item = display->push_queue; + + display->push_queue = item->tail; + free(item); + } + + free(display); + *pdisplay = NULL; + return UWAC_SUCCESS; +} + +int UwacDisplayGetFd(UwacDisplay *display) { + return display->epoll_fd; +} + +static const char *errorStrings[] = { + "success", + "out of memory error", + "unable to connect to wayland display", + "invalid UWAC display", + "not enough resources", + "timed out", + "not found", + "closed connection", + + "internal error", +}; + +const char *UwacErrorString(UwacReturnCode error) { + if (error < 0 || error >= UWAC_ERROR_LAST) + return "invalid error code"; + + return errorStrings[error]; +} + +UwacReturnCode UwacDisplayQueryInterfaceVersion(const UwacDisplay *display, const char *name, uint32_t *version) { + const UwacGlobal *global; + + if (!display) + return UWAC_ERROR_INVALID_DISPLAY; + + wl_list_for_each(global, &display->globals, link) { + if (strcmp(global->interface, name) == 0) { + if (version) + *version = global->version; + return UWAC_SUCCESS; + } + } + + return UWAC_NOT_FOUND; +} + +uint32_t UwacDisplayQueryGetNbShmFormats(UwacDisplay *display) { + if (!display) { + display->last_error = UWAC_ERROR_INVALID_DISPLAY; + return 0; + } + + if (!display->shm) { + display->last_error = UWAC_NOT_FOUND; + return 0; + } + + display->last_error = UWAC_SUCCESS; + return display->shm_formats_nb; +} + + +UwacReturnCode UwacDisplayQueryShmFormats(const UwacDisplay *display, enum wl_shm_format *formats, int formats_size, int *filled) { + if (!display) + return UWAC_ERROR_INVALID_DISPLAY; + + *filled = min(display->shm_formats_nb, formats_size); + memcpy(formats, (const void *)display->shm_formats, *filled * sizeof(enum wl_shm_format)); + + return UWAC_SUCCESS; +} + +uint32_t UwacDisplayGetNbOutputs(UwacDisplay *display) { + return wl_list_length(&display->outputs); +} + +UwacOutput *UwacDisplayGetOutput(UwacDisplay *display, int index) { + struct wl_list *l; + int i; + + for (i = 0, l = &display->outputs; l && i < index; i++, l = l->next) + ; + + if (!l) { + display->last_error = UWAC_NOT_FOUND; + return NULL; + } + + display->last_error = UWAC_SUCCESS; + return container_of(l, UwacOutput, link); +} + +UwacReturnCode UwacOutputGetResolution(UwacOutput *output, UwacSize *resolution) { + *resolution = output->resolution; + return UWAC_SUCCESS; +} + + +UwacEvent *UwacDisplayNewEvent(UwacDisplay *display, int type) { + UwacEventListItem *ret; + + if (!display) { + display->last_error = UWAC_ERROR_INVALID_DISPLAY; + return 0; + } + + ret = zalloc(sizeof(UwacEventListItem)); + if (!ret) { + assert(uwacErrorHandler(display, UWAC_ERROR_NOMEMORY, "unable to allocate a '%s' event", event_names[type])); + display->last_error = UWAC_ERROR_NOMEMORY; + return 0; + } + + ret->event.type = type; + ret->tail = display->push_queue; + if (ret->tail) + ret->tail->head = ret; + else + display->pop_queue = ret; + display->push_queue = ret; + return &ret->event; +} + +bool UwacHasEvent(UwacDisplay *display) { + return display->pop_queue != NULL; +} + + +UwacReturnCode UwacNextEvent(UwacDisplay *display, UwacEvent *event) { + UwacEventListItem *prevItem; + int ret; + + if (!display) + return UWAC_ERROR_INVALID_DISPLAY; + + while (!display->pop_queue) { + ret = UwacDisplayDispatch(display, 1 * 1000); + if (ret < 0) + return UWAC_ERROR_INTERNAL; + else if (ret == 0) + return UWAC_ERROR_CLOSED; + } + + prevItem = display->pop_queue->head; + *event = display->pop_queue->event; + free(display->pop_queue); + display->pop_queue = prevItem; + if (prevItem) + prevItem->tail = NULL; + else + display->push_queue = NULL; + return UWAC_SUCCESS; +} diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c new file mode 100644 index 000000000..76e2f5ec4 --- /dev/null +++ b/uwac/libuwac/uwac-input.c @@ -0,0 +1,847 @@ +/* + * Copyright © 2014-2015 David FORT + * + * 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 "uwac-priv.h" +#include "uwac-utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static void keyboard_repeat_func(UwacTask *task, uint32_t events) +{ + UwacSeat *input = container_of(task, UwacSeat, repeat_task); + UwacWindow *window = input->keyboard_focus; + uint64_t exp; + + if (read(input->repeat_timer_fd, &exp, sizeof exp) != sizeof exp) + /* If we change the timer between the fd becoming + * readable and getting here, there'll be nothing to + * read and we get EAGAIN. */ + return; + + if (window) { + UwacKeyEvent *key; + + key = (UwacKeyEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_KEY); + if (!key) + return; + + key->window = window; + key->sym = input->repeat_sym; + key->pressed = true; + } + +} + +static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, + uint32_t format, int fd, uint32_t size) +{ + UwacSeat *input = data; + struct xkb_keymap *keymap; + struct xkb_state *state; + char *map_str; + + if (!data) { + close(fd); + return; + } + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + close(fd); + return; + } + + keymap = xkb_keymap_new_from_string(input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(map_str, size); + close(fd); + + if (!keymap) { + assert(uwacErrorHandler(input->display, UWAC_ERROR_INTERNAL, "failed to compile keymap\n")); + return; + } + + state = xkb_state_new(keymap); + if (!state) { + assert(uwacErrorHandler(input->display, UWAC_ERROR_NOMEMORY, "failed to create XKB state\n")); + xkb_keymap_unref(keymap); + return; + } + + xkb_keymap_unref(input->xkb.keymap); + xkb_state_unref(input->xkb.state); + input->xkb.keymap = keymap; + input->xkb.state = state; + + input->xkb.control_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Control"); + input->xkb.alt_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Mod1"); + input->xkb.shift_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Shift"); +} + +static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t time, uint32_t key, + uint32_t state_w); + +static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface, struct wl_array *keys) +{ + uint32_t *key, *pressedKey; + UwacSeat *input = (UwacSeat *)data; + int i, found; + UwacKeyboardEnterLeaveEvent *event; + + event = (UwacKeyboardEnterLeaveEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_KEYBOARD_ENTER); + if (!event) + return; + + event->window = input->keyboard_focus = (UwacWindow *)wl_surface_get_user_data(surface); + + /* look for keys that have been released */ + found = false; + for (pressedKey = input->pressed_keys.data, i = 0; i < input->pressed_keys.size; i += sizeof(uint32_t)) { + wl_array_for_each(key, keys) { + if (*key == *pressedKey) { + found = true; + break; + } + } + + if (!found) { + keyboard_handle_key(data, keyboard, serial, 0, *pressedKey, WL_KEYBOARD_KEY_STATE_RELEASED); + } else { + pressedKey++; + } + } + + /* handle keys that are now pressed */ + wl_array_for_each(key, keys) { + keyboard_handle_key(data, keyboard, serial, 0, *key, WL_KEYBOARD_KEY_STATE_PRESSED); + } +} + +static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface) +{ + struct itimerspec its; + UwacSeat *input; + UwacPointerEnterLeaveEvent *event; + + input = (UwacSeat *)data; + + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 0; + timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); + + event = (UwacPointerEnterLeaveEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_POINTER_LEAVE); + if (!event) + return; + + event->window = input->keyboard_focus; +} + +static int update_key_pressed(UwacSeat *seat, uint32_t key) { + uint32_t *keyPtr; + + /* check if the key is not already pressed */ + wl_array_for_each(keyPtr, &seat->pressed_keys) { + if (*keyPtr == key) + return 1; + } + + keyPtr = wl_array_add(&seat->pressed_keys, sizeof(uint32_t)); + if (!keyPtr) + return -1; + + *keyPtr = key; + return 0; +} + +static int update_key_released(UwacSeat *seat, uint32_t key) { + uint32_t *keyPtr; + int i, toMove; + bool found = false; + + for (i = 0, keyPtr = seat->pressed_keys.data; i < seat->pressed_keys.size; i++, keyPtr++) { + if (*keyPtr == key) { + found = true; + break; + } + } + + if (found) { + toMove = seat->pressed_keys.size - ((i + 1) * sizeof(uint32_t)); + if (toMove) + memmove(keyPtr, keyPtr+1, toMove); + + seat->pressed_keys.size -= sizeof(uint32_t); + } + return 1; + +} + +static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t time, uint32_t key, + uint32_t state_w) +{ + UwacSeat *input = (UwacSeat *)data; + UwacWindow *window = input->keyboard_focus; + UwacKeyEvent *keyEvent; + + uint32_t code, num_syms; + enum wl_keyboard_key_state state = state_w; + const xkb_keysym_t *syms; + xkb_keysym_t sym; + struct itimerspec its; + + if (state_w == WL_KEYBOARD_KEY_STATE_PRESSED) + update_key_pressed(input, key); + else + update_key_released(input, key); + + input->display->serial = serial; + code = key + 8; + if (!window || !input->xkb.state) + return; + + /* We only use input grabs for pointer events for now, so just + * ignore key presses if a grab is active. We expand the key + * event delivery mechanism to route events to widgets to + * properly handle key grabs. In the meantime, this prevents + * key event delivery while a grab is active. */ + /*if (input->grab && input->grab_button == 0) + return;*/ + + num_syms = xkb_state_key_get_syms(input->xkb.state, code, &syms); + + sym = XKB_KEY_NoSymbol; + if (num_syms == 1) + sym = syms[0]; + + if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == input->repeat_key) { + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 0; + timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); + } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(input->xkb.keymap, code)) { + input->repeat_sym = sym; + input->repeat_key = key; + input->repeat_time = time; + its.it_interval.tv_sec = input->repeat_rate_sec; + its.it_interval.tv_nsec = input->repeat_rate_nsec; + its.it_value.tv_sec = input->repeat_delay_sec; + its.it_value.tv_nsec = input->repeat_delay_nsec; + timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); + } + + keyEvent = (UwacKeyEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_KEY); + if (!keyEvent) + return; + + keyEvent->window = window; + keyEvent->sym = sym; + keyEvent->raw_key = key; + keyEvent->pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); +} + +static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + UwacSeat *input = data; + xkb_mod_mask_t mask; + + /* If we're not using a keymap, then we don't handle PC-style modifiers */ + if (!input->xkb.keymap) + return; + + xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); + mask = xkb_state_serialize_mods(input->xkb.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); + input->modifiers = 0; + if (mask & input->xkb.control_mask) + input->modifiers |= UWAC_MOD_CONTROL_MASK; + if (mask & input->xkb.alt_mask) + input->modifiers |= UWAC_MOD_ALT_MASK; + if (mask & input->xkb.shift_mask) + input->modifiers |= UWAC_MOD_SHIFT_MASK; +} + +static void set_repeat_info(UwacSeat *input, int32_t rate, int32_t delay) +{ + input->repeat_rate_sec = input->repeat_rate_nsec = 0; + input->repeat_delay_sec = input->repeat_delay_nsec = 0; + + /* a rate of zero disables any repeating, regardless of the delay's + * value */ + if (rate == 0) + return; + + if (rate == 1) + input->repeat_rate_sec = 1; + else + input->repeat_rate_nsec = 1000000000 / rate; + + input->repeat_delay_sec = delay / 1000; + delay -= (input->repeat_delay_sec * 1000); + input->repeat_delay_nsec = delay * 1000 * 1000; +} + + +static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + UwacSeat *input = data; + + set_repeat_info(input, rate, delay); +} + +static const struct wl_keyboard_listener keyboard_listener = { + keyboard_handle_keymap, + keyboard_handle_enter, + keyboard_handle_leave, + keyboard_handle_key, + keyboard_handle_modifiers, + keyboard_handle_repeat_info +}; + +static bool touch_send_start_frame(UwacSeat *seat) { + UwacTouchFrameBegin *ev; + + ev = (UwacTouchFrameBegin *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_TOUCH_FRAME_BEGIN); + if (!ev) + return false; + + seat->touch_frame_started = true; + return true; +} + +static void touch_handle_down(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, struct wl_surface *surface, + int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) +{ + UwacSeat *seat = data; + UwacTouchDown *tdata; + + seat->display->serial = serial; + if (!seat->touch_frame_started && !touch_send_start_frame(seat)) + return; + + tdata = (UwacTouchDown *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_TOUCH_DOWN); + if (!tdata) + return; + + tdata->seat = seat; + tdata->id = id; + tdata->x = x_w; + tdata->y = y_w; + +#if 0 + struct widget *widget; + float sx = wl_fixed_to_double(x); + float sy = wl_fixed_to_double(y); + + + input->touch_focus = wl_surface_get_user_data(surface); + if (!input->touch_focus) { + DBG("Failed to find to touch focus for surface %p\n", surface); + return; + } + + if (surface != input->touch_focus->main_surface->surface) { + DBG("Ignoring input event from subsurface %p\n", surface); + input->touch_focus = NULL; + return; + } + + if (input->grab) + widget = input->grab; + else + widget = window_find_widget(input->touch_focus, + wl_fixed_to_double(x), + wl_fixed_to_double(y)); + if (widget) { + struct touch_point *tp = xmalloc(sizeof *tp); + if (tp) { + tp->id = id; + tp->widget = widget; + tp->x = sx; + tp->y = sy; + wl_list_insert(&input->touch_point_list, &tp->link); + + if (widget->touch_down_handler) + (*widget->touch_down_handler)(widget, input, + serial, time, id, + sx, sy, + widget->user_data); + } + } +#endif +} + +static void touch_handle_up(void *data, struct wl_touch *wl_touch, + uint32_t serial, uint32_t time, int32_t id) +{ + UwacSeat *seat = data; + UwacTouchUp *tdata; + + if (!seat->touch_frame_started && !touch_send_start_frame(seat)) + return; + + tdata = (UwacTouchUp *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_TOUCH_UP); + if (!tdata) + return; + + tdata->seat = seat; + tdata->id = id; + + +#if 0 + struct touch_point *tp, *tmp; + + if (!input->touch_focus) { + DBG("No touch focus found for touch up event!\n"); + return; + } + + wl_list_for_each_safe(tp, tmp, &input->touch_point_list, link) { + if (tp->id != id) + continue; + + if (tp->widget->touch_up_handler) + (*tp->widget->touch_up_handler)(tp->widget, input, serial, + time, id, + tp->widget->user_data); + + wl_list_remove(&tp->link); + free(tp); + + return; + } +#endif +} + +static void touch_handle_motion(void *data, struct wl_touch *wl_touch, + uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) +{ + UwacSeat *seat = data; + UwacTouchMotion *tdata; + + if (!seat->touch_frame_started && !touch_send_start_frame(seat)) + return; + + tdata = (UwacTouchMotion *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_TOUCH_MOTION); + if (!tdata) + return; + + tdata->seat = seat; + tdata->id = id; + tdata->x = x_w; + tdata->y = y_w; + +#if 0 + struct touch_point *tp; + float sx = wl_fixed_to_double(x); + float sy = wl_fixed_to_double(y); + + DBG("touch_handle_motion: %i %i\n", id, wl_list_length(&seat->touch_point_list)); + + if (!seat->touch_focus) { + DBG("No touch focus found for touch motion event!\n"); + return; + } + + wl_list_for_each(tp, &seat->touch_point_list, link) { + if (tp->id != id) + continue; + + tp->x = sx; + tp->y = sy; + if (tp->widget->touch_motion_handler) + (*tp->widget->touch_motion_handler)(tp->widget, seat, time, + id, sx, sy, + tp->widget->user_data); + return; + } +#endif +} + +static void touch_handle_frame(void *data, struct wl_touch *wl_touch) +{ + UwacSeat *seat = data; + UwacTouchFrameEnd *ev; + + ev = (UwacTouchFrameEnd *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_TOUCH_FRAME_END); + if (!ev) + return; + + ev->seat = seat; + seat->touch_frame_started = false; +} + +static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) +{ + UwacSeat *seat = data; + UwacTouchCancel *ev; + + ev = (UwacTouchCancel *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_TOUCH_CANCEL); + if (!ev) + return; + + ev->seat = seat; + seat->touch_frame_started = false; + +#if 0 + struct touch_point *tp, *tmp; + + DBG("touch_handle_cancel\n"); + + if (!input->touch_focus) { + DBG("No touch focus found for touch cancel event!\n"); + return; + } + + wl_list_for_each_safe(tp, tmp, &input->touch_point_list, link) { + if (tp->widget->touch_cancel_handler) + (*tp->widget->touch_cancel_handler)(tp->widget, input, + tp->widget->user_data); + + wl_list_remove(&tp->link); + free(tp); + } +#endif +} + +static const struct wl_touch_listener touch_listener = { + touch_handle_down, + touch_handle_up, + touch_handle_motion, + touch_handle_frame, + touch_handle_cancel, +}; + + +static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface, wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + UwacSeat *input = data; + UwacWindow *window; + UwacPointerEnterLeaveEvent *event; + + float sx = wl_fixed_to_double(sx_w); + float sy = wl_fixed_to_double(sy_w); + + if (!surface) { + /* enter event for a window we've just destroyed */ + return; + } + + input->display->serial = serial; + window = wl_surface_get_user_data(surface); + if (window) + window->pointer_enter_serial = serial; + input->pointer_focus = window; + input->sx = sx; + input->sy = sy; + + event = (UwacPointerEnterLeaveEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_POINTER_ENTER); + if (!event) + return; + + event->seat = input; + event->window = window; + event->x = sx; + event->y = sy; +} + +static void pointer_handle_leave(void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface) +{ + UwacPointerEnterLeaveEvent *event; + UwacWindow *window; + UwacSeat *input = data; + + input->display->serial = serial; + + event = (UwacPointerEnterLeaveEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_POINTER_LEAVE); + if (!event) + return; + + window = wl_surface_get_user_data(surface); + + event->seat = input; + event->window = window; + +#if 0 + input_remove_pointer_focus(input); +#endif +} + +static void pointer_handle_motion(void *data, struct wl_pointer *pointer, uint32_t time, + wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + UwacPointerMotionEvent *motion_event; + UwacSeat *input = data; + UwacWindow *window = input->pointer_focus; + + float sx = wl_fixed_to_double(sx_w); + float sy = wl_fixed_to_double(sy_w); + + if (!window) + return; + + input->sx = sx; + input->sy = sy; + + motion_event = (UwacPointerMotionEvent *)UwacDisplayNewEvent(input->display, UWAC_EVENT_POINTER_MOTION); + if (!motion_event) + return; + + motion_event->seat = input; + motion_event->window = window; + motion_event->x = wl_fixed_to_int(sx_w); + motion_event->y = wl_fixed_to_int(sy_w); +} + +static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state_w) +{ + UwacPointerButtonEvent *event; + UwacSeat *seat = data; + UwacWindow *window = seat->pointer_focus; + + seat->display->serial = serial; + + event = (UwacPointerButtonEvent *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_POINTER_BUTTONS); + if (!event) + return; + + event->seat = seat; + event->window = window; + event->x = seat->sx; + event->y = seat->sy; + event->button = button; + event->state = (enum wl_pointer_button_state)state_w; +} + +static void pointer_handle_axis(void *data, struct wl_pointer *pointer, uint32_t time, + uint32_t axis, wl_fixed_t value) +{ + UwacPointerAxisEvent *event; + UwacSeat *seat = data; + UwacWindow *window = seat->pointer_focus; + + if (!window) + return; + + event = (UwacPointerAxisEvent *)UwacDisplayNewEvent(seat->display, UWAC_EVENT_POINTER_AXIS); + if (!event) + return; + + event->seat = seat; + event->window = window; + event->x = seat->sx; + event->y = seat->sy; + event->axis = axis; + event->value = value; +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, +}; + + + +static void seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) +{ + UwacSeat *input = data; + + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { + input->pointer = wl_seat_get_pointer(seat); + wl_pointer_set_user_data(input->pointer, input); + wl_pointer_add_listener(input->pointer, &pointer_listener, input); + } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { +#ifdef WL_POINTER_RELEASE_SINCE_VERSION + if (input->seat_version >= WL_POINTER_RELEASE_SINCE_VERSION) + wl_pointer_release(input->pointer); + else +#endif + wl_pointer_destroy(input->pointer); + input->pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) { + input->keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_set_user_data(input->keyboard, input); + wl_keyboard_add_listener(input->keyboard, &keyboard_listener, input); + } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) { +#ifdef WL_KEYBOARD_RELEASE_SINCE_VERSION + if (input->seat_version >= WL_KEYBOARD_RELEASE_SINCE_VERSION) + wl_keyboard_release(input->keyboard); + else +#endif + wl_keyboard_destroy(input->keyboard); + input->keyboard = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { + input->touch = wl_seat_get_touch(seat); + wl_touch_set_user_data(input->touch, input); + wl_touch_add_listener(input->touch, &touch_listener, input); + } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) { +#ifdef WL_TOUCH_RELEASE_SINCE_VERSION + if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION) + wl_touch_release(input->touch); + else +#endif + wl_touch_destroy(input->touch); + input->touch = NULL; + } +} + +static void +seat_handle_name(void *data, struct wl_seat *seat, const char *name) +{ + UwacSeat *input = data; + if (input->name) + free(input->name); + + input->name = strdup(name); + if (!input->name) + assert(uwacErrorHandler(input->display, UWAC_ERROR_NOMEMORY, "unable to strdup seat's name\n")); +} + +static const struct wl_seat_listener seat_listener = { + seat_handle_capabilities, + seat_handle_name, +}; + + +UwacSeat *UwacSeatNew(UwacDisplay *d, uint32_t id, uint32_t version) { + UwacSeat *ret; + + ret = zalloc(sizeof(UwacSeat)); + ret->display = d; + ret->seat_id = id; + ret->seat_version = version; + + wl_array_init(&ret->pressed_keys); + ret->xkb_context = xkb_context_new(0); + if (!ret->xkb_context) { + fprintf(stderr, "%s: unable to allocate a xkb_context\n", __FUNCTION__); + goto error_xkb_context; + } + + ret->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, version); + wl_seat_add_listener(ret->seat, &seat_listener, ret); + wl_seat_set_user_data(ret->seat, ret); + + ret->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + if (ret->repeat_timer_fd < 0) { + fprintf(stderr, "%s: error creating repeat timer\n", __FUNCTION__); + goto error_timer_fd; + } + ret->repeat_task.run = keyboard_repeat_func; + if (UwacDisplayWatchFd(d, ret->repeat_timer_fd, EPOLLIN, &ret->repeat_task) < 0) { + fprintf(stderr, "%s: error polling repeat timer\n", __FUNCTION__); + goto error_watch_timerfd; + } + + wl_list_insert(d->seats.prev, &ret->link); + return ret; + +error_watch_timerfd: + close(ret->repeat_timer_fd); +error_timer_fd: + wl_seat_destroy(ret->seat); +error_xkb_context: + free(ret); + return NULL; +} + +void UwacSeatDestroy(UwacSeat *s) { + if (s->seat) { +#ifdef WL_SEAT_RELEASE_SINCE_VERSION + if (s->seat_version >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_seat_release(s->seat); + else +#endif + wl_seat_destroy(s->seat); + } + s->seat = NULL; + + free(s->name); + wl_array_release(&s->pressed_keys); + + xkb_state_unref(s->xkb.state); + xkb_context_unref(s->xkb_context); + + if (s->pointer) { +#ifdef WL_POINTER_RELEASE_SINCE_VERSION + if (s->seat_version >= WL_POINTER_RELEASE_SINCE_VERSION) + wl_pointer_release(s->pointer); + else +#endif + wl_pointer_destroy(s->pointer); + } + + if (s->touch) { +#ifdef WL_TOUCH_RELEASE_SINCE_VERSION + if (s->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION) + wl_touch_release(s->touch); + else +#endif + wl_touch_destroy(s->touch); + } + + if (s->keyboard) { +#ifdef WL_KEYBOARD_RELEASE_SINCE_VERSION + if (s->seat_version >= WL_KEYBOARD_RELEASE_SINCE_VERSION) + wl_keyboard_release(s->keyboard); + else +#endif + wl_keyboard_destroy(s->keyboard); + } + + wl_list_remove(&s->link); + free(s); +} + +const char *UwacSeatGetName(const UwacSeat *seat) { + return seat->name; +} diff --git a/uwac/libuwac/uwac-os.c b/uwac/libuwac/uwac-os.c new file mode 100644 index 000000000..ec9efe47b --- /dev/null +++ b/uwac/libuwac/uwac-os.c @@ -0,0 +1,236 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * 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. + */ + +/* + * This file is an adaptation of src/wayland-os.h from the wayland project and + * shared/os-compatiblity.h from the weston project. + * + * Functions have been renamed just to prevent name clashes. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../config.h" +#include "uwac-os.h" + +static int set_cloexec_or_close(int fd) +{ + long flags; + + if (fd == -1) + return -1; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + goto err; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + goto err; + + return fd; + +err: + close(fd); + return -1; +} + +int uwac_os_socket_cloexec(int domain, int type, int protocol) +{ + int fd; + + fd = socket(domain, type | SOCK_CLOEXEC, protocol); + if (fd >= 0) + return fd; + if (errno != EINVAL) + return -1; + + fd = socket(domain, type, protocol); + return set_cloexec_or_close(fd); +} + +int uwac_os_dupfd_cloexec(int fd, long minfd) +{ + int newfd; + + newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd); + if (newfd >= 0) + return newfd; + if (errno != EINVAL) + return -1; + + newfd = fcntl(fd, F_DUPFD, minfd); + return set_cloexec_or_close(newfd); +} + +static ssize_t recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags) +{ + ssize_t len; + struct cmsghdr *cmsg; + unsigned char *data; + int *fd; + int *end; + + len = recvmsg(sockfd, msg, flags); + if (len == -1) + return -1; + + if (!msg->msg_control || msg->msg_controllen == 0) + return len; + + cmsg = CMSG_FIRSTHDR(msg); + for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS) + continue; + + data = CMSG_DATA(cmsg); + end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0)); + for (fd = (int *)data; fd < end; ++fd) + *fd = set_cloexec_or_close(*fd); + } + + return len; +} + +ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) +{ + ssize_t len; + + len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC); + if (len >= 0) + return len; + if (errno != EINVAL) + return -1; + + return recvmsg_cloexec_fallback(sockfd, msg, flags); +} + +int uwac_os_epoll_create_cloexec(void) +{ + int fd; + +#ifdef EPOLL_CLOEXEC + fd = epoll_create1(EPOLL_CLOEXEC); + if (fd >= 0) + return fd; + if (errno != EINVAL) + return -1; +#endif + + fd = epoll_create(1); + return set_cloexec_or_close(fd); +} + +static int create_tmpfile_cloexec(char *tmpname) +{ + int fd; + +#ifdef HAVE_MKOSTEMP + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); +#else + fd = mkstemp(tmpname); + if (fd >= 0) { + fd = set_cloexec_or_close(fd); + unlink(tmpname); + } +#endif + + return fd; +} + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * If the C library implements posix_fallocate(), it is used to + * guarantee that disk space is available for the file at the + * given size. If disk space is insufficient, errno is set to ENOSPC. + * If posix_fallocate() is not supported, program may receive + * SIGBUS on accessing mmap()'ed file contents instead. + */ +int uwac_create_anonymous_file(off_t size) +{ + static const char template[] = "/weston-shared-XXXXXX"; + const char *path; + char *name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + if (!name) + return -1; + + strcpy(name, path); + strcat(name, template); + + fd = create_tmpfile_cloexec(name); + + free(name); + + if (fd < 0) + return -1; + +#ifdef HAVE_POSIX_FALLOCATE + ret = posix_fallocate(fd, 0, size); + if (ret != 0) { + close(fd); + errno = ret; + return -1; + } +#else + ret = ftruncate(fd, size); + if (ret < 0) { + close(fd); + return -1; + } +#endif + + return fd; +} diff --git a/uwac/libuwac/uwac-os.h b/uwac/libuwac/uwac-os.h new file mode 100644 index 000000000..be927df7d --- /dev/null +++ b/uwac/libuwac/uwac-os.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * Copyright © 2014 David FORT + * + * 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. + */ + +/* + * This file is an adaptation of src/wayland-os.h from the wayland project and + * shared/os-compatiblity.h from the weston project. + * + * Functions have been renamed just to prevent name clashes. + */ + +#ifndef __UWAC_OS_H +#define __UWAC_OS_H + +#include + +int uwac_os_socket_cloexec(int domain, int type, int protocol); + +int uwac_os_dupfd_cloexec(int fd, long minfd); + +ssize_t uwac_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags); + +int uwac_os_epoll_create_cloexec(void); + +int uwac_create_anonymous_file(off_t size); +#endif /* __UWAC_OS_H */ diff --git a/uwac/libuwac/uwac-output.c b/uwac/libuwac/uwac-output.c new file mode 100644 index 000000000..0da871c1c --- /dev/null +++ b/uwac/libuwac/uwac-output.c @@ -0,0 +1,126 @@ +/* + * Copyright © 2014 David FORT + * + * 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 "uwac-priv.h" +#include "uwac-utils.h" + +#include +#include +#include +#include + +#define TARGET_OUTPUT_INTERFACE 2 + +static void output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, + int physical_width, int physical_height, int subpixel, + const char *make, const char *model, int transform) +{ + UwacOutput *output = data; + +/* output->allocation.x = x; + output->allocation.y = y;*/ + output->transform = transform; + + if (output->make) + free(output->make); + output->make = strdup(make); + if (!output->make) { + assert(uwacErrorHandler(output->display, UWAC_ERROR_NOMEMORY, "%s: unable to strdup make\n", __FUNCTION__)); + } + + if (output->model) + free(output->model); + output->model = strdup(model); + if (!output->model) { + assert(uwacErrorHandler(output->display, UWAC_ERROR_NOMEMORY, "%s: unable to strdup model\n", __FUNCTION__)); + } +} + +static void output_handle_done(void *data, struct wl_output *wl_output) +{ + UwacOutput *output = data; + + output->doneReceived = true; +} + +static void output_handle_scale(void *data, struct wl_output *wl_output, int32_t scale) +{ + UwacOutput *output = data; + + output->scale = scale; +} + +static void output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, + int width, int height, int refresh) +{ + UwacOutput *output = data; + //UwacDisplay *display = output->display; + + if (output->doneNeeded && output->doneReceived) { + /* TODO: we should clear the mode list */ + } + + if (flags & WL_OUTPUT_MODE_CURRENT) { + output->resolution.width = width; + output->resolution.height = height; + /* output->allocation.width = width; + output->allocation.height = height; + if (display->output_configure_handler) + (*display->output_configure_handler)( + output, display->user_data);*/ + } +} + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, + output_handle_done, + output_handle_scale +}; + +UwacOutput *UwacCreateOutput(UwacDisplay *d, uint32_t id, uint32_t version) { + UwacOutput *o; + + o = zalloc(sizeof *o); + if (!o) + return NULL; + + o->display = d; + o->server_output_id = id; + o->doneNeeded = (version > 1); + o->doneReceived = false; + o->output = wl_registry_bind(d->registry, id, &wl_output_interface, min(TARGET_OUTPUT_INTERFACE, version)); + wl_output_add_listener(o->output, &output_listener, o); + + wl_list_insert(d->outputs.prev, &o->link); + return o; +} + +int UwacDestroyOutput(UwacOutput *output) { + free(output->make); + free(output->model); + + wl_output_destroy(output->output); + wl_list_remove(&output->link); + free(output); + + return UWAC_SUCCESS; +} diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h new file mode 100644 index 000000000..8b0324d23 --- /dev/null +++ b/uwac/libuwac/uwac-priv.h @@ -0,0 +1,237 @@ +/* + * Copyright © 2014 David FORT + * + * 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. + */ + +#ifndef __UWAC_PRIV_H_ +#define __UWAC_PRIV_H_ + +#include "config.h" + +#include +#include +#include "xdg-shell-client-protocol.h" +#ifdef BUILD_IVI +#include "ivi-application-client-protocol.h" +#endif +#ifdef BUILD_FULLSCREEN_SHELL +#include "fullscreen-shell-client-protocol.h" +#endif + +#ifdef HAVE_PIXMAN_REGION +#include +#else +#include +#endif + +#include + +#include + + +extern UwacErrorHandler uwacErrorHandler; + +typedef struct uwac_task UwacTask; + +/** @brief */ +struct uwac_task { + void (*run)(UwacTask *task, uint32_t events); + struct wl_list link; +}; + +/** @brief a global registry object */ +struct uwac_global { + uint32_t name; + char *interface; + uint32_t version; + struct wl_list link; +}; +typedef struct uwac_global UwacGlobal; + +struct uwac_event_list_item; +typedef struct uwac_event_list_item UwacEventListItem; + +/** @brief */ +struct uwac_event_list_item { + UwacEvent event; + UwacEventListItem *tail, *head; +}; + + +/** @brief main connection object to a wayland display */ +struct uwac_display { + struct wl_list globals; + + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; + struct wl_shell *shell; + struct xdg_shell *xdg_shell; +#ifdef BUILD_IVI + struct ivi_application *ivi_application; +#endif +#ifdef BUILD_FULLSCREEN_SHELL + struct _wl_fullscreen_shell *fullscreen_shell; +#endif + + struct wl_shm *shm; + enum wl_shm_format *shm_formats; + uint32_t shm_formats_nb; + bool has_rgb565; + + struct wl_data_device_manager *data_device_manager; + struct text_cursor_position *text_cursor_position; + struct workspace_manager *workspace_manager; + + struct wl_list seats; + + int display_fd; + UwacReturnCode last_error; + uint32_t display_fd_events; + int epoll_fd; + bool running; + UwacTask dispatch_fd_task; + uint32_t serial; + + struct wl_cursor_theme *cursor_theme; + struct wl_cursor **cursors; + + struct wl_list windows; + + struct wl_list outputs; + + UwacEventListItem *push_queue, *pop_queue; +}; + +/** @brief an output on a wayland display */ +struct uwac_output { + UwacDisplay *display; + + bool doneNeeded; + bool doneReceived; + + UwacSize resolution; + int transform; + int scale; + char *make; + char *model; + uint32_t server_output_id; + struct wl_output *output; + + struct wl_list link; +}; + +/** @brief a seat attached to a wayland display */ +struct uwac_seat { + UwacDisplay *display; + char *name; + struct wl_seat *seat; + uint32_t seat_id; + uint32_t seat_version; + struct wl_pointer *pointer; + struct wl_keyboard *keyboard; + struct wl_touch *touch; + struct xkb_context *xkb_context; + + struct { + struct xkb_keymap *keymap; + struct xkb_state *state; + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + } xkb; + uint32_t modifiers; + int32_t repeat_rate_sec, repeat_rate_nsec; + int32_t repeat_delay_sec, repeat_delay_nsec; + uint32_t repeat_sym, repeat_key, repeat_time; + + struct wl_array pressed_keys; + + UwacWindow *pointer_focus; + + UwacWindow *keyboard_focus; + + UwacWindow *touch_focus; + bool touch_frame_started; + + int repeat_timer_fd; + UwacTask repeat_task; + float sx, sy; + struct wl_list link; +}; + + +/** @brief a buffer used for drawing a surface frame */ +struct uwac_buffer { + bool used; +#ifdef HAVE_PIXMAN_REGION + pixman_region32_t damage; +#else + REGION16 damage; +#endif + struct wl_buffer *wayland_buffer; + void *data; +}; +typedef struct uwac_buffer UwacBuffer; + + +/** @brief a window */ +struct uwac_window { + UwacDisplay *display; + int width, height, stride; + int surfaceStates; + enum wl_shm_format format; + + int nbuffers; + UwacBuffer *buffers; + + struct wl_region *opaque_region; + struct wl_region *input_region; + struct wl_callback *frame_callback; + UwacBuffer *drawingBuffer, *pendingBuffer; + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + struct xdg_surface *xdg_surface; +#ifdef BUILD_IVI + struct ivi_surface *ivi_surface; +#endif + struct wl_list link; + + uint32_t pointer_enter_serial; + uint32_t pointer_cursor_serial; + int pointer_current_cursor; +}; + + +/* in uwa-display.c */ +UwacEvent *UwacDisplayNewEvent(UwacDisplay *d, int type); +int UwacDisplayWatchFd(UwacDisplay *display, int fd, uint32_t events, UwacTask *task); + + +/* in uwac-input.c */ +UwacSeat *UwacSeatNew(UwacDisplay *d, uint32_t id, uint32_t version); +void UwacSeatDestroy(UwacSeat *s); + +/* in uwac-output.c */ +UwacOutput *UwacCreateOutput(UwacDisplay *d, uint32_t id, uint32_t version); +int UwacDestroyOutput(UwacOutput *output); + +#endif /* __UWAC_PRIV_H_ */ diff --git a/uwac/libuwac/uwac-tools.c b/uwac/libuwac/uwac-tools.c new file mode 100644 index 000000000..73aff227e --- /dev/null +++ b/uwac/libuwac/uwac-tools.c @@ -0,0 +1,93 @@ +/* + * Copyright © 2015 David FORT + * + * 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 +#include +#include + +/** @brief */ +struct uwac_touch_automata { + struct wl_array tp; +}; + +void UwacTouchAutomataInit(UwacTouchAutomata *automata) { + wl_array_init(&automata->tp); +} + +void UwacTouchAutomataReset(UwacTouchAutomata *automata) { + automata->tp.size = 0; +} + +bool UwacTouchAutomataInjectEvent(UwacTouchAutomata *automata, UwacEvent *event) { + + UwacTouchPoint *tp; + + switch (event->type) { + case UWAC_EVENT_TOUCH_FRAME_BEGIN: + break; + + case UWAC_EVENT_TOUCH_UP: { + UwacTouchUp *touchUp = &event->touchUp; + int toMove = automata->tp.size - sizeof(UwacTouchPoint); + + wl_array_for_each(tp, &automata->tp) { + if (tp->id == touchUp->id) { + if (toMove) + memmove(tp, tp+1, toMove); + return true; + } + + toMove -= sizeof(UwacTouchPoint); + } + break; + } + + case UWAC_EVENT_TOUCH_DOWN: { + UwacTouchDown *touchDown = &event->touchDown; + + wl_array_for_each(tp, &automata->tp) { + if (tp->id == touchDown->id) { + tp->x = touchDown->x; + tp->y = touchDown->y; + return true; + } + } + + tp = wl_array_add(&automata->tp, sizeof(UwacTouchPoint)); + if (!tp) + return false; + + tp->id = touchDown->id; + tp->x = touchDown->x; + tp->y = touchDown->y; + break; + } + + case UWAC_EVENT_TOUCH_FRAME_END: + break; + + default: + break; + } + + return true; +} diff --git a/uwac/libuwac/uwac-utils.c b/uwac/libuwac/uwac-utils.c new file mode 100644 index 000000000..c9c33f6fe --- /dev/null +++ b/uwac/libuwac/uwac-utils.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * Copyright © 2008 Kristian Høgsberg + * Copyright © 2014 David FORT + * + * 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 "config.h" + +#include +#include +#include +#include + +#include "uwac-utils.h" + +/* + * This part is an adaptation of client/window.c from the weston project. + */ + +void *fail_on_null(void *p) { + if (p == NULL) { + fprintf(stderr, "out of memory\n"); + exit(EXIT_FAILURE); + } + + return p; +} + +void *xmalloc(size_t s) { + return fail_on_null(malloc(s)); +} + +void *xzalloc(size_t s) { + return fail_on_null(zalloc(s)); +} + +char *xstrdup(const char *s) { + return fail_on_null(strdup(s)); +} + +void *xrealloc(char *p, size_t s) { + return fail_on_null(realloc(p, s)); +} + + diff --git a/uwac/libuwac/uwac-utils.h b/uwac/libuwac/uwac-utils.h new file mode 100644 index 000000000..e30507300 --- /dev/null +++ b/uwac/libuwac/uwac-utils.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2014 David FORT + * + * 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. + */ + +#ifndef __UWAC_UTILS_H_ +#define __UWAC_UTILS_H_ + +#include + +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + + + +void *xmalloc(size_t s); + +static inline void *zalloc(size_t size) { + return calloc(1, size); +} + +void *xzalloc(size_t s); + +char *xstrdup(const char *s); + +void *xrealloc(char *p, size_t s); + +#endif /* __UWAC_UTILS_H_ */ diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c new file mode 100644 index 000000000..b3fd370ad --- /dev/null +++ b/uwac/libuwac/uwac-window.c @@ -0,0 +1,620 @@ +/* + * Copyright © 2014 David FORT + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "uwac-priv.h" +#include "uwac-utils.h" +#include "uwac-os.h" + + +#define UWAC_INITIAL_BUFFERS 3 + + +static int bppFromShmFormat(enum wl_shm_format format) { + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + case WL_SHM_FORMAT_XRGB8888: + default: + return 4; + } +} + + +static void buffer_release(void *data, struct wl_buffer *buffer) { + UwacBuffer *uwacBuffer = (UwacBuffer *)data; + + uwacBuffer->used = false; +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +void UwacWindowDestroyBuffers(UwacWindow *w) { + int i; + + for (i = 0; i < w->nbuffers; i++) { + UwacBuffer *buffer = &w->buffers[i]; +#ifdef HAVE_PIXMAN_REGION + pixman_region32_fini(&buffer->damage); +#else + region16_uninit(&buffer->damage); +#endif + wl_buffer_destroy(buffer->wayland_buffer); + } + + w->nbuffers = 0; + free(w->buffers); + w->buffers = NULL; +} + + +int UwacWindowShmAllocBuffers(UwacWindow *w, int nbuffers, int allocSize, uint32_t width, + uint32_t height, enum wl_shm_format format); + +static void xdg_handle_configure(void *data, struct xdg_surface *surface, + int32_t width, int32_t height, + struct wl_array *states, uint32_t serial) +{ + UwacWindow *window = (UwacWindow *)data; + UwacConfigureEvent *event; + int ret, surfaceState; + enum xdg_surface_state *state; + + surfaceState = 0; + wl_array_for_each(state, states) { + switch (*state) { + case XDG_SURFACE_STATE_MAXIMIZED: + surfaceState |= UWAC_WINDOW_MAXIMIZED; + break; + case XDG_SURFACE_STATE_FULLSCREEN: + surfaceState |= UWAC_WINDOW_FULLSCREEN; + break; + case XDG_SURFACE_STATE_ACTIVATED: + surfaceState |= UWAC_WINDOW_ACTIVATED; + break; + case XDG_SURFACE_STATE_RESIZING: + surfaceState |= UWAC_WINDOW_RESIZING; + break; + default: + break; + } + } + + window->surfaceStates = surfaceState; + + event = (UwacConfigureEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE); + if(!event) { + assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY, "failed to allocate a configure event\n")); + goto ack; + } + + event->window = window; + event->states = surfaceState; + if (width && height) { + event->width = width; + event->height = height; + + UwacWindowDestroyBuffers(window); + + window->width = width; + window->stride = width * bppFromShmFormat(window->format); + window->height = height; + + ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height, + width, height, window->format); + if (ret != UWAC_SUCCESS) { + assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n")); + window->drawingBuffer = window->pendingBuffer = NULL; + goto ack; + } + window->drawingBuffer = window->pendingBuffer = &window->buffers[0]; + } else { + event->width = window->width; + event->height = window->height; + } + +ack: + xdg_surface_ack_configure(surface, serial); +} + +static void xdg_handle_close(void *data, struct xdg_surface *xdg_surface) +{ + UwacCloseEvent *event; + UwacWindow *window = (UwacWindow *)data; + + event = (UwacCloseEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CLOSE); + if(!event) { + assert(uwacErrorHandler(window->display, UWAC_ERROR_INTERNAL, "failed to allocate a close event\n")); + return; + } + + event->window = window; +} + +static const struct xdg_surface_listener xdg_surface_listener = { + xdg_handle_configure, + xdg_handle_close, +}; + +#if BUILD_IVI + +static void ivi_handle_configure(void *data, struct ivi_surface *surface, + int32_t width, int32_t height) +{ + UwacWindow *window = (UwacWindow *)data; + UwacConfigureEvent *event; + int ret; + + + event = (UwacConfigureEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE); + if(!event) { + assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY, "failed to allocate a configure event\n")); + return; + } + + event->window = window; + event->states = 0; + if (width && height) { + event->width = width; + event->height = height; + + UwacWindowDestroyBuffers(window); + + window->width = width; + window->stride = width * bppFromShmFormat(window->format); + window->height = height; + + ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height, + width, height, window->format); + if (ret != UWAC_SUCCESS) { + assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n")); + window->drawingBuffer = window->pendingBuffer = NULL; + return; + } + window->drawingBuffer = window->pendingBuffer = &window->buffers[0]; + } else { + event->width = window->width; + event->height = window->height; + } +} + +static const struct ivi_surface_listener ivi_surface_listener = { + ivi_handle_configure, +}; +#endif + +void shell_ping(void *data, struct wl_shell_surface *surface, uint32_t serial) +{ + wl_shell_surface_pong(surface, serial); +} + +void shell_configure(void *data, struct wl_shell_surface *surface, uint32_t edges, + int32_t width, int32_t height) +{ + UwacWindow *window = (UwacWindow *)data; + UwacConfigureEvent *event; + int ret; + + event = (UwacConfigureEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_CONFIGURE); + if(!event) { + assert(uwacErrorHandler(window->display, UWAC_ERROR_NOMEMORY, "failed to allocate a configure event\n")); + return; + } + + event->window = window; + event->states = 0; + if (width && height) { + event->width = width; + event->height = height; + + UwacWindowDestroyBuffers(window); + + window->width = width; + window->stride = width * bppFromShmFormat(window->format); + window->height = height; + + ret = UwacWindowShmAllocBuffers(window, UWAC_INITIAL_BUFFERS, window->stride * height, + width, height, window->format); + if (ret != UWAC_SUCCESS) { + assert(uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n")); + window->drawingBuffer = window->pendingBuffer = NULL; + return; + } + window->drawingBuffer = window->pendingBuffer = &window->buffers[0]; + } else { + event->width = window->width; + event->height = window->height; + } + +} + + +void shell_popup_done(void *data, struct wl_shell_surface *surface) +{ +} + + +static const struct wl_shell_surface_listener shell_listener = { + shell_ping, + shell_configure, + shell_popup_done +}; + + +int UwacWindowShmAllocBuffers(UwacWindow *w, int nbuffers, int allocSize, uint32_t width, + uint32_t height, enum wl_shm_format format) +{ + int ret = UWAC_SUCCESS; + UwacBuffer *newBuffers; + int i, fd; + void *data; + struct wl_shm_pool *pool; + + newBuffers = realloc(w->buffers, (w->nbuffers + nbuffers) * sizeof(UwacBuffer)); + if (!newBuffers) + return UWAC_ERROR_NOMEMORY; + + w->buffers = newBuffers; + + memset(w->buffers + w->nbuffers, 0, sizeof(UwacBuffer) * nbuffers); + + fd = uwac_create_anonymous_file(allocSize * nbuffers); + if (fd < 0) { + return UWAC_ERROR_INTERNAL; + } + + data = mmap(NULL, allocSize * nbuffers, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + ret = UWAC_ERROR_NOMEMORY; + goto error_mmap; + } + + pool = wl_shm_create_pool(w->display->shm, fd, allocSize * nbuffers); + if (!pool) { + ret = UWAC_ERROR_NOMEMORY; + goto error_mmap; + } + + for (i = 0; i < nbuffers; i++) { + UwacBuffer *buffer = &w->buffers[w->nbuffers + i]; +#ifdef HAVE_PIXMAN_REGION + pixman_region32_init(&buffer->damage); +#else + region16_init(&buffer->damage); +#endif + buffer->data = data + (allocSize * i); + + buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format); + wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer); + + } + + wl_shm_pool_destroy(pool); + w->nbuffers += nbuffers; + +error_mmap: + close(fd); + return ret; +} + +UwacBuffer *UwacWindowFindFreeBuffer(UwacWindow *w) { + int i, ret; + + for (i = 0; i < w->nbuffers; i++) { + if (!w->buffers[i].used) { + w->buffers[i].used = true; + return &w->buffers[i]; + } + } + + ret = UwacWindowShmAllocBuffers(w, 2, w->stride * w->height, w->width, w->height, w->format); + if (ret != UWAC_SUCCESS) { + w->display->last_error = ret; + return NULL; + } + + w->buffers[i].used = true; + return &w->buffers[i]; +} + + +UwacWindow *UwacCreateWindowShm(UwacDisplay *display, uint32_t width, uint32_t height, enum wl_shm_format format) { + UwacWindow *w; + int allocSize, ret; + + if (!display) { + display->last_error = UWAC_ERROR_INVALID_DISPLAY; + return NULL; + } + + w = zalloc(sizeof(*w)); + if (!w) { + display->last_error = UWAC_ERROR_NOMEMORY; + return NULL; + } + + w->display = display; + w->format = format; + w->width = width; + w->height = height; + w->stride = width * bppFromShmFormat(format); + allocSize = w->stride * height; + + ret = UwacWindowShmAllocBuffers(w, UWAC_INITIAL_BUFFERS, allocSize, width, height, format); + if (ret != UWAC_SUCCESS) { + display->last_error = ret; + goto out_error_free; + } + + w->buffers[0].used = true; + w->drawingBuffer = &w->buffers[0]; + + w->surface = wl_compositor_create_surface(display->compositor); + if (!w->surface) { + display->last_error = UWAC_ERROR_NOMEMORY; + goto out_error_surface; + } + wl_surface_set_user_data(w->surface, w); + + if (display->xdg_shell) { + w->xdg_surface = xdg_shell_get_xdg_surface(display->xdg_shell, w->surface); + if (!w->xdg_surface) { + display->last_error = UWAC_ERROR_NOMEMORY; + goto out_error_shell; + } + + assert(w->xdg_surface); + + xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w); +#if BUILD_IVI + } else if (display->ivi_application) { + w->ivi_surface = ivi_application_surface_create(display->ivi_application, 1, w->surface); + + assert (w->ivi_surface); + + ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w); +#endif +#if BUILD_FULLSCREEN_SHELL + } else if (display->fullscreen_shell) { + _wl_fullscreen_shell_present_surface(display->fullscreen_shell, w->surface, + _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER, NULL); +#endif + } else { + w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface); + + assert(w->shell_surface); + + wl_shell_surface_add_listener(w->shell_surface, &shell_listener, w); + wl_shell_surface_set_toplevel(w->shell_surface); + } + + wl_list_insert(display->windows.prev, &w->link); + + display->last_error = UWAC_SUCCESS; + return w; + +out_error_shell: + wl_surface_destroy(w->surface); +out_error_surface: + UwacWindowDestroyBuffers(w); +out_error_free: + free(w); + return NULL; +} + + +UwacReturnCode UwacDestroyWindow(UwacWindow **pwindow) { + UwacWindow *w; + + assert (pwindow); + + w = *pwindow; + UwacWindowDestroyBuffers(w); + + if (w->frame_callback) + wl_callback_destroy(w->frame_callback); + + if (w->xdg_surface) + xdg_surface_destroy(w->xdg_surface); +#if BUILD_IVI + if (w->ivi_surface) + ivi_surface_destroy(w->ivi_surface); +#endif + + if (w->opaque_region) + wl_region_destroy(w->opaque_region); + + if (w->input_region) + wl_region_destroy(w->opaque_region); + + wl_surface_destroy(w->surface); + wl_list_remove(&w->link); + free(w); + + *pwindow = NULL; + return UWAC_SUCCESS; +} + + +UwacReturnCode UwacWindowSetOpaqueRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, + uint32_t height) +{ + assert(window); + + if (window->opaque_region) + wl_region_destroy(window->opaque_region); + + window->opaque_region = wl_compositor_create_region(window->display->compositor); + if (!window->opaque_region) + return UWAC_ERROR_NOMEMORY; + + wl_region_add(window->opaque_region, x, y, width, height); + wl_surface_set_opaque_region(window->surface, window->opaque_region); + return UWAC_SUCCESS; +} + +UwacReturnCode UwacWindowSetInputRegion(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { + assert(window); + + if (window->input_region) + wl_region_destroy(window->input_region); + + window->input_region = wl_compositor_create_region(window->display->compositor); + if (!window->input_region) + return UWAC_ERROR_NOMEMORY; + + wl_region_add(window->input_region, x, y, width, height); + wl_surface_set_input_region(window->surface, window->input_region); + return UWAC_SUCCESS; +} + + +void *UwacWindowGetDrawingBuffer(UwacWindow *window) { + return window->drawingBuffer->data; +} + +static void frame_done_cb(void *data, struct wl_callback *callback, uint32_t time); + +static const struct wl_callback_listener frame_listener = { + frame_done_cb +}; + + +static void UwacSubmitBufferPtr(UwacWindow *window, UwacBuffer *buffer) { + int nrects, i; +#ifdef HAVE_PIXMAN_REGION + const pixman_box32_t *box; +#else + const RECTANGLE_16 *box; +#endif + + wl_surface_attach(window->surface, buffer->wayland_buffer, 0, 0); + +#ifdef HAVE_PIXMAN_REGION + box = pixman_region32_rectangles(&buffer->damage, &nrects); + for (i = 0; i < nrects; i++, box++) + wl_surface_damage(window->surface, box->x1, box->y1, (box->x2 - box->x1), (box->y2 - box->y1)); +#else + box = region16_rects(&buffer->damage, &nrects); + for (i = 0; i < nrects; i++, box++) + wl_surface_damage(window->surface, box->left, box->top, (box->right - box->left), (box->bottom - box->top)); +#endif + + if (window->frame_callback) + wl_callback_destroy(window->frame_callback); + + window->frame_callback = wl_surface_frame(window->surface); + wl_callback_add_listener(window->frame_callback, &frame_listener, window); + + wl_surface_commit(window->surface); + +#ifdef HAVE_PIXMAN_REGION + pixman_region32_clear(&buffer->damage); +#else + region16_clear(&buffer->damage); +#endif +} + + +static void frame_done_cb(void *data, struct wl_callback *callback, uint32_t time) { + UwacWindow *window = (UwacWindow *)data; + UwacFrameDoneEvent *event; + + window->pendingBuffer = NULL; + event = (UwacFrameDoneEvent *)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE); + if(event) + event->window = window; +} + + +UwacReturnCode UwacWindowAddDamage(UwacWindow *window, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { +#ifdef HAVE_PIXMAN_REGION + if (!pixman_region32_union_rect(&window->drawingBuffer->damage, &window->drawingBuffer->damage, x, y, width, height)) +#else + RECTANGLE_16 box; + box.left = x; box.top = y; + box.right = x + width; box.bottom = y + height; + + if (!region16_union_rect(&window->drawingBuffer->damage, &window->drawingBuffer->damage, &box)) +#endif + return UWAC_ERROR_INTERNAL; + + return UWAC_SUCCESS; +} + + +UwacReturnCode UwacWindowSubmitBuffer(UwacWindow *window, bool copyContentForNextFrame) { + UwacBuffer *drawingBuffer = window->drawingBuffer; + + if (window->pendingBuffer) { + /* we already have a pending frame, don't do anything*/ + return UWAC_SUCCESS; + } + + UwacSubmitBufferPtr(window, drawingBuffer); + + window->pendingBuffer = window->drawingBuffer; + window->drawingBuffer = UwacWindowFindFreeBuffer(window); + if (!window->drawingBuffer) + return UWAC_ERROR_NOMEMORY; + + if (copyContentForNextFrame) { + memcpy(window->drawingBuffer->data, window->pendingBuffer->data, window->stride * window->height); + } + + return UWAC_SUCCESS; +} + +UwacReturnCode UwacWindowGetGeometry(UwacWindow *window, UwacSize *geometry) { + assert(window); + assert(geometry); + + geometry->width = window->width; + geometry->height = window->height; + return UWAC_SUCCESS; +} + + +UwacReturnCode UwacWindowSetFullscreenState(UwacWindow *window, UwacOutput *output, bool isFullscreen) { + if (window->xdg_surface) { + if (isFullscreen) { + xdg_surface_set_fullscreen(window->xdg_surface, output ? output->output : NULL); + } else { + xdg_surface_unset_fullscreen(window->xdg_surface); + } + } + return UWAC_SUCCESS; +} + +void UwacWindowSetTitle(UwacWindow *window, const char *name) { + if (window->xdg_surface) + xdg_surface_set_title(window->xdg_surface, name); + else if (window->shell_surface) + wl_shell_surface_set_title(window->shell_surface, name); +} diff --git a/uwac/protocols/fullscreen-shell.xml b/uwac/protocols/fullscreen-shell.xml new file mode 100644 index 000000000..e2b994b94 --- /dev/null +++ b/uwac/protocols/fullscreen-shell.xml @@ -0,0 +1,206 @@ + + + + Displays a single surface per output. + + This interface provides a mechanism for a single client to display + simple full-screen surfaces. While there technically may be multiple + clients bound to this interface, only one of those clients should be + shown at a time. + + To present a surface, the client uses either the present_surface or + present_surface_for_mode requests. Presenting a surface takes effect + on the next wl_surface.commit. See the individual requests for + details about scaling and mode switches. + + The client can have at most one surface per output at any time. + Requesting a surface be presented on an output that already has a + surface replaces the previously presented surface. Presenting a null + surface removes its content and effectively disables the output. + Exactly what happens when an output is "disabled" is + compositor-specific. The same surface may be presented on multiple + outputs simultaneously. + + Once a surface is presented on an output, it stays on that output + until either the client removes it or the compositor destroys the + output. This way, the client can update the output's contents by + simply attaching a new buffer. + + + + + Release the binding from the wl_fullscreen_shell interface + + This destroys the server-side object and frees this binding. If + the client binds to wl_fullscreen_shell multiple times, it may wish + to free some of those bindings. + + + + + + Various capabilities that can be advertised by the compositor. They + are advertised one-at-a-time when the wl_fullscreen_shell interface is + bound. See the wl_fullscreen_shell.capability event for more details. + + ARBITRARY_MODE: + This is a hint to the client that indicates that the compositor is + capable of setting practically any mode on its outputs. If this + capability is provided, wl_fullscreen_shell.present_surface_for_mode + will almost never fail and clients should feel free to set whatever + mode they like. If the compositor does not advertise this, it may + still support some modes that are not advertised through wl_global.mode + but it is less likely. + + CURSOR_PLANE: + This is a hint to the client that indicates that the compositor can + handle a cursor surface from the client without actually compositing. + This may be because of a hardware cursor plane or some other mechanism. + If the compositor does not advertise this capability then setting + wl_pointer.cursor may degrade performance or be ignored entirely. If + CURSOR_PLANE is not advertised, it is recommended that the client draw + its own cursor and set wl_pointer.cursor(NULL). + + + + + + + + Advertises a single capability of the compositor. + + When the wl_fullscreen_shell interface is bound, this event is emitted + once for each capability advertised. Valid capabilities are given by + the wl_fullscreen_shell.capability enum. If clients want to take + advantage of any of these capabilities, they should use a + wl_display.sync request immediately after binding to ensure that they + receive all the capability events. + + + + + + + Hints to indicate to the compositor how to deal with a conflict + between the dimensions of the surface and the dimensions of the + output. The compositor is free to ignore this parameter. + + + + + + + + + + + Present a surface on the given output. + + If the output is null, the compositor will present the surface on + whatever display (or displays) it thinks best. In particular, this + may replace any or all surfaces currently presented so it should + not be used in combination with placing surfaces on specific + outputs. + + The method parameter is a hint to the compositor for how the surface + is to be presented. In particular, it tells the compositor how to + handle a size mismatch between the presented surface and the + output. The compositor is free to ignore this parameter. + + The "zoom", "zoom_crop", and "stretch" methods imply a scaling + operation on the surface. This will override any kind of output + scaling, so the buffer_scale property of the surface is effectively + ignored. + + + + + + + + + Presents a surface on the given output for a particular mode. + + If the current size of the output differs from that of the surface, + the compositor will attempt to change the size of the output to + match the surface. The result of the mode-switch operation will be + returned via the provided wl_fullscreen_shell_mode_feedback object. + + If the current output mode matches the one requested or if the + compositor successfully switches the mode to match the surface, + then the mode_successful event will be sent and the output will + contain the contents of the given surface. If the compositor + cannot match the output size to the surface size, the mode_failed + will be sent and the output will contain the contents of the + previously presented surface (if any). If another surface is + presented on the given output before either of these has a chance + to happen, the present_cancelled event will be sent. + + Due to race conditions and other issues unknown to the client, no + mode-switch operation is guaranteed to succeed. However, if the + mode is one advertised by wl_output.mode or if the compositor + advertises the ARBITRARY_MODES capability, then the client should + expect that the mode-switch operation will usually succeed. + + If the size of the presented surface changes, the resulting output + is undefined. The compositor may attempt to change the output mode + to compensate. However, there is no guarantee that a suitable mode + will be found and the client has no way to be notified of success + or failure. + + The framerate parameter specifies the desired framerate for the + output in mHz. The compositor is free to ignore this parameter. A + value of 0 indicates that the client has no preference. + + If the value of wl_output.scale differs from wl_surface.buffer_scale, + then the compositor may choose a mode that matches either the buffer + size or the surface size. In either case, the surface will fill the + output. + + + + + + + + + + These errors can be emitted in response to wl_fullscreen_shell requests + + + + + + + + + This event indicates that the attempted mode switch operation was + successful. A surface of the size requested in the mode switch + will fill the output without scaling. + + Upon receiving this event, the client should destroy the + wl_fullscreen_shell_mode_feedback object. + + + + + This event indicates that the attempted mode switch operation + failed. This may be because the requested output mode is not + possible or it may mean that the compositor does not want to allow it. + + Upon receiving this event, the client should destroy the + wl_fullscreen_shell_mode_feedback object. + + + + + This event indicates that the attempted mode switch operation was + cancelled. Most likely this is because the client requested a + second mode switch before the first one completed. + + Upon receiving this event, the client should destroy the + wl_fullscreen_shell_mode_feedback object. + + + + diff --git a/uwac/protocols/ivi-application.xml b/uwac/protocols/ivi-application.xml new file mode 100644 index 000000000..8f2422688 --- /dev/null +++ b/uwac/protocols/ivi-application.xml @@ -0,0 +1,100 @@ + + + + + Copyright (C) 2013 DENSO CORPORATION + Copyright (c) 2013 BMW Car IT GmbH + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + + + + This removes link from ivi_id to wl_surface and destroys ivi_surface. + The ID, ivi_id, is free and can be used for surface_create again. + + + + + + The configure event asks the client to resize its surface. + + The size is a hint, in the sense that the client is free to + ignore it if it doesn't resize, pick a smaller size (to + satisfy aspect ratio or resize in steps of NxM pixels). + + The client is free to dismiss all but the last configure + event it received. + + The width and height arguments specify the size of the window + in surface local coordinates. + + + + + + + + + This interface is exposed as a global singleton. + This interface is implemented by servers that provide IVI-style user interfaces. + It allows clients to associate a ivi_surface with wl_surface. + + + + + + + + + + This request gives the wl_surface the role of an IVI Surface. Creating more than + one ivi_surface for a wl_surface is not allowed. Note, that this still allows the + following example: + + 1. create a wl_surface + 2. create ivi_surface for the wl_surface + 3. destroy the ivi_surface + 4. create ivi_surface for the wl_surface (with the same or another ivi_id as before) + + surface_create will create a interface:ivi_surface with numeric ID; ivi_id in + ivi compositor. These ivi_ids are defined as unique in the system to identify + it inside of ivi compositor. The ivi compositor implements business logic how to + set properties of the surface with ivi_id according to status of the system. + E.g. a unique ID for Car Navigation application is used for implementing special + logic of the application about where it shall be located. + The server regards following cases as protocol errors and disconnects the client. + - wl_surface already has an nother role. + - ivi_id is already assigned to an another wl_surface. + + If client destroys ivi_surface or wl_surface which is assigne to the ivi_surface, + ivi_id which is assigned to the ivi_surface is free for reuse. + + + + + + + + + diff --git a/uwac/protocols/xdg-shell.xml b/uwac/protocols/xdg-shell.xml new file mode 100644 index 000000000..f98e760d4 --- /dev/null +++ b/uwac/protocols/xdg-shell.xml @@ -0,0 +1,608 @@ + + + + + Copyright © 2008-2013 Kristian Høgsberg + Copyright © 2013 Rafael Antognolli + Copyright © 2013 Jasper St. Pierre + Copyright © 2010-2013 Intel Corporation + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + xdg_shell allows clients to turn a wl_surface into a "real window" + which can be dragged, resized, stacked, and moved around by the + user. Everything about this interface is suited towards traditional + desktop environments. + + + + + The 'current' member of this enum gives the version of the + protocol. Implementations can compare this to the version + they implement using static_assert to ensure the protocol and + implementation versions match. + + + + + + + + + + + + + + Destroy this xdg_shell object. + + Destroying a bound xdg_shell object while there are surfaces + still alive created by this xdg_shell object instance is illegal + and will result in a protocol error. + + + + + + Negotiate the unstable version of the interface. This + mechanism is in place to ensure client and server agree on the + unstable versions of the protocol that they speak or exit + cleanly if they don't agree. This request will go away once + the xdg-shell protocol is stable. + + + + + + + This creates an xdg_surface for the given surface and gives it the + xdg_surface role. A wl_surface can only be given an xdg_surface role + once. If get_xdg_surface is called with a wl_surface that already has + an active xdg_surface associated with it, or if it had any other role, + an error is raised. + + See the documentation of xdg_surface for more details about what an + xdg_surface is and how it is used. + + + + + + + + This creates an xdg_popup for the given surface and gives it the + xdg_popup role. A wl_surface can only be given an xdg_popup role + once. If get_xdg_popup is called with a wl_surface that already has + an active xdg_popup associated with it, or if it had any other role, + an error is raised. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + + + + + + + The ping event asks the client if it's still alive. Pass the + serial specified in the event back to the compositor by sending + a "pong" request back with the specified serial. + + Compositors can use this to determine if the client is still + alive. It's unspecified what will happen if the client doesn't + respond to the ping request, or in what timeframe. Clients should + try to respond in a reasonable amount of time. + + A compositor is free to ping in any way it wants, but a client must + always respond to any xdg_shell object it created. + + + + + + + A client must respond to a ping event with a pong request or + the client may be deemed unresponsive. + + + + + + + + An interface that may be implemented by a wl_surface, for + implementations that provide a desktop-style user interface. + + It provides requests to treat surfaces like windows, allowing to set + properties like maximized, fullscreen, minimized, and to move and resize + them, and associate metadata like title and app id. + + The client must call wl_surface.commit on the corresponding wl_surface + for the xdg_surface state to take effect. Prior to committing the new + state, it can set up initial configuration, such as maximizing or setting + a window geometry. + + Even without attaching a buffer the compositor must respond to initial + committed configuration, for instance sending a configure event with + expected window geometry if the client maximized its surface during + initialization. + + For a surface to be mapped by the compositor the client must have + committed both an xdg_surface state and a buffer. + + + + + Unmap and destroy the window. The window will be effectively + hidden from the user's point of view, and all state like + maximization, fullscreen, and so on, will be lost. + + + + + + Set the "parent" of this surface. This window should be stacked + above a parent. The parent surface must be mapped as long as this + surface is mapped. + + Parent windows should be set on dialogs, toolboxes, or other + "auxiliary" surfaces, so that the parent is raised when the dialog + is raised. + + + + + + + Set a short title for the surface. + + This string may be used to identify the surface in a task bar, + window list, or other user interface elements provided by the + compositor. + + The string must be encoded in UTF-8. + + + + + + + Set an application identifier for the surface. + + The app ID identifies the general class of applications to which + the surface belongs. The compositor can use this to group multiple + surfaces together, or to determine how to launch a new application. + + For D-Bus activatable applications, the app ID is used as the D-Bus + service name. + + The compositor shell will try to group application surfaces together + by their app ID. As a best practice, it is suggested to select app + ID's that match the basename of the application's .desktop file. + For example, "org.freedesktop.FooViewer" where the .desktop file is + "org.freedesktop.FooViewer.desktop". + + See the desktop-entry specification [0] for more details on + application identifiers and how they relate to well-known D-Bus + names and .desktop files. + + [0] http://standards.freedesktop.org/desktop-entry-spec/ + + + + + + + Clients implementing client-side decorations might want to show + a context menu when right-clicking on the decorations, giving the + user a menu that they can use to maximize or minimize the window. + + This request asks the compositor to pop up such a window menu at + the given position, relative to the local surface coordinates of + the parent surface. There are no guarantees as to what menu items + the window menu contains. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. + + + + + + + + + + + Start an interactive, user-driven move of the surface. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. The passed + serial is used to determine the type of interactive move (touch, + pointer, etc). + + The server may ignore move requests depending on the state of + the surface (e.g. fullscreen or maximized), or if the passed serial + is no longer valid. + + If triggered, the surface will lose the focus of the device + (wl_pointer, wl_touch, etc) used for the move. It is up to the + compositor to visually indicate that the move is taking place, such as + updating a pointer cursor, during the move. There is no guarantee + that the device focus will return when the move is completed. + + + + + + + + These values are used to indicate which edge of a surface + is being dragged in a resize operation. + + + + + + + + + + + + + + + Start a user-driven, interactive resize of the surface. + + This request must be used in response to some sort of user action + like a button press, key press, or touch down event. The passed + serial is used to determine the type of interactive resize (touch, + pointer, etc). + + The server may ignore resize requests depending on the state of + the surface (e.g. fullscreen or maximized). + + If triggered, the client will receive configure events with the + "resize" state enum value and the expected sizes. See the "resize" + enum value for more details about what is required. The client + must also acknowledge configure events using "ack_configure". After + the resize is completed, the client will receive another "configure" + event without the resize state. + + If triggered, the surface also will lose the focus of the device + (wl_pointer, wl_touch, etc) used for the resize. It is up to the + compositor to visually indicate that the resize is taking place, + such as updating a pointer cursor, during the resize. There is no + guarantee that the device focus will return when the resize is + completed. + + The edges parameter specifies how the surface should be resized, + and is one of the values of the resize_edge enum. The compositor + may use this information to update the surface position for + example when dragging the top left corner. The compositor may also + use this information to adapt its behavior, e.g. choose an + appropriate cursor image. + + + + + + + + + The different state values used on the surface. This is designed for + state values like maximized, fullscreen. It is paired with the + configure event to ensure that both the client and the compositor + setting the state can be synchronized. + + States set in this way are double-buffered. They will get applied on + the next commit. + + Desktop environments may extend this enum by taking up a range of + values and documenting the range they chose in this description. + They are not required to document the values for the range that they + chose. Ideally, any good extensions from a desktop environment should + make its way into standardization into this enum. + + The current reserved ranges are: + + 0x0000 - 0x0FFF: xdg-shell core values, documented below. + 0x1000 - 0x1FFF: GNOME + + + The surface is maximized. The window geometry specified in the configure + event must be obeyed by the client. + + + The surface is fullscreen. The window geometry specified in the configure + event must be obeyed by the client. + + + The surface is being resized. The window geometry specified in the + configure event is a maximum; the client cannot resize beyond it. + Clients that have aspect ratio or cell sizing configuration can use + a smaller size, however. + + + Client window decorations should be painted as if the window is + active. Do not assume this means that the window actually has + keyboard or pointer focus. + + + + + + The configure event asks the client to resize its surface or to + change its state. + + The width and height arguments specify a hint to the window + about how its surface should be resized in window geometry + coordinates. See set_window_geometry. + + If the width or height arguments are zero, it means the client + should decide its own window dimension. This may happen when the + compositor need to configure the state of the surface but doesn't + have any information about any previous or expected dimension. + + The states listed in the event specify how the width/height + arguments should be interpreted, and possibly how it should be + drawn. + + Clients should arrange their surface for the new size and + states, and then send a ack_configure request with the serial + sent in this configure event at some point before committing + the new surface. + + If the client receives multiple configure events before it + can respond to one, it is free to discard all but the last + event it received. + + + + + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make a ack_configure request before the commit request, + passing along the serial of the configure event. + + For instance, the compositor might use this information to move + a surface to the top left only when the client has drawn itself + for the maximized or fullscreen state. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + + + + + + The window geometry of a window is its "visible bounds" from the + user's perspective. Client-side decorations often have invisible + portions like drop-shadows which should be ignored for the + purposes of aligning, placing and constraining windows. + + The window geometry is double buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + Once the window geometry of the surface is set once, it is not + possible to unset it, and it will remain the same until + set_window_geometry is called again, even if a new subsurface or + buffer is attached. + + If never set, the value is the full bounds of the surface, + including any subsurfaces. This updates dynamically on every + commit. This unset mode is meant for extremely simple clients. + + If responding to a configure event, the window geometry in here + must respect the sizing negotiations specified by the states in + the configure event. + + The arguments are given in the surface local coordinate space of + the wl_surface associated with this xdg_surface. + + The width and height must be greater than zero. + + + + + + + + + + Maximize the surface. + + After requesting that the surface should be maximized, the compositor + will respond by emitting a configure event with the "maximized" state + and the required window geometry. The client should then update its + content, drawing it in a maximized state, i.e. without shadow or other + decoration outside of the window geometry. The client must also + acknowledge the configure when committing the new content (see + ack_configure). + + It is up to the compositor to decide how and where to maximize the + surface, for example which output and what region of the screen should + be used. + + If the surface was already maximized, the compositor will still emit + a configure event with the "maximized" state. + + + + + + Unmaximize the surface. + + After requesting that the surface should be unmaximized, the compositor + will respond by emitting a configure event without the "maximized" + state. If available, the compositor will include the window geometry + dimensions the window had prior to being maximized in the configure + request. The client must then update its content, drawing it in a + regular state, i.e. potentially with shadow, etc. The client must also + acknowledge the configure when committing the new content (see + ack_configure). + + It is up to the compositor to position the surface after it was + unmaximized; usually the position the surface had before maximizing, if + applicable. + + If the surface was already not maximized, the compositor will still + emit a configure event without the "maximized" state. + + + + + + Make the surface fullscreen. + + You can specify an output that you would prefer to be fullscreen. + If this value is NULL, it's up to the compositor to choose which + display will be used to map this surface. + + If the surface doesn't cover the whole output, the compositor will + position the surface in the center of the output and compensate with + black borders filling the rest of the output. + + + + + + + + Request that the compositor minimize your surface. There is no + way to know if the surface is currently minimized, nor is there + any way to unset minimization on this surface. + + If you are looking to throttle redrawing when minimized, please + instead use the wl_surface.frame event for this, as this will + also work with live previews on windows in Alt-Tab, Expose or + similar compositor features. + + + + + + The close event is sent by the compositor when the user + wants the surface to be closed. This should be equivalent to + the user clicking the close button in client-side decorations, + if your application has any... + + This is only a request that the user intends to close your + window. The client may choose to ignore this request, or show + a dialog to ask the user to save their data... + + + + + + + A popup surface is a short-lived, temporary surface that can be + used to implement menus. It takes an explicit grab on the surface + that will be dismissed when the user dismisses the popup. This can + be done by the user clicking outside the surface, using the keyboard, + or even locking the screen through closing the lid or a timeout. + + When the popup is dismissed, a popup_done event will be sent out, + and at the same time the surface will be unmapped. The xdg_popup + object is now inert and cannot be reactivated, so clients should + destroy it. Explicitly destroying the xdg_popup object will also + dismiss the popup and unmap the surface. + + Clients will receive events for all their surfaces during this + grab (which is an "owner-events" grab in X11 parlance). This is + done so that users can navigate through submenus and other + "nested" popup windows without having to dismiss the topmost + popup. + + Clients that want to dismiss the popup when another surface of + their own is clicked should dismiss the popup using the destroy + request. + + The parent surface must have either an xdg_surface or xdg_popup + role. + + Specifying an xdg_popup for the parent means that the popups are + nested, with this popup now being the topmost popup. Nested + popups must be destroyed in the reverse order they were created + in, e.g. the only popup you are allowed to destroy at all times + is the topmost one. + + If there is an existing popup when creating a new popup, the + parent must be the current topmost popup. + + A parent surface must be mapped before the new popup is mapped. + + When compositors choose to dismiss a popup, they will likely + dismiss every nested popup as well. When a compositor dismisses + popups, it will follow the same dismissing order as required + from the client. + + The x and y arguments passed when creating the popup object specify + where the top left of the popup should be placed, relative to the + local surface coordinates of the parent surface. See + xdg_shell.get_xdg_popup. + + The client must call wl_surface.commit on the corresponding wl_surface + for the xdg_popup state to take effect. + + For a surface to be mapped by the compositor the client must have + committed both the xdg_popup state and a buffer. + + + + + This destroys the popup. Explicitly destroying the xdg_popup + object will also dismiss the popup, and unmap the surface. + + If this xdg_popup is not the "topmost" popup, a protocol error + will be sent. + + + + + + The popup_done event is sent out when a popup is dismissed by the + compositor. The client should destroy the xdg_popup object at this + point. + + + + + diff --git a/uwac/uwac.pc.in b/uwac/uwac.pc.in new file mode 100644 index 000000000..66b477e98 --- /dev/null +++ b/uwac/uwac.pc.in @@ -0,0 +1,15 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=${prefix}/@UWAC_INCLUDE_DIR@ +libs=-luwac + +Name: uwac +Description: uwac: using wayland as a client +URL: http://www.freerdp.com/ +Version: @UWAC_VERSION@ +Requires: +Requires.private: wayland-client xkbcommon freerdp@FREERDP_VERSION_MAJOR@ +Libs: -L${libdir} ${libs} +Libs.private: +Cflags: -I${includedir} diff --git a/uwac/uwacConfig.cmake.in b/uwac/uwacConfig.cmake.in new file mode 100644 index 000000000..2433842e9 --- /dev/null +++ b/uwac/uwacConfig.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + +set(UWAC_VERSION_MAJOR "@UWAC_VERSION_MAJOR@") +set(UWAC_VERSION_MINOR "@UWAC_VERSION_MINOR@") +set(UWAC_VERSION_REVISION "@UWAC_VERSION_REVISION@") + +set_and_check(UWAC_INCLUDE_DIR "@PACKAGE_UWAC_INCLUDE_DIR@") + +include("${CMAKE_CURRENT_LIST_DIR}/uwac.cmake") diff --git a/uwac/uwacVersion.cmake b/uwac/uwacVersion.cmake new file mode 100644 index 000000000..2a789d7d0 --- /dev/null +++ b/uwac/uwacVersion.cmake @@ -0,0 +1,46 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "0.0.1") + +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if("0.0.1" MATCHES "^([0-9]+)\\.") + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + else() + set(CVF_VERSION_MAJOR "0.0.1") + endif() + + if("${PACKAGE_FIND_VERSION_MAJOR}" STREQUAL "${CVF_VERSION_MAJOR}") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() + + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index d3bb446fb..ae5280e2c 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -48,8 +48,8 @@ include(GNUInstallDirsWrapper) include(CMakePackageConfigHelpers) # Soname versioning -set(WINPR_VERSION_MAJOR "1") -set(WINPR_VERSION_MINOR "1") +set(WINPR_VERSION_MAJOR "2") +set(WINPR_VERSION_MINOR "0") set(WINPR_VERSION_REVISION "0") set(WINPR_VERSION "${WINPR_VERSION_MAJOR}.${WINPR_VERSION_MINOR}.${WINPR_VERSION_REVISION}") set(WINPR_VERSION_FULL "${WINPR_VERSION}") @@ -66,6 +66,7 @@ endif(NOT IOS) if(FREERDP_BUILD) set(WINPR_VERSION_FULL ${WINPR_VERSION_FULL} PARENT_SCOPE) set(WINPR_VERSION ${WINPR_VERSION} PARENT_SCOPE) + set(WINPR_API_VERSION ${WINPR_API_VERSION} PARENT_SCOPE) else() set(CMAKE_THREAD_PREFER_PTHREAD TRUE) diff --git a/winpr/include/winpr/comm.h b/winpr/include/winpr/comm.h index 6f0a23077..d4a33b3dd 100644 --- a/winpr/include/winpr/comm.h +++ b/winpr/include/winpr/comm.h @@ -523,37 +523,37 @@ static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] = /** * FIXME: got a proper function name and place */ -const char* _comm_serial_ioctl_name(ULONG number); +WINPR_API const char* _comm_serial_ioctl_name(ULONG number); /** * FIXME: got a proper function name and place */ -void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID); +WINPR_API void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID); /** * FIXME: got a proper function name and place * * permissive mode is disabled by default. */ -BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive); +WINPR_API BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive); /** * FIXME: to be moved in comm_ioctl.h */ -BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, +WINPR_API BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); /** * FIXME: to be moved in comm_io.h */ -BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, +WINPR_API BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); /** * FIXME: to be moved in comm_io.h */ -BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, +WINPR_API BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); #ifdef __cplusplus diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index 7754700dd..7e05124f6 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.h @@ -500,9 +500,9 @@ WINPR_API PCCERT_CONTEXT CertFindCertificateInStore(HCERTSTORE hCertStore, DWORD WINPR_API PCCERT_CONTEXT CertEnumCertificatesInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext); -DWORD CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, +WINPR_API DWORD CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void* pvTypePara, LPWSTR pszNameString, DWORD cchNameString); -DWORD CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType, +WINPR_API DWORD CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void* pvTypePara, LPSTR pszNameString, DWORD cchNameString); #ifdef __cplusplus @@ -642,14 +642,16 @@ union _WINPR_MD5_CTX }; typedef union _WINPR_MD5_CTX WINPR_MD5_CTX; +#define WINPR_MD5_DIGEST_LENGTH 16 + #ifdef __cplusplus extern "C" { #endif -WINPR_API void winpr_MD5_Init(WINPR_MD5_CTX* ctx); -WINPR_API void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const BYTE* input, size_t ilen); -WINPR_API void winpr_MD5_Final(WINPR_MD5_CTX* ctx, BYTE* output); -WINPR_API void winpr_MD5(const BYTE* input, size_t ilen, BYTE* output); +WINPR_API BOOL winpr_MD5_Init(WINPR_MD5_CTX* ctx); +WINPR_API BOOL winpr_MD5_Update(WINPR_MD5_CTX* ctx, const BYTE* input, size_t ilen); +WINPR_API BOOL winpr_MD5_Final(WINPR_MD5_CTX* ctx, BYTE* output, size_t ilen); +WINPR_API BOOL winpr_MD5(const BYTE* input, size_t ilen, BYTE* output, size_t olen); #ifdef __cplusplus } @@ -683,14 +685,16 @@ union _WINPR_MD4_CTX }; typedef union _WINPR_MD4_CTX WINPR_MD4_CTX; +#define WINPR_MD4_DIGEST_LENGTH 16 + #ifdef __cplusplus extern "C" { #endif -WINPR_API void winpr_MD4_Init(WINPR_MD4_CTX* ctx); -WINPR_API void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const BYTE* input, size_t ilen); -WINPR_API void winpr_MD4_Final(WINPR_MD4_CTX* ctx, BYTE* output); -WINPR_API void winpr_MD4(const BYTE* input, size_t ilen, BYTE* output); +WINPR_API BOOL winpr_MD4_Init(WINPR_MD4_CTX* ctx); +WINPR_API BOOL winpr_MD4_Update(WINPR_MD4_CTX* ctx, const BYTE* input, size_t ilen); +WINPR_API BOOL winpr_MD4_Final(WINPR_MD4_CTX* ctx, BYTE* output, size_t ilen); +WINPR_API BOOL winpr_MD4(const BYTE* input, size_t ilen, BYTE* output, size_t olen); #ifdef __cplusplus } @@ -700,6 +704,8 @@ WINPR_API void winpr_MD4(const BYTE* input, size_t ilen, BYTE* output); * SHA1 Hashing */ +#define WINPR_SHA1_DIGEST_LENGTH 20 + struct _OPENSSL_SHA1_CTX { UINT32 h0, h1, h2, h3, h4; @@ -728,10 +734,10 @@ typedef union _WINPR_SHA1_CTX WINPR_SHA1_CTX; extern "C" { #endif -WINPR_API void winpr_SHA1_Init(WINPR_SHA1_CTX* ctx); -WINPR_API void winpr_SHA1_Update(WINPR_SHA1_CTX* ctx, const BYTE* input, size_t ilen); -WINPR_API void winpr_SHA1_Final(WINPR_SHA1_CTX* ctx, BYTE* output); -WINPR_API void winpr_SHA1(const BYTE* input, size_t ilen, BYTE* output); +WINPR_API BOOL winpr_SHA1_Init(WINPR_SHA1_CTX* ctx); +WINPR_API BOOL winpr_SHA1_Update(WINPR_SHA1_CTX* ctx, const BYTE* input, size_t ilen); +WINPR_API BOOL winpr_SHA1_Final(WINPR_SHA1_CTX* ctx, BYTE* output, size_t ilen); +WINPR_API BOOL winpr_SHA1(const BYTE* input, size_t ilen, BYTE* output, size_t olen); #ifdef __cplusplus } @@ -740,17 +746,19 @@ WINPR_API void winpr_SHA1(const BYTE* input, size_t ilen, BYTE* output); /** * HMAC */ - -#define WINPR_MD_NONE 0 -#define WINPR_MD_MD2 1 -#define WINPR_MD_MD4 2 -#define WINPR_MD_MD5 3 -#define WINPR_MD_SHA1 4 -#define WINPR_MD_SHA224 5 -#define WINPR_MD_SHA256 6 -#define WINPR_MD_SHA384 7 -#define WINPR_MD_SHA512 8 -#define WINPR_MD_RIPEMD160 9 +typedef enum +{ + WINPR_MD_NONE = 0, + WINPR_MD_MD2 = 1, + WINPR_MD_MD4 = 2, + WINPR_MD_MD5 = 3, + WINPR_MD_SHA1 = 4, + WINPR_MD_SHA224 = 5, + WINPR_MD_SHA256 = 6, + WINPR_MD_SHA384 = 7, + WINPR_MD_SHA512 = 8, + WINPR_MD_RIPEMD160 = 9 +} WINPR_MD_TYPE; struct _OPENSSL_EVP_MD_CTX { @@ -793,10 +801,11 @@ typedef union _WINPR_HMAC_CTX WINPR_HMAC_CTX; extern "C" { #endif -WINPR_API int winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, int md, const BYTE* key, size_t keylen); -WINPR_API int winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen); -WINPR_API int winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output); -WINPR_API int winpr_HMAC(int md, const BYTE* key, size_t keylen, const BYTE* input, size_t ilen, BYTE* output); +WINPR_API BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, size_t keylen); +WINPR_API BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen); +WINPR_API BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t ilen); +WINPR_API BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, + const BYTE* input, size_t ilen, BYTE* output, size_t olen); #ifdef __cplusplus } @@ -838,10 +847,10 @@ typedef union _WINPR_DIGEST_CTX WINPR_DIGEST_CTX; extern "C" { #endif -WINPR_API int winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, int md); -WINPR_API int winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen); -WINPR_API int winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output); -WINPR_API int winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output); +WINPR_API BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); +WINPR_API BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen); +WINPR_API BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t ilen); +WINPR_API BOOL winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen); #ifdef __cplusplus } @@ -892,9 +901,9 @@ typedef union _WINPR_RC4_CTX WINPR_RC4_CTX; extern "C" { #endif -WINPR_API void winpr_RC4_Init(WINPR_RC4_CTX* ctx, const BYTE* key, size_t keylen); -WINPR_API int winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output); -WINPR_API void winpr_RC4_Final(WINPR_RC4_CTX* ctx); +WINPR_API WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen); +WINPR_API BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output); +WINPR_API void winpr_RC4_Free(WINPR_RC4_CTX* ctx); #ifdef __cplusplus } @@ -904,6 +913,8 @@ WINPR_API void winpr_RC4_Final(WINPR_RC4_CTX* ctx); * Generic Cipher API */ +#define WINPR_AES_BLOCK_SIZE 16 + /* cipher operation types */ #define WINPR_ENCRYPT 0 #define WINPR_DECRYPT 1 @@ -1007,9 +1018,10 @@ typedef union _WINPR_CIPHER_CTX WINPR_CIPHER_CTX; extern "C" { #endif -WINPR_API int winpr_Cipher_Init(WINPR_CIPHER_CTX* ctx, int cipher, int op, const BYTE* key, const BYTE* iv); -WINPR_API int winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const BYTE* input, size_t ilen, BYTE* output, size_t* olen); -WINPR_API int winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, BYTE* output, size_t* olen); +WINPR_API WINPR_CIPHER_CTX* winpr_Cipher_New(int cipher, int op, const BYTE* key, const BYTE* iv); +WINPR_API BOOL winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const BYTE* input, size_t ilen, BYTE* output, size_t* olen); +WINPR_API BOOL winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, BYTE* output, size_t* olen); +WINPR_API void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx); #ifdef __cplusplus } diff --git a/winpr/include/winpr/error.h b/winpr/include/winpr/error.h index e84b8f7bc..0a1511b0f 100644 --- a/winpr/include/winpr/error.h +++ b/winpr/include/winpr/error.h @@ -518,6 +518,7 @@ #define ERROR_DEVICE_ENUMERATION_ERROR 0x00000288 #define ERROR_MOUNT_POINT_NOT_RESOLVED 0x00000289 #define ERROR_INVALID_DEVICE_OBJECT_PARAMETER 0x0000028A +/* The following is not a typo. It's the same spelling as in the Microsoft headers */ #define ERROR_MCA_OCCURED 0x0000028B #define ERROR_DRIVER_DATABASE_ERROR 0x0000028C #define ERROR_SYSTEM_HIVE_TOO_LARGE 0x0000028D diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index f0129e212..386705e2c 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -288,6 +288,9 @@ WINPR_API BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffse WINPR_API BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped); +WINPR_API BOOL SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime); + WINPR_API HANDLE FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData); WINPR_API HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData); diff --git a/winpr/include/winpr/input.h b/winpr/include/winpr/input.h index 6779f30fa..36918847f 100644 --- a/winpr/include/winpr/input.h +++ b/winpr/include/winpr/input.h @@ -80,8 +80,9 @@ #define VK_HANJA 0x19 /* IME Hanja mode */ #define VK_KANJI 0x19 /* IME Kanji mode */ -/* 0x1A is undefined */ +/* 0x1A is undefined, use it for missing Hiragana/Katakana Toggle */ +#define VK_HKTG 0x1A /* Hiragana/Katakana toggle */ #define VK_ESCAPE 0x1B /* ESC key */ #define VK_CONVERT 0x1C /* IME convert */ #define VK_NONCONVERT 0x1D /* IME nonconvert */ @@ -555,7 +556,7 @@ #define KBD7_T0A VK_KEY_9 #define KBD7_T0B VK_KEY_0 #define KBD7_T0C VK_OEM_MINUS -#define KBD7_T0D VK_OEM_7 /* NE */ +#define KBD7_T0D VK_OEM_PLUS #define KBD7_T0E VK_BACK #define KBD7_T0F VK_TAB #define KBD7_T10 VK_KEY_Q @@ -581,8 +582,8 @@ #define KBD7_T24 VK_KEY_J #define KBD7_T25 VK_KEY_K #define KBD7_T26 VK_KEY_L -#define KBD7_T27 VK_OEM_PLUS /* NE */ -#define KBD7_T28 VK_OEM_1 /* NE */ +#define KBD7_T27 VK_OEM_1 +#define KBD7_T28 VK_OEM_7 #define KBD7_T29 VK_OEM_3 /* NE */ #define KBD7_T2A VK_LSHIFT #define KBD7_T2B VK_OEM_5 /* NE */ @@ -600,7 +601,7 @@ #define KBD7_T37 VK_MULTIPLY #define KBD7_T38 VK_LMENU #define KBD7_T39 VK_SPACE -#define KBD7_T3A VK_DBE_ALPHANUMERIC /* NE */ +#define KBD7_T3A VK_CAPITAL #define KBD7_T3B VK_F1 #define KBD7_T3C VK_F2 #define KBD7_T3D VK_F3 @@ -613,22 +614,22 @@ #define KBD7_T44 VK_F10 #define KBD7_T45 VK_NUMLOCK #define KBD7_T46 VK_SCROLL -#define KBD7_T47 VK_HOME -#define KBD7_T48 VK_UP -#define KBD7_T49 VK_PRIOR +#define KBD7_T47 VK_NUMPAD7 /* VK_HOME */ +#define KBD7_T48 VK_NUMPAD8 /* VK_UP */ +#define KBD7_T49 VK_NUMPAD9 /* VK_PRIOR */ #define KBD7_T4A VK_SUBTRACT -#define KBD7_T4B VK_LEFT -#define KBD7_T4C VK_CLEAR -#define KBD7_T4D VK_RIGHT +#define KBD7_T4B VK_NUMPAD4 /* VK_LEFT */ +#define KBD7_T4C VK_NUMPAD5 /* VK_CLEAR */ +#define KBD7_T4D VK_NUMPAD6 /* VK_RIGHT */ #define KBD7_T4E VK_ADD -#define KBD7_T4F VK_END -#define KBD7_T50 VK_DOWN -#define KBD7_T51 VK_NEXT -#define KBD7_T52 VK_INSERT -#define KBD7_T53 VK_DELETE +#define KBD7_T4F VK_NUMPAD1 /* VK_END */ +#define KBD7_T50 VK_NUMPAD2 /* VK_DOWN */ +#define KBD7_T51 VK_NUMPAD3 /* VK_NEXT */ +#define KBD7_T52 VK_NUMPAD0 /* VK_INSERT */ +#define KBD7_T53 VK_DECIMAL /* VK_DELETE */ #define KBD7_T54 VK_SNAPSHOT #define KBD7_T55 VK_NONE -#define KBD7_T56 VK_NONE /* NE */ +#define KBD7_T56 VK_OEM_102 #define KBD7_T57 VK_F11 #define KBD7_T58 VK_F12 #define KBD7_T59 VK_CLEAR @@ -654,27 +655,27 @@ #define KBD7_T6D VK_F22 #define KBD7_T6E VK_F23 #define KBD7_T6F VK_NONE /* NE */ -#define KBD7_T70 VK_DBE_KATAKANA /* NE */ +#define KBD7_T70 VK_HKTG /* NE */ #define KBD7_T71 VK_NONE /* NE */ #define KBD7_T72 VK_NONE -#define KBD7_T73 VK_OEM_102 /* NE */ +#define KBD7_T73 VK_ABNT_C1 #define KBD7_T74 VK_NONE #define KBD7_T75 VK_NONE #define KBD7_T76 VK_F24 -#define KBD7_T77 VK_DBE_SBCSCHAR /* NE */ +#define KBD7_T77 VK_NONE #define KBD7_T78 VK_NONE #define KBD7_T79 VK_CONVERT /* NE */ #define KBD7_T7A VK_NONE #define KBD7_T7B VK_NONCONVERT /* NE */ #define KBD7_T7C VK_TAB -#define KBD7_T7D VK_NONE /* NE */ +#define KBD7_T7D VK_OEM_8 #define KBD7_T7E VK_ABNT_C2 #define KBD7_T7F VK_OEM_PA2 #define KBD7_X10 VK_MEDIA_PREV_TRACK #define KBD7_X19 VK_MEDIA_NEXT_TRACK #define KBD7_X1C VK_RETURN -#define KBD7_X1D VK_RCONTROL /* NE */ +#define KBD7_X1D VK_RCONTROL #define KBD7_X20 VK_VOLUME_MUTE #define KBD7_X21 VK_LAUNCH_APP2 #define KBD7_X22 VK_MEDIA_PLAY_PAUSE @@ -682,10 +683,10 @@ #define KBD7_X2E VK_VOLUME_DOWN #define KBD7_X30 VK_VOLUME_UP #define KBD7_X32 VK_BROWSER_HOME -#define KBD7_X33 VK_OEM_8 /* NE */ +#define KBD7_X33 VK_NONE #define KBD7_X35 VK_DIVIDE #define KBD7_X37 VK_SNAPSHOT -#define KBD7_X38 VK_DBE_HIRAGANA /* NE */ +#define KBD7_X38 VK_RMENU #define KBD7_X42 VK_NONE #define KBD7_X43 VK_NONE #define KBD7_X44 VK_NONE diff --git a/winpr/include/winpr/nt.h b/winpr/include/winpr/nt.h index 29263d885..95693cc9b 100644 --- a/winpr/include/winpr/nt.h +++ b/winpr/include/winpr/nt.h @@ -962,6 +962,7 @@ #define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS)0x00000367) #define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS)0xC0000368) #define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS)0xC0000369) +/* The following is not a typo. It's the same spelling as in the Microsoft headers */ #define STATUS_MCA_OCCURED ((NTSTATUS)0xC000036A) #define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS)0xC000036B) #define STATUS_DRIVER_BLOCKED ((NTSTATUS)0xC000036C) diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index 2e9f89f27..7571a1380 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -50,35 +50,51 @@ WINPR_API BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size); WINPR_API wStream* Stream_New(BYTE* buffer, size_t size); WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); -#define _stream_read_n8(_t, _s, _v, _p) do { _v = \ - (_t)(*_s->pointer); \ - _s->pointer += _p; } while (0) +static INLINE void Stream_Seek(wStream* s, size_t _offset) +{ + s->pointer += (_offset); +} -#define _stream_read_n16_le(_t, _s, _v, _p) do { _v = \ +static INLINE void Stream_Rewind(wStream* s, size_t _offset) +{ + s->pointer -= (_offset); +} + +#define _stream_read_n8(_t, _s, _v, _p) do { \ + _v = \ + (_t)(*_s->pointer); \ + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) + +#define _stream_read_n16_le(_t, _s, _v, _p) do { \ + _v = \ (_t)(*_s->pointer) + \ (((_t)(*(_s->pointer + 1))) << 8); \ - if (_p) _s->pointer += 2; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n16_be(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n16_be(_t, _s, _v, _p) do { \ + _v = \ (((_t)(*_s->pointer)) << 8) + \ (_t)(*(_s->pointer + 1)); \ - if (_p) _s->pointer += 2; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n32_le(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n32_le(_t, _s, _v, _p) do { \ + _v = \ (_t)(*_s->pointer) + \ (((_t)(*(_s->pointer + 1))) << 8) + \ (((_t)(*(_s->pointer + 2))) << 16) + \ (((_t)(*(_s->pointer + 3))) << 24); \ - if (_p) _s->pointer += 4; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n32_be(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n32_be(_t, _s, _v, _p) do { \ + _v = \ (((_t)(*(_s->pointer))) << 24) + \ (((_t)(*(_s->pointer + 1))) << 16) + \ (((_t)(*(_s->pointer + 2))) << 8) + \ (((_t)(*(_s->pointer + 3)))); \ - if (_p) _s->pointer += 4; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n64_le(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n64_le(_t, _s, _v, _p) do { \ + _v = \ (_t)(*_s->pointer) + \ (((_t)(*(_s->pointer + 1))) << 8) + \ (((_t)(*(_s->pointer + 2))) << 16) + \ @@ -87,9 +103,10 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); (((_t)(*(_s->pointer + 5))) << 40) + \ (((_t)(*(_s->pointer + 6))) << 48) + \ (((_t)(*(_s->pointer + 7))) << 56); \ - if (_p) _s->pointer += 8; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) -#define _stream_read_n64_be(_t, _s, _v, _p) do { _v = \ +#define _stream_read_n64_be(_t, _s, _v, _p) do { \ + _v = \ (((_t)(*(_s->pointer))) << 56) + \ (((_t)(*(_s->pointer + 1))) << 48) + \ (((_t)(*(_s->pointer + 2))) << 40) + \ @@ -98,102 +115,108 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); (((_t)(*(_s->pointer + 5))) << 16) + \ (((_t)(*(_s->pointer + 6))) << 8) + \ (((_t)(*(_s->pointer + 7)))); \ - if (_p) _s->pointer += 8; } while (0) + if (_p) Stream_Seek(_s, sizeof(_t)); } while (0) +#define Stream_Read_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, TRUE) +#define Stream_Read_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, TRUE) -#define Stream_Read_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, 1) -#define Stream_Read_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, 1) +#define Stream_Read_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, TRUE) +#define Stream_Read_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, TRUE) -#define Stream_Read_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, 1) -#define Stream_Read_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, 1) +#define Stream_Read_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, TRUE) +#define Stream_Read_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, TRUE) -#define Stream_Read_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, 1) -#define Stream_Read_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, 1) +#define Stream_Read_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, TRUE) +#define Stream_Read_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, TRUE) -#define Stream_Read_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, 1) -#define Stream_Read_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, 1) +#define Stream_Read_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, TRUE) +#define Stream_Read_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, TRUE) -#define Stream_Read_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, 1) -#define Stream_Read_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, 1) +#define Stream_Read_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, TRUE) +#define Stream_Read_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, TRUE) -#define Stream_Read_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, 1) -#define Stream_Read_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, 1) +#define Stream_Read_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, TRUE) +#define Stream_Read_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, TRUE) -#define Stream_Read_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, 1) -#define Stream_Read_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, 1) +static INLINE void Stream_Read(wStream* _s, void* _b, size_t _n) +{ + memcpy(_b, (_s->pointer), (_n)); + Stream_Seek(_s, _n); +} -#define Stream_Read(_s, _b, _n) do { \ - memcpy(_b, (_s->pointer), (_n)); \ - _s->pointer += (_n); \ - } while (0) +#define Stream_Peek_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, FALSE) +#define Stream_Peek_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, FALSE) +#define Stream_Peek_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, FALSE) +#define Stream_Peek_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, FALSE) -#define Stream_Peek_UINT8(_s, _v) _stream_read_n8(UINT8, _s, _v, 0) -#define Stream_Peek_INT8(_s, _v) _stream_read_n8(INT8, _s, _v, 0) +#define Stream_Peek_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, FALSE) +#define Stream_Peek_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, FALSE) -#define Stream_Peek_UINT16(_s, _v) _stream_read_n16_le(UINT16, _s, _v, 0) -#define Stream_Peek_INT16(_s, _v) _stream_read_n16_le(INT16, _s, _v, 0) +#define Stream_Peek_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, FALSE) +#define Stream_Peek_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, FALSE) -#define Stream_Peek_UINT16_BE(_s, _v) _stream_read_n16_be(UINT16, _s, _v, 0) -#define Stream_Peek_INT16_BE(_s, _v) _stream_read_n16_be(INT16, _s, _v, 0) +#define Stream_Peek_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, FALSE) +#define Stream_Peek_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, FALSE) -#define Stream_Peek_UINT32(_s, _v) _stream_read_n32_le(UINT32, _s, _v, 0) -#define Stream_Peek_INT32(_s, _v) _stream_read_n32_le(INT32, _s, _v, 0) +#define Stream_Peek_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, FALSE) +#define Stream_Peek_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, FALSE) -#define Stream_Peek_UINT32_BE(_s, _v) _stream_read_n32_be(UINT32, _s, _v, 0) -#define Stream_Peek_INT32_BE(_s, _v) _stream_read_n32_be(INT32, _s, _v, 0) +#define Stream_Peek_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, FALSE) +#define Stream_Peek_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, FALSE) -#define Stream_Peek_UINT64(_s, _v) _stream_read_n64_le(UINT64, _s, _v, 0) -#define Stream_Peek_INT64(_s, _v) _stream_read_n64_le(INT64, _s, _v, 0) +static INLINE void Stream_Peek(wStream* _s, void* _b, size_t _n) +{ + memcpy(_b, (_s->pointer), (_n)); +} -#define Stream_Peek_UINT64_BE(_s, _v) _stream_read_n64_be(UINT64, _s, _v, 0) -#define Stream_Peek_INT64_BE(_s, _v) _stream_read_n64_be(INT64, _s, _v, 0) +static INLINE void Stream_Write_UINT8(wStream* _s, UINT8 _v) +{ + *_s->pointer++ = (UINT8)(_v); +} -#define Stream_Peek(_s, _b, _n) do { \ - memcpy(_b, (_s->pointer), (_n)); \ - } while (0) +static INLINE void Stream_Write_UINT16(wStream* _s, UINT16 _v) +{ + *_s->pointer++ = (_v) & 0xFF; + *_s->pointer++ = ((_v) >> 8) & 0xFF; +} +static INLINE void Stream_Write_UINT16_BE(wStream* _s, UINT16 _v) +{ + *_s->pointer++ = ((_v) >> 8) & 0xFF; + *_s->pointer++ = (_v) & 0xFF; +} -#define Stream_Write_UINT8(_s, _v) do { \ - *_s->pointer++ = (UINT8)(_v); } while (0) +static INLINE void Stream_Write_UINT32(wStream* _s, UINT32 _v) +{ + *_s->pointer++ = (_v) & 0xFF; + *_s->pointer++ = ((_v) >> 8) & 0xFF; + *_s->pointer++ = ((_v) >> 16) & 0xFF; + *_s->pointer++ = ((_v) >> 24) & 0xFF; +} -#define Stream_Write_UINT16(_s, _v) do { \ - *_s->pointer++ = (_v) & 0xFF; \ - *_s->pointer++ = ((_v) >> 8) & 0xFF; } while (0) +static INLINE void Stream_Write_UINT32_BE(wStream* _s, UINT32 _v) +{ + Stream_Write_UINT16_BE(_s, ((_v) >> 16 & 0xFFFF)); + Stream_Write_UINT16_BE(_s, ((_v) & 0xFFFF)); +} -#define Stream_Write_UINT16_BE(_s, _v) do { \ - *_s->pointer++ = ((_v) >> 8) & 0xFF; \ - *_s->pointer++ = (_v) & 0xFF; } while (0) - -#define Stream_Write_UINT32(_s, _v) do { \ - *_s->pointer++ = (_v) & 0xFF; \ - *_s->pointer++ = ((_v) >> 8) & 0xFF; \ - *_s->pointer++ = ((_v) >> 16) & 0xFF; \ - *_s->pointer++ = ((_v) >> 24) & 0xFF; } while (0) - -#define Stream_Write_UINT32_BE(_s, _v) do { \ - Stream_Write_UINT16_BE(_s, ((_v) >> 16 & 0xFFFF)); \ - Stream_Write_UINT16_BE(_s, ((_v) & 0xFFFF)); \ - } while (0) - -#define Stream_Write_UINT64(_s, _v) do { \ - *_s->pointer++ = (UINT64)(_v) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 8) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 16) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 24) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 32) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 40) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 48) & 0xFF; \ - *_s->pointer++ = ((UINT64)(_v) >> 56) & 0xFF; } while (0) - -#define Stream_Write(_s, _b, _n) do { \ - memcpy(_s->pointer, (_b), (_n)); \ - _s->pointer += (_n); \ - } while (0) - - -#define Stream_Seek(_s,_offset) _s->pointer += (_offset) -#define Stream_Rewind(_s,_offset) _s->pointer -= (_offset) +static INLINE void Stream_Write_UINT64(wStream* _s, UINT64 _v) +{ + *_s->pointer++ = (UINT64)(_v) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 8) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 16) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 24) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 32) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 40) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 48) & 0xFF; + *_s->pointer++ = ((UINT64)(_v) >> 56) & 0xFF; +} +static INLINE void Stream_Write(wStream* _s, const void* _b, size_t _n) +{ + memcpy(_s->pointer, (_b), (_n)); + Stream_Seek(_s, _n); +} #define Stream_Seek_UINT8(_s) Stream_Seek(_s, 1) #define Stream_Seek_UINT16(_s) Stream_Seek(_s, 2) @@ -205,45 +228,93 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); #define Stream_Rewind_UINT32(_s) Stream_Rewind(_s, 4) #define Stream_Rewind_UINT64(_s) Stream_Rewind(_s, 8) -#define Stream_Zero(_s, _n) do { \ - memset(_s->pointer, '\0', (_n)); \ - _s->pointer += (_n); \ - } while (0) +static INLINE void Stream_Zero(wStream* _s, size_t _n) +{ + memset(_s->pointer, '\0', (_n)); + Stream_Seek(_s, _n); +} -#define Stream_Fill(_s, _v, _n) do { \ - memset(_s->pointer, _v, (_n)); \ - _s->pointer += (_n); \ - } while (0) +static INLINE void Stream_Fill(wStream* _s, int _v, size_t _n) +{ + memset(_s->pointer, _v, (_n)); + Stream_Seek(_s, _n); +} -#define Stream_Copy(_dst, _src, _n) do { \ - memcpy(_dst->pointer, _src->pointer, _n); \ - _dst->pointer += _n; \ - _src->pointer += _n; \ - } while (0) +static INLINE void Stream_Copy(wStream* _src, wStream* _dst, size_t _n) +{ + memcpy(_dst->pointer, _src->pointer, _n); + Stream_Seek(_dst, _n); + Stream_Seek(_src, _n); +} -#define Stream_Buffer(_s) _s->buffer -#define Stream_GetBuffer(_s, _b) _b = _s->buffer -#define Stream_SetBuffer(_s, _b) _s->buffer = _b +static INLINE BYTE* Stream_Buffer(wStream* _s) +{ + return _s->buffer; +} -#define Stream_Pointer(_s) _s->pointer -#define Stream_GetPointer(_s, _p) _p = _s->pointer -#define Stream_SetPointer(_s, _p) _s->pointer = _p +#define Stream_GetBuffer(_s, _b) _b = Stream_Buffer(_s) +static INLINE void Stream_SetBuffer(wStream* _s, BYTE* _b) +{ + _s->buffer = _b; +} -#define Stream_Length(_s) _s->length -#define Stream_GetLength(_s, _l) _l = _s->length -#define Stream_SetLength(_s, _l) _s->length = _l +static INLINE BYTE* Stream_Pointer(wStream* _s) +{ + return _s->pointer; +} -#define Stream_Capacity(_s) _s->capacity -#define Stream_GetCapacity(_s, _c) _c = _s->capacity -#define Stream_SetCapacity(_s, _c) _s->capacity = _c +#define Stream_GetPointer(_s, _p) _p = Stream_Pointer(_s) +static INLINE void Stream_SetPointer(wStream* _s, BYTE* _p) +{ + _s->pointer = _p; +} -#define Stream_GetPosition(_s) (_s->pointer - _s->buffer) -#define Stream_SetPosition(_s, _p) _s->pointer = _s->buffer + (_p) +static INLINE size_t Stream_Length(wStream* _s) +{ + return _s->length; +} -#define Stream_SealLength(_s) _s->length = (_s->pointer - _s->buffer) -#define Stream_GetRemainingLength(_s) (_s->length - (_s->pointer - _s->buffer)) +#define Stream_GetLength(_s, _l) _l = Stream_Length(_s) +static INLINE void Stream_SetLength(wStream* _s, size_t _l) +{ + _s->length = _l; +} -#define Stream_Clear(_s) memset(_s->buffer, 0, _s->capacity) +static INLINE size_t Stream_Capacity(wStream* _s) +{ + return _s->capacity; +} + +#define Stream_GetCapacity(_s, _c) _c = Stream_Capacity(_s); +static INLINE void Stream_SetCapacity(wStream* _s, size_t _c) +{ + _s->capacity = _c; +} + +static INLINE size_t Stream_GetPosition(wStream* _s) +{ + return (_s->pointer - _s->buffer); +} + +static INLINE void Stream_SetPosition(wStream* _s, size_t _p) +{ + _s->pointer = _s->buffer + (_p); +} + +static INLINE void Stream_SealLength(wStream* _s) +{ + _s->length = (_s->pointer - _s->buffer); +} + +static INLINE size_t Stream_GetRemainingLength(wStream* _s) +{ + return (_s->length - (_s->pointer - _s->buffer)); +} + +static INLINE void Stream_Clear(wStream* _s) +{ + memset(_s->buffer, 0, _s->capacity); +} static INLINE BOOL Stream_SafeSeek(wStream* s, size_t size) { if (Stream_GetRemainingLength(s) < size) diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index aef0ef1b4..c71a063b0 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -197,6 +197,8 @@ WINPR_API char* ConvertLineEndingToCRLF(const char* str, int* size); WINPR_API char* StrSep(char** stringp, const char* delim); +WINPR_API INT64 GetLine(char** lineptr, size_t* size, FILE* stream); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/user.h b/winpr/include/winpr/user.h index 59afbb2db..0e9a62802 100644 --- a/winpr/include/winpr/user.h +++ b/winpr/include/winpr/user.h @@ -51,6 +51,7 @@ #define IDTIMEOUT 32000 #define IDASYNC 32001 +#define CF_RAW 0 #define CF_TEXT 1 #define CF_BITMAP 2 #define CF_METAFILEPICT 3 diff --git a/winpr/include/winpr/wtypes.h.in b/winpr/include/winpr/wtypes.h.in index 1bfa553a8..93543f9af 100644 --- a/winpr/include/winpr/wtypes.h.in +++ b/winpr/include/winpr/wtypes.h.in @@ -285,7 +285,7 @@ typedef void *PVOID64, *LPVOID64; #if WINPR_HAVE_STDINT_H typedef intptr_t INT_PTR; typedef uintptr_t UINT_PTR; -#elif __x86_64__ +#elif defined (__x86_64__) typedef __int64 INT_PTR; typedef unsigned __int64 UINT_PTR; #else diff --git a/winpr/libwinpr/asn1/module.def b/winpr/libwinpr/asn1/module.def deleted file mode 100644 index eba1a913a..000000000 --- a/winpr/libwinpr/asn1/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-asn1" -EXPORTS - diff --git a/winpr/libwinpr/com/module.def b/winpr/libwinpr/com/module.def deleted file mode 100644 index 4467b6c7b..000000000 --- a/winpr/libwinpr/com/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-com" -EXPORTS diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c index 5c8b0277f..04e11da4b 100644 --- a/winpr/libwinpr/comm/comm_serial_sys.c +++ b/winpr/libwinpr/comm/comm_serial_sys.c @@ -1344,7 +1344,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus) } else { - /* FIXME: "is 80 percent full" from the specs is ambiguous, need to track when it previously occured? */ + /* FIXME: "is 80 percent full" from the specs is ambiguous, need to track when it previously * occurred? */ pComm->PendingEvents &= ~SERIAL_EV_RX80FULL; } diff --git a/winpr/libwinpr/comm/module.def b/winpr/libwinpr/comm/module.def deleted file mode 100644 index 44feb6f4e..000000000 --- a/winpr/libwinpr/comm/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr" -EXPORTS - diff --git a/winpr/libwinpr/credentials/module.def b/winpr/libwinpr/credentials/module.def deleted file mode 100644 index 1d5bc0e56..000000000 --- a/winpr/libwinpr/credentials/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-credentials" -EXPORTS diff --git a/winpr/libwinpr/credui/module.def b/winpr/libwinpr/credui/module.def deleted file mode 100644 index 70ec4964d..000000000 --- a/winpr/libwinpr/credui/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-credui" -EXPORTS diff --git a/winpr/libwinpr/crt/module.def b/winpr/libwinpr/crt/module.def deleted file mode 100644 index 3c3c4ffb4..000000000 --- a/winpr/libwinpr/crt/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-crt" -EXPORTS diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index b17a34714..c6fb1d3c1 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -485,4 +486,42 @@ char* StrSep(char** stringp, const char* delim) return start; } +INT64 GetLine(char** lineptr, size_t* size, FILE* stream) +{ +#if defined(_WIN32) + char c; + char *n; + size_t step = 32; + size_t used = 0; + if (!lineptr || !size) + { + errno = EINVAL; + return -1; + } + + do + { + if (used + 2 >= *size) + { + *size += step; + n = realloc(*lineptr, *size); + if (!n) + { + return -1; + } + *lineptr = n; + } + c = fgetc(stream); + if (c != EOF) + (*lineptr)[used++] = c; + } while((c != '\n') && (c != '\r') && (c != EOF)); + (*lineptr)[used] = '\0'; + + return used; +#elif !defined(ANDROID) && !defined(IOS) + return getline(lineptr, size, stream); +#else + return -1; +#endif +} diff --git a/winpr/libwinpr/crt/test/TestUnicodeConversion.c b/winpr/libwinpr/crt/test/TestUnicodeConversion.c index 559c919be..08497bf82 100644 --- a/winpr/libwinpr/crt/test/TestUnicodeConversion.c +++ b/winpr/libwinpr/crt/test/TestUnicodeConversion.c @@ -260,7 +260,7 @@ int convert_utf16_to_utf8(BYTE* lpWideCharStr, BYTE* expected_lpMultiByteStr, in return length; } -int test_unicode_uppercasing(BYTE* lower, BYTE* upper) +BOOL test_unicode_uppercasing(BYTE* lower, BYTE* upper) { WCHAR* lowerW = NULL; int lowerLength; @@ -280,13 +280,182 @@ int test_unicode_uppercasing(BYTE* lower, BYTE* upper) printf("Uppercase String:\n"); string_hexdump((BYTE*) upperW, upperLength * 2); - return -1; + return FALSE; } free(lowerW); free(upperW); - return 0; + printf("success\n\n"); + return TRUE; +} + +BOOL test_ConvertFromUnicode_wrapper() +{ + /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 */ + WCHAR src1[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T','@','@','@' }; + WCHAR src2[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + CHAR cmp0[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + CHAR* dst = NULL; + int i; + + /* Test unterminated unicode string: + * ConvertFromUnicode must always null-terminate, even if the src string isn't + */ + + printf("Input UTF16 String:\n"); + string_hexdump((BYTE*) src1, 19 * sizeof(WCHAR)); + + i = ConvertFromUnicode(CP_UTF8, 0, src1, 16, &dst, 0, NULL, NULL); + if (i != 16) + { + fprintf(stderr, "ConvertFromUnicode failure A1: unexpectedly returned %d instead of 16\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertFromUnicode failure A2: destination ist NULL\n"); + goto fail; + } + if ((i = strlen(dst)) != 16) + { + fprintf(stderr, "ConvertFromUnicode failure A3: dst length is %d instead of 16\n", i); + goto fail; + } + if (strcmp(dst, cmp0)) + { + fprintf(stderr, "ConvertFromUnicode failure A4: data mismatch\n"); + goto fail; + } + printf("Output UTF8 String:\n"); + string_hexdump((BYTE*) dst, i + 1); + + free(dst); + dst = NULL; + + /* Test null-terminated string */ + + printf("Input UTF16 String:\n"); + string_hexdump((BYTE*) src2, (_wcslen(src2) + 1 ) * sizeof(WCHAR)); + + i = ConvertFromUnicode(CP_UTF8, 0, src2, -1, &dst, 0, NULL, NULL); + if (i != 17) + { + fprintf(stderr, "ConvertFromUnicode failure B1: unexpectedly returned %d instead of 17\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertFromUnicode failure B2: destination ist NULL\n"); + goto fail; + } + if ((i = strlen(dst)) != 16) + { + fprintf(stderr, "ConvertFromUnicode failure B3: dst length is %d instead of 16\n", i); + goto fail; + } + if (strcmp(dst, cmp0)) + { + fprintf(stderr, "ConvertFromUnicode failure B: data mismatch\n"); + goto fail; + } + printf("Output UTF8 String:\n"); + string_hexdump((BYTE*) dst, i + 1); + + free(dst); + dst = NULL; + + printf("success\n\n"); + + return TRUE; + +fail: + free(dst); + return FALSE; +} + +BOOL test_ConvertToUnicode_wrapper() +{ + /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 */ + CHAR src1[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T','@','@','@' }; + CHAR src2[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + WCHAR cmp0[] = { 'R','I','C','H',' ','T','E','X','T',' ','F','O','R','M','A','T', 0 }; + WCHAR* dst = NULL; + int i; + + /* Test unterminated unicode string: + * ConvertToUnicode must always null-terminate, even if the src string isn't + */ + + printf("Input UTF8 String:\n"); + string_hexdump((BYTE*) src1, 19); + + i = ConvertToUnicode(CP_UTF8, 0, src1, 16, &dst, 0); + if (i != 16) + { + fprintf(stderr, "ConvertToUnicode failure A1: unexpectedly returned %d instead of 16\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertToUnicode failure A2: destination ist NULL\n"); + goto fail; + } + if ((i = _wcslen(dst)) != 16) + { + fprintf(stderr, "ConvertToUnicode failure A3: dst length is %d instead of 16\n", i); + goto fail; + } + if (_wcscmp(dst, cmp0)) + { + fprintf(stderr, "ConvertToUnicode failure A4: data mismatch\n"); + goto fail; + } + printf("Output UTF16 String:\n"); + string_hexdump((BYTE*) dst, (i + 1) * sizeof(WCHAR)); + + free(dst); + dst = NULL; + + /* Test null-terminated string */ + + printf("Input UTF8 String:\n"); + string_hexdump((BYTE*) src2, strlen(src2) + 1); + + i = ConvertToUnicode(CP_UTF8, 0, src2, -1, &dst, 0); + if (i != 17) + { + fprintf(stderr, "ConvertToUnicode failure B1: unexpectedly returned %d instead of 17\n", i); + goto fail; + } + if (dst == NULL) + { + fprintf(stderr, "ConvertToUnicode failure B2: destination ist NULL\n"); + goto fail; + } + if ((i = _wcslen(dst)) != 16) + { + fprintf(stderr, "ConvertToUnicode failure B3: dst length is %d instead of 16\n", i); + goto fail; + } + if (_wcscmp(dst, cmp0)) + { + fprintf(stderr, "ConvertToUnicode failure B: data mismatch\n"); + goto fail; + } + printf("Output UTF16 String:\n"); + string_hexdump((BYTE*) dst, (i + 1) * 2); + + free(dst); + dst = NULL; + + printf("success\n\n"); + + return TRUE; + +fail: + free(dst); + return FALSE; } int TestUnicodeConversion(int argc, char* argv[]) @@ -375,7 +544,47 @@ int TestUnicodeConversion(int argc, char* argv[]) printf("Uppercasing\n"); - test_unicode_uppercasing(ru_Administrator_lower, ru_Administrator_upper); + if (!test_unicode_uppercasing(ru_Administrator_lower, ru_Administrator_upper)) + return -1; + /* ConvertFromUnicode */ + + printf("ConvertFromUnicode\n"); + + if (!test_ConvertFromUnicode_wrapper()) + return -1; + + /* ConvertToUnicode */ + + printf("ConvertToUnicode\n"); + + if (!test_ConvertToUnicode_wrapper()) + return -1; +/* + + printf("----------------------------------------------------------\n\n"); + + if (0) + { + BYTE src[] = { 'R',0,'I',0,'C',0,'H',0,' ',0, 'T',0,'E',0,'X',0,'T',0,' ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; + //BYTE src[] = { 'R',0,'I',0,'C',0,'H',0,' ',0, 0,0, 'T',0,'E',0,'X',0,'T',0,' ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; + //BYTE src[] = { 0,0,'R',0,'I',0,'C',0,'H',0,' ',0, 'T',0,'E',0,'X',0,'T',0,' ',0,'F',0,'O',0,'R',0,'M',0,'A',0,'T',0,'@',0,'@',0 }; + char* dst = NULL; + int num; + num = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) src, 16, &dst, 0, NULL, NULL); + printf("ConvertFromUnicode returned %d dst=[%s]\n", num, dst); + string_hexdump((BYTE*)dst, num+1); + } + if (1) + { + char src[] = "RICH TEXT FORMAT@@@@@@"; + WCHAR *dst = NULL; + int num; + num = ConvertToUnicode(CP_UTF8, 0, src, 16, &dst, 0); + printf("ConvertToUnicode returned %d dst=%p\n", num, dst); + string_hexdump((BYTE*)dst, num * 2 + 2); + + } +*/ return 0; } diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c index d0445c181..0cea9de37 100644 --- a/winpr/libwinpr/crt/unicode.c +++ b/winpr/libwinpr/crt/unicode.c @@ -276,6 +276,19 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int #endif +/** + * ConvertToUnicode is a convenience wrapper for MultiByteToWideChar: + * + * If the lpWideCharStr prarameter for the converted string points to NULL + * or if the cchWideChar parameter is set to 0 this function will automatically + * allocate the required memory which is guaranteed to be null-terminated + * after the conversion, even if the source c string isn't. + * + * If the cbMultiByte parameter is set to -1 the passed lpMultiByteStr must + * be null-terminated and the required length for the converted string will be + * calculated accordingly. + */ + int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR* lpWideCharStr, int cchWideChar) { @@ -305,7 +318,7 @@ int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, if (allocate) { - *lpWideCharStr = (LPWSTR) calloc(cchWideChar, sizeof(WCHAR)); + *lpWideCharStr = (LPWSTR) calloc(cchWideChar + 1, sizeof(WCHAR)); if (!(*lpWideCharStr)) { @@ -317,11 +330,31 @@ int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr, cchWideChar); if (status != cchWideChar) + { + if (allocate) + { + free(*lpWideCharStr); + *lpWideCharStr = NULL; + } status = 0; + } return status; } +/** + * ConvertFromUnicode is a convenience wrapper for WideCharToMultiByte: + * + * If the lpMultiByteStr parameter for the converted string points to NULL + * or if the cbMultiByte parameter is set to 0 this function will automatically + * allocate the required memory which is guaranteed to be null-terminated + * after the conversion, even if the source unicode string isn't. + * + * If the cchWideChar parameter is set to -1 the passed lpWideCharStr must + * be null-terminated and the required length for the converted string will be + * calculated accordingly. + */ + int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar) { diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c index c7cdb52e1..f85ab6532 100644 --- a/winpr/libwinpr/crypto/cipher.c +++ b/winpr/libwinpr/crypto/cipher.c @@ -43,33 +43,49 @@ * RC4 */ -void winpr_RC4_Init(WINPR_RC4_CTX* ctx, const BYTE* key, size_t keylen) +WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen) { + WINPR_RC4_CTX* ctx = NULL; + + if (!key || (keylen == 0)) + return NULL; + + ctx = calloc(1, sizeof(WINPR_RC4_CTX)); + if (!ctx) + return NULL; + #if defined(WITH_OPENSSL) RC4_set_key((RC4_KEY*) ctx, keylen, key); #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C) mbedtls_arc4_init((mbedtls_arc4_context*) ctx); mbedtls_arc4_setup((mbedtls_arc4_context*) ctx, key, (unsigned int) keylen); #endif + return ctx; } -int winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output) +BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output) { #if defined(WITH_OPENSSL) RC4((RC4_KEY*) ctx, length, input, output); - return 0; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C) - return mbedtls_arc4_crypt((mbedtls_arc4_context*) ctx, length, input, output); + if (mbedtls_arc4_crypt((mbedtls_arc4_context*) ctx, length, input, output) != 0) + return FALSE; #endif + + return TRUE; } -void winpr_RC4_Final(WINPR_RC4_CTX* ctx) +void winpr_RC4_Free(WINPR_RC4_CTX* ctx) { + if (!ctx) + return; + #if defined(WITH_OPENSSL) #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_ARC4_C) mbedtls_arc4_free((mbedtls_arc4_context*) ctx); #endif + free(ctx); } /** @@ -496,81 +512,121 @@ mbedtls_cipher_type_t winpr_mbedtls_get_cipher_type(int cipher) } #endif -int winpr_Cipher_Init(WINPR_CIPHER_CTX* ctx, int cipher, int op, const BYTE* key, const BYTE* iv) +WINPR_CIPHER_CTX* winpr_Cipher_New(int cipher, int op, const BYTE* key, const BYTE* iv) { + WINPR_CIPHER_CTX* ctx; #if defined(WITH_OPENSSL) int operation; const EVP_CIPHER* evp; - evp = winpr_openssl_get_evp_cipher(cipher); - - if (!evp) - return -1; - - operation = (op == WINPR_ENCRYPT) ? 1 : 0; - EVP_CIPHER_CTX_init((EVP_CIPHER_CTX*) ctx); - - if (EVP_CipherInit_ex((EVP_CIPHER_CTX*) ctx, evp, NULL, key, iv, operation) != 1) - return -1; + EVP_CIPHER_CTX* octx; #elif defined(WITH_MBEDTLS) int key_bitlen; mbedtls_operation_t operation; mbedtls_cipher_type_t cipher_type; const mbedtls_cipher_info_t* cipher_info; +#endif + + ctx = calloc(1, sizeof(WINPR_CIPHER_CTX)); + if (!ctx) + return NULL; + +#if defined(WITH_OPENSSL) + octx = (EVP_CIPHER_CTX*)ctx; + evp = winpr_openssl_get_evp_cipher(cipher); + + if (!evp) + { + free (ctx); + return NULL; + } + + operation = (op == WINPR_ENCRYPT) ? 1 : 0; + EVP_CIPHER_CTX_init(octx); + + if (EVP_CipherInit_ex(octx, evp, NULL, key, iv, operation) != 1) + { + EVP_CIPHER_CTX_cleanup(octx); + free (octx); + return NULL; + } + + EVP_CIPHER_CTX_set_padding(octx, 0); +#elif defined(WITH_MBEDTLS) cipher_type = winpr_mbedtls_get_cipher_type(cipher); cipher_info = mbedtls_cipher_info_from_type(cipher_type); if (!cipher_info) - return -1; + { + free (ctx); + return NULL; + } operation = (op == WINPR_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT; mbedtls_cipher_init((mbedtls_cipher_context_t*) ctx); if (mbedtls_cipher_setup((mbedtls_cipher_context_t*) ctx, cipher_info) != 0) - return -1; + { + free (ctx); + return NULL; + } key_bitlen = mbedtls_cipher_get_key_bitlen((mbedtls_cipher_context_t*) ctx); if (mbedtls_cipher_setkey((mbedtls_cipher_context_t*) ctx, key, key_bitlen, operation) != 0) - return -1; + { + mbedtls_cipher_free((mbedtls_cipher_context_t*) ctx); + free (ctx); + return NULL; + } #endif - return 0; + return ctx; } -int winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const BYTE* input, size_t ilen, BYTE* output, size_t* olen) +BOOL winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const BYTE* input, size_t ilen, BYTE* output, size_t* olen) { #if defined(WITH_OPENSSL) int outl = (int) *olen; if (EVP_CipherUpdate((EVP_CIPHER_CTX*) ctx, output, &outl, input, ilen) != 1) - return -1; + return FALSE; *olen = (size_t) outl; #elif defined(WITH_MBEDTLS) if (mbedtls_cipher_update((mbedtls_cipher_context_t*) ctx, input, ilen, output, olen) != 0) - return -1; + return FALSE; #endif - return 0; + return TRUE; } -int winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, BYTE* output, size_t* olen) +BOOL winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, BYTE* output, size_t* olen) { #if defined(WITH_OPENSSL) int outl = (int) *olen; if (EVP_CipherFinal_ex((EVP_CIPHER_CTX*) ctx, output, &outl) != 1) - return -1; + return FALSE; - EVP_CIPHER_CTX_cleanup((EVP_CIPHER_CTX*) ctx); *olen = (size_t) outl; #elif defined(WITH_MBEDTLS) if (mbedtls_cipher_finish((mbedtls_cipher_context_t*) ctx, output, olen) != 0) - return -1; + return FALSE; +#endif + return TRUE; +} +void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx) +{ + if (!ctx) + return; + +#if defined(WITH_OPENSSL) + EVP_CIPHER_CTX_cleanup((EVP_CIPHER_CTX*) ctx); +#elif defined(WITH_MBEDTLS) mbedtls_cipher_free((mbedtls_cipher_context_t*) ctx); #endif - return 0; } + /** * Key Generation */ diff --git a/winpr/libwinpr/crypto/crypto.c b/winpr/libwinpr/crypto/crypto.c index 9e3064e84..144222af3 100644 --- a/winpr/libwinpr/crypto/crypto.c +++ b/winpr/libwinpr/crypto/crypto.c @@ -150,7 +150,7 @@ BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) { BYTE* pCipherText; size_t cbOut, cbFinal; - WINPR_CIPHER_CTX enc; + WINPR_CIPHER_CTX* enc = NULL; BYTE randomKey[256]; WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock; @@ -186,27 +186,35 @@ BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) pCipherText = (BYTE*) malloc(cbOut); if (!pCipherText) - { - free(pMemBlock); - return FALSE; - } + goto out; - winpr_Cipher_Init(&enc, WINPR_CIPHER_AES_256_CBC, WINPR_ENCRYPT, pMemBlock->key, pMemBlock->iv); - winpr_Cipher_Update(&enc, pMemBlock->pData, pMemBlock->cbData, pCipherText, &cbOut); - winpr_Cipher_Final(&enc, pCipherText + cbOut, &cbFinal); + if ((enc = winpr_Cipher_New(WINPR_CIPHER_AES_256_CBC, WINPR_ENCRYPT, + pMemBlock->key, pMemBlock->iv)) == NULL) + goto out; + if (!winpr_Cipher_Update(enc, pMemBlock->pData, pMemBlock->cbData, pCipherText, &cbOut)) + goto out; + if (!winpr_Cipher_Final(enc, pCipherText + cbOut, &cbFinal)) + goto out; + winpr_Cipher_Free(enc); CopyMemory(pMemBlock->pData, pCipherText, pMemBlock->cbData); free(pCipherText); return ListDictionary_Add(g_ProtectedMemoryBlocks, pData, pMemBlock); +out: + free (pMemBlock); + free (pCipherText); + winpr_Cipher_Free(enc); + + return FALSE; } BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) { - BYTE* pPlainText; + BYTE* pPlainText = NULL; size_t cbOut, cbFinal; - WINPR_CIPHER_CTX dec; - WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock; + WINPR_CIPHER_CTX* dec = NULL; + WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = NULL; if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS) return FALSE; @@ -217,18 +225,23 @@ BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData); if (!pMemBlock) - return FALSE; + goto out; cbOut = pMemBlock->cbData + 16 - 1; pPlainText = (BYTE*) malloc(cbOut); if (!pPlainText) - return FALSE; + goto out; - winpr_Cipher_Init(&dec, WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT, pMemBlock->key, pMemBlock->iv); - winpr_Cipher_Update(&dec, pMemBlock->pData, pMemBlock->cbData, pPlainText, &cbOut); - winpr_Cipher_Final(&dec, pPlainText + cbOut, &cbFinal); + if ((dec = winpr_Cipher_New(WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT, + pMemBlock->key, pMemBlock->iv)) == NULL) + goto out; + if (!winpr_Cipher_Update(dec, pMemBlock->pData, pMemBlock->cbData, pPlainText, &cbOut)) + goto out; + if (!winpr_Cipher_Final(dec, pPlainText + cbOut, &cbFinal)) + goto out; + winpr_Cipher_Free(dec); CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData); SecureZeroMemory(pPlainText, pMemBlock->cbData); @@ -239,6 +252,12 @@ BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags) free(pMemBlock); return TRUE; + +out: + free(pPlainText); + free(pMemBlock); + winpr_Cipher_Free(dec); + return FALSE; } BOOL CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, DATA_BLOB* pOptionalEntropy, diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index ba7fdb720..70c4392fa 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -43,123 +43,167 @@ * MD5 */ -void winpr_MD5_Init(WINPR_MD5_CTX* ctx) +BOOL winpr_MD5_Init(WINPR_MD5_CTX* ctx) { #if defined(WITH_OPENSSL) - MD5_Init((MD5_CTX*) ctx); + if (MD5_Init((MD5_CTX*) ctx) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_MD5_C) mbedtls_md5_init((mbedtls_md5_context*) ctx); mbedtls_md5_starts((mbedtls_md5_context*) ctx); #endif + + return TRUE; } -void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const BYTE* input, size_t ilen) +BOOL winpr_MD5_Update(WINPR_MD5_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) - MD5_Update((MD5_CTX*) ctx, input, ilen); + if (MD5_Update((MD5_CTX*) ctx, input, ilen) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_MD5_C) mbedtls_md5_update((mbedtls_md5_context*) ctx, input, ilen); #endif + + return TRUE; } -void winpr_MD5_Final(WINPR_MD5_CTX* ctx, BYTE* output) +BOOL winpr_MD5_Final(WINPR_MD5_CTX* ctx, BYTE* output, size_t ilen) { + if (ilen < WINPR_MD5_DIGEST_LENGTH) + return FALSE; + #if defined(WITH_OPENSSL) - MD5_Final(output, (MD5_CTX*) ctx); + if (MD5_Final(output, (MD5_CTX*) ctx) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_MD5_C) mbedtls_md5_finish((mbedtls_md5_context*) ctx, output); mbedtls_md5_free((mbedtls_md5_context*) ctx); #endif + + return TRUE; } -void winpr_MD5(const BYTE* input, size_t ilen, BYTE* output) +BOOL winpr_MD5(const BYTE* input, size_t ilen, BYTE* output, size_t olen) { WINPR_MD5_CTX ctx; - winpr_MD5_Init(&ctx); - winpr_MD5_Update(&ctx, input, ilen); - winpr_MD5_Final(&ctx, output); + + if (!winpr_MD5_Init(&ctx)) + return FALSE; + if (!winpr_MD5_Update(&ctx, input, ilen)) + return FALSE; + return winpr_MD5_Final(&ctx, output, olen); } /** * MD4 */ -void winpr_MD4_Init(WINPR_MD4_CTX* ctx) +BOOL winpr_MD4_Init(WINPR_MD4_CTX* ctx) { #if defined(WITH_OPENSSL) - MD4_Init((MD4_CTX*) ctx); + if (MD4_Init((MD4_CTX*) ctx) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_MD4_C) mbedtls_md4_init((mbedtls_md4_context*) ctx); mbedtls_md4_starts((mbedtls_md4_context*) ctx); #endif + return TRUE; } -void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const BYTE* input, size_t ilen) +BOOL winpr_MD4_Update(WINPR_MD4_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) - MD4_Update((MD4_CTX*) ctx, input, ilen); + if (MD4_Update((MD4_CTX*) ctx, input, ilen) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_MD4_C) mbedtls_md4_update((mbedtls_md4_context*) ctx, input, ilen); #endif + + return TRUE; } -void winpr_MD4_Final(WINPR_MD4_CTX* ctx, BYTE* output) +BOOL winpr_MD4_Final(WINPR_MD4_CTX* ctx, BYTE* output, size_t olen) { + if (olen < WINPR_MD4_DIGEST_LENGTH) + return FALSE; + #if defined(WITH_OPENSSL) - MD4_Final(output, (MD4_CTX*) ctx); + if (MD4_Final(output, (MD4_CTX*) ctx) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_MD4_C) mbedtls_md4_finish((mbedtls_md4_context*) ctx, output); mbedtls_md4_free((mbedtls_md4_context*) ctx); #endif + + return TRUE; } -void winpr_MD4(const BYTE* input, size_t ilen, BYTE* output) +BOOL winpr_MD4(const BYTE* input, size_t ilen, BYTE* output, size_t olen) { WINPR_MD4_CTX ctx; - winpr_MD4_Init(&ctx); - winpr_MD4_Update(&ctx, input, ilen); - winpr_MD4_Final(&ctx, output); + + if (!winpr_MD4_Init(&ctx)) + return FALSE; + if (!winpr_MD4_Update(&ctx, input, ilen)) + return FALSE; + return winpr_MD4_Final(&ctx, output, olen); } /** * SHA1 */ -void winpr_SHA1_Init(WINPR_SHA1_CTX* ctx) +BOOL winpr_SHA1_Init(WINPR_SHA1_CTX* ctx) { #if defined(WITH_OPENSSL) - SHA1_Init((SHA_CTX*) ctx); + if (SHA1_Init((SHA_CTX*) ctx) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_SHA1_C) mbedtls_sha1_init((mbedtls_sha1_context*) ctx); mbedtls_sha1_starts((mbedtls_sha1_context*) ctx); #endif + + return TRUE; } -void winpr_SHA1_Update(WINPR_SHA1_CTX* ctx, const BYTE* input, size_t ilen) +BOOL winpr_SHA1_Update(WINPR_SHA1_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) - SHA1_Update((SHA_CTX*) ctx, input, ilen); + if (SHA1_Update((SHA_CTX*) ctx, input, ilen) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_SHA1_C) mbedtls_sha1_update((mbedtls_sha1_context*) ctx, input, ilen); #endif + + return TRUE; } -void winpr_SHA1_Final(WINPR_SHA1_CTX* ctx, BYTE* output) +BOOL winpr_SHA1_Final(WINPR_SHA1_CTX* ctx, BYTE* output, size_t olen) { + if (olen < WINPR_SHA1_DIGEST_LENGTH) + return FALSE; + #if defined(WITH_OPENSSL) - SHA1_Final(output, (SHA_CTX*) ctx); + if (SHA1_Final(output, (SHA_CTX*) ctx) != 1) + return FALSE; #elif defined(WITH_MBEDTLS) && defined(MBEDTLS_SHA1_C) mbedtls_sha1_finish((mbedtls_sha1_context*) ctx, output); mbedtls_sha1_free((mbedtls_sha1_context*) ctx); #endif + + return TRUE; } -void winpr_SHA1(const BYTE* input, size_t ilen, BYTE* output) +BOOL winpr_SHA1(const BYTE* input, size_t ilen, BYTE* output, size_t olen) { WINPR_SHA1_CTX ctx; - winpr_SHA1_Init(&ctx); - winpr_SHA1_Update(&ctx, input, ilen); - winpr_SHA1_Final(&ctx, output); + + if (!winpr_SHA1_Init(&ctx)) + return FALSE; + if (!winpr_SHA1_Update(&ctx, input, ilen)) + return FALSE; + return winpr_SHA1_Final(&ctx, output, olen); } /** @@ -264,13 +308,13 @@ mbedtls_md_type_t winpr_mbedtls_get_md_type(int md) } #endif -int winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, int md, const BYTE* key, size_t keylen) +BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, size_t keylen) { #if defined(WITH_OPENSSL) const EVP_MD* evp = winpr_openssl_get_evp_md(md); if (!evp) - return -1; + return FALSE; HMAC_CTX_init((HMAC_CTX*) ctx); @@ -278,7 +322,7 @@ int winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, int md, const BYTE* key, size_t keylen) HMAC_Init_ex((HMAC_CTX*) ctx, key, keylen, evp, NULL); #else if (HMAC_Init_ex((HMAC_CTX*) ctx, key, keylen, evp, NULL) != 1) - return -1; + return FALSE; #endif #elif defined(WITH_MBEDTLS) @@ -287,143 +331,150 @@ int winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, int md, const BYTE* key, size_t keylen) md_info = mbedtls_md_info_from_type(md_type); if (!md_info) - return -1; + return FALSE; mbedtls_md_init((mbedtls_md_context_t*) ctx); if (mbedtls_md_setup((mbedtls_md_context_t*) ctx, md_info, 1) != 0) - return -1; + return FALSE; if (mbedtls_md_hmac_starts((mbedtls_md_context_t*) ctx, key, keylen) != 0) - return -1; + return FALSE; #endif - return 0; + return TRUE; } -int winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) +BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) #if (OPENSSL_VERSION_NUMBER < 0x10000000L) HMAC_Update((HMAC_CTX*) ctx, input, ilen); #else if (HMAC_Update((HMAC_CTX*) ctx, input, ilen) != 1) - return -1; + return FALSE; #endif #elif defined(WITH_MBEDTLS) if (mbedtls_md_hmac_update((mbedtls_md_context_t*) ctx, input, ilen) != 0) - return -1; + return FALSE; #endif - return 0; + return TRUE; } -int winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output) +BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) { + /* TODO + if (olen < ctx->digestLength) + return FALSE; + */ + #if defined(WITH_OPENSSL) #if (OPENSSL_VERSION_NUMBER < 0x10000000L) HMAC_Final((HMAC_CTX*) ctx, output, NULL); #else if (HMAC_Final((HMAC_CTX*) ctx, output, NULL) != 1) - return -1; + return FALSE; #endif HMAC_CTX_cleanup((HMAC_CTX*) ctx); #elif defined(WITH_MBEDTLS) if (mbedtls_md_hmac_finish((mbedtls_md_context_t*) ctx, output) != 0) - return -1; + return FALSE; mbedtls_md_free((mbedtls_md_context_t*) ctx); #endif - return 0; + return TRUE; } -int winpr_HMAC(int md, const BYTE* key, size_t keylen, const BYTE* input, size_t ilen, BYTE* output) +BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, + const BYTE* input, size_t ilen, BYTE* output, size_t olen) { WINPR_HMAC_CTX ctx; - if (winpr_HMAC_Init(&ctx, md, key, keylen) != 0) - return -1; + if (!winpr_HMAC_Init(&ctx, md, key, keylen)) + return FALSE; - if (winpr_HMAC_Update(&ctx, input, ilen) != 0) - return -1; + if (!winpr_HMAC_Update(&ctx, input, ilen)) + return FALSE; - if (winpr_HMAC_Final(&ctx, output) != 0) - return -1; + if (!winpr_HMAC_Final(&ctx, output, olen)) + return FALSE; - return 0; + return TRUE; } /** * Generic Digest API */ -int winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, int md) +BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { #if defined(WITH_OPENSSL) const EVP_MD* evp = winpr_openssl_get_evp_md(md); if (!evp) - return -1; + return FALSE; EVP_MD_CTX_init((EVP_MD_CTX*) ctx); if (EVP_DigestInit_ex((EVP_MD_CTX*) ctx, evp, NULL) != 1) - return -1; + return FALSE; #elif defined(WITH_MBEDTLS) const mbedtls_md_info_t* md_info; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); md_info = mbedtls_md_info_from_type(md_type); if (!md_info) - return -1; + return FALSE; mbedtls_md_init((mbedtls_md_context_t*) ctx); if (mbedtls_md_setup((mbedtls_md_context_t*) ctx, md_info, 0) != 0) - return -1; + return FALSE; if (mbedtls_md_starts((mbedtls_md_context_t*) ctx) != 0) - return -1; + return FALSE; #endif - return 0; + return TRUE; } -int winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) +BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) if (EVP_DigestUpdate((EVP_MD_CTX*) ctx, input, ilen) != 1) - return -1; + return FALSE; #elif defined(WITH_MBEDTLS) if (mbedtls_md_update((mbedtls_md_context_t*) ctx, input, ilen) != 0) - return -1; + return FALSE; #endif - return 0; + return TRUE; } -int winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output) +BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) { + // TODO: output length check #if defined(WITH_OPENSSL) if (EVP_DigestFinal_ex((EVP_MD_CTX*) ctx, output, NULL) != 1) - return -1; + return FALSE; #elif defined(WITH_MBEDTLS) if (mbedtls_md_finish((mbedtls_md_context_t*) ctx, output) != 0) - return -1; + return FALSE; mbedtls_md_free((mbedtls_md_context_t*) ctx); #endif - return 0; + return TRUE; } -int winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output) +BOOL winpr_Digest(int md, const BYTE* input, size_t ilen, BYTE* output, size_t olen) { WINPR_DIGEST_CTX ctx; - if (winpr_Digest_Init(&ctx, md) != 0) - return -1; + if (!winpr_Digest_Init(&ctx, md)) + return FALSE; - if (winpr_Digest_Update(&ctx, input, ilen) != 0) - return -1; + if (!winpr_Digest_Update(&ctx, input, ilen)) + return FALSE; - if (winpr_Digest_Final(&ctx, output) != 0) - return -1; + if (!winpr_Digest_Final(&ctx, output, olen)) + return FALSE; - return 0; + return TRUE; } diff --git a/winpr/libwinpr/crypto/module.def b/winpr/libwinpr/crypto/module.def deleted file mode 100644 index d21b12685..000000000 --- a/winpr/libwinpr/crypto/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-crypto" -EXPORTS - diff --git a/winpr/libwinpr/crypto/test/TestCryptoCipher.c b/winpr/libwinpr/crypto/test/TestCryptoCipher.c index 29aa925a8..cbf940d9a 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoCipher.c +++ b/winpr/libwinpr/crypto/test/TestCryptoCipher.c @@ -7,22 +7,26 @@ static const BYTE* TEST_RC4_KEY = (BYTE*) "Key"; static const char* TEST_RC4_PLAINTEXT = "Plaintext"; static const BYTE* TEST_RC4_CIPHERTEXT = (BYTE*) "\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3"; -BOOL test_crypto_cipher_rc4() +static BOOL test_crypto_cipher_rc4() { size_t len; - BYTE* text; - WINPR_RC4_CTX ctx; + BOOL rc = FALSE; + BYTE* text = NULL; + WINPR_RC4_CTX* ctx; len = strlen(TEST_RC4_PLAINTEXT); text = (BYTE*) calloc(1, len); if (!text) - return FALSE; + goto out; - winpr_RC4_Init(&ctx, TEST_RC4_KEY, strlen((char*) TEST_RC4_KEY)); - winpr_RC4_Update(&ctx, len, (BYTE*) TEST_RC4_PLAINTEXT, text); - winpr_RC4_Final(&ctx); + if ((ctx = winpr_RC4_New(TEST_RC4_KEY, strlen((char*) TEST_RC4_KEY))) == NULL) + goto out; + rc = winpr_RC4_Update(ctx, len, (BYTE*) TEST_RC4_PLAINTEXT, text); + winpr_RC4_Free(ctx); + if (!rc) + goto out; if (memcmp(text, TEST_RC4_CIPHERTEXT, len) != 0) { @@ -36,11 +40,14 @@ BOOL test_crypto_cipher_rc4() free(actual); free(expected); - - return FALSE; + goto out; } - return TRUE; + rc = TRUE; + +out: + free(text); + return rc; } static const BYTE* TEST_RAND_DATA = (BYTE*) @@ -56,7 +63,7 @@ static const BYTE* TEST_CIPHER_KEY = (BYTE*) static const BYTE* TEST_CIPHER_IV = (BYTE*) "\xFE\xE3\x9F\xF0\xD1\x5E\x37\x0C\xAB\xAB\x9B\x04\xF3\xDB\x99\x15"; -BOOL test_crypto_cipher_key() +static BOOL test_crypto_cipher_key() { int status; BYTE key[32]; diff --git a/winpr/libwinpr/crypto/test/TestCryptoHash.c b/winpr/libwinpr/crypto/test/TestCryptoHash.c index 8178469ac..ffdf3dba9 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoHash.c +++ b/winpr/libwinpr/crypto/test/TestCryptoHash.c @@ -6,29 +6,32 @@ static const char* TEST_MD5_DATA = "test"; static const BYTE* TEST_MD5_HASH = (BYTE*) "\x09\x8f\x6b\xcd\x46\x21\xd3\x73\xca\xde\x4e\x83\x26\x27\xb4\xf6"; -BOOL test_crypto_hash_md5() +static BOOL test_crypto_hash_md5(void) { - BYTE hash[16]; + BYTE hash[WINPR_MD5_DIGEST_LENGTH]; WINPR_MD5_CTX ctx; - winpr_MD5_Init(&ctx); - winpr_MD5_Update(&ctx, (BYTE*) TEST_MD5_DATA, strlen(TEST_MD5_DATA)); - winpr_MD5_Final(&ctx, hash); + if (!winpr_MD5_Init(&ctx)) + return FALSE; + if (!winpr_MD5_Update(&ctx, (BYTE*) TEST_MD5_DATA, strlen(TEST_MD5_DATA))) + return FALSE; + if (!winpr_MD5_Final(&ctx, hash, sizeof(hash))) + return FALSE; - if (memcmp(hash, TEST_MD5_HASH, 16) != 0) + if (memcmp(hash, TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0) { char* actual; char* expected; - actual = winpr_BinToHexString(hash, 16, FALSE); - expected = winpr_BinToHexString(TEST_MD5_HASH, 16, FALSE); + actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE); + expected = winpr_BinToHexString(TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE); fprintf(stderr, "unexpected MD5 hash: Actual: %s Expected: %s\n", actual, expected); free(actual); free(expected); - return -1; + return FALSE; } return TRUE; @@ -37,29 +40,32 @@ BOOL test_crypto_hash_md5() static const char* TEST_MD4_DATA = "test"; static const BYTE* TEST_MD4_HASH = (BYTE*) "\xdb\x34\x6d\x69\x1d\x7a\xcc\x4d\xc2\x62\x5d\xb1\x9f\x9e\x3f\x52"; -BOOL test_crypto_hash_md4() +static BOOL test_crypto_hash_md4(void) { - BYTE hash[16]; + BYTE hash[WINPR_MD4_DIGEST_LENGTH]; WINPR_MD4_CTX ctx; - winpr_MD4_Init(&ctx); - winpr_MD4_Update(&ctx, (BYTE*) TEST_MD4_DATA, strlen(TEST_MD4_DATA)); - winpr_MD4_Final(&ctx, hash); + if (!winpr_MD4_Init(&ctx)) + return FALSE; + if (!winpr_MD4_Update(&ctx, (BYTE*) TEST_MD4_DATA, strlen(TEST_MD4_DATA))) + return FALSE; + if (!winpr_MD4_Final(&ctx, hash, sizeof(hash))) + return FALSE; - if (memcmp(hash, TEST_MD4_HASH, 16) != 0) + if (memcmp(hash, TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH) != 0) { char* actual; char* expected; - actual = winpr_BinToHexString(hash, 16, FALSE); - expected = winpr_BinToHexString(TEST_MD4_HASH, 16, FALSE); + actual = winpr_BinToHexString(hash, WINPR_MD4_DIGEST_LENGTH, FALSE); + expected = winpr_BinToHexString(TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH, FALSE); fprintf(stderr, "unexpected MD4 hash: Actual: %s Expected: %s\n", actual, expected); free(actual); free(expected); - return -1; + return FALSE; } return TRUE; @@ -68,29 +74,32 @@ BOOL test_crypto_hash_md4() static const char* TEST_SHA1_DATA = "test"; static const BYTE* TEST_SHA1_HASH = (BYTE*) "\xa9\x4a\x8f\xe5\xcc\xb1\x9b\xa6\x1c\x4c\x08\x73\xd3\x91\xe9\x87\x98\x2f\xbb\xd3"; -BOOL test_crypto_hash_sha1() +static BOOL test_crypto_hash_sha1(void) { - BYTE hash[20]; + BYTE hash[WINPR_SHA1_DIGEST_LENGTH]; WINPR_SHA1_CTX ctx; - winpr_SHA1_Init(&ctx); - winpr_SHA1_Update(&ctx, (BYTE*) TEST_SHA1_DATA, strlen(TEST_SHA1_DATA)); - winpr_SHA1_Final(&ctx, hash); + if (!winpr_SHA1_Init(&ctx)) + return FALSE; + if (!winpr_SHA1_Update(&ctx, (BYTE*) TEST_SHA1_DATA, strlen(TEST_SHA1_DATA))) + return FALSE; + if (!winpr_SHA1_Final(&ctx, hash, sizeof(hash))) + return FALSE; - if (memcmp(hash, TEST_SHA1_HASH, 20) != 0) + if (memcmp(hash, TEST_SHA1_HASH, WINPR_MD5_DIGEST_LENGTH) != 0) { char* actual; char* expected; - actual = winpr_BinToHexString(hash, 20, FALSE); - expected = winpr_BinToHexString(TEST_SHA1_HASH, 20, FALSE); + actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE); + expected = winpr_BinToHexString(TEST_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE); fprintf(stderr, "unexpected SHA1 hash: Actual: %s Expected: %s\n", actual, expected); free(actual); free(expected); - return -1; + return FALSE; } return TRUE; @@ -100,29 +109,32 @@ static const char* TEST_HMAC_MD5_DATA = "Hi There"; static const BYTE* TEST_HMAC_MD5_KEY = (BYTE*) "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; static const BYTE* TEST_HMAC_MD5_HASH = (BYTE*) "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d"; -BOOL test_crypto_hash_hmac_md5() +static BOOL test_crypto_hash_hmac_md5(void) { - BYTE hash[16]; + BYTE hash[WINPR_MD5_DIGEST_LENGTH]; WINPR_HMAC_CTX ctx; - winpr_HMAC_Init(&ctx, WINPR_MD_MD5, TEST_HMAC_MD5_KEY, 16); - winpr_HMAC_Update(&ctx, (BYTE*) TEST_HMAC_MD5_DATA, strlen(TEST_HMAC_MD5_DATA)); - winpr_HMAC_Final(&ctx, hash); + if (!winpr_HMAC_Init(&ctx, WINPR_MD_MD5, TEST_HMAC_MD5_KEY, WINPR_MD5_DIGEST_LENGTH)) + return FALSE; + if (!winpr_HMAC_Update(&ctx, (BYTE*) TEST_HMAC_MD5_DATA, strlen(TEST_HMAC_MD5_DATA))) + return FALSE; + if (!winpr_HMAC_Final(&ctx, hash, sizeof(hash))) + return FALSE; - if (memcmp(hash, TEST_HMAC_MD5_HASH, 16) != 0) + if (memcmp(hash, TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0) { char* actual; char* expected; - actual = winpr_BinToHexString(hash, 16, FALSE); - expected = winpr_BinToHexString(TEST_HMAC_MD5_HASH, 16, FALSE); + actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE); + expected = winpr_BinToHexString(TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE); fprintf(stderr, "unexpected HMAC-MD5 hash: Actual: %s Expected: %s\n", actual, expected); free(actual); free(expected); - return -1; + return FALSE; } return TRUE; @@ -132,29 +144,32 @@ static const char* TEST_HMAC_SHA1_DATA = "Hi There"; static const BYTE* TEST_HMAC_SHA1_KEY = (BYTE*) "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; static const BYTE* TEST_HMAC_SHA1_HASH = (BYTE*) "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00"; -BOOL test_crypto_hash_hmac_sha1() +static BOOL test_crypto_hash_hmac_sha1(void) { - BYTE hash[20]; + BYTE hash[WINPR_SHA1_DIGEST_LENGTH]; WINPR_HMAC_CTX ctx; - winpr_HMAC_Init(&ctx, WINPR_MD_SHA1, TEST_HMAC_SHA1_KEY, 20); - winpr_HMAC_Update(&ctx, (BYTE*) TEST_HMAC_SHA1_DATA, strlen(TEST_HMAC_SHA1_DATA)); - winpr_HMAC_Final(&ctx, hash); + if (!winpr_HMAC_Init(&ctx, WINPR_MD_SHA1, TEST_HMAC_SHA1_KEY, WINPR_SHA1_DIGEST_LENGTH)) + return FALSE; + if (!winpr_HMAC_Update(&ctx, (BYTE*) TEST_HMAC_SHA1_DATA, strlen(TEST_HMAC_SHA1_DATA))) + return FALSE; + if (!winpr_HMAC_Final(&ctx, hash, sizeof(hash))) + return FALSE; - if (memcmp(hash, TEST_HMAC_SHA1_HASH, 20) != 0) + if (memcmp(hash, TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH) != 0) { char* actual; char* expected; - actual = winpr_BinToHexString(hash, 20, FALSE); - expected = winpr_BinToHexString(TEST_HMAC_SHA1_HASH, 20, FALSE); + actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE); + expected = winpr_BinToHexString(TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE); fprintf(stderr, "unexpected HMAC-SHA1 hash: Actual: %s Expected: %s\n", actual, expected); free(actual); free(expected); - return -1; + return FALSE; } return TRUE; diff --git a/winpr/libwinpr/dsparse/module.def b/winpr/libwinpr/dsparse/module.def deleted file mode 100644 index 683aae863..000000000 --- a/winpr/libwinpr/dsparse/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-dsparse" -EXPORTS - diff --git a/winpr/libwinpr/environment/module.def b/winpr/libwinpr/environment/module.def deleted file mode 100644 index e46493ad3..000000000 --- a/winpr/libwinpr/environment/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-environment" -EXPORTS diff --git a/winpr/libwinpr/error/module.def b/winpr/libwinpr/error/module.def deleted file mode 100644 index be897a9a8..000000000 --- a/winpr/libwinpr/error/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-error" -EXPORTS - diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 8d558d8c0..d8008ac34 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -24,7 +24,11 @@ #include -#ifndef _WIN32 +#ifdef _WIN32 + +#include + +#else /* _WIN32 */ #include "../log.h" #define TAG WINPR_TAG("file") @@ -36,6 +40,8 @@ #include #include #include +#include +#include static BOOL FileIsHandled(HANDLE handle) { @@ -342,6 +348,128 @@ static BOOL FileUnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfByte return TRUE; } +static BOOL FileSetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime) +{ + int rc; +#if defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) + struct stat buf; +#endif +/* OpenBSD, NetBSD and DragonflyBSD support POSIX futimens */ +#if defined(ANDROID) || defined(__FreeBSD__) + struct timeval timevals[2]; +#else + struct timespec times[2]; /* last access, last modification */ +#endif + WINPR_FILE* pFile = (WINPR_FILE*)hFile; + const UINT64 EPOCH_DIFF = 11644473600ULL; + + if (!hFile) + return FALSE; + +#if defined(__APPLE__) || defined(ANDROID) || defined(__FreeBSD__) + rc = fstat(fileno(pFile->fp), &buf); + if (rc < 0) + return FALSE; +#endif + if (!lpLastAccessTime) + { +#if defined(__APPLE__) +#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE) + times[0] = buf.st_atimespec; +#else + times[0].tv_sec = buf.st_atime; + times[0].tv_nsec = buf.st_atimensec; +#endif +#elif defined(__FreeBSD__) + timevals[0].tv_sec = buf.st_atime; +#ifdef _POSIX_SOURCE + TIMESPEC_TO_TIMEVAL(&timevals[0], &buf.st_atim); +#else + TIMESPEC_TO_TIMEVAL(&timevals[0], &buf.st_atimespec); +#endif +#elif defined(ANDROID) + timevals[0].tv_sec = buf.st_atime; + timevals[0].tv_usec = buf.st_atimensec / 1000UL; +#else + times[0].tv_sec = UTIME_OMIT; + times[0].tv_nsec = UTIME_OMIT; +#endif + } + else + { + UINT64 tmp = ((UINT64)lpLastAccessTime->dwHighDateTime) << 32 + | lpLastAccessTime->dwLowDateTime; + tmp -= EPOCH_DIFF; + tmp /= 10ULL; + +#if defined(ANDROID) || defined(__FreeBSD__) + tmp /= 10000ULL; + + timevals[0].tv_sec = tmp / 10000ULL; + timevals[0].tv_usec = tmp % 10000ULL; +#else + times[0].tv_sec = tmp / 10000000ULL; + times[0].tv_nsec = tmp % 10000000ULL; +#endif + } + if (!lpLastWriteTime) + { +#ifdef __APPLE__ +#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE) + times[1] = buf.st_mtimespec; +#else + times[1].tv_sec = buf.st_mtime; + times[1].tv_nsec = buf.st_mtimensec; +#endif +#elif defined(__FreeBSD__) + timevals[1].tv_sec = buf.st_mtime; +#ifdef _POSIX_SOURCE + TIMESPEC_TO_TIMEVAL(&timevals[1], &buf.st_mtim); +#else + TIMESPEC_TO_TIMEVAL(&timevals[1], &buf.st_mtimespec); +#endif +#elif defined(ANDROID) + timevals[1].tv_sec = buf.st_mtime; + timevals[1].tv_usec = buf.st_mtimensec / 1000UL; +#else + times[1].tv_sec = UTIME_OMIT; + times[1].tv_nsec = UTIME_OMIT; +#endif + } + else + { + UINT64 tmp = ((UINT64)lpLastWriteTime->dwHighDateTime) << 32 + | lpLastWriteTime->dwLowDateTime; + tmp -= EPOCH_DIFF; + tmp /= 10ULL; + +#if defined(ANDROID) || defined(__FreeBSD__) + tmp /= 10000ULL; + + timevals[1].tv_sec = tmp / 10000ULL; + timevals[1].tv_usec = tmp % 10000ULL; +#else + times[1].tv_sec = tmp / 10000000ULL; + times[1].tv_nsec = tmp % 10000000ULL; +#endif + } + + // TODO: Creation time can not be handled! +#ifdef __APPLE__ + rc = futimes(fileno(pFile->fp), times); +#elif defined(ANDROID) || defined(__FreeBSD__) + rc = utimes(pFile->lpFileName, timevals); +#else + rc = futimens(fileno(pFile->fp), times); +#endif + if (rc != 0) + return FALSE; + + return TRUE; + +} + static HANDLE_OPS fileOps = { FileIsHandled, FileCloseHandle, @@ -361,7 +489,8 @@ static HANDLE_OPS fileOps = { NULL, /* FileLockFile */ FileLockFileEx, FileUnlockFile, - FileUnlockFileEx + FileUnlockFileEx, + FileSetFileTime }; static HANDLE_OPS shmOps = { @@ -383,8 +512,8 @@ static HANDLE_OPS shmOps = { NULL, /* FileLockFile */ NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ - NULL /* FileUnlockFileEx */ - + NULL, /* FileUnlockFileEx */ + NULL /* FileSetFileTime */ }; @@ -503,7 +632,7 @@ BOOL IsFileDevice(LPCTSTR lpDeviceName) return TRUE; } -HANDLE_CREATOR _FileHandleCreator = +HANDLE_CREATOR _FileHandleCreator = { IsFileDevice, FileCreateFileA @@ -583,7 +712,7 @@ HANDLE GetFileHandleForFileDescriptor(int fd) { #ifdef _WIN32 return (HANDLE)_get_osfhandle(fd); -#else /* WIN32 */ +#else /* _WIN32 */ WINPR_FILE *pFile; FILE* fp; int flags; @@ -611,7 +740,7 @@ HANDLE GetFileHandleForFileDescriptor(int fd) return INVALID_HANDLE_VALUE; return (HANDLE)pFile; -#endif /* WIN32 */ +#endif /* _WIN32 */ } diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 8719787ad..71d4756a2 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -274,7 +274,7 @@ HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSTR lpFileNameA = NULL; HANDLE hdl; - if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL)) + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL) < 1) return NULL; hdl= CreateFileA(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes, @@ -296,7 +296,7 @@ BOOL DeleteFileW(LPCWSTR lpFileName) LPSTR lpFileNameA = NULL; BOOL rc = FALSE; - if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL)) + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL) < 1) return FALSE; rc = DeleteFileA(lpFileNameA); free (lpFileNameA); @@ -623,6 +623,27 @@ BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLo return FALSE; } +BOOL WINAPI SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime) +{ + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->SetFileTime) + return handle->ops->SetFileTime(handle, lpCreationTime, + lpLastAccessTime, lpLastWriteTime); + + WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__); + return FALSE; +} + struct _WIN32_FILE_SEARCH { DIR* pDir; diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c index b78f8eb7c..a318c9482 100644 --- a/winpr/libwinpr/file/namedPipeClient.c +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -51,14 +51,14 @@ static HANDLE_CREATOR _NamedPipeClientHandleCreator; static BOOL NamedPipeClientIsHandled(HANDLE handle) { - WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle; + WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle; - if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE)) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - return TRUE; + if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE)) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + return TRUE; } BOOL NamedPipeClientCloseHandle(HANDLE handle) @@ -124,7 +124,8 @@ static HANDLE_OPS ops = { NULL, /* FileLockFile */ NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ - NULL /* FileUnlockFileEx */ + NULL, /* FileUnlockFileEx */ + NULL /* SetFileTime */ }; static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index d2669baa7..fc49e6429 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -77,6 +77,8 @@ typedef BOOL (*pcUnlockFile)(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOf DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh); typedef BOOL (*pcUnlockFileEx)(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped); +typedef BOOL (*pcSetFileTime)(HANDLE hFile, const FILETIME *lpCreationTime, + const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime); typedef struct _HANDLE_OPS { @@ -99,6 +101,7 @@ typedef struct _HANDLE_OPS pcLockFileEx LockFileEx; pcUnlockFile UnlockFile; pcUnlockFileEx UnlockFileEx; + pcSetFileTime SetFileTime; } HANDLE_OPS; struct winpr_handle diff --git a/winpr/libwinpr/handle/module.def b/winpr/libwinpr/handle/module.def deleted file mode 100644 index 5e4d32f95..000000000 --- a/winpr/libwinpr/handle/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-handle" -EXPORTS - diff --git a/winpr/libwinpr/heap/module.def b/winpr/libwinpr/heap/module.def deleted file mode 100644 index 7b6e836dd..000000000 --- a/winpr/libwinpr/heap/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-heap" -EXPORTS diff --git a/winpr/libwinpr/input/keycode.c b/winpr/libwinpr/input/keycode.c index 3d445cbc4..1c628b2ff 100644 --- a/winpr/libwinpr/input/keycode.c +++ b/winpr/libwinpr/input/keycode.c @@ -405,7 +405,7 @@ DWORD KEYCODE_TO_VKCODE_EVDEV[256] = VK_DBE_KATAKANA, /* 98 */ VK_DBE_HIRAGANA, /* 99 */ VK_CONVERT, /* 100 */ - VK_DBE_HIRAGANA, /* 101 */ + VK_HKTG, /* 101 */ VK_NONCONVERT, /* 102 */ 0, /* 103 */ VK_RETURN | KBDEXT, /* 104 */ @@ -436,7 +436,7 @@ DWORD KEYCODE_TO_VKCODE_EVDEV[256] = VK_ABNT_C2, /* KEY_KPCOMMA 129 */ VK_HANGUL, /* 130 */ VK_HANJA, /* 131 */ - 0, /* 132 */ + VK_OEM_8, /* 132 */ VK_LWIN | KBDEXT, /* 133 */ VK_RWIN | KBDEXT, /* 134 */ VK_APPS | KBDEXT, /* 135 */ diff --git a/winpr/libwinpr/input/virtualkey.c b/winpr/libwinpr/input/virtualkey.c index 64f71f056..94d20fd4c 100644 --- a/winpr/libwinpr/input/virtualkey.c +++ b/winpr/libwinpr/input/virtualkey.c @@ -64,7 +64,7 @@ static const VIRTUAL_KEY_CODE VIRTUAL_KEY_CODE_TABLE[256] = { VK_JUNJA, "VK_JUNJA" }, { VK_FINAL, "VK_FINAL" }, { VK_KANJI, "VK_KANJI" }, /* also VK_HANJA */ - { 0, NULL }, + { VK_HKTG, "VK_HKTG" }, { VK_ESCAPE, "VK_ESCAPE" }, { VK_CONVERT, "VK_CONVERT" }, { VK_NONCONVERT, "VK_NONCONVERT" }, @@ -417,7 +417,7 @@ XKB_KEYNAME XKB_KEYNAME_TABLE[] = { "HENK", VK_CONVERT }, { "MUHE", VK_NONCONVERT }, - { "HKTG", VK_DBE_KATAKANA }, + { "HKTG", VK_HKTG }, // { "AE13", VK_BACKSLASH_JP }, // JP // { "LVL3", 0x54} @@ -425,9 +425,10 @@ XKB_KEYNAME XKB_KEYNAME_TABLE[] = char* GetVirtualKeyName(DWORD vkcode) { - char* vkname; + char* vkname = NULL; - vkname = (char*) VIRTUAL_KEY_CODE_TABLE[vkcode].name; + if (vkcode < ARRAYSIZE(VIRTUAL_KEY_CODE_TABLE)) + vkname = (char*) VIRTUAL_KEY_CODE_TABLE[vkcode].name; if (!vkname) vkname = "VK_NONE"; diff --git a/winpr/libwinpr/interlocked/module.def b/winpr/libwinpr/interlocked/module.def deleted file mode 100644 index 39f295109..000000000 --- a/winpr/libwinpr/interlocked/module.def +++ /dev/null @@ -1,14 +0,0 @@ -LIBRARY "libwinpr-interlocked" -EXPORTS - ; Not required on windows > 5.1 - ; InterlockedCompareExchange64 @1 - InitializeListHead @2 - IsListEmpty @3 - RemoveEntryList @4 - InsertHeadList @5 - RemoveHeadList @6 - InsertTailList @7 - RemoveTailList @8 - AppendTailList @9 - PushEntryList @10 - PopEntryList @11 diff --git a/winpr/libwinpr/io/module.def b/winpr/libwinpr/io/module.def deleted file mode 100644 index 1f984b577..000000000 --- a/winpr/libwinpr/io/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-io" -EXPORTS diff --git a/winpr/libwinpr/library/module.def b/winpr/libwinpr/library/module.def deleted file mode 100644 index c4a5071c4..000000000 --- a/winpr/libwinpr/library/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-library" -EXPORTS - diff --git a/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt b/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt index 3241f0939..b7c0649e2 100644 --- a/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt +++ b/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt @@ -21,7 +21,7 @@ set(MODULE_PREFIX "TEST_LIBRARY_A") set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} TestLibraryA.c) if(MSVC) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}) endif() add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) diff --git a/winpr/libwinpr/library/test/TestLibraryA/module.def b/winpr/libwinpr/library/test/TestLibraryA/module.def deleted file mode 100644 index d49a3e406..000000000 --- a/winpr/libwinpr/library/test/TestLibraryA/module.def +++ /dev/null @@ -1,4 +0,0 @@ -LIBRARY "TestLibraryA" -EXPORTS - FunctionA @1 - FunctionB @2 diff --git a/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt b/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt index ec4e85c63..c1cc32a2f 100644 --- a/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt +++ b/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt @@ -21,7 +21,7 @@ set(MODULE_PREFIX "TEST_LIBRARY_B") set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} TestLibraryB.c) if(MSVC) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS}) endif() add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) diff --git a/winpr/libwinpr/library/test/TestLibraryB/module.def b/winpr/libwinpr/library/test/TestLibraryB/module.def deleted file mode 100644 index 19ab14dd0..000000000 --- a/winpr/libwinpr/library/test/TestLibraryB/module.def +++ /dev/null @@ -1,4 +0,0 @@ -LIBRARY "TestLibraryB" -EXPORTS - FunctionA @1 - FunctionB @2 diff --git a/winpr/libwinpr/locale/module.def b/winpr/libwinpr/locale/module.def deleted file mode 100644 index 593aba52f..000000000 --- a/winpr/libwinpr/locale/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-locale" -EXPORTS diff --git a/winpr/libwinpr/memory/module.def b/winpr/libwinpr/memory/module.def deleted file mode 100644 index 14a9402ee..000000000 --- a/winpr/libwinpr/memory/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-memory" -EXPORTS - diff --git a/winpr/libwinpr/nt/module.def b/winpr/libwinpr/nt/module.def deleted file mode 100644 index b45c622b5..000000000 --- a/winpr/libwinpr/nt/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-nt" -EXPORTS - diff --git a/winpr/libwinpr/pipe/module.def b/winpr/libwinpr/pipe/module.def deleted file mode 100644 index 8c4cc1eac..000000000 --- a/winpr/libwinpr/pipe/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-pipe" -EXPORTS - diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index 02beb5d5b..0d8a6b6b0 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -191,7 +191,8 @@ static HANDLE_OPS ops = { NULL, /* FileLockFile */ NULL, /* FileLockFileEx */ NULL, /* FileUnlockFile */ - NULL /* FileUnlockFileEx */ + NULL, /* FileUnlockFileEx */ + NULL /* SetFileTime */ }; diff --git a/winpr/libwinpr/pool/module.def b/winpr/libwinpr/pool/module.def deleted file mode 100644 index 1651b3c99..000000000 --- a/winpr/libwinpr/pool/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-pool" -EXPORTS - diff --git a/winpr/libwinpr/registry/module.def b/winpr/libwinpr/registry/module.def deleted file mode 100644 index d65f4556c..000000000 --- a/winpr/libwinpr/registry/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-registry" -EXPORTS diff --git a/winpr/libwinpr/rpc/module.def b/winpr/libwinpr/rpc/module.def deleted file mode 100644 index 63efed138..000000000 --- a/winpr/libwinpr/rpc/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-rpc" -EXPORTS - diff --git a/winpr/libwinpr/security/module.def b/winpr/libwinpr/security/module.def deleted file mode 100644 index 9857be66b..000000000 --- a/winpr/libwinpr/security/module.def +++ /dev/null @@ -1,2 +0,0 @@ -LIBRARY "libwinpr-security" -EXPORTS diff --git a/winpr/libwinpr/smartcard/module.def b/winpr/libwinpr/smartcard/module.def deleted file mode 100644 index 3691a2338..000000000 --- a/winpr/libwinpr/smartcard/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-smartcard" -EXPORTS - diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 2a7beb0b5..060246658 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -239,6 +239,8 @@ void ntlm_ContextFree(NTLM_CONTEXT* context) if (!context) return; + winpr_RC4_Free(context->SendRc4Seal); + winpr_RC4_Free(context->RecvRc4Seal); sspi_SecBufferFree(&context->NegotiateMessage); sspi_SecBufferFree(&context->ChallengeMessage); sspi_SecBufferFree(&context->AuthenticateMessage); @@ -889,7 +891,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, int length; void* data; UINT32 SeqNo; - BYTE digest[16]; + BYTE digest[WINPR_MD5_DIGEST_LENGTH]; BYTE checksum[8]; BYTE* signature; ULONG version = 1; @@ -923,15 +925,15 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, CopyMemory(data, data_buffer->pvBuffer, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ - winpr_HMAC_Init(&hmac, WINPR_MD_MD5, context->SendSigningKey, 16); + winpr_HMAC_Init(&hmac, WINPR_MD_MD5, context->SendSigningKey, WINPR_MD5_DIGEST_LENGTH); winpr_HMAC_Update(&hmac, (void*) &(SeqNo), 4); winpr_HMAC_Update(&hmac, (void*) data, length); - winpr_HMAC_Final(&hmac, digest); + winpr_HMAC_Final(&hmac, digest, WINPR_MD5_DIGEST_LENGTH); /* Encrypt message using with RC4, result overwrites original buffer */ if (context->confidentiality) - winpr_RC4_Update(&context->SendRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer); + winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer); else CopyMemory(data_buffer->pvBuffer, data, length); @@ -943,7 +945,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, #endif free(data); /* RC4-encrypt first 8 bytes of digest */ - winpr_RC4_Update(&context->SendRc4Seal, 8, digest, checksum); + winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum); signature = (BYTE*) signature_buffer->pvBuffer; /* Concatenate version, ciphertext and sequence number to build signature */ CopyMemory(signature, (void*) &version, 4); @@ -963,12 +965,12 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD int length; void* data; UINT32 SeqNo; - BYTE digest[16]; + BYTE digest[WINPR_MD5_DIGEST_LENGTH]; BYTE checksum[8]; UINT32 version = 1; WINPR_HMAC_CTX hmac; NTLM_CONTEXT* context; - BYTE expected_signature[16]; + BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH]; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; SeqNo = (UINT32) MessageSeqNo; @@ -1000,15 +1002,15 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD /* Decrypt message using with RC4, result overwrites original buffer */ if (context->confidentiality) - winpr_RC4_Update(&context->RecvRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer); + winpr_RC4_Update(context->RecvRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer); else CopyMemory(data_buffer->pvBuffer, data, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ - winpr_HMAC_Init(&hmac, WINPR_MD_MD5, context->RecvSigningKey, 16); + winpr_HMAC_Init(&hmac, WINPR_MD_MD5, context->RecvSigningKey, WINPR_MD5_DIGEST_LENGTH); winpr_HMAC_Update(&hmac, (void*) &(SeqNo), 4); winpr_HMAC_Update(&hmac, (void*) data_buffer->pvBuffer, data_buffer->cbBuffer); - winpr_HMAC_Final(&hmac, digest); + winpr_HMAC_Final(&hmac, digest, WINPR_MD5_DIGEST_LENGTH); #ifdef WITH_DEBUG_NTLM WLog_DBG(TAG, "Encrypted Data Buffer (length = %d)", length); winpr_HexDump(TAG, WLOG_DEBUG, data, length); @@ -1017,7 +1019,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD #endif free(data); /* RC4-encrypt first 8 bytes of digest */ - winpr_RC4_Update(&context->RecvRc4Seal, 8, digest, checksum); + winpr_RC4_Update(context->RecvRc4Seal, 8, digest, checksum); /* Concatenate version, ciphertext and sequence number to build signature */ CopyMemory(expected_signature, (void*) &version, 4); CopyMemory(&expected_signature[4], (void*) checksum, 8); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h index bdccecdb3..8253f3d9b 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm.h @@ -225,8 +225,8 @@ struct _NTLM_CONTEXT BYTE MachineID[32]; BOOL SendVersionInfo; BOOL confidentiality; - WINPR_RC4_CTX SendRc4Seal; - WINPR_RC4_CTX RecvRc4Seal; + WINPR_RC4_CTX* SendRc4Seal; + WINPR_RC4_CTX* RecvRc4Seal; BYTE* SendSigningKey; BYTE* RecvSigningKey; BYTE* SendSealingKey; diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c index d3b980222..96d37384a 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c @@ -260,7 +260,7 @@ void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) UINT32 ChannelBindingTokenLength; SEC_CHANNEL_BINDINGS* ChannelBindings; - ZeroMemory(context->ChannelBindingsHash, 16); + ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH); ChannelBindings = context->Bindings.Bindings; if (!ChannelBindings) @@ -275,7 +275,7 @@ void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) ntlm_md5_update_uint32_be(&md5, ChannelBindings->cbAcceptorLength); ntlm_md5_update_uint32_be(&md5, ChannelBindings->cbApplicationDataLength); winpr_MD5_Update(&md5, (void*) ChannelBindingToken, ChannelBindingTokenLength); - winpr_MD5_Final(&md5, context->ChannelBindingsHash); + winpr_MD5_Final(&md5, context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH); } void ntlm_compute_single_host_data(NTLM_CONTEXT* context) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index b2973c4ac..8c18466f7 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -315,7 +315,7 @@ int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) { BYTE* response; - BYTE value[16]; + BYTE value[WINPR_MD5_DIGEST_LENGTH]; if (context->LmCompatibilityLevel < 2) { @@ -340,7 +340,9 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) response = (BYTE*) context->LmChallengeResponse.pvBuffer; /* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */ - winpr_HMAC(WINPR_MD_MD5, (void*) context->NtlmV2Hash, 16, (BYTE*) value, 16, (BYTE*) response); + winpr_HMAC(WINPR_MD_MD5, (void*) context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, + (BYTE*) value, WINPR_MD5_DIGEST_LENGTH, + (BYTE*) response, WINPR_MD5_DIGEST_LENGTH); /* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */ CopyMemory(&response[16], context->ClientChallenge, 8); return 1; @@ -356,7 +358,7 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) { BYTE* blob; - BYTE nt_proof_str[16]; + BYTE nt_proof_str[WINPR_MD5_DIGEST_LENGTH]; SecBuffer ntlm_v2_temp; SecBuffer ntlm_v2_temp_chal; PSecBuffer TargetInfo; @@ -385,7 +387,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) WLog_DBG(TAG, "Workstation (length = %d)", context->Workstation.Length); winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*) context->Workstation.Buffer, context->Workstation.Length); WLog_DBG(TAG, "NTOWFv2, NTLMv2 Hash"); - winpr_HexDump(TAG, WLOG_DEBUG, context->NtlmV2Hash, 16); + winpr_HexDump(TAG, WLOG_DEBUG, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH); #endif /* Construct temp */ blob[0] = 1; /* RespType (1 byte) */ @@ -409,8 +411,9 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) blob = (BYTE*) ntlm_v2_temp_chal.pvBuffer; CopyMemory(blob, context->ServerChallenge, 8); CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); - winpr_HMAC(WINPR_MD_MD5, (BYTE*) context->NtlmV2Hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer, - ntlm_v2_temp_chal.cbBuffer, (BYTE*) nt_proof_str); + winpr_HMAC(WINPR_MD_MD5, (BYTE*) context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, + (BYTE*) ntlm_v2_temp_chal.pvBuffer, ntlm_v2_temp_chal.cbBuffer, + (BYTE*) nt_proof_str, WINPR_MD5_DIGEST_LENGTH); /* NtChallengeResponse, Concatenate NTProofStr with temp */ @@ -421,7 +424,9 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) CopyMemory(blob, nt_proof_str, 16); CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); /* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */ - winpr_HMAC(WINPR_MD_MD5, (BYTE*) context->NtlmV2Hash, 16, (BYTE*) nt_proof_str, 16, (BYTE*) context->SessionBaseKey); + winpr_HMAC(WINPR_MD_MD5, (BYTE*) context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, + (BYTE*) nt_proof_str, WINPR_MD5_DIGEST_LENGTH, + (BYTE*) context->SessionBaseKey, WINPR_MD5_DIGEST_LENGTH); sspi_SecBufferFree(&ntlm_v2_temp); sspi_SecBufferFree(&ntlm_v2_temp_chal); return 1; @@ -437,10 +442,12 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) { - WINPR_RC4_CTX rc4; - winpr_RC4_Init(&rc4, (void*) key, 16); - winpr_RC4_Update(&rc4, length, (void*) plaintext, (void*) ciphertext); - winpr_RC4_Final(&rc4); + WINPR_RC4_CTX* rc4 = winpr_RC4_New(key, 16); + if (rc4) + { + winpr_RC4_Update(rc4, length, plaintext, ciphertext); + winpr_RC4_Free(rc4); + } } /** @@ -544,18 +551,18 @@ int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* value; WINPR_MD5_CTX md5; - length = 16 + sign_magic->cbBuffer; + length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer; value = (BYTE*) malloc(length); if (!value) return -1; /* Concatenate ExportedSessionKey with sign magic */ - CopyMemory(value, exported_session_key, 16); - CopyMemory(&value[16], sign_magic->pvBuffer, sign_magic->cbBuffer); + CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH); + CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer); winpr_MD5_Init(&md5); winpr_MD5_Update(&md5, value, length); - winpr_MD5_Final(&md5, signing_key); + winpr_MD5_Final(&md5, signing_key, WINPR_MD5_DIGEST_LENGTH); free(value); return 1; } @@ -602,16 +609,16 @@ int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, WINPR_MD5_CTX md5; SecBuffer buffer; - if (!sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer)) + if (!sspi_SecBufferAlloc(&buffer, WINPR_MD5_DIGEST_LENGTH + seal_magic->cbBuffer)) return -1; p = (BYTE*) buffer.pvBuffer; /* Concatenate ExportedSessionKey with seal magic */ - CopyMemory(p, exported_session_key, 16); - CopyMemory(&p[16], seal_magic->pvBuffer, seal_magic->cbBuffer); + CopyMemory(p, exported_session_key, WINPR_MD5_DIGEST_LENGTH); + CopyMemory(&p[WINPR_MD5_DIGEST_LENGTH], seal_magic->pvBuffer, seal_magic->cbBuffer); winpr_MD5_Init(&md5); winpr_MD5_Update(&md5, buffer.pvBuffer, buffer.cbBuffer); - winpr_MD5_Final(&md5, sealing_key); + winpr_MD5_Final(&md5, sealing_key, WINPR_MD5_DIGEST_LENGTH); sspi_SecBufferFree(&buffer); return 1; } @@ -657,8 +664,8 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) context->RecvSigningKey = context->ClientSigningKey; context->SendSealingKey = context->ClientSealingKey; context->RecvSealingKey = context->ServerSealingKey; - winpr_RC4_Init(&context->SendRc4Seal, context->ServerSealingKey, 16); - winpr_RC4_Init(&context->RecvRc4Seal, context->ClientSealingKey, 16); + context->SendRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16); + context->RecvRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16); } else { @@ -666,8 +673,8 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) context->RecvSigningKey = context->ServerSigningKey; context->SendSealingKey = context->ServerSealingKey; context->RecvSealingKey = context->ClientSealingKey; - winpr_RC4_Init(&context->SendRc4Seal, context->ClientSealingKey, 16); - winpr_RC4_Init(&context->RecvRc4Seal, context->ServerSealingKey, 16); + context->SendRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16); + context->RecvRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16); } } @@ -679,9 +686,9 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context) * CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey */ - winpr_HMAC_Init(&hmac, WINPR_MD_MD5, context->ExportedSessionKey, 16); + winpr_HMAC_Init(&hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH); winpr_HMAC_Update(&hmac, (BYTE*) context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); winpr_HMAC_Update(&hmac, (BYTE*) context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); winpr_HMAC_Update(&hmac, (BYTE*) context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer); - winpr_HMAC_Final(&hmac, context->MessageIntegrityCheck); + winpr_HMAC_Final(&hmac, context->MessageIntegrityCheck, WINPR_MD5_DIGEST_LENGTH); } diff --git a/winpr/libwinpr/sspi/module.def b/winpr/libwinpr/sspi/module.def deleted file mode 100644 index b08f89731..000000000 --- a/winpr/libwinpr/sspi/module.def +++ /dev/null @@ -1,34 +0,0 @@ -LIBRARY "libwinpr-sspi" -EXPORTS - AcceptSecurityContext - AcquireCredentialsHandleA - AcquireCredentialsHandleW - ApplyControlToken - CompleteAuthToken - DecryptMessage - DeleteSecurityContext - EncryptMessage - EnumerateSecurityPackagesA - EnumerateSecurityPackagesW - ExportSecurityContext - FreeContextBuffer - FreeCredentialsHandle - ImpersonateSecurityContext - ImportSecurityContextA - ImportSecurityContextW - InitSecurityInterfaceA - InitSecurityInterfaceW - InitializeSecurityContextA - InitializeSecurityContextW - MakeSignature - QueryContextAttributesA - QueryContextAttributesW - QueryCredentialsAttributesA - QueryCredentialsAttributesW - QuerySecurityContextToken - QuerySecurityPackageInfoA - QuerySecurityPackageInfoW - RevertSecurityContext - VerifySignature - InitSecurityInterfaceExA - InitSecurityInterfaceExW diff --git a/winpr/libwinpr/sysinfo/module.def b/winpr/libwinpr/sysinfo/module.def deleted file mode 100644 index 50f4066fc..000000000 --- a/winpr/libwinpr/sysinfo/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-sysinfo" -EXPORTS - diff --git a/winpr/libwinpr/thread/module.def b/winpr/libwinpr/thread/module.def deleted file mode 100644 index 688109ba6..000000000 --- a/winpr/libwinpr/thread/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-thread" -EXPORTS - diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index 54fd38874..39eaa3584 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -663,8 +663,7 @@ DWORD GetCurrentThreadId(VOID) /* Since pthread_t can be 64-bits on some systems, take just the */ /* lower 32-bits of it for the thread ID returned by this function. */ - tid = (long)tid & 0xffffffff; - return (DWORD) tid; + return (DWORD)tid & 0xffffffffUL; } DWORD ResumeThread(HANDLE hThread) diff --git a/winpr/libwinpr/timezone/timezone.c b/winpr/libwinpr/timezone/timezone.c index d910eaa39..f277d4abd 100644 --- a/winpr/libwinpr/timezone/timezone.c +++ b/winpr/libwinpr/timezone/timezone.c @@ -22,12 +22,1754 @@ #endif #include +#include +#include "../log.h" + +#define TAG WINPR_TAG("timezone") #ifndef _WIN32 +#include +#include + +struct _TIME_ZONE_RULE_ENTRY +{ + UINT64 TicksStart; + UINT64 TicksEnd; + INT32 DaylightDelta; + SYSTEMTIME StandardDate; + SYSTEMTIME DaylightDate; +}; +typedef struct _TIME_ZONE_RULE_ENTRY TIME_ZONE_RULE_ENTRY; + +struct _TIME_ZONE_ENTRY +{ + const char* Id; + UINT32 Bias; + BOOL SupportsDST; + const char* DisplayName; + const char* StandardName; + const char* DaylightName; + TIME_ZONE_RULE_ENTRY* RuleTable; + UINT32 RuleTableCount; +}; +typedef struct _TIME_ZONE_ENTRY TIME_ZONE_ENTRY; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_3[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_4[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_5[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_7[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_8[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_10[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_11[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_14[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_15[] = +{ + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_17[] = +{ + { 633662964000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 9, 6, 1, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_18[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_19[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 1, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 0, 1, 0, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_21[] = +{ + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 4, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 5, 6, 1, 23, 59 }, { 0, 8, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_22[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 0, 1 }, { 0, 4, 0, 1, 0, 1 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 11, 0, 1, 0, 1 }, { 0, 3, 0, 1, 0, 1 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 0, 1 }, }, + { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 11, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_23[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 2, 0, 1, 2, 0 }, { 0, 11, 0, 1, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 0, 1, 0, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 2, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_24[] = +{ + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 1, 1, 1, 0, 0 }, { 0, 12, 0, 1, 0, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 6, 1, 23, 59 }, { 0, 1, 4, 1, 0, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_26[] = +{ + { 633662964000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, }, + { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 1, 23, 0 }, { 0, 3, 6, 1, 22, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_27[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 9, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 10, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_28[] = +{ + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 1, 6, 1, 0, 0 }, { 0, 10, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638395956000000000ULL, 638081460000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 638712180000000000ULL, 638396820000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639027540000000000ULL, 638713044000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639342900000000000ULL, 639028404000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639658260000000000ULL, 639343764000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 639974484000000000ULL, 639659124000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640289844000000000ULL, 639975348000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640605204000000000ULL, 640290708000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 640920564000000000ULL, 640606068000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641236788000000000ULL, 640921428000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641552148000000000ULL, 641237652000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 641867508000000000ULL, 641553012000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642182868000000000ULL, 641868372000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642499092000000000ULL, 642183732000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 642814452000000000ULL, 642499956000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 643129812000000000ULL, 642815316000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 643445172000000000ULL, 643130676000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 643446036000000000ULL, 60, { 0, 2, 6, 1, 23, 59 }, { 0, 10, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_30[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_31[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_33[] = +{ + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 0, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 5, 0, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 8, 6, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 7, 6, 1, 23, 59 }, { 0, 4, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_35[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 0, 1, 1, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_37[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_38[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_39[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_40[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_42[] = +{ + { 634293684000000000ULL, 180000000000ULL, -60, { 0, 9, 0, 1, 2, 0 }, { 0, 4, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 2, 0 }, { 0, 9, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_43[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 5, 1, 1, 0 }, { 0, 3, 4, 1, 0, 0 }, }, + { 3155378292000000000ULL, 633032244000000000ULL, 60, { 0, 10, 5, 1, 1, 0 }, { 0, 3, 4, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_44[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_45[] = +{ + { 633978324000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 0, 0 }, { 0, 3, 0, 1, 0, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 637450740000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_46[] = +{ + { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 5, 1, 0, 0 }, }, + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 5, 1, 0, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 8, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_47[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 9, 3, 1, 23, 59 }, { 0, 3, 5, 1, 23, 59 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 11, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, + { 3155378292000000000ULL, 636188436000000000ULL, 60, { 0, 10, 4, 1, 23, 59 }, { 0, 4, 4, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_49[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_50[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 1, 1, 3, 0 }, }, + { 3155378292000000000ULL, 634609908000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 3, 0, 1, 3, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_51[] = +{ + { 632716020000000000ULL, 632401524000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 635240628000000000ULL, 634926132000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 635555988000000000ULL, 635241492000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 635871348000000000ULL, 635556852000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 636187572000000000ULL, 635872212000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, }, + { 636502932000000000ULL, 636188436000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 636818292000000000ULL, 636503796000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 637133652000000000ULL, 636819156000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 637449876000000000ULL, 637134516000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 637765236000000000ULL, 637450740000000000ULL, 60, { 0, 9, 0, 1, 2, 0 }, { 0, 3, 5, 1, 2, 0 }, }, + { 638080596000000000ULL, 637766100000000000ULL, 60, { 0, 10, 0, 1, 2, 0 }, { 0, 4, 5, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_52[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_53[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 4, 0 }, { 0, 4, 0, 1, 3, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 10, 1, 1, 4, 0 }, { 0, 4, 0, 1, 3, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_54[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_57[] = +{ + { 632716020000000000ULL, 180000000000ULL, 60, { 0, 9, 2, 1, 2, 0 }, { 0, 3, 0, 1, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 9, 6, 1, 23, 59 }, { 0, 3, 4, 1, 23, 59 }, }, + { 3155378292000000000ULL, 633663828000000000ULL, 60, { 0, 9, 1, 1, 23, 59 }, { 0, 3, 6, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_59[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 5, 0 }, { 0, 3, 0, 1, 4, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_60[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_61[] = +{ + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 1, 2, 1, 0, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 1, 2, 0 }, { 0, 1, 4, 1, 0, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_63[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_65[] = +{ + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 10, 5, 1, 23, 59 }, { 0, 5, 6, 1, 23, 59 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 10, 6, 1, 23, 59 }, { 0, 4, 2, 1, 23, 59 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_71[] = +{ + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 12, 4, 1, 23, 59 }, { 0, 6, 5, 1, 23, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_72[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_75[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_77[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_79[] = +{ + { 633031380000000000ULL, 632716884000000000ULL, 60, { 0, 1, 0, 1, 0, 0 }, { 0, 12, 0, 1, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633662964000000000ULL, 633347604000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 1, 4, 1, 0, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_82[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_85[] = +{ + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_88[] = +{ + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_90[] = +{ + { 633346740000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_91[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_93[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_94[] = +{ + { 633031380000000000ULL, 180000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 633346740000000000ULL, 633032244000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 9, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 633347604000000000ULL, 60, { 0, 4, 0, 1, 3, 0 }, { 0, 9, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_96[] = +{ + { 633978324000000000ULL, 633663828000000000ULL, 60, { 0, 1, 4, 1, 0, 0 }, { 0, 11, 0, 1, 2, 0 }, }, + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 634609044000000000ULL, 634294548000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 634925268000000000ULL, 634609908000000000ULL, 60, { 0, 1, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, }, + { 3155378292000000000ULL, 634926132000000000ULL, 60, { 0, 3, 0, 1, 3, 0 }, { 0, 10, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_97[] = +{ + { 634293684000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_98[] = +{ + { 3155378292000000000ULL, 180000000000ULL, 60, { 0, 10, 0, 1, 3, 0 }, { 0, 3, 0, 1, 2, 0 }, } +}; + +static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_100[] = +{ + { 634293684000000000ULL, 633979188000000000ULL, 60, { 0, 1, 5, 1, 0, 0 }, { 0, 9, 6, 1, 23, 59 }, }, + { 3155378292000000000ULL, 634294548000000000ULL, 60, { 0, 4, 0, 1, 1, 0 }, { 0, 9, 0, 1, 0, 0 }, } +}; + +static const TIME_ZONE_ENTRY TimeZoneTable[] = +{ + { + "Dateline Standard Time", 720, FALSE, "(UTC-12:00) International Date Line West", + "Dateline Standard Time", "Dateline Daylight Time", + NULL, 0 + }, + { + "UTC-11", 780, FALSE, "(UTC-11:00) Coordinated Universal Time-11", + "UTC-11", "UTC-11", + NULL, 0 + }, + { + "Hawaiian Standard Time", 840, FALSE, "(UTC-10:00) Hawaii", + "Hawaiian Standard Time", "Hawaiian Daylight Time", + NULL, 0 + }, + { + "Alaskan Standard Time", 900, TRUE, "(UTC-09:00) Alaska", + "Alaskan Standard Time", "Alaskan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_3, 2 + }, + { + "Pacific Standard Time (Mexico)", 960, TRUE, "(UTC-08:00) Baja California", + "Pacific Standard Time (Mexico)", "Pacific Daylight Time (Mexico)", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_4, 1 + }, + { + "Pacific Standard Time", 960, TRUE, "(UTC-08:00) Pacific Time (US & Canada)", + "Pacific Standard Time", "Pacific Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_5, 2 + }, + { + "US Mountain Standard Time", 1020, FALSE, "(UTC-07:00) Arizona", + "US Mountain Standard Time", "US Mountain Daylight Time", + NULL, 0 + }, + { + "Mountain Standard Time (Mexico)", 1020, TRUE, "(UTC-07:00) Chihuahua, La Paz, Mazatlan", + "Mountain Standard Time (Mexico)", "Mountain Daylight Time (Mexico)", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_7, 1 + }, + { + "Mountain Standard Time", 1020, TRUE, "(UTC-07:00) Mountain Time (US & Canada)", + "Mountain Standard Time", "Mountain Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_8, 2 + }, + { + "Central America Standard Time", 1080, FALSE, "(UTC-06:00) Central America", + "Central America Standard Time", "Central America Daylight Time", + NULL, 0 + }, + { + "Central Standard Time", 1080, TRUE, "(UTC-06:00) Central Time (US & Canada)", + "Central Standard Time", "Central Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_10, 2 + }, + { + "Central Standard Time (Mexico)", 1080, TRUE, "(UTC-06:00) Guadalajara, Mexico City, Monterrey", + "Central Standard Time (Mexico)", "Central Daylight Time (Mexico)", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_11, 1 + }, + { + "Canada Central Standard Time", 1080, FALSE, "(UTC-06:00) Saskatchewan", + "Canada Central Standard Time", "Canada Central Daylight Time", + NULL, 0 + }, + { + "SA Pacific Standard Time", 1140, FALSE, "(UTC-05:00) Bogota, Lima, Quito", + "SA Pacific Standard Time", "SA Pacific Daylight Time", + NULL, 0 + }, + { + "Eastern Standard Time", 1140, TRUE, "(UTC-05:00) Eastern Time (US & Canada)", + "Eastern Standard Time", "Eastern Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_14, 2 + }, + { + "US Eastern Standard Time", 1140, TRUE, "(UTC-05:00) Indiana (East)", + "US Eastern Standard Time", "US Eastern Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_15, 2 + }, + { + "Venezuela Standard Time", 1170, FALSE, "(UTC-04:30) Caracas", + "Venezuela Standard Time", "Venezuela Daylight Time", + NULL, 0 + }, + { + "Paraguay Standard Time", 1200, TRUE, "(UTC-04:00) Asuncion", + "Paraguay Standard Time", "Paraguay Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_17, 14 + }, + { + "Atlantic Standard Time", 1200, TRUE, "(UTC-04:00) Atlantic Time (Canada)", + "Atlantic Standard Time", "Atlantic Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_18, 2 + }, + { + "Central Brazilian Standard Time", 1200, TRUE, "(UTC-04:00) Cuiaba", + "Central Brazilian Standard Time", "Central Brazilian Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_19, 35 + }, + { + "SA Western Standard Time", 1200, FALSE, "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan", + "SA Western Standard Time", "SA Western Daylight Time", + NULL, 0 + }, + { + "Pacific SA Standard Time", 1200, TRUE, "(UTC-04:00) Santiago", + "Pacific SA Standard Time", "Pacific SA Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_21, 6 + }, + { + "Newfoundland Standard Time", 1230, TRUE, "(UTC-03:30) Newfoundland", + "Newfoundland Standard Time", "Newfoundland Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_22, 7 + }, + { + "E. South America Standard Time", 1260, TRUE, "(UTC-03:00) Brasilia", + "E. South America Standard Time", "E. South America Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_23, 35 + }, + { + "Argentina Standard Time", 1260, TRUE, "(UTC-03:00) Buenos Aires", + "Argentina Standard Time", "Argentina Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_24, 3 + }, + { + "SA Eastern Standard Time", 1260, FALSE, "(UTC-03:00) Cayenne, Fortaleza", + "SA Eastern Standard Time", "SA Eastern Daylight Time", + NULL, 0 + }, + { + "Greenland Standard Time", 1260, TRUE, "(UTC-03:00) Greenland", + "Greenland Standard Time", "Greenland Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_26, 14 + }, + { + "Montevideo Standard Time", 1260, TRUE, "(UTC-03:00) Montevideo", + "Montevideo Standard Time", "Montevideo Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_27, 2 + }, + { + "Bahia Standard Time", 1260, TRUE, "(UTC-03:00) Salvador", + "Bahia Standard Time", "Bahia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_28, 30 + }, + { + "UTC-02", 1320, FALSE, "(UTC-02:00) Coordinated Universal Time-02", + "UTC-02", "UTC-02", + NULL, 0 + }, + { + "Mid-Atlantic Standard Time", 1320, TRUE, "(UTC-02:00) Mid-Atlantic", + "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_30, 1 + }, + { + "Azores Standard Time", 1380, TRUE, "(UTC-01:00) Azores", + "Azores Standard Time", "Azores Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_31, 1 + }, + { + "Cape Verde Standard Time", 1380, FALSE, "(UTC-01:00) Cape Verde Is.", + "Cape Verde Standard Time", "Cape Verde Daylight Time", + NULL, 0 + }, + { + "Morocco Standard Time", 0, TRUE, "(UTC) Casablanca", + "Morocco Standard Time", "Morocco Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_33, 4 + }, + { + "UTC", 0, FALSE, "(UTC) Coordinated Universal Time", + "Coordinated Universal Time", "Coordinated Universal Time", + NULL, 0 + }, + { + "GMT Standard Time", 0, TRUE, "(UTC) Dublin, Edinburgh, Lisbon, London", + "GMT Standard Time", "GMT Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_35, 1 + }, + { + "Greenwich Standard Time", 0, FALSE, "(UTC) Monrovia, Reykjavik", + "Greenwich Standard Time", "Greenwich Daylight Time", + NULL, 0 + }, + { + "W. Europe Standard Time", 60, TRUE, "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", + "W. Europe Standard Time", "W. Europe Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_37, 1 + }, + { + "Central Europe Standard Time", 60, TRUE, "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague", + "Central Europe Standard Time", "Central Europe Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_38, 1 + }, + { + "Romance Standard Time", 60, TRUE, "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", + "Romance Standard Time", "Romance Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_39, 1 + }, + { + "Central European Standard Time", 60, TRUE, "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", + "Central European Standard Time", "Central European Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_40, 1 + }, + { + "W. Central Africa Standard Time", 60, FALSE, "(UTC+01:00) West Central Africa", + "W. Central Africa Standard Time", "W. Central Africa Daylight Time", + NULL, 0 + }, + { + "Namibia Standard Time", 60, TRUE, "(UTC+01:00) Windhoek", + "Namibia Standard Time", "Namibia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_42, 2 + }, + { + "Jordan Standard Time", 120, TRUE, "(UTC+02:00) Amman", + "Jordan Standard Time", "Jordan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_43, 2 + }, + { + "GTB Standard Time", 120, TRUE, "(UTC+02:00) Athens, Bucharest, Istanbul", + "GTB Standard Time", "GTB Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_44, 1 + }, + { + "Middle East Standard Time", 120, TRUE, "(UTC+02:00) Beirut", + "Middle East Standard Time", "Middle East Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_45, 13 + }, + { + "Egypt Standard Time", 120, TRUE, "(UTC+02:00) Cairo", + "Egypt Standard Time", "Egypt Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_46, 6 + }, + { + "Syria Standard Time", 120, TRUE, "(UTC+02:00) Damascus", + "Syria Standard Time", "Syria Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_47, 12 + }, + { + "South Africa Standard Time", 120, FALSE, "(UTC+02:00) Harare, Pretoria", + "South Africa Standard Time", "South Africa Daylight Time", + NULL, 0 + }, + { + "FLE Standard Time", 120, TRUE, "(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", + "FLE Standard Time", "FLE Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_49, 1 + }, + { + "Turkey Standard Time", 120, TRUE, "(UTC+02:00) Istanbul", + "Turkey Standard Time", "Turkey Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_50, 3 + }, + { + "Israel Standard Time", 120, TRUE, "(UTC+02:00) Jerusalem", + "Jerusalem Standard Time", "Jerusalem Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_51, 18 + }, + { + "E. Europe Standard Time", 120, TRUE, "(UTC+02:00) Nicosia", + "E. Europe Standard Time", "E. Europe Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_52, 1 + }, + { + "Arabic Standard Time", 180, TRUE, "(UTC+03:00) Baghdad", + "Arabic Standard Time", "Arabic Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_53, 2 + }, + { + "Kaliningrad Standard Time", 180, TRUE, "(UTC+03:00) Kaliningrad, Minsk", + "Kaliningrad Standard Time", "Kaliningrad Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_54, 1 + }, + { + "Arab Standard Time", 180, FALSE, "(UTC+03:00) Kuwait, Riyadh", + "Arab Standard Time", "Arab Daylight Time", + NULL, 0 + }, + { + "E. Africa Standard Time", 180, FALSE, "(UTC+03:00) Nairobi", + "E. Africa Standard Time", "E. Africa Daylight Time", + NULL, 0 + }, + { + "Iran Standard Time", 210, TRUE, "(UTC+03:30) Tehran", + "Iran Standard Time", "Iran Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_57, 3 + }, + { + "Arabian Standard Time", 240, FALSE, "(UTC+04:00) Abu Dhabi, Muscat", + "Arabian Standard Time", "Arabian Daylight Time", + NULL, 0 + }, + { + "Azerbaijan Standard Time", 240, TRUE, "(UTC+04:00) Baku", + "Azerbaijan Standard Time", "Azerbaijan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_59, 1 + }, + { + "Russian Standard Time", 240, TRUE, "(UTC+04:00) Moscow, St. Petersburg, Volgograd", + "Russian Standard Time", "Russian Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_60, 1 + }, + { + "Mauritius Standard Time", 240, TRUE, "(UTC+04:00) Port Louis", + "Mauritius Standard Time", "Mauritius Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_61, 2 + }, + { + "Georgian Standard Time", 240, FALSE, "(UTC+04:00) Tbilisi", + "Georgian Standard Time", "Georgian Daylight Time", + NULL, 0 + }, + { + "Caucasus Standard Time", 240, TRUE, "(UTC+04:00) Yerevan", + "Caucasus Standard Time", "Caucasus Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_63, 1 + }, + { + "Afghanistan Standard Time", 270, FALSE, "(UTC+04:30) Kabul", + "Afghanistan Standard Time", "Afghanistan Daylight Time", + NULL, 0 + }, + { + "Pakistan Standard Time", 300, TRUE, "(UTC+05:00) Islamabad, Karachi", + "Pakistan Standard Time", "Pakistan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_65, 2 + }, + { + "West Asia Standard Time", 300, FALSE, "(UTC+05:00) Tashkent", + "West Asia Standard Time", "West Asia Daylight Time", + NULL, 0 + }, + { + "India Standard Time", 330, FALSE, "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", + "India Standard Time", "India Daylight Time", + NULL, 0 + }, + { + "Sri Lanka Standard Time", 330, FALSE, "(UTC+05:30) Sri Jayawardenepura", + "Sri Lanka Standard Time", "Sri Lanka Daylight Time", + NULL, 0 + }, + { + "Nepal Standard Time", 345, FALSE, "(UTC+05:45) Kathmandu", + "Nepal Standard Time", "Nepal Daylight Time", + NULL, 0 + }, + { + "Central Asia Standard Time", 360, FALSE, "(UTC+06:00) Astana", + "Central Asia Standard Time", "Central Asia Daylight Time", + NULL, 0 + }, + { + "Bangladesh Standard Time", 360, TRUE, "(UTC+06:00) Dhaka", + "Bangladesh Standard Time", "Bangladesh Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_71, 1 + }, + { + "Ekaterinburg Standard Time", 360, TRUE, "(UTC+06:00) Ekaterinburg", + "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_72, 1 + }, + { + "Myanmar Standard Time", 390, FALSE, "(UTC+06:30) Yangon (Rangoon)", + "Myanmar Standard Time", "Myanmar Daylight Time", + NULL, 0 + }, + { + "SE Asia Standard Time", 420, FALSE, "(UTC+07:00) Bangkok, Hanoi, Jakarta", + "SE Asia Standard Time", "SE Asia Daylight Time", + NULL, 0 + }, + { + "N. Central Asia Standard Time", 420, TRUE, "(UTC+07:00) Novosibirsk", + "N. Central Asia Standard Time", "N. Central Asia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_75, 1 + }, + { + "China Standard Time", 480, FALSE, "(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", + "China Standard Time", "China Daylight Time", + NULL, 0 + }, + { + "North Asia Standard Time", 480, TRUE, "(UTC+08:00) Krasnoyarsk", + "North Asia Standard Time", "North Asia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_77, 1 + }, + { + "Singapore Standard Time", 480, FALSE, "(UTC+08:00) Kuala Lumpur, Singapore", + "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", + NULL, 0 + }, + { + "W. Australia Standard Time", 480, TRUE, "(UTC+08:00) Perth", + "W. Australia Standard Time", "W. Australia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_79, 4 + }, + { + "Taipei Standard Time", 480, FALSE, "(UTC+08:00) Taipei", + "Taipei Standard Time", "Taipei Daylight Time", + NULL, 0 + }, + { + "Ulaanbaatar Standard Time", 480, FALSE, "(UTC+08:00) Ulaanbaatar", + "Ulaanbaatar Standard Time", "Ulaanbaatar Daylight Time", + NULL, 0 + }, + { + "North Asia East Standard Time", 540, TRUE, "(UTC+09:00) Irkutsk", + "North Asia East Standard Time", "North Asia East Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_82, 1 + }, + { + "Tokyo Standard Time", 540, FALSE, "(UTC+09:00) Osaka, Sapporo, Tokyo", + "Tokyo Standard Time", "Tokyo Daylight Time", + NULL, 0 + }, + { + "Korea Standard Time", 540, FALSE, "(UTC+09:00) Seoul", + "Korea Standard Time", "Korea Daylight Time", + NULL, 0 + }, + { + "Cen. Australia Standard Time", 570, TRUE, "(UTC+09:30) Adelaide", + "Cen. Australia Standard Time", "Cen. Australia Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_85, 2 + }, + { + "AUS Central Standard Time", 570, FALSE, "(UTC+09:30) Darwin", + "AUS Central Standard Time", "AUS Central Daylight Time", + NULL, 0 + }, + { + "E. Australia Standard Time", 600, FALSE, "(UTC+10:00) Brisbane", + "E. Australia Standard Time", "E. Australia Daylight Time", + NULL, 0 + }, + { + "AUS Eastern Standard Time", 600, TRUE, "(UTC+10:00) Canberra, Melbourne, Sydney", + "AUS Eastern Standard Time", "AUS Eastern Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_88, 2 + }, + { + "West Pacific Standard Time", 600, FALSE, "(UTC+10:00) Guam, Port Moresby", + "West Pacific Standard Time", "West Pacific Daylight Time", + NULL, 0 + }, + { + "Tasmania Standard Time", 600, TRUE, "(UTC+10:00) Hobart", + "Tasmania Standard Time", "Tasmania Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_90, 2 + }, + { + "Yakutsk Standard Time", 600, TRUE, "(UTC+10:00) Yakutsk", + "Yakutsk Standard Time", "Yakutsk Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_91, 1 + }, + { + "Central Pacific Standard Time", 660, FALSE, "(UTC+11:00) Solomon Is., New Caledonia", + "Central Pacific Standard Time", "Central Pacific Daylight Time", + NULL, 0 + }, + { + "Vladivostok Standard Time", 660, TRUE, "(UTC+11:00) Vladivostok", + "Vladivostok Standard Time", "Vladivostok Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_93, 1 + }, + { + "New Zealand Standard Time", 720, TRUE, "(UTC+12:00) Auckland, Wellington", + "New Zealand Standard Time", "New Zealand Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_94, 3 + }, + { + "UTC+12", 720, FALSE, "(UTC+12:00) Coordinated Universal Time+12", + "UTC+12", "UTC+12", + NULL, 0 + }, + { + "Fiji Standard Time", 720, TRUE, "(UTC+12:00) Fiji", + "Fiji Standard Time", "Fiji Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_96, 5 + }, + { + "Magadan Standard Time", 720, TRUE, "(UTC+12:00) Magadan", + "Magadan Standard Time", "Magadan Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_97, 1 + }, + { + "Kamchatka Standard Time", 720, TRUE, "(UTC+12:00) Petropavlovsk-Kamchatsky - Old", + "Kamchatka Standard Time", "Kamchatka Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_98, 1 + }, + { + "Tonga Standard Time", 780, FALSE, "(UTC+13:00) Nuku'alofa", + "Tonga Standard Time", "Tonga Daylight Time", + NULL, 0 + }, + { + "Samoa Standard Time", 780, TRUE, "(UTC+13:00) Samoa", + "Samoa Standard Time", "Samoa Daylight Time", + (TIME_ZONE_RULE_ENTRY*) &TimeZoneRuleTable_100, 2 + } +}; + +/* Table generated with WindowsZones.cs */ + +struct _WINDOWS_TZID_ENTRY +{ + const char* windows; + const char* tzid; +}; +typedef struct _WINDOWS_TZID_ENTRY WINDOWS_TZID_ENTRY; + +const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[] = +{ + { "Afghanistan Standard Time", "Asia/Kabul" }, + { "Alaskan Standard Time", "America/Anchorage America/Juneau " + "America/Nome America/Sitka America/Yakutat" }, + { "Alaskan Standard Time", "America/Anchorage" }, + { "Arab Standard Time", "Asia/Aden" }, + { "Arab Standard Time", "Asia/Bahrain" }, + { "Arab Standard Time", "Asia/Kuwait" }, + { "Arab Standard Time", "Asia/Qatar" }, + { "Arab Standard Time", "Asia/Riyadh" }, + { "Arabian Standard Time", "Asia/Dubai" }, + { "Arabian Standard Time", "Asia/Muscat" }, + { "Arabian Standard Time", "Etc/GMT-4" }, + { "Arabic Standard Time", "Asia/Baghdad" }, + { "Argentina Standard Time", "America/Buenos_Aires America/Argentina/La_Rioja " + "America/Argentina/Rio_Gallegos America/Argentina/Salta " + "America/Argentina/San_Juan America/Argentina/San_Luis " + "America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca " + "America/Cordoba America/Jujuy America/Mendoza" }, + { "Argentina Standard Time", "America/Buenos_Aires" }, + { "Atlantic Standard Time", "America/Halifax America/Glace_Bay " + "America/Goose_Bay America/Moncton" }, + { "Atlantic Standard Time", "America/Halifax" }, + { "Atlantic Standard Time", "America/Thule" }, + { "Atlantic Standard Time", "Atlantic/Bermuda" }, + { "AUS Central Standard Time", "Australia/Darwin" }, + { "AUS Eastern Standard Time", "Australia/Sydney Australia/Melbourne" }, + { "AUS Eastern Standard Time", "Australia/Sydney" }, + { "Azerbaijan Standard Time", "Asia/Baku" }, + { "Azores Standard Time", "America/Scoresbysund" }, + { "Azores Standard Time", "Atlantic/Azores" }, + { "Bahia Standard Time", "America/Bahia" }, + { "Bangladesh Standard Time", "Asia/Dhaka" }, + { "Bangladesh Standard Time", "Asia/Thimphu" }, + { "Canada Central Standard Time", "America/Regina America/Swift_Current" }, + { "Canada Central Standard Time", "America/Regina" }, + { "Cape Verde Standard Time", "Atlantic/Cape_Verde" }, + { "Cape Verde Standard Time", "Etc/GMT+1" }, + { "Caucasus Standard Time", "Asia/Yerevan" }, + { "Cen. Australia Standard Time", "Australia/Adelaide Australia/Broken_Hill" }, + { "Cen. Australia Standard Time", "Australia/Adelaide" }, + { "Central America Standard Time", "America/Belize" }, + { "Central America Standard Time", "America/Costa_Rica" }, + { "Central America Standard Time", "America/El_Salvador" }, + { "Central America Standard Time", "America/Guatemala" }, + { "Central America Standard Time", "America/Managua" }, + { "Central America Standard Time", "America/Tegucigalpa" }, + { "Central America Standard Time", "Etc/GMT+6" }, + { "Central America Standard Time", "Pacific/Galapagos" }, + { "Central Asia Standard Time", "Antarctica/Vostok" }, + { "Central Asia Standard Time", "Asia/Almaty Asia/Qyzylorda" }, + { "Central Asia Standard Time", "Asia/Almaty" }, + { "Central Asia Standard Time", "Asia/Bishkek" }, + { "Central Asia Standard Time", "Etc/GMT-6" }, + { "Central Asia Standard Time", "Indian/Chagos" }, + { "Central Brazilian Standard Time", "America/Cuiaba America/Campo_Grande" }, + { "Central Brazilian Standard Time", "America/Cuiaba" }, + { "Central Europe Standard Time", "Europe/Belgrade" }, + { "Central Europe Standard Time", "Europe/Bratislava" }, + { "Central Europe Standard Time", "Europe/Budapest" }, + { "Central Europe Standard Time", "Europe/Ljubljana" }, + { "Central Europe Standard Time", "Europe/Podgorica" }, + { "Central Europe Standard Time", "Europe/Prague" }, + { "Central Europe Standard Time", "Europe/Tirane" }, + { "Central European Standard Time", "Europe/Sarajevo" }, + { "Central European Standard Time", "Europe/Skopje" }, + { "Central European Standard Time", "Europe/Warsaw" }, + { "Central European Standard Time", "Europe/Zagreb" }, + { "Central Pacific Standard Time", "Antarctica/Macquarie" }, + { "Central Pacific Standard Time", "Etc/GMT-11" }, + { "Central Pacific Standard Time", "Pacific/Efate" }, + { "Central Pacific Standard Time", "Pacific/Guadalcanal" }, + { "Central Pacific Standard Time", "Pacific/Noumea" }, + { "Central Pacific Standard Time", "Pacific/Ponape Pacific/Kosrae" }, + { "Central Standard Time (Mexico)", "America/Mexico_City America/Bahia_Banderas " + "America/Cancun America/Merida America/Monterrey" }, + { "Central Standard Time (Mexico)", "America/Mexico_City" }, + { "Central Standard Time", "America/Chicago America/Indiana/Knox " + "America/Indiana/Tell_City America/Menominee " + "America/North_Dakota/Beulah America/North_Dakota/Center " + "America/North_Dakota/New_Salem" }, + { "Central Standard Time", "America/Chicago" }, + { "Central Standard Time", "America/Matamoros" }, + { "Central Standard Time", "America/Winnipeg America/Rainy_River " + "America/Rankin_Inlet America/Resolute" }, + { "Central Standard Time", "CST6CDT" }, + { "China Standard Time", "Asia/Hong_Kong" }, + { "China Standard Time", "Asia/Macau" }, + { "China Standard Time", "Asia/Shanghai Asia/Chongqing Asia/Harbin Asia/Kashgar Asia/Urumqi" }, + { "China Standard Time", "Asia/Shanghai" }, + { "Dateline Standard Time", "Etc/GMT+12" }, + { "E. Africa Standard Time", "Africa/Addis_Ababa" }, + { "E. Africa Standard Time", "Africa/Asmera" }, + { "E. Africa Standard Time", "Africa/Dar_es_Salaam" }, + { "E. Africa Standard Time", "Africa/Djibouti" }, + { "E. Africa Standard Time", "Africa/Juba" }, + { "E. Africa Standard Time", "Africa/Kampala" }, + { "E. Africa Standard Time", "Africa/Khartoum" }, + { "E. Africa Standard Time", "Africa/Mogadishu" }, + { "E. Africa Standard Time", "Africa/Nairobi" }, + { "E. Africa Standard Time", "Antarctica/Syowa" }, + { "E. Africa Standard Time", "Etc/GMT-3" }, + { "E. Africa Standard Time", "Indian/Antananarivo" }, + { "E. Africa Standard Time", "Indian/Comoro" }, + { "E. Africa Standard Time", "Indian/Mayotte" }, + { "E. Australia Standard Time", "Australia/Brisbane Australia/Lindeman" }, + { "E. Australia Standard Time", "Australia/Brisbane" }, + { "E. Europe Standard Time", "Asia/Nicosia" }, + { "E. South America Standard Time", "America/Sao_Paulo" }, + { "Eastern Standard Time", "America/Grand_Turk" }, + { "Eastern Standard Time", "America/Nassau" }, + { "Eastern Standard Time", "America/New_York America/Detroit " + "America/Indiana/Petersburg America/Indiana/Vincennes " + "America/Indiana/Winamac America/Kentucky/Monticello America/Louisville" }, + { "Eastern Standard Time", "America/New_York" }, + { "Eastern Standard Time", "America/Toronto America/Iqaluit America/Montreal " + "America/Nipigon America/Pangnirtung America/Thunder_Bay" }, + { "Eastern Standard Time", "EST5EDT" }, + { "Egypt Standard Time", "Africa/Cairo" }, + { "Egypt Standard Time", "Asia/Gaza Asia/Hebron" }, + { "Ekaterinburg Standard Time", "Asia/Yekaterinburg" }, + { "Fiji Standard Time", "Pacific/Fiji" }, + { "FLE Standard Time", "Europe/Helsinki" }, + { "FLE Standard Time", "Europe/Kiev Europe/Simferopol Europe/Uzhgorod Europe/Zaporozhye" }, + { "FLE Standard Time", "Europe/Kiev" }, + { "FLE Standard Time", "Europe/Mariehamn" }, + { "FLE Standard Time", "Europe/Riga" }, + { "FLE Standard Time", "Europe/Sofia" }, + { "FLE Standard Time", "Europe/Tallinn" }, + { "FLE Standard Time", "Europe/Vilnius" }, + { "Georgian Standard Time", "Asia/Tbilisi" }, + { "GMT Standard Time", "Atlantic/Canary" }, + { "GMT Standard Time", "Atlantic/Faeroe" }, + { "GMT Standard Time", "Europe/Dublin" }, + { "GMT Standard Time", "Europe/Guernsey" }, + { "GMT Standard Time", "Europe/Isle_of_Man" }, + { "GMT Standard Time", "Europe/Jersey" }, + { "GMT Standard Time", "Europe/Lisbon Atlantic/Madeira" }, + { "GMT Standard Time", "Europe/London" }, + { "Greenland Standard Time", "America/Godthab" }, + { "Greenwich Standard Time", "Africa/Abidjan" }, + { "Greenwich Standard Time", "Africa/Accra" }, + { "Greenwich Standard Time", "Africa/Bamako" }, + { "Greenwich Standard Time", "Africa/Banjul" }, + { "Greenwich Standard Time", "Africa/Bissau" }, + { "Greenwich Standard Time", "Africa/Conakry" }, + { "Greenwich Standard Time", "Africa/Dakar" }, + { "Greenwich Standard Time", "Africa/El_Aaiun" }, + { "Greenwich Standard Time", "Africa/Freetown" }, + { "Greenwich Standard Time", "Africa/Lome" }, + { "Greenwich Standard Time", "Africa/Monrovia" }, + { "Greenwich Standard Time", "Africa/Nouakchott" }, + { "Greenwich Standard Time", "Africa/Ouagadougou" }, + { "Greenwich Standard Time", "Africa/Sao_Tome" }, + { "Greenwich Standard Time", "Atlantic/Reykjavik" }, + { "Greenwich Standard Time", "Atlantic/St_Helena" }, + { "GTB Standard Time", "Europe/Athens" }, + { "GTB Standard Time", "Europe/Bucharest" }, + { "GTB Standard Time", "Europe/Chisinau" }, + { "GTB Standard Time", "Europe/Istanbul" }, + { "Hawaiian Standard Time", "Etc/GMT+10" }, + { "Hawaiian Standard Time", "Pacific/Fakaofo" }, + { "Hawaiian Standard Time", "Pacific/Honolulu" }, + { "Hawaiian Standard Time", "Pacific/Johnston" }, + { "Hawaiian Standard Time", "Pacific/Rarotonga" }, + { "Hawaiian Standard Time", "Pacific/Tahiti" }, + { "India Standard Time", "Asia/Calcutta Asia/Kolkata" }, + { "Iran Standard Time", "Asia/Tehran" }, + { "Israel Standard Time", "Asia/Jerusalem" }, + { "Jordan Standard Time", "Asia/Amman" }, + { "Kaliningrad Standard Time", "Europe/Kaliningrad" }, + { "Kaliningrad Standard Time", "Europe/Minsk" }, + { "Korea Standard Time", "Asia/Pyongyang" }, + { "Korea Standard Time", "Asia/Seoul" }, + { "Magadan Standard Time", "Asia/Magadan Asia/Anadyr Asia/Kamchatka" }, + { "Magadan Standard Time", "Asia/Magadan" }, + { "Mauritius Standard Time", "Indian/Mahe" }, + { "Mauritius Standard Time", "Indian/Mauritius" }, + { "Mauritius Standard Time", "Indian/Reunion" }, + { "Middle East Standard Time", "Asia/Beirut" }, + { "Montevideo Standard Time", "America/Montevideo" }, + { "Morocco Standard Time", "Africa/Casablanca" }, + { "Mountain Standard Time (Mexico)", "America/Chihuahua America/Mazatlan" }, + { "Mountain Standard Time (Mexico)", "America/Chihuahua" }, + { "Mountain Standard Time", "America/Denver America/Boise America/Shiprock" }, + { "Mountain Standard Time", "America/Denver" }, + { "Mountain Standard Time", "America/Edmonton " + "America/Cambridge_Bay America/Inuvik America/Yellowknife" }, + { "Mountain Standard Time", "America/Ojinaga" }, + { "Mountain Standard Time", "MST7MDT" }, + { "Myanmar Standard Time", "Asia/Rangoon" }, + { "Myanmar Standard Time", "Indian/Cocos" }, + { "N. Central Asia Standard Time", "Asia/Novosibirsk Asia/Novokuznetsk Asia/Omsk" }, + { "N. Central Asia Standard Time", "Asia/Novosibirsk" }, + { "Namibia Standard Time", "Africa/Windhoek" }, + { "Nepal Standard Time", "Asia/Katmandu Asia/Kathmandu" }, + { "New Zealand Standard Time", "Antarctica/South_Pole Antarctica/McMurdo" }, + { "New Zealand Standard Time", "Pacific/Auckland" }, + { "Newfoundland Standard Time", "America/St_Johns" }, + { "North Asia East Standard Time", "Asia/Irkutsk" }, + { "North Asia Standard Time", "Asia/Krasnoyarsk" }, + { "Pacific SA Standard Time", "America/Santiago" }, + { "Pacific SA Standard Time", "Antarctica/Palmer" }, + { "Pacific Standard Time (Mexico)", "America/Santa_Isabel" }, + { "Pacific Standard Time", "America/Los_Angeles" }, + { "Pacific Standard Time", "America/Tijuana America/Ensenada" }, + { "Pacific Standard Time", "America/Vancouver America/Dawson America/Whitehorse" }, + { "Pacific Standard Time", "PST8PDT" }, + { "Pakistan Standard Time", "Asia/Karachi" }, + { "Paraguay Standard Time", "America/Asuncion" }, + { "Romance Standard Time", "Europe/Brussels" }, + { "Romance Standard Time", "Europe/Copenhagen" }, + { "Romance Standard Time", "Europe/Madrid Africa/Ceuta" }, + { "Romance Standard Time", "Europe/Paris" }, + { "Russian Standard Time", "Europe/Moscow Europe/Samara Europe/Volgograd" }, + { "Russian Standard Time", "Europe/Moscow" }, + { "SA Eastern Standard Time", "America/Cayenne" }, + { "SA Eastern Standard Time", "America/Fortaleza America/Araguaina " + "America/Belem America/Maceio America/Recife America/Santarem" }, + { "SA Eastern Standard Time", "America/Paramaribo" }, + { "SA Eastern Standard Time", "Antarctica/Rothera" }, + { "SA Eastern Standard Time", "Etc/GMT+3" }, + { "SA Pacific Standard Time", "America/Bogota" }, + { "SA Pacific Standard Time", "America/Cayman" }, + { "SA Pacific Standard Time", "America/Coral_Harbour" }, + { "SA Pacific Standard Time", "America/Guayaquil" }, + { "SA Pacific Standard Time", "America/Jamaica" }, + { "SA Pacific Standard Time", "America/Lima" }, + { "SA Pacific Standard Time", "America/Panama" }, + { "SA Pacific Standard Time", "America/Port-au-Prince" }, + { "SA Pacific Standard Time", "Etc/GMT+5" }, + { "SA Western Standard Time", "America/Anguilla" }, + { "SA Western Standard Time", "America/Antigua" }, + { "SA Western Standard Time", "America/Aruba" }, + { "SA Western Standard Time", "America/Barbados" }, + { "SA Western Standard Time", "America/Blanc-Sablon" }, + { "SA Western Standard Time", "America/Curacao" }, + { "SA Western Standard Time", "America/Dominica" }, + { "SA Western Standard Time", "America/Grenada" }, + { "SA Western Standard Time", "America/Guadeloupe" }, + { "SA Western Standard Time", "America/Guyana" }, + { "SA Western Standard Time", "America/La_Paz" }, + { "SA Western Standard Time", "America/Manaus America/Boa_Vista " + "America/Eirunepe America/Porto_Velho America/Rio_Branco" }, + { "SA Western Standard Time", "America/Marigot" }, + { "SA Western Standard Time", "America/Martinique" }, + { "SA Western Standard Time", "America/Montserrat" }, + { "SA Western Standard Time", "America/Port_of_Spain" }, + { "SA Western Standard Time", "America/Puerto_Rico" }, + { "SA Western Standard Time", "America/Santo_Domingo" }, + { "SA Western Standard Time", "America/St_Barthelemy" }, + { "SA Western Standard Time", "America/St_Kitts" }, + { "SA Western Standard Time", "America/St_Lucia" }, + { "SA Western Standard Time", "America/St_Thomas" }, + { "SA Western Standard Time", "America/St_Vincent" }, + { "SA Western Standard Time", "America/Tortola" }, + { "SA Western Standard Time", "Etc/GMT+4" }, + { "Samoa Standard Time", "Pacific/Apia Pacific/Samoa" }, + { "SE Asia Standard Time", "Antarctica/Davis" }, + { "SE Asia Standard Time", "Asia/Bangkok" }, + { "SE Asia Standard Time", "Asia/Hovd" }, + { "SE Asia Standard Time", "Asia/Jakarta Asia/Pontianak" }, + { "SE Asia Standard Time", "Asia/Phnom_Penh" }, + { "SE Asia Standard Time", "Asia/Saigon Asia/Ho_Chi_Minh" }, + { "SE Asia Standard Time", "Asia/Vientiane" }, + { "SE Asia Standard Time", "Etc/GMT-7" }, + { "SE Asia Standard Time", "Indian/Christmas" }, + { "Singapore Standard Time", "Asia/Brunei" }, + { "Singapore Standard Time", "Asia/Kuala_Lumpur Asia/Kuching" }, + { "Singapore Standard Time", "Asia/Makassar" }, + { "Singapore Standard Time", "Asia/Manila" }, + { "Singapore Standard Time", "Asia/Singapore" }, + { "Singapore Standard Time", "Etc/GMT-8" }, + { "South Africa Standard Time", "Africa/Blantyre" }, + { "South Africa Standard Time", "Africa/Bujumbura" }, + { "South Africa Standard Time", "Africa/Gaborone" }, + { "South Africa Standard Time", "Africa/Harare" }, + { "South Africa Standard Time", "Africa/Johannesburg" }, + { "South Africa Standard Time", "Africa/Kigali" }, + { "South Africa Standard Time", "Africa/Lubumbashi" }, + { "South Africa Standard Time", "Africa/Lusaka" }, + { "South Africa Standard Time", "Africa/Maputo" }, + { "South Africa Standard Time", "Africa/Maseru" }, + { "South Africa Standard Time", "Africa/Mbabane" }, + { "South Africa Standard Time", "Africa/Tripoli" }, + { "South Africa Standard Time", "Etc/GMT-2" }, + { "Sri Lanka Standard Time", "Asia/Colombo" }, + { "Syria Standard Time", "Asia/Damascus" }, + { "Taipei Standard Time", "Asia/Taipei" }, + { "Tasmania Standard Time", "Australia/Hobart Australia/Currie" }, + { "Tasmania Standard Time", "Australia/Hobart" }, + { "Tokyo Standard Time", "Asia/Dili" }, + { "Tokyo Standard Time", "Asia/Jayapura" }, + { "Tokyo Standard Time", "Asia/Tokyo" }, + { "Tokyo Standard Time", "Etc/GMT-9" }, + { "Tokyo Standard Time", "Pacific/Palau" }, + { "Tonga Standard Time", "Etc/GMT-13" }, + { "Tonga Standard Time", "Pacific/Enderbury" }, + { "Tonga Standard Time", "Pacific/Tongatapu" }, + /* { "Turkey Standard Time", "Europe/Istanbul" }, */ + { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar Asia/Choibalsan" }, + { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar" }, + { "US Eastern Standard Time", "America/Indianapolis " + "America/Indiana/Marengo America/Indiana/Vevay" }, + { "US Eastern Standard Time", "America/Indianapolis" }, + { "US Mountain Standard Time", "America/Dawson_Creek" }, + { "US Mountain Standard Time", "America/Hermosillo" }, + { "US Mountain Standard Time", "America/Phoenix" }, + { "US Mountain Standard Time", "Etc/GMT+7" }, + { "UTC", "America/Danmarkshavn" }, + { "UTC", "Etc/GMT" }, + { "UTC+12", "Etc/GMT-12" }, + { "UTC+12", "Pacific/Funafuti" }, + { "UTC+12", "Pacific/Majuro Pacific/Kwajalein" }, + { "UTC+12", "Pacific/Nauru" }, + { "UTC+12", "Pacific/Tarawa" }, + { "UTC+12", "Pacific/Wake" }, + { "UTC+12", "Pacific/Wallis" }, + { "UTC-02", "America/Noronha" }, + { "UTC-02", "Atlantic/South_Georgia" }, + { "UTC-02", "Etc/GMT+2" }, + { "UTC-11", "Etc/GMT+11" }, + { "UTC-11", "Pacific/Midway" }, + { "UTC-11", "Pacific/Niue" }, + { "UTC-11", "Pacific/Pago_Pago" }, + { "Venezuela Standard Time", "America/Caracas" }, + { "Vladivostok Standard Time", "Asia/Vladivostok Asia/Sakhalin" }, + { "Vladivostok Standard Time", "Asia/Vladivostok" }, + { "W. Australia Standard Time", "Antarctica/Casey" }, + { "W. Australia Standard Time", "Australia/Perth" }, + { "W. Central Africa Standard Time", "Africa/Algiers" }, + { "W. Central Africa Standard Time", "Africa/Bangui" }, + { "W. Central Africa Standard Time", "Africa/Brazzaville" }, + { "W. Central Africa Standard Time", "Africa/Douala" }, + { "W. Central Africa Standard Time", "Africa/Kinshasa" }, + { "W. Central Africa Standard Time", "Africa/Lagos" }, + { "W. Central Africa Standard Time", "Africa/Libreville" }, + { "W. Central Africa Standard Time", "Africa/Luanda" }, + { "W. Central Africa Standard Time", "Africa/Malabo" }, + { "W. Central Africa Standard Time", "Africa/Ndjamena" }, + { "W. Central Africa Standard Time", "Africa/Niamey" }, + { "W. Central Africa Standard Time", "Africa/Porto-Novo" }, + { "W. Central Africa Standard Time", "Africa/Tunis" }, + { "W. Central Africa Standard Time", "Etc/GMT-1" }, + { "W. Europe Standard Time", "Arctic/Longyearbyen" }, + { "W. Europe Standard Time", "Europe/Amsterdam" }, + { "W. Europe Standard Time", "Europe/Andorra" }, + { "W. Europe Standard Time", "Europe/Berlin" }, + { "W. Europe Standard Time", "Europe/Gibraltar" }, + { "W. Europe Standard Time", "Europe/Luxembourg" }, + { "W. Europe Standard Time", "Europe/Malta" }, + { "W. Europe Standard Time", "Europe/Monaco" }, + { "W. Europe Standard Time", "Europe/Oslo" }, + { "W. Europe Standard Time", "Europe/Rome" }, + { "W. Europe Standard Time", "Europe/San_Marino" }, + { "W. Europe Standard Time", "Europe/Stockholm" }, + { "W. Europe Standard Time", "Europe/Vaduz" }, + { "W. Europe Standard Time", "Europe/Vatican" }, + { "W. Europe Standard Time", "Europe/Vienna" }, + { "W. Europe Standard Time", "Europe/Zurich" }, + { "West Asia Standard Time", "Antarctica/Mawson" }, + { "West Asia Standard Time", "Asia/Ashgabat" }, + { "West Asia Standard Time", "Asia/Dushanbe" }, + { "West Asia Standard Time", "Asia/Oral Asia/Aqtau Asia/Aqtobe" }, + { "West Asia Standard Time", "Asia/Tashkent Asia/Samarkand" }, + { "West Asia Standard Time", "Asia/Tashkent" }, + { "West Asia Standard Time", "Etc/GMT-5" }, + { "West Asia Standard Time", "Indian/Kerguelen" }, + { "West Asia Standard Time", "Indian/Maldives" }, + { "West Pacific Standard Time", "Antarctica/DumontDUrville" }, + { "West Pacific Standard Time", "Etc/GMT-10" }, + { "West Pacific Standard Time", "Pacific/Guam" }, + { "West Pacific Standard Time", "Pacific/Port_Moresby" }, + { "West Pacific Standard Time", "Pacific/Saipan" }, + { "West Pacific Standard Time", "Pacific/Truk" }, + { "Yakutsk Standard Time", "Asia/Yakutsk" } +}; + +static UINT64 winpr_windows_gmtime() +{ + time_t unix_time; + UINT64 windows_time; + + time(&unix_time); + windows_time = unix_time; + windows_time *= 10000000; + windows_time += 621355968000000000ULL; + + return windows_time; +} + +static char* winpr_read_unix_timezone_identifier_from_file(FILE* fp) +{ + long length; + char* tzid = NULL; + + if (fseek(fp, 0, SEEK_END) != 0) + return NULL; + length = ftell(fp); + if (fseek(fp, 0, SEEK_SET) != 0) + return NULL; + + if (length < 2) + return NULL; + + tzid = (char*) malloc(length + 1); + if (!tzid) + return NULL; + + if (fread(tzid, length, 1, fp) != 1) + { + free(tzid); + return NULL; + } + + tzid[length] = '\0'; + if (tzid[length - 1] == '\n') + tzid[length - 1] = '\0'; + + return tzid; +} + +static char* winpr_get_timezone_from_link(void) +{ + const char* links[] = + { + "/etc/localtime", + "/etc/TZ" + }; + size_t x; + ssize_t len; + char buf[1024]; + char* tzid = NULL; + + /* + * On linux distros such as Redhat or Archlinux, a symlink at /etc/localtime + * will point to /usr/share/zoneinfo/region/place where region/place could be + * America/Montreal for example. + * Some distributions do have to symlink at /etc/TZ. + */ + + for (x=0; xBias = bias; + return timezone; + } + } + } + + WLog_ERR(TAG, "Unable to find a match for unix timezone: %s", tzid); + free(tzid); + return NULL; +} + +static TIME_ZONE_RULE_ENTRY* winpr_get_current_time_zone_rule(TIME_ZONE_RULE_ENTRY* rules, UINT32 count) +{ + int i; + UINT64 windows_time; + + windows_time = winpr_windows_gmtime(); + + for (i = 0; i < (int) count; i++) + { + if ((rules[i].TicksStart >= windows_time) && (windows_time >= rules[i].TicksEnd)) + { + /*WLog_ERR(TAG, "Got rule %d from table at %p with count %u", i, rules, count);*/ + return &rules[i]; + } + } + + WLog_ERR(TAG, "Unable to get current timezone rule"); + return NULL; +} + DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation) { - return 0; + time_t t; + struct tm* local_time; + TIME_ZONE_ENTRY* dtz; + LPTIME_ZONE_INFORMATION tz = lpTimeZoneInformation; + + lpTimeZoneInformation->StandardBias = 0; + + time(&t); + local_time = localtime(&t); + + memset(tz, 0, sizeof(TIME_ZONE_INFORMATION)); + +#ifdef HAVE_TM_GMTOFF + #if defined(__FreeBSD__) || defined(__OpenBSD__) + if (local_time->tm_gmtoff >= 0) + tz->Bias = (UINT32) (local_time->tm_gmtoff / 60); + else + tz->Bias = (UINT32) (1440 + (INT32) (local_time->tm_gmtoff / 60)); + #else + tz->Bias = (UINT32) (local_time->tm_gmtoff / 60); + #endif +#else + tz->Bias = 0; +#endif + + dtz = winpr_detect_windows_time_zone(tz->Bias); + + if (dtz!= NULL) + { + int status; + WLog_DBG(TAG, "tz: Bias=%d sn='%s' dln='%s'", + dtz->Bias, dtz->StandardName, dtz->DaylightName); + + tz->Bias = dtz->Bias; + tz->StandardBias = dtz->Bias; + tz->DaylightBias = dtz->Bias; + + ZeroMemory(tz->StandardName, sizeof(tz->StandardName)); + ZeroMemory(tz->DaylightName, sizeof(tz->DaylightName)); + status = MultiByteToWideChar(CP_UTF8, 0, dtz->StandardName, -1, tz->StandardName, + sizeof(tz->StandardName)/sizeof(WCHAR)-1); + if (status < 1) + { + WLog_ERR(TAG, "StandardName convertion failed - using default"); + goto out_error; + } + + status = MultiByteToWideChar(CP_UTF8, 0, dtz->DaylightName, -1, tz->DaylightName, + sizeof(tz->DaylightName)/sizeof(WCHAR)-1); + if (status < 1) + { + WLog_ERR(TAG, "DaylightName convertion failed - using default"); + goto out_error; + } + + if ((dtz->SupportsDST) && (dtz->RuleTableCount > 0)) + { + TIME_ZONE_RULE_ENTRY* rule; + rule = winpr_get_current_time_zone_rule(dtz->RuleTable, dtz->RuleTableCount); + + if (rule != NULL) + { + tz->DaylightBias = -rule->DaylightDelta; + + tz->StandardDate = rule->StandardDate; + tz->DaylightDate = rule->DaylightDate; + } + } + free(dtz); + + /* 1 ... TIME_ZONE_ID_STANDARD + * 2 ... TIME_ZONE_ID_DAYLIGHT */ + return local_time->tm_isdst ? 2 : 1; + } + else + { + /* could not detect timezone, fallback to using GMT */ + WLog_DBG(TAG, "tz not found, using GMT."); +out_error: + memcpy(tz->StandardName, L"GMT Standard Time", sizeof(tz->StandardName)); + memcpy(tz->DaylightName, L"GMT Daylight Time", sizeof(tz->DaylightName)); + return 0; /* TIME_ZONE_ID_UNKNOWN */ + } } BOOL SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation) diff --git a/winpr/libwinpr/utils/ntlm.c b/winpr/libwinpr/utils/ntlm.c index 709d4d89c..be1deaedc 100644 --- a/winpr/libwinpr/utils/ntlm.c +++ b/winpr/libwinpr/utils/ntlm.c @@ -42,9 +42,12 @@ BYTE* NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash) if (!NtHash && !(NtHash = malloc(16))) return NULL; - winpr_MD4_Init(&md4); - winpr_MD4_Update(&md4, (BYTE*) Password, (size_t) PasswordLength); - winpr_MD4_Final(&md4, NtHash); + if (!winpr_MD4_Init(&md4)) + return NULL; + if (!winpr_MD4_Update(&md4, (BYTE*) Password, (size_t) PasswordLength)) + return NULL; + if (!winpr_MD4_Final(&md4, NtHash, WINPR_MD4_DIGEST_LENGTH)) + return NULL; return NtHash; } @@ -77,11 +80,12 @@ BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User, { BYTE* buffer; BYTE NtHashV1[16]; + BYTE* result = NtHash; if ((!User) || (!Password)) return NULL; - if (!NtHash && !(NtHash = (BYTE*) malloc(16))) + if (!NtHash && !(NtHash = (BYTE*) malloc(WINPR_MD4_DIGEST_LENGTH))) return NULL; if (!NTOWFv1W(Password, PasswordLength, NtHashV1)) @@ -103,11 +107,12 @@ BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User, CopyMemory(&buffer[UserLength], Domain, DomainLength); /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is the NTLMv2 hash */ - winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLength + DomainLength, NtHash); + if (!winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLength + DomainLength, NtHash, WINPR_MD4_DIGEST_LENGTH)) + result = NULL; free(buffer); - return NtHash; + return result; } BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, @@ -141,11 +146,12 @@ out_fail: BYTE* NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength, LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash) { BYTE* buffer; + BYTE* result = NtHash; if (!User) return NULL; - if (!NtHash && !(NtHash = (BYTE*) malloc(16))) + if (!NtHash && !(NtHash = (BYTE*) malloc(WINPR_MD4_DIGEST_LENGTH))) return NULL; if (!(buffer = (BYTE*) malloc(UserLength + DomainLength))) @@ -165,11 +171,12 @@ BYTE* NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength, LPWSTR Do } /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is the NTLMv2 hash */ - winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLength + DomainLength, NtHash); + if (!winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLength + DomainLength, NtHash, WINPR_MD4_DIGEST_LENGTH)) + result = NULL; free(buffer); - return NtHash; + return result; } BYTE* NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash) diff --git a/winpr/libwinpr/utils/test/TestStream.c b/winpr/libwinpr/utils/test/TestStream.c index 005dcef1b..7b0a75142 100644 --- a/winpr/libwinpr/utils/test/TestStream.c +++ b/winpr/libwinpr/utils/test/TestStream.c @@ -261,6 +261,252 @@ static BOOL TestStream_Reading(void) return result; } +static BOOL TestStream_Write(void) +{ + BOOL rc = FALSE; + UINT8 u8; + UINT16 u16; + UINT32 u32; + UINT64 u64; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, 100); + if (!s) + goto out; + if (s->pointer != s->buffer) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) == 0) + rc = TRUE; + if (s->pointer != s->buffer + sizeof(data)) + goto out; + + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Write_UINT8(s, 42); + if (s->pointer != s->buffer + 1) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT8(s, u8); + if (u8 != 42) + goto out; + + Stream_Write_UINT16(s, 0x1234); + if (s->pointer != s->buffer + 2) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT16(s, u16); + if (u16 != 0x1234) + goto out; + + Stream_Write_UINT32(s, 0x12345678UL); + if (s->pointer != s->buffer + 4) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT32(s, u32); + if (u32 != 0x12345678UL) + goto out; + + Stream_Write_UINT64(s, 0x1234567890ABCDEFULL); + if (s->pointer != s->buffer + 8) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Peek_UINT64(s, u64); + if (u64 != 0x1234567890ABCDEFULL) + goto out; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Seek(void) +{ + BOOL rc = FALSE; + wStream* s = Stream_New(NULL, 100); + if (!s) + goto out; + + if (s->pointer != s->buffer) + goto out; + + Stream_Seek(s, 5); + if (s->pointer != s->buffer + 5) + goto out; + Stream_Seek_UINT8(s); + if (s->pointer != s->buffer + 6) + goto out; + + Stream_Seek_UINT16(s); + if (s->pointer != s->buffer + 8) + goto out; + + Stream_Seek_UINT32(s); + if (s->pointer != s->buffer + 12) + goto out; + Stream_Seek_UINT64(s); + if (s->pointer != s->buffer + 20) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Rewind(void) +{ + BOOL rc = FALSE; + wStream* s = Stream_New(NULL, 100); + if (!s) + goto out; + if (s->pointer != s->buffer) + goto out; + + Stream_Seek(s, 100); + if (s->pointer != s->buffer + 100) + goto out; + + Stream_Rewind(s, 10); + if (s->pointer != s->buffer + 90) + goto out; + Stream_Rewind_UINT8(s); + if (s->pointer != s->buffer + 89) + goto out; + Stream_Rewind_UINT16(s); + if (s->pointer != s->buffer + 87) + goto out; + + Stream_Rewind_UINT32(s); + if (s->pointer != s->buffer + 83) + goto out; + Stream_Rewind_UINT64(s); + if (s->pointer != s->buffer + 75) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Zero(void) +{ + UINT32 x; + BOOL rc = FALSE; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, sizeof(data)); + if (!s) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Zero(s, 5); + if (s->pointer != s->buffer + 5) + goto out; + if (memcmp(Stream_Pointer(s), data+5, sizeof(data)-5) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + for (x=0; x<5; x++) + { + UINT8 val; + Stream_Read_UINT8(s, val); + if (val != 0) + goto out; + } + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Fill(void) +{ + BOOL rc = FALSE; + const BYTE fill[7] = "XXXXXXX"; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, sizeof(data)); + if (!s) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + Stream_Fill(s, fill[0], sizeof(fill)); + if (s->pointer != s->buffer + sizeof(fill)) + goto out; + if (memcmp(Stream_Pointer(s), data+sizeof(fill), sizeof(data)-sizeof(fill)) != 0) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + if (memcmp(Stream_Pointer(s), fill, sizeof(fill)) != 0) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + return rc; +} + +static BOOL TestStream_Copy(void) +{ + BOOL rc = FALSE; + const BYTE data[] = "someteststreamdata"; + wStream* s = Stream_New(NULL, sizeof(data)); + wStream* d = Stream_New(NULL, sizeof(data)); + if (!s || !d) + goto out; + if (s->pointer != s->buffer) + goto out; + + Stream_Write(s, data, sizeof(data)); + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + if (s->pointer != s->buffer + sizeof(data)) + goto out; + Stream_SetPosition(s, 0); + if (s->pointer != s->buffer) + goto out; + + Stream_Copy(s, d, sizeof(data)); + if (s->pointer != s->buffer + sizeof(data)) + goto out; + if (d->pointer != d->buffer + sizeof(data)) + goto out; + if (Stream_GetPosition(s) != Stream_GetPosition(d)) + goto out; + + if (memcmp(Stream_Buffer(s), data, sizeof(data)) != 0) + goto out; + if (memcmp(Stream_Buffer(d), data, sizeof(data)) != 0) + goto out; + + rc = TRUE; +out: + Stream_Free(s, TRUE); + Stream_Free(d, TRUE); + return rc; +} + int TestStream(int argc, char* argv[]) { @@ -278,15 +524,24 @@ int TestStream(int argc, char* argv[]) if (!TestStream_New()) return 5; - /** - * FIXME: Add tests for - * Stream_Write_* - * Stream_Seek_* - * Stream_Rewind_* - * Stream_Zero - * Stream_Fill - * Stream_Copy - */ + + if (!TestStream_Write()) + return 6; + + if (!TestStream_Seek()) + return 7; + + if (!TestStream_Rewind()) + return 8; + + if (!TestStream_Zero()) + return 9; + + if (!TestStream_Fill()) + return 10; + + if (!TestStream_Copy()) + return 11; return 0; } diff --git a/winpr/libwinpr/utils/wlog/BinaryAppender.h b/winpr/libwinpr/utils/wlog/BinaryAppender.h index 22f1075df..31a9341f8 100644 --- a/winpr/libwinpr/utils/wlog/BinaryAppender.h +++ b/winpr/libwinpr/utils/wlog/BinaryAppender.h @@ -22,6 +22,6 @@ #include "wlog.h" -WINPR_API wLogAppender* WLog_BinaryAppender_New(wLog* log); +wLogAppender* WLog_BinaryAppender_New(wLog* log); #endif /* WINPR_WLOG_BINARY_APPENDER_PRIVATE_H */ diff --git a/winpr/libwinpr/winsock/module.def b/winpr/libwinpr/winsock/module.def deleted file mode 100644 index e4d0419ce..000000000 --- a/winpr/libwinpr/winsock/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-winsock" -EXPORTS - diff --git a/winpr/libwinpr/wnd/module.def b/winpr/libwinpr/wnd/module.def deleted file mode 100644 index de91bf1fa..000000000 --- a/winpr/libwinpr/wnd/module.def +++ /dev/null @@ -1,3 +0,0 @@ -LIBRARY "libwinpr-wnd" -EXPORTS -