/* * @implemented */ BOOL WINAPI LogonUserExW( _In_ LPWSTR lpszUsername, _In_opt_ LPWSTR lpszDomain, _In_opt_ LPWSTR lpszPassword, _In_ DWORD dwLogonType, _In_ DWORD dwLogonProvider, _Out_opt_ PHANDLE phToken, _Out_opt_ PSID *ppLogonSid, _Out_opt_ PVOID *ppProfileBuffer, _Out_opt_ LPDWORD pdwProfileLength, _Out_opt_ PQUOTA_LIMITS pQuotaLimits) { SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY}; SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; PSID LogonSid = NULL; PSID LocalSid = NULL; LSA_STRING OriginName; UNICODE_STRING DomainName; UNICODE_STRING UserName; UNICODE_STRING Password; PMSV1_0_INTERACTIVE_LOGON AuthInfo = NULL; ULONG AuthInfoLength; ULONG_PTR Ptr; TOKEN_SOURCE TokenSource; PTOKEN_GROUPS TokenGroups = NULL; PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer = NULL; ULONG ProfileBufferLength = 0; LUID Luid = {0, 0}; LUID LogonId = {0, 0}; HANDLE TokenHandle = NULL; QUOTA_LIMITS QuotaLimits; SECURITY_LOGON_TYPE LogonType; NTSTATUS SubStatus = STATUS_SUCCESS; NTSTATUS Status; *phToken = NULL; switch (dwLogonType) { case LOGON32_LOGON_INTERACTIVE: LogonType = Interactive; break; case LOGON32_LOGON_NETWORK: LogonType = Network; break; case LOGON32_LOGON_BATCH: LogonType = Batch; break; case LOGON32_LOGON_SERVICE: LogonType = Service; break; default: ERR("Invalid logon type: %ul\n", dwLogonType); Status = STATUS_INVALID_PARAMETER; goto done; } if (LsaHandle == NULL) { Status = OpenLogonLsaHandle(); if (!NT_SUCCESS(Status)) goto done; } RtlInitAnsiString((PANSI_STRING)&OriginName, "Advapi32 Logon"); RtlInitUnicodeString(&DomainName, lpszDomain); RtlInitUnicodeString(&UserName, lpszUsername); RtlInitUnicodeString(&Password, lpszPassword); AuthInfoLength = sizeof(MSV1_0_INTERACTIVE_LOGON)+ DomainName.MaximumLength + UserName.MaximumLength + Password.MaximumLength; AuthInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, AuthInfoLength); if (AuthInfo == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } AuthInfo->MessageType = MsV1_0InteractiveLogon; Ptr = (ULONG_PTR)AuthInfo + sizeof(MSV1_0_INTERACTIVE_LOGON); AuthInfo->LogonDomainName.Length = DomainName.Length; AuthInfo->LogonDomainName.MaximumLength = DomainName.MaximumLength; AuthInfo->LogonDomainName.Buffer = (DomainName.Buffer == NULL) ? NULL : (PWCHAR)Ptr; if (DomainName.MaximumLength > 0) { RtlCopyMemory(AuthInfo->LogonDomainName.Buffer, DomainName.Buffer, DomainName.MaximumLength); Ptr += DomainName.MaximumLength; } AuthInfo->UserName.Length = UserName.Length; AuthInfo->UserName.MaximumLength = UserName.MaximumLength; AuthInfo->UserName.Buffer = (PWCHAR)Ptr; if (UserName.MaximumLength > 0) RtlCopyMemory(AuthInfo->UserName.Buffer, UserName.Buffer, UserName.MaximumLength); Ptr += UserName.MaximumLength; AuthInfo->Password.Length = Password.Length; AuthInfo->Password.MaximumLength = Password.MaximumLength; AuthInfo->Password.Buffer = (PWCHAR)Ptr; if (Password.MaximumLength > 0) RtlCopyMemory(AuthInfo->Password.Buffer, Password.Buffer, Password.MaximumLength); /* Create the Logon SID*/ AllocateLocallyUniqueId(&LogonId); Status = RtlAllocateAndInitializeSid(&SystemAuthority, SECURITY_LOGON_IDS_RID_COUNT, SECURITY_LOGON_IDS_RID, LogonId.HighPart, LogonId.LowPart, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &LogonSid); if (!NT_SUCCESS(Status)) goto done; /* Create the Local SID*/ Status = RtlAllocateAndInitializeSid(&LocalAuthority, 1, SECURITY_LOCAL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, SECURITY_NULL_RID, &LocalSid); if (!NT_SUCCESS(Status)) goto done; /* Allocate and set the token groups */ TokenGroups = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TOKEN_GROUPS) + ((2 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES))); if (TokenGroups == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto done; } TokenGroups->GroupCount = 2; TokenGroups->Groups[0].Sid = LogonSid; TokenGroups->Groups[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID; TokenGroups->Groups[1].Sid = LocalSid; TokenGroups->Groups[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT; /* Set the token source */ strncpy(TokenSource.SourceName, "Advapi ", sizeof(TokenSource.SourceName)); AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); Status = LsaLogonUser(LsaHandle, &OriginName, LogonType, AuthenticationPackage, (PVOID)AuthInfo, AuthInfoLength, TokenGroups, &TokenSource, (PVOID*)&ProfileBuffer, &ProfileBufferLength, &Luid, &TokenHandle, &QuotaLimits, &SubStatus); if (!NT_SUCCESS(Status)) { ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status); goto done; } if (ProfileBuffer != NULL) { TRACE("ProfileBuffer: %p\n", ProfileBuffer); TRACE("MessageType: %u\n", ProfileBuffer->MessageType); TRACE("FullName: %p\n", ProfileBuffer->FullName.Buffer); TRACE("FullName: %S\n", ProfileBuffer->FullName.Buffer); TRACE("LogonServer: %p\n", ProfileBuffer->LogonServer.Buffer); TRACE("LogonServer: %S\n", ProfileBuffer->LogonServer.Buffer); } TRACE("Luid: 0x%08lx%08lx\n", Luid.HighPart, Luid.LowPart); if (TokenHandle != NULL) { TRACE("TokenHandle: %p\n", TokenHandle); } *phToken = TokenHandle; /* FIXME: return ppLogonSid, ppProfileBuffer, pdwProfileLength and pQuotaLimits */ done: if (ProfileBuffer != NULL) LsaFreeReturnBuffer(ProfileBuffer); if (!NT_SUCCESS(Status)) { if (TokenHandle != NULL) CloseHandle(TokenHandle); } if (TokenGroups != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups); if (LocalSid != NULL) RtlFreeSid(LocalSid); if (LogonSid != NULL) RtlFreeSid(LogonSid); if (AuthInfo != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } return TRUE; }
SECURITY_STATUS SEC_ENTRY AcceptSecurityContext( PCredHandle phCredential, // Cred to base context PCtxtHandle phContext, // Existing context (OPT) PSecBufferDesc pInput, // Input buffer unsigned long fContextReq, // Context Requirements unsigned long TargetDataRep, // Target Data Rep PCtxtHandle phNewContext, // (out) New context handle PSecBufferDesc pOutput, // (inout) Output buffers unsigned long SEC_FAR * pfContextAttr, // (out) Context attributes PTimeStamp ptsExpiry // (out) Life span (OPT) ) { SECURITY_STATUS scRet; NTSTATUS SubStatus; PAUTHENTICATE_MESSAGE AuthenticateMessage; ULONG AuthenticateMessageSize; PNTLM_AUTHENTICATE_MESSAGE NtlmAuthenticateMessage; ULONG NtlmAuthenticateMessageSize; PNTLM_ACCEPT_RESPONSE NtlmAcceptResponse = NULL; PMSV1_0_LM20_LOGON LogonBuffer = NULL; ULONG LogonBufferSize; PMSV1_0_LM20_LOGON_PROFILE LogonProfile = NULL; ULONG LogonProfileSize; PSecBuffer AcceptResponseToken = NULL; PClient Client = NULL; ANSI_STRING SourceName; LUID LogonId; LUID UNALIGNED * TempLogonId; LARGE_INTEGER UNALIGNED * TempKickoffTime; HANDLE TokenHandle = NULL; QUOTA_LIMITS Quotas; PUCHAR Where; STRING DomainName; STRING UserName; STRING Workstation; STRING NtChallengeResponse; STRING LmChallengeResponse; ULONG EffectivePackageId; RtlInitString( &SourceName, NULL ); PAGED_CODE(); // // Check for valid sizes, pointers, etc.: // if (!phCredential) { return(SEC_E_INVALID_HANDLE); } // // Check that we can indeed call the LSA and get the client // handle to it. // scRet = IsOkayToExec(&Client); if (!NT_SUCCESS(scRet)) { return(scRet); } // // Locate the buffers with the input data // if (!GetTokenBuffer( pInput, 0, // get the first security token (PVOID *) &AuthenticateMessage, &AuthenticateMessageSize, TRUE // may be readonly ) || (!GetTokenBuffer( pInput, 1, // get the second security token (PVOID *) &NtlmAuthenticateMessage, &NtlmAuthenticateMessageSize, TRUE // may be readonly ))) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Get the output tokens // if (!GetSecurityToken( pOutput, 0, &AcceptResponseToken ) ) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Make sure the sizes are o.k. // if ((AuthenticateMessageSize < sizeof(AUTHENTICATE_MESSAGE)) || (NtlmAuthenticateMessageSize < sizeof(NTLM_AUTHENTICATE_MESSAGE))) { scRet = SEC_E_INVALID_TOKEN; } // // Make sure the caller does not want us to allocate memory: // if (fContextReq & ISC_REQ_ALLOCATE_MEMORY) { scRet = SEC_E_UNSUPPORTED_FUNCTION; goto Cleanup; } if (AcceptResponseToken->cbBuffer < sizeof(NTLM_ACCEPT_RESPONSE)) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Verify the validity of the Authenticate message. // if (strncmp( AuthenticateMessage->Signature, NTLMSSP_SIGNATURE, sizeof(NTLMSSP_SIGNATURE))) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } if (AuthenticateMessage->MessageType != NtLmAuthenticate) { scRet = SEC_E_INVALID_TOKEN; goto Cleanup; } // // Fixup the buffer pointers // UserName = AuthenticateMessage->UserName; UserName.Buffer = UserName.Buffer + (ULONG) AuthenticateMessage; DomainName = AuthenticateMessage->DomainName; DomainName.Buffer = DomainName.Buffer + (ULONG) AuthenticateMessage; Workstation = AuthenticateMessage->Workstation; Workstation.Buffer = Workstation.Buffer + (ULONG) AuthenticateMessage; NtChallengeResponse = AuthenticateMessage->NtChallengeResponse; NtChallengeResponse.Buffer = NtChallengeResponse.Buffer + (ULONG) AuthenticateMessage; LmChallengeResponse = AuthenticateMessage->LmChallengeResponse; LmChallengeResponse.Buffer = LmChallengeResponse.Buffer + (ULONG) AuthenticateMessage; // // Allocate a buffer to pass into LsaLogonUser // LogonBufferSize = sizeof(MSV1_0_LM20_LOGON) + UserName.Length + DomainName.Length + Workstation.Length + LmChallengeResponse.Length + NtChallengeResponse.Length; scRet = ZwAllocateVirtualMemory( NtCurrentProcess(), &LogonBuffer, 0L, &LogonBufferSize, MEM_COMMIT, PAGE_READWRITE ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } // // Fill in the fixed-length portions // LogonBuffer->MessageType = MsV1_0NetworkLogon; RtlCopyMemory( LogonBuffer->ChallengeToClient, NtlmAuthenticateMessage->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH ); // // Fill in the variable length pieces // Where = (PUCHAR) (LogonBuffer + 1); PutString( (PSTRING) &LogonBuffer->LogonDomainName, &DomainName, 0, &Where ); PutString( (PSTRING) &LogonBuffer->UserName, &UserName, 0, &Where ); PutString( (PSTRING) &LogonBuffer->Workstation, &Workstation, 0, &Where ); PutString( (PSTRING) &LogonBuffer->CaseSensitiveChallengeResponse, &NtChallengeResponse, 0, &Where ); PutString( (PSTRING) &LogonBuffer->CaseInsensitiveChallengeResponse, &LmChallengeResponse, 0, &Where ); LogonBuffer->ParameterControl = MSV1_0_CLEARTEXT_PASSWORD_ALLOWED | NtlmAuthenticateMessage->ParameterControl; scRet = RtlUnicodeStringToAnsiString( &SourceName, (PUNICODE_STRING) &Workstation, TRUE ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } if ( fContextReq & ASC_REQ_LICENSING ) { EffectivePackageId = PackageId | LSA_CALL_LICENSE_SERVER ; } else { EffectivePackageId = PackageId ; } scRet = LsaLogonUser( Client->hPort, &SourceName, Network, EffectivePackageId, LogonBuffer, LogonBufferSize, NULL, // token groups &KsecTokenSource, (PVOID *) &LogonProfile, &LogonProfileSize, &LogonId, &TokenHandle, &Quotas, &SubStatus ); if (scRet == STATUS_ACCOUNT_RESTRICTION) { scRet = SubStatus; } if (!NT_SUCCESS(scRet)) { // // LsaLogonUser returns garbage for the token if it fails, // so zero it now so we don't try to close it later. // TokenHandle = NULL; goto Cleanup; } // // Create the kernel context // scRet = NtlmInitKernelContext( LogonProfile->UserSessionKey, LogonProfile->LanmanSessionKey, TokenHandle, phNewContext ); if (!NT_SUCCESS(scRet)) { goto Cleanup; } TokenHandle = NULL; // // Allocate the return buffer. // NtlmAcceptResponse = (PNTLM_ACCEPT_RESPONSE) AcceptResponseToken->pvBuffer; if (NtlmAcceptResponse == NULL) { scRet = SEC_E_INSUFFICIENT_MEMORY; goto Cleanup; } TempLogonId = (LUID UNALIGNED *) &NtlmAcceptResponse->LogonId; *TempLogonId = LogonId; NtlmAcceptResponse->UserFlags = LogonProfile->UserFlags; RtlCopyMemory( NtlmAcceptResponse->UserSessionKey, LogonProfile->UserSessionKey, MSV1_0_USER_SESSION_KEY_LENGTH ); RtlCopyMemory( NtlmAcceptResponse->LanmanSessionKey, LogonProfile->LanmanSessionKey, MSV1_0_LANMAN_SESSION_KEY_LENGTH ); TempKickoffTime = (LARGE_INTEGER UNALIGNED *) &NtlmAcceptResponse->KickoffTime; *TempKickoffTime = LogonProfile->KickOffTime; AcceptResponseToken->cbBuffer = sizeof(NTLM_ACCEPT_RESPONSE); if ( fContextReq & ASC_REQ_LICENSING ) { *pfContextAttr = ASC_RET_ALLOCATED_MEMORY | ASC_RET_LICENSING ; } else { *pfContextAttr = ASC_RET_ALLOCATED_MEMORY; } *ptsExpiry = LogonProfile->LogoffTime; scRet = SEC_E_OK; Cleanup: if (SourceName.Buffer != NULL) { RtlFreeAnsiString(&SourceName); } if (LogonBuffer != NULL) { ZwFreeVirtualMemory( NtCurrentProcess(), &LogonBuffer, &LogonBufferSize, MEM_RELEASE ); } if (LogonProfile != NULL) { LsaFreeReturnBuffer(LogonProfile); } if (TokenHandle != NULL) { NtClose(TokenHandle); } return(scRet); }
bool SecurityHelper::CallLsaLogonUser( HANDLE hLsa, const wchar_t* domain, const wchar_t* user, const wchar_t* pass, SECURITY_LOGON_TYPE logonType, LUID* pLogonSessionId, HANDLE* phToken, MSV1_0_INTERACTIVE_PROFILE** ppProfile, DWORD* pWin32Error) { bool result = false; DWORD win32Error = 0; *phToken = 0; LUID ignoredLogonSessionId; // optional arguments if (ppProfile) *ppProfile = 0; if (pWin32Error) *pWin32Error = 0; if (!pLogonSessionId) pLogonSessionId = &ignoredLogonSessionId; LSA_STRING logonProcessName = { 0 }; TOKEN_SOURCE sourceContext = { 's', 'a', 'm', 'p', 'l', 'e' }; MSV1_0_INTERACTIVE_PROFILE* pProfile = 0; ULONG cbProfile = 0; QUOTA_LIMITS quotaLimits; NTSTATUS substatus; DWORD cbLogonRequest; MSV1_0_INTERACTIVE_LOGON* pLogonRequest = _allocLogonRequest(domain, user, pass, &cbLogonRequest); if (!pLogonRequest) { win32Error = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } if (!_newLsaString(&logonProcessName, LOGON_PROCESS_NAME)) { win32Error = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } // LsaLogonUser - the function from hell NTSTATUS status = LsaLogonUser( hLsa, &logonProcessName, // we use our logon process name for the "origin name" logonType, LOGON32_PROVIDER_DEFAULT, // we use MSV1_0 or Kerb, whichever is supported pLogonRequest, cbLogonRequest, 0, // we do not add any group SIDs &sourceContext, (void**)&pProfile, // caller must free this via LsaFreeReturnBuffer &cbProfile, pLogonSessionId, phToken, "aLimits, // we ignore this, but must pass in anyway &substatus); if (status) { win32Error = LsaNtStatusToWinError(status); if ((ERROR_ACCOUNT_RESTRICTION == win32Error && STATUS_PASSWORD_EXPIRED == substatus)) { win32Error = ERROR_PASSWORD_EXPIRED; } *phToken = 0; pProfile = 0; LDB2(L"LsaLogonUser failed. Status = %d, substatus = 0x%08X", win32Error, substatus); goto cleanup; } if (ppProfile) { *ppProfile = (MSV1_0_INTERACTIVE_PROFILE*)pProfile; pProfile = 0; } result = true; cleanup: // if caller cares about the details, pass them on if (pWin32Error) *pWin32Error = win32Error; if (pLogonRequest) { SecureZeroMemory(pLogonRequest, cbLogonRequest); delete pLogonRequest; } if (pProfile) LsaFreeReturnBuffer(pProfile); _deleteLsaString(&logonProcessName); return result; }
int _tmain(int argc, TCHAR *argv[]) { BOOL bResult; NTSTATUS Status; NTSTATUS SubStatus; HANDLE hLsa = NULL; HANDLE hProcess = NULL; HANDLE hToken = NULL; HANDLE hTokenS4U = NULL; LSA_STRING Msv1_0Name = { 0 }; LSA_STRING OriginName = { 0 }; PMSV1_0_S4U_LOGON pS4uLogon = NULL; TOKEN_SOURCE TokenSource; ULONG ulAuthenticationPackage; DWORD dwMessageLength; PBYTE pbPosition; PROCESS_INFORMATION pi = { 0 }; STARTUPINFO si = { 0 }; PTOKEN_GROUPS pGroups = NULL; PSID pLogonSid = NULL; PSID pExtraSid = NULL; PVOID pvProfile = NULL; DWORD dwProfile = 0; LUID logonId = { 0 }; QUOTA_LIMITS quotaLimits; LPTSTR szCommandLine = NULL; LPTSTR szSrcCommandLine = TEXT("%systemroot%\\system32\\cmd.exe"); LPTSTR szDomain = NULL; LPTSTR szUsername = NULL; TCHAR seps[] = TEXT("\\"); TCHAR *next_token = NULL; g_hHeap = GetProcessHeap(); if (argc < 2) { fprintf(stderr, "Usage:\n s4u.exe Domain\\Username [Extra SID]\n\n"); goto End; } // // Get DOMAIN and USERNAME from command line. // szDomain = _tcstok_s(argv[1], seps, &next_token); if (szDomain == NULL) { fprintf(stderr, "Unable to parse command line.\n"); goto End; } szUsername = _tcstok_s(NULL, seps, &next_token); if (szUsername == NULL) { fprintf(stderr, "Unable to parse command line.\n"); goto End; } // // Activate the TCB privilege // hProcess = GetCurrentProcess(); OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); if (!SetPrivilege(hToken, SE_TCB_NAME, TRUE)) { goto End; } // // Get logon SID // if (!GetLogonSID(hToken, &pLogonSid)) { fprintf(stderr, "Unable to find logon SID.\n"); goto End; } // // Connect (Untrusted) to LSA // Status = LsaConnectUntrusted(&hLsa); if (Status!=STATUS_SUCCESS) { fprintf(stderr, "LsaConnectUntrusted failed (error 0x%x).", Status); hLsa = NULL; goto End; } // // Lookup for the MSV1_0 authentication package (NTLMSSP) // InitLsaString(&Msv1_0Name, MSV1_0_PACKAGE_NAME); Status = LsaLookupAuthenticationPackage(hLsa, &Msv1_0Name, &ulAuthenticationPackage); if (Status!=STATUS_SUCCESS) { fprintf(stderr, "LsaLookupAuthenticationPackage failed (error 0x%x).", Status); hLsa = NULL; goto End; } // // Create MSV1_0_S4U_LOGON structure // dwMessageLength = sizeof(MSV1_0_S4U_LOGON) + (2 + wcslen(szDomain) + wcslen(szUsername)) * sizeof(WCHAR); pS4uLogon = (PMSV1_0_S4U_LOGON)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, dwMessageLength); if (pS4uLogon == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } pS4uLogon->MessageType = MsV1_0S4ULogon; pbPosition = (PBYTE)pS4uLogon + sizeof(MSV1_0_S4U_LOGON); pbPosition = InitUnicodeString(&pS4uLogon->UserPrincipalName, szUsername, pbPosition); pbPosition = InitUnicodeString(&pS4uLogon->DomainName, szDomain, pbPosition); // // Misc // strcpy_s(TokenSource.SourceName, TOKEN_SOURCE_LENGTH, "S4UWin"); InitLsaString(&OriginName, "S4U for Windows"); AllocateLocallyUniqueId(&TokenSource.SourceIdentifier); // // Add extra SID to token. // // If the application needs to connect to a Windows Desktop, Logon SID must be added to the Token. // pGroups = (PTOKEN_GROUPS)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, sizeof(TOKEN_GROUPS) + 2*sizeof(SID_AND_ATTRIBUTES)); if (pGroups == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } pGroups->GroupCount = 1; pGroups->Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; pGroups->Groups[0].Sid = pLogonSid; // // If an extra SID is specified to command line, add it to the pGroups structure. // if (argc==3) { bResult = ConvertStringSidToSid(argv[2], &pExtraSid); if (bResult == TRUE) { pGroups->GroupCount = 2; pGroups->Groups[1].Attributes = SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; pGroups->Groups[1].Sid = pExtraSid; } else { fprintf(stderr, "Unable to convert SID (error %u).", GetLastError()); } } // // Call LSA // Status = LsaLogonUser( hLsa, &OriginName, Network, // Or Batch ulAuthenticationPackage, pS4uLogon, dwMessageLength, pGroups, // LocalGroups &TokenSource, // SourceContext &pvProfile, &dwProfile, &logonId, &hTokenS4U, "aLimits, &SubStatus ); if (Status!=STATUS_SUCCESS) { printf("LsaLogonUser failed (error 0x%x).\n", Status); goto End; } printf("LsaLogonUser: OK, LogonId: 0x%x-0x%x\n", logonId.HighPart, logonId.LowPart); // // Create process with S4U token. // si.cb = sizeof(STARTUPINFO); si.lpDesktop = TEXT("winsta0\\default"); // // Warning: szCommandLine parameter of CreateProcessAsUser() must be writable // szCommandLine = (LPTSTR)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, MAX_PATH * sizeof(TCHAR)); if (szCommandLine == NULL) { fprintf(stderr, "HeapAlloc failed (error %u).", GetLastError()); goto End; } if (ExpandEnvironmentStrings(szSrcCommandLine, szCommandLine, MAX_PATH) == 0) { fprintf(stderr, "ExpandEnvironmentStrings failed (error %u).", GetLastError()); goto End; } // // CreateProcessAsUser required SeAssignPrimaryTokenPrivilege but no need to be activated. // bResult = CreateProcessAsUser( hTokenS4U, NULL, szCommandLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, TEXT("c:\\"), &si, &pi ); if (bResult == FALSE) { printf("CreateProcessAsUser failed (error %u).\n", GetLastError()); goto End; } End: // // Free resources // if (Msv1_0Name.Buffer) HeapFree(g_hHeap, 0, Msv1_0Name.Buffer); if (OriginName.Buffer) HeapFree(g_hHeap, 0, OriginName.Buffer); if (pLogonSid) HeapFree(g_hHeap, 0, pLogonSid); if (pExtraSid) LocalFree(pExtraSid); if (pS4uLogon) HeapFree(g_hHeap, 0, pS4uLogon); if (pGroups) HeapFree(g_hHeap, 0, pGroups); if (pvProfile) LsaFreeReturnBuffer(pvProfile); if (hLsa) LsaClose(hLsa); if (hToken) CloseHandle(hToken); if (hTokenS4U) CloseHandle(hTokenS4U); if (pi.hProcess) CloseHandle(pi.hProcess); if (pi.hThread) CloseHandle(pi.hThread); return EXIT_SUCCESS; }
int LsaLogon(HANDLE *hToken, char homeDir[MAX_PATH], char *user, char *pkBlob, int pkBlobSize, char *sign, int signSize, char *data, int dataSize, int dataFellow) { int exitCode = 1; NTSTATUS ntStat = 0; LSA_STRING logonProcName; LSA_STRING originName; LSA_STRING authPckgName; HANDLE hLsa = NULL; LSA_OPERATIONAL_MODE securityMode; /* * Impersonation, "weak" token returned from network logon. * We can't create process as other user via this token. */ HANDLE hWeakToken = NULL; /* * Login data. */ LsaAuth *lsaAuth = NULL; ULONG lsaAuthSize = 0; ULONG authPckgId = 0; TOKEN_SOURCE srcToken; PVOID profile = NULL; ULONG profileSize; LUID logonId; QUOTA_LIMITS quotas; NTSTATUS loginStat; debug("-> LsaLogon()..."); /* * We check only hToken arg, becouse other args are tested in AllocLsaAuth(). */ debug("Checking args..."); FAIL(hToken == NULL); /* * Setup lsa strings. */ debug("Setting up LSA Strings..."); FAIL(InitLsaString(&logonProcName, "sshd-logon")); FAIL(InitLsaString(&originName, "NTLM")); FAIL(InitLsaString(&authPckgName, "SSH-LSA")); /* * Enable needed privilege to current running process. */ EnablePrivilege("SeTcbPrivilege", 1); /* * Register new logon process. */ debug("LsaRegisterLogonProcess()..."); NTFAIL(LsaRegisterLogonProcess(&logonProcName, &hLsa, &securityMode)); /* * Retrieve Authenticated Package ID. */ debug("Retrieving Authentification Package ID..."); NTFAIL(LsaLookupAuthenticationPackage(hLsa, &authPckgName, &authPckgId)); /* * Allocate LsaAuth struct. */ debug("Allocating LsaAuth struct..."); FAIL(AllocLsaAuth(&lsaAuth, user, pkBlob, pkBlobSize, sign, signSize, data, dataSize, dataFellow)); lsaAuthSize = lsaAuth -> totalSize_; /* * Create TOKEN_SOURCE part */ debug("Setting up TOKEN_SOURCE..."); FAIL(AllocateLocallyUniqueId(&srcToken.SourceIdentifier) == FALSE); memcpy(srcToken.SourceName, "**sshd**", 8); /* * Try to login using LsaAuth struct. */ debug("Login attemp..."); NTFAIL(LsaLogonUser(hLsa, &originName, Network, authPckgId, lsaAuth, lsaAuthSize, NULL, &srcToken, &profile, &profileSize, &logonId, &hWeakToken, "as, &loginStat)); debug("login status: %x...", loginStat); //FAIL(WideCharToMultiByte( CP_UTF8, 0, profile, -1, homeDir, MAX_PATH, NULL, NULL)==0); //memcpy(homeDir, profile, MAX_PATH*sizeof(wchar_t)); lstrcpyW(homeDir, profile); debug("homedir = [%ls]", (char *) homeDir); //strcpy(homeDir, profile); //PrintToken(hToken); /* * Duplicate 'weak' impersonation token into Primary Key token. * We can create process using duplicated token. */ debug("Duplicating token..."); FAIL(DuplicateTokenEx(hWeakToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, hToken) == 0); exitCode = 0; fail: if (exitCode) { switch(ntStat) { case STATUS_LOGON_FAILURE: { debug("SSH-LSA authorization failed. " "(err = %u, ntStat = %x).", GetLastError(), ntStat); exitCode = 0; break; } case STATUS_NO_SUCH_PACKAGE: { debug("SSH-LSA package not found. " "(err = %u, ntStat = %x).", GetLastError(), ntStat); break; } default: { debug("Cannot logon using LSA package (err = %u, ntStat = %x).", GetLastError(), ntStat); } } hToken = NULL; } else { debug("LsaLogon : OK."); } /* * Clean up. */ CloseHandle(hWeakToken); LsaFreeReturnBuffer(profile); EnablePrivilege("SeTcbPrivilege", 0); LsaDeregisterLogonProcess(hLsa); ClearLsaString(&logonProcName); ClearLsaString(&originName); ClearLsaString(&authPckgName); debug("<- LsaLogon()..."); return exitCode; }