diff --git a/dlls/secur32/ntlm.c b/dlls/secur32/ntlm.c index c6bdcc7fc46..94715b5ed44 100644 --- a/dlls/secur32/ntlm.c +++ b/dlls/secur32/ntlm.c @@ -389,10 +389,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA( } /*********************************************************************** - * InitializeSecurityContextA + * InitializeSecurityContextW */ -static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( - PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, +static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( + PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) @@ -400,10 +400,283 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( SECURITY_STATUS ret; TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext, - debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, + debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); + if(phCredential){ - ret = SEC_E_UNSUPPORTED_FUNCTION; + /* As the server side of sspi never calls this, make sure that + * the handler is a client handler. + */ + PNegoHelper helper = (PNegoHelper)phCredential->dwLower; + ULONG ctxt_attr = 0; + if(helper->mode == NTLM_CLIENT) + { + /**************************************** + * When communicating with the client, there can be the + * following reply packets: + * YR should be sent to the server + * PW should be sent back to helper with + * base64 encoded password + * AF client is done, blob should be + * sent to server with KK prefixed + * BH something broke + */ + BOOL first = FALSE; + /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */ + char* buffer = HeapAlloc(GetProcessHeap(), 0, + sizeof(char) * NTLM_MAX_BUF); + PBYTE bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * + NTLM_MAX_BUF); + int buffer_len, bin_len, max_len = NTLM_MAX_BUF; + + if((phContext == NULL) && (pInput == NULL)) + first = TRUE; + if (pszTargetName) + { + TRACE("According to a MS whitepaper pszTargetName is ignored.\n"); + } + /* Handle all the flags */ + if(fContextReq & ISC_REQ_ALLOCATE_MEMORY) + { + FIXME("InitializeSecurityContext(): ISC_REQ_ALLOCATE_MEMORY stub\n"); + } + if(fContextReq & ISC_REQ_CONFIDENTIALITY) + { + FIXME("InitializeSecurityContext(): ISC_REQ_CONFIDENTIALITY stub\n"); + } + if(fContextReq & ISC_REQ_CONNECTION) + { + /* This is default, so we'll enable it */ + ctxt_attr |= ISC_RET_CONNECTION; + } + if(fContextReq & ISC_REQ_EXTENDED_ERROR) + { + FIXME("InitializeSecurityContext(): ISC_REQ_EXTENDED_ERROR stub\n"); + } + if(fContextReq & ISC_REQ_INTEGRITY) + { + FIXME("InitializeSecurityContext(): ISC_REQ_INTEGRITY stub\n"); + } + if(fContextReq & ISC_REQ_MUTUAL_AUTH) + { + FIXME("InitializeSecurityContext(): ISC_REQ_MUTUAL_AUTH stub\n"); + } + if(fContextReq & ISC_REQ_REPLAY_DETECT) + { + FIXME("InitializeSecurityContext(): ISC_REQ_REPLAY_DETECT stub\n"); + } + if(fContextReq & ISC_REQ_SEQUENCE_DETECT) + { + FIXME("InitializeSecurityContext(): ISC_REQ_SEQUENCE_DETECT stub\n"); + } + if(fContextReq & ISC_REQ_STREAM) + { + FIXME("InitializeSecurityContext(): ISC_REQ_STREAM stub\n"); + } + /* Done with the flags */ + if(TargetDataRep == SECURITY_NETWORK_DREP){ + FIXME("Don't know how to do SECURITY_NETWORK_DREP\n"); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + if(first) + { + TRACE("First time in ISC()\n"); + /* Request a challenge request from ntlm_auth */ + if(helper->password == NULL) + { + FIXME("Using empty password for now.\n"); + lstrcpynA(buffer, "PW AA==", max_len-1); + } + else + { + lstrcpynA(buffer, "PW ", max_len-1); + if((ret = encodeBase64((unsigned char*)helper->password, + helper->pwlen-2, buffer+3, + max_len-3, &buffer_len)) != SEC_E_OK) + { + TRACE("Deleting password!\n"); + memset(helper->password, 0, helper->pwlen-2); + HeapFree(GetProcessHeap(), 0, helper->password); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + + } + + TRACE("Sending to helper: %s\n", debugstr_a(buffer)); + if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != + SEC_E_OK) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + TRACE("Helper returned %s\n", debugstr_a(buffer)); + lstrcpynA(buffer, "YR", max_len-1); + + if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != + SEC_E_OK) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + + TRACE("%s\n", buffer); + + if(strncmp(buffer, "YR ", 3) != 0) + { + + /* Something borked */ + TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INTERNAL_ERROR; + } + if((ret = decodeBase64(buffer+3, buffer_len-3, bin, + max_len-1, &bin_len)) != SEC_E_OK) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + + /* put the decoded client blob into the out buffer */ + if(pOutput == NULL){ + TRACE("pOutput is NULL\n"); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INSUFFICIENT_MEMORY; + } + + if(pOutput->cBuffers < 1) + { + TRACE("pOutput->cBuffers is %ld\n", pOutput->cBuffers); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INSUFFICIENT_MEMORY; + } + pOutput->pBuffers[0].cbBuffer = bin_len; + pOutput->pBuffers[0].BufferType = SECBUFFER_DATA; + memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len); + + ret = SEC_I_CONTINUE_NEEDED; + } + else + { + /* handle second call here */ + /* encode server data to base64 */ + if(pInput == NULL) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INCOMPLETE_MESSAGE; + } + + if(pInput->cBuffers < 1) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INCOMPLETE_MESSAGE; + } + + if(pInput->pBuffers[0].cbBuffer > max_len) + { + TRACE("pInput->pBuffers[0].cbBuffer is: %ld\n", + pInput->pBuffers[0].cbBuffer); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INVALID_TOKEN; + } + else + bin_len = pInput->pBuffers[0].cbBuffer; + + memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len); + + lstrcpynA(buffer, "TT ", max_len-1); + + if((ret = encodeBase64(bin, bin_len, buffer+3, + max_len-3, &buffer_len)) != SEC_E_OK) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + + TRACE("Server sent: %s\n", debugstr_a(buffer)); + + /* send TT base64 blob to ntlm_auth */ + if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != + SEC_E_OK) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + + TRACE("Helper replied: %s\n", debugstr_a(buffer)); + + if( (strncmp(buffer, "KK ", 3) != 0) && + (strncmp(buffer, "AF ", 3) !=0)) + { + TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INVALID_TOKEN; + } + + /* decode the blob and send it to server */ + if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, + &bin_len)) != SEC_E_OK) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return ret; + } + + if(pOutput == NULL) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INSUFFICIENT_MEMORY; + } + + if(pOutput->cBuffers < 1) + { + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + return SEC_E_INSUFFICIENT_MEMORY; + } + + pOutput->pBuffers[0].cbBuffer = bin_len; + pOutput->pBuffers[0].BufferType = SECBUFFER_DATA; + memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len); + + ret = SEC_E_OK; + phNewContext->dwUpper = ctxt_attr; + phNewContext->dwLower = ret; + + } + HeapFree(GetProcessHeap(), 0, buffer); + HeapFree(GetProcessHeap(), 0, bin); + if(ret != SEC_I_CONTINUE_NEEDED) + { + TRACE("Deleting password!\n"); + if(helper->password) + memset(helper->password, 0, helper->pwlen-2); + HeapFree(GetProcessHeap(), 0, helper->password); + } + + } + else + { + ret = SEC_E_INVALID_HANDLE; + TRACE("Helper mode = %d\n", helper->mode); + } } else { @@ -413,10 +686,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( } /*********************************************************************** - * InitializeSecurityContextW + * InitializeSecurityContextA */ -static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( - PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, +static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( + PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) @@ -424,11 +697,27 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( SECURITY_STATUS ret; TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext, - debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, + debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); + if (phCredential) { - ret = SEC_E_UNSUPPORTED_FUNCTION; + SEC_WCHAR *target = NULL; + if(pszTargetName != NULL) + { + int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName, + strlen(pszTargetName)+1, NULL, 0); + target = HeapAlloc(GetProcessHeap(), 0, target_size * + sizeof(SEC_WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1, + target, target_size); + } + + ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target, + fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry); + + HeapFree(GetProcessHeap(), 0, target); } else {