diff --git a/dll/Environment.c b/dll/Environment.c index df58be2..658fdab 100644 --- a/dll/Environment.c +++ b/dll/Environment.c @@ -191,3 +191,62 @@ void MsRdpEx_FreeEnvironmentVariables(int envc, char** envs) free(envs); } + +char* MsRdpEx_ReadTextFromNamedPipe(const char* pipeName) +{ + size_t size = 0; + size_t length = 0; + DWORD readBytes = 0; + char* text = NULL; + char* buffer = NULL; + char* tempBuffer = NULL; + HANDLE pipeHandle = NULL; + char filename[MSRDPEX_MAX_PATH]; + + if (!pipeName) + return NULL; + + sprintf_s(filename, sizeof(filename) - 1, "\\\\.\\pipe\\%s", pipeName); + + pipeHandle = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (pipeHandle == INVALID_HANDLE_VALUE) { + goto exit; + } + + size = 1024; + buffer = (char*) malloc(size); + + if (!buffer) + goto exit; + + length = 0; + while (1) { + if (!ReadFile(pipeHandle, buffer + length, size - length, &readBytes, NULL) || (readBytes == 0)) { + // If no bytes were read or an error occurred, break out of the loop. + break; + } + + length += readBytes; + if ((size - length) <= 1) { + tempBuffer = (char*) realloc(buffer, size * 2); + if (!tempBuffer) { + goto exit; + } + buffer = tempBuffer; + size = size * 2; + } + } + buffer[length] = '\0'; + text = _strdup(buffer); + +exit: + if (buffer) { + SecureZeroMemory(buffer, size); + free(buffer); + } + if (pipeHandle && (pipeHandle != INVALID_HANDLE_VALUE)) { + CloseHandle(pipeHandle); + } + return text; +} diff --git a/dll/MsRdpClient.cpp b/dll/MsRdpClient.cpp index 4ab5922..c6c6c14 100644 --- a/dll/MsRdpClient.cpp +++ b/dll/MsRdpClient.cpp @@ -496,6 +496,7 @@ class CMsRdpClient : public IMsRdpClient10 CMsRdpExtendedSettings* pMsRdpExtendedSettings = m_pMsRdpExtendedSettings; m_pMsRdpExtendedSettings->LoadRdpFile(NULL); + m_pMsRdpExtendedSettings->LoadRdpFileFromNamedPipe(NULL); m_pMsRdpExtendedSettings->PrepareSspiSessionIdHack(); m_pMsRdpExtendedSettings->PrepareMouseJiggler(); diff --git a/dll/RdpFile.c b/dll/RdpFile.c index 2e5505f..b5fcf97 100644 --- a/dll/RdpFile.c +++ b/dll/RdpFile.c @@ -1,6 +1,17 @@ #include +bool MsRdpEx_IsSensitivePropertyName(const char* name) +{ + if (!name) + return false; + + if (MsRdpEx_IStringEndsWith(name, "Password")) + return true; + + return false; +} + MsRdpEx_RdpFileEntry* MsRdpEx_RdpFileEntry_New(char type, const char* name, const char* value) { MsRdpEx_RdpFileEntry* entry; @@ -86,6 +97,10 @@ void MsRdpEx_RdpFileEntry_Free(MsRdpEx_RdpFileEntry* entry) if (!entry) return; + if (MsRdpEx_IsSensitivePropertyName(entry->name) && entry->value) { + SecureZeroMemory(entry->value, strlen(entry->value)); + } + if (entry->name) { free(entry->name); entry->name = NULL; @@ -251,7 +266,9 @@ bool MsRdpEx_RdpFile_Load(MsRdpEx_RdpFile* ctx, const char* filename) } else if (*type == 's') /* string type */ { - MsRdpEx_LogPrint(DEBUG, "RDP(s): %s = %s", name, value); + MsRdpEx_LogPrint(DEBUG, "RDP(s): %s = %s", name, + MsRdpEx_IsSensitivePropertyName(name) ? "*omitted*" : value); + entry = MsRdpEx_RdpFileEntry_New(*type, name, value); if (entry) { @@ -273,6 +290,97 @@ bool MsRdpEx_RdpFile_Load(MsRdpEx_RdpFile* ctx, const char* filename) return true; } +bool MsRdpEx_RdpFile_LoadText(MsRdpEx_RdpFile* ctx, const char* text) +{ + size_t index; + size_t size; + size_t length; + char* line; + char* type; + char* d1; + char* d2; + char* beg; + char* name; + char* value; + char* tokctx = NULL; + char* buffer = NULL; + MsRdpEx_RdpFileEntry* entry; + + if (!text) + return false; + + size = strlen(text); + buffer = _strdup(text); + + if (!buffer) + return false; + + index = 0; + line = strtok_s(buffer, "\r\n", &tokctx); + + while (line) + { + length = strnlen(line, size); + + if (length > 1) + { + beg = line; + + d1 = strchr(line, ':'); + + if (!d1) + goto next_line; /* no first delimiter */ + + type = &d1[1]; + d2 = strchr(type, ':'); + + if (!d2) + goto next_line; /* no second delimiter */ + + if ((d2 - d1) != 2) + goto next_line; /* improper type length */ + + *d1 = 0; + *d2 = 0; + name = beg; + value = &d2[1]; + + if (*type == 'i') /* integer type */ + { + MsRdpEx_LogPrint(DEBUG, "RDP(i): %s = %s", name, value); + entry = MsRdpEx_RdpFileEntry_New(*type, name, value); + + if (entry) { + MsRdpEx_ArrayList_Add(ctx->entries, entry); + } + } + else if (*type == 's') /* string type */ + { + MsRdpEx_LogPrint(DEBUG, "RDP(s): %s = %s", name, + MsRdpEx_IsSensitivePropertyName(name) ? "*omitted*" : value); + + entry = MsRdpEx_RdpFileEntry_New(*type, name, value); + + if (entry) { + MsRdpEx_ArrayList_Add(ctx->entries, entry); + } + } + else if (*type == 'b') /* binary type */ + { + + } + } + + next_line: + line = strtok_s(NULL, "\r\n", &tokctx); + index++; + } + + SecureZeroMemory(buffer, size); + free(buffer); + return true; +} + MsRdpEx_RdpFile* MsRdpEx_RdpFile_New() { MsRdpEx_RdpFile* ctx; diff --git a/dll/RdpSettings.cpp b/dll/RdpSettings.cpp index 341c199..f7181c4 100644 --- a/dll/RdpSettings.cpp +++ b/dll/RdpSettings.cpp @@ -607,6 +607,7 @@ HRESULT __stdcall CMsRdpExtendedSettings::SetTargetPassword(const char* password bstr_t propValue = _com_util::ConvertStringToBSTR(password); m_CoreProps->SetSecureStringProperty("Password", propValue); + SecureZeroMemory(propValue.GetBSTR(), wcslen(propValue.GetBSTR()) * sizeof(WCHAR)); return S_OK; } @@ -617,6 +618,7 @@ HRESULT __stdcall CMsRdpExtendedSettings::SetGatewayPassword(const char* passwor bstr_t propValue = _com_util::ConvertStringToBSTR(password); m_TransportProps->SetSecureStringProperty("GatewayPassword", propValue); + SecureZeroMemory(propValue.GetBSTR(), wcslen(propValue.GetBSTR()) * sizeof(WCHAR)); return S_OK; } @@ -695,138 +697,178 @@ HRESULT CMsRdpExtendedSettings::AttachRdpClient(IMsTscAx* pMsTscAx) return S_OK; } -HRESULT CMsRdpExtendedSettings::LoadRdpFile(const char* rdpFileName) +HRESULT CMsRdpExtendedSettings::ApplyRdpFile(void* rdpFilePtr) { - char* filename; - - if (rdpFileName) - filename = _strdup(rdpFileName); - else - filename = MsRdpEx_GetRdpFilenameFromCommandLine(); - - if (!filename) - return E_UNEXPECTED; - + MsRdpEx_ArrayListIt* it = NULL; + MsRdpEx_RdpFileEntry* entry = NULL; CMsRdpExtendedSettings* pMsRdpExtendedSettings = this; + MsRdpEx_RdpFile* rdpFile = (MsRdpEx_RdpFile*) rdpFilePtr; - MsRdpEx_LogPrint(DEBUG, "Loading %s", filename); - MsRdpEx_RdpFile* rdpFile = MsRdpEx_RdpFile_New(); - - if (MsRdpEx_RdpFile_Load(rdpFile, filename)) { - MsRdpEx_ArrayListIt* it = NULL; - MsRdpEx_RdpFileEntry* entry = NULL; + it = MsRdpEx_ArrayList_It(rdpFile->entries, MSRDPEX_ITERATOR_FLAG_EXCLUSIVE); - it = MsRdpEx_ArrayList_It(rdpFile->entries, MSRDPEX_ITERATOR_FLAG_EXCLUSIVE); - - while (!MsRdpEx_ArrayListIt_Done(it)) - { - VARIANT value; - VariantInit(&value); + while (!MsRdpEx_ArrayListIt_Done(it)) + { + VARIANT value; + VariantInit(&value); - entry = (MsRdpEx_RdpFileEntry*) MsRdpEx_ArrayListIt_Next(it); + entry = (MsRdpEx_RdpFileEntry*)MsRdpEx_ArrayListIt_Next(it); - if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "DisableCredentialsDelegation")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->PutProperty(propName, &value); - } + if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "DisableCredentialsDelegation")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->PutProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "RedirectedAuthentication")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->PutProperty(propName, &value); - } + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "RedirectedAuthentication")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->PutProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "RestrictedLogon")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->PutProperty(propName, &value); - } + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "RestrictedLogon")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->PutProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "UserSpecifiedServerName")) { + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "UserSpecifiedServerName")) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value); + value.bstrVal = propValue; + value.vt = VT_BSTR; + pMsRdpExtendedSettings->put_CoreProperty(propName, &value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "DisableUDPTransport")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value); - value.bstrVal = propValue; - value.vt = VT_BSTR; pMsRdpExtendedSettings->put_CoreProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "DisableUDPTransport")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_CoreProperty(propName, &value); - } - } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "ConnectToChildSession")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_CoreProperty(propName, &value); - } - } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "EnableHardwareMode")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_Property(propName, &value); - } - } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "AllowBackgroundInput")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_BaseProperty(propName, &value); - } - } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "EnableRelativeMouse")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_BaseProperty(propName, &value); - } - } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "EnableMouseJiggler")) { - if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_Property(propName, &value); - } - } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "MouseJigglerInterval")) { - if (MsRdpEx_RdpFileEntry_GetIntValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_Property(propName, &value); - } + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "ConnectToChildSession")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_CoreProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "MouseJigglerMethod")) { - if (MsRdpEx_RdpFileEntry_GetIntValue(entry, &value)) { - bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); - pMsRdpExtendedSettings->put_Property(propName, &value); - } + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "EnableHardwareMode")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_Property(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "ClearTextPassword")) { - pMsRdpExtendedSettings->SetTargetPassword(entry->value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "AllowBackgroundInput")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_BaseProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "GatewayPassword")) { - pMsRdpExtendedSettings->SetGatewayPassword(entry->value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "EnableRelativeMouse")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_BaseProperty(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "TargetUserName")) { - bstr_t propName = _com_util::ConvertStringToBSTR("UserName"); - bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value); - value.bstrVal = propValue; - value.vt = VT_BSTR; - pMsRdpExtendedSettings->put_CoreProperty(propName, &value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "EnableMouseJiggler")) { + if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_Property(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "TargetDomain")) { - bstr_t propName = _com_util::ConvertStringToBSTR("Domain"); - bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value); - value.bstrVal = propValue; - value.vt = VT_BSTR; - pMsRdpExtendedSettings->put_CoreProperty(propName, &value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "MouseJigglerInterval")) { + if (MsRdpEx_RdpFileEntry_GetIntValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_Property(propName, &value); } - else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "KDCProxyURL")) { - pMsRdpExtendedSettings->SetKdcProxyUrl(entry->value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "MouseJigglerMethod")) { + if (MsRdpEx_RdpFileEntry_GetIntValue(entry, &value)) { + bstr_t propName = _com_util::ConvertStringToBSTR(entry->name); + pMsRdpExtendedSettings->put_Property(propName, &value); } } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "ClearTextPassword")) { + pMsRdpExtendedSettings->SetTargetPassword(entry->value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "GatewayPassword")) { + pMsRdpExtendedSettings->SetGatewayPassword(entry->value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "TargetUserName")) { + bstr_t propName = _com_util::ConvertStringToBSTR("UserName"); + bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value); + value.bstrVal = propValue; + value.vt = VT_BSTR; + pMsRdpExtendedSettings->put_CoreProperty(propName, &value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "TargetDomain")) { + bstr_t propName = _com_util::ConvertStringToBSTR("Domain"); + bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value); + value.bstrVal = propValue; + value.vt = VT_BSTR; + pMsRdpExtendedSettings->put_CoreProperty(propName, &value); + } + else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "KDCProxyURL")) { + pMsRdpExtendedSettings->SetKdcProxyUrl(entry->value); + } + } + + MsRdpEx_ArrayListIt_Finish(it); + + return S_OK; +} + +HRESULT CMsRdpExtendedSettings::LoadRdpFile(const char* rdpFileName) +{ + char* filename; + + if (rdpFileName) + filename = _strdup(rdpFileName); + else + filename = MsRdpEx_GetRdpFilenameFromCommandLine(); + + if (!filename) + return E_UNEXPECTED; - MsRdpEx_ArrayListIt_Finish(it); + MsRdpEx_LogPrint(DEBUG, "Loading RDP file: %s", filename); + MsRdpEx_RdpFile* rdpFile = MsRdpEx_RdpFile_New(); + + if (MsRdpEx_RdpFile_Load(rdpFile, filename)) + { + this->ApplyRdpFile(rdpFile); } + MsRdpEx_RdpFile_Free(rdpFile); free(filename); + return S_OK; +} + +HRESULT CMsRdpExtendedSettings::LoadRdpFileFromNamedPipe(const char* pipeName) +{ + char* pipeNameEnv = MsRdpEx_GetEnv("MSRDPEX_SECURE_PIPE_NAME"); + + if (pipeNameEnv) + pipeName = pipeNameEnv; + + if (!pipeName) + return S_OK; // no named pipe to read from + + MsRdpEx_LogPrint(DEBUG, "Loading RDP file from named pipe: %s", pipeName); + MsRdpEx_RdpFile* rdpFile = MsRdpEx_RdpFile_New(); + + char* pipeText = MsRdpEx_ReadTextFromNamedPipe(pipeName); + + if (pipeText && MsRdpEx_RdpFile_LoadText(rdpFile, pipeText)) + { + this->ApplyRdpFile(rdpFile); + } + + MsRdpEx_RdpFile_Free(rdpFile); + + free(pipeNameEnv); + + if (pipeText) { + SecureZeroMemory(pipeText, strlen(pipeText)); + free(pipeText); + } return S_OK; } diff --git a/include/MsRdpEx/Environment.h b/include/MsRdpEx/Environment.h index d364bab..671b3f8 100644 --- a/include/MsRdpEx/Environment.h +++ b/include/MsRdpEx/Environment.h @@ -18,6 +18,8 @@ int MsRdpEx_GetEnvInt(const char* name, int defaultValue); char** MsRdpEx_GetEnvironmentVariables(int* envc); void MsRdpEx_FreeEnvironmentVariables(int envc, char** envs); +char* MsRdpEx_ReadTextFromNamedPipe(const char* pipeName); + #ifdef __cplusplus } #endif diff --git a/include/MsRdpEx/RdpFile.h b/include/MsRdpEx/RdpFile.h index e7cd05a..08c7706 100644 --- a/include/MsRdpEx/RdpFile.h +++ b/include/MsRdpEx/RdpFile.h @@ -37,6 +37,7 @@ typedef struct _MsRdpEx_RdpFile MsRdpEx_RdpFile; char* MsRdpEx_GetRdpFilenameFromCommandLine(); bool MsRdpEx_RdpFile_Load(MsRdpEx_RdpFile* ctx, const char* filename); +bool MsRdpEx_RdpFile_LoadText(MsRdpEx_RdpFile* ctx, const char* text); MsRdpEx_RdpFile* MsRdpEx_RdpFile_New(); void MsRdpEx_RdpFile_Free(MsRdpEx_RdpFile* ctx); diff --git a/include/MsRdpEx/RdpSettings.h b/include/MsRdpEx/RdpSettings.h index 6810f6f..e29e4f0 100644 --- a/include/MsRdpEx/RdpSettings.h +++ b/include/MsRdpEx/RdpSettings.h @@ -40,7 +40,9 @@ class CMsRdpExtendedSettings : public IMsRdpExtendedSettings HRESULT __stdcall SetGatewayPassword(const char* password); HRESULT __stdcall SetKdcProxyUrl(const char* kdcProxyUrl); HRESULT __stdcall AttachRdpClient(IMsTscAx* pMsTscAx); + HRESULT __stdcall ApplyRdpFile(void* rdpFilePtr); HRESULT __stdcall LoadRdpFile(const char* rdpFileName); + HRESULT __stdcall LoadRdpFileFromNamedPipe(const char* pipeName); HRESULT __stdcall GetCorePropsRawPtr(LPVOID* ppCorePropsRaw); HRESULT __stdcall PrepareSspiSessionIdHack(); HRESULT __stdcall PrepareMouseJiggler();