PSS ID Number: 137578
Article Last Modified on 5/7/2003
MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
Batch
Service
Interactive
Mssdk\Lib\Advapi32.lib
Mssdk\Lib\Kernel32.lib
Mssdk\Lib\Secur32.lib
Mssdk\Lib\Advapi32.lib
Mssdk\Lib\Kernel32.lib
Ntddk\Libfre\I386\Lsadll.lib
Ntddk\Libfre\I386\Ntdll.lib
#include <windows.h>
#include <stdio.h>
#include <ntsecapi.h>
BOOL
SetCurrentPrivilege(
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
);
NTSTATUS RegisterLogonProcess(void);
void DeRegisterLogonProcess(void);
NTSTATUS MyLogonUser(
LPWSTR UserName,
LPWSTR Domain,
LPWSTR Password,
SECURITY_LOGON_TYPE LogonType,
PHANDLE pLogonToken,
PMSV1_0_INTERACTIVE_PROFILE *pProfileBuffer);
void DisplayProfile(
PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer);
void DisplaySystemTime(
LPSTR Text,
LPFILETIME ft);
void InitString(PLSA_STRING LsaString, LPSTR String);
#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13
#define AUTH_PACKAGE "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0"
//
// if you have the ddk, include ntstatus.h
//
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#endif
//
// cache LsaHandle and the authentication package Id
//
HANDLE gLsaHandle = INVALID_HANDLE_VALUE;
ULONG gAuthPackageId = 0;
int wmain(int argc, wchar_t *argv[])
{
HANDLE hToken;
PMSV1_0_INTERACTIVE_PROFILE Profile = NULL;
NTSTATUS Status;
LPWSTR wUserName;
LPWSTR wDomain;
LPWSTR wPassword;
if (argc != 4)
{
fprintf(stderr,
"Usage: %ls <UserName> <DomainName> <Password>\n", argv[0]);
return RTN_USAGE;
}
wUserName = argv[1];
wDomain = argv[2];
wPassword = argv[3];
//
// enable the SeTcbPrivilege
//
if (!SetCurrentPrivilege(SE_TCB_NAME, TRUE))
{
fprintf(stderr,
"SeTcbPrivilege could not be enabled! (rc=%lu)\n",
GetLastError());
return RTN_ERROR;
}
//
// Prepare to use the authentication package
//
Status=RegisterLogonProcess();
//
// disable the SeTcbPrivilege
//
SetCurrentPrivilege(SE_TCB_NAME, FALSE);
if (Status != STATUS_SUCCESS)
{
fprintf(stderr,
"RegisterLogonProcess error! (ntstatus=0x%lx)\n", Status);
return RTN_ERROR;
}
//
// we've successfully setup a link to the authentication package
// we can now logon via MyLogonUser until we DeRegister the
// authentication package
//
Status = MyLogonUser(wUserName, wDomain, wPassword,
Interactive, &hToken, &Profile);
if (Status == STATUS_SUCCESS)
{
//
// impersonate the user we just got a token for
//
if (ImpersonateLoggedOnUser(hToken))
{
CHAR szName[255];
DWORD cbName=255;
//
// indicate who we logged on, to verify success
//
GetUserNameA(szName, &cbName);
fprintf(stdout,"Successfully logged on user = %s\n",
szName);
RevertToSelf();
//
// Display the Profile
//
DisplayProfile(Profile);
//
// free Profile buffer allocated by Lsa
//
if (Profile)
LsaFreeReturnBuffer(Profile);
}
else
{
fprintf(stdout,"ImpersonateLoggedOnUser error (rc=%lu)\n",
GetLastError());
}
//
// close the process token
//
CloseHandle(hToken);
}
else
{
fprintf(stderr,
"MyLogonUser error! (ntstatus=0x%lx)\n", Status);
}
//
// we are done with the authentication package
//
DeRegisterLogonProcess();
return RTN_OK;
}
NTSTATUS RegisterLogonProcess(void)
{
CHAR szFileName[128];
LSA_STRING LogonProcessName;
LSA_STRING PackageName;
LSA_OPERATIONAL_MODE SecurityMode;
NTSTATUS Status;
GetModuleFileNameA(NULL, szFileName, 127);
//
// Prepare to use authentication services
//
InitString(&LogonProcessName, szFileName);
if ((Status=LsaRegisterLogonProcess(
&LogonProcessName,
&gLsaHandle, // global LsaHandle
&SecurityMode
)) != STATUS_SUCCESS)
return Status;
//
// Obtain ID used to reference the authentication package
//
InitString(&PackageName, AUTH_PACKAGE);
if ((Status=LsaLookupAuthenticationPackage(
gLsaHandle,
&PackageName,
&gAuthPackageId // global Authentication Package Id
)) != STATUS_SUCCESS)
{
//
// if this failed, cleanup
//
DeRegisterLogonProcess();
}
return Status;
}
void DeRegisterLogonProcess(void)
{
//
// Close and invalidate the handle
//
CloseHandle(gLsaHandle);
gLsaHandle = INVALID_HANDLE_VALUE;
}
NTSTATUS MyLogonUser(
LPWSTR UserName,
LPWSTR Domain,
LPWSTR Password,
SECURITY_LOGON_TYPE LogonType,
PHANDLE pLogonToken,
PMSV1_0_INTERACTIVE_PROFILE *pProfileBuffer)
{
HANDLE hHeap=GetProcessHeap(); // cache the process heap handle
USHORT cbUserName; // number of bytes for username
USHORT cbDomain; // number of bytes for domain
USHORT cbPassword; // number of bytes for password
LSA_STRING OriginName;
LUID LogonLuid;
TOKEN_SOURCE SourceContext;
QUOTA_LIMITS Quotas;
PMSV1_0_INTERACTIVE_LOGON MsvAuthInfo;
ULONG ProfileBufferLength;
PVOID AuthInfoBuf;
ULONG AuthInfoSize;
PTOKEN_GROUPS TokenGroups;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority=
SECURITY_LOCAL_SID_AUTHORITY;
PSID LogonSid;
PSID LocalSid;
NTSTATUS Status;
NTSTATUS SubStatus;
//
// invalidate pointers to dynamically allocated resources
//
LocalSid = NULL;
LogonSid = NULL;
AuthInfoBuf = NULL;
//
// Set logon origin
// change to represent your product name
//
InitString(&OriginName, "nospam@microsoft.com");
//
// Initialize source context structure
//
strncpy(SourceContext.SourceName, "Source ",
sizeof(SourceContext.SourceName));
if (!AllocateLocallyUniqueId(&SourceContext.SourceIdentifier))
{
return STATUS_UNSUCCESSFUL;
}
__try
{
//
// the following code is specific to the interactive logontype
//
//
// Create Logon Sid and Local Sid
//
if (!AllocateLocallyUniqueId(&LogonLuid))
{
Status = STATUS_UNSUCCESSFUL;
__leave;
}
//
// NOTE: for Gina, winlogon passes us a Logon Sid, which we could use
// here instead
//
if (!AllocateAndInitializeSid(
&IdentifierAuthority,
3,
SECURITY_LOGON_IDS_RID,
LogonLuid.HighPart,
LogonLuid.LowPart,
0, 0, 0, 0, 0,
&LogonSid))
{
Status = STATUS_NO_MEMORY;
__leave;
}
if (!AllocateAndInitializeSid(
&IdentifierAuthority,
1,
SECURITY_LOCAL_RID,
0, 0, 0, 0, 0, 0, 0,
&LocalSid))
{
Status = STATUS_NO_MEMORY;
__leave;
}
//
// Create logon token groups containing Logon and Local Sid
// for a gina call to LsaLogonUser, we are given a logon Sid,
// so we could skip creating the LogonSid below, and just add what
// we were passed in by gina
//
#define TOKEN_GROUP_COUNT 2
TokenGroups = (PTOKEN_GROUPS)HeapAlloc(hHeap, 0,
sizeof(TOKEN_GROUPS) +
(TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) *
sizeof(SID_AND_ATTRIBUTES));
if (TokenGroups == NULL)
{
Status = STATUS_NO_MEMORY;
__leave;
}
TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
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;
//
// Build logon authentication package valid for the following
// logons: batch, interactive, service
//
// the package is passed in an LPC call, so it needs to reside in
// contiguous memory.
//
cbUserName = (USHORT)(wcslen(UserName) * sizeof(WCHAR));
cbDomain = (USHORT)(wcslen(Domain) * sizeof(WCHAR));
cbPassword = (USHORT)(wcslen(Password) * sizeof(WCHAR));
AuthInfoSize = sizeof(MSV1_0_INTERACTIVE_LOGON) +
cbUserName + sizeof(WCHAR) +
cbDomain + sizeof(WCHAR) +
cbPassword + sizeof(WCHAR) ;
AuthInfoBuf = HeapAlloc(hHeap,
HEAP_ZERO_MEMORY,
AuthInfoSize);
MsvAuthInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthInfoBuf;
if (MsvAuthInfo == NULL)
{
Status = STATUS_NO_MEMORY;
__leave;
}
//
// The authentication buffer is interactivelogon type for
// batch, interactive, service
//
MsvAuthInfo->MessageType = MsV1_0InteractiveLogon;
//
// Copy the user name into the authentication buffer
//
MsvAuthInfo->UserName.Length = cbUserName;
MsvAuthInfo->UserName.MaximumLength = cbUserName + sizeof(WCHAR);
MsvAuthInfo->UserName.Buffer = (PWSTR)(MsvAuthInfo + 1);
wcscpy(MsvAuthInfo->UserName.Buffer, UserName);
//
// Copy the domain name into the authentication buffer
//
MsvAuthInfo->LogonDomainName.Length = cbDomain;
MsvAuthInfo->LogonDomainName.MaximumLength = cbDomain + sizeof(WCHAR);
MsvAuthInfo->LogonDomainName.Buffer = (PWSTR)
((PBYTE)(MsvAuthInfo->UserName.Buffer) +
MsvAuthInfo->UserName.MaximumLength);
wcscpy(MsvAuthInfo->LogonDomainName.Buffer, Domain);
//
// Copy the password into the authentication buffer
//
MsvAuthInfo->Password.Length = cbPassword;
MsvAuthInfo->Password.MaximumLength = cbPassword + sizeof(WCHAR);
MsvAuthInfo->Password.Buffer = (PWSTR)
((PBYTE)(MsvAuthInfo->LogonDomainName.Buffer) +
MsvAuthInfo->LogonDomainName.MaximumLength);
wcscpy(MsvAuthInfo->Password.Buffer, Password);
Status = LsaLogonUser(
gLsaHandle, // global LsaHandle
&OriginName,
LogonType, // logon type
gAuthPackageId, // global authentication package ID
AuthInfoBuf,
AuthInfoSize,
TokenGroups,
&SourceContext,
(PVOID *)pProfileBuffer,
&ProfileBufferLength,
&LogonLuid,
pLogonToken,
&Quotas,
&SubStatus);
} // try
__finally
{
cbUserName = cbDomain = cbPassword = 0; // sensitive information
//
// free token group list
//
if (TokenGroups)
HeapFree(hHeap, 0, TokenGroups);
//
// zero and free authentication buffer
//
if (AuthInfoBuf)
{
ZeroMemory(AuthInfoBuf, AuthInfoSize); // sensitive buffer
HeapFree(hHeap, 0, AuthInfoBuf);
}
//
// free Sids
//
if (LocalSid)
FreeSid(LocalSid);
//
// TODO add a parameter to this function for the LogonSid
// We would then call FreeSid from outside this function when we
// are done with the logon Sid. This is appropriate for Gina, etc.
//
//
// NOTE: THIS LOGIC WILL BE DIFFERENT FOR A GINA IF WE USE THE
// SID WHICH GINA PREPARED.
//
if (Status != STATUS_SUCCESS) // only free this if we failed
{
if (LogonSid)
FreeSid(LogonSid);
}
} // finally
return Status;
}
void DisplayProfile(PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer)
{
fprintf(stdout, "LogonCount = 0x%x\n",
ProfileBuffer->LogonCount);
fprintf(stdout, "BadPasswordCount = 0x%x\n",
ProfileBuffer->BadPasswordCount);
DisplaySystemTime("LogonTime ",
(LPFILETIME)&ProfileBuffer->LogonTime);
DisplaySystemTime("LogoffTime ",
(LPFILETIME)&ProfileBuffer->LogoffTime);
DisplaySystemTime("KickOffTime ",
(LPFILETIME)&ProfileBuffer->KickOffTime);
DisplaySystemTime("PasswordLastSet ",
(LPFILETIME)&ProfileBuffer->PasswordLastSet);
DisplaySystemTime("PasswordCanChange ",
(LPFILETIME)&ProfileBuffer->PasswordCanChange);
DisplaySystemTime("PasswordMustChange",
(LPFILETIME)&ProfileBuffer->PasswordMustChange);
fprintf(stdout, "LogonScript = %ls\n",
ProfileBuffer->LogonScript.Buffer);
fprintf(stdout, "HomeDirectory = %ls\n",
ProfileBuffer->HomeDirectory.Buffer);
fprintf(stdout, "FullName = %ls\n",
ProfileBuffer->FullName.Buffer);
fprintf(stdout, "ProfilePath = %ls\n",
ProfileBuffer->ProfilePath.Buffer);
fprintf(stdout, "HomeDirectoryDrive = %ls\n",
ProfileBuffer->HomeDirectoryDrive.Buffer);
fprintf(stdout, "LogonServer = %ls\n",
ProfileBuffer->LogonServer.Buffer);
fprintf(stdout, "UserFlags = 0x%lx\n",
ProfileBuffer->UserFlags);
}
void DisplaySystemTime(
LPSTR Text,
LPFILETIME ft)
{
SYSTEMTIME utc;
SYSTEMTIME st;
FileTimeToSystemTime(ft, &utc);
SystemTimeToTzSpecificLocalTime(NULL, &utc, &st);
fprintf(stdout,"%s = %02u-%02u-%u %02u:%02u:%02u.%02u\n",
Text, st.wMonth, st.wDay, st.wYear,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
}
void InitString(
PLSA_STRING LsaString,
LPSTR String)
{
DWORD StringLength;
if (String == NULL)
{
LsaString->Buffer = NULL;
LsaString->Length = 0;
LsaString->MaximumLength = 0;
return;
}
StringLength = strlen(String);
LsaString->Buffer = String;
LsaString->Length = (USHORT) StringLength * sizeof(CHAR);
LsaString->MaximumLength =
(USHORT) (StringLength + 1) * sizeof(CHAR);
}
BOOL SetCurrentPrivilege(
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege) // to enable or disable privilege
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
BOOL bSuccess=FALSE;
if (!LookupPrivilegeValue(NULL, Privilege, &luid))
return FALSE;
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken
))
return FALSE;
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious);
if (GetLastError() == ERROR_SUCCESS)
{
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if (bEnablePrivilege) {
tpPrevious.Privileges[0].Attributes |=
(SE_PRIVILEGE_ENABLED);
}
else
{
tpPrevious.Privileges[0].Attributes ^=
(SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
}
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL);
if (GetLastError() == ERROR_SUCCESS)
bSuccess=TRUE;
}
CloseHandle(hToken);
return bSuccess;
}
Additional query words: prodnt winlogon BseSecurity BseMisc CodeSam
Keywords: kbAPI kbhowto kbKernBase kbLSA kbSecurity KB137578
Technology: kbAudDeveloper kbOSWin2000 kbOSWinNT400 kbOSWinNTSearch kbOSWinSearch kbOSWinXP kbOSWinXPSearch kbWin32API kbWin32sSearch