freerdp: add configurable NTLM SAM file option for server-side NLA
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 21 Jul 2016 22:58:24 +0000 (18:58 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 21 Jul 2016 22:58:24 +0000 (18:58 -0400)
12 files changed:
include/freerdp/settings.h
libfreerdp/common/settings.c
libfreerdp/core/nla.c
libfreerdp/core/nla.h
libfreerdp/core/settings.c
server/shadow/shadow_server.c
winpr/include/winpr/sam.h
winpr/include/winpr/sspi.h
winpr/libwinpr/sspi/NTLM/ntlm.c
winpr/libwinpr/sspi/NTLM/ntlm.h
winpr/libwinpr/sspi/NTLM/ntlm_compute.c
winpr/libwinpr/utils/sam.c

index 8fb335a..47d88e8 100644 (file)
@@ -602,6 +602,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
 #define FreeRDP_AuthenticationLevel                            1100
 #define FreeRDP_AllowedTlsCiphers                              1101
 #define FreeRDP_VmConnectMode                                  1102
+#define FreeRDP_NtlmSamFile                                    1103
 #define FreeRDP_MstscCookieMode                                        1152
 #define FreeRDP_CookieMaxLength                                        1153
 #define FreeRDP_PreconnectionId                                        1154
@@ -1005,7 +1006,8 @@ struct rdp_settings
        ALIGN64 BOOL AuthenticationLevel; /* 1100 */
        ALIGN64 char* AllowedTlsCiphers; /* 1101 */
        ALIGN64 BOOL VmConnectMode; /* 1102 */
-       UINT64 padding1152[1152 - 1103]; /* 1103 */
+       ALIGN64 char* NtlmSamFile; /* 1103 */
+       UINT64 padding1152[1152 - 1104]; /* 1104 */
 
        /* Connection Cookie */
        ALIGN64 BOOL MstscCookieMode; /* 1152 */
index b8a4a20..9b24162 100644 (file)
@@ -2398,6 +2398,12 @@ char* freerdp_get_param_string(rdpSettings* settings, int id)
                case FreeRDP_AuthenticationServiceClass:
                        return settings->AuthenticationServiceClass;
 
+               case FreeRDP_AllowedTlsCiphers:
+                       return settings->AllowedTlsCiphers;
+
+               case FreeRDP_NtlmSamFile:
+                       return settings->NtlmSamFile;
+
                case FreeRDP_PreconnectionBlob:
                        return settings->PreconnectionBlob;
 
@@ -2574,6 +2580,14 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param)
                        tmp = &settings->AuthenticationServiceClass;
                        break;
 
+               case FreeRDP_AllowedTlsCiphers:
+                       tmp = &settings->AllowedTlsCiphers;
+                       break;
+
+               case FreeRDP_NtlmSamFile:
+                       tmp = &settings->NtlmSamFile;
+                       break;
+
                case FreeRDP_PreconnectionBlob:
                        tmp = &settings->PreconnectionBlob;
                        break;
index c586cdb..606c809 100644 (file)
@@ -164,7 +164,7 @@ int nla_client_init(rdpNla* nla)
 
        if (PromptPassword && settings->Username && strlen(settings->Username))
        {
-               sam = SamOpen(TRUE);
+               sam = SamOpen(NULL, TRUE);
 
                if (sam)
                {
@@ -715,9 +715,9 @@ int nla_server_authenticate(rdpNla* nla)
                        return -1;
 
                nla->status = nla->table->AcceptSecurityContext(&nla->credentials,
-                               nla-> haveContext? &nla->context: NULL,
-                                &nla->inputBufferDesc, nla->fContextReq, SECURITY_NATIVE_DREP, &nla->context,
-                                &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
+                               nla->haveContext? &nla->context: NULL,
+                               &nla->inputBufferDesc, nla->fContextReq, SECURITY_NATIVE_DREP, &nla->context,
+                               &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
 
                WLog_VRB(TAG, "AcceptSecurityContext status %s [%08X]",
                           GetSecurityStatusString(nla->status), nla->status);
@@ -726,10 +726,17 @@ int nla_server_authenticate(rdpNla* nla)
 
                if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
                {
+                       if (nla->SamFile)
+                       {
+                               nla->table->SetContextAttributes(&nla->context,
+                                       SECPKG_ATTR_AUTH_NTLM_SAM_FILE, nla->SamFile, strlen(nla->SamFile) + 1);
+                       }
+
                        if (nla->table->CompleteAuthToken)
                        {
                                SECURITY_STATUS status;
                                status = nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc);
+
                                if (status != SEC_E_OK)
                                {
                                        WLog_WARN(TAG, "CompleteAuthToken status %s [%08X]",
@@ -737,6 +744,7 @@ int nla_server_authenticate(rdpNla* nla)
                                        return -1;
                                }
                        }
+
                        if (nla->status == SEC_I_COMPLETE_NEEDED)
                                nla->status = SEC_E_OK;
                        else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE)
@@ -1717,16 +1725,16 @@ LPTSTR nla_make_spn(const char* ServiceClass, const char* hostname)
 
 rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings)
 {
-
        rdpNla* nla = (rdpNla*) calloc(1, sizeof(rdpNla));
 
        if (!nla)
                return NULL;
 
        nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
+
        if (!nla->identity)
        {
-               free (nla);
+               free(nla);
                return NULL;
        }
 
@@ -1738,6 +1746,9 @@ rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* setting
        nla->recvSeqNum = 0;
        nla->version = 3;
 
+       if (settings->NtlmSamFile)
+               nla->SamFile = _strdup(settings->NtlmSamFile);
+
        ZeroMemory(&nla->negoToken, sizeof(SecBuffer));
        ZeroMemory(&nla->pubKeyAuth, sizeof(SecBuffer));
        ZeroMemory(&nla->authInfo, sizeof(SecBuffer));
@@ -1804,6 +1815,12 @@ void nla_free(rdpNla* nla)
                }
        }
 
+       if (nla->SamFile)
+       {
+               free(nla->SamFile);
+               nla->SamFile = NULL;
+       }
+
        sspi_SecBufferFree(&nla->PublicKey);
        sspi_SecBufferFree(&nla->tsCredentials);
 
index f6f173e..49bef8f 100644 (file)
@@ -56,6 +56,7 @@ struct rdp_nla
        freerdp* instance;
        CtxtHandle context;
        LPTSTR SspiModule;
+       char* SamFile;
        rdpSettings* settings;
        rdpTransport* transport;
        UINT32 cbMaxToken;
index 5fee7f2..a353f08 100644 (file)
@@ -598,6 +598,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
                CHECKED_STRDUP(RemoteAssistanceRCTicket); /* 1028 */
                CHECKED_STRDUP(AuthenticationServiceClass); /* 1098 */
                CHECKED_STRDUP(AllowedTlsCiphers); /* 1101 */
+               CHECKED_STRDUP(NtlmSamFile); /* 1103 */
                CHECKED_STRDUP(PreconnectionBlob); /* 1155 */
                CHECKED_STRDUP(KerberosKdc); /* 1344 */
                CHECKED_STRDUP(KerberosRealm); /* 1345 */
@@ -920,6 +921,7 @@ void freerdp_settings_free(rdpSettings* settings)
     free(settings->ClientAddress);
     free(settings->ClientDir);
     free(settings->AllowedTlsCiphers);
+    free(settings->NtlmSamFile);
     free(settings->CertificateFile);
     free(settings->PrivateKeyFile);
     free(settings->ConnectionFile);
index 7f6a6e2..d3dd1a0 100644 (file)
@@ -55,6 +55,7 @@ static COMMAND_LINE_ARGUMENT_A shadow_args[] =
        { "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "tls protocol security" },
        { "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "nla protocol security" },
        { "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "nla extended protocol security" },
+       { "sam-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL, "NTLM SAM file for NLA authentication" },
        { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" },
        { "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "Print help" },
        { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
@@ -311,6 +312,10 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a
                {
                        settings->ExtSecurity = arg->Value ? TRUE : FALSE;
                }
+               CommandLineSwitchCase(arg, "sam-file")
+               {
+                       freerdp_set_param_string(settings, FreeRDP_NtlmSamFile, arg->Value);
+               }
                CommandLineSwitchDefault(arg)
                {
 
index d1c6f1f..3740daf 100644 (file)
@@ -28,7 +28,7 @@ struct winpr_sam
        FILE* fp;
        char* line;
        char* buffer;
-       BOOL read_only;
+       BOOL readOnly;
 };
 typedef struct winpr_sam WINPR_SAM;
 
@@ -53,7 +53,7 @@ WINPR_API WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 Us
 WINPR_API void SamResetEntry(WINPR_SAM_ENTRY* entry);
 WINPR_API void SamFreeEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry);
 
-WINPR_API WINPR_SAM* SamOpen(BOOL read_only);
+WINPR_API WINPR_SAM* SamOpen(const char* filename, BOOL readOnly);
 WINPR_API void SamClose(WINPR_SAM* sam);
 
 #ifdef __cplusplus
index f069fb2..790a6e7 100644 (file)
@@ -1005,13 +1005,14 @@ extern "C" {
 #define SECPKG_ATTR_AUTH_IDENTITY                      1001
 #define SECPKG_ATTR_AUTH_PASSWORD                      1002
 #define SECPKG_ATTR_AUTH_NTLM_HASH                     1003
+#define SECPKG_ATTR_AUTH_NTLM_SAM_FILE                 1004
 #define SECPKG_ATTR_AUTH_NTLM_MESSAGE                  1100
 #define SECPKG_ATTR_AUTH_NTLM_TIMESTAMP                        1101
-#define SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE 1102
-#define SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE 1103
+#define SECPKG_ATTR_AUTH_NTLM_CLIENT_CHALLENGE         1102
+#define SECPKG_ATTR_AUTH_NTLM_SERVER_CHALLENGE         1103
 #define SECPKG_ATTR_AUTH_NTLM_NTPROOF_VALUE            1104
 #define SECPKG_ATTR_AUTH_NTLM_RANDKEY                  1105
-#define SECPKG_ATTR_AUTH_NTLM_MIC                              1106
+#define SECPKG_ATTR_AUTH_NTLM_MIC                      1106
 #define SECPKG_ATTR_AUTH_NTLM_MIC_VALUE                        1107
 
 
index 1d56de1..32ff60a 100644 (file)
@@ -805,6 +805,15 @@ SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULON
 
                return SEC_E_OK;
        }
+       else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_SAM_FILE)
+       {
+               const char* filename = (char*) pBuffer;
+
+               free(context->SamFile);
+               context->SamFile = filename ? _strdup(filename) : NULL;
+
+               return SEC_E_OK;
+       }
        else if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_MESSAGE)
        {
                SecPkgContext_AuthNtlmMessage* AuthNtlmMessage = (SecPkgContext_AuthNtlmMessage*) pBuffer;
index 8253f3d..5a6256c 100644 (file)
@@ -220,6 +220,7 @@ struct _NTLM_CONTEXT
        NTLM_STATE state;
        int SendSeqNum;
        int RecvSeqNum;
+       char* SamFile;
        BYTE NtlmHash[16];
        BYTE NtlmV2Hash[16];
        BYTE MachineID[32];
index 8c18466..bde267b 100644 (file)
@@ -196,7 +196,7 @@ int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
        WINPR_SAM_ENTRY* entry;
        SSPI_CREDENTIALS* credentials = context->credentials;
 
-       sam = SamOpen(TRUE);
+       sam = SamOpen(context->SamFile, TRUE);
 
        if (!sam)
                return -1;
index d097c0a..2b68fbf 100644 (file)
@@ -30,6 +30,7 @@
 #include <winpr/print.h>
 
 #include "../log.h"
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #endif
 #define TAG WINPR_TAG("utils")
 
-WINPR_SAM* SamOpen(BOOL read_only)
+WINPR_SAM* SamOpen(const char* filename, BOOL readOnly)
 {
        FILE* fp = NULL;
        WINPR_SAM* sam = NULL;
 
-       if (read_only)
+       if (!filename)
+               filename = WINPR_SAM_FILE;
+
+       if (readOnly)
        {
-               fp = fopen(WINPR_SAM_FILE, "r");
+               fp = fopen(filename, "r");
        }
        else
        {
-               fp = fopen(WINPR_SAM_FILE, "r+");
+               fp = fopen(filename, "r+");
 
                if (!fp)
-                       fp = fopen(WINPR_SAM_FILE, "w+");
+                       fp = fopen(filename, "w+");
        }
 
        if (fp)
        {
                sam = (WINPR_SAM*) malloc(sizeof(WINPR_SAM));
+
                if (!sam)
                {
                        fclose(fp);
                        return NULL;
                }
-               sam->read_only = read_only;
+
+               sam->readOnly = readOnly;
                sam->fp = fp;
        }
        else
+       {
                WLog_DBG(TAG, "Could not open SAM file!");
+       }
 
        return sam;
 }
 
 static BOOL SamLookupStart(WINPR_SAM* sam)
 {
-       size_t read_size;
-       long int file_size;
+       size_t readSize;
+       long int fileSize;
+
        fseek(sam->fp, 0, SEEK_END);
-       file_size = ftell(sam->fp);
+       fileSize = ftell(sam->fp);
        fseek(sam->fp, 0, SEEK_SET);
 
-       if (file_size < 1)
+       if (fileSize < 1)
                return FALSE;
 
-       sam->buffer = (char*) malloc(file_size + 2);
+       sam->buffer = (char*) malloc(fileSize + 2);
+
        if (!sam->buffer)
                return FALSE;
 
-       read_size = fread(sam->buffer, file_size, 1, sam->fp);
+       readSize = fread(sam->buffer, fileSize, 1, sam->fp);
 
-       if (!read_size)
+       if (!readSize)
        {
                if (!ferror(sam->fp))
-                       read_size = file_size;
+                       readSize = fileSize;
        }
 
-       if (read_size < 1)
+       if (readSize < 1)
        {
                free(sam->buffer);
                sam->buffer = NULL;
                return FALSE;
        }
 
-       sam->buffer[file_size] = '\n';
-       sam->buffer[file_size + 1] = '\0';
+       sam->buffer[fileSize] = '\n';
+       sam->buffer[fileSize + 1] = '\0';
        sam->line = strtok(sam->buffer, "\n");
+
        return TRUE;
 }
 
@@ -224,17 +235,19 @@ void SamResetEntry(WINPR_SAM_ENTRY* entry)
                free(entry->Domain);
                entry->Domain = NULL;
        }
+
        ZeroMemory(entry->LmHash, sizeof(entry->LmHash));
        ZeroMemory(entry->NtHash, sizeof(entry->NtHash));
 }
 
-
 WINPR_SAM_ENTRY* SamLookupUserA(WINPR_SAM* sam, LPSTR User, UINT32 UserLength, LPSTR Domain, UINT32 DomainLength)
 {
        int length;
        BOOL found = FALSE;
        WINPR_SAM_ENTRY* entry;
+
        entry = (WINPR_SAM_ENTRY*) calloc(1, sizeof(WINPR_SAM_ENTRY));
+
        if (!entry)
                return NULL;