470 lines
12 KiB
C
470 lines
12 KiB
C
/*+
|
|
*
|
|
* Microsoft Windows
|
|
* Copyright (C) Microsoft Corporation, 1997 - 1998.
|
|
*
|
|
* Name : seclogon.cxx
|
|
* Author:Jeffrey Richter (v-jeffrr)
|
|
*
|
|
* Abstract:
|
|
* This is the service DLL for Secondary Logon Service
|
|
* This service supports the CreateProcessWithLogon API implemented
|
|
* in advapi32.dll
|
|
*
|
|
* Revision History:
|
|
* PraeritG 10/8/97 To integrate this in to services.exe
|
|
*
|
|
-*/
|
|
|
|
|
|
#define STRICT
|
|
|
|
#include <Windows.h>
|
|
#include <userenv.h>
|
|
#include <lm.h>
|
|
#include <dsgetdc.h>
|
|
#include <sddl.h>
|
|
|
|
PTOKEN_USER
|
|
SlpGetTokenUser(
|
|
HANDLE TokenHandle,
|
|
PLUID AuthenticationId OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the TOKEN_USER structure for the
|
|
current user, and optionally, the AuthenticationId from his
|
|
token.
|
|
|
|
Arguments:
|
|
|
|
AuthenticationId - Supplies an optional pointer to return the
|
|
AuthenticationId.
|
|
|
|
Return Value:
|
|
|
|
On success, returns a pointer to a TOKEN_USER structure.
|
|
|
|
On failure, returns NULL. Call GetLastError() for more
|
|
detailed error information.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ReturnLength;
|
|
TOKEN_STATISTICS TokenStats;
|
|
PTOKEN_USER pTokenUser = NULL;
|
|
BOOLEAN b = FALSE;
|
|
|
|
if(!GetTokenInformation (
|
|
TokenHandle,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&ReturnLength
|
|
))
|
|
{
|
|
|
|
pTokenUser = (PTOKEN_USER)HeapAlloc( GetProcessHeap(), 0,
|
|
ReturnLength );
|
|
|
|
if (pTokenUser) {
|
|
|
|
if ( GetTokenInformation (
|
|
TokenHandle,
|
|
TokenUser,
|
|
pTokenUser,
|
|
ReturnLength,
|
|
&ReturnLength
|
|
))
|
|
{
|
|
|
|
if (AuthenticationId) {
|
|
|
|
if(GetTokenInformation (
|
|
TokenHandle,
|
|
TokenStatistics,
|
|
(PVOID)&TokenStats,
|
|
sizeof( TOKEN_STATISTICS ),
|
|
&ReturnLength
|
|
))
|
|
{
|
|
|
|
*AuthenticationId = TokenStats.AuthenticationId;
|
|
b = TRUE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We're done, mark that everything worked
|
|
//
|
|
|
|
b = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (!b) {
|
|
|
|
//
|
|
// Something failed, clean up what we were going to return
|
|
//
|
|
|
|
HeapFree( GetProcessHeap(), 0, pTokenUser );
|
|
pTokenUser = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( pTokenUser );
|
|
}
|
|
|
|
|
|
DWORD
|
|
SlpGetUserName(
|
|
IN HANDLE TokenHandle,
|
|
OUT LPTSTR UserName,
|
|
IN OUT PDWORD UserNameLen,
|
|
OUT LPTSTR DomainName,
|
|
IN OUT PDWORD DomNameLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the LSA Server worker routine for the LsaGetUserName
|
|
API.
|
|
|
|
|
|
WARNING: This routine allocates memory for its output. The caller is
|
|
responsible for freeing this memory after use. See description of the
|
|
Names parameter.
|
|
|
|
Arguments:
|
|
|
|
UserName - Receives name of the current user.
|
|
|
|
DomainName - Optionally receives domain name of the current user.
|
|
|
|
Return Values:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_SUCCESS - The call completed successfully and all Sids have
|
|
been translated to names.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
|
|
such as memory to complete the call.
|
|
--*/
|
|
|
|
{
|
|
LUID LogonId;
|
|
PTOKEN_USER TokenUserInformation = NULL;
|
|
SID_NAME_USE Use;
|
|
|
|
//
|
|
// Let's see if we're trying to look up the currently logged on
|
|
// user.
|
|
//
|
|
//
|
|
// TokenUserInformation from this call must be freed by calling
|
|
// HeapFree().
|
|
//
|
|
|
|
TokenUserInformation = SlpGetTokenUser( TokenHandle, &LogonId );
|
|
|
|
if ( TokenUserInformation ) {
|
|
|
|
//
|
|
// Simply do LookupAccountSid...
|
|
//
|
|
if(LookupAccountSid(NULL, TokenUserInformation->User.Sid,
|
|
UserName, UserNameLen, DomainName, DomNameLen,
|
|
&Use))
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, TokenUserInformation );
|
|
return ERROR_SUCCESS;
|
|
}
|
|
HeapFree( GetProcessHeap(), 0, TokenUserInformation );
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
HeapFree( GetProcessHeap(), 0, TokenUserInformation );
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
SlpIsDomainUser(
|
|
HANDLE Token,
|
|
PBOOLEAN IsDomain
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if the current user is logged on to a domain account
|
|
or a local machine account.
|
|
|
|
Arguments:
|
|
|
|
IsDomain - Returns TRUE if the current user is logged on to a domain
|
|
account, FALSE otherwise.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success, FALSE on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR UserName[MAX_PATH];
|
|
DWORD UserNameLen = MAX_PATH;
|
|
TCHAR Domain[MAX_PATH];
|
|
DWORD DomNameLen = MAX_PATH;
|
|
DWORD Status;
|
|
WCHAR pwszMachineName[(MAX_COMPUTERNAME_LENGTH + 1) * sizeof( WCHAR )];
|
|
DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
|
|
BOOL b = FALSE;
|
|
|
|
*IsDomain = FALSE;
|
|
|
|
Status = SlpGetUserName( Token, UserName, &UserNameLen,
|
|
Domain, &DomNameLen );
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
if (GetComputerName ( pwszMachineName, &nSize )) {
|
|
|
|
*IsDomain = (lstrcmp( pwszMachineName, Domain ) != 0);
|
|
|
|
b = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return( b );
|
|
}
|
|
|
|
BOOL
|
|
SlpLoadUserProfile(
|
|
IN HANDLE hToken,
|
|
OUT PHANDLE hProfile
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to determine if the user's profile is loaded,
|
|
and if it is not, loads it.
|
|
|
|
Callers are expected to call SlpUnloadUserProfile() during their cleanup.
|
|
|
|
Arguments:
|
|
|
|
hToken - Returns a handle to the user's token.
|
|
|
|
hProfile - Returns a handle to the user's profile.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the profile is already loaded or if this routine loads it successfully,
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN b = FALSE;
|
|
BOOLEAN DomainUser;
|
|
BOOL fReturn = FALSE;
|
|
TCHAR lpDomainName[MAX_PATH];
|
|
DWORD DomNameLen = MAX_PATH;
|
|
LPWSTR lpServerName = NULL;
|
|
PUSER_INFO_3 lpUserInfo;
|
|
TCHAR lpUserName[MAX_PATH];
|
|
DWORD UserNameLen = MAX_PATH;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
LPWSTR SidString = NULL;
|
|
NTSTATUS Status;
|
|
DWORD dwResult;
|
|
|
|
PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
|
|
|
|
*hProfile = NULL;
|
|
|
|
//
|
|
// First, see if the profile is loaded. If it is,
|
|
// make a simple call to LoadUserProfile just to refcount it
|
|
// and return.
|
|
//
|
|
Status = SlpGetUserName(
|
|
hToken,
|
|
lpUserName,
|
|
&UserNameLen,
|
|
lpDomainName,
|
|
&DomNameLen
|
|
);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
PTOKEN_USER TokenInfo = SlpGetTokenUser( hToken, NULL );
|
|
|
|
if (TokenInfo != NULL) {
|
|
|
|
PSID UserSid = TokenInfo->User.Sid;
|
|
|
|
if(ConvertSidToStringSid( UserSid, &SidString ))
|
|
{
|
|
|
|
LONG lRet;
|
|
HKEY phKeyCurrentUser;
|
|
|
|
//
|
|
// Impersonate the user before doing this.
|
|
//
|
|
if (ImpersonateLoggedOnUser(hToken)) {
|
|
lRet = RegOpenKeyExW(
|
|
HKEY_USERS,
|
|
SidString,
|
|
0, // dwOptions
|
|
MAXIMUM_ALLOWED,
|
|
&phKeyCurrentUser
|
|
);
|
|
|
|
RevertToSelf();
|
|
}
|
|
else {
|
|
lRet = GetLastError();
|
|
if (ERROR_SUCCESS == lRet) {
|
|
lRet = ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
LocalFree(SidString);
|
|
|
|
if (ERROR_SUCCESS == lRet) {
|
|
|
|
//
|
|
// The profile is loaded. Ref it so it doesn't disappear.
|
|
//
|
|
|
|
PROFILEINFO pi;
|
|
|
|
ZeroMemory (&pi, sizeof(pi));
|
|
pi.dwSize = sizeof(pi);
|
|
pi.lpUserName = lpUserName;
|
|
|
|
fReturn = LoadUserProfile (hToken, &pi);
|
|
|
|
if (!fReturn) {
|
|
|
|
rc = GetLastError();
|
|
|
|
} else {
|
|
|
|
*hProfile = pi.hProfile;
|
|
}
|
|
|
|
RegCloseKey( phKeyCurrentUser );
|
|
|
|
} else {
|
|
|
|
//
|
|
// The profile is not loaded. Load it.
|
|
//
|
|
|
|
if (SlpIsDomainUser( hToken, &DomainUser )) {
|
|
|
|
if (DomainUser) {
|
|
|
|
//
|
|
// Determine the name of the DC for this domain
|
|
//
|
|
|
|
if (ImpersonateLoggedOnUser(hToken)) {
|
|
if (ERROR_SUCCESS == (dwResult = DsGetDcName
|
|
(NULL,
|
|
lpDomainName,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&DomainControllerInfo
|
|
))) {
|
|
|
|
lpServerName = DomainControllerInfo->DomainControllerName;
|
|
b = TRUE;
|
|
} else {
|
|
SetLastError(dwResult);
|
|
}
|
|
RevertToSelf();
|
|
}
|
|
|
|
} else {
|
|
|
|
lpServerName = NULL;
|
|
|
|
b = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (b) {
|
|
|
|
//
|
|
// Impersonate the user to get the information
|
|
//
|
|
if (ImpersonateLoggedOnUser(hToken)) {
|
|
Status = NetUserGetInfo( lpServerName, lpUserName, 3, (LPBYTE *)&lpUserInfo );
|
|
|
|
// we must revert before calling LoadUserProfile
|
|
RevertToSelf();
|
|
} else {
|
|
Status = GetLastError();
|
|
if (ERROR_SUCCESS == Status) {
|
|
Status = ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
PROFILEINFO pi;
|
|
|
|
ZeroMemory (&pi, sizeof(pi));
|
|
pi.dwSize = sizeof(pi);
|
|
pi.lpUserName = lpUserName;
|
|
pi.lpProfilePath = lpUserInfo->usri3_profile;
|
|
|
|
fReturn = LoadUserProfile (hToken, &pi);
|
|
|
|
if (fReturn) {
|
|
*hProfile = pi.hProfile;
|
|
}
|
|
|
|
NetApiBufferFree( lpUserInfo );
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(TokenInfo)
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, TokenInfo );
|
|
}
|
|
}
|
|
|
|
if (lpServerName) {
|
|
NetApiBufferFree( DomainControllerInfo );
|
|
}
|
|
|
|
return( fReturn );
|
|
}
|