Better late than never.
You estabilish a connection to the LSA server, you search for the "Negotiate" authentication package, you create an authentication info structure filling in as the type of logon the constant MsV1_0S4ULogon that identifies a service for user (S4U) logon.
When an S4U logon is used, no password is stored by the system and there is no access to the network or encrypted files.
The SeTcbPrivilege privilege is needed to be able to create the token for impersonation purposes.
If you execute the program as administrator who, by default, doesn't have the SeTcbPrivilege privilege, the program returns success but the token created is not a primary token and can be used only for identification purposes.
#include "stdafx.h"
#include <Windows.h>
#include <Ntsecapi.h>
#include <stdio.h>
#include <Userenv.h>
size_t wcsByteLen(const wchar_t* str);
void InitUnicodeString(UNICODE_STRING& str, const wchar_t* value, BYTE* buffer, size_t& offset);
//#define NEGOSSP_NAME_A "Negotiate"
int main(int argc, char * argv[])
{
HANDLE lsa;
ULONG Flags = MSV1_0_S4U_LOGON_FLAG_CHECK_LOGONHOURS;
DWORD len;
TOKEN_STATISTICS tokenstats;
LsaConnectUntrusted(&lsa);
const wchar_t* domain = L"Computer_name";
const wchar_t* user = L"User_name";
// prepare the authentication info
ULONG authInfoSize = sizeof(MSV1_0_S4U_LOGON) + wcsByteLen(user) + wcsByteLen(domain);
BYTE* authInfoBuf = new BYTE[authInfoSize];
MSV1_0_S4U_LOGON* authInfo = (MSV1_0_S4U_LOGON*)authInfoBuf;
// https://msdn.microsoft.com/en-us/aa378764
authInfo->MessageType = MsV1_0S4ULogon;
/*authInfo->Flags = Flags;*/
size_t offset = sizeof(MSV1_0_S4U_LOGON);
InitUnicodeString(authInfo->UserPrincipalName, user, authInfoBuf, offset);
InitUnicodeString(authInfo->DomainName, domain, authInfoBuf, offset);
// find the Negotiate security package
char packageNameRaw[] = "Negotiate";
LSA_STRING packageName;
packageName.Buffer = packageNameRaw;
packageName.Length = packageName.MaximumLength = (USHORT)strlen(packageName.Buffer);
ULONG packageId;
NTSTATUS stao_05 = LsaLookupAuthenticationPackage(lsa, &packageName, &packageId);
// create a test origin and token source
LSA_STRING origin = {};
origin.Buffer = _strdup("Test");
origin.Length = (USHORT)strlen(origin.Buffer);
origin.MaximumLength = origin.Length;
TOKEN_SOURCE source = {};
strcpy_s(source.SourceName, "Test");
bool test = AllocateLocallyUniqueId(&source.SourceIdentifier);
void* profileBuffer;
DWORD profileBufLen;
LUID luid;
HANDLE token;
QUOTA_LIMITS qlimits;
NTSTATUS subStatus;
NTSTATUS status = LsaLogonUser(lsa, &origin, Batch, packageId, authInfo, authInfoSize, NULL, &source, &profileBuffer, &profileBufLen, &luid, &token, &qlimits, &subStatus);
if (status == ERROR_SUCCESS)
{
if (GetTokenInformation(token, TokenStatistics, &tokenstats, sizeof(TOKEN_STATISTICS), &len) == TRUE)
{
switch (tokenstats.TokenType)
{
case TokenPrimary: printf("Token type: %s\n", "Primary");
break;
case TokenImpersonation: printf("Token type: %s\n", "Impersonation");
break;
}
switch (tokenstats.ImpersonationLevel)
{
case SecurityAnonymous: printf("Impersonation level: %s\n", "Anonymous");
break;
case SecurityIdentification: printf("Impersonation level: %s\n", "Identification");
break;
case SecurityImpersonation: printf("Impersonation level: %s\n", "Impersonation");
break;
case SecurityDelegation: printf("Impersonation level: %s\n", "Delegation");
break;
}
}
}
else
{
ULONG err = LsaNtStatusToWinError(status);
printf("LsaLogonUser failed: %x\n", status);
return 1;
}
}
size_t wcsByteLen(const wchar_t* str)
{
return wcslen(str) * sizeof(wchar_t);
}
void InitUnicodeString(UNICODE_STRING& str, const wchar_t* value, BYTE* buffer, size_t& offset)
{
size_t size = wcsByteLen(value);
str.Length = str.MaximumLength = (USHORT)size;
str.Buffer = (PWSTR)(buffer + offset);
memcpy(str.Buffer, value, size);
offset += size;
}