Leaked source code of windows server 2003
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

/*++
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);
}