diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c index 539696fcc11..9ca3993953a 100644 --- a/dlls/secur32/ntlm.c +++ b/dlls/secur32/ntlm.c @@ -443,29 +443,41 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( } lstrcpyA(want_flags, "SF"); if(fContextReq & ISC_REQ_CONFIDENTIALITY) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL"); - if(fContextReq & ISC_REQ_CONNECTION) { - /* This is default, so we'll enable it */ - ctxt_attr |= ISC_RET_CONNECTION; - /* Work around a bug in ntlm_auth that sets the - * NTLMSSP_FEATURE_SIGN flag for this want flag, which - * breaks RPC. */ - if(0) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SESSION_KEY"); + char *ptr; + if((ptr = strstr(want_flags, "NTLMSSP_FEATURE_SEAL")) == NULL) + lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL"); } + if(fContextReq & ISC_REQ_CONNECTION) + ctxt_attr |= ISC_RET_CONNECTION; if(fContextReq & ISC_REQ_EXTENDED_ERROR) - FIXME("ISC_REQ_EXTENDED_ERROR\n"); + ctxt_attr |= ISC_RET_EXTENDED_ERROR; if(fContextReq & ISC_REQ_INTEGRITY) - lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); + { + char *ptr; + if((ptr = strstr(want_flags, "NTLMSSP_FEATURE_SIGN")) == NULL) + lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); + } if(fContextReq & ISC_REQ_MUTUAL_AUTH) - FIXME("ISC_REQ_MUTUAL_AUTH\n"); + ctxt_attr |= ISC_RET_MUTUAL_AUTH; if(fContextReq & ISC_REQ_REPLAY_DETECT) - FIXME("ISC_REQ_REPLAY_DETECT\n"); + { + char *ptr; + if((ptr = strstr(want_flags, "NTLMSSP_FEATURE_SIGN")) == NULL) + lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); + } if(fContextReq & ISC_REQ_SEQUENCE_DETECT) - FIXME("ISC_REQ_SEQUENCE_DETECT\n"); + { + char *ptr; + if((ptr = strstr(want_flags, "NTLMSSP_FEATURE_SIGN")) == NULL) + lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); + } if(fContextReq & ISC_REQ_STREAM) FIXME("ISC_REQ_STREAM\n"); + if(fContextReq & ISC_REQ_USE_DCE_STYLE) + ctxt_attr |= ISC_RET_USED_DCE_STYLE; + if(fContextReq & ISC_REQ_DELEGATE) + ctxt_attr |= ISC_RET_DELEGATE; /* If no password is given, try to use cached credentials. Fall back to an empty * password if this failed. */ @@ -533,6 +545,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( max_len-1, &bin_len)) != SEC_E_OK) goto isc_end; + /* We need to set NTLMSSP_NEGOTIATE_ALWAYS_SIGN manually for now */ + bin[13] |= 0x80; /* put the decoded client blob into the out buffer */ ret = SEC_I_CONTINUE_NEEDED; diff --git a/dlls/secur32/tests/ntlm.c b/dlls/secur32/tests/ntlm.c index 47a4888965c..f616491b35a 100644 --- a/dlls/secur32/tests/ntlm.c +++ b/dlls/secur32/tests/ntlm.c @@ -550,7 +550,215 @@ static void communicate(SspiData *from, SspiData *to) } } } - + +/**********************************************************************/ +static void testInitializeSecurityContextFlags() +{ + SECURITY_STATUS sec_status; + PSecPkgInfo pkg_info = NULL; + SspiData client; + SEC_WINNT_AUTH_IDENTITY id; + static char sec_pkg_name[] = "NTLM"; + ULONG req_attr, ctxt_attr; + TimeStamp ttl; + PBYTE packet; + + if(pQuerySecurityPackageInfoA( sec_pkg_name, &pkg_info) != SEC_E_OK) + { + trace("Package not installed, skipping test!\n"); + return; + } + + pFreeContextBuffer(pkg_info); + id.User = (unsigned char*) "testuser"; + id.UserLength = strlen((char *) id.User); + id.Domain = (unsigned char *) "WORKGROUP"; + id.DomainLength = strlen((char *) id.Domain); + id.Password = (unsigned char*) "testpass"; + id.PasswordLength = strlen((char *) id.Password); + id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + + client.id = &id; + + if((sec_status = setupClient(&client, sec_pkg_name)) != SEC_E_OK) + { + trace("Setting up the client returned %s, skipping test!\n", + getSecError(sec_status)); + return; + } + + packet = client.out_buf->pBuffers[0].pvBuffer; + + /* Due to how the requesting of the flags is implemented in ntlm_auth, + * the tests need to be in this order, as there is no way to specify + * "I request no special features" in ntlm_auth */ + + /* Without any flags, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = 0; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "With req_attr == 0, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_CONNECTION, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_CONNECTION; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_CONNECTION, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_EXTENDED_ERROR, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_EXTENDED_ERROR; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_EXTENDED_ERROR, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_MUTUAL_AUTH, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_MUTUAL_AUTH; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_MUTUAL_AUTH, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_USE_DCE_STYLE, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_USE_DCE_STYLE; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_USE_DCE_STYLE, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_DELEGATE, the lowest byte should not have bits 0x20 or 0x10 set*/ + req_attr = ISC_REQ_DELEGATE; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0), + "For ISC_REQ_DELEGATE, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_INTEGRITY, the lowest byte should have bit 0x10 set */ + req_attr = ISC_REQ_INTEGRITY; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x10) != 0, + "For ISC_REQ_INTEGRITY, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_REPLAY_DETECT, the lowest byte should have bit 0x10 set */ + req_attr = ISC_REQ_REPLAY_DETECT; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x10) != 0, + "For ISC_REQ_REPLAY_DETECT, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_SEQUENCE_DETECT, the lowest byte should have bit 0x10 set */ + req_attr = ISC_REQ_SEQUENCE_DETECT; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x10) != 0, + "For ISC_REQ_SEQUENCE_DETECT, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + + /* With ISC_REQ_CONFIDENTIALITY, the lowest byte should have bit 0x20 set */ + req_attr = ISC_REQ_CONFIDENTIALITY; + + if((sec_status = pInitializeSecurityContextA(client.cred, NULL, NULL, req_attr, + 0, SECURITY_NETWORK_DREP, NULL, 0, client.ctxt, client.out_buf, + &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED) + { + trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n", + getSecError(sec_status)); + goto tISCFend; + } + + ok((packet[12] & 0x20) != 0, + "For ISC_REQ_CONFIDENTIALITY, flags are 0x%02x%02x%02x%02x.\n", + packet[15], packet[14], packet[13], packet[12]); + +tISCFend: + cleanupBuffers(&client); + pFreeCredentialsHandle(client.cred); + +} + /**********************************************************************/ static void testAuth(ULONG data_rep, BOOL fake) @@ -906,9 +1114,10 @@ START_TEST(ntlm) if(pFreeCredentialsHandle && pDeleteSecurityContext && pDeleteSecurityContext && pAcquireCredentialsHandleA && - pInitializeSecurityContextA && pCompleteAuthToken && + pInitializeSecurityContextA && pCompleteAuthToken && pQuerySecurityPackageInfoA) { + testInitializeSecurityContextFlags(); if(pAcceptSecurityContext) { testAuth(SECURITY_NATIVE_DREP, TRUE);