/*++ 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 #include #ifndef __WIN9XBUILD__ #include #include #include #include #include #include #include #include #endif #include "Helper.h" #ifndef __WIN9XBUILD__ #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; va_list marker; va_start(marker, format); SYSTEMTIME sysTime; GetSystemTime(&sysTime); try { memset( buf, 0, sizeof(buf) ); _sntprintf( 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 ); _vsntprintf( buf + lstrlen(buf), sizeof(buf)/sizeof(buf[0]) - lstrlen(buf), format, marker ); OutputDebugString(buf); } catch(...) { } va_end(marker); return; } #endif #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; } #ifndef __WIN9XBUILD__ /*---------------------------------------------------------------------------- Routine Description: This function checks to see whether the specified sid is enabled in the specified token. Arguments: TokenHandle - If present, this token is checked for the sid. If not present then the current effective token will be used. This must be an impersonation token. SidToCheck - The sid to check for presence in the token IsMember - If the sid is enabled in the token, contains TRUE otherwise false. Return Value: TRUE - The API completed successfully. It does not indicate that the sid is a member of the token. FALSE - The API failed. A more detailed status code can be retrieved via GetLastError() Note : Code modified from 5.0 \\rastaman\ntwin\src\base\advapi\security.c ----------------------------------------------------------------------------*/ BOOL TLSCheckTokenMembership( IN HANDLE TokenHandle OPTIONAL, IN PSID SidToCheck, OUT PBOOL IsMember ) { HANDLE ProcessToken = NULL; HANDLE EffectiveToken = NULL; DWORD Status = ERROR_SUCCESS; PISECURITY_DESCRIPTOR SecDesc = NULL; ULONG SecurityDescriptorSize; GENERIC_MAPPING GenericMapping = { STANDARD_RIGHTS_READ, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_ALL }; // // The size of the privilege set needs to contain the set itself plus // any privileges that may be used. The privileges that are used // are SeTakeOwnership and SeSecurity, plus one for good measure // BYTE PrivilegeSetBuffer[sizeof(PRIVILEGE_SET) + 3*sizeof(LUID_AND_ATTRIBUTES)]; PPRIVILEGE_SET PrivilegeSet = (PPRIVILEGE_SET) PrivilegeSetBuffer; ULONG PrivilegeSetLength = sizeof(PrivilegeSetBuffer); ACCESS_MASK AccessGranted = 0; BOOL AccessStatus = FALSE; PACL Dacl = NULL; #define MEMBER_ACCESS 1 *IsMember = FALSE; // // Get a handle to the token // if (TokenHandle != NULL) { EffectiveToken = TokenHandle; } else { if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, // don't open as self &EffectiveToken)) { // // if there is no thread token, try the process token // if((Status=GetLastError()) == ERROR_NO_TOKEN) { if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &ProcessToken)) { Status = GetLastError(); } // // If we have a process token, we need to convert it to an // impersonation token // if (Status == ERROR_SUCCESS) { BOOL Result; Result = DuplicateToken(ProcessToken, SecurityImpersonation, &EffectiveToken); CloseHandle(ProcessToken); if (!Result) { return(FALSE); } } } if (Status != ERROR_SUCCESS) { goto Cleanup; } } } // // Construct a security descriptor to pass to access check // // // The size is equal to the size of an SD + twice the length of the SID // (for owner and group) + size of the DACL = sizeof ACL + size of the // ACE, which is an ACE + length of // ths SID. // SecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR) + sizeof(ACCESS_ALLOWED_ACE) + sizeof(ACL) + 3 * GetLengthSid(SidToCheck); SecDesc = (PISECURITY_DESCRIPTOR) LocalAlloc(LMEM_ZEROINIT, SecurityDescriptorSize ); if (SecDesc == NULL) { Status = ERROR_OUTOFMEMORY; goto Cleanup; } Dacl = (PACL) (SecDesc + 1); InitializeSecurityDescriptor(SecDesc, SECURITY_DESCRIPTOR_REVISION); // // Fill in fields of security descriptor // SetSecurityDescriptorOwner(SecDesc, SidToCheck, FALSE); SetSecurityDescriptorGroup(SecDesc, SidToCheck, FALSE); if(!InitializeAcl( Dacl, SecurityDescriptorSize - sizeof(SECURITY_DESCRIPTOR), ACL_REVISION)) { Status=GetLastError(); goto Cleanup; } if(!AddAccessAllowedAce(Dacl, ACL_REVISION, MEMBER_ACCESS, SidToCheck)) { Status=GetLastError(); goto Cleanup; } if(!SetSecurityDescriptorDacl(SecDesc, TRUE, Dacl, FALSE)) { Status=GetLastError(); goto Cleanup; } if(!AccessCheck(SecDesc, EffectiveToken, MEMBER_ACCESS, &GenericMapping, PrivilegeSet, &PrivilegeSetLength, &AccessGranted, &AccessStatus)) { Status=GetLastError(); goto Cleanup; } // // if the access check failed, then the sid is not a member of the // token // if ((AccessStatus == TRUE) && (AccessGranted == MEMBER_ACCESS)) { *IsMember = TRUE; } Cleanup: if (TokenHandle == NULL && EffectiveToken != NULL) { CloseHandle(EffectiveToken); } if (SecDesc != NULL) { LocalFree(SecDesc); } return (Status == ERROR_SUCCESS) ? TRUE : FALSE; } /*------------------------------------------------------------------------ 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(!TLSCheckTokenMembership(NULL, psidAdministrators, bMember)) { dwStatus=GetLastError(); } FreeSid(psidAdministrators); } while(FALSE); return dwStatus; } #endif 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 ) /*++ 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 nLength = MAX_HELPACCOUNT_PASSWORD; int iTotal = 0; DWORD RandomNum = 0; int i; time_t timeVal; 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') }; // // 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; iusri3_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 --*/ { OSVERSIONINFOEX osVersionInfo; DWORDLONG dwlConditionMask = 0; BOOL bSuccess; ZeroMemory( &osVersionInfo, sizeof(OSVERSIONINFOEX) ); osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osVersionInfo.wProductType = VER_NT_SERVER; VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL); bSuccess= VerifyVersionInfo( &osVersionInfo, VER_PRODUCT_TYPE, dwlConditionMask ); return !bSuccess; } 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. 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); } Status = LsaStorePrivateData( PolicyHandle, &SecretKeyName, &SecretData ); 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; } #endif long GetUserTSLogonIdEx( HANDLE hToken ) /*++ --*/ { BOOL Result; LONG SessionId = -1; ULONG ReturnLength; #ifndef __WIN9XBUILD__ // // 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; } #endif 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; #ifndef __WIN9XBUILD__ HANDLE hToken; BOOL bSuccess; bSuccess = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, //TOKEN_ALL_ACCESS, FALSE, &hToken ); if( TRUE == bSuccess ) { lSessionId = GetUserTSLogonIdEx(hToken); CloseHandle(hToken); } #else lSessionId = 0; #endif 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) { 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) { 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 ); } // ignore any error and continue on } } 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. --*/ { #ifndef __WIN9XBUILD__ 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, FALSE, &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; #else return E_UNEXPECTED; #endif } //---------------------------------------------------------------- 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(). --*/ { #ifndef __WIN9XBUILD__ 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); #else bstrSid = WIN9X_USER_SID; return S_OK; #endif } BOOL FileExists( IN LPCTSTR FileName, OUT PWIN32_FIND_DATA FindData OPTIONAL ) /*++ Routine Description: Determine if a file exists and is accessible. Errormode is set (and then restored) so the user will not see any pop-ups. Arguments: FileName - supplies full path of file to check for existance. FindData - if specified, receives find data for the file. Return Value: TRUE if the file exists and is accessible. FALSE if not. GetLastError() returns extended error info. --*/ { WIN32_FIND_DATA findData; HANDLE FindHandle; DWORD Error; FindHandle = FindFirstFile(FileName,&findData); if(FindHandle == INVALID_HANDLE_VALUE) { Error = GetLastError(); } else { FindClose(FindHandle); if(FindData) { *FindData = findData; } Error = NO_ERROR; } SetLastError(Error); return (Error == NO_ERROR); } BOOL AdjustPrivilege( PWSTR Privilege ) /*++ Routine Description: This routine tries to adjust the priviliege of the current process. Arguments: Privilege - String with the name of the privilege to be adjusted. Return Value: Returns TRUE if the privilege could be adjusted. Returns FALSE, otherwise. --*/ { HANDLE TokenHandle; LUID_AND_ATTRIBUTES LuidAndAttributes; TOKEN_PRIVILEGES TokenPrivileges; if( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle ) ) { return( FALSE ); } if( !LookupPrivilegeValue( NULL, Privilege, // (LPWSTR)SE_SECURITY_NAME, &( LuidAndAttributes.Luid ) ) ) { return( FALSE ); } LuidAndAttributes.Attributes = SE_PRIVILEGE_ENABLED; TokenPrivileges.PrivilegeCount = 1; TokenPrivileges.Privileges[0] = LuidAndAttributes; if( !AdjustTokenPrivileges( TokenHandle, FALSE, &TokenPrivileges, 0, NULL, NULL ) ) { return( FALSE ); } if( GetLastError() != NO_ERROR ) { return( FALSE ); } return( TRUE ); }