You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2319 lines
54 KiB
2319 lines
54 KiB
/*++
|
|
|
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Helper.cpp
|
|
|
|
Abstract:
|
|
|
|
Various funtion encapsulate HELP user account
|
|
validation, creating.
|
|
|
|
Author:
|
|
|
|
HueiWang 2/17/2000
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
|
|
#include <windows.h>
|
|
#include <ntsecapi.h>
|
|
#include <lmcons.h>
|
|
#include <lm.h>
|
|
#include <sspi.h>
|
|
#include <wtsapi32.h>
|
|
#include <winbase.h>
|
|
#include <security.h>
|
|
#include <Sddl.h>
|
|
|
|
#define STRSAFE_NO_DEPRECATE
|
|
#include <strsafe.h>
|
|
|
|
#include "Helper.h"
|
|
|
|
#if DBG
|
|
|
|
void
|
|
DebugPrintf(
|
|
IN LPCTSTR format, ...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
sprintf() like wrapper around OutputDebugString().
|
|
|
|
Parameters:
|
|
|
|
hConsole : Handle to console.
|
|
format : format string.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
Note:
|
|
|
|
To be replace by generic tracing code.
|
|
|
|
++*/
|
|
{
|
|
TCHAR buf[8096]; // max. error text
|
|
DWORD dump;
|
|
HRESULT hr;
|
|
va_list marker;
|
|
va_start(marker, format);
|
|
|
|
SYSTEMTIME sysTime;
|
|
GetSystemTime(&sysTime);
|
|
|
|
try {
|
|
hr = StringCchPrintf(
|
|
buf,
|
|
sizeof(buf)/sizeof(buf[0]),
|
|
_TEXT(" %d [%d:%d:%d:%d:%d.%d] : "),
|
|
GetCurrentThreadId(),
|
|
sysTime.wMonth,
|
|
sysTime.wDay,
|
|
sysTime.wHour,
|
|
sysTime.wMinute,
|
|
sysTime.wSecond,
|
|
sysTime.wMilliseconds
|
|
);
|
|
|
|
if( S_OK == hr )
|
|
{
|
|
hr = StringCchVPrintf(
|
|
buf + lstrlen(buf),
|
|
sizeof(buf)/sizeof(buf[0]) - lstrlen(buf),
|
|
format,
|
|
marker
|
|
);
|
|
}
|
|
|
|
if( S_OK == hr || STRSAFE_E_INSUFFICIENT_BUFFER == hr )
|
|
{
|
|
// StringCchPrintf() and StringCchVPrintf() will
|
|
// truncate string and NULL terminate buffer so
|
|
// we are safe to dump out whatever we got.
|
|
OutputDebugString(buf);
|
|
}
|
|
else
|
|
{
|
|
OutputDebugString( _TEXT("Debug String Too Long...\n") );
|
|
}
|
|
}
|
|
catch(...) {
|
|
}
|
|
|
|
va_end(marker);
|
|
return;
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
UnixTimeToFileTime(
|
|
time_t t,
|
|
LPFILETIME pft
|
|
)
|
|
{
|
|
LARGE_INTEGER li;
|
|
|
|
li.QuadPart = Int32x32To64(t, 10000000) + 116444736000000000;
|
|
|
|
pft->dwHighDateTime = li.HighPart;
|
|
pft->dwLowDateTime = li.LowPart;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
|
|
BOOL IsUserAdmin(BOOL)
|
|
|
|
returns TRUE if user is an admin
|
|
FALSE if user is not an admin
|
|
------------------------------------------------------------------------*/
|
|
DWORD
|
|
IsUserAdmin(
|
|
BOOL* bMember
|
|
)
|
|
{
|
|
PSID psidAdministrators;
|
|
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
|
|
DWORD dwStatus=ERROR_SUCCESS;
|
|
|
|
do {
|
|
if(!AllocateAndInitializeSid(&siaNtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&psidAdministrators))
|
|
{
|
|
dwStatus=GetLastError();
|
|
continue;
|
|
}
|
|
|
|
// assume that we don't find the admin SID.
|
|
if(!CheckTokenMembership(NULL,
|
|
psidAdministrators,
|
|
bMember))
|
|
{
|
|
dwStatus=GetLastError();
|
|
}
|
|
|
|
FreeSid(psidAdministrators);
|
|
|
|
} while(FALSE);
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
DWORD
|
|
GetRandomNumber(
|
|
HCRYPTPROV hProv,
|
|
DWORD* pdwRandom
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
if( NULL == hProv )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
if( !CryptGenRandom(hProv, sizeof(*pdwRandom), (PBYTE)pdwRandom) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
MYASSERT( ERROR_SUCCESS == dwStatus );
|
|
return dwStatus;
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
|
|
DWORD
|
|
ShuffleCharArray(
|
|
IN HCRYPTPROV hProv,
|
|
IN int iSizeOfTheArray,
|
|
IN OUT TCHAR *lptsTheArray
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Random shuffle content of a char. array.
|
|
|
|
Parameters:
|
|
|
|
iSizeOfTheArray : Size of array.
|
|
lptsTheArray : On input, the array to be randomly shuffer,
|
|
on output, the shuffled array.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
Note:
|
|
|
|
Code Modified from winsta\server\wstrpc.c
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
int iTotal;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
if( NULL == hProv )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
iTotal = iSizeOfTheArray / sizeof(TCHAR);
|
|
for (i = 0; i < iTotal && ERROR_SUCCESS == dwStatus; i++)
|
|
{
|
|
DWORD RandomNum;
|
|
TCHAR c;
|
|
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
|
|
if( ERROR_SUCCESS == dwStatus )
|
|
{
|
|
c = lptsTheArray[i];
|
|
lptsTheArray[i] = lptsTheArray[RandomNum % iTotal];
|
|
lptsTheArray[RandomNum % iTotal] = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
|
|
DWORD
|
|
GenerateRandomBytes(
|
|
IN DWORD dwSize,
|
|
IN OUT LPBYTE pbBuffer
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Generate fill buffer with random bytes.
|
|
|
|
Parameters:
|
|
|
|
dwSize : Size of buffer pbBuffer point to.
|
|
pbBuffer : Pointer to buffer to hold the random bytes.
|
|
|
|
Returns:
|
|
|
|
TRUE/FALSE
|
|
|
|
--*/
|
|
{
|
|
HCRYPTPROV hProv = NULL;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Create a Crypto Provider to generate random number
|
|
//
|
|
if( !CryptAcquireContext(
|
|
&hProv,
|
|
NULL,
|
|
NULL,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT
|
|
) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( !CryptGenRandom(hProv, dwSize, pbBuffer) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( NULL != hProv )
|
|
{
|
|
CryptReleaseContext( hProv, 0 );
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
DWORD
|
|
GenerateRandomString(
|
|
IN DWORD dwSizeRandomSeed,
|
|
IN OUT LPTSTR* pszRandomString
|
|
)
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
PBYTE lpBuffer = NULL;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
BOOL bSuccess;
|
|
DWORD cbConvertString = 0;
|
|
|
|
if( 0 == dwSizeRandomSeed || NULL == pszRandomString )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
MYASSERT(FALSE);
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
*pszRandomString = NULL;
|
|
|
|
lpBuffer = (PBYTE)LocalAlloc( LPTR, dwSizeRandomSeed );
|
|
if( NULL == lpBuffer )
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
dwStatus = GenerateRandomBytes( dwSizeRandomSeed, lpBuffer );
|
|
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
// Convert to string
|
|
bSuccess = CryptBinaryToString(
|
|
lpBuffer,
|
|
dwSizeRandomSeed,
|
|
CRYPT_STRING_BASE64,
|
|
0,
|
|
&cbConvertString
|
|
);
|
|
if( FALSE == bSuccess )
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
*pszRandomString = (LPTSTR)LocalAlloc( LPTR, (cbConvertString+1)*sizeof(TCHAR) );
|
|
if( NULL == *pszRandomString )
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
bSuccess = CryptBinaryToString(
|
|
lpBuffer,
|
|
dwSizeRandomSeed,
|
|
CRYPT_STRING_BASE64,
|
|
*pszRandomString,
|
|
&cbConvertString
|
|
);
|
|
if( FALSE == bSuccess )
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
if( (*pszRandomString)[cbConvertString - 1] == '\n' &&
|
|
(*pszRandomString)[cbConvertString - 2] == '\r' )
|
|
{
|
|
(*pszRandomString)[cbConvertString - 2] = 0;
|
|
}
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
if( NULL != *pszRandomString )
|
|
{
|
|
LocalFree(*pszRandomString);
|
|
}
|
|
}
|
|
|
|
if( NULL != lpBuffer )
|
|
{
|
|
LocalFree(lpBuffer);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
DWORD
|
|
CreatePassword(
|
|
OUT TCHAR *pszPassword,
|
|
IN DWORD nLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to randomly create a password.
|
|
|
|
Parameters:
|
|
|
|
pszPassword : Pointer to buffer to received a randomly generated
|
|
password, buffer must be at least
|
|
MAX_HELPACCOUNT_PASSWORD+1 characters.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
Note:
|
|
|
|
Code copied from winsta\server\wstrpc.c
|
|
|
|
--*/
|
|
{
|
|
HCRYPTPROV hProv = NULL;
|
|
int iTotal = 0;
|
|
DWORD RandomNum = 0;
|
|
int i;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
|
|
TCHAR six2pr[64] =
|
|
{
|
|
_T('A'), _T('B'), _T('C'), _T('D'), _T('E'), _T('F'), _T('G'),
|
|
_T('H'), _T('I'), _T('J'), _T('K'), _T('L'), _T('M'), _T('N'),
|
|
_T('O'), _T('P'), _T('Q'), _T('R'), _T('S'), _T('T'), _T('U'),
|
|
_T('V'), _T('W'), _T('X'), _T('Y'), _T('Z'), _T('a'), _T('b'),
|
|
_T('c'), _T('d'), _T('e'), _T('f'), _T('g'), _T('h'), _T('i'),
|
|
_T('j'), _T('k'), _T('l'), _T('m'), _T('n'), _T('o'), _T('p'),
|
|
_T('q'), _T('r'), _T('s'), _T('t'), _T('u'), _T('v'), _T('w'),
|
|
_T('x'), _T('y'), _T('z'), _T('0'), _T('1'), _T('2'), _T('3'),
|
|
_T('4'), _T('5'), _T('6'), _T('7'), _T('8'), _T('9'), _T('*'),
|
|
_T('_')
|
|
};
|
|
|
|
TCHAR something1[12] =
|
|
{
|
|
_T('!'), _T('@'), _T('#'), _T('$'), _T('^'), _T('&'), _T('*'),
|
|
_T('('), _T(')'), _T('-'), _T('+'), _T('=')
|
|
};
|
|
|
|
TCHAR something2[10] =
|
|
{
|
|
_T('0'), _T('1'), _T('2'), _T('3'), _T('4'), _T('5'), _T('6'),
|
|
_T('7'), _T('8'), _T('9')
|
|
};
|
|
|
|
TCHAR something3[26] =
|
|
{
|
|
_T('A'), _T('B'), _T('C'), _T('D'), _T('E'), _T('F'), _T('G'),
|
|
_T('H'), _T('I'), _T('J'), _T('K'), _T('L'), _T('M'), _T('N'),
|
|
_T('O'), _T('P'), _T('Q'), _T('R'), _T('S'), _T('T'), _T('U'),
|
|
_T('V'), _T('W'), _T('X'), _T('Y'), _T('Z')
|
|
};
|
|
|
|
TCHAR something4[26] =
|
|
{
|
|
_T('a'), _T('b'), _T('c'), _T('d'), _T('e'), _T('f'), _T('g'),
|
|
_T('h'), _T('i'), _T('j'), _T('k'), _T('l'), _T('m'), _T('n'),
|
|
_T('o'), _T('p'), _T('q'), _T('r'), _T('s'), _T('t'), _T('u'),
|
|
_T('v'), _T('w'), _T('x'), _T('y'), _T('z')
|
|
};
|
|
|
|
if( nLength < MIN_HELPACCOUNT_PASSWORD ) {
|
|
// This can't happen as function is called internally with
|
|
// buffer of MAX_HELPACCOUNT_PASSWORD so assert here.
|
|
dwStatus = ERROR_INSUFFICIENT_BUFFER;
|
|
ASSERT( FALSE );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Create a Crypto Provider to generate random number
|
|
//
|
|
if( !CryptAcquireContext(
|
|
&hProv,
|
|
NULL,
|
|
NULL,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT
|
|
) )
|
|
{
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Shuffle around the six2pr[] array.
|
|
//
|
|
|
|
dwStatus = ShuffleCharArray(hProv, sizeof(six2pr), six2pr);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
//
|
|
// Assign each character of the password array.
|
|
//
|
|
|
|
iTotal = sizeof(six2pr) / sizeof(TCHAR);
|
|
for (i=0; i<nLength && ERROR_SUCCESS == dwStatus; i++)
|
|
{
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS == dwStatus )
|
|
{
|
|
pszPassword[i]=six2pr[RandomNum%iTotal];
|
|
}
|
|
}
|
|
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
MYASSERT(FALSE);
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
//
|
|
// In order to meet a possible policy set upon passwords, replace chars
|
|
// 2 through 5 with these:
|
|
//
|
|
// 1) something from !@#$%^&*()-+=
|
|
// 2) something from 1234567890
|
|
// 3) an uppercase letter
|
|
// 4) a lowercase letter
|
|
//
|
|
|
|
//
|
|
// Security: We need to randomize where we put special characters,
|
|
// randomindex[0] is where we going to put symbol in pszPassword
|
|
// randomindex[1] is where we going to put digit in pszPassword
|
|
// randomindex[2] is where we going to put uppercase letter in pszPassword
|
|
// randomindex[3] is where we going to put lowercase letter in pszPassword
|
|
DWORD randomindex[4];
|
|
int indexassigned = 0;
|
|
|
|
// randomly pick one characters in password to gtes char. from something1.
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
randomindex[0] = RandomNum % nLength;
|
|
indexassigned++;
|
|
|
|
while( ERROR_SUCCESS == dwStatus && indexassigned < sizeof(randomindex)/sizeof(randomindex[0]) )
|
|
{
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS == dwStatus )
|
|
{
|
|
RandomNum = RandomNum % nLength;
|
|
|
|
// make sure we don't re-use the index.
|
|
for( i=0; i < indexassigned && randomindex[i] != RandomNum; i++ );
|
|
|
|
// if index already assign for symbol, digit, or uppercase letter,
|
|
// loop again to try other index.
|
|
if( i >= indexassigned )
|
|
{
|
|
randomindex[indexassigned] = RandomNum;
|
|
indexassigned++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
dwStatus = ShuffleCharArray(hProv, sizeof(something1), (TCHAR*)&something1);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
dwStatus = ShuffleCharArray(hProv, sizeof(something2), (TCHAR*)&something2);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
dwStatus = ShuffleCharArray(hProv, sizeof(something3), (TCHAR*)&something3);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
dwStatus = ShuffleCharArray(hProv, sizeof(something4), (TCHAR*)&something4);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
iTotal = sizeof(something1) / sizeof(TCHAR);
|
|
pszPassword[randomindex[0]] = something1[RandomNum % iTotal];
|
|
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
iTotal = sizeof(something2) / sizeof(TCHAR);
|
|
pszPassword[randomindex[1]] = something2[RandomNum % iTotal];
|
|
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
iTotal = sizeof(something3) / sizeof(TCHAR);
|
|
pszPassword[randomindex[2]] = something3[RandomNum % iTotal];
|
|
|
|
dwStatus = GetRandomNumber(hProv, &RandomNum);
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
iTotal = sizeof(something4) / sizeof(TCHAR);
|
|
pszPassword[randomindex[3]] = something4[RandomNum % iTotal];
|
|
|
|
pszPassword[nLength] = _T('\0');
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( NULL != hProv )
|
|
{
|
|
CryptReleaseContext( hProv, 0 );
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
|
|
DWORD
|
|
RenameLocalAccount(
|
|
IN LPWSTR pszOrgName,
|
|
IN LPWSTR pszNewName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS err;
|
|
USER_INFO_0 UserInfo;
|
|
|
|
UserInfo.usri0_name = pszNewName;
|
|
err = NetUserSetInfo(
|
|
NULL,
|
|
pszOrgName,
|
|
0,
|
|
(LPBYTE) &UserInfo,
|
|
NULL
|
|
);
|
|
|
|
return err;
|
|
}
|
|
|
|
DWORD
|
|
UpdateLocalAccountFullnameAndDesc(
|
|
IN LPWSTR pszAccOrgName,
|
|
IN LPWSTR pszAccFullName,
|
|
IN LPWSTR pszAccDesc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update account full name and description.
|
|
|
|
Parameters:
|
|
|
|
pszAccName : Account name.
|
|
pszAccFullName : new account full name.
|
|
pszAccDesc : new account description.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pbServer = NULL;
|
|
BYTE *pBuffer;
|
|
NET_API_STATUS netErr = NERR_Success;
|
|
DWORD parm_err;
|
|
|
|
netErr = NetUserGetInfo(
|
|
NULL,
|
|
pszAccOrgName,
|
|
3,
|
|
&pBuffer
|
|
);
|
|
|
|
if( NERR_Success == netErr )
|
|
{
|
|
USER_INFO_3 *lpui3 = (USER_INFO_3 *)pBuffer;
|
|
|
|
lpui3->usri3_comment = pszAccDesc;
|
|
lpui3->usri3_full_name = pszAccFullName;
|
|
|
|
netErr = NetUserSetInfo(
|
|
NULL,
|
|
pszAccOrgName,
|
|
3,
|
|
(PBYTE)lpui3,
|
|
&parm_err
|
|
);
|
|
|
|
NetApiBufferFree(pBuffer);
|
|
}
|
|
|
|
return netErr;
|
|
}
|
|
|
|
DWORD
|
|
IsLocalAccountEnabled(
|
|
IN LPWSTR pszUserName,
|
|
IN BOOL* pEnabled
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if local account enabled
|
|
|
|
Parameters:
|
|
|
|
pszUserName : Name of user account.
|
|
pEnabled : Return TRUE is account is enabled, FALSE otherwise.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult;
|
|
NET_API_STATUS err;
|
|
LPBYTE pBuffer;
|
|
USER_INFO_1 *pUserInfo;
|
|
|
|
err = NetUserGetInfo(
|
|
NULL,
|
|
pszUserName,
|
|
1,
|
|
&pBuffer
|
|
);
|
|
|
|
if( NERR_Success == err )
|
|
{
|
|
pUserInfo = (USER_INFO_1 *)pBuffer;
|
|
|
|
if (pUserInfo != NULL)
|
|
{
|
|
if( pUserInfo->usri1_flags & UF_ACCOUNTDISABLE )
|
|
{
|
|
*pEnabled = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
NetApiBufferFree( pBuffer );
|
|
}
|
|
else if( NERR_UserNotFound == err )
|
|
{
|
|
*pEnabled = FALSE;
|
|
//err = NERR_Success;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
|
|
DWORD
|
|
EnableLocalAccount(
|
|
IN LPWSTR pszUserName,
|
|
IN BOOL bEnable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to enable/disable a local account.
|
|
|
|
Parameters:
|
|
|
|
pszUserName : Name of user account.
|
|
bEnable : TRUE if enabling account, FALSE if disabling account.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult;
|
|
NET_API_STATUS err;
|
|
LPBYTE pBuffer;
|
|
USER_INFO_1 *pUserInfo;
|
|
BOOL bChangeAccStatus = TRUE;
|
|
|
|
err = NetUserGetInfo(
|
|
NULL,
|
|
pszUserName,
|
|
1,
|
|
&pBuffer
|
|
);
|
|
|
|
if( NERR_Success == err )
|
|
{
|
|
pUserInfo = (USER_INFO_1 *)pBuffer;
|
|
|
|
if(pUserInfo != NULL)
|
|
{
|
|
|
|
if( TRUE == bEnable && pUserInfo->usri1_flags & UF_ACCOUNTDISABLE )
|
|
{
|
|
pUserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE;
|
|
}
|
|
else if( FALSE == bEnable && !(pUserInfo->usri1_flags & UF_ACCOUNTDISABLE) )
|
|
{
|
|
pUserInfo->usri1_flags |= UF_ACCOUNTDISABLE;
|
|
}
|
|
else
|
|
{
|
|
bChangeAccStatus = FALSE;
|
|
}
|
|
|
|
if( TRUE == bChangeAccStatus )
|
|
{
|
|
err = NetUserSetInfo(
|
|
NULL,
|
|
pszUserName,
|
|
1,
|
|
pBuffer,
|
|
&dwResult
|
|
);
|
|
}
|
|
}
|
|
|
|
NetApiBufferFree( pBuffer );
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
|
|
BOOL
|
|
IsPersonalOrProMachine()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if machine is PER or PRO sku.
|
|
|
|
Parameters:
|
|
|
|
None.
|
|
|
|
Return:
|
|
|
|
TRUE/FALSE
|
|
--*/
|
|
{
|
|
BOOL fRet;
|
|
DWORDLONG dwlConditionMask;
|
|
OSVERSIONINFOEX osVersionInfo;
|
|
|
|
RtlZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
osVersionInfo.wProductType = VER_NT_WORKSTATION;
|
|
|
|
dwlConditionMask = 0;
|
|
VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
|
|
|
|
fRet = VerifyVersionInfo(
|
|
&osVersionInfo,
|
|
VER_PRODUCT_TYPE,
|
|
dwlConditionMask
|
|
);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CreateLocalAccount(
|
|
IN LPWSTR pszUserName,
|
|
IN LPWSTR pszUserPwd,
|
|
IN LPWSTR pszFullName,
|
|
IN LPWSTR pszComment,
|
|
IN LPWSTR pszGroup,
|
|
IN LPWSTR pszScript,
|
|
OUT BOOL* pbAccountExist
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an user account on local machine.
|
|
|
|
Parameters:
|
|
|
|
pszUserName : Name of the user account.
|
|
pszUserPwd : User account password.
|
|
pszFullName : Account Full Name.
|
|
pszComment : Account comment.
|
|
pszGroup : Local group of the account.
|
|
pbAccountExist ; Return TRUE if account already exists, FALSE otherwise.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pbServer = NULL;
|
|
BYTE *pBuffer;
|
|
NET_API_STATUS netErr = NERR_Success;
|
|
DWORD parm_err;
|
|
DWORD dwStatus;
|
|
|
|
netErr = NetUserGetInfo(
|
|
NULL,
|
|
pszUserName,
|
|
3,
|
|
&pBuffer
|
|
);
|
|
|
|
if( NERR_Success == netErr )
|
|
{
|
|
//
|
|
// User account exists, if account is disabled,
|
|
// enable it and change password
|
|
//
|
|
USER_INFO_3 *lpui3 = (USER_INFO_3 *)pBuffer;
|
|
|
|
if( lpui3->usri3_flags & UF_ACCOUNTDISABLE ||
|
|
lpui3->usri3_flags & UF_LOCKOUT )
|
|
{
|
|
// enable the account
|
|
lpui3->usri3_flags &= ~ ~UF_LOCKOUT;;
|
|
|
|
if( lpui3->usri3_flags & UF_ACCOUNTDISABLE )
|
|
{
|
|
// we only reset password if account is disabled.
|
|
lpui3->usri3_flags &= ~ UF_ACCOUNTDISABLE;
|
|
}
|
|
|
|
//lpui3->usri3_password = pszUserPwd;
|
|
|
|
// reset password if account is disabled.
|
|
lpui3->usri3_name = pszUserName;
|
|
lpui3->usri3_comment = pszComment;
|
|
lpui3->usri3_full_name = pszFullName;
|
|
//lpui3->usri3_primary_group_id = dwGroupId;
|
|
|
|
netErr = NetUserSetInfo(
|
|
NULL,
|
|
pszUserName,
|
|
3,
|
|
(PBYTE)lpui3,
|
|
&parm_err
|
|
);
|
|
}
|
|
|
|
*pbAccountExist = TRUE;
|
|
NetApiBufferFree(pBuffer);
|
|
}
|
|
else if( NERR_UserNotFound == netErr )
|
|
{
|
|
//
|
|
// Account does not exist, create and set it to our group
|
|
//
|
|
USER_INFO_1 UserInfo;
|
|
|
|
memset(&UserInfo, 0, sizeof(USER_INFO_1));
|
|
|
|
UserInfo.usri1_name = pszUserName;
|
|
UserInfo.usri1_password = pszUserPwd;
|
|
UserInfo.usri1_priv = USER_PRIV_USER; // see USER_INFO_1 for detail
|
|
UserInfo.usri1_comment = pszComment;
|
|
UserInfo.usri1_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
|
|
|
|
netErr = NetUserAdd(
|
|
NULL,
|
|
1,
|
|
(PBYTE)&UserInfo,
|
|
&parm_err
|
|
);
|
|
|
|
*pbAccountExist = FALSE;
|
|
}
|
|
|
|
return netErr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
ChangeLocalAccountPassword(
|
|
IN LPWSTR pszAccName,
|
|
IN LPWSTR pszOldPwd,
|
|
IN LPWSTR pszNewPwd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change password of a local account.
|
|
|
|
Parameters:
|
|
|
|
pszAccName : Name of user account.
|
|
pszOldPwd : Old password.
|
|
pszNewPwd : New password.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
Notes:
|
|
|
|
User NetUserChangePassword(), must have priviledge
|
|
|
|
--*/
|
|
{
|
|
USER_INFO_1003 sUserInfo3;
|
|
NET_API_STATUS netErr;
|
|
|
|
|
|
UNREFERENCED_PARAMETER( pszOldPwd );
|
|
|
|
sUserInfo3.usri1003_password = pszNewPwd;
|
|
netErr = NetUserSetInfo(
|
|
NULL,
|
|
pszAccName,
|
|
1003,
|
|
(BYTE *) &sUserInfo3,
|
|
0
|
|
);
|
|
|
|
return netErr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
RetrieveKeyFromLSA(
|
|
IN PWCHAR pwszKeyName,
|
|
OUT PBYTE * ppbKey,
|
|
OUT DWORD * pcbKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve private data previously stored with StoreKeyWithLSA().
|
|
|
|
Parameters:
|
|
|
|
pwszKeyName : Name of the key.
|
|
ppbKey : Pointer to PBYTE to receive binary data.
|
|
pcbKey : Size of binary data.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS
|
|
ERROR_INVALID_PARAMETER.
|
|
ERROR_FILE_NOT_FOUND
|
|
LSA return code
|
|
|
|
Note:
|
|
|
|
Memory is allocated using LocalAlloc()
|
|
|
|
--*/
|
|
{
|
|
LSA_HANDLE PolicyHandle;
|
|
UNICODE_STRING SecretKeyName;
|
|
UNICODE_STRING *pSecretData;
|
|
DWORD Status;
|
|
|
|
if( ( NULL == pwszKeyName ) || ( NULL == ppbKey ) || ( NULL == pcbKey ) )
|
|
{
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// setup the UNICODE_STRINGs for the call.
|
|
//
|
|
InitLsaString(
|
|
&SecretKeyName,
|
|
pwszKeyName
|
|
);
|
|
|
|
Status = OpenPolicy(
|
|
NULL,
|
|
POLICY_GET_PRIVATE_INFORMATION,
|
|
&PolicyHandle
|
|
);
|
|
|
|
if( Status != ERROR_SUCCESS )
|
|
{
|
|
return LsaNtStatusToWinError(Status);
|
|
}
|
|
|
|
Status = LsaRetrievePrivateData(
|
|
PolicyHandle,
|
|
&SecretKeyName,
|
|
&pSecretData
|
|
);
|
|
|
|
LsaClose( PolicyHandle );
|
|
|
|
if( Status != ERROR_SUCCESS )
|
|
{
|
|
return LsaNtStatusToWinError(Status);
|
|
}
|
|
|
|
if(pSecretData->Length)
|
|
{
|
|
*ppbKey = ( LPBYTE )LocalAlloc( LPTR, pSecretData->Length );
|
|
|
|
if( *ppbKey )
|
|
{
|
|
*pcbKey = pSecretData->Length;
|
|
CopyMemory( *ppbKey, pSecretData->Buffer, pSecretData->Length );
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_FILE_NOT_FOUND;
|
|
*pcbKey = 0;
|
|
*ppbKey = NULL;
|
|
}
|
|
|
|
ZeroMemory( pSecretData->Buffer, pSecretData->Length );
|
|
LsaFreeMemory( pSecretData );
|
|
|
|
return Status;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
StoreKeyWithLSA(
|
|
IN PWCHAR pwszKeyName,
|
|
IN BYTE * pbKey,
|
|
IN DWORD cbKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save private data to LSA.
|
|
|
|
Parameters:
|
|
|
|
pwszKeyName : Name of the key this data going to be stored under.
|
|
pbKey : Binary data to be saved, pass NULL to delete previously stored
|
|
LSA key and data.
|
|
cbKey : Size of binary data.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS
|
|
ERROR_INVALID_PARAMETER.
|
|
LSA return code
|
|
|
|
--*/
|
|
{
|
|
LSA_HANDLE PolicyHandle;
|
|
UNICODE_STRING SecretKeyName;
|
|
UNICODE_STRING SecretData;
|
|
DWORD Status;
|
|
|
|
if( ( NULL == pwszKeyName ) )
|
|
{
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// setup the UNICODE_STRINGs for the call.
|
|
//
|
|
|
|
InitLsaString(
|
|
&SecretKeyName,
|
|
pwszKeyName
|
|
);
|
|
|
|
SecretData.Buffer = ( LPWSTR )pbKey;
|
|
SecretData.Length = ( USHORT )cbKey;
|
|
SecretData.MaximumLength = ( USHORT )cbKey;
|
|
|
|
Status = OpenPolicy(
|
|
NULL,
|
|
POLICY_CREATE_SECRET,
|
|
&PolicyHandle
|
|
);
|
|
|
|
if( Status != ERROR_SUCCESS )
|
|
{
|
|
return LsaNtStatusToWinError(Status);
|
|
}
|
|
|
|
// Based on pbKey, either to store the data or delete the key.
|
|
Status = LsaStorePrivateData(
|
|
PolicyHandle,
|
|
&SecretKeyName,
|
|
(pbKey != NULL) ? &SecretData : NULL
|
|
);
|
|
|
|
LsaClose(PolicyHandle);
|
|
|
|
return LsaNtStatusToWinError(Status);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
OpenPolicy(
|
|
IN LPWSTR ServerName,
|
|
IN DWORD DesiredAccess,
|
|
OUT PLSA_HANDLE PolicyHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create/return a LSA policy handle.
|
|
|
|
Parameters:
|
|
|
|
ServerName : Name of server, refer to LsaOpenPolicy().
|
|
DesiredAccess : Desired access level, refer to LsaOpenPolicy().
|
|
PolicyHandle : Return PLSA_HANDLE.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or LSA error code
|
|
|
|
--*/
|
|
{
|
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_UNICODE_STRING ServerString;
|
|
PLSA_UNICODE_STRING Server;
|
|
|
|
//
|
|
// Always initialize the object attributes to all zeroes.
|
|
//
|
|
|
|
ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
|
|
|
|
if( NULL != ServerName )
|
|
{
|
|
//
|
|
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in
|
|
//
|
|
|
|
InitLsaString( &ServerString, ServerName );
|
|
Server = &ServerString;
|
|
|
|
}
|
|
else
|
|
{
|
|
Server = NULL;
|
|
}
|
|
|
|
//
|
|
// Attempt to open the policy.
|
|
//
|
|
|
|
return( LsaOpenPolicy(
|
|
Server,
|
|
&ObjectAttributes,
|
|
DesiredAccess,
|
|
PolicyHandle ) );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
InitLsaString(
|
|
IN OUT PLSA_UNICODE_STRING LsaString,
|
|
IN LPWSTR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize LSA unicode string.
|
|
|
|
Parameters:
|
|
|
|
LsaString : Pointer to LSA_UNICODE_STRING to be initialized.
|
|
String : String to initialize LsaString.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
Note:
|
|
|
|
Refer to LSA_UNICODE_STRING
|
|
|
|
--*/
|
|
{
|
|
DWORD StringLength;
|
|
|
|
if( NULL == String )
|
|
{
|
|
LsaString->Buffer = NULL;
|
|
LsaString->Length = 0;
|
|
LsaString->MaximumLength = 0;
|
|
return;
|
|
}
|
|
|
|
StringLength = lstrlenW( String );
|
|
LsaString->Buffer = String;
|
|
LsaString->Length = ( USHORT ) StringLength * sizeof( WCHAR );
|
|
LsaString->MaximumLength=( USHORT )( StringLength + 1 ) * sizeof( WCHAR );
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
BOOL
|
|
ValidatePassword(
|
|
IN LPWSTR pszUserName,
|
|
IN LPWSTR pszDomain,
|
|
IN LPWSTR pszPassword
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate user account password.
|
|
|
|
Parameters:
|
|
|
|
pszUserName : Name of user account.
|
|
pszDomain : Domain name.
|
|
pszPassword : Password to be verified.
|
|
|
|
Returns:
|
|
|
|
TRUE or FALSE.
|
|
|
|
|
|
Note:
|
|
|
|
To debug this code, you will need to run process as service in order
|
|
for it to verify password. Refer to MSDN on LogonUser
|
|
|
|
--*/
|
|
{
|
|
HANDLE hToken;
|
|
BOOL bSuccess;
|
|
|
|
|
|
//
|
|
// To debug this code, you will need to run process as service in order
|
|
// for it to verify password. Refer to MSDN on LogonUser
|
|
//
|
|
|
|
bSuccess = LogonUser(
|
|
pszUserName,
|
|
pszDomain, //_TEXT("."), //pszDomain,
|
|
pszPassword,
|
|
LOGON32_LOGON_NETWORK_CLEARTEXT,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&hToken
|
|
);
|
|
|
|
if( TRUE == bSuccess )
|
|
{
|
|
CloseHandle( hToken );
|
|
}
|
|
else
|
|
{
|
|
DWORD dwStatus = GetLastError();
|
|
|
|
DebugPrintf(
|
|
_TEXT("ValidatePassword() failed with %d\n"),
|
|
dwStatus
|
|
);
|
|
|
|
SetLastError(dwStatus);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
BOOL
|
|
GetTextualSid(
|
|
IN PSID pSid, // binary Sid
|
|
IN OUT LPTSTR TextualSid, // buffer for Textual representation of Sid
|
|
IN OUT LPDWORD lpdwBufferLen // required/provided TextualSid buffersize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Conver a SID to string representation, code from MSDN
|
|
|
|
Parameters:
|
|
|
|
pSid : Pointer to SID to be converted to string.
|
|
TextualSid : On input, pointer to buffer to received converted string, on output,
|
|
converted SID in string form.
|
|
lpdwBufferLen : On input, size of the buffer, on output, length of converted string
|
|
or required buffer size in char.
|
|
|
|
Returns:
|
|
|
|
TRUE/FALSE, use GetLastError() to retrieve detail error code.
|
|
|
|
--*/
|
|
{
|
|
PSID_IDENTIFIER_AUTHORITY psia;
|
|
DWORD dwSubAuthorities;
|
|
DWORD dwSidRev=SID_REVISION;
|
|
DWORD dwCounter;
|
|
DWORD dwSidSize;
|
|
|
|
// Validate the binary SID.
|
|
|
|
if(!IsValidSid(pSid))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the identifier authority value from the SID.
|
|
|
|
psia = GetSidIdentifierAuthority(pSid);
|
|
|
|
// Get the number of subauthorities in the SID.
|
|
|
|
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
|
|
|
|
// Compute the buffer length.
|
|
// S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
|
|
|
|
dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
|
|
|
|
// Check input buffer length.
|
|
// If too small, indicate the proper size and set last error.
|
|
|
|
if (*lpdwBufferLen < dwSidSize)
|
|
{
|
|
*lpdwBufferLen = dwSidSize;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
// Add 'S' prefix and revision number to the string.
|
|
|
|
dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
|
|
|
|
// Add SID identifier authority to the string.
|
|
|
|
if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
|
|
{
|
|
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
|
|
TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
|
|
(USHORT)psia->Value[0],
|
|
(USHORT)psia->Value[1],
|
|
(USHORT)psia->Value[2],
|
|
(USHORT)psia->Value[3],
|
|
(USHORT)psia->Value[4],
|
|
(USHORT)psia->Value[5]);
|
|
}
|
|
else
|
|
{
|
|
dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
|
|
TEXT("%lu"),
|
|
(ULONG)(psia->Value[5] ) +
|
|
(ULONG)(psia->Value[4] << 8) +
|
|
(ULONG)(psia->Value[3] << 16) +
|
|
(ULONG)(psia->Value[2] << 24) );
|
|
}
|
|
|
|
// Add SID subauthorities to the string.
|
|
//
|
|
for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
|
|
{
|
|
dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
|
|
*GetSidSubAuthority(pSid, dwCounter) );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
long
|
|
GetUserTSLogonIdEx(
|
|
HANDLE hToken
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
BOOL Result;
|
|
LONG SessionId = -1;
|
|
ULONG ReturnLength;
|
|
//
|
|
// Use the _HYDRA_ extension to GetTokenInformation to
|
|
// return the SessionId from the token.
|
|
//
|
|
|
|
Result = GetTokenInformation(
|
|
hToken,
|
|
TokenSessionId,
|
|
&SessionId,
|
|
sizeof(SessionId),
|
|
&ReturnLength
|
|
);
|
|
|
|
if( !Result ) {
|
|
|
|
DWORD dwStatus = GetLastError();
|
|
SessionId = -1;
|
|
|
|
}
|
|
|
|
return SessionId;
|
|
}
|
|
|
|
|
|
|
|
long
|
|
GetUserTSLogonId()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return client TS Session ID.
|
|
|
|
Parameters:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
Client's TS session ID or 0 if not on TS.
|
|
|
|
Note:
|
|
|
|
Must have impersonate user first.
|
|
|
|
--*/
|
|
{
|
|
LONG lSessionId = -1;
|
|
HANDLE hToken;
|
|
BOOL bSuccess;
|
|
|
|
bSuccess = OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken
|
|
);
|
|
|
|
if( TRUE == bSuccess )
|
|
{
|
|
lSessionId = GetUserTSLogonIdEx(hToken);
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return lSessionId;
|
|
}
|
|
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
DWORD
|
|
RegEnumSubKeys(
|
|
IN HKEY hKey,
|
|
IN LPCTSTR pszSubKey,
|
|
IN RegEnumKeyCallback pFunc,
|
|
IN HANDLE userData
|
|
)
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus;
|
|
HKEY hSubKey = NULL;
|
|
int index;
|
|
|
|
LONG dwNumSubKeys;
|
|
DWORD dwMaxSubKeyLength;
|
|
DWORD dwSubKeyLength;
|
|
LPTSTR pszSubKeyName = NULL;
|
|
|
|
DWORD dwMaxValueNameLen;
|
|
LPTSTR pszValueName = NULL;
|
|
DWORD dwValueNameLength;
|
|
|
|
if( NULL == hKey )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
return dwStatus;
|
|
}
|
|
|
|
dwStatus = RegOpenKeyEx(
|
|
hKey,
|
|
pszSubKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hSubKey
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
// key does not exist
|
|
return dwStatus;
|
|
}
|
|
|
|
//
|
|
// Query number of subkeys
|
|
//
|
|
dwStatus = RegQueryInfoKey(
|
|
hSubKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
(DWORD *)&dwNumSubKeys,
|
|
&dwMaxSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxValueNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
dwMaxValueNameLen++;
|
|
pszValueName = (LPTSTR)LocalAlloc(
|
|
LPTR,
|
|
dwMaxValueNameLen * sizeof(TCHAR)
|
|
);
|
|
if(pszValueName == NULL)
|
|
{
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(dwNumSubKeys > 0)
|
|
{
|
|
// allocate buffer for subkeys.
|
|
dwMaxSubKeyLength++;
|
|
pszSubKeyName = (LPTSTR)LocalAlloc(
|
|
LPTR,
|
|
dwMaxSubKeyLength * sizeof(TCHAR)
|
|
);
|
|
if(pszSubKeyName == NULL)
|
|
{
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
for(;dwStatus == ERROR_SUCCESS && dwNumSubKeys >= 0;)
|
|
{
|
|
// delete this subkey.
|
|
dwSubKeyLength = dwMaxSubKeyLength;
|
|
memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
|
|
|
|
// retrieve subkey name
|
|
dwStatus = RegEnumKeyEx(
|
|
hSubKey,
|
|
(DWORD)--dwNumSubKeys,
|
|
pszSubKeyName,
|
|
&dwSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
dwStatus = pFunc(
|
|
hSubKey,
|
|
pszSubKeyName,
|
|
userData
|
|
);
|
|
}
|
|
}
|
|
|
|
if( ERROR_NO_MORE_ITEMS == dwStatus )
|
|
{
|
|
dwStatus = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
// close the key before trying to delete it.
|
|
if(hSubKey != NULL)
|
|
{
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
if(pszValueName != NULL)
|
|
{
|
|
LocalFree(pszValueName);
|
|
}
|
|
|
|
if(pszSubKeyName != NULL)
|
|
{
|
|
LocalFree(pszSubKeyName);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RegDelKey(
|
|
IN HKEY hRegKey,
|
|
IN LPCTSTR pszSubKey
|
|
)
|
|
/*++
|
|
|
|
Abstract:
|
|
|
|
Recursively delete entire registry key.
|
|
|
|
Parameter:
|
|
|
|
hKey : Handle to a curently open key.
|
|
pszSubKey : Pointer to NULL terminated string containing the key to be deleted.
|
|
|
|
Returns:
|
|
|
|
Error code from RegOpenKeyEx(), RegQueryInfoKey(),
|
|
RegEnumKeyEx().
|
|
|
|
++*/
|
|
{
|
|
DWORD dwStatus;
|
|
HKEY hSubKey = NULL;
|
|
int index;
|
|
|
|
DWORD dwNumSubKeys;
|
|
DWORD dwMaxSubKeyLength;
|
|
DWORD dwSubKeyLength;
|
|
LPTSTR pszSubKeyName = NULL;
|
|
|
|
DWORD dwMaxValueNameLen;
|
|
LPTSTR pszValueName = NULL;
|
|
DWORD dwValueNameLength;
|
|
|
|
if( NULL == hRegKey )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
return dwStatus;
|
|
}
|
|
|
|
dwStatus = RegOpenKeyEx(
|
|
hRegKey,
|
|
pszSubKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hSubKey
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
// key does not exist
|
|
return dwStatus;
|
|
}
|
|
|
|
//
|
|
// Query number of subkeys
|
|
//
|
|
dwStatus = RegQueryInfoKey(
|
|
hSubKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwNumSubKeys,
|
|
&dwMaxSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxValueNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
dwMaxValueNameLen++;
|
|
pszValueName = (LPTSTR)LocalAlloc(
|
|
LPTR,
|
|
dwMaxValueNameLen * sizeof(TCHAR)
|
|
);
|
|
if(pszValueName == NULL)
|
|
{
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(dwNumSubKeys > 0)
|
|
{
|
|
// allocate buffer for subkeys.
|
|
|
|
dwMaxSubKeyLength++;
|
|
pszSubKeyName = (LPTSTR)LocalAlloc(
|
|
LPTR,
|
|
dwMaxSubKeyLength * sizeof(TCHAR)
|
|
);
|
|
if(pszSubKeyName == NULL)
|
|
{
|
|
dwStatus = ERROR_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
//for(index = 0; index < dwNumSubKeys; index++)
|
|
for(;dwStatus == ERROR_SUCCESS;)
|
|
{
|
|
// delete this subkey.
|
|
dwSubKeyLength = dwMaxSubKeyLength;
|
|
memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
|
|
|
|
// retrieve subkey name
|
|
dwStatus = RegEnumKeyEx(
|
|
hSubKey,
|
|
(DWORD)0,
|
|
pszSubKeyName,
|
|
&dwSubKeyLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
dwStatus = RegDelKey( hSubKey, pszSubKeyName );
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
for(dwStatus = ERROR_SUCCESS; pszValueName != NULL && dwStatus == ERROR_SUCCESS;)
|
|
{
|
|
dwValueNameLength = dwMaxValueNameLen;
|
|
memset(pszValueName, 0, dwMaxValueNameLen * sizeof(TCHAR));
|
|
|
|
dwStatus = RegEnumValue(
|
|
hSubKey,
|
|
0,
|
|
pszValueName,
|
|
&dwValueNameLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
RegDeleteValue(hSubKey, pszValueName);
|
|
}
|
|
}
|
|
|
|
// close the key before trying to delete it.
|
|
if(hSubKey != NULL)
|
|
{
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
// try to delete this key, will fail if any of the subkey
|
|
// failed to delete in loop
|
|
dwStatus = RegDeleteKey(
|
|
hRegKey,
|
|
pszSubKey
|
|
);
|
|
|
|
|
|
|
|
if(pszValueName != NULL)
|
|
{
|
|
LocalFree(pszValueName);
|
|
}
|
|
|
|
if(pszSubKeyName != NULL)
|
|
{
|
|
LocalFree(pszSubKeyName);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
DWORD
|
|
GetUserSid(
|
|
OUT PBYTE* ppbSid,
|
|
OUT DWORD* pcbSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve user's SID , must impersonate client first.
|
|
|
|
Parameters:
|
|
|
|
ppbSid : Pointer to PBYTE to receive user's SID.
|
|
pcbSid : Pointer to DWORD to receive size of SID.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
Note:
|
|
|
|
Must have call ImpersonateClient(), funtion is NT specific,
|
|
Win9X will return internal error.
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
HANDLE hToken = NULL;
|
|
DWORD dwSize = 0;
|
|
TOKEN_USER* pToken = NULL;
|
|
|
|
*ppbSid = NULL;
|
|
*pcbSid = 0;
|
|
|
|
//
|
|
// Open current process token
|
|
//
|
|
bSuccess = OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken
|
|
);
|
|
|
|
if( TRUE == bSuccess )
|
|
{
|
|
//
|
|
// get user's token.
|
|
//
|
|
GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&dwSize
|
|
);
|
|
|
|
pToken = (TOKEN_USER *)LocalAlloc( LPTR, dwSize );
|
|
if( NULL != pToken )
|
|
{
|
|
bSuccess = GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
(LPVOID) pToken,
|
|
dwSize,
|
|
&dwSize
|
|
);
|
|
|
|
if( TRUE == bSuccess )
|
|
{
|
|
//
|
|
// GetLengthSid() return size of buffer require,
|
|
// must call IsValidSid() first
|
|
//
|
|
bSuccess = IsValidSid( pToken->User.Sid );
|
|
if( TRUE == bSuccess )
|
|
{
|
|
*pcbSid = GetLengthSid( (PBYTE)pToken->User.Sid );
|
|
*ppbSid = (PBYTE)LocalAlloc(LPTR, *pcbSid);
|
|
if( NULL != *ppbSid )
|
|
{
|
|
bSuccess = CopySid(
|
|
*pcbSid,
|
|
*ppbSid,
|
|
pToken->User.Sid
|
|
);
|
|
}
|
|
else // fail in LocalAlloc()
|
|
{
|
|
bSuccess = FALSE;
|
|
}
|
|
} // IsValidSid()
|
|
} // GetTokenInformation()
|
|
}
|
|
else // LocalAlloc() fail
|
|
{
|
|
bSuccess = FALSE;
|
|
}
|
|
}
|
|
|
|
if( TRUE != bSuccess )
|
|
{
|
|
dwStatus = GetLastError();
|
|
|
|
if( NULL != *ppbSid )
|
|
{
|
|
LocalFree(*ppbSid);
|
|
*ppbSid = NULL;
|
|
*pcbSid = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free resources...
|
|
//
|
|
if( NULL != pToken )
|
|
{
|
|
LocalFree(pToken);
|
|
}
|
|
|
|
if( NULL != hToken )
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
HRESULT
|
|
GetUserSidString(
|
|
OUT CComBSTR& bstrSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve user's SID in textual form, must impersonate client first.
|
|
|
|
Parameters:
|
|
|
|
bstrSID : Return users' SID in textual form.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS or error code.
|
|
|
|
Note:
|
|
|
|
Must have call ImpersonateClient().
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus;
|
|
PBYTE pbSid = NULL;
|
|
DWORD cbSid = 0;
|
|
BOOL bSuccess = TRUE;
|
|
LPTSTR pszTextualSid = NULL;
|
|
DWORD dwTextualSid = 0;
|
|
|
|
dwStatus = GetUserSid( &pbSid, &cbSid );
|
|
if( ERROR_SUCCESS == dwStatus )
|
|
{
|
|
bSuccess = GetTextualSid(
|
|
pbSid,
|
|
NULL,
|
|
&dwTextualSid
|
|
);
|
|
|
|
if( FALSE == bSuccess && ERROR_INSUFFICIENT_BUFFER == GetLastError() )
|
|
{
|
|
pszTextualSid = (LPTSTR)LocalAlloc(
|
|
LPTR,
|
|
(dwTextualSid + 1) * sizeof(TCHAR)
|
|
);
|
|
|
|
if( NULL != pszTextualSid )
|
|
{
|
|
bSuccess = GetTextualSid(
|
|
pbSid,
|
|
pszTextualSid,
|
|
&dwTextualSid
|
|
);
|
|
|
|
if( TRUE == bSuccess )
|
|
{
|
|
bstrSid = pszTextualSid;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( FALSE == bSuccess )
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
}
|
|
|
|
if( NULL != pszTextualSid )
|
|
{
|
|
LocalFree(pszTextualSid);
|
|
}
|
|
|
|
if( NULL != pbSid )
|
|
{
|
|
LocalFree(pbSid);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(dwStatus);
|
|
}
|
|
|
|
HRESULT
|
|
ConvertSidToAccountName(
|
|
IN CComBSTR& SidString,
|
|
IN BSTR* ppszDomain,
|
|
IN BSTR* ppszUserAcc
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Convert a string SID to domain\account.
|
|
|
|
Parameters:
|
|
|
|
ownerSidString : SID in string form to be converted.
|
|
ppszDomain : Pointer to string pointer to receive domain name
|
|
UserAcc : Pointer to string pointer to receive user name
|
|
|
|
Returns:
|
|
|
|
S_OK or error code.
|
|
|
|
Note:
|
|
|
|
Routine uses LocalAlloc() to allocate memory for ppszDomain
|
|
and ppszUserAcc.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PSID pOwnerSid = NULL;
|
|
//LPTSTR pszAccName = NULL;
|
|
BSTR pszAccName = NULL;
|
|
DWORD cbAccName = 0;
|
|
//LPTSTR pszDomainName = NULL;
|
|
BSTR pszDomainName = NULL;
|
|
DWORD cbDomainName = 0;
|
|
SID_NAME_USE SidType;
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Convert string form SID to PSID
|
|
//
|
|
if( FALSE == ConvertStringSidToSid( (LPCTSTR)SidString, &pOwnerSid ) )
|
|
{
|
|
// this might also fail if system is in shutdown state.
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( NULL == ppszDomain || NULL == ppszUserAcc )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
MYASSERT( FALSE );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Lookup user account for this SID
|
|
//
|
|
bSuccess = LookupAccountSid(
|
|
NULL,
|
|
pOwnerSid,
|
|
pszAccName,
|
|
&cbAccName,
|
|
pszDomainName,
|
|
&cbDomainName,
|
|
&SidType
|
|
);
|
|
|
|
if( TRUE == bSuccess || ERROR_INSUFFICIENT_BUFFER == GetLastError() )
|
|
{
|
|
//pszAccName = (LPWSTR) LocalAlloc( LPTR, (cbAccName + 1) * sizeof(WCHAR) );
|
|
//pszDomainName = (LPWSTR) LocalAlloc( LPTR, (cbDomainName + 1)* sizeof(WCHAR) );
|
|
|
|
pszAccName = ::SysAllocStringLen( NULL, (cbAccName + 1) );
|
|
pszDomainName = ::SysAllocStringLen( NULL, (cbDomainName + 1) );
|
|
|
|
if( NULL != pszAccName && NULL != pszDomainName )
|
|
{
|
|
bSuccess = LookupAccountSid(
|
|
NULL,
|
|
pOwnerSid,
|
|
pszAccName,
|
|
&cbAccName,
|
|
pszDomainName,
|
|
&cbDomainName,
|
|
&SidType
|
|
);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bSuccess = FALSE;
|
|
}
|
|
}
|
|
|
|
if( FALSE == bSuccess )
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
*ppszDomain = pszDomainName;
|
|
*ppszUserAcc = pszAccName;
|
|
pszDomainName = NULL;
|
|
pszAccName = NULL;
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( NULL != pOwnerSid )
|
|
{
|
|
LocalFree( pOwnerSid );
|
|
}
|
|
|
|
if( NULL != pszAccName )
|
|
{
|
|
//LocalFree( pszAccName );
|
|
::SysFreeString( pszAccName );
|
|
}
|
|
|
|
if( NULL != pszDomainName )
|
|
{
|
|
// LocalFree( pszDomainName );
|
|
::SysFreeString( pszAccName );
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(dwStatus);
|
|
}
|