|
|
/*++
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"
typedef enum { GUFM_SUCCESS, GUFM_NO_PATH, GUFM_NO_PASSWORD, GUFM_NO_USER_ID } GUFM_RETURN;
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(IMDCOM * pcCom,LPCTSTR szWamUserName,LPCTSTR szWamUserPass); int IsDomainController(void); BOOL WaitForDCAvailability(void); HRESULT UpdateAdminAcl(IMDCOM *pcCom, LPCWSTR szPath, LPCWSTR szAccountName);
// 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) { BOOL fEnabled = FALSE; NTSTATUS status; LSA_UNICODE_STRING UserRightString; LSA_HANDLE PolicyHandle = NULL;
// Create a LSA_UNICODE_STRING for the privilege name.
InitLsaString(&UserRightString, PrivilegeName);
// get the sid of szAccountName
PSID pSID = NULL; BOOL bWellKnownSID = FALSE;
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 ) { UINT i; LSA_UNICODE_STRING *rgUserRights = NULL; ULONG cRights; 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;
*fHaveThatRight = FALSE;
// Create a LSA_UNICODE_STRING for the privilege name.
InitLsaString(&UserRightString, PrivilegeName);
// get the sid of szAccountName
PSID pSID = NULL; BOOL bWellKnownSID = FALSE;
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; DWORD sidLength;
if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &tokenHandle)) { GetTokenInformation (tokenHandle, TokenUser, tokenUser, 0, &tokenSize);
tokenUser = (TOKEN_USER *) malloc (tokenSize); if (!tokenUser) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return GetLastError(); }
if (GetTokenInformation (tokenHandle, TokenUser, tokenUser, tokenSize, &tokenSize)) { sidLength = GetLengthSid (tokenUser->User.Sid); *Sid = (PSID) malloc (sidLength); if (*Sid) { memcpy (*Sid, tokenUser->User.Sid, sidLength); } CloseHandle (tokenHandle); } else dwReturn = GetLastError();
if (tokenUser) free(tokenUser);
} else dwReturn = GetLastError();
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 ) {
DWORD returnValue=ERROR_SUCCESS; SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY; PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority; BYTE Count; DWORD dwRID[8]; TCHAR pszPrincipal[MAX_PATH];
*pbWellKnownSID = TRUE; memset(&(dwRID[0]), 0, 8 * sizeof(DWORD));
DBG_ASSERT(wcslen(Principal) < MAX_PATH); wcscpy(pszPrincipal, Principal); _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; }
if (*pbWellKnownSID) { 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)) { 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, 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 (!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, 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 (!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) { err = 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) { err = 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, MAX_PATH * 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; BOOL fReturn = FALSE; 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); }
int GetGuestUserNameForDomain_FastWay(LPTSTR szDomainToLookUp,LPTSTR lpGuestUsrName) { int iReturn = FALSE; NET_API_STATUS NetStatus;
// for UaspGetDomainId()
SAM_HANDLE SamServerHandle = NULL; PPOLICY_ACCOUNT_DOMAIN_INFO pAccountDomainInfo = NULL;
PSID pAccountSid = NULL; PSID pDomainSid = NULL;
// for LookupAccountSid()
SID_NAME_USE sidNameUse = SidTypeUser; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; TCHAR szUserName[UNLEN+1]; DWORD cbName = UNLEN+1; // use UNLEN because DNLEN is too small
TCHAR szReferencedDomainName[UNLEN+1]; DWORD cbReferencedDomainName = sizeof(szReferencedDomainName);
// make sure not to return back gobble-d-gook
wcscpy(lpGuestUsrName, TEXT(""));
//
// 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)) { DWORD dwErr = GetLastError(); goto GetGuestUserNameForDomain_FastWay_Exit; }
//
// Retrieve the UserName for the specified SID
//
wcscpy(szUserName, TEXT("")); wcscpy(szReferencedDomainName, TEXT("")); // szDomainToLookUp=NULL for local machine
if (!LookupAccountSid(szDomainToLookUp, pAccountSid, szUserName, &cbName, szReferencedDomainName, &cbReferencedDomainName, &sidNameUse)) { DWORD dwErr = GetLastError(); goto GetGuestUserNameForDomain_FastWay_Exit; }
// Return the guest user name that we got.
wcscpy(lpGuestUsrName, szUserName);
// Wow, after all that, we must have succeeded
iReturn = 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 iReturn; }
int GetGuestUserName_SlowWay(LPWSTR lpGuestUsrName) {
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 { wcscpy(lpGuestUsrName, p[i].usri1_name); fStatus = FALSE; } } NetApiBufferFree(SortedBuffer); }
return 0; }
void GetGuestUserName(LPTSTR lpOutGuestUsrName) { // 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.
TCHAR szGuestUsrName[UNLEN+1]; LPTSTR pszComputerName = NULL; if (!GetGuestUserNameForDomain_FastWay(pszComputerName,szGuestUsrName)) {
// 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)
GetGuestUserName_SlowWay(szGuestUsrName); }
// Return back the username
wcscpy(lpOutGuestUsrName,szGuestUsrName); return; }
int GetGuestGrpName(LPTSTR lpGuestGrpName) { LPCTSTR ServerName = NULL; // local machine
// use UNLEN because DNLEN is too small
DWORD cbName = UNLEN+1; TCHAR ReferencedDomainName[UNLEN+1]; DWORD cbReferencedDomainName = sizeof(ReferencedDomainName); 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) { int err;
// get the sid of szAccountName
PSID pSID = NULL; BOOL bWellKnownSID = FALSE; err = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID); if (err != ERROR_SUCCESS) { return (err); }
// Get the localized LocalGroupName
TCHAR szLocalizedLocalGroupName[GNLEN + 1]; if (_wcsicmp(szLocalGroupName, TEXT("Guests")) == 0) { GetGuestGrpName(szLocalizedLocalGroupName); } else { wcscpy(szLocalizedLocalGroupName, szLocalGroupName); }
// transfer szLocalGroupName to WCHAR
WCHAR wszLocalGroupName[_MAX_PATH]; wcscpy(wszLocalGroupName, szLocalizedLocalGroupName);
LOCALGROUP_MEMBERS_INFO_0 buf;
buf.lgrmi0_sid = pSID;
if (fAction) { err = NetLocalGroupAddMembers(NULL, wszLocalGroupName, 0, (LPBYTE)&buf, 1); } else { err = NetLocalGroupDelMembers(NULL, wszLocalGroupName, 0, (LPBYTE)&buf, 1); }
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 = 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;
// get the sid of szAccountName
PSID pSID = NULL; BOOL bWellKnownSID = FALSE; err = GetPrincipalSID ((LPTSTR)szAccountName, &pSID, &bWellKnownSID); if (err != ERROR_SUCCESS) { return (err); }
LSA_UNICODE_STRING UserRightString; LSA_HANDLE PolicyHandle = NULL;
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) { 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;
wcscpy(szCopyOfUserName, szUserName);
//iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ChangeUserPassword().Start.name=%s,pass=%s"),szCopyOfUserName,szNewPassword));
if ( !GetComputerName( szRawComputerName, &dwLen )) {goto ChangeUserPassword_Exit;}
// Make a copy to be sure not to move the pointer around.
wcscpy(szTempFullUserName, szCopyOfUserName); // 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
wcscpy(szCopyOfUserName,pch+1); // 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] != '\\' ) {wcscpy(szComputerName,L"\\\\");} wcscat(szComputerName,szRawComputerName); //
// 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];
GetGuestUserName(defGuest);
GetGuestGrpName(defGuestGroup);
memset((PVOID)wchUsername, 0, sizeof(wchUsername)); memset((PVOID)wchPassword, 0, 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 ) { do { 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;} } else { break; } }
} while (FALSE);
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; BYTE *pBuffer; 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];
//
// First Load the Resources
//
HMODULE hBinary;
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;
int GetRandomNum(void) { int RandomNum; UCHAR cRandomByte;
if ( ProcSslGenerateRandomBits != NULL ) { (*ProcSslGenerateRandomBits)( &cRandomByte, 1 ); RandomNum = cRandomByte; } else { RandomNum = rand(); }
return(RandomNum); }
void ShuffleCharArray(int iSizeOfTheArray, TCHAR * lptsTheArray) { int i; int iTotal; int RandomNum;
iTotal = iSizeOfTheArray / sizeof(TCHAR); for (i=0; i<iTotal;i++ ) { // shuffle the array
RandomNum=GetRandomNum(); TCHAR c = lptsTheArray[i]; lptsTheArray[i]=lptsTheArray[RandomNum%iTotal]; lptsTheArray[RandomNum%iTotal]=c; } return; }
//
// Create a random password
//
void CreatePassword( TCHAR *pszPassword ) { //
// Use Maximum available password length, as
// setting any other length might run afoul
// of the minimum password length setting
//
int nLength = LM20_PWLEN; int iTotal = 0; int RandomNum = 0; int i; TCHAR six2pr[64] = { TEXT('A'), TEXT('B'), TEXT('C'), TEXT('D'), TEXT('E'), TEXT('F'), TEXT('G'), TEXT('H'), TEXT('I'), TEXT('J'), TEXT('K'), TEXT('L'), TEXT('M'), TEXT('N'), TEXT('O'), TEXT('P'), TEXT('Q'), TEXT('R'), TEXT('S'), TEXT('T'), TEXT('U'), TEXT('V'), TEXT('W'), TEXT('X'), TEXT('Y'), TEXT('Z'), TEXT('a'), TEXT('b'), TEXT('c'), TEXT('d'), TEXT('e'), TEXT('f'), TEXT('g'), TEXT('h'), TEXT('i'), TEXT('j'), TEXT('k'), TEXT('l'), TEXT('m'), TEXT('n'), TEXT('o'), TEXT('p'), TEXT('q'), TEXT('r'), TEXT('s'), TEXT('t'), TEXT('u'), TEXT('v'), TEXT('w'), TEXT('x'), TEXT('y'), TEXT('z'), TEXT('0'), TEXT('1'), TEXT('2'), TEXT('3'), TEXT('4'), TEXT('5'), TEXT('6'), TEXT('7'), TEXT('8'), TEXT('9'), TEXT('*'), TEXT('_') };
// create a random password
ProcSslGenerateRandomBits = NULL;
HINSTANCE hSslDll = LoadLibraryEx(TEXT("schannel.dll"), NULL, 0 ); if ( hSslDll ) { ProcSslGenerateRandomBits = (P_SslGenerateRandomBits)GetProcAddress( hSslDll, "SslGenerateRandomBits"); }
// See the random number generation for rand() call in GetRandomNum()
time_t timer; time( &timer ); srand( (unsigned int) timer );
// shuffle around the global six2pr[] array
ShuffleCharArray(sizeof(six2pr), (TCHAR*) &six2pr); // assign each character of the password array
iTotal = sizeof(six2pr) / sizeof(TCHAR); for ( i=0;i<nLength;i++ ) { RandomNum=GetRandomNum(); pszPassword[i]=six2pr[RandomNum%iTotal]; }
//
// in order to meet a possible
// policy set upon passwords..
//
// replace the last 4 chars with these:
//
// 1) something from !@#$%^&*()-+=
// 2) something from 1234567890
// 3) an uppercase letter
// 4) a lowercase letter
//
TCHAR something1[12] = {TEXT('!'), TEXT('@'), TEXT('#'), TEXT('$'), TEXT('^'), TEXT('&'), TEXT('*'), TEXT('('), TEXT(')'), TEXT('-'), TEXT('+'), TEXT('=')}; ShuffleCharArray(sizeof(something1), (TCHAR*) &something1); TCHAR something2[10] = {TEXT('0'), TEXT('1'), TEXT('2'), TEXT('3'), TEXT('4'), TEXT('5'), TEXT('6'), TEXT('7'), TEXT('8'), TEXT('9')}; ShuffleCharArray(sizeof(something2),(TCHAR*) &something2); TCHAR something3[26] = {TEXT('A'), TEXT('B'), TEXT('C'), TEXT('D'), TEXT('E'), TEXT('F'), TEXT('G'), TEXT('H'), TEXT('I'), TEXT('J'), TEXT('K'), TEXT('L'), TEXT('M'), TEXT('N'), TEXT('O'), TEXT('P'), TEXT('Q'), TEXT('R'), TEXT('S'), TEXT('T'), TEXT('U'), TEXT('V'), TEXT('W'), TEXT('X'), TEXT('Y'), TEXT('Z')}; ShuffleCharArray(sizeof(something3),(TCHAR*) &something3); TCHAR something4[26] = {TEXT('a'), TEXT('b'), TEXT('c'), TEXT('d'), TEXT('e'), TEXT('f'), TEXT('g'), TEXT('h'), TEXT('i'), TEXT('j'), TEXT('k'), TEXT('l'), TEXT('m'), TEXT('n'), TEXT('o'), TEXT('p'), TEXT('q'), TEXT('r'), TEXT('s'), TEXT('t'), TEXT('u'), TEXT('v'), TEXT('w'), TEXT('x'), TEXT('y'), TEXT('z')}; ShuffleCharArray(sizeof(something4),(TCHAR*)&something4);
RandomNum=GetRandomNum(); iTotal = sizeof(something1) / sizeof(TCHAR); pszPassword[nLength-4]=something1[RandomNum%iTotal];
RandomNum=GetRandomNum(); iTotal = sizeof(something2) / sizeof(TCHAR); pszPassword[nLength-3]=something2[RandomNum%iTotal];
RandomNum=GetRandomNum(); iTotal = sizeof(something3) / sizeof(TCHAR); pszPassword[nLength-2]=something3[RandomNum%iTotal];
RandomNum=GetRandomNum(); iTotal = sizeof(something4) / sizeof(TCHAR); pszPassword[nLength-1]=something4[RandomNum%iTotal];
pszPassword[nLength]=TEXT('\0');
if (hSslDll) {FreeLibrary( hSslDll );} }
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 ) { TCHAR keyName [256]; DWORD err;
wcscpy(keyName, TEXT("APPID\\")); wcscat(keyName, AppID);
if (SetPrincipal) { err = 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 ) {
TCHAR keyName [256]; DWORD err;
wcscpy(keyName, TEXT("APPID\\")); wcscat(keyName, AppID);
if (SetPrincipal) { err = 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) { int iReturn = FALSE; 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" };
/*
TCHAR szEntry[_MAX_PATH]; TCHAR szPassword[LM20_PWLEN+1];
CreatePassword(szPassword); */
//
// 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)) { memset (szAnsiUserName,0,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)) { wcscpy(pstAnonyPass, pstSyncPass); } 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
//
wcscpy(pstSyncPass, pstAnonyPass);
wcscpy(ustSyncName, ustAnonyName);
} } } else { fCreateAccount = TRUE; }
if (fCreateAccount) {
//
// The user does not exist, so let's create it.
// Make sure there's a password first.
//
if (gufmTemp == GUFM_NO_PASSWORD) { #if 0
//
// If it's not there then subauth should be set
// and the password should not be in the metabase.
// Also, if we add it in, then it could cause
// a synchronization problem in the IUSR password
// between W3 and FTP.
//
CreatePassword(pstAnonyPass);
fCreateAccount = WritePasswordToMetabase(pcCom, pszPath, dwPasswordMetaId, pstAnonyPass); #endif
}
if (fCreateAccount) { if (MD_WAM_USER_NAME == dwUserMetaId) { fRet = CreateUserAccount(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,TRUE); if( fRet ) { fUpdateComApplications = TRUE; } // 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.
if (!fRet) { if (TRUE == WaitForDCAvailability()) { // try again...
fRet = CreateUserAccount(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,TRUE); if( fRet ) { fUpdateComApplications = TRUE; } } } } else { fRet = CreateUserAccount(ustAnonyName,pstAnonyPass,dwUserCommentResourceId,dwUserFullNameResourceId,FALSE); if (!fRet) { if (TRUE == WaitForDCAvailability()) { // try again...
fRet = CreateUserAccount(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)) { memset (szAnsiUserName,0,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 ) { HRESULT hr = UpdateComApplications( pcCom, ustAnonyName, pstAnonyPass );
if( hr != S_OK ) { if( !g_eventLogForAccountRecreation ) { CreateEventLogObject(); }
if ( g_eventLogForAccountRecreation ) { g_eventLogForAccountRecreation->LogEvent( INET_SVC_ACCOUNT_COMUPDATE_FAILED, 0, NULL, hr ); } } } } 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)) { memset (szAnsiUserName,0,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;
MyLocalGroup.lgrpi1_name = szGroupName; MyLocalGroup.lgrpi1_comment = szGroupComment;
dwRes = NetLocalGroupAdd(NULL, 1, (LPBYTE)&MyLocalGroup, NULL); if(dwRes != NERR_Success && dwRes != NERR_GroupExists && dwRes != ERROR_ALIAS_EXISTS) { hr = HRESULT_FROM_WIN32(dwRes); }
return hr; }
VOID UpdateUsers( BOOL fRestore /* = FALSE */ ) { HRESULT hresTemp; IMDCOM *pcCom; BOOL fPerformUpdate = TRUE; BOOL fPerformPasswordValidate = FALSE; HKEY hkRegistryKey = NULL; DWORD dwRegReturn,dwBuffer, dwSize, 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));
RegisterAccountToLocalGroup(L"NT Authority\\Local Service", IIS_WP_GROUP, TRUE);
RegisterAccountToLocalGroup(L"NT Authority\\Network Service", IIS_WP_GROUP, TRUE);
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);
DBGPRINTF((DBG_CONTEXT, "Called into Updating IWAM user, hr %x\n", hr));
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);
DBGPRINTF((DBG_CONTEXT, "Called into Updating IUSR user, hr %x\n", hr));
//
// 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);
DBGPRINTF((DBG_CONTEXT, "Called into Updating IUSR user, hr %x\n", hr));
hr = UpdateAdminAcl(pcCom, L"/LM/W3SVC", IIS_WP_GROUP);
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) { BOOL b= FALSE, bDaclPresent = FALSE, bDaclDefaulted = FALSE;; PACL pDacl = NULL; ACCESS_ALLOWED_ACE* pAce; ACCESS_MASK dwOldMask, dwNewMask, dwExtraMask, dwMask;
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));
// get dacl length
DWORD cbDacl = pDacl->AclSize; // 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)) { wcscpy(szUserName, L"(unknown...)"); 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())); } } }
return; }
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, Sacl = NULL; PSID Owner = NULL, Group = NULL; DWORD dwDaclSize = 0; DWORD dwSaclSize = 0; DWORD dwOwnerSize = 0; DWORD dwPrimaryGroupSize = 0;
if( !IsValidSecurityDescriptor( psdOriginal ) ) { goto cleanup; }
if( !GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) { DWORD err = GetLastError(); 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; 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;
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; } }
DWORD AccessMask = (MD_ACR_READ | MD_ACR_WRITE | MD_ACR_RESTRICTED_WRITE | MD_ACR_UNSECURE_PROPS_READ | MD_ACR_ENUM_KEYS | MD_ACR_WRITE_DAC);
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( IMDCOM * pcCom, 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:
pcCom - metabase object 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 = NOERROR; 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; BSTR bstrAppCollectionName = NULL; LONG nAppsInCollection; LONG iCurrentApp; LONG nChanges; BOOL fAppCreated = FALSE;
VARIANT varOldAppIdentity; VARIANT varNewAppIdentity; VARIANT varNewAppPassword;
// 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 );
//
// 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"
//
if( !bufMDPath.Resize( wcslen( pwszCurrentPath ) * sizeof( WCHAR ) + 20 ) ) { hr = E_OUTOFMEMORY; goto cleanup; } pwszMDPath = ( WCHAR* )bufMDPath.QueryPtr(); wcscpy( pwszMDPath, ROOTMDPath ); wcscat( pwszMDPath, pwszCurrentPath );
//
// Get rid of the trailing '/' or '\\'
//
dwMDPathLen = 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; hr = CreateCOMPlusApplication( pwszMDPath, wszAppPackageId, wszWamClsid, &fAppCreated ); 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++; } }
// 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
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( L"Applications", (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( L"Identity", &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( L"Identity", varNewAppIdentity ); if( FAILED(hr) ) { DBGERROR(( DBG_CONTEXT, "Failed to set new Identify (%08x)\n", hr )); fNoErrors = FALSE; continue; }
hr = pComApp->put_Value( L"Password", 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;
// 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 WaitForDCAvailability(void) { BOOL bRetVal = FALSE; HANDLE hEvent; DWORD dwResult; DWORD dwCount = 0, dwMax; DWORD dwMaxWait = 20000; // 20 second 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, dwSize = sizeof( 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; }
|