Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

558 lines
16 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <rpc.h>
  6. #include <ntdsapi.h>
  7. #define SECURITY_WIN32
  8. #include <security.h>
  9. #include <aclapi.h>
  10. #include <winldap.h>
  11. #include <ntldap.h>
  12. #include <dsgetdc.h>
  13. #include <wbemcli.h>
  14. #include "smartptr.h"
  15. #include "rsoputil.h"
  16. #include "rsopdbg.h"
  17. #include "rsopsec.h"
  18. #include <strsafe.h>
  19. extern "C" {
  20. DWORD CheckAccessForPolicyGeneration( HANDLE hToken,
  21. LPCWSTR szContainer,
  22. LPWSTR szDomain,
  23. BOOL bLogging,
  24. BOOL* pbAccessGranted);
  25. }
  26. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  27. //*************************************************************
  28. //
  29. // CheckAccessForPolicyGeneration()
  30. //
  31. // Purpose: Finds out whether user has the right to generate rsop data
  32. //
  33. // Parameters: hToken - Token of the user who is using the tool
  34. // szContainer - DS Container with which it needs to be validated
  35. // bLogging - Logging or Planning mode
  36. // pbAccessGranted - Access was granted or not
  37. //
  38. // Return: ERROR_SUCCESS
  39. // Error Code otherwise
  40. //
  41. // The container passed in is actually parsed to figure out the first ou= or
  42. // dc= supercontainer and then the rights are evaluated..
  43. //
  44. //*************************************************************
  45. DWORD
  46. CheckAccessForPolicyGeneration( HANDLE hToken,
  47. LPCWSTR szContainer,
  48. LPWSTR szDomain,
  49. BOOL bLogging,
  50. BOOL* pbAccessGranted)
  51. {
  52. DWORD dwError = ERROR_SUCCESS;
  53. XHandle xhTokenDup;
  54. BOOL bDomain = FALSE;
  55. // BOOLEAN bSecurityWasEnabled;
  56. WCHAR *pDomainString[1];
  57. PDS_NAME_RESULT pNameResult = NULL;
  58. *pbAccessGranted = 0;
  59. //
  60. // Parse the container first to get the OU= or DC=
  61. // The "Actual SOM"
  62. //
  63. while (*szContainer) {
  64. //
  65. // See if the DN name starts with OU=
  66. //
  67. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  68. szContainer, 3, TEXT("OU="), 3) == CSTR_EQUAL) {
  69. break;
  70. }
  71. //
  72. // See if the DN name starts with DC=
  73. //
  74. else if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  75. szContainer, 3, TEXT("DC="), 3) == CSTR_EQUAL) {
  76. break;
  77. }
  78. //
  79. // Move to the next chunk of the DN name
  80. //
  81. while (*szContainer && (*szContainer != TEXT(','))) {
  82. szContainer++;
  83. }
  84. if (*szContainer == TEXT(',')) {
  85. szContainer++;
  86. }
  87. }
  88. if (!*szContainer) {
  89. return ERROR_INVALID_PARAMETER;
  90. }
  91. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"CheckAccessForPolicyGeneration: SOM for account is %s", szContainer );
  92. //
  93. // See if the DN name starts with DC=
  94. //
  95. if (CompareString (LOCALE_INVARIANT, NORM_IGNORECASE,
  96. szContainer, 3, TEXT("DC="), 3) == CSTR_EQUAL) {
  97. bDomain = TRUE;
  98. }
  99. //
  100. // preparse the name to just get the string , dc=
  101. //
  102. XPtrLF<WCHAR> xwszDomain;
  103. LPWSTR szDomLocal;
  104. if (!szDomain) {
  105. dwError = GetDomain(szContainer, &xwszDomain);
  106. if (dwError != ERROR_SUCCESS) {
  107. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: GetDomain failed with error %d", dwError );
  108. return dwError;
  109. }
  110. szDomLocal = xwszDomain;
  111. }
  112. else {
  113. szDomLocal = szDomain;
  114. }
  115. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"CheckAccessForPolicyGeneration: Som resides in domain %s", szDomLocal );
  116. DWORD dwDSObjLength = wcslen(L"LDAP://") + wcslen(szDomLocal) + wcslen(szContainer) + 5;
  117. XPtrLF<WCHAR> xszDSObject = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * ( dwDSObjLength ));
  118. if (!xszDSObject) {
  119. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: AllocMem failed with %d.", GetLastError() );
  120. return GetLastError();
  121. }
  122. HRESULT hr = StringCchCopy(xszDSObject, dwDSObjLength, L"LDAP://");
  123. if(SUCCEEDED(hr))
  124. hr = StringCchCat(xszDSObject, dwDSObjLength, szDomLocal);
  125. if(SUCCEEDED(hr))
  126. hr = StringCchCat(xszDSObject, dwDSObjLength, L"/");
  127. if(SUCCEEDED(hr))
  128. hr = StringCchCat(xszDSObject, dwDSObjLength, szContainer);
  129. if(FAILED(hr))
  130. return HRESULT_CODE(hr);
  131. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"CheckAccessForPolicyGeneration: getting SD off %s", xszDSObject );
  132. if ( !DuplicateTokenEx( hToken,
  133. TOKEN_IMPERSONATE | TOKEN_QUERY,
  134. 0,
  135. SecurityImpersonation,
  136. TokenImpersonation,
  137. &xhTokenDup ) )
  138. {
  139. dwError = GetLastError();
  140. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: DuplicateTokenEx failed, 0x%X", dwError );
  141. return dwError;
  142. }
  143. //
  144. // Enable privilege to read SDs
  145. //
  146. /*
  147. dwError = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, TRUE, FALSE, &bSecurityWasEnabled);
  148. if (!NT_SUCCESS(dwError)) {
  149. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: DuplicateTokenEx failed, 0x%X", dwError );
  150. return dwError;
  151. }
  152. */
  153. XPtrLF<SECURITY_DESCRIPTOR> xptrSD;
  154. dwError = GetNamedSecurityInfo( (LPWSTR) xszDSObject,
  155. SE_DS_OBJECT_ALL,
  156. DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION ,
  157. 0,
  158. 0,
  159. 0,
  160. 0,
  161. (void**) &xptrSD );
  162. if ( !dwError )
  163. {
  164. //
  165. // bf967aa5-0de6-11d0-a285-00aa003049e
  166. //
  167. GUID OUClass = {0xbf967aa5, 0x0de6, 0x11d0, 0xa2, 0x85, 0x00, 0xaa, 0x00, 0x30, 0x49, 0xe2};
  168. //
  169. // 19195a5b-6da0-11d0-afd3-00c04fd930c9
  170. //
  171. GUID DomainClass = {0x19195a5b, 0x6da0, 0x11d0, 0xaf, 0xd3, 0x00, 0xc0, 0x4f, 0xd9, 0x30, 0xc9};
  172. //
  173. // b7b1b3dd-ab09-4242-9e30-9980e5d322f7
  174. //
  175. GUID planningRight = {0xb7b1b3dd, 0xab09, 0x4242, 0x9e, 0x30, 0x99, 0x80, 0xe5, 0xd3, 0x22, 0xf7};
  176. //
  177. // b7b1b3de-ab09-4242-9e30-9980e5d322f7
  178. //
  179. GUID loggingRight = {0xb7b1b3de, 0xab09, 0x4242, 0x9e, 0x30, 0x99, 0x80, 0xe5, 0xd3, 0x22, 0xf7};
  180. OBJECT_TYPE_LIST ObjType[2];
  181. ObjType[0].Level = ACCESS_OBJECT_GUID;
  182. ObjType[0].Sbz = 0;
  183. if (bDomain) {
  184. ObjType[0].ObjectType = &DomainClass;
  185. }
  186. else {
  187. ObjType[0].ObjectType = &OUClass;
  188. }
  189. ObjType[1].Level = ACCESS_PROPERTY_SET_GUID;
  190. ObjType[1].Sbz = 0;
  191. if (bLogging) {
  192. ObjType[1].ObjectType = &loggingRight;
  193. }
  194. else {
  195. ObjType[1].ObjectType = &planningRight;
  196. }
  197. GENERIC_MAPPING GenericMapping = {
  198. DS_GENERIC_READ,
  199. DS_GENERIC_WRITE,
  200. DS_GENERIC_EXECUTE,
  201. DS_GENERIC_ALL
  202. };
  203. const DWORD PriviledgeSize = 2 * ( sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES) );
  204. BYTE PrivilegeSetBuffer[PriviledgeSize];
  205. DWORD cPrivilegeSet = PriviledgeSize;
  206. PPRIVILEGE_SET pPrivilegeSet = (PPRIVILEGE_SET)PrivilegeSetBuffer;
  207. DWORD dwGrantedAccess;
  208. if ( !AccessCheckByType( xptrSD,
  209. 0,
  210. xhTokenDup,
  211. ACTRL_DS_CONTROL_ACCESS,
  212. ObjType,
  213. ARRAYSIZE(ObjType),
  214. &GenericMapping,
  215. pPrivilegeSet,
  216. &cPrivilegeSet,
  217. &dwGrantedAccess,
  218. pbAccessGranted ) )
  219. {
  220. dwError = GetLastError();
  221. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: AccessCheckByType failed, 0x%X", dwError );
  222. }
  223. }
  224. else {
  225. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: GetNamedSecurityInfo failed, 0x%X", dwError );
  226. }
  227. /*
  228. dwError = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, bSecurityWasEnabled, FALSE, &bSecurityWasEnabled);
  229. if (!NT_SUCCESS(dwError)) {
  230. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: DuplicateTokenEx failed, 0x%X", dwError );
  231. return dwError;
  232. }
  233. */
  234. return dwError;
  235. }
  236. //*************************************************************
  237. //
  238. // GetSOM()
  239. //
  240. // Purpose: Finds out the FQDN of a given user/computer
  241. //
  242. // Parameters: szAccount - User or computer Account name in an appropriate format
  243. //
  244. // Return: SOM, NULL otherwise. GetLastError() for details
  245. // This just returns the DN of the user
  246. //
  247. //*************************************************************
  248. LPWSTR
  249. GetSOM( LPCWSTR szAccount )
  250. {
  251. DWORD dwSize = 0;
  252. XPtrLF<WCHAR> xszXlatName;
  253. XPtrLF<WCHAR> xszSOM;
  254. TranslateName( szAccount,
  255. NameUnknown,
  256. NameFullyQualifiedDN,
  257. xszXlatName,
  258. &dwSize );
  259. if (!dwSize)
  260. {
  261. return 0;
  262. }
  263. xszXlatName = (LPWSTR)LocalAlloc( LPTR, ( dwSize + 1 ) * sizeof( WCHAR ) );
  264. if ( !xszXlatName )
  265. {
  266. return 0;
  267. }
  268. if ( !TranslateName(szAccount,
  269. NameUnknown,
  270. NameFullyQualifiedDN,
  271. xszXlatName,
  272. &dwSize ) )
  273. {
  274. return 0;
  275. }
  276. xszSOM = xszXlatName.Acquire();
  277. return xszSOM.Acquire();
  278. }
  279. //*************************************************************
  280. //
  281. // GetDomain()
  282. //
  283. // Purpose: Finds out the domain given a SOM.
  284. //
  285. // Parameters: szSOM - SOM
  286. //
  287. // Return: domain Dns if success, null otherwise
  288. //
  289. //*************************************************************
  290. DWORD
  291. GetDomain( LPCWSTR szSOM, LPWSTR *pszDomain )
  292. {
  293. DWORD dwError = ERROR_SUCCESS;
  294. WCHAR *pDomainString[1];
  295. PDS_NAME_RESULT pNameResult = NULL;
  296. //
  297. // preparse the name to just get the string , dc=
  298. //
  299. pDomainString[0] = NULL;
  300. LPWSTR pwszTemp = (LPWSTR)szSOM;
  301. while ( *pwszTemp ) {
  302. if (CompareString ( LOCALE_INVARIANT, NORM_IGNORECASE,
  303. pwszTemp, 3, TEXT("DC="), 3) == CSTR_EQUAL ) {
  304. pDomainString[0] = pwszTemp;
  305. break;
  306. }
  307. //
  308. // Move to the next chunk of the DN name
  309. //
  310. while ( *pwszTemp && (*pwszTemp != TEXT(',')))
  311. pwszTemp++;
  312. if ( *pwszTemp == TEXT(','))
  313. pwszTemp++;
  314. }
  315. if (pDomainString[0] == NULL) {
  316. dbg.Msg( DEBUG_MESSAGE_WARNING, L"GetDomain: Som doesn't have DC=. failing" );
  317. return ERROR_INVALID_PARAMETER;
  318. }
  319. dwError = DsCrackNames( (HANDLE) -1,
  320. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  321. DS_FQDN_1779_NAME,
  322. DS_CANONICAL_NAME,
  323. 1,
  324. pDomainString,
  325. &pNameResult );
  326. if ( dwError != ERROR_SUCCESS
  327. || pNameResult->cItems == 0
  328. || pNameResult->rItems[0].status != ERROR_SUCCESS
  329. || pNameResult->rItems[0].pDomain == NULL ) {
  330. dbg.Msg( DEBUG_MESSAGE_WARNING, L"GetDomain: DsCrackNames failed with 0x%x.", dwError );
  331. return dwError;
  332. }
  333. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"GetDomain: Som resides in domain %s", pNameResult->rItems[0].pDomain );
  334. DWORD dwDomainLength = wcslen(pNameResult->rItems[0].pDomain) + 2;
  335. XPtrLF<WCHAR> xszDomain = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * ( dwDomainLength ));
  336. if (!xszDomain) {
  337. dbg.Msg( DEBUG_MESSAGE_WARNING, L"CheckAccessForPolicyGeneration: AllocMem failed with %d.", GetLastError() );
  338. DsFreeNameResult( pNameResult );
  339. return GetLastError();
  340. }
  341. HRESULT hr = StringCchCopy(xszDomain, dwDomainLength, pNameResult->rItems[0].pDomain);
  342. if(FAILED(hr)){
  343. DsFreeNameResult( pNameResult );
  344. return HRESULT_CODE(hr);
  345. }
  346. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"GetDomain: Domain for som %s = %s", szSOM, xszDomain );
  347. DsFreeNameResult( pNameResult );
  348. *pszDomain = xszDomain.Acquire();
  349. return ERROR_SUCCESS;
  350. }
  351. //*************************************************************
  352. //
  353. // AuthenticateUser()
  354. //
  355. // Purpose: Authenticates whether the user has the right to do the operation
  356. //
  357. // Parameters: hToken - Token of the user
  358. // szMachSOM - Machine SOM (optional)
  359. // szUserSOM - User SOM (optional)
  360. // bLogging - Logging or Planning mode
  361. //
  362. // Return: S_OK on success, error code otherwise
  363. //
  364. //*************************************************************
  365. HRESULT AuthenticateUser(HANDLE hToken, LPCWSTR szMachSOM, LPCWSTR szUserSOM, BOOL bLogging, DWORD *pdwExtendedInfo)
  366. {
  367. if ( !szMachSOM && !szUserSOM )
  368. {
  369. dbg.Msg( DEBUG_MESSAGE_WARNING, L"AuthenticateUser: No mach and user som specified" );
  370. return E_INVALIDARG;
  371. }
  372. DWORD dwError = ERROR_SUCCESS;
  373. BOOL bMachAccess = FALSE, bUserAccess = FALSE;
  374. //
  375. // authenticate for machine SOM
  376. //
  377. *pdwExtendedInfo = 0;
  378. if (szMachSOM) {
  379. *pdwExtendedInfo |= RSOP_COMPUTER_ACCESS_DENIED;
  380. }
  381. if (szUserSOM) {
  382. *pdwExtendedInfo |= RSOP_USER_ACCESS_DENIED;
  383. }
  384. if (szMachSOM) {
  385. dwError = CheckAccessForPolicyGeneration( hToken,
  386. szMachSOM,
  387. NULL,
  388. bLogging,
  389. &bMachAccess
  390. );
  391. if ( dwError != ERROR_SUCCESS )
  392. {
  393. dbg.Msg( DEBUG_MESSAGE_WARNING, L"AuthenticateUser: CheckAccessForPolicyGeneration Machine returned error - %d", dwError );
  394. return HRESULT_FROM_WIN32( dwError );
  395. }
  396. if ( bMachAccess )
  397. {
  398. *pdwExtendedInfo &= ~RSOP_COMPUTER_ACCESS_DENIED;
  399. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"AuthenticateUser: Access granted on Machine SOM");
  400. }
  401. }
  402. else {
  403. bMachAccess = TRUE;
  404. }
  405. //
  406. // authenticate for user SOM
  407. //
  408. if (szUserSOM) {
  409. dwError = CheckAccessForPolicyGeneration( hToken,
  410. szUserSOM,
  411. NULL,
  412. bLogging,
  413. &bUserAccess
  414. );
  415. if ( dwError != ERROR_SUCCESS )
  416. {
  417. dbg.Msg( DEBUG_MESSAGE_WARNING, L"AuthenticateUser: CheckAccessForPolicyGeneration User returned error - %d", dwError );
  418. return HRESULT_FROM_WIN32( dwError );
  419. }
  420. if ( bUserAccess )
  421. {
  422. *pdwExtendedInfo &= ~RSOP_USER_ACCESS_DENIED;
  423. dbg.Msg( DEBUG_MESSAGE_VERBOSE, L"AuthenticateUser: Access granted on User SOM");
  424. }
  425. }
  426. else {
  427. bUserAccess = TRUE;
  428. }
  429. if ( !bUserAccess || !bMachAccess )
  430. return E_ACCESSDENIED;
  431. return S_OK;
  432. }