#include #include #include #include #include #include #define SECURITY_WIN32 #include #include #include #include #include #include #include "smartptr.h" #include "rsoputil.h" #include "rsopdbg.h" #include "rsopsec.h" extern "C" { DWORD CheckAccessForPolicyGeneration( HANDLE hToken, LPCWSTR szContainer, LPWSTR szDomain, BOOL bLogging, BOOL* pbAccessGranted); } #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) //************************************************************* // // CheckAccessForPolicyGeneration() // // Purpose: Finds out whether user has the right to generate rsop data // // Parameters: hToken - Token of the user who is using the tool // szContainer - DS Container with which it needs to be validated // bLogging - Logging or Planning mode // pbAccessGranted - Access was granted or not // // Return: ERROR_SUCCESS // Error Code otherwise // // The container passed in is actually parsed to figure out the first ou= or // dc= supercontainer and then the rights are evaluated.. // //************************************************************* DWORD CheckAccessForPolicyGeneration( HANDLE hToken, LPCWSTR szContainer, LPWSTR szDomain, BOOL bLogging, BOOL* pbAccessGranted) { DWORD dwError = ERROR_SUCCESS; XHandle xhTokenDup; BOOL bDomain = FALSE; // BOOLEAN bSecurityWasEnabled; WCHAR *pDomainString[1]; PDS_NAME_RESULT pNameResult = NULL; *pbAccessGranted = 0; // // Parse the container first to get the OU= or DC= // The "Actual SOM" // while (*szContainer) { // // See if the DN name starts with OU= // if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szContainer, 3, TEXT("OU="), 3) == CSTR_EQUAL) { break; } // // See if the DN name starts with DC= // else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szContainer, 3, TEXT("DC="), 3) == CSTR_EQUAL) { break; } // // Move to the next chunk of the DN name // while (*szContainer && (*szContainer != TEXT(','))) { szContainer++; } if (*szContainer == TEXT(',')) { szContainer++; } } if (!*szContainer) { return ERROR_INVALID_PARAMETER; } dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"CheckAccessForPolicyGeneration: SOM for account is %s", szContainer ); // // See if the DN name starts with DC= // if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szContainer, 3, TEXT("DC="), 3) == CSTR_EQUAL) { bDomain = TRUE; } // // preparse the name to just get the string , dc= // XPtrLF xwszDomain; LPWSTR szDomLocal; if (!szDomain) { dwError = GetDomain(szContainer, &xwszDomain); if (dwError != ERROR_SUCCESS) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: GetDomain failed with error %d", dwError ); return dwError; } szDomLocal = xwszDomain; } else { szDomLocal = szDomain; } dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"CheckAccessForPolicyGeneration: Som resides in domain %s", szDomLocal ); XPtrLF xszDSObject = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(L"LDAP://")+ wcslen(szDomLocal)+ wcslen(szContainer)+5)); if (!xszDSObject) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: AllocMem failed with %d.", GetLastError() ); return GetLastError(); } wcscpy(xszDSObject, L"LDAP://"); wcscat(xszDSObject, szDomLocal); wcscat(xszDSObject, L"/"); wcscat(xszDSObject, szContainer); dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"CheckAccessForPolicyGeneration: getting SD off %s", xszDSObject ); if ( !DuplicateTokenEx( hToken, TOKEN_IMPERSONATE | TOKEN_QUERY, 0, SecurityImpersonation, TokenImpersonation, &xhTokenDup ) ) { dwError = GetLastError(); dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: DuplicateTokenEx failed, 0x%X", dwError ); return dwError; } // // Enable privilege to read SDs // /* dwError = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, TRUE, FALSE, &bSecurityWasEnabled); if (!NT_SUCCESS(dwError)) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: DuplicateTokenEx failed, 0x%X", dwError ); return dwError; } */ XPtrLF xptrSD; dwError = GetNamedSecurityInfo( (LPWSTR) xszDSObject, SE_DS_OBJECT_ALL, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION , 0, 0, 0, 0, (void**) &xptrSD ); if ( !dwError ) { // // bf967aa5-0de6-11d0-a285-00aa003049e // GUID OUClass = {0xbf967aa5, 0x0de6, 0x11d0, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2}; // // 19195a5b-6da0-11d0-afd3-00c04fd930c9 // GUID DomainClass = {0x19195a5b, 0x6da0, 0x11d0, 0xaf, 0xd3, 0x00, 0xc0, 0x4f, 0xd9, 0x30, 0xc9}; // // b7b1b3dd-ab09-4242-9e30-9980e5d322f7 // GUID planningRight = {0xb7b1b3dd, 0xab09, 0x4242, 0x9e, 0x30, 0x99, 0x80, 0xe5, 0xd3, 0x22, 0xf7}; // // b7b1b3de-ab09-4242-9e30-9980e5d322f7 // GUID loggingRight = {0xb7b1b3de, 0xab09, 0x4242, 0x9e, 0x30, 0x99, 0x80, 0xe5, 0xd3, 0x22, 0xf7}; OBJECT_TYPE_LIST ObjType[2]; ObjType[0].Level = ACCESS_OBJECT_GUID; ObjType[0].Sbz = 0; if (bDomain) { ObjType[0].ObjectType = &DomainClass; } else { ObjType[0].ObjectType = &OUClass; } ObjType[1].Level = ACCESS_PROPERTY_SET_GUID; ObjType[1].Sbz = 0; if (bLogging) { ObjType[1].ObjectType = &loggingRight; } else { ObjType[1].ObjectType = &planningRight; } GENERIC_MAPPING GenericMapping = { DS_GENERIC_READ, DS_GENERIC_WRITE, DS_GENERIC_EXECUTE, DS_GENERIC_ALL }; const DWORD PriviledgeSize = 2 * ( sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES) ); BYTE PrivilegeSetBuffer[PriviledgeSize]; DWORD cPrivilegeSet = PriviledgeSize; PPRIVILEGE_SET pPrivilegeSet = (PPRIVILEGE_SET)PrivilegeSetBuffer; DWORD dwGrantedAccess; if ( !AccessCheckByType( xptrSD, 0, xhTokenDup, ACTRL_DS_CONTROL_ACCESS, ObjType, ARRAYSIZE(ObjType), &GenericMapping, pPrivilegeSet, &cPrivilegeSet, &dwGrantedAccess, pbAccessGranted ) ) { dwError = GetLastError(); dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: AccessCheckByType failed, 0x%X", dwError ); } } else { dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: GetNamedSecurityInfo failed, 0x%X", dwError ); } /* dwError = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, bSecurityWasEnabled, FALSE, &bSecurityWasEnabled); if (!NT_SUCCESS(dwError)) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: DuplicateTokenEx failed, 0x%X", dwError ); return dwError; } */ return dwError; } //************************************************************* // // GetSOM() // // Purpose: Finds out the FQDN of a given user/computer // // Parameters: szAccount - User or computer Account name in an appropriate format // // Return: SOM, NULL otherwise. GetLastError() for details // This just returns the DN of the user // //************************************************************* LPWSTR GetSOM( LPCWSTR szAccount ) { DWORD dwSize = 0; XPtrLF xszXlatName; XPtrLF xszSOM; TranslateName( szAccount, NameUnknown, NameFullyQualifiedDN, xszXlatName, &dwSize ); if (!dwSize) { return 0; } xszXlatName = (LPWSTR)LocalAlloc( LPTR, ( dwSize + 1 ) * sizeof( WCHAR ) ); if ( !xszXlatName ) { return 0; } if ( !TranslateName(szAccount, NameUnknown, NameFullyQualifiedDN, xszXlatName, &dwSize ) ) { return 0; } xszSOM = xszXlatName.Acquire(); return xszSOM.Acquire(); } //************************************************************* // // GetDomain() // // Purpose: Finds out the domain given a SOM. // // Parameters: szSOM - SOM // // Return: domain Dns if success, null otherwise // //************************************************************* DWORD GetDomain( LPCWSTR szSOM, LPWSTR *pszDomain ) { DWORD dwError = ERROR_SUCCESS; WCHAR *pDomainString[1]; PDS_NAME_RESULT pNameResult = NULL; // // preparse the name to just get the string , dc= // pDomainString[0] = NULL; LPWSTR pwszTemp = (LPWSTR)szSOM; while ( *pwszTemp ) { if (CompareString ( LOCALE_USER_DEFAULT, NORM_IGNORECASE, pwszTemp, 3, TEXT("DC="), 3) == CSTR_EQUAL ) { pDomainString[0] = pwszTemp; break; } // // Move to the next chunk of the DN name // while ( *pwszTemp && (*pwszTemp != TEXT(','))) pwszTemp++; if ( *pwszTemp == TEXT(',')) pwszTemp++; } if (pDomainString[0] == NULL) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"GetDomain: Som doesn't have DC=. failing" ); return ERROR_INVALID_PARAMETER; } dwError = DsCrackNames( (HANDLE) -1, DS_NAME_FLAG_SYNTACTICAL_ONLY, DS_FQDN_1779_NAME, DS_CANONICAL_NAME, 1, pDomainString, &pNameResult ); if ( dwError != ERROR_SUCCESS || pNameResult->cItems == 0 || pNameResult->rItems[0].status != ERROR_SUCCESS || pNameResult->rItems[0].pDomain == NULL ) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"GetDomain: DsCrackNames failed with 0x%x.", dwError ); return dwError; } dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"GetDomain: Som resides in domain %s", pNameResult->rItems[0].pDomain ); XPtrLF xszDomain = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(pNameResult->rItems[0].pDomain)+2)); if (!xszDomain) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: AllocMem failed with %d.", GetLastError() ); DsFreeNameResult( pNameResult ); return GetLastError(); } wcscpy(xszDomain, pNameResult->rItems[0].pDomain); dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"GetDomain: Domain for som %s = %s", szSOM, xszDomain ); DsFreeNameResult( pNameResult ); *pszDomain = xszDomain.Acquire(); return ERROR_SUCCESS; } //************************************************************* // // AuthenticateUser() // // Purpose: Authenticates whether the user has the right to do the operation // // Parameters: hToken - Token of the user // szMachSOM - Machine SOM (optional) // szUserSOM - User SOM (optional) // bLogging - Logging or Planning mode // // Return: S_OK on success, error code otherwise // //************************************************************* HRESULT AuthenticateUser(HANDLE hToken, LPCWSTR szMachSOM, LPCWSTR szUserSOM, BOOL bLogging, DWORD *pdwExtendedInfo) { if ( !szMachSOM && !szUserSOM ) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"AuthenticateUser: No mach and user som specified" ); return E_INVALIDARG; } DWORD dwError = ERROR_SUCCESS; BOOL bMachAccess = FALSE, bUserAccess = FALSE; // // authenticate for machine SOM // if (szMachSOM) { dwError = CheckAccessForPolicyGeneration( hToken, szMachSOM, NULL, bLogging, &bMachAccess ); if ( dwError != ERROR_SUCCESS ) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"AuthenticateUser: CheckAccessForPolicyGeneration Machine returned error - %d", dwError ); return HRESULT_FROM_WIN32( dwError ); } if ( !bMachAccess ) { *pdwExtendedInfo |= RSOP_COMPUTER_ACCESS_DENIED; dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"AuthenticateUser: No access on Machine SOM"); } } else { bMachAccess = TRUE; } // // authenticate for user SOM // if (szUserSOM) { dwError = CheckAccessForPolicyGeneration( hToken, szUserSOM, NULL, bLogging, &bUserAccess ); if ( dwError != ERROR_SUCCESS ) { dbg.Msg( DEBUG_MESSAGE_WARNING, L"AuthenticateUser: CheckAccessForPolicyGeneration User returned error - %d", dwError ); return HRESULT_FROM_WIN32( dwError ); } if ( !bUserAccess ) { *pdwExtendedInfo |= RSOP_USER_ACCESS_DENIED; dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"AuthenticateUser: No access on User SOM"); } } else { bUserAccess = TRUE; } if ( !bUserAccess || !bMachAccess ) return E_ACCESSDENIED; return S_OK; }