#include "advapi.h" #include #include #include #include #include #include #include #include #include RTL_CRITICAL_SECTION SiteSidCacheLock; // internal function declarations HRESULT MakeSidFromHash(PSID *ppSid, BYTE *pbBuffer, DWORD cbBuffer); void UpdateSiteSidUsage( HKEY hCacheKey, LPCWSTR lpwszSiteSid, LPWSTR lpwszSite, UINT cbSiteBuffer); void Base32Encode(LPVOID pvData, UINT cbData, LPWSTR pchData); typedef HRESULT (STDAPICALLTYPE CREATESECURITYMANAGER) ( IServiceProvider *pSP, IInternetSecurityManager **ppSM, DWORD dwReserved); CREATESECURITYMANAGER *pfnCoInternetCreateSecurityManager = CoInternetCreateSecurityManager; HMODULE hUrlMon = 0; PSID APIENTRY GetSiteSidFromToken( IN HANDLE TokenHandle ) { PTOKEN_GROUPS RestrictedSids = NULL; ULONG ReturnLength; NTSTATUS Status; PSID psSiteSid = NULL; Status = NtQueryInformationToken( TokenHandle, TokenRestrictedSids, NULL, 0, &ReturnLength ); if (Status != STATUS_BUFFER_TOO_SMALL) { BaseSetLastNTError(Status); return NULL; } RestrictedSids = (PTOKEN_GROUPS) RtlAllocateHeap(RtlProcessHeap(), 0, ReturnLength); if (RestrictedSids == NULL) { SetLastError(ERROR_OUTOFMEMORY); return NULL; } Status = NtQueryInformationToken( TokenHandle, TokenRestrictedSids, RestrictedSids, ReturnLength, &ReturnLength ); if (NT_SUCCESS(Status)) { UINT i; SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = SECURITY_INTERNETSITE_AUTHORITY; for (i = 0; i < RestrictedSids->GroupCount; i++) { if (RtlCompareMemory((PVOID) &((SID *) RestrictedSids->Groups[i].Sid)->IdentifierAuthority, (PVOID) &InternetSiteAuthority, sizeof(SID_IDENTIFIER_AUTHORITY)) == sizeof(SID_IDENTIFIER_AUTHORITY)) { psSiteSid = RtlAllocateHeap(RtlProcessHeap(), 0, RtlLengthSid((RestrictedSids->Groups[i]).Sid)); if (psSiteSid == NULL) { SetLastError(ERROR_OUTOFMEMORY); } else { RtlCopySid(RtlLengthSid((RestrictedSids->Groups[i]).Sid), psSiteSid, (RestrictedSids->Groups[i]).Sid); } break; } } } else { BaseSetLastNTError(Status); } RtlFreeHeap(RtlProcessHeap(), 0, RestrictedSids); return psSiteSid; } HRESULT GetRestrictedSids( LPCWSTR pszSite, SID_AND_ATTRIBUTES *pSidToRestrict, ULONG *pCount) { HRESULT hr = S_OK; ULONG i = 0; long error; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; *pCount = 0; pSidToRestrict[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED; pSidToRestrict[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED; pSidToRestrict[2].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED; //Get the site SID. pSidToRestrict[0].Sid = GetSiteSidFromUrl(pszSite); if(!pSidToRestrict[0].Sid) { return HRESULT_FROM_WIN32(GetLastError()); } i++; //BUGBUG: Get the zone SID. //Get the restricted SID. error = RtlAllocateAndInitializeSid(&NtAuthority, 1, SECURITY_RESTRICTED_CODE_RID, 0, 0, 0, 0, 0, 0, 0, &pSidToRestrict[i].Sid); if(!error) { i++; } else { hr = HRESULT_FROM_WIN32( GetLastError() ); } if(FAILED(hr)) { return hr; } *pCount = i; return hr; } HRESULT APIENTRY GetSiteNameFromSid(PSID pSid, LPWSTR *pwsSite) { HRESULT hr = S_OK; WCHAR wsValueNameBuffer[MAX_MANGLED_SITE]; LPWSTR wsValueName = wsValueNameBuffer; HKEY hCacheKey; DWORD dwDisposition; WCHAR *wszValue; ULONG ulValueSize; DWORD error; *pwsSite = NULL; error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SITE_SID_CACHE_REG_KEY, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hCacheKey, &dwDisposition); if (ERROR_SUCCESS != error) { // Can't write, try read-only. We won't be able to update the cache, // but we might be able to return the site name error = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SITE_SID_CACHE_REG_KEY, 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hCacheKey, &dwDisposition); if (ERROR_SUCCESS != error) { return HRESULT_FROM_WIN32(error); } } GetMangledSiteSid(pSid, MAX_MANGLED_SITE, &wsValueName); ASSERT(wsValueName == wsValueNameBuffer); //Get the size and allocate memory for the site name. error = RegQueryValueExW( hCacheKey, wsValueName, NULL, NULL, NULL, &ulValueSize); if (ERROR_SUCCESS != error) { RegCloseKey(hCacheKey); return HRESULT_FROM_WIN32(error); } wszValue = (WCHAR *) LocalAlloc(0, ulValueSize); if (wszValue != NULL) { error = RegQueryValueExW( hCacheKey, wsValueName, NULL, NULL, (BYTE *) wszValue, &ulValueSize); if (ERROR_SUCCESS == error) { *pwsSite = wszValue; UpdateSiteSidUsage(hCacheKey, wsValueName, wszValue, ulValueSize); } else { hr = HRESULT_FROM_WIN32(error); LocalFree(wszValue); } } else { hr = E_OUTOFMEMORY; } RegCloseKey(hCacheKey); return hr; } PSID APIENTRY GetSiteSidFromUrl(LPCWSTR wsUrl) { HRESULT hr; PSID pSid = NULL; IInternetSecurityManager *pIScManager; DWORD cbSecurityId = lstrlenW(wsUrl) * sizeof(WCHAR) + sizeof(DWORD); BYTE *pbSecurityId = (BYTE *) alloca(cbSecurityId); HCRYPTPROV hProv; HCRYPTHASH hHash; DWORD dwCount; DWORD dwHashLen; BYTE *pbBuffer; HKEY hCacheKey; DWORD dwDisposition; WCHAR wsValueNameBuffer[MAX_MANGLED_SITE]; LPWSTR wsValueName = wsValueNameBuffer; ULONG ulValueSize = (lstrlenW(wsUrl) + 1) * sizeof(WCHAR); WCHAR *wsValue; NTSTATUS Status; DWORD error; //Crack the URL to get the site name. hr = (*pfnCoInternetCreateSecurityManager)(NULL, &pIScManager, 0); if(SUCCEEDED(hr)) { hr = pIScManager->GetSecurityId(wsUrl, pbSecurityId, &cbSecurityId, 0); if(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) { pbSecurityId = (BYTE *) alloca(cbSecurityId); hr = pIScManager->GetSecurityId(wsUrl, pbSecurityId, &cbSecurityId, 0); } //Remove the dwZone from the end of the pbSecurityId. cbSecurityId -= sizeof(DWORD); pIScManager->Release(); } if(FAILED(hr)) { SetLastError(hr); return NULL; } // acquire security context - if this is unsuccessful, // the hashing functions cannot be called if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return NULL; if (!CryptCreateHash(hProv, SITE_SID_HASH_ALGORITHM, 0, 0, &hHash)) { CryptReleaseContext(hProv, 0); return NULL; } // hash the site name if (!CryptHashData(hHash, pbSecurityId, cbSecurityId, 0)) { CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return NULL; } // TODO: salt? - with local machine name? // get size of the hash value - for memory allocation dwCount = sizeof(DWORD); if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *) &dwHashLen, &dwCount, 0)) { CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return NULL; } pbBuffer = (BYTE *) LocalAlloc(0, dwHashLen); if (pbBuffer == NULL) { //out of memory CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); SetLastError(ERROR_OUTOFMEMORY); return NULL; } if (!CryptGetHashParam(hHash, HP_HASHVAL, pbBuffer, &dwHashLen, 0)) { LocalFree(pbBuffer); CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); return NULL; } CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); // make SID from the hash value in pbBuffer hr = MakeSidFromHash(&pSid, pbBuffer, dwHashLen); if (FAILED(hr)) { LocalFree(pbBuffer); SetLastError(hr); return NULL; } // check if the SID is already in the SID cache // if it is, update the time of last use // if not, insert it into the cache, deleting the LRU // item if the cache is already full // whatever happens here, we already have the mapping // from URL to SID that we wanted, so we always return // success // // Convert the cracked site name to Unicode // __try { wsUrl = (WCHAR *) alloca(ulValueSize); } __except (EXCEPTION_EXECUTE_HANDLER) { return pSid; // alloca failed } Status = RtlMultiByteToUnicodeN((WCHAR *) wsUrl, ulValueSize, &dwCount, (char *) pbSecurityId, cbSecurityId); if (!(NT_SUCCESS(Status))) { return pSid; } ((WCHAR *)wsUrl)[dwCount / sizeof(WCHAR)] = L'\0'; hCacheKey = NULL; if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, SITE_SID_CACHE_REG_KEY, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hCacheKey, &dwDisposition) != ERROR_SUCCESS) { // cannot open/create the cache registry key return pSid; } GetMangledSiteSid(pSid, MAX_MANGLED_SITE, &wsValueName); ASSERT(wsValueName == wsValueNameBuffer); __try { wsValue = (WCHAR *) alloca(ulValueSize); } __except (EXCEPTION_EXECUTE_HANDLER) { RegCloseKey(hCacheKey); // alloca failed return pSid; } error = RegQueryValueExW( hCacheKey, wsValueName, NULL, NULL, (BYTE *) wsValue, &ulValueSize); if (ERROR_SUCCESS == error) { // this SID is already there in the cache // check for collision // if wsValue is "", we already know of a collision if (wsValue[0] != L'\0') { if (wcscmp(wsUrl, wsValue) != 0) { // COLLISION !!! // we handle collision by retaining the SID in // the cache and setting the site name to "" // so the wrong site name cannot be returned DbgPrint("Site SID Collision:\n\t%ws\n\t%ws\n", wsUrl,wsValue); WCHAR wcNull = L'\0'; RegSetValueExW(hCacheKey, wsValueName, 0, REG_BINARY, (CONST BYTE *) &wcNull, sizeof(WCHAR)); } else { UpdateSiteSidUsage( hCacheKey, wsValueName, wsValue, ulValueSize); } } } else if (ERROR_FILE_NOT_FOUND == error) { UpdateSiteSidUsage(hCacheKey, wsValueName, (WCHAR *) wsUrl, 0); } RegCloseKey(hCacheKey); return pSid; } void UpdateSiteSidUsage( HKEY hCacheKey, LPCWSTR lpwszSiteSid, LPWSTR lpwszSite, UINT cbSiteBuffer) { UINT cbSite = wcslen(lpwszSite)*sizeof(WCHAR) + sizeof(L'\0'); UINT cbRequiredBuffer = cbSite + sizeof(LARGE_INTEGER); BOOL bCheckOverflow = (0 == cbSiteBuffer); LARGE_INTEGER Now; if (cbSiteBuffer < cbRequiredBuffer) { // Either this is a new cache entry or somebody mucked with the // cache data LPWSTR lpwsz; __try { lpwsz = (LPWSTR) alloca(cbRequiredBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { return; // alloca failed } wcscpy(lpwsz, lpwszSite); cbSiteBuffer = cbRequiredBuffer; lpwszSite = lpwsz; } // Tack the current time after the end of the string and write it out NtQuerySystemTime(&Now); * (UNALIGNED LARGE_INTEGER *) (((BYTE *) lpwszSite) + cbSite) = Now; RegSetValueExW( hCacheKey, lpwszSiteSid, NULL, REG_BINARY, (BYTE *) lpwszSite, cbSiteBuffer); if (!bCheckOverflow) return; // Check for cache overflow #define _PTIME(i) ((__int64 *) (pEntryInfo + i * cbEntryInfo)) #define _PVALUE(i) ((WCHAR *) (_PTIME(i) + 1)) static volatile LONG lFlushing = 0; DWORD error; DWORD cEntries; DWORD cTotalEntries; DWORD cbEntryValue; DWORD cbMaxEntryValue; BYTE *pEntryValue; DWORD cbMaxEntryName; DWORD cbEntryInfo; BYTE *pEntryInfo; UINT iFreeEntry; UINT iNewestEntry; UINT i; DWORD cb; error = RegQueryInfoKeyW(hCacheKey, NULL, NULL, NULL, NULL, NULL, NULL, &cEntries, &cbMaxEntryName, &cbMaxEntryValue, NULL, NULL); if (ERROR_SUCCESS != error || cEntries < SITE_SID_CACHE_SIZE_HIGH || 1 == InterlockedExchange((LONG *) &lFlushing, 1)) { return; // Cache is under limit or we are already flushing } cbMaxEntryName = (cbMaxEntryName + 1) * sizeof(WCHAR); cTotalEntries = cEntries - SITE_SID_CACHE_SIZE_LOW + 1; cbEntryInfo = sizeof(LARGE_INTEGER) + cbMaxEntryName; // Allocate space for the largest value size __try { pEntryValue = (BYTE *) alloca(cbMaxEntryValue); } __except (EXCEPTION_EXECUTE_HANDLER) { return; } // Allocate space to hold the cache entries to delete (+1) do { pEntryInfo = (BYTE *) LocalAlloc(0, cbEntryInfo * cTotalEntries); if (NULL == pEntryInfo) { cTotalEntries = cTotalEntries / 2; if (cTotalEntries < 2) { lFlushing = 0; return; } } } while (NULL == pEntryInfo); iFreeEntry = 0; iNewestEntry = 0; i = 0; cb = cbEntryInfo - sizeof(LARGE_INTEGER); cEntries = 1; BOOL bNewNewest = FALSE; cbEntryValue = cbMaxEntryValue; while (ERROR_SUCCESS == RegEnumValueW( hCacheKey, i, _PVALUE(iFreeEntry), &cb, NULL, NULL, pEntryValue, &cbEntryValue)) { ++i; cb = cbEntryInfo - sizeof(LARGE_INTEGER); cbEntryValue = cbMaxEntryValue; * _PTIME(iFreeEntry) = * (__int64 *) (wcschr((WCHAR *) pEntryValue, L'\0') + 1); if (cEntries < cTotalEntries) { ++cEntries; ++iFreeEntry; if (cEntries == cTotalEntries) bNewNewest = TRUE; } else if (*_PTIME(iFreeEntry) < *_PTIME(iNewestEntry)) { UINT t = iNewestEntry; iNewestEntry = iFreeEntry; iFreeEntry = t; bNewNewest = TRUE; } if (bNewNewest) { bNewNewest = FALSE; for (DWORD j = 0; j < cEntries; j++) { if (j != iFreeEntry) if (*_PTIME(j) > *_PTIME(iNewestEntry)) iNewestEntry = j; } } } if (i >= SITE_SID_CACHE_SIZE_HIGH) { for (DWORD j = 0; j < cEntries; j++) { if (j != iFreeEntry) RegDeleteValueW(hCacheKey, _PVALUE(j)); } } LocalFree(pEntryInfo); lFlushing = 0; #undef _PVALUE #undef _PTIME } HRESULT MakeSidFromHash(PSID *ppSid, BYTE *pbBuffer, DWORD cbBuffer) { HRESULT hr = S_OK; long error; DWORD aSubAuthorities[8]; SID_IDENTIFIER_AUTHORITY siaAuthority = SITE_SID_CACHE_AUTHORITY; *ppSid = NULL; if(cbBuffer > sizeof(aSubAuthorities)) { return E_INVALIDARG; } memset(aSubAuthorities, 0, sizeof(aSubAuthorities)); memcpy(aSubAuthorities, pbBuffer, cbBuffer); error = RtlAllocateAndInitializeSid(&siaAuthority, (BYTE) ((cbBuffer + 3) / sizeof(DWORD)), aSubAuthorities[0], aSubAuthorities[1], aSubAuthorities[2], aSubAuthorities[3], aSubAuthorities[4], aSubAuthorities[5], aSubAuthorities[6], aSubAuthorities[7], ppSid); if(error) { hr = HRESULT_FROM_WIN32(error); } return hr; } HRESULT APIENTRY GetMangledSiteSid(PSID pSid, ULONG cchMangledSite, LPWSTR *ppwszMangledSite) { SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = SECURITY_INTERNETSITE_AUTHORITY; SID_IDENTIFIER_AUTHORITY *InAuthority; InAuthority = RtlIdentifierAuthoritySid(pSid); if (NULL == InAuthority) return HRESULT_FROM_WIN32(ERROR_INVALID_SID); if (0 != memcmp( InAuthority, &InternetSiteAuthority, sizeof(InternetSiteAuthority))) { return HRESULT_FROM_WIN32(ERROR_INVALID_SID); } if (cchMangledSite < MAX_MANGLED_SITE) { *ppwszMangledSite = (WCHAR *) LocalAlloc( 0, MAX_MANGLED_SITE * sizeof(WCHAR)); if (NULL == *ppwszMangledSite) return E_OUTOFMEMORY; } // The value of MAX_MANGLED_SITE assumes 4 dwords ASSERT(4 == *RtlSubAuthorityCountSid(pSid)); Base32Encode( RtlSubAuthoritySid(pSid, 0), *RtlSubAuthorityCountSid(pSid) * sizeof(DWORD), *ppwszMangledSite); // The output string should always be MAX_MANGLED_SITE - 1 chars long ASSERT(MAX_MANGLED_SITE - 1 == lstrlenW(*ppwszMangledSite)); return S_OK; } ULONG APIENTRY GetSiteDirectoryA( HANDLE hToken, LPSTR lpBuffer, ULONG nBufferLength ) /*++ Routine Description: ANSI thunk to GetSiteDirectoryW --*/ { PUNICODE_STRING Unicode; ANSI_STRING AnsiString; NTSTATUS Status; DWORD ReturnValue; #if defined (FE_SB) // GetSiteDirectoryA(); local variable ULONG cbAnsiString; #endif // FE_SB if ( nBufferLength > MAXUSHORT ) { nBufferLength = MAXUSHORT-2; } Unicode = &NtCurrentTeb()->StaticUnicodeString; Unicode->Length = (USHORT)GetSiteDirectoryW( hToken, Unicode->Buffer, Unicode->MaximumLength ); #if defined (FE_SB) // GetSiteDirectoryA(): bug fix // // Unicode->Length contains the byte count of unicode string. // Original code does "UnicodeLength / sizeof(WCHAR)" to // get the size of corresponding ansi string. // This is correct in SBCS environment. However in DBCS // environment, it's definitely WRONG. // Status = RtlUnicodeToMultiByteSize( &cbAnsiString, Unicode->Buffer, Unicode->Length ); if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError(Status); ReturnValue = 0; } else { if ( nBufferLength > (DWORD)(cbAnsiString ) ) { AnsiString.Buffer = lpBuffer; AnsiString.MaximumLength = (USHORT)(nBufferLength+1); Status = BasepUnicodeStringTo8BitString(&AnsiString,Unicode,FALSE); if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError(Status); ReturnValue = 0; } else { ReturnValue = AnsiString.Length; } } else { // // current spec says the length doesn't // include null terminate character. // this may be a bug but I would like // to make this same as US (see US original code). // ReturnValue = cbAnsiString + 1; } } #else if ( nBufferLength > (DWORD)(Unicode->Length>>1) ) { AnsiString.Buffer = lpBuffer; AnsiString.MaximumLength = (USHORT)(nBufferLength+1); Status = RtlUnicodeStringToAnsiString(&AnsiString,Unicode,FALSE); if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError(Status); ReturnValue = 0; } else { ReturnValue = AnsiString.Length; } } else { ReturnValue = ((Unicode->Length)>>1)+1; } #endif // FE_SB return ReturnValue; } /***************************************************************************\ * GetUserSid * * Allocs space for the user sid, fills it in and returns a pointer. Caller * The sid should be freed by calling DeleteUserSid. * * Note the sid returned is the user's real sid, not the per-logon sid. * * Returns pointer to sid or NULL on failure. * * History: * 26-Aug-92 Davidc Created. \***************************************************************************/ PSID GetUserSid (HANDLE UserToken) { PTOKEN_USER pUser; PSID pSid; DWORD BytesRequired = 200; NTSTATUS status; // // Allocate space for the user info // pUser = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, BytesRequired); if (pUser == NULL) { // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"), // BytesRequired)); return NULL; } // // Read in the UserInfo // status = NtQueryInformationToken( UserToken, // Handle TokenUser, // TokenInformationClass pUser, // TokenInformation BytesRequired, // TokenInformationLength &BytesRequired // ReturnLength ); if (status == STATUS_BUFFER_TOO_SMALL) { // // Allocate a bigger buffer and try again. // HLOCAL realloc = LocalReAlloc(pUser, BytesRequired, LMEM_MOVEABLE); if (NULL == realloc) { // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"), // BytesRequired)); LocalFree(pUser); return NULL; } pUser = (PTOKEN_USER) realloc; status = NtQueryInformationToken( UserToken, // Handle TokenUser, // TokenInformationClass pUser, // TokenInformation BytesRequired, // TokenInformationLength &BytesRequired // ReturnLength ); } if (!NT_SUCCESS(status)) { // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to query user info from user token, status = 0x%x"), // status)); LocalFree(pUser); return NULL; } BytesRequired = RtlLengthSid(pUser->User.Sid); pSid = LocalAlloc(LMEM_FIXED, BytesRequired); if (pSid == NULL) { // DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"), // BytesRequired)); LocalFree(pUser); return NULL; } status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid); LocalFree(pUser); if (!NT_SUCCESS(status)) { // DebugMsg((DM_WARNING, TEXT("GetUserSid: RtlCopySid Failed. status = %d"), // status)); LocalFree(pSid); pSid = NULL; } return pSid; } BOOL CreateSiteDirectory( LPCWSTR pszSiteDirectory, PSID psidUser, PSID psidSite) { BOOL bRetVal = FALSE; SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; PACL pAcl = NULL; PSID psidSystem = NULL; PSID psidAdmin = NULL; DWORD cbAcl, AceIndex, dwDisp; ACE_HEADER * lpAceHeader; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES saSite; // // Get the system sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem)) { goto Exit; } // // Get the admin sid // if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) { goto Exit; } // // Allocate space for the ACL // cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + (2 * GetLengthSid (psidSite)) + sizeof(ACL) + (8 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl); if (!pAcl) { goto Exit; } if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { goto Exit; } // // Add Aces for User, System, and Admin. Non-inheritable ACEs first // AceIndex = 0; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidUser)) { goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) { goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) { goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSite)) { goto Exit; } // // Now the inheritable ACEs // AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) { goto Exit; } if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) { goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) { goto Exit; } if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) { goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) { goto Exit; } if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) { goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSite)) { goto Exit; } if (!GetAce(pAcl, AceIndex, (void **)&lpAceHeader)) { goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); // // Put together the security descriptor // if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { goto Exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { goto Exit; } // // Add the security descriptor to the sa structure // saSite.nLength = sizeof(SECURITY_ATTRIBUTES); saSite.lpSecurityDescriptor = &sd; saSite.bInheritHandle = FALSE; // // Attempt to create the directory // bRetVal = CreateDirectoryW(pszSiteDirectory, &saSite); Exit: // // Free the sids and acl // if (psidSystem) { FreeSid(psidSystem); } if (psidAdmin) { FreeSid(psidAdmin); } if (pAcl) { GlobalFree (pAcl); } return bRetVal; } ULONG APIENTRY GetSiteDirectoryW( HANDLE hToken, LPWSTR pszSiteDirectory, ULONG uSize) { ULONG cb = 0; PSID psidUser = 0; PSID psidSite = 0; WCHAR szProfile[MAX_PATH + 1]; LPWSTR pszProfile = szProfile; HANDLE hProcessToken = 0; long error = 0; //Get the process token. if(!hToken) { if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken)) { hToken = hProcessToken; } else { return 0; } } //Get the path to the user profile directory. psidUser = GetUserSid(hToken); if(psidUser != NULL) { UNICODE_STRING wstrUserSid = {0, 0, 0}; error = RtlConvertSidToUnicodeString(&wstrUserSid, psidUser, TRUE); if(!error) { HKEY hkUserProfile; //Read the registry key. lstrcpyW(szProfile, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"); lstrcatW(szProfile, wstrUserSid.Buffer); error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szProfile, 0, KEY_READ, &hkUserProfile); if(!error) { DWORD dwType; DWORD dwSize = sizeof(szProfile); error = RegQueryValueExW(hkUserProfile, L"ProfileImagePath", NULL, &dwType, (BYTE*)szProfile, &dwSize ); if(!error) { if ( dwType == REG_EXPAND_SZ ) { pszProfile = (LPWSTR) alloca((MAX_PATH + 1) * sizeof(WCHAR)); ExpandEnvironmentStringsW(szProfile, pszProfile, MAX_PATH); } } RegCloseKey(hkUserProfile); } RtlFreeUnicodeString(&wstrUserSid); } } else { error = GetLastError(); } //Get the path to the site directory. if(!error) { psidSite = GetSiteSidFromToken(hToken); if(psidSite != NULL) { WCHAR wszSiteNameBuffer[MAX_MANGLED_SITE]; LPWSTR wszSiteName = wszSiteNameBuffer; GetMangledSiteSid(psidSite, MAX_MANGLED_SITE, &wszSiteName); ASSERT(wszSiteName == wszSiteNameBuffer); cb = sizeof(WCHAR) * (lstrlenW(pszProfile) + sizeof('\\') + lstrlenW(wszSiteName) + sizeof('\0')); if(uSize * 2 < cb) { return cb/2; } else { lstrcpyW(pszSiteDirectory, pszProfile); lstrcatW(pszSiteDirectory, L"\\"); lstrcatW(pszSiteDirectory, wszSiteName); //Check if the directory already exists. if(GetFileAttributesW(pszSiteDirectory) == -1) { CreateSiteDirectory(pszSiteDirectory, psidUser, psidSite); } } RtlFreeSid(psidSite); } else { error = GetLastError(); } } if(error) { SetLastError(error); } if(hProcessToken) { CloseHandle(hProcessToken); } if(psidUser) { RtlFreeSid(psidUser); } return cb; } BOOL APIENTRY IsProcessRestricted(void) /*++ Routine Description: Checks if the current process is a restricted process. Arguments: None. Return Value: TRUE if the current process is a restricted process. FALSE if it isn't, or if the handle of the current process cannot be obtained Notes: --*/ { static long fIsRestricted = -1; if(-1 == fIsRestricted) { HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) { fIsRestricted = IsTokenRestricted(hToken); CloseHandle(hToken); } else { fIsRestricted = 0; } } return fIsRestricted; } WINADVAPI BOOL WINAPI IsInSandbox(VOID) { return IsProcessRestricted(); } //+------------------------------------------------------------------- // // Function: CoInternetCreateSecurityManager // // Synopsis: Loads urlmon.dll and calls CoInternetCreateSecurityManager. // // Returns: S_OK, ERROR_MOD_NOT_FOUND // //-------------------------------------------------------------------- STDAPI CoInternetCreateSecurityManager( IN IServiceProvider *pSP, OUT IInternetSecurityManager **ppSM, IN DWORD dwReserved) { HRESULT hr = E_FAIL; if(!hUrlMon) { hUrlMon = LoadLibraryA("urlmon.dll"); } if(hUrlMon != 0) { void *pfn = GetProcAddress(hUrlMon, "CoInternetCreateSecurityManager"); if(pfn != NULL) { pfnCoInternetCreateSecurityManager = (CREATESECURITYMANAGER *) pfn; hr = (*pfnCoInternetCreateSecurityManager)(pSP, ppSM, dwReserved); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } //+---------------------------------------------------------------------------- // // Function: Base32Encode // // Synopsis: Convert the given data to base32 // // Notes: Adapted from Mim64Encode in the mshtml project. // // For 128 bit input (4 DWORDs) the output string will be // 27 chars long (including the null terminator) // //----------------------------------------------------------------------------- void Base32Encode(LPVOID pvData, UINT cbData, LPWSTR pchData) { static const WCHAR alphabet[32] = { L'a', L'b', L'c', L'd', L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', L'u', L'v', L'w', L'x', L'y', L'z', L'0', L'1', L'2', L'3', L'4', L'5' }; int shift = 0; // The # of unprocessed bits in accum ULONG accum = 0; // The unprocessed bits ULONG value; BYTE *pData = (BYTE *) pvData; // For each byte... while (cbData) { // Move the byte into the low bits of the accumulator accum = (accum << 8) | *pData++; shift += 8; --cbData; // Lop off the high 5 or 10 bits and write them out while ( shift >= 5 ) { shift -= 5; value = (accum >> shift) & 0x1Fl; *pchData++ = alphabet[value]; } } // If there are any remaining bits, push out one more char padded with 0's if (shift) { value = (accum << (5 - shift)) & 0x1Fl; *pchData++ = alphabet[value]; } *pchData = L'\0'; }