Source code of Windows XP (NT5)
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.

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