|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
checker.cxx
Abstract:
IIS Services IISADMIN Extension Unicode Metadata Sink.
Author:
Michael W. Thomas 11-19-98
--*/ #include <cominc.hxx>
#include <lmaccess.h>
#include <lmserver.h>
#include <lmapibuf.h>
#include <lmerr.h>
#include <ntlsa.h>
#include <time.h>
#include <ntsam.h>
#include <netlib.h>
#include <resource.h>
#define SECURITY_WIN32
#define ISSP_LEVEL 32
#define ISSP_MODE 1
#include <sspi.h>
#include <sspi.h>
#include <eventlog.hxx>
#include "extend.h"
#include <comadmin.h>
#include <sddl.h>
#include "wmrgexp.h"
typedef TCHAR USERNAME_STRING_TYPE[MAX_PATH]; typedef TCHAR PASSWORD_STRING_TYPE[LM20_PWLEN+1];
const LPCWSTR ROOTMDPath = L"/LM/W3SVC";
#define IIS_WP_GROUP L"IIS_WPG"
#ifndef ARRAYSIZE
#define ARRAYSIZE(_a) (sizeof((_a))/sizeof(*(_a)))
#endif
typedef enum { GUFM_SUCCESS, GUFM_NO_PATH, GUFM_NO_PASSWORD, GUFM_NO_USER_ID } GUFM_RETURN;
typedef struct _COM_APP_THREAD_STRUCT { USERNAME_STRING_TYPE ustWamUserName; PASSWORD_STRING_TYPE pstWamUserPass; } COM_APP_THREAD_STRUCT;
BOOL ValidatePassword(IN LPCTSTR UserName,IN LPCTSTR Domain,IN LPCTSTR Password); void InitLsaString(PLSA_UNICODE_STRING LsaString,LPWSTR String); DWORD GetPrincipalSID (LPCTSTR Principal,PSID *Sid,BOOL *pbWellKnownSID); DWORD OpenPolicy(LPTSTR ServerName,DWORD DesiredAccess,PLSA_HANDLE PolicyHandle); DWORD AddRightToUserAccount(LPCTSTR szAccountName, LPTSTR PrivilegeName); DWORD DoesUserHaveThisRight(LPCTSTR szAccountName, LPTSTR PrivilegeName,BOOL *fHaveThatRight); HRESULT UpdateComApplications(LPCTSTR szWamUserName,LPCTSTR szWamUserPass); DWORD UpdateComApplicationsThread(PVOID pv); int IsDomainController(void); BOOL WaitForDCAvailability(void); HRESULT UpdateAdminAcl(IMDCOM *pcCom, LPCWSTR szPath, LPCWSTR szAccountName); BOOL MakeSureUserGetsCreated(LPTSTR pszAnonyName,LPTSTR pszAnonyPass,DWORD dwUserCommentResourceId,DWORD dwUserFullNameResourceId,BOOL fSpecicaliWamAccount); // these two lines for logging event about account recreation
EVENT_LOG *g_eventLogForAccountRecreation = NULL; BOOL CreateEventLogObject();
VOID UpdateUserRights( LPCTSTR account, LPTSTR pstrRights[], DWORD dwNofRights) { DWORD status; BOOL fPresence;
for (DWORD i=0;i<dwNofRights;i++) { status = DoesUserHaveThisRight(account,pstrRights[i],&fPresence); if (!NT_SUCCESS(status)) { DBGPRINTF(( DBG_CONTEXT,"[UpdateAnonymousUser] DoesUserHaveThisRight returned err=0x%0X for account %s right %s\n",status,account,pstrRights[i])); } else { if (!fPresence) { status = AddRightToUserAccount(account,pstrRights[i]); if (!NT_SUCCESS(status)) { DBGPRINTF(( DBG_CONTEXT,"[UpdateAnonymousUser] AddRightToUserAccount returned err=0x%0X for account %s right %s\n",status,account,pstrRights[i])); } } } } }
DWORD AddRightToUserAccount( LPCTSTR szAccountName, LPTSTR PrivilegeName) { NTSTATUS status; LSA_UNICODE_STRING UserRightString; LSA_HANDLE PolicyHandle = NULL; PSID pSID = NULL; BOOL bWellKnownSID = FALSE;
// Create a LSA_UNICODE_STRING for the privilege name.
InitLsaString(&UserRightString, PrivilegeName);
// get the sid of szAccountName
status = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID);
if (status != ERROR_SUCCESS) { DBGPRINTF(( DBG_CONTEXT,"[AddRightToUserAccount] GetPrincipalSID returned err=0x%0X\n",status)); return (status); }
status = OpenPolicy(NULL, POLICY_ALL_ACCESS,&PolicyHandle); if ( status == NERR_Success ) { status = LsaAddAccountRights ( PolicyHandle, pSID, &UserRightString, 1); }
if (PolicyHandle) { LsaClose(PolicyHandle); } if (pSID) { if (bWellKnownSID) { FreeSid (pSID); } else { free (pSID); } } return status; }
DWORD DoesUserHaveThisRight( LPCTSTR szAccountName, LPTSTR PrivilegeName, BOOL *fHaveThatRight) { BOOL fEnabled = FALSE; NTSTATUS status; LSA_UNICODE_STRING UserRightString; LSA_HANDLE PolicyHandle = NULL; PSID pSID = NULL; BOOL bWellKnownSID = FALSE;
*fHaveThatRight = FALSE;
// Create a LSA_UNICODE_STRING for the privilege name.
InitLsaString(&UserRightString, PrivilegeName);
// get the sid of szAccountName
status = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID); if (status != ERROR_SUCCESS) { return status; }
status = OpenPolicy(NULL, POLICY_ALL_ACCESS,&PolicyHandle); if ( status == NERR_Success ) { UINT i; LSA_UNICODE_STRING *rgUserRights = NULL; ULONG cRights;
status = LsaEnumerateAccountRights( PolicyHandle, pSID, &rgUserRights, &cRights);
if (status==STATUS_OBJECT_NAME_NOT_FOUND) { // no rights/privileges for this account
status = ERROR_SUCCESS; fEnabled = FALSE; } else if (!NT_SUCCESS(status)) { //iisDebugOut((LOG_TYPE_ERROR, _T("DoesUserHaveBasicRights:GetPrincipalSID:Failed to enumerate rights: status 0x%08lx\n"), status));
goto DoesUserHaveBasicRights_Exit; }
for(i=0; i < cRights; i++) { if ( RtlEqualUnicodeString(&rgUserRights[i],&UserRightString,FALSE) ) { fEnabled = TRUE; break; } }
if (rgUserRights) { LsaFreeMemory(rgUserRights); } }
DoesUserHaveBasicRights_Exit:
if (PolicyHandle) { LsaClose(PolicyHandle); } if (pSID) { if (bWellKnownSID) { FreeSid (pSID); } else { free (pSID); } }
*fHaveThatRight = fEnabled; return status; }
DWORD GetCurrentUserSID( PSID *Sid) { DWORD dwReturn = ERROR_SUCCESS; TOKEN_USER *tokenUser = NULL; HANDLE tokenHandle = NULL; DWORD tokenSize = 0 ; DWORD sidLength = 0;
if ( !Sid ) { dwReturn = ERROR_BAD_ARGUMENTS; goto exit; }
*Sid = NULL;
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &tokenHandle ) ) { dwReturn = GetLastError(); goto exit; }
if ( !GetTokenInformation( tokenHandle, TokenUser, tokenUser, 0, &tokenSize ) ) { if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { dwReturn = GetLastError(); goto exit; } } else { dwReturn = (DWORD)E_UNEXPECTED; goto exit; }
tokenUser = (TOKEN_USER *)malloc( tokenSize ); if ( !tokenUser ) { dwReturn = ERROR_OUTOFMEMORY; goto exit; }
if ( !GetTokenInformation( tokenHandle, TokenUser, tokenUser, tokenSize, &tokenSize ) ) { dwReturn = GetLastError(); goto exit; }
sidLength = GetLengthSid( tokenUser->User.Sid ); *Sid = (PSID)malloc( sidLength ); if ( !*Sid ) { dwReturn = ERROR_OUTOFMEMORY; goto exit; }
memcpy( *Sid, tokenUser->User.Sid, sidLength );
exit: if (tokenHandle) { CloseHandle (tokenHandle); tokenHandle = NULL; } if (tokenUser) { free(tokenUser); tokenUser = NULL; }
return dwReturn; }
DWORD CreateNewSD( SECURITY_DESCRIPTOR **SD) { PACL dacl; DWORD sidLength; PSID sid = NULL; PSID groupSID; PSID ownerSID; DWORD returnValue;
*SD = NULL;
returnValue = GetCurrentUserSID (&sid); if (returnValue != ERROR_SUCCESS) { if (sid) { free(sid); } return returnValue; }
sidLength = GetLengthSid (sid);
*SD = (SECURITY_DESCRIPTOR *) malloc ( (sizeof (ACL)+sizeof (ACCESS_ALLOWED_ACE)+sidLength) + (2 * sidLength) + sizeof (SECURITY_DESCRIPTOR)); if (!*SD) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return GetLastError(); }
groupSID = (SID *) (*SD + 1); ownerSID = (SID *) (((BYTE *) groupSID) + sidLength); dacl = (ACL *) (((BYTE *) ownerSID) + sidLength);
if (!InitializeSecurityDescriptor (*SD, SECURITY_DESCRIPTOR_REVISION)) { free (*SD); free (sid); return GetLastError(); }
if (!InitializeAcl (dacl, sizeof (ACL)+sizeof (ACCESS_ALLOWED_ACE)+sidLength, ACL_REVISION2)) { free (*SD); free (sid); return GetLastError(); }
if (!AddAccessAllowedAce (dacl, ACL_REVISION2, COM_RIGHTS_EXECUTE, sid)) { free (*SD); free (sid); return GetLastError(); }
if (!SetSecurityDescriptorDacl (*SD, TRUE, dacl, FALSE)) { free (*SD); free (sid); return GetLastError(); }
memcpy (groupSID, sid, sidLength); if (!SetSecurityDescriptorGroup (*SD, groupSID, FALSE)) { free (*SD); free (sid); return GetLastError(); }
memcpy (ownerSID, sid, sidLength); if (!SetSecurityDescriptorOwner (*SD, ownerSID, FALSE)) { free (*SD); free (sid); return GetLastError(); }
if (sid) free(sid); return ERROR_SUCCESS; }
DWORD GetNamedValueSD ( HKEY RootKey, LPTSTR KeyName, LPTSTR ValueName, SECURITY_DESCRIPTOR **SD, BOOL *NewSD) { DWORD returnValue; HKEY registryKey; DWORD valueType; DWORD valueSize = 0;
*NewSD = FALSE;
//
// Get the security descriptor from the named value. If it doesn't
// exist, create a fresh one.
//
returnValue = RegOpenKeyEx (RootKey, KeyName, 0, KEY_ALL_ACCESS, ®istryKey);
if (returnValue != ERROR_SUCCESS) { if (returnValue == ERROR_FILE_NOT_FOUND) { *SD = NULL; returnValue = CreateNewSD (SD); if (returnValue != ERROR_SUCCESS) { if (*SD) { free(*SD); }
return returnValue; }
*NewSD = TRUE; return ERROR_SUCCESS; } else { return returnValue; } }
returnValue = RegQueryValueEx (registryKey, ValueName, NULL, &valueType, NULL, &valueSize);
if (returnValue && returnValue != ERROR_INSUFFICIENT_BUFFER) { *SD = NULL; returnValue = CreateNewSD (SD); if (returnValue != ERROR_SUCCESS) { if (*SD) { free(*SD); } return returnValue; }
*NewSD = TRUE; } else { *SD = (SECURITY_DESCRIPTOR *) malloc (valueSize); if (!*SD) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return GetLastError(); }
returnValue = RegQueryValueEx (registryKey, ValueName, NULL, &valueType, (LPBYTE) *SD, &valueSize); if (returnValue) { if (*SD) free (*SD);
*SD = NULL; returnValue = CreateNewSD (SD); if (returnValue != ERROR_SUCCESS) { if (*SD) { free(*SD); }
return returnValue; }
*NewSD = TRUE; } }
RegCloseKey (registryKey);
return ERROR_SUCCESS; }
DWORD GetPrincipalSID( LPCTSTR Principal, PSID *Sid, BOOL *pbWellKnownSID) { HRESULT hr = S_OK; DWORD returnValue=ERROR_SUCCESS; SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY; PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority = NULL; BYTE Count = 0; DWORD dwRID[8]; TCHAR pszPrincipal[MAX_PATH];
*pbWellKnownSID = TRUE; memset(&(dwRID[0]), 0, 8 * sizeof(DWORD));
DBG_ASSERT(wcslen(Principal) < MAX_PATH); hr = StringCchCopy(pszPrincipal, ARRAYSIZE(pszPrincipal), Principal); if ( FAILED(hr) ) { return HRESULTTOWIN32( hr ); } _wcslwr(pszPrincipal); if ( wcsstr(pszPrincipal, TEXT("administrators")) != NULL ) { // Administrators group
pSidIdentifierAuthority = &SidIdentifierNTAuthority; Count = 2; dwRID[0] = SECURITY_BUILTIN_DOMAIN_RID; dwRID[1] = DOMAIN_ALIAS_RID_ADMINS; } else if ( wcsstr(pszPrincipal, TEXT("system")) != NULL) { // SYSTEM
pSidIdentifierAuthority = &SidIdentifierNTAuthority; Count = 1; dwRID[0] = SECURITY_LOCAL_SYSTEM_RID; } else if ( wcsstr(pszPrincipal, TEXT("interactive")) != NULL) { // INTERACTIVE
pSidIdentifierAuthority = &SidIdentifierNTAuthority; Count = 1; dwRID[0] = SECURITY_INTERACTIVE_RID; } else if ( wcsstr(pszPrincipal, TEXT("everyone")) != NULL) { // Everyone
pSidIdentifierAuthority = &SidIdentifierWORLDAuthority; Count = 1; dwRID[0] = SECURITY_WORLD_RID; } else { *pbWellKnownSID = FALSE; }
// IVANPASH
// Going through the above code *pbWellKnownSID and pSidIdentifierAuthority
// will always be in sync, but still there is warning on /W4
// so I added initializing pSidIdentifierAuthority to NULL and the
// additional check for pSidIdentifierAuthority in this if to make cl and prefast happy.
if ( *pbWellKnownSID && pSidIdentifierAuthority ) { if ( !AllocateAndInitializeSid( pSidIdentifierAuthority, (BYTE)Count, dwRID[0], dwRID[1], dwRID[2], dwRID[3], dwRID[4], dwRID[5], dwRID[6], dwRID[7], Sid) ) { returnValue = GetLastError(); } } else { // get regular account sid
DWORD sidSize; TCHAR refDomain [256]; DWORD refDomainSize; SID_NAME_USE snu;
sidSize = 0; refDomainSize = 255;
LookupAccountName (NULL, pszPrincipal, *Sid, &sidSize, refDomain, &refDomainSize, &snu);
returnValue = GetLastError();
if (returnValue == ERROR_INSUFFICIENT_BUFFER) { *Sid = (PSID) malloc (sidSize); if (!*Sid) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return GetLastError(); } refDomainSize = 255;
if (!LookupAccountName (NULL, pszPrincipal, *Sid, &sidSize, refDomain, &refDomainSize, &snu)) { free( *Sid ); *Sid = NULL; returnValue = GetLastError(); } else { returnValue = ERROR_SUCCESS; } } }
return returnValue; }
DWORD CopyACL( PACL OldACL, PACL NewACL) { ACL_SIZE_INFORMATION aclSizeInfo; LPVOID ace; ACE_HEADER *aceHeader; ULONG i;
GetAclInformation (OldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof (aclSizeInfo), AclSizeInformation);
//
// Copy all of the ACEs to the new ACL
//
for (i = 0; i < aclSizeInfo.AceCount; i++) { //
// Get the ACE and header info
//
if (!GetAce (OldACL, i, &ace)) return GetLastError();
aceHeader = (ACE_HEADER *) ace;
//
// Add the ACE to the new list
//
if (!AddAce (NewACL, ACL_REVISION, 0xffffffff, ace, aceHeader->AceSize)) return GetLastError(); }
return ERROR_SUCCESS; }
DWORD AddAccessAllowedACEToACL( PACL *Acl, DWORD PermissionMask, LPTSTR Principal) { ACL_SIZE_INFORMATION aclSizeInfo; int aclSize; DWORD returnValue = ERROR_SUCCESS; PSID principalSID = NULL; PACL oldACL; PACL newACL; BOOL bWellKnownSID = FALSE;
oldACL = *Acl;
returnValue = GetPrincipalSID (Principal, &principalSID, &bWellKnownSID); if (returnValue != ERROR_SUCCESS) { return returnValue; }
GetAclInformation (oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof (ACL_SIZE_INFORMATION), AclSizeInformation);
aclSize = aclSizeInfo.AclBytesInUse + sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) + GetLengthSid (principalSID) - sizeof (DWORD);
newACL = (PACL) new BYTE [aclSize];
if ( newACL == NULL ) { returnValue = ERROR_OUTOFMEMORY; goto cleanup;
}
if (!InitializeAcl (newACL, aclSize, ACL_REVISION)) { returnValue = GetLastError(); goto cleanup; }
returnValue = CopyACL (oldACL, newACL); if (returnValue != ERROR_SUCCESS) { goto cleanup; }
if (!AddAccessAllowedAce (newACL, ACL_REVISION2, PermissionMask, principalSID)) { returnValue = GetLastError(); goto cleanup; }
*Acl = newACL; newACL = NULL;
cleanup:
// BugFix: 57654 Whistler
// Prefix bug leaking memory in error condition.
// By setting the newACL to NULL above if we have
// relinquished the memory to *Acl, we avoid releasing
// memory we have passed back to the caller.
// EBK 5/5/2000
if (newACL) { delete [] newACL; newACL = NULL; }
if (principalSID) { if (bWellKnownSID) { FreeSid (principalSID); } else { free (principalSID); } }
return returnValue; }
DWORD RemovePrincipalFromACL ( PACL Acl, LPTSTR Principal) { ACL_SIZE_INFORMATION aclSizeInfo; ULONG i; LPVOID ace; ACCESS_ALLOWED_ACE *accessAllowedAce; ACCESS_DENIED_ACE *accessDeniedAce; SYSTEM_AUDIT_ACE *systemAuditAce; PSID principalSID = NULL; DWORD returnValue = ERROR_SUCCESS; ACE_HEADER *aceHeader; BOOL bWellKnownSID = FALSE;
returnValue = GetPrincipalSID (Principal, &principalSID, &bWellKnownSID); if (returnValue != ERROR_SUCCESS) { return returnValue; }
GetAclInformation (Acl, (LPVOID) &aclSizeInfo, (DWORD) sizeof (ACL_SIZE_INFORMATION), AclSizeInformation);
for (i = 0; i < aclSizeInfo.AceCount; i++) { if (!GetAce (Acl, i, &ace)) { returnValue = GetLastError(); break; }
aceHeader = (ACE_HEADER *) ace;
if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) { accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
if (EqualSid (principalSID, (PSID) &accessAllowedAce->SidStart)) { DeleteAce (Acl, i); break; } } else if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE) { accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
if (EqualSid (principalSID, (PSID) &accessDeniedAce->SidStart)) { DeleteAce (Acl, i); break; } } else if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE) { systemAuditAce = (SYSTEM_AUDIT_ACE *) ace;
if (EqualSid (principalSID, (PSID) &systemAuditAce->SidStart)) { DeleteAce (Acl, i); break; } } }
if (principalSID) { if (bWellKnownSID) { FreeSid (principalSID); } else { free (principalSID); } }
return returnValue; }
DWORD MakeSDAbsolute( PSECURITY_DESCRIPTOR OldSD, PSECURITY_DESCRIPTOR *NewSD) { PSECURITY_DESCRIPTOR sd = NULL; DWORD descriptorSize; DWORD daclSize; DWORD saclSize; DWORD ownerSIDSize; DWORD groupSIDSize; PACL dacl = NULL; PACL sacl = NULL; PSID ownerSID = NULL; PSID groupSID = NULL; BOOL present; BOOL systemDefault;
//
// Get SACL
//
if (!GetSecurityDescriptorSacl (OldSD, &present, &sacl, &systemDefault)) { return GetLastError(); }
if (sacl && present) { saclSize = sacl->AclSize; } else { saclSize = 0; }
//
// Get DACL
//
if (!GetSecurityDescriptorDacl (OldSD, &present, &dacl, &systemDefault)) return GetLastError();
if (dacl && present) { daclSize = dacl->AclSize; } else { daclSize = 0; }
//
// Get Owner
//
if (!GetSecurityDescriptorOwner (OldSD, &ownerSID, &systemDefault)) { return GetLastError(); }
ownerSIDSize = GetLengthSid (ownerSID);
//
// Get Group
//
if (!GetSecurityDescriptorGroup (OldSD, &groupSID, &systemDefault)) { return GetLastError(); }
groupSIDSize = GetLengthSid (groupSID);
//
// Do the conversion
//
descriptorSize = 0;
MakeAbsoluteSD (OldSD, sd, &descriptorSize, dacl, &daclSize, sacl, &saclSize, ownerSID, &ownerSIDSize, groupSID, &groupSIDSize);
sd = (PSECURITY_DESCRIPTOR) new BYTE [SECURITY_DESCRIPTOR_MIN_LENGTH]; if (!sd) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return GetLastError(); } if (!InitializeSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION)) return GetLastError();
if (!MakeAbsoluteSD (OldSD, sd, &descriptorSize, dacl, &daclSize, sacl, &saclSize, ownerSID, &ownerSIDSize, groupSID, &groupSIDSize)) { return GetLastError(); }
*NewSD = sd; return ERROR_SUCCESS; }
DWORD SetNamedValueSD( HKEY RootKey, LPTSTR KeyName, LPTSTR ValueName, SECURITY_DESCRIPTOR *SD) { DWORD returnValue; DWORD disposition; HKEY registryKey;
//
// Create new key or open existing key
//
returnValue = RegCreateKeyEx (RootKey, KeyName, 0, TEXT(""), 0, KEY_ALL_ACCESS, NULL, ®istryKey, &disposition); if (returnValue != ERROR_SUCCESS) { return returnValue; }
//
// Write the security descriptor
//
returnValue = RegSetValueEx (registryKey, ValueName, 0, REG_BINARY, (LPBYTE) SD, GetSecurityDescriptorLength (SD)); if (returnValue != ERROR_SUCCESS) { return returnValue; }
RegCloseKey (registryKey);
return ERROR_SUCCESS; }
DWORD RemovePrincipalFromNamedValueSD ( HKEY RootKey, LPTSTR KeyName, LPTSTR ValueName, LPTSTR Principal) { DWORD returnValue = ERROR_SUCCESS; SECURITY_DESCRIPTOR *sd = NULL; SECURITY_DESCRIPTOR *sdSelfRelative = NULL; SECURITY_DESCRIPTOR *sdAbsolute = NULL; DWORD secDescSize; BOOL present; BOOL defaultDACL; PACL dacl = NULL; BOOL newSD = FALSE; BOOL fFreeAbsolute = TRUE;
returnValue = GetNamedValueSD (RootKey, KeyName, ValueName, &sd, &newSD);
//
// Get security descriptor from registry or create a new one
//
if (returnValue != ERROR_SUCCESS) { return returnValue; }
if (!GetSecurityDescriptorDacl (sd, &present, &dacl, &defaultDACL)) { returnValue = GetLastError(); goto Cleanup; }
//
// If the security descriptor is new, add the required Principals to it
//
if (newSD) { AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("SYSTEM")); AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("INTERACTIVE")); }
//
// Remove the Principal that the caller wants removed
//
returnValue = RemovePrincipalFromACL (dacl, Principal); if (returnValue != ERROR_SUCCESS) { goto Cleanup; }
//
// Make the security descriptor absolute if it isn't new
//
if (!newSD) { MakeSDAbsolute ((PSECURITY_DESCRIPTOR) sd, (PSECURITY_DESCRIPTOR *) &sdAbsolute); fFreeAbsolute = TRUE; } else { sdAbsolute = sd; fFreeAbsolute = FALSE; }
//
// Set the discretionary ACL on the security descriptor
//
if (!SetSecurityDescriptorDacl (sdAbsolute, TRUE, dacl, FALSE)) { returnValue = GetLastError(); goto Cleanup; }
//
// Make the security descriptor self-relative so that we can
// store it in the registry
//
secDescSize = 0; MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize); sdSelfRelative = (SECURITY_DESCRIPTOR *) malloc (secDescSize); if (!sdSelfRelative) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); returnValue = GetLastError(); goto Cleanup; }
if (!MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize)) { returnValue = GetLastError(); goto Cleanup; }
//
// Store the security descriptor in the registry
//
SetNamedValueSD (RootKey, KeyName, ValueName, sdSelfRelative);
Cleanup: if (sd) { free (sd); } if (sdSelfRelative) { free (sdSelfRelative); } if (fFreeAbsolute && sdAbsolute) { free (sdAbsolute); }
return returnValue; }
DWORD AddAccessDeniedACEToACL( PACL *Acl, DWORD PermissionMask, LPTSTR Principal) { ACL_SIZE_INFORMATION aclSizeInfo; int aclSize; DWORD returnValue = ERROR_SUCCESS; PSID principalSID = NULL; PACL oldACL; PACL newACL; BOOL bWellKnownSID = FALSE;
oldACL = *Acl;
returnValue = GetPrincipalSID (Principal, &principalSID, &bWellKnownSID); if (returnValue != ERROR_SUCCESS) { return returnValue; }
GetAclInformation (oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof (ACL_SIZE_INFORMATION), AclSizeInformation);
aclSize = aclSizeInfo.AclBytesInUse + sizeof (ACL) + sizeof (ACCESS_DENIED_ACE) + GetLengthSid (principalSID) - sizeof (DWORD);
newACL = (PACL) new BYTE [aclSize];
if ( newACL == NULL ) { returnValue = ERROR_OUTOFMEMORY; goto cleanup;
}
if (!InitializeAcl (newACL, aclSize, ACL_REVISION)) { returnValue = GetLastError(); goto cleanup; }
if (!AddAccessDeniedAce (newACL, ACL_REVISION2, PermissionMask, principalSID)) { returnValue = GetLastError(); goto cleanup; }
returnValue = CopyACL (oldACL, newACL); if (returnValue != ERROR_SUCCESS) { goto cleanup; }
*Acl = newACL; newACL = NULL;
cleanup:
// BugFix: 57654 Whistler
// Prefix bug leaking memory in error condition.
// By setting the newACL to NULL above if we have
// relinquished the memory to *Acl, we avoid releasing
// memory we have passed back to the caller.
// EBK 5/5/2000
if (newACL) { delete[] newACL; newACL = NULL; }
if (principalSID) { if (bWellKnownSID) { FreeSid (principalSID); } else { free (principalSID); } }
return returnValue; }
DWORD AddPrincipalToNamedValueSD( HKEY RootKey, LPTSTR KeyName, LPTSTR ValueName, LPTSTR Principal, BOOL Permit) { DWORD returnValue = ERROR_SUCCESS; SECURITY_DESCRIPTOR *sd = NULL; SECURITY_DESCRIPTOR *sdSelfRelative = NULL; SECURITY_DESCRIPTOR *sdAbsolute = NULL; DWORD secDescSize; BOOL present; BOOL defaultDACL; PACL dacl; BOOL newSD = FALSE; BOOL fFreeAbsolute = TRUE;
returnValue = GetNamedValueSD (RootKey, KeyName, ValueName, &sd, &newSD);
//
// Get security descriptor from registry or create a new one
//
if (returnValue != ERROR_SUCCESS) { return returnValue; }
if (!GetSecurityDescriptorDacl (sd, &present, &dacl, &defaultDACL)) { returnValue = GetLastError(); goto Cleanup; }
if (newSD) { AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("SYSTEM")); AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, TEXT("INTERACTIVE")); }
//
// Add the Principal that the caller wants added
//
if (Permit) { returnValue = AddAccessAllowedACEToACL (&dacl, COM_RIGHTS_EXECUTE, Principal); } else { returnValue = AddAccessDeniedACEToACL (&dacl, GENERIC_ALL, Principal); }
if (returnValue != ERROR_SUCCESS) { goto Cleanup; }
//
// Make the security descriptor absolute if it isn't new
//
if (!newSD) { MakeSDAbsolute ((PSECURITY_DESCRIPTOR) sd, (PSECURITY_DESCRIPTOR *) &sdAbsolute); fFreeAbsolute = TRUE; } else { sdAbsolute = sd; fFreeAbsolute = FALSE; }
//
// Set the discretionary ACL on the security descriptor
//
if (!SetSecurityDescriptorDacl (sdAbsolute, TRUE, dacl, FALSE)) { returnValue = GetLastError(); goto Cleanup; }
//
// Make the security descriptor self-relative so that we can
// store it in the registry
//
secDescSize = 0; MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize); sdSelfRelative = (SECURITY_DESCRIPTOR *) malloc (secDescSize); if (!sdSelfRelative) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); returnValue = GetLastError(); goto Cleanup; }
if (!MakeSelfRelativeSD (sdAbsolute, sdSelfRelative, &secDescSize)) { returnValue = GetLastError(); goto Cleanup; }
//
// Store the security descriptor in the registry
//
SetNamedValueSD (RootKey, KeyName, ValueName, sdSelfRelative);
Cleanup: if (sd) { free (sd); } if (sdSelfRelative) { free (sdSelfRelative); } if (fFreeAbsolute && sdAbsolute) { free (sdAbsolute); }
return returnValue; }
DWORD ChangeDCOMAccessACL( LPTSTR Principal, BOOL SetPrincipal, BOOL Permit) { DWORD err;
if (SetPrincipal) { // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
// because its failure is not important (for example DefaultAccessPermission might
// not exist). The important call that must succeed is AddPrincipalToNamedValueSD
RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\OLE"), TEXT("DefaultAccessPermission"), Principal); err = AddPrincipalToNamedValueSD (HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\OLE"), TEXT("DefaultAccessPermission"), Principal, Permit); } else { err = RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\OLE"), TEXT("DefaultAccessPermission"), Principal); } return err; }
DWORD ChangeDCOMLaunchACL( LPTSTR Principal, BOOL SetPrincipal, BOOL Permit) { TCHAR keyName [256] = TEXT("Software\\Microsoft\\OLE"); DWORD err;
if (SetPrincipal) { // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
// because its failure is not important (for example DefaultAccessPermission might
// not exist). The important call that must succeed is AddPrincipalToNamedValueSD
RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE, keyName, TEXT("DefaultLaunchPermission"), Principal); err = AddPrincipalToNamedValueSD (HKEY_LOCAL_MACHINE, keyName, TEXT("DefaultLaunchPermission"), Principal, Permit); } else { err = RemovePrincipalFromNamedValueSD (HKEY_LOCAL_MACHINE, keyName, TEXT("DefaultLaunchPermission"), Principal); } return err; }
GUFM_RETURN GetUserFromMetabase( IMDCOM *pcCom, LPWSTR pszPath, DWORD dwUserMetaId, DWORD dwPasswordMetaId, USERNAME_STRING_TYPE ustUserBuf, PASSWORD_STRING_TYPE pstPasswordBuf) {
HRESULT hresTemp; GUFM_RETURN gufmReturn = GUFM_SUCCESS; METADATA_RECORD mdrData; DWORD dwRequiredDataLen; METADATA_HANDLE mhOpenHandle;
hresTemp = pcCom->ComMDOpenMetaObject(METADATA_MASTER_ROOT_HANDLE, pszPath, METADATA_PERMISSION_READ, OPEN_TIMEOUT_VALUE, &mhOpenHandle); if (FAILED(hresTemp)) { gufmReturn = GUFM_NO_PATH; } else { MD_SET_DATA_RECORD_EXT(&mdrData, dwUserMetaId, METADATA_NO_ATTRIBUTES, ALL_METADATA, STRING_METADATA, MAX_PATH * sizeof(TCHAR), (PBYTE)ustUserBuf)
hresTemp = pcCom->ComMDGetMetaData(mhOpenHandle, NULL, &mdrData, &dwRequiredDataLen);
if (FAILED(hresTemp) || (ustUserBuf[0] == (TCHAR)'\0')) { gufmReturn = GUFM_NO_USER_ID; } else { MD_SET_DATA_RECORD_EXT(&mdrData, dwPasswordMetaId, METADATA_NO_ATTRIBUTES, ALL_METADATA, STRING_METADATA, (LM20_PWLEN+1) * sizeof(TCHAR), (PBYTE)pstPasswordBuf)
hresTemp = pcCom->ComMDGetMetaData(mhOpenHandle, NULL, &mdrData, &dwRequiredDataLen); if (FAILED(hresTemp)) { gufmReturn = GUFM_NO_PASSWORD; } } pcCom->ComMDCloseMetaObject(mhOpenHandle); }
return gufmReturn; }
BOOL WritePasswordToMetabase( IMDCOM *pcCom, LPWSTR pszPath, DWORD dwPasswordMetaId, PASSWORD_STRING_TYPE pstPasswordBuf) { HRESULT hresReturn; METADATA_RECORD mdrData; METADATA_HANDLE mhOpenHandle;
hresReturn = pcCom->ComMDOpenMetaObject(METADATA_MASTER_ROOT_HANDLE, pszPath, METADATA_PERMISSION_WRITE, OPEN_TIMEOUT_VALUE, &mhOpenHandle); if (SUCCEEDED(hresReturn)) { MD_SET_DATA_RECORD_EXT(&mdrData, dwPasswordMetaId, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, sizeof(pstPasswordBuf), (PBYTE)pstPasswordBuf)
hresReturn = pcCom->ComMDSetMetaData(mhOpenHandle, NULL, &mdrData);
pcCom->ComMDCloseMetaObject(mhOpenHandle); }
return SUCCEEDED(hresReturn); }
BOOL DoesUserExist( LPWSTR strUsername, BOOL *fDisabled) { BYTE *pBuffer; INT err = NERR_Success; BOOL fReturn = FALSE;
*fDisabled = FALSE;
err = NetUserGetInfo( NULL, strUsername, 3, &pBuffer );
if ( err == NERR_Success ) { *fDisabled = !!(((PUSER_INFO_3)pBuffer)->usri3_flags & UF_ACCOUNTDISABLE); NetApiBufferFree( pBuffer ); fReturn = TRUE; }
return( fReturn ); }
NET_API_STATUS NetpNtStatusToApiStatus ( IN NTSTATUS NtStatus)
/*++
Routine Description:
This function takes an NT status code and maps it to the appropriate LAN Man error code.
Arguments:
NtStatus - Supplies the NT status.
Return Value:
Returns the appropriate LAN Man error code for the NT status.
--*/ { NET_API_STATUS error;
//
// A small optimization for the most common case.
//
if ( NtStatus == STATUS_SUCCESS ) { return NERR_Success; }
switch ( NtStatus ) { case STATUS_BUFFER_TOO_SMALL : return NERR_BufTooSmall;
case STATUS_FILES_OPEN : return NERR_OpenFiles;
case STATUS_CONNECTION_IN_USE : return NERR_DevInUse;
case STATUS_INVALID_LOGON_HOURS : return NERR_InvalidLogonHours;
case STATUS_INVALID_WORKSTATION : return NERR_InvalidWorkstation;
case STATUS_PASSWORD_EXPIRED : return NERR_PasswordExpired;
case STATUS_ACCOUNT_EXPIRED : return NERR_AccountExpired;
case STATUS_REDIRECTOR_NOT_STARTED : return NERR_NetNotStarted;
case STATUS_GROUP_EXISTS: return NERR_GroupExists;
case STATUS_INTERNAL_DB_CORRUPTION: return NERR_InvalidDatabase;
case STATUS_INVALID_ACCOUNT_NAME: return NERR_BadUsername;
case STATUS_INVALID_DOMAIN_ROLE: case STATUS_INVALID_SERVER_STATE: case STATUS_BACKUP_CONTROLLER: return NERR_NotPrimary;
case STATUS_INVALID_DOMAIN_STATE: return NERR_ACFNotLoaded;
case STATUS_MEMBER_IN_GROUP: return NERR_UserInGroup;
case STATUS_MEMBER_NOT_IN_GROUP: return NERR_UserNotInGroup;
case STATUS_NONE_MAPPED: case STATUS_NO_SUCH_GROUP: return NERR_GroupNotFound;
case STATUS_SPECIAL_GROUP: case STATUS_MEMBERS_PRIMARY_GROUP: return NERR_SpeGroupOp;
case STATUS_USER_EXISTS: return NERR_UserExists;
case STATUS_NO_SUCH_USER: return NERR_UserNotFound;
case STATUS_PRIVILEGE_NOT_HELD: return ERROR_ACCESS_DENIED;
case STATUS_LOGON_SERVER_CONFLICT: return NERR_LogonServerConflict;
case STATUS_TIME_DIFFERENCE_AT_DC: return NERR_TimeDiffAtDC;
case STATUS_SYNCHRONIZATION_REQUIRED: return NERR_SyncRequired;
case STATUS_WRONG_PASSWORD_CORE: return NERR_BadPasswordCore;
case STATUS_DOMAIN_CONTROLLER_NOT_FOUND: return NERR_DCNotFound;
case STATUS_PASSWORD_RESTRICTION: return NERR_PasswordTooShort;
case STATUS_ALREADY_DISCONNECTED: return NERR_Success;
default:
//
// Use the system routine to do the mapping to ERROR_ codes.
//
#ifndef WIN32_CHICAGO
error = RtlNtStatusToDosError( NtStatus );
if ( error != (NET_API_STATUS)NtStatus ) { return error; } #endif // WIN32_CHICAGO
//
// Could not map the NT status to anything appropriate.
//
return NERR_InternalError; } } // NetpNtStatusToApiStatus
NET_API_STATUS UaspGetDomainId( IN LPCWSTR ServerName OPTIONAL, OUT PSAM_HANDLE SamServerHandle OPTIONAL, OUT PPOLICY_ACCOUNT_DOMAIN_INFO * AccountDomainInfo ) /*++
Routine Description: Return a domain ID of the account domain of a server. Arguments: ServerName - A pointer to a string containing the name of the Domain Controller (DC) to query. A NULL pointer or string specifies the local machine. SamServerHandle - Returns the SAM connection handle if the caller wants it. DomainId - Receives a pointer to the domain ID. Caller must deallocate buffer using NetpMemoryFree. Return Value: Error code for the operation. --*/ { NET_API_STATUS NetStatus; NTSTATUS Status; SAM_HANDLE LocalSamHandle = NULL; ACCESS_MASK LSADesiredAccess; LSA_HANDLE LSAPolicyHandle = NULL; OBJECT_ATTRIBUTES LSAObjectAttributes; UNICODE_STRING ServerNameString;
//
// Connect to the SAM server
//
RtlInitUnicodeString( &ServerNameString, ServerName );
Status = SamConnect( &ServerNameString, &LocalSamHandle, SAM_SERVER_LOOKUP_DOMAIN, NULL);
if ( !NT_SUCCESS(Status)) { LocalSamHandle = NULL; NetStatus = NetpNtStatusToApiStatus( Status ); goto Cleanup; }
//
// Open LSA to read account domain info.
//
if ( AccountDomainInfo != NULL) { //
// set desired access mask.
//
LSADesiredAccess = POLICY_VIEW_LOCAL_INFORMATION;
InitializeObjectAttributes( &LSAObjectAttributes, NULL, // Name
0, // Attributes
NULL, // Root
NULL ); // Security Descriptor
Status = LsaOpenPolicy( &ServerNameString, &LSAObjectAttributes, LSADesiredAccess, &LSAPolicyHandle );
if( !NT_SUCCESS(Status) ) { NetStatus = NetpNtStatusToApiStatus( Status ); goto Cleanup; }
//
// now read account domain info from LSA.
//
Status = LsaQueryInformationPolicy( LSAPolicyHandle, PolicyAccountDomainInformation, (PVOID *) AccountDomainInfo );
if( !NT_SUCCESS(Status) ) { NetStatus = NetpNtStatusToApiStatus( Status ); goto Cleanup; } }
//
// Return the SAM connection handle to the caller if he wants it.
// Otherwise, disconnect from SAM.
//
if ( ARGUMENT_PRESENT( SamServerHandle ) ) { *SamServerHandle = LocalSamHandle; LocalSamHandle = NULL; }
NetStatus = NERR_Success;
//
// Cleanup locally used resources
//
Cleanup: if ( LocalSamHandle != NULL ) { (VOID) SamCloseHandle( LocalSamHandle ); }
if( LSAPolicyHandle != NULL ) { LsaClose( LSAPolicyHandle ); }
return NetStatus; } // UaspGetDomainId
NET_API_STATUS SampCreateFullSid( IN PSID DomainSid, IN ULONG Rid, OUT PSID *AccountSid) /*++
Routine Description: This function creates a domain account sid given a domain sid and the relative id of the account within the domain. The returned Sid may be freed with LocalFree. --*/ { NET_API_STATUS NetStatus; NTSTATUS IgnoreStatus; UCHAR AccountSubAuthorityCount; ULONG AccountSidLength; PULONG RidLocation;
//
// Calculate the size of the new sid
//
AccountSubAuthorityCount = *RtlSubAuthorityCountSid(DomainSid) + (UCHAR)1; AccountSidLength = RtlLengthRequiredSid(AccountSubAuthorityCount);
//
// Allocate space for the account sid
//
*AccountSid = LocalAlloc(LMEM_ZEROINIT,AccountSidLength); if (*AccountSid == NULL) { NetStatus = ERROR_NOT_ENOUGH_MEMORY; } else { //
// Copy the domain sid into the first part of the account sid
//
IgnoreStatus = RtlCopySid(AccountSidLength, *AccountSid, DomainSid); ASSERT(NT_SUCCESS(IgnoreStatus));
//
// Increment the account sid sub-authority count
//
*RtlSubAuthorityCountSid(*AccountSid) = AccountSubAuthorityCount;
//
// Add the rid as the final sub-authority
//
RidLocation = RtlSubAuthoritySid(*AccountSid, AccountSubAuthorityCount-1); *RidLocation = Rid;
NetStatus = NERR_Success; }
return(NetStatus); }
BOOL GetGuestUserNameForDomain_FastWay( LPTSTR szDomainToLookUp, LPTSTR lpGuestUsrName, DWORD cchGuestUsrName) { HRESULT hr = S_OK; BOOL fReturn = FALSE; NET_API_STATUS NetStatus; SAM_HANDLE SamServerHandle = NULL; // for UaspGetDomainId()
PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo = NULL; PSID pAccountSid = NULL; PSID pDomainSid = NULL; SID_NAME_USE sidNameUse = SidTypeUser; // for LookupAccountSid()
TCHAR szUserName[UNLEN+1]; DWORD cbName = UNLEN+1; TCHAR szReferencedDomainName[UNLEN+1]; // use UNLEN because DNLEN is too small
DWORD cbReferencedDomainName = sizeof(szReferencedDomainName);
// make sure not to return back gobble-d-gook
*lpGuestUsrName = TEXT('\0');
//
// Get the Sid for the specified Domain
//
// szDomainToLookUp=NULL for local machine
NetStatus = UaspGetDomainId( szDomainToLookUp,&SamServerHandle,&pAccountDomainInfo ); if ( NetStatus != NERR_Success ) { goto GetGuestUserNameForDomain_FastWay_Exit; } pDomainSid = pAccountDomainInfo->DomainSid; //
// Use the Domain Sid and the well known Guest RID to create the Real Guest Sid
//
// Well-known users ...
// DOMAIN_USER_RID_ADMIN (0x000001F4L)
// DOMAIN_USER_RID_GUEST (0x000001F5L)
NetStatus = NERR_InternalError; NetStatus = SampCreateFullSid(pDomainSid, DOMAIN_USER_RID_GUEST, &pAccountSid); if ( NetStatus != NERR_Success ) { goto GetGuestUserNameForDomain_FastWay_Exit; }
//
// Check if the SID is valid
//
if (0 == IsValidSid(pAccountSid)) { goto GetGuestUserNameForDomain_FastWay_Exit; }
//
// Retrieve the UserName for the specified SID
//
*szUserName = TEXT('\0'); *szReferencedDomainName = TEXT('\0'); // szDomainToLookUp=NULL for local machine
if (!LookupAccountSid(szDomainToLookUp, pAccountSid, szUserName, &cbName, szReferencedDomainName, &cbReferencedDomainName, &sidNameUse)) { goto GetGuestUserNameForDomain_FastWay_Exit; }
// Return the guest user name that we got.
hr = StringCchCopy(lpGuestUsrName, cchGuestUsrName, szUserName); if ( FAILED(hr) ) { *lpGuestUsrName = TEXT('\0'); goto GetGuestUserNameForDomain_FastWay_Exit; }
// Wow, after all that, we must have succeeded
fReturn = TRUE;
GetGuestUserNameForDomain_FastWay_Exit: // Free the Domain info if we got some
if (pAccountDomainInfo) { NetpMemoryFree(pAccountDomainInfo); } // Free the sid if we had allocated one
if (pAccountSid) { LocalFree(pAccountSid); } return fReturn; }
BOOL GetGuestUserName_SlowWay( LPWSTR lpGuestUsrName, DWORD cchGuestUsrName) { HRESULT hr = S_OK; LPWSTR ServerName = NULL; // default to local machine
DWORD Level = 1; // to retrieve info of all local and global normal user accounts
DWORD Index = 0; DWORD EntriesRequested = 5; DWORD PreferredMaxLength = 1024; DWORD ReturnedEntryCount = 0; PVOID SortedBuffer = NULL; NET_DISPLAY_USER *p = NULL; DWORD i=0; int err = 0; BOOL fStatus = TRUE;
while (fStatus) { err = NetQueryDisplayInformation(ServerName, Level, Index, EntriesRequested, PreferredMaxLength, &ReturnedEntryCount, &SortedBuffer); if (err == NERR_Success) { fStatus = FALSE; }
if (err == NERR_Success || err == ERROR_MORE_DATA) { p = (NET_DISPLAY_USER *)SortedBuffer; i = 0; while (i < ReturnedEntryCount && (p[i].usri1_user_id != DOMAIN_USER_RID_GUEST)) { i++; }
if (i == ReturnedEntryCount) { if (err == ERROR_MORE_DATA) { // need to get more entries
Index = p[i-1].usri1_next_index; } } else { hr = StringCchCopyW(lpGuestUsrName, cchGuestUsrName, p[i].usri1_name); if ( FAILED(hr) ) { NetApiBufferFree(SortedBuffer); SortedBuffer = NULL; *lpGuestUsrName = TEXT('\0'); return FALSE; }
fStatus = FALSE; } } else { if ( SortedBuffer != NULL ) { NetApiBufferFree(SortedBuffer); SortedBuffer = NULL; }
return FALSE; } NetApiBufferFree(SortedBuffer); SortedBuffer = NULL; }
return TRUE; }
BOOL GetGuestUserName( LPTSTR lpOutGuestUsrName, DWORD cchOutGuestUsrName) { HRESULT hr = S_OK; TCHAR szGuestUsrName[UNLEN+1]; LPTSTR pszComputerName = NULL;
// try to retrieve the guest username the fast way
// meaning = lookup the domain sid, and the well known guest rid, to get the guest sid.
// then look it up. The reason for this function is that on large domains with mega users
// the account can be quickly looked up.
if (!GetGuestUserNameForDomain_FastWay(pszComputerName, szGuestUsrName, UNLEN+1)) { // if the fast way failed for some reason, then let's do it
// the slow way, since this way always used to work, only on large domains (1 mil users)
// it could take 24hrs (since this function actually enumerates thru the domain)
if (!GetGuestUserName_SlowWay(szGuestUsrName, UNLEN+1)) { return FALSE; } }
// Return back the username
hr = StringCchCopyW(lpOutGuestUsrName, cchOutGuestUsrName, szGuestUsrName); if ( FAILED(hr) ) { return FALSE; }
return TRUE; }
int GetGuestGrpName( LPTSTR lpGuestGrpName) { LPCTSTR ServerName = NULL; // local machine
DWORD cbName = UNLEN+1; // use UNLEN because DNLEN is too small
TCHAR ReferencedDomainName[UNLEN+1]; DWORD cbReferencedDomainName = sizeof(ReferencedDomainName) / sizeof(TCHAR); SID_NAME_USE sidNameUse = SidTypeUser; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID GuestsSid = NULL;
AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0, &GuestsSid);
LookupAccountSid(ServerName, GuestsSid, lpGuestGrpName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &sidNameUse);
if (GuestsSid) { FreeSid(GuestsSid); }
return 0; }
INT RegisterAccountToLocalGroup( LPCTSTR szAccountName, LPCTSTR szLocalGroupName, BOOL fAction) { HRESULT hr = S_OK; int err; PSID pSID = NULL; BOOL bWellKnownSID = FALSE; TCHAR szLocalizedLocalGroupName[GNLEN + 1] = TEXT( "\0" ) ; WCHAR wszLocalGroupName[_MAX_PATH]; LOCALGROUP_MEMBERS_INFO_0 buf;
// get the sid of szAccountName
err = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID); if (err != ERROR_SUCCESS) { return (err); }
// Get the localized LocalGroupName
if (_wcsicmp(szLocalGroupName, TEXT("Guests")) == 0) { GetGuestGrpName(szLocalizedLocalGroupName); } else { hr = StringCchCopy(szLocalizedLocalGroupName, ARRAYSIZE(szLocalizedLocalGroupName), szLocalGroupName); if ( FAILED(hr) ) { err = (INT)HRESULTTOWIN32(hr); goto exit; } }
// transfer szLocalGroupName to WCHAR
hr = StringCchCopyW(wszLocalGroupName, ARRAYSIZE(wszLocalGroupName), szLocalizedLocalGroupName); if ( FAILED(hr) ) { err = (INT)HRESULTTOWIN32(hr); goto exit; }
buf.lgrmi0_sid = pSID;
if (fAction) { err = NetLocalGroupAddMembers(NULL, wszLocalGroupName, 0, (LPBYTE)&buf, 1); } else { err = NetLocalGroupDelMembers(NULL, wszLocalGroupName, 0, (LPBYTE)&buf, 1); }
exit: if (pSID) { if (bWellKnownSID) { FreeSid (pSID); } else { free (pSID); } }
return (err); }
void InitLsaString( PLSA_UNICODE_STRING LsaString, LPWSTR String) { DWORD StringLength;
if (String == NULL) { LsaString->Buffer = NULL; LsaString->Length = 0; LsaString->MaximumLength = 0; return; }
StringLength = (DWORD)wcslen(String); LsaString->Buffer = String; LsaString->Length = (USHORT) StringLength * sizeof(WCHAR); LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR); }
DWORD OpenPolicy( LPTSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle) { DWORD Error; LSA_OBJECT_ATTRIBUTES ObjectAttributes; LSA_UNICODE_STRING ServerString; PLSA_UNICODE_STRING Server = NULL; SECURITY_QUALITY_OF_SERVICE QualityOfService;
QualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); QualityOfService.ImpersonationLevel = SecurityImpersonation; QualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; QualityOfService.EffectiveOnly = FALSE;
//
// The two fields that must be set are length and the quality of service.
//
ObjectAttributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES); ObjectAttributes.RootDirectory = NULL; ObjectAttributes.ObjectName = NULL; ObjectAttributes.Attributes = 0; ObjectAttributes.SecurityDescriptor = NULL; ObjectAttributes.SecurityQualityOfService = &QualityOfService;
if (ServerName != NULL) { //
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in
//
InitLsaString(&ServerString,ServerName); Server = &ServerString; } //
// Attempt to open the policy for all access
//
Error = LsaOpenPolicy(Server,&ObjectAttributes,DesiredAccess,PolicyHandle); return(Error);
}
INT RegisterAccountUserRights( LPCTSTR szAccountName, BOOL fAction, BOOL fSpecicaliWamAccount) { int err; PSID pSID = NULL; BOOL bWellKnownSID = FALSE; LSA_UNICODE_STRING UserRightString; LSA_HANDLE PolicyHandle = NULL;
// get the sid of szAccountName
err = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID); if (err != ERROR_SUCCESS) { return (err); }
err = OpenPolicy(NULL, POLICY_ALL_ACCESS,&PolicyHandle); if ( err == NERR_Success ) { if (fAction) { // defined in ntsecapi.h and ntlsa.h
//#define SE_INTERACTIVE_LOGON_NAME TEXT("SeInteractiveLogonRight")
//#define SE_NETWORK_LOGON_NAME TEXT("SeNetworkLogonRight")
//#define SE_BATCH_LOGON_NAME TEXT("SeBatchLogonRight")
//#define SE_SERVICE_LOGON_NAME TEXT("SeServiceLogonRight")
// Defined in winnt.h
//#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege")
//#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege")
//#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege")
//#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege")
//#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege")
//#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege")
//#define SE_TCB_NAME TEXT("SeTcbPrivilege")
//#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege")
//#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege")
//#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege")
//#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege")
//#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege")
//#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege")
//#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege")
//#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege")
//#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege")
//#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
//#define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
//#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
//#define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
//#define SE_AUDIT_NAME TEXT("SeAuditPrivilege")
//#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege")
//#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege")
//#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege")
//#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege")
//#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege")
//#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege")
if (fSpecicaliWamAccount) { // no interactive logon for iwam!
InitLsaString(&UserRightString, SE_NETWORK_LOGON_NAME); err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1); InitLsaString(&UserRightString, SE_BATCH_LOGON_NAME); err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1); } else { InitLsaString(&UserRightString, SE_INTERACTIVE_LOGON_NAME); err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1); InitLsaString(&UserRightString, SE_NETWORK_LOGON_NAME); err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1); InitLsaString(&UserRightString, SE_BATCH_LOGON_NAME); err = LsaAddAccountRights(PolicyHandle, pSID, &UserRightString, 1); } } else { InitLsaString(&UserRightString, SE_INTERACTIVE_LOGON_NAME); err = LsaRemoveAccountRights(PolicyHandle, pSID, FALSE, &UserRightString,1); InitLsaString(&UserRightString, SE_NETWORK_LOGON_NAME); err = LsaRemoveAccountRights(PolicyHandle, pSID, FALSE, &UserRightString,1); InitLsaString(&UserRightString, SE_BATCH_LOGON_NAME); err = LsaRemoveAccountRights(PolicyHandle, pSID, FALSE, &UserRightString,1); }
LsaClose(PolicyHandle); }
if (pSID) { if (bWellKnownSID) { FreeSid (pSID); } else { free (pSID); } }
return (err); }
int ChangeUserPassword( IN LPTSTR szUserName, IN LPTSTR szNewPassword) { HRESULT hr = S_OK; int iReturn = TRUE; USER_INFO_1003 pi1003; NET_API_STATUS nas; TCHAR szRawComputerName[CNLEN + 10]; DWORD dwLen = CNLEN + 10; TCHAR szComputerName[CNLEN + 10]; TCHAR szCopyOfUserName[UNLEN+10]; TCHAR szTempFullUserName[(CNLEN + 10) + (UNLEN+1)]; LPTSTR pch = NULL;
hr = StringCchCopy(szCopyOfUserName, ARRAYSIZE(szCopyOfUserName), szUserName); if ( FAILED(hr) ) { iReturn = FALSE; goto ChangeUserPassword_Exit; }
//iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ChangeUserPassword().Start.name=%s,pass=%s"),szCopyOfUserName,szNewPassword));
if ( !GetComputerName( szRawComputerName, &dwLen )) { iReturn = FALSE; goto ChangeUserPassword_Exit; }
// Make a copy to be sure not to move the pointer around.
hr = StringCchCopy(szTempFullUserName, ARRAYSIZE(szTempFullUserName), szCopyOfUserName); if ( FAILED(hr) ) { iReturn = FALSE; goto ChangeUserPassword_Exit; }
// Check if there is a "\" in there.
pch = wcschr(szTempFullUserName, '\\'); if (pch) { // szCopyOfUserName should now go from something like this:
// mycomputer\myuser
// to this myuser
hr = StringCchCopy(szCopyOfUserName, ARRAYSIZE(szCopyOfUserName), pch+1); if ( FAILED(hr) ) { iReturn = FALSE; goto ChangeUserPassword_Exit; } // trim off the '\' character to leave just the domain\computername so we can check against it.
*pch = '\0'; // compare the szTempFullUserName with the local computername.
if (0 == _wcsicmp(szRawComputerName, szTempFullUserName)) { // the computername\username has a hardcoded computername in it.
// lets try to get only the username
// look szCopyOfusername is already set
} else { // the local computer machine name
// and the specified username are different, so get out
// and don't even try to change this user\password since
// it's probably a domain\username
// return true -- saying that we did in fact change the passoword.
// we really didn't but we can't
iReturn = TRUE; goto ChangeUserPassword_Exit; } }
// Make sure the computername has a \\ in front of it
if ( szRawComputerName[0] != '\\' ) { hr = StringCchCopyW(szComputerName, ARRAYSIZE(szComputerName), L"\\\\"); if ( FAILED(hr) ) { iReturn = FALSE; goto ChangeUserPassword_Exit; } } hr = StringCchCatW(szComputerName, ARRAYSIZE(szComputerName), szRawComputerName); if ( FAILED(hr) ) { iReturn = FALSE; goto ChangeUserPassword_Exit; }
//
// administrative over-ride of existing password
//
// by this time szCopyOfUserName
// should not look like mycomputername\username but it should look like username.
pi1003.usri1003_password = szNewPassword; nas = NetUserSetInfo( szComputerName, // computer name
szCopyOfUserName, // username
1003, // info level
(LPBYTE)&pi1003, // new info
NULL );
if(nas != NERR_Success) { iReturn = FALSE; goto ChangeUserPassword_Exit; }
ChangeUserPassword_Exit: //iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ChangeUserPassword().End.Ret=%d"),iReturn));
return iReturn; }
//
// Create InternetGuest Account
//
BOOL CreateUser( LPCTSTR szUsername, LPCTSTR szPassword, LPCTSTR szComment, LPCTSTR szFullName, BOOL fSpecialiWamAccount) { INT err = NERR_Success; BYTE *pBuffer; WCHAR defGuest[UNLEN+1]; TCHAR defGuestGroup[GNLEN+1]; WCHAR wchGuestGroup[GNLEN+1]; WCHAR wchUsername[UNLEN+1]; WCHAR wchPassword[LM20_PWLEN+1]; BOOL fRet;
fRet = GetGuestUserName(defGuest, UNLEN+1);
if ( !fRet ) { return FALSE; }
GetGuestGrpName(defGuestGroup);
SecureZeroMemory((PVOID)wchUsername, sizeof(wchUsername)); SecureZeroMemory((PVOID)wchPassword, sizeof(wchPassword)); wcsncpy(wchGuestGroup, defGuestGroup, GNLEN); wcsncpy(wchUsername, szUsername, UNLEN); wcsncpy(wchPassword, szPassword, LM20_PWLEN);
err = NetUserGetInfo( NULL, defGuest, 3, &pBuffer );
if ( err == NERR_Success ) { WCHAR wchComment[MAXCOMMENTSZ+1]; WCHAR wchFullName[UNLEN+1];
memset((PVOID)wchComment, 0, sizeof(wchComment)); memset((PVOID)wchFullName, 0, sizeof(wchFullName)); wcsncpy(wchComment, szComment, MAXCOMMENTSZ); wcsncpy(wchFullName, szFullName, UNLEN);
USER_INFO_3 *lpui3 = (USER_INFO_3 *)pBuffer;
lpui3->usri3_name = wchUsername; lpui3->usri3_password = wchPassword; lpui3->usri3_flags &= ~ UF_ACCOUNTDISABLE; lpui3->usri3_flags |= UF_DONT_EXPIRE_PASSWD; lpui3->usri3_acct_expires = TIMEQ_FOREVER;
lpui3->usri3_comment = wchComment; lpui3->usri3_usr_comment = wchComment; lpui3->usri3_full_name = wchFullName; lpui3->usri3_primary_group_id = DOMAIN_GROUP_RID_USERS;
DWORD parm_err;
err = NetUserAdd( NULL, 3, pBuffer, &parm_err );
if ( err != NERR_Success ) { if ( err == NERR_UserExists ) { // see if we can just change the password.
if (TRUE == ChangeUserPassword((LPTSTR) szUsername, (LPTSTR) szPassword)) { err = NERR_Success; } } }
NetApiBufferFree( pBuffer ); } if ( err == NERR_Success ) { // add it to the guests or IIS_WPG group
if (fSpecialiWamAccount) { RegisterAccountToLocalGroup(szUsername, IIS_WP_GROUP, TRUE); } else { RegisterAccountToLocalGroup(szUsername, TEXT("Guests"), TRUE); }
// add certain user rights to this account
RegisterAccountUserRights(szUsername, TRUE, fSpecialiWamAccount); }
return err == NERR_Success; }
INT DeleteGuestUser( LPCTSTR szUsername) { INT err = NERR_Success; BOOL fDisabled; WCHAR wchUsername[UNLEN+1];
wcsncpy(wchUsername, szUsername, UNLEN);
if (FALSE == DoesUserExist(wchUsername,&fDisabled)) { return err; }
// remove it from the guests group
RegisterAccountToLocalGroup(szUsername, TEXT("Guests"), FALSE);
// remove certain user rights of this account
RegisterAccountUserRights(szUsername, FALSE, TRUE);
err = ::NetUserDel( TEXT(""), wchUsername );
return err; }
#define MAX_REALISTIC_RESOURCE_LEN MAX_PATH
BOOL CreateUserAccount( LPTSTR pszAnonyName, LPTSTR pszAnonyPass, DWORD dwUserCommentResourceId, DWORD dwUserFullNameResourceId, BOOL fSpecicaliWamAccount) { BOOL fReturn = FALSE; WCHAR pszComment[MAX_REALISTIC_RESOURCE_LEN]; WCHAR pszFullName[MAX_REALISTIC_RESOURCE_LEN]; HMODULE hBinary;
//
// First Load the Resources
//
hBinary = GetModuleHandle(TEXT("svcext"));
if (hBinary != NULL) { fReturn = LoadString(hBinary, dwUserCommentResourceId, pszComment, MAX_REALISTIC_RESOURCE_LEN); if (fReturn) { fReturn = LoadString(hBinary, dwUserFullNameResourceId, pszFullName, MAX_REALISTIC_RESOURCE_LEN); }
}
if (fReturn) { fReturn = CreateUser(pszAnonyName, pszAnonyPass, pszComment, pszFullName, fSpecicaliWamAccount ); }
if (fReturn) { ChangeDCOMLaunchACL(pszAnonyName, TRUE, TRUE); /* removed when fixing bug 355249
ChangeDCOMAccessACL(pszAnonyName, TRUE, TRUE); */ }
return fReturn; }
typedef void (*P_SslGenerateRandomBits)( PUCHAR pRandomData, LONG size ); P_SslGenerateRandomBits ProcSslGenerateRandomBits = NULL;
BOOL ValidatePassword( IN LPCTSTR UserName, IN LPCTSTR Domain, IN LPCTSTR Password) /*++
Routine Description: Uses SSPI to validate the specified password Arguments: UserName - Supplies the user name Domain - Supplies the user's domain Password - Supplies the password Return Value: TRUE if the password is valid. FALSE otherwise. --*/ { SECURITY_STATUS SecStatus; SECURITY_STATUS AcceptStatus; SECURITY_STATUS InitStatus; CredHandle ClientCredHandle; CredHandle ServerCredHandle; BOOL ClientCredAllocated = FALSE; BOOL ServerCredAllocated = FALSE; CtxtHandle ClientContextHandle; CtxtHandle ServerContextHandle; TimeStamp Lifetime; ULONG ContextAttributes; PSecPkgInfo PackageInfo = NULL; ULONG ClientFlags; ULONG ServerFlags; TCHAR TargetName[100]; SEC_WINNT_AUTH_IDENTITY_W AuthIdentity; BOOL Validated = FALSE; SecBufferDesc NegotiateDesc; SecBuffer NegotiateBuffer; SecBufferDesc ChallengeDesc; SecBuffer ChallengeBuffer; SecBufferDesc AuthenticateDesc; SecBuffer AuthenticateBuffer;
AuthIdentity.User = (LPWSTR)UserName; AuthIdentity.UserLength = lstrlenW(UserName); AuthIdentity.Domain = (LPWSTR)Domain; AuthIdentity.DomainLength = lstrlenW(Domain); AuthIdentity.Password = (LPWSTR)Password; AuthIdentity.PasswordLength = lstrlenW(Password); AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
NegotiateBuffer.pvBuffer = NULL; ChallengeBuffer.pvBuffer = NULL; AuthenticateBuffer.pvBuffer = NULL;
//
// Get info about the security packages.
//
SecStatus = QuerySecurityPackageInfo( TEXT("NTLM"), &PackageInfo );
if ( SecStatus != STATUS_SUCCESS ) { goto error_exit; }
//
// Acquire a credential handle for the server side
//
SecStatus = AcquireCredentialsHandle( NULL, TEXT("NTLM"), SECPKG_CRED_INBOUND, NULL, &AuthIdentity, NULL, NULL, &ServerCredHandle, &Lifetime );
if ( SecStatus != STATUS_SUCCESS ) { goto error_exit; } ServerCredAllocated = TRUE;
//
// Acquire a credential handle for the client side
//
SecStatus = AcquireCredentialsHandle( NULL, // New principal
TEXT("NTLM"), SECPKG_CRED_OUTBOUND, NULL, &AuthIdentity, NULL, NULL, &ClientCredHandle, &Lifetime );
if ( SecStatus != STATUS_SUCCESS ) { goto error_exit; } ClientCredAllocated = TRUE;
//
// Get the NegotiateMessage (ClientSide)
//
NegotiateDesc.ulVersion = 0; NegotiateDesc.cBuffers = 1; NegotiateDesc.pBuffers = &NegotiateBuffer;
NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken; NegotiateBuffer.BufferType = SECBUFFER_TOKEN; NegotiateBuffer.pvBuffer = LocalAlloc( 0, NegotiateBuffer.cbBuffer ); if ( NegotiateBuffer.pvBuffer == NULL ) { goto error_exit; }
ClientFlags = ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT;
InitStatus = InitializeSecurityContext( &ClientCredHandle, NULL, // No Client context yet
NULL, ClientFlags, 0, // Reserved 1
SECURITY_NATIVE_DREP, NULL, // No initial input token
0, // Reserved 2
&ClientContextHandle, &NegotiateDesc, &ContextAttributes, &Lifetime );
if ( !NT_SUCCESS(InitStatus) ) { goto error_exit; }
//
// Get the ChallengeMessage (ServerSide)
//
NegotiateBuffer.BufferType |= SECBUFFER_READONLY; ChallengeDesc.ulVersion = 0; ChallengeDesc.cBuffers = 1; ChallengeDesc.pBuffers = &ChallengeBuffer;
ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken; ChallengeBuffer.BufferType = SECBUFFER_TOKEN; ChallengeBuffer.pvBuffer = LocalAlloc( 0, ChallengeBuffer.cbBuffer ); if ( ChallengeBuffer.pvBuffer == NULL ) { goto error_exit; } ServerFlags = ASC_REQ_EXTENDED_ERROR;
AcceptStatus = AcceptSecurityContext( &ServerCredHandle, NULL, // No Server context yet
&NegotiateDesc, ServerFlags, SECURITY_NATIVE_DREP, &ServerContextHandle, &ChallengeDesc, &ContextAttributes, &Lifetime );
if ( !NT_SUCCESS(AcceptStatus) ) { goto error_exit; }
if (InitStatus != STATUS_SUCCESS) { //
// Get the AuthenticateMessage (ClientSide)
//
ChallengeBuffer.BufferType |= SECBUFFER_READONLY; AuthenticateDesc.ulVersion = 0; AuthenticateDesc.cBuffers = 1; AuthenticateDesc.pBuffers = &AuthenticateBuffer;
AuthenticateBuffer.cbBuffer = PackageInfo->cbMaxToken; AuthenticateBuffer.BufferType = SECBUFFER_TOKEN; AuthenticateBuffer.pvBuffer = LocalAlloc( 0, AuthenticateBuffer.cbBuffer ); if ( AuthenticateBuffer.pvBuffer == NULL ) { goto error_exit; }
SecStatus = InitializeSecurityContext( NULL, &ClientContextHandle, TargetName, 0, 0, // Reserved 1
SECURITY_NATIVE_DREP, &ChallengeDesc, 0, // Reserved 2
&ClientContextHandle, &AuthenticateDesc, &ContextAttributes, &Lifetime );
if ( !NT_SUCCESS(SecStatus) ) { goto error_exit; }
if (AcceptStatus != STATUS_SUCCESS) { //
// Finally authenticate the user (ServerSide)
//
AuthenticateBuffer.BufferType |= SECBUFFER_READONLY;
SecStatus = AcceptSecurityContext( NULL, &ServerContextHandle, &AuthenticateDesc, ServerFlags, SECURITY_NATIVE_DREP, &ServerContextHandle, NULL, &ContextAttributes, &Lifetime );
if ( !NT_SUCCESS(SecStatus) ) { goto error_exit; } Validated = TRUE;
}
}
error_exit: if (ServerCredAllocated) { FreeCredentialsHandle( &ServerCredHandle ); } if (ClientCredAllocated) { FreeCredentialsHandle( &ClientCredHandle ); }
//
// Final Cleanup
//
if ( NegotiateBuffer.pvBuffer != NULL ) { (VOID) LocalFree( NegotiateBuffer.pvBuffer ); }
if ( ChallengeBuffer.pvBuffer != NULL ) { (VOID) LocalFree( ChallengeBuffer.pvBuffer ); }
if ( AuthenticateBuffer.pvBuffer != NULL ) { (VOID) LocalFree( AuthenticateBuffer.pvBuffer ); } return(Validated); }
DWORD ChangeAppIDAccessACL( LPTSTR AppID, LPTSTR Principal, BOOL SetPrincipal, BOOL Permit) { HRESULT hr = S_OK; TCHAR keyName [256]; DWORD err;
hr = StringCchCopy( keyName, ARRAYSIZE(keyName), TEXT("APPID\\") ); if ( FAILED(hr) ) { return HRESULTTOWIN32( hr ); }
hr = StringCchCat( keyName, ARRAYSIZE(keyName), AppID ); if ( FAILED(hr) ) { return HRESULTTOWIN32( hr ); }
if (SetPrincipal) { // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
// because its failure is not important (for example DefaultAccessPermission might
// not exist). The important call that must succeed is AddPrincipalToNamedValueSD
RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT, keyName, TEXT("AccessPermission"), Principal); err = AddPrincipalToNamedValueSD (HKEY_CLASSES_ROOT, keyName, TEXT("AccessPermission"), Principal, Permit); } else { err = RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT, keyName, TEXT("AccessPermission"), Principal); }
return err; }
DWORD ChangeAppIDLaunchACL( LPTSTR AppID, LPTSTR Principal, BOOL SetPrincipal, BOOL Permit) { HRESULT hr = S_OK; TCHAR keyName [256]; DWORD err;
hr = StringCchCopy( keyName, ARRAYSIZE(keyName), TEXT("APPID\\") ); if ( FAILED(hr) ) { return HRESULTTOWIN32( hr ); }
hr = StringCchCat( keyName, ARRAYSIZE(keyName), AppID ); if ( FAILED(hr) ) { return HRESULTTOWIN32( hr ); }
if (SetPrincipal) { // There is not need to check the return value of RemovePrincipalFromNamedValueSD,
// because its failure is not important (for example DefaultAccessPermission might
// not exist). The important call that must succeed is AddPrincipalToNamedValueSD
RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT, keyName, TEXT("LaunchPermission"), Principal); err = AddPrincipalToNamedValueSD (HKEY_CLASSES_ROOT, keyName, TEXT("LaunchPermission"), Principal, Permit); } else { err = RemovePrincipalFromNamedValueSD (HKEY_CLASSES_ROOT, keyName, TEXT("LaunchPermission"), Principal); }
return err; }
//
// Function will open the metabase and check the iusr_ and iwam_ usernames.
// it will check if the names are still valid and if the passwords are still valid.
//
VOID UpdateAnonymousUser( IMDCOM *pcCom, LPTSTR pszPath, DWORD dwUserMetaId, DWORD dwPasswordMetaId, DWORD dwUserCommentResourceId, DWORD dwUserFullNameResourceId, LPTSTR pszDefaultUserNamePrefix, USERNAME_STRING_TYPE ustSyncName, PASSWORD_STRING_TYPE pstSyncPass, BOOL fPerformPasswordValidate) { HRESULT hr = S_OK; USERNAME_STRING_TYPE ustAnonyName = L"\0"; PASSWORD_STRING_TYPE pstAnonyPass = L"\0"; GUFM_RETURN gufmTemp; BOOL fRet; BOOL fExistence; BOOL fDisabled; BOOL fUpdateComApplications = FALSE; LPTSTR pstrRightsFor_IUSR[] = { L"SeInteractiveLogonRight", L"SeNetworkLogonRight", L"SeBatchLogonRight" };
LPTSTR pstrRightsFor_IWAM[] = { L"SeNetworkLogonRight", L"SeBatchLogonRight", L"SeAssignPrimaryTokenPrivilege", L"SeIncreaseQuotaPrivilege" };
//
// Get the WAM username and password
//
gufmTemp = GetUserFromMetabase(pcCom, pszPath, dwUserMetaId, dwPasswordMetaId, ustAnonyName, pstAnonyPass);
//
// If the metabase path doesn't exist, then
// service doesn't exist, punt
// If ID doesn't exist in the metabase, then punt, assume they
// don't want an anonymous User. We may want to revisit this.
//
//
if ((gufmTemp != GUFM_NO_PATH) && (gufmTemp != GUFM_NO_USER_ID)) { BOOL fCreateAccount = FALSE;
//
// See if this is our default account. Otherwise do nothing.
//
if (_wcsnicmp(pszDefaultUserNamePrefix, ustAnonyName, wcslen(pszDefaultUserNamePrefix)) == 0) {
// Check if this user actually exists...
fExistence = DoesUserExist(ustAnonyName,&fDisabled);
if (fExistence) { if (fDisabled) { fCreateAccount = FALSE; if (!g_eventLogForAccountRecreation) { CreateEventLogObject (); }
if (g_eventLogForAccountRecreation) { CHAR szAnsiUserName[MAX_PATH]; const CHAR *pszUserNames[1];
if (! WideCharToMultiByte(CP_ACP, 0, ustAnonyName, -1, szAnsiUserName, MAX_PATH-1, NULL, NULL)) { SecureZeroMemory(szAnsiUserName, sizeof(szAnsiUserName)); }
pszUserNames[0] = szAnsiUserName;
g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_DISABLED, 1, pszUserNames, 0 ); }
} else { if (gufmTemp != GUFM_NO_PASSWORD) { DBG_ASSERT(gufmTemp == GUFM_SUCCESS);
if (fPerformPasswordValidate) { BOOL fCheckPassword = TRUE;
//
// Make sure this is the same password as other
// instances of this account. If not, set it.
//
if ((pstSyncPass[0] != (TCHAR)'\0') && (_wcsicmp(ustSyncName, ustAnonyName) == 0)) { if (wcscmp(pstSyncPass, pstAnonyPass) != 0) { //
// Passwords are different.
//
if (WritePasswordToMetabase(pcCom, pszPath, dwPasswordMetaId, pstSyncPass)) { // We already checked there is enough speace in pstAnonyPass
hr = StringCchCopy( pstAnonyPass, ARRAYSIZE(pstAnonyPass), pstSyncPass ); DBG_ASSERT( SUCCEEDED(hr) ); } else { fCheckPassword = FALSE; } } }
if (fCheckPassword) { if (ValidatePassword(ustAnonyName, TEXT(""), pstAnonyPass)) { // thats a good case account is ok, do nothing there
} else { // we comment out DeleteGuestUser because we try to change pswd on that user
// DeleteGuestUser(ustAnonyName);
fCreateAccount = TRUE; } } }
//
// Set the sync password here
//
hr = StringCbCopy( pstSyncPass, sizeof(PASSWORD_STRING_TYPE), pstAnonyPass ); DBG_ASSERT( SUCCEEDED(hr) );
hr = StringCbCopy( ustSyncName, sizeof(USERNAME_STRING_TYPE), ustAnonyName ); DBG_ASSERT( SUCCEEDED(hr) );
} } } else { fCreateAccount = TRUE; }
if (fCreateAccount) { //
// The user does not exist, so let's create it.
// Make sure there's a password first.
//
if (fCreateAccount) { if (MD_WAM_USER_NAME == dwUserMetaId) { fRet = MakeSureUserGetsCreated(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,TRUE); if( fRet ) { fUpdateComApplications = TRUE; } } else { fRet = MakeSureUserGetsCreated(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,FALSE); }
if (!g_eventLogForAccountRecreation) { CreateEventLogObject (); }
if (g_eventLogForAccountRecreation) { CHAR szAnsiUserName[MAX_PATH]; const CHAR *pszUserNames[1];
if (! WideCharToMultiByte(CP_ACP, 0, ustAnonyName, -1, szAnsiUserName, MAX_PATH-1, NULL, NULL)) { SecureZeroMemory(szAnsiUserName, sizeof(szAnsiUserName)); }
pszUserNames[0] = szAnsiUserName;
// if succeded to recreate an account then log an event
if (fRet) { g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_RECREATED, 1, pszUserNames, 0 ); } else { // if the creation of the account failed, then log that too.
g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_CREATE_FAILED, 1, pszUserNames, 0 ); } }
if (dwUserMetaId == MD_WAM_USER_NAME) { ChangeAppIDLaunchACL(TEXT("{9209B1A6-964A-11D0-9372-00A0C9034910}"), ustAnonyName, TRUE, TRUE); ChangeAppIDAccessACL(TEXT("{9209B1A6-964A-11D0-9372-00A0C9034910}"), ustAnonyName, TRUE, TRUE); } } // fCreateAccount == TRUE
} // fCreateAccount == TRUE
//
// check if user has enough rights otherwise add some (bug 361833)
//
if (wcscmp(pszDefaultUserNamePrefix,TEXT("IUSR_")) == 0) { UpdateUserRights (ustAnonyName,pstrRightsFor_IUSR,sizeof(pstrRightsFor_IUSR)/sizeof(LPTSTR)); } else if (wcscmp(pszDefaultUserNamePrefix,TEXT("IWAM_")) == 0) { UpdateUserRights (ustAnonyName,pstrRightsFor_IWAM,sizeof(pstrRightsFor_IWAM)/sizeof(LPTSTR)); }
// Update the com applications with the new wam user information
if( fUpdateComApplications ) { DWORD dwThreadID = 0; HANDLE hThread = NULL; COM_APP_THREAD_STRUCT * pUpdateComAppInfo = NULL;
pUpdateComAppInfo = new COM_APP_THREAD_STRUCT; if (pUpdateComAppInfo) { if ( wcslen(ustAnonyName) < (sizeof(pUpdateComAppInfo->ustWamUserName) / sizeof(WCHAR)) ) { hr = StringCchCopy(pUpdateComAppInfo->ustWamUserName, ARRAYSIZE(pUpdateComAppInfo->ustWamUserName), ustAnonyName); DBG_ASSERT( SUCCEEDED(hr) );
if ( wcslen(pstAnonyPass) < (sizeof(pUpdateComAppInfo->pstWamUserPass) / sizeof(WCHAR)) ) { StringCchCopy(pUpdateComAppInfo->pstWamUserPass, ARRAYSIZE(pUpdateComAppInfo->pstWamUserPass), pstAnonyPass);
hThread = CreateThread(NULL, 0, UpdateComApplicationsThread, (PVOID) pUpdateComAppInfo, 0, &dwThreadID);
if (hThread != NULL) { CloseHandle(hThread); } else { if (pUpdateComAppInfo) { delete pUpdateComAppInfo; pUpdateComAppInfo=NULL; } } } } } } } else { // This is not one of our accouts.
// in other words -- it doesn't start with
// iusr_ or iwam_
//
// however there is a problem here.
//
// on machines that are made to be replica domain controllers or
// backup domain controllers, when dcpromo is run to create those types
// of machines, all the local accounts are wiped out.
//
// this is fine if the usernames are iusr_ or iwam_, since they are just
// re-created in the above code (or the user is warned that they were unable
// to be crated). however in the case where these are
// user created accounts, the user has no way of knowing that
// they're iusr/iwam accounts have been hosed.
//
// the code here is just to warn the user of that fact.
if (TRUE == IsDomainController()) { // check if they are valid.
// Check if this user actually exists...
fExistence = DoesUserExist(ustAnonyName,&fDisabled); if (!fExistence) { if (!fDisabled) { // the user doesn't exist
// log SOMETHING at least
if (!g_eventLogForAccountRecreation) { CreateEventLogObject (); }
if (g_eventLogForAccountRecreation) { CHAR szAnsiUserName[MAX_PATH]; const CHAR *pszUserNames[1];
if (! WideCharToMultiByte(CP_ACP, 0, ustAnonyName, -1, szAnsiUserName, MAX_PATH-1, NULL, NULL)) { SecureZeroMemory(szAnsiUserName, sizeof(szAnsiUserName)); }
pszUserNames[0] = szAnsiUserName;
g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_NOT_EXIST, 1, pszUserNames, 0 );
} } } } } } }
HRESULT CreateGroup( LPWSTR szGroupName, LPWSTR szGroupComment) { HRESULT hr = S_OK; NET_API_STATUS dwRes; LOCALGROUP_INFO_1 MyLocalGroup; const DWORD dwMaxCount = 20; DWORD dwCount = 0;
MyLocalGroup.lgrpi1_name = szGroupName; MyLocalGroup.lgrpi1_comment = szGroupComment;
do { dwRes = NetLocalGroupAdd(NULL, 1, (LPBYTE)&MyLocalGroup, NULL); if(dwRes != NERR_Success && dwRes != NERR_GroupExists && dwRes != ERROR_ALIAS_EXISTS) { hr = HRESULT_FROM_WIN32(dwRes);
//
// if this is a domain controller.
// we have to wait for the domain controller
// replication to be finished, otherwise The CreateUserAccount
// call will fail
//
// if we failed to create the user
// it could be because this is a DC and we need
// to wait for the sysvol to be ready.
Sleep(10000); WaitForDCAvailability(); } else { hr = S_OK; } } while ((FAILED(hr)) && (++dwCount < dwMaxCount));
return hr; }
VOID UpdateUsers( BOOL fRestore /* = FALSE */) { HRESULT hresTemp; IMDCOM *pcCom; BOOL fPerformUpdate = TRUE; BOOL fPerformPasswordValidate = FALSE; HKEY hkRegistryKey = NULL; DWORD dwRegReturn; DWORD dwBuffer; DWORD dwSize; DWORD dwType; HRESULT hr;
//
// First get the metabase interface
//
dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\InetStp", &hkRegistryKey); if (dwRegReturn == ERROR_SUCCESS) { dwSize = sizeof(dwBuffer);
dwRegReturn = RegQueryValueEx(hkRegistryKey, L"DisableUserAccountRestore", NULL, &dwType, (BYTE *)&dwBuffer, &dwSize); if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_DWORD)) { fPerformUpdate = FALSE; }
if (fPerformUpdate) { // we are doing the check to see if the user exists...
// see if we need to verify that the password is ssynced as well...
dwRegReturn = RegQueryValueEx(hkRegistryKey, L"EnableUserAccountRestorePassSync", NULL, &dwType, (BYTE *)&dwBuffer, &dwSize); if ((dwRegReturn == ERROR_SUCCESS) && dwType == (REG_DWORD)) { fPerformPasswordValidate = TRUE; } }
RegCloseKey( hkRegistryKey ); }
if( fRestore ) { fPerformPasswordValidate = TRUE; }
if (fPerformUpdate) { hresTemp = CoCreateInstance(CLSID_MDCOM, NULL, CLSCTX_SERVER, IID_IMDCOM, (void**) &pcCom);
if (SUCCEEDED(hresTemp)) { //
// Make sure the IIS_WPG group exists
//
hr = CreateGroup(IIS_WP_GROUP, L"IIS Worker Process Group"); DBGPRINTF((DBG_CONTEXT, "Called into CreateGroup, hr %x\n", hr));
LPTSTR pstrRightsFor_IIS_WPG[] = { L"SeBatchLogonRight", L"SeImpersonatePrivilege" }; UpdateUserRights(IIS_WP_GROUP,pstrRightsFor_IIS_WPG,sizeof(pstrRightsFor_IIS_WPG)/sizeof(LPTSTR));
PASSWORD_STRING_TYPE pstAnonyPass; USERNAME_STRING_TYPE ustAnonyName;
pstAnonyPass[0] = (TCHAR)'\0'; ustAnonyName[0] = (TCHAR)'\0';
UpdateAnonymousUser(pcCom, TEXT("LM/W3SVC"), MD_WAM_USER_NAME, MD_WAM_PWD, IDS_WAMUSER_COMMENT, IDS_WAMUSER_FULLNAME, TEXT("IWAM_"), ustAnonyName, pstAnonyPass, fPerformPasswordValidate);
pstAnonyPass[0] = (TCHAR)'\0'; ustAnonyName[0] = (TCHAR)'\0'; UpdateAnonymousUser(pcCom, TEXT("LM/W3SVC"), MD_ANONYMOUS_USER_NAME, MD_ANONYMOUS_PWD, IDS_USER_COMMENT, IDS_USER_FULLNAME, TEXT("IUSR_"), ustAnonyName, pstAnonyPass, fPerformPasswordValidate);
//
// At this point pstAnonyPass should contain the web server password.
//
UpdateAnonymousUser(pcCom, TEXT("LM/MSFTPSVC"), MD_ANONYMOUS_USER_NAME, MD_ANONYMOUS_PWD, IDS_USER_COMMENT, IDS_USER_FULLNAME, TEXT("IUSR_"), ustAnonyName, pstAnonyPass, fPerformPasswordValidate);
hr = UpdateAdminAcl(pcCom, L"/", IIS_WP_GROUP);
DBGPRINTF((DBG_CONTEXT, "Called into UpdateAdminAcl, hr %x\n", hr));
hr = UpdateAdminAcl(pcCom, L"/", L"NT Authority\\Network Service");
DBGPRINTF((DBG_CONTEXT, "Called into UpdateAdminAcl, hr %x\n", hr));
hr = UpdateAdminAcl(pcCom, L"/", L"NT Authority\\Local Service");
DBGPRINTF((DBG_CONTEXT, "Called into UpdateAdminAcl, hr %x\n", hr));
pcCom->Release(); } }
if (g_eventLogForAccountRecreation) { delete g_eventLogForAccountRecreation; g_eventLogForAccountRecreation = NULL; } }
void DumpAdminACL( PSECURITY_DESCRIPTOR pSD) { HRESULT hr = S_OK; BOOL b = FALSE; BOOL bDaclPresent = FALSE; BOOL bDaclDefaulted = FALSE; PACL pDacl = NULL; ACCESS_ALLOWED_ACE* pAce;
DBGPRINTF((DBG_CONTEXT, "Dumping AdminAcl %p\n", pSD));
b = GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDacl, &bDaclDefaulted); if (b) { DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:ACE count: %d\n", (int)pDacl->AceCount));
// now check if SID's ACE is there
for (int i = 0; i < pDacl->AceCount; i++) { if (!GetAce(pDacl, i, (LPVOID *) &pAce)) { DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:GetAce failed with 0x%x\n", GetLastError())); continue; }
if (IsValidSid( (PSID) &(pAce->SidStart) ) ) { LPTSTR pszSid; LPCTSTR ServerName = NULL; // local machine
DWORD cbName = UNLEN+1; TCHAR ReferencedDomainName[200]; DWORD cbReferencedDomainName = sizeof(ReferencedDomainName); SID_NAME_USE sidNameUse = SidTypeUser; TCHAR szUserName[UNLEN + 1];
// dump out the sid in string format
if ( ConvertSidToStringSid( (PSID)&(pAce->SidStart), &pszSid ) ) { hr = StringCchCopy(szUserName, ARRAYSIZE(szUserName), L"(unknown...)"); DBG_ASSERT( SUCCEEDED(hr) );
if (LookupAccountSid(ServerName, (PSID) &(pAce->SidStart), szUserName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &sidNameUse)) { // echo to logfile
DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:Sid[%i]=%S,%S,0x%x,0x%x,0x%x,0x%x\n",i, pszSid, szUserName, pAce->Header.AceType, pAce->Header.AceFlags, pAce->Header.AceSize, pAce->Mask )); } else { DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:Sid[%i]=%S='%S'\n",i,pszSid,szUserName)); }
LocalFree(LocalHandle(pszSid)); } } else { DBGPRINTF((DBG_CONTEXT, "DumpAdminACL:IsValidSid failed with 0x%x\n", GetLastError())); } } } }
BOOL MakeAbsoluteCopyFromRelative( PSECURITY_DESCRIPTOR psdOriginal, PSECURITY_DESCRIPTOR* ppsdNew) { // we have to find out whether the original is already self-relative
SECURITY_DESCRIPTOR_CONTROL sdc = 0; PSECURITY_DESCRIPTOR psdAbsoluteCopy = NULL; DWORD dwRevision = 0; DWORD cb = 0; PACL Dacl = NULL; PACL Sacl = NULL; PSID Owner = NULL; PSID Group = NULL; DWORD dwDaclSize = 0; DWORD dwSaclSize = 0; DWORD dwOwnerSize = 0; DWORD dwPrimaryGroupSize = 0;
if( !IsValidSecurityDescriptor( psdOriginal ) ) { goto cleanup; }
if( !GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) { goto cleanup; }
if( sdc & SE_SELF_RELATIVE ) { // the original is in self-relative format, build an absolute copy
// get required buffer size
cb = 0; MakeAbsoluteSD( psdOriginal, // address of self-relative SD
psdAbsoluteCopy, // address of absolute SD
&cb, // address of size of absolute SD
NULL, // address of discretionary ACL
&dwDaclSize, // address of size of discretionary ACL
NULL, // address of system ACL
&dwSaclSize, // address of size of system ACL
NULL, // address of owner SID
&dwOwnerSize, // address of size of owner SID
NULL, // address of primary-group SID
&dwPrimaryGroupSize // address of size of group SID
);
// alloc the memory
psdAbsoluteCopy = (PSECURITY_DESCRIPTOR) malloc( cb ); Dacl = (PACL) malloc( dwDaclSize ); Sacl = (PACL) malloc( dwSaclSize ); Owner = (PSID) malloc( dwOwnerSize ); Group = (PSID) malloc( dwPrimaryGroupSize );
if(NULL == psdAbsoluteCopy || NULL == Dacl || NULL == Sacl || NULL == Owner || NULL == Group ) { goto cleanup; }
// make the copy
if( !MakeAbsoluteSD( psdOriginal, // address of self-relative SD
psdAbsoluteCopy, // address of absolute SD
&cb, // address of size of absolute SD
Dacl, // address of discretionary ACL
&dwDaclSize, // address of size of discretionary ACL
Sacl, // address of system ACL
&dwSaclSize, // address of size of system ACL
Owner, // address of owner SID
&dwOwnerSize, // address of size of owner SID
Group, // address of primary-group SID
&dwPrimaryGroupSize // address of size of group SID
) ) { goto cleanup; } } else { // the original is in absolute format, fail
goto cleanup; }
// paranoia check
if( !IsValidSecurityDescriptor( psdAbsoluteCopy ) ) { goto cleanup; } if( !IsValidSecurityDescriptor( psdOriginal ) ) { goto cleanup; }
*ppsdNew = psdAbsoluteCopy;
return(TRUE);
cleanup: if( Dacl != NULL ) { free((PVOID) Dacl ); Dacl = NULL; } if( Sacl != NULL ) { free((PVOID) Sacl ); Sacl = NULL; } if( Owner != NULL ) { free((PVOID) Owner ); Owner = NULL; } if( Group != NULL ) { free((PVOID) Group ); Group = NULL; } if( psdAbsoluteCopy != NULL ) { free((PVOID) psdAbsoluteCopy ); psdAbsoluteCopy = NULL; }
*ppsdNew = NULL;
return (FALSE); }
BOOL AddUserAccessToSD( IN PSECURITY_DESCRIPTOR pSd, IN PSID pSid, IN DWORD NewAccess, IN UCHAR TheAceType, OUT PSECURITY_DESCRIPTOR *ppSdNew) { ULONG i; BOOL bReturn = FALSE; BOOL Result; BOOL DaclPresent; BOOL DaclDefaulted; DWORD Length; DWORD NewAclLength; ACCESS_ALLOWED_ACE* OldAce; PACE_HEADER NewAce = NULL; ACL_SIZE_INFORMATION AclInfo; PACL Dacl = NULL; PACL NewDacl = NULL; PACL NewAceDacl = NULL; PSECURITY_DESCRIPTOR NewSD = NULL; PSECURITY_DESCRIPTOR OldSD = NULL; PSECURITY_DESCRIPTOR outpSD = NULL; DWORD cboutpSD = 0; BOOL fAceForGroupPresent = FALSE; DWORD dwMask;
OldSD = pSd;
// only do if the ace is allowed/denied
if (ACCESS_ALLOWED_ACE_TYPE != TheAceType && ACCESS_DENIED_ACE_TYPE != TheAceType) { goto Exit; }
// Convert SecurityDescriptor to absolute format. It generates
// a new SecurityDescriptor for its output which we must free.
if ( !MakeAbsoluteCopyFromRelative(OldSD, &NewSD) ) { goto Exit; }
// Must get DACL pointer from new (absolute) SD
if(!GetSecurityDescriptorDacl(NewSD,&DaclPresent,&Dacl,&DaclDefaulted)) { goto Exit; }
// If no DACL, no need to add the user since no DACL
// means all accesss
if( !DaclPresent ) { bReturn = TRUE; goto Exit; }
// Code can return DaclPresent, but a NULL which means
// a NULL Dacl is present. This allows all access to the object.
if( Dacl == NULL ) { bReturn = TRUE; goto Exit; }
// Get the current ACL's size
if( !GetAclInformation(Dacl,&AclInfo,sizeof(AclInfo),AclSizeInformation) ) { goto Exit; }
// Check if access is already there
// --------------------------------
// Check to see if this SID already exists in there
// if it does (and it has the right access we want) then forget it, we don't have to do anything more.
for (i = 0; i < AclInfo.AceCount; i++) { ACE_HEADER *pAceHeader; ACCESS_ALLOWED_ACE* pAce = NULL;
if (!GetAce(Dacl, i, (LPVOID *) &pAce)) { goto Exit; }
pAceHeader = (ACE_HEADER *)pAce;
// check if group sid is already there
if (EqualSid((PSID) &(pAce->SidStart), pSid)) { if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) { // If the correct access is present, return success
if ((pAce->Mask & NewAccess) == NewAccess) { bReturn = TRUE; goto Exit; } else { // the ace that exist doesn't have the permissions that we want.
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
fAceForGroupPresent = TRUE; } } break; } }
// If we have to create a new ACE
// (because our user isn't listed in the existing ACL)
// then let's Create a new ACL to put the new access allowed ACE on
// --------------------------------
if (!fAceForGroupPresent) { NewAclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) + GetLengthSid( pSid );
NewAceDacl = (PACL) LocalAlloc( LMEM_FIXED, NewAclLength ); if ( NewAceDacl == NULL ) { goto Exit; }
if(!InitializeAcl( NewAceDacl, NewAclLength, ACL_REVISION )) { goto Exit; }
if (ACCESS_DENIED_ACE_TYPE == TheAceType) { Result = AddAccessDeniedAce(NewAceDacl,ACL_REVISION,NewAccess,pSid); } else { Result = AddAccessAllowedAce(NewAceDacl,ACL_REVISION,NewAccess,pSid); } if( !Result ) { goto Exit; } // Grab the 1st ace from the Newly created Dacl
if(!GetAce( NewAceDacl, 0, (void **)&NewAce )) { goto Exit; }
// add CONTAINER_INHERIT_ACE TO AceFlags
//NewAce->AceFlags |= CONTAINER_INHERIT_ACE;
Length = AclInfo.AclBytesInUse + NewAce->AceSize; } else { Length = AclInfo.AclBytesInUse; }
// Allocate new DACL
NewDacl = (PACL) LocalAlloc( LMEM_FIXED, Length ); if(NewDacl == NULL) { goto Exit; } if(!InitializeAcl( NewDacl, Length, ACL_REVISION )) { goto Exit; }
// Insert new ACE at the front of the new DACL
if (!fAceForGroupPresent) { if(!AddAce( NewDacl, ACL_REVISION, 0, NewAce, NewAce->AceSize )) { goto Exit; } }
// ----------------------------------------
// Read thru the old Dacl and get the ACE's
// add it to the new Dacl
// ----------------------------------------
for ( i = 0; i < AclInfo.AceCount; i++ ) { ACE_HEADER *pAceHeader;
Result = GetAce( Dacl, i, (LPVOID*) &OldAce ); if( !Result ) { goto Exit; }
pAceHeader = (ACE_HEADER *)OldAce;
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
//
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) { dwMask = OldAce->Mask; if (fAceForGroupPresent) { if (EqualSid((PSID) &(OldAce->SidStart), pSid)) { dwMask = NewAccess | OldAce->Mask; } }
// now add ace to new dacl
Result = AddAccessAllowedAceEx(NewDacl, ACL_REVISION, OldAce->Header.AceFlags,dwMask,(PSID) &(OldAce->SidStart)); if( !Result ) { goto Exit; } } else { // copy denied or audit ace.
if (!AddAce(NewDacl, ACL_REVISION, 0xFFFFFFFF,OldAce, pAceHeader->AceSize )) { goto Exit; } } }
// Set new DACL for Security Descriptor
if(!SetSecurityDescriptorDacl(NewSD,TRUE,NewDacl,FALSE)) { goto Exit; }
// The new SD is in absolute format. change it to Relative before we pass it back
cboutpSD = 0; MakeSelfRelativeSD(NewSD, outpSD, &cboutpSD); outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR, cboutpSD); if ( !outpSD ) { goto Exit; }
if (!MakeSelfRelativeSD(NewSD, outpSD, &cboutpSD)) { goto Exit; }
// The new SD is passed back in relative format,
*ppSdNew = outpSD;
bReturn = TRUE;
Exit: if (NewSD) { free( NewSD ); NewSD = NULL; } if (NewDacl) { LocalFree( NewDacl ); NewDacl = NULL; } if (NewAceDacl) { LocalFree( NewAceDacl ); NewAceDacl = NULL; } return bReturn; }
HRESULT UpdateAdminAcl( IMDCOM * pcCom, LPCWSTR szPath, LPCWSTR szAccountName) /*++
Routine Description:
After DCPromo, need to update the AdminAcl in the metabase --*/ { METADATA_HANDLE hMetabase = NULL; METADATA_RECORD mdrAdminAcl; BUFFER buffSid; BUFFER buffDomainName; PSECURITY_DESCRIPTOR pOldSd = NULL; PSECURITY_DESCRIPTOR pNewSd = NULL; HRESULT hr; DWORD dwMDGetDataLen; DWORD cbSid; DWORD cchDomainName; SID_NAME_USE peUse; DWORD AccessMask = ( MD_ACR_READ | MD_ACR_UNSECURE_PROPS_READ | MD_ACR_ENUM_KEYS );
hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE, szPath, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, OPEN_TIMEOUT_VALUE, &hMetabase ); if( FAILED(hr) ) { DBGPRINTF((DBG_CONTEXT, "Error opening metabase path %S, hr %x\n", szPath, hr)); goto cleanup; }
MD_SET_DATA_RECORD_EXT( &mdrAdminAcl, MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE, IIS_MD_UT_SERVER, BINARY_METADATA, 0, NULL );
hr = pcCom->ComMDGetMetaData(hMetabase, NULL, &mdrAdminAcl, &dwMDGetDataLen);
if (FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "Error retrieving data, hr %x\n", hr)); goto cleanup; }
pOldSd = (PSECURITY_DESCRIPTOR)mdrAdminAcl.pbMDData;
//
// obtain the logon sid of the user/group
//
cbSid = buffSid.QuerySize(); cchDomainName = buffDomainName.QuerySize() / sizeof(WCHAR); while(!LookupAccountName(NULL, szAccountName, buffSid.QueryPtr(), &cbSid, (LPWSTR)buffDomainName.QueryPtr(), &cchDomainName, &peUse)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { DBGPRINTF((DBG_CONTEXT, "Error retrieving account %S, hr %x\n", szAccountName, hr)); hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; }
if (!buffSid.Resize(cbSid) || !buffDomainName.Resize(cchDomainName * sizeof(WCHAR))) { hr = HRESULT_FROM_WIN32(GetLastError()); goto cleanup; } }
DumpAdminACL(pOldSd);
if (!AddUserAccessToSD(pOldSd, buffSid.QueryPtr(), AccessMask, ACCESS_ALLOWED_ACE_TYPE, &pNewSd)) { hr = HRESULT_FROM_WIN32(GetLastError()); DBGPRINTF((DBG_CONTEXT, "Error adding user to AdminAcl, hr %x\n", hr)); goto cleanup; }
if (pNewSd) { DumpAdminACL(pNewSd);
DWORD dwNewSd = GetSecurityDescriptorLength(pNewSd);
MD_SET_DATA_RECORD_EXT( &mdrAdminAcl, MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE, IIS_MD_UT_SERVER, BINARY_METADATA, dwNewSd, pNewSd );
hr = pcCom->ComMDSetMetaData(hMetabase, NULL, &mdrAdminAcl);
if (FAILED(hr)) { DBGPRINTF((DBG_CONTEXT, "Error setting adminacl, hr %x\n", hr)); goto cleanup; } }
cleanup: if (pNewSd) { GlobalFree(pNewSd); pNewSd = NULL; }
if (hMetabase) { // Done with the metabase
pcCom->ComMDCloseMetaObject(hMetabase); hMetabase = NULL; }
return hr; }
HRESULT UpdateComApplications( LPCTSTR szWamUserName, LPCTSTR szWamUserPass) /*++
Routine Description:
If the IWAM account has been modified, it is necessary to update the the out of process com+ applications with the correct account information. This routine will collect all the com+ applications and reset the activation information.
Arguments:
szWamUserName - the new user name szWamUserPass - the new user password
Note:
This routine is a royal pain in the butt. I take back all the good things I may have said about com automation.
Return Value:
HRESULT - Return value from failed API call - E_OUTOFMEMORY - S_OK - everything worked - S_FALSE - encountered a non-fatal error, unable to reset at least one application. --*/ { HRESULT hr = S_OK; BOOL fNoErrors = TRUE; METADATA_HANDLE hMetabase = NULL; WCHAR * pwszDataPaths = NULL; DWORD cchDataPaths = 0; BOOL fTryAgain; DWORD cMaxApplications; WCHAR * pwszCurrentPath; STACK_BUFFER( bufMDPath, 64 ); WCHAR * pwszMDPath = NULL; DWORD dwMDPathLen; SAFEARRAY * psaApplications = NULL; SAFEARRAYBOUND rgsaBound[1]; DWORD cApplications; VARIANT varAppKey; LONG rgIndices[1]; METADATA_RECORD mdrAppIsolated; METADATA_RECORD mdrAppPackageId; METADATA_RECORD mdrWamClsid; DWORD dwAppIsolated; WCHAR wszAppPackageId[ 40 ]; WCHAR wszWamClsid[ 40 ]; DWORD dwMDGetDataLen = 0; ICOMAdminCatalog * pComCatalog = NULL; ICatalogCollection *pComAppCollection = NULL; ICatalogObject * pComApp = NULL; LONG nAppsInCollection; LONG iCurrentApp; LONG nChanges; BOOL fAppCreated = FALSE; VARIANT varOldAppIdentity; VARIANT varNewAppIdentity; VARIANT varNewAppPassword; IMDCOM * pcCom = NULL; BSTR bstrApplications = NULL; BSTR bstrIdentity = NULL; BSTR bstrPassword = NULL; DWORD cbMDPath;
// This is built unicode right now. Since all the com apis I need
// are unicode only I'm using wide characters here. I should get
// plenty of compiler errors if _UNICODE isn't defined, but just
// in case....
// DBG_ASSERT( sizeof(TCHAR) == sizeof(WCHAR) );
DBGPRINTF(( DBG_CONTEXT, "Updating activation identity for out of process apps.\n" ));
// Init variants
VariantInit( &varAppKey ); VariantInit( &varOldAppIdentity ); VariantInit( &varNewAppIdentity ); VariantInit( &varNewAppPassword );
// Allocate the BSTRs
bstrApplications = SysAllocString( L"Applications" ); if ( bstrApplications == NULL ) { hr = E_OUTOFMEMORY; DBGERROR(( DBG_CONTEXT, "Out of memory allocating BSTR\n" )); goto cleanup; } bstrIdentity = SysAllocString( L"Identity" ); if ( bstrIdentity == NULL ) { hr = E_OUTOFMEMORY; DBGERROR(( DBG_CONTEXT, "Out of memory allocating BSTR\n" )); goto cleanup; } bstrPassword = SysAllocString( L"Password" ); if ( bstrPassword == NULL ) { hr = E_OUTOFMEMORY; DBGERROR(( DBG_CONTEXT, "Out of memory allocating BSTR\n" )); goto cleanup; }
hr = CoCreateInstance(CLSID_MDCOM, NULL, CLSCTX_SERVER, IID_IMDCOM, (void**) &pcCom); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed CoCreateInstance CLSID_MDCOM (%08x)\n", hr )); goto cleanup; }
//
// Get the applications to be reset by querying the metabase paths
//
hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE, ROOTMDPath, METADATA_PERMISSION_READ, OPEN_TIMEOUT_VALUE, &hMetabase ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to open metabase (%08x)\n", hr )); goto cleanup; }
// Get the data paths string
fTryAgain = TRUE; do { hr = pcCom->ComMDGetMetaDataPaths( hMetabase, NULL, MD_APP_PACKAGE_ID, STRING_METADATA, cchDataPaths, pwszDataPaths, &cchDataPaths );
if( HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr ) { delete[] pwszDataPaths; pwszDataPaths = NULL;
pwszDataPaths = new WCHAR[cchDataPaths]; if( !pwszDataPaths ) { hr = E_OUTOFMEMORY; goto cleanup; } } else { fTryAgain = FALSE; } } while( fTryAgain );
//
// Done with the metabase for now
//
pcCom->ComMDCloseMetaObject(hMetabase); hMetabase = NULL;
if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to find metadata (%08x) Data(%d)\n", hr, MD_APP_PACKAGE_ID )); goto cleanup; } else if (pwszDataPaths == NULL) { //
// If we found no isolated apps, make the path list an empty multisz
//
cchDataPaths = 1; pwszDataPaths = new WCHAR[cchDataPaths]; if( !pwszDataPaths ) { hr = E_OUTOFMEMORY; goto cleanup; } pwszDataPaths[0] = L'\0'; }
// Determine the maximum number of applications
cMaxApplications = 1; // The pooled application
for( pwszCurrentPath = pwszDataPaths; *pwszCurrentPath != L'\0'; pwszCurrentPath += wcslen(pwszCurrentPath) + 1 ) { cMaxApplications++; }
//
// Build a key array and load the com applications.
//
// Create an array to hold the keys
rgsaBound[0].cElements = cMaxApplications; rgsaBound[0].lLbound = 0;
psaApplications = SafeArrayCreate( VT_VARIANT, 1, rgsaBound ); if( psaApplications == NULL ) { hr = E_OUTOFMEMORY; goto cleanup; }
// Set the out of process pool application key
varAppKey.vt = VT_BSTR; varAppKey.bstrVal = SysAllocString( W3_OOP_POOL_PACKAGE_ID ); if( !varAppKey.bstrVal ) { hr = E_OUTOFMEMORY; goto cleanup; }
rgIndices[0] = 0; hr = SafeArrayPutElement( psaApplications, rgIndices, &varAppKey ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed setting an element in a safe array (%08x)\n", hr )); goto cleanup; }
// For each of the application paths determine if an out of process
// application is defined there and set the appropriate key into
// our array
MD_SET_DATA_RECORD_EXT( &mdrAppIsolated, MD_APP_ISOLATED, METADATA_NO_ATTRIBUTES, ALL_METADATA, DWORD_METADATA, sizeof(DWORD), (PBYTE)&dwAppIsolated );
MD_SET_DATA_RECORD_EXT( &mdrAppPackageId, MD_APP_PACKAGE_ID, METADATA_NO_ATTRIBUTES, ALL_METADATA, STRING_METADATA, sizeof(wszAppPackageId), (PBYTE)wszAppPackageId );
wszAppPackageId[0] = L'\0';
MD_SET_DATA_RECORD_EXT( &mdrWamClsid, MD_APP_WAM_CLSID, METADATA_NO_ATTRIBUTES, ALL_METADATA, STRING_METADATA, sizeof(wszWamClsid), (PBYTE)wszWamClsid );
wszWamClsid[0] = L'\0';
// Go through each data path and set it into our array if
// it is an isolated application
cApplications = 1; // Actual # of applications - 1 for pool
for( pwszCurrentPath = pwszDataPaths; *pwszCurrentPath != L'\0'; pwszCurrentPath += wcslen(pwszCurrentPath) + 1 ) { if( hMetabase != NULL ) { pcCom->ComMDCloseMetaObject(hMetabase); hMetabase = NULL; }
//
// 20 is the size of L"/LM/W3SVC"
//
cbMDPath = (DWORD)(wcslen( pwszCurrentPath ) * sizeof( WCHAR )) + 20; if ( !bufMDPath.Resize( cbMDPath ) ) { hr = E_OUTOFMEMORY; goto cleanup; }
pwszMDPath = ( WCHAR* )bufMDPath.QueryPtr();
hr = StringCbCopyW( pwszMDPath, cbMDPath, ROOTMDPath ); if ( FAILED(hr) ) { goto cleanup;
}
hr = StringCbCopyW( pwszMDPath, cbMDPath, pwszCurrentPath ); if ( FAILED(hr) ) { goto cleanup;
}
//
// Get rid of the trailing '/' or '\\'
//
dwMDPathLen = (DWORD)wcslen( pwszMDPath ); if( pwszMDPath[ dwMDPathLen - 1 ] == L'\\' || pwszMDPath[ dwMDPathLen - 1 ] == L'/' ) { pwszMDPath[ dwMDPathLen - 1 ] = L'\0'; }
hr = pcCom->ComMDOpenMetaObject( METADATA_MASTER_ROOT_HANDLE, pwszMDPath, METADATA_PERMISSION_READ, OPEN_TIMEOUT_VALUE, &hMetabase ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to open metabase (%08x)\n", hr )); goto cleanup; }
hr = pcCom->ComMDGetMetaData( hMetabase, NULL, &mdrAppIsolated, &dwMDGetDataLen ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get data from the metabase (%08x)" " Path(%S) Data(%d)\n", hr, pwszMDPath, mdrAppIsolated.dwMDIdentifier ));
fNoErrors = FALSE; continue; }
// Is the application out of process
if( dwAppIsolated == 1 ) { // Get the application id
hr = pcCom->ComMDGetMetaData( hMetabase, NULL, &mdrAppPackageId, &dwMDGetDataLen ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get data from the metabase (%08x)" " Path(%S) Data(%d)\n", hr, pwszMDPath, mdrAppPackageId.dwMDIdentifier ));
fNoErrors = FALSE; continue; }
// Get the wam class id
hr = pcCom->ComMDGetMetaData( hMetabase, NULL, &mdrWamClsid, &dwMDGetDataLen ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get data from the metabase (%08x)" " Path(%S) Data(%d)\n", hr, pwszMDPath, mdrWamClsid.dwMDIdentifier ));
fNoErrors = FALSE; continue; }
//
// Close meta object since we may need to write to it after we
// create a new COM+ application.
//
pcCom->ComMDCloseMetaObject(hMetabase); hMetabase = NULL;
if ( g_pfnCreateCOMPlusApplication ) { hr = g_pfnCreateCOMPlusApplication( pwszMDPath, wszAppPackageId, wszWamClsid, &fAppCreated ); } else { hr = E_FAIL; }
if( FAILED( hr ) ) { fNoErrors = FALSE; continue; }
if( fAppCreated ) { //
// We don't need to fix the password for this
// COM+ application
//
continue; }
// Add the application id to the array
VariantClear( &varAppKey ); varAppKey.vt = VT_BSTR; varAppKey.bstrVal = SysAllocString( wszAppPackageId ); if( !varAppKey.bstrVal ) { hr = E_OUTOFMEMORY; goto cleanup; }
rgIndices[0]++; hr = SafeArrayPutElement( psaApplications, rgIndices, &varAppKey ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to set safe array element (%08x)\n", hr )); VariantClear( &varAppKey ); rgIndices[0]--; fNoErrors = FALSE; continue; } cApplications++; } }
//
// IVANPASH: BUG #524473
// Close meta object, because if W3SVC is starting it will keep SCM locked
// until it finishes, but it will be blocked by us from accessing /LM/W3SVC.
// and we will be blocked in the CoCreate for the COM+ Catalog waiting for
// SCM to unlock to start the service and SCM is waiting for W3SVC.
//
if( hMetabase != NULL ) { pcCom->ComMDCloseMetaObject(hMetabase); hMetabase = NULL; }
// Shrink the size of the safe-array if necessary
if( cApplications < cMaxApplications ) { rgsaBound[0].cElements = cApplications;
hr = SafeArrayRedim( psaApplications, rgsaBound ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to redim safe array (%08x)\n", hr )); goto cleanup; } }
//
// For each application reset the activation identity
//
// Use our key array to get the application collection
DBG_ASSERT( hMetabase == NULL );
hr = CoCreateInstance( CLSID_COMAdminCatalog, NULL, CLSCTX_SERVER, IID_ICOMAdminCatalog, (void**)&pComCatalog ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to create COM catalog (%08x)\n", hr )); goto cleanup; }
hr = pComCatalog->GetCollection( bstrApplications, (IDispatch **)&pComAppCollection ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get Applications collection (%08x)\n", hr )); goto cleanup; }
hr = pComAppCollection->PopulateByKey( psaApplications ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to populate Applications collection (%08x)\n", hr )); goto cleanup; }
// Iterate over the application collection and update all the
// applications that use IWAM.
hr = pComAppCollection->get_Count( &nAppsInCollection ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get Applications count (%08x)\n", hr )); goto cleanup; }
// Init our new app identity and password.
varNewAppIdentity.vt = VT_BSTR; varNewAppIdentity.bstrVal = SysAllocString( szWamUserName ); if( !varNewAppIdentity.bstrVal ) { hr = E_OUTOFMEMORY; goto cleanup; }
varNewAppPassword.vt = VT_BSTR; varNewAppPassword.bstrVal = SysAllocString( szWamUserPass ); if( !varNewAppPassword.bstrVal ) { hr = E_OUTOFMEMORY; goto cleanup; }
for( iCurrentApp = 0; iCurrentApp < nAppsInCollection; ++iCurrentApp ) { if( pComApp ) { pComApp->Release(); pComApp = NULL; } if( varOldAppIdentity.vt != VT_EMPTY ) { VariantClear( &varOldAppIdentity ); }
hr = pComAppCollection->get_Item( iCurrentApp, (IDispatch **)&pComApp ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get item from Applications collection (%08x)\n", hr )); fNoErrors = FALSE; continue; }
// If the user has set this to something other than the IWAM_
// user, then we will respect that and not reset the identiy.
hr = pComApp->get_Value( bstrIdentity, &varOldAppIdentity ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to get Identify from Application (%08x)\n", hr )); fNoErrors = FALSE; continue; }
DBG_ASSERT( varOldAppIdentity.vt == VT_BSTR ); if( varOldAppIdentity.vt == VT_BSTR ) { if( memcmp( L"IWAM_", varOldAppIdentity.bstrVal, 10 ) == 0 ) { hr = pComApp->put_Value( bstrIdentity, varNewAppIdentity ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to set new Identify (%08x)\n", hr )); fNoErrors = FALSE; continue; }
hr = pComApp->put_Value( bstrPassword, varNewAppPassword ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to set new Password (%08x)\n", hr )); fNoErrors = FALSE; continue; } } else { DBGINFO(( DBG_CONTEXT, "Unrecognized application identity (%S)\n", varOldAppIdentity.bstrVal )); } } }
hr = pComAppCollection->SaveChanges( &nChanges ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to save changes (%08x)\n", hr )); goto cleanup; }
cleanup:
if( hMetabase != NULL ) { pcCom->ComMDCloseMetaObject(hMetabase); hMetabase = NULL; }
if( psaApplications != NULL ) { SafeArrayDestroy( psaApplications ); }
if( pComCatalog != NULL ) { pComCatalog->Release(); }
if( pComAppCollection != NULL ) { pComAppCollection->Release(); }
if( pComApp != NULL ) { pComApp->Release(); }
if( varAppKey.vt != VT_EMPTY ) { VariantClear( &varAppKey ); }
if( varOldAppIdentity.vt != VT_EMPTY ) { VariantClear( &varOldAppIdentity ); }
if( varNewAppIdentity.vt != VT_EMPTY ) { VariantClear( &varNewAppIdentity ); }
if( varNewAppPassword.vt != VT_EMPTY ) { VariantClear( &varNewAppPassword ); }
delete [] pwszDataPaths;
if ( bstrApplications != NULL) { SysFreeString( bstrApplications ); bstrApplications = NULL; } if ( bstrIdentity != NULL) { SysFreeString( bstrIdentity ); bstrIdentity = NULL; } if ( bstrPassword != NULL) { SysFreeString( bstrPassword ); bstrPassword = NULL; }
if( pcCom != NULL ) { pcCom->Release(); }
// return
if( FAILED(hr) ) { return hr; } else if( fNoErrors == FALSE ) { return S_FALSE; } else { return S_OK; } }
int IsDomainController(void) { int iReturn = FALSE; OSVERSIONINFOEX VerInfo;
ZeroMemory(&VerInfo, sizeof VerInfo); VerInfo.dwOSVersionInfoSize = sizeof VerInfo; if (GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&VerInfo))) { if (VER_NT_DOMAIN_CONTROLLER == VerInfo.wProductType) { iReturn = TRUE; } }
return iReturn; }
BOOL MakeSureUserGetsCreated( LPTSTR pszAnonyName, LPTSTR pszAnonyPass, DWORD dwUserCommentResourceId, DWORD dwUserFullNameResourceId, BOOL fSpecicaliWamAccount) { BOOL bReturn = FALSE; const DWORD dwMaxCount = 20; DWORD dwCount = 0;
do { bReturn = CreateUserAccount(pszAnonyName,pszAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,fSpecicaliWamAccount); if (!bReturn) { // if this is a domain controller.
// we have to wait for the domain controller
// replication to be finished, otherwise The CreateUserAccount
// call will fail
//
// if we failed to create the user
// it could be because this is a DC and we need
// to wait for the sysvol to be ready.
Sleep(10000); WaitForDCAvailability(); }
} while ((!bReturn) && (++dwCount < dwMaxCount));
return bReturn; }
BOOL WaitForDCAvailability(void) { BOOL bRetVal = FALSE; DWORD dwResult; DWORD dwCount = 0; DWORD dwMaxWait = 60000; // 1 minute max wait
HKEY hKeyNetLogonParams;
if (FALSE == IsDomainController()) { // not a domain controller
// so we don't have to worry about replication delays...
return TRUE; }
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,TEXT("SYSTEM\\CurrentControlSet\\Services\\netlogon\\parameters"),0,KEY_READ,&hKeyNetLogonParams ); if ( dwResult == ERROR_SUCCESS ) { //
// value exists
//
DWORD dwSysVolReady = 0; DWORD dwSize = sizeof( DWORD ); DWORD dwType = REG_DWORD;
dwResult = RegQueryValueEx( hKeyNetLogonParams,TEXT("SysVolReady"),0,&dwType,(LPBYTE) &dwSysVolReady,&dwSize ); if ( dwResult == ERROR_SUCCESS ) { //
// SysVolReady?
//
if ( dwSysVolReady == 0 ) { HANDLE hEvent; //
// wait for SysVol to become ready
//
hEvent = CreateEvent( 0, TRUE, FALSE, TEXT("IISSysVolReadyEvent") ); if ( hEvent ) { dwResult = RegNotifyChangeKeyValue( hKeyNetLogonParams, FALSE, REG_NOTIFY_CHANGE_LAST_SET, hEvent, TRUE ); if ( dwResult == ERROR_SUCCESS ) { const DWORD dwMaxCount = 3; do { //
// wait for SysVolReady to change
// hEvent is signaled for any changes in hKeyNetLogonParams
// not just the SysVolReady value.
//
WaitForSingleObject (hEvent, dwMaxWait / dwMaxCount ); dwResult = RegQueryValueEx( hKeyNetLogonParams,TEXT("SysVolReady"),0,&dwType,(LPBYTE) &dwSysVolReady,&dwSize ); } while ( dwSysVolReady == 0 && ++dwCount < dwMaxCount );
if ( dwSysVolReady ) { bRetVal = TRUE; } } CloseHandle( hEvent ); } } else { // sysvol is ready
bRetVal = TRUE; }
} else { //
// value is non-existent, SysVol is assumed to be ready
//
if ( dwResult == ERROR_FILE_NOT_FOUND ) { bRetVal = TRUE; } }
RegCloseKey( hKeyNetLogonParams ); } else { // error opening regkey, maybe it's not even there
bRetVal = TRUE; }
return bRetVal; }
DWORD UpdateComApplicationsThread( PVOID pv) {
HRESULT hr = S_OK; COM_APP_THREAD_STRUCT *pUpdateComAppInfo = (COM_APP_THREAD_STRUCT *) pv; BOOL fComInitialized = FALSE;
if ( pUpdateComAppInfo == NULL ) { goto exit; }
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if ( FAILED( hr ) ) { goto exit; } fComInitialized = TRUE;
hr = UpdateComApplications( pUpdateComAppInfo->ustWamUserName, pUpdateComAppInfo->pstWamUserPass );
exit: if( hr != S_OK ) { if( !g_eventLogForAccountRecreation ) { CreateEventLogObject(); }
if ( g_eventLogForAccountRecreation ) { g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_COMUPDATE_FAILED, 0, NULL, hr ); } } if ( pUpdateComAppInfo != NULL ) { // erase the memory that we held the username/password in.
SecureZeroMemory( (PVOID)pUpdateComAppInfo->ustWamUserName, sizeof(pUpdateComAppInfo->ustWamUserName) ); SecureZeroMemory( (PVOID)pUpdateComAppInfo->pstWamUserPass, sizeof(pUpdateComAppInfo->pstWamUserPass) );
delete pUpdateComAppInfo; pUpdateComAppInfo = NULL; } if ( fComInitialized ) { CoUninitialize(); }
return 0; }
|