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.

1475 lines
44 KiB

  1. #include "precomp.h"
  2. #include <tchar.h>
  3. #include "wmiauthz.h"
  4. /**************************************************************************
  5. Win32 Authz prototypes
  6. ***************************************************************************/
  7. typedef BOOL (WINAPI*PAuthzAccessCheck)(
  8. IN DWORD Flags,
  9. IN AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext,
  10. IN PAUTHZ_ACCESS_REQUEST pRequest,
  11. IN AUTHZ_AUDIT_EVENT_HANDLE AuditInfo OPTIONAL,
  12. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  13. IN PSECURITY_DESCRIPTOR *OptionalSecurityDescriptorArray OPTIONAL,
  14. IN DWORD OptionalSecurityDescriptorCount,
  15. IN OUT PAUTHZ_ACCESS_REPLY pReply,
  16. OUT PAUTHZ_ACCESS_CHECK_RESULTS_HANDLE pAuthzHandle OPTIONAL );
  17. typedef BOOL (WINAPI*PAuthzInitializeResourceManager)(
  18. IN DWORD AuthzFlags,
  19. IN PFN_AUTHZ_DYNAMIC_ACCESS_CHECK pfnAccessCheck OPTIONAL,
  20. IN PFN_AUTHZ_COMPUTE_DYNAMIC_GROUPS pfnComputeDynamicGroups OPTIONAL,
  21. IN PFN_AUTHZ_FREE_DYNAMIC_GROUPS pfnFreeDynamicGroups OPTIONAL,
  22. IN PCWSTR szResourceManagerName,
  23. OUT PAUTHZ_RESOURCE_MANAGER_HANDLE pAuthzResourceManager
  24. );
  25. typedef BOOL (WINAPI*PAuthzInitializeContextFromSid)(
  26. IN DWORD Flags,
  27. IN PSID UserSid,
  28. IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
  29. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  30. IN LUID Identifier,
  31. IN PVOID DynamicGroupArgs OPTIONAL,
  32. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  33. );
  34. typedef BOOL (WINAPI*PAuthzInitializeContextFromToken)(
  35. IN HANDLE TokenHandle,
  36. IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
  37. IN PLARGE_INTEGER pExpirationTime OPTIONAL,
  38. IN LUID Identifier,
  39. IN DWORD Flags,
  40. IN PVOID DynamicGroupArgs OPTIONAL,
  41. OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
  42. );
  43. typedef BOOL (WINAPI*PAuthzFreeContext)( AUTHZ_CLIENT_CONTEXT_HANDLE );
  44. typedef BOOL (WINAPI*PAuthzFreeResourceManager)( AUTHZ_RESOURCE_MANAGER_HANDLE );
  45. BOOL WINAPI ComputeDynamicGroups(
  46. IN AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext,
  47. IN PVOID Args,
  48. OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
  49. OUT PDWORD pSidCount,
  50. OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
  51. OUT PDWORD pRestrictedSidCount
  52. )
  53. {
  54. BOOL bRet;
  55. *pRestrictedSidAttrArray = NULL;
  56. *pRestrictedSidCount = 0;
  57. //
  58. // if sid is not local system, then don't need to do anything.
  59. //
  60. *pSidAttrArray = NULL;
  61. *pSidCount = 0;
  62. if ( !*(BOOL*)(Args) )
  63. {
  64. bRet = TRUE;
  65. }
  66. else
  67. {
  68. //
  69. // need to add authenticated users and everyone groups.
  70. //
  71. PSID_AND_ATTRIBUTES psa = new SID_AND_ATTRIBUTES[2];
  72. if ( psa != NULL )
  73. {
  74. ZeroMemory( psa, sizeof(SID_AND_ATTRIBUTES)*2 );
  75. SID_IDENTIFIER_AUTHORITY wid = SECURITY_WORLD_SID_AUTHORITY;
  76. SID_IDENTIFIER_AUTHORITY ntid = SECURITY_NT_AUTHORITY;
  77. if ( bRet = AllocateAndInitializeSid( &wid,
  78. 1,
  79. SECURITY_WORLD_RID,
  80. 0,0,0,0,0,0,0,
  81. &psa[0].Sid ) )
  82. {
  83. if ( bRet = AllocateAndInitializeSid( &ntid,
  84. 1,
  85. SECURITY_AUTHENTICATED_USER_RID,
  86. 0,0,0,0,0,0,0,
  87. &psa[1].Sid ) )
  88. {
  89. *pSidCount = 2;
  90. *pSidAttrArray = psa;
  91. }
  92. else
  93. {
  94. FreeSid( &psa[0].Sid );
  95. delete psa;
  96. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  97. }
  98. }
  99. else
  100. {
  101. delete psa;
  102. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  103. }
  104. }
  105. else
  106. {
  107. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  108. bRet = FALSE;
  109. }
  110. }
  111. return bRet;
  112. }
  113. void WINAPI FreeDynamicGroups( PSID_AND_ATTRIBUTES psa )
  114. {
  115. if ( psa != NULL )
  116. {
  117. FreeSid( psa[0].Sid );
  118. FreeSid( psa[1].Sid );
  119. delete [] psa;
  120. }
  121. }
  122. /**************************************************************************
  123. CWmiAuthzApi
  124. ***************************************************************************/
  125. #define FUNCMEMBER(FUNC) P ## FUNC m_fp ## FUNC;
  126. class CWmiAuthzApi
  127. {
  128. HMODULE m_hMod;
  129. public:
  130. FUNCMEMBER(AuthzInitializeContextFromToken)
  131. FUNCMEMBER(AuthzInitializeContextFromSid)
  132. FUNCMEMBER(AuthzInitializeResourceManager)
  133. FUNCMEMBER(AuthzAccessCheck)
  134. FUNCMEMBER(AuthzFreeContext)
  135. FUNCMEMBER(AuthzFreeResourceManager)
  136. CWmiAuthzApi() { ZeroMemory( this, sizeof(CWmiAuthzApi) ); }
  137. ~CWmiAuthzApi() { if ( m_hMod != NULL ) FreeLibrary( m_hMod ); }
  138. HRESULT Initialize();
  139. };
  140. #define SETFUNC(FUNC) \
  141. m_fp ## FUNC = (P ## FUNC) GetProcAddress( m_hMod, #FUNC ); \
  142. if ( m_fp ## FUNC == NULL ) return WBEM_E_NOT_SUPPORTED;
  143. HRESULT CWmiAuthzApi::Initialize()
  144. {
  145. m_hMod = LoadLibrary( _T("authz") );
  146. if ( m_hMod == NULL )
  147. {
  148. return WBEM_E_NOT_SUPPORTED;
  149. }
  150. SETFUNC(AuthzInitializeContextFromToken)
  151. SETFUNC(AuthzInitializeResourceManager)
  152. SETFUNC(AuthzInitializeContextFromSid)
  153. SETFUNC(AuthzInitializeContextFromToken)
  154. SETFUNC(AuthzAccessCheck)
  155. SETFUNC(AuthzFreeContext)
  156. SETFUNC(AuthzFreeResourceManager)
  157. return WBEM_S_NO_ERROR;
  158. };
  159. /**************************************************************************
  160. CWmiAuthz
  161. ***************************************************************************/
  162. #define CALLFUNC(API,FUNC) (*API->m_fp ## FUNC)
  163. CWmiAuthz::CWmiAuthz( CLifeControl* pControl )
  164. : CUnkBase<IWbemTokenCache,&IID_IWbemTokenCache>( pControl ),
  165. m_hResMgr(NULL), m_pApi(NULL), m_pAdministratorsSid(NULL),
  166. m_pLocalSystemSid(NULL)
  167. {
  168. }
  169. HRESULT CWmiAuthz::EnsureInitialized()
  170. {
  171. HRESULT hr;
  172. CInCritSec ics( &m_cs );
  173. if ( m_hResMgr != NULL )
  174. {
  175. return WBEM_S_NO_ERROR;
  176. }
  177. //
  178. // try to create the API object.
  179. //
  180. if ( m_pApi == NULL )
  181. {
  182. m_pApi = new CWmiAuthzApi;
  183. if ( m_pApi == NULL )
  184. {
  185. return WBEM_E_OUT_OF_MEMORY;
  186. }
  187. hr = m_pApi->Initialize();
  188. if ( FAILED(hr) )
  189. {
  190. delete m_pApi;
  191. m_pApi = NULL;
  192. return hr;
  193. }
  194. }
  195. //
  196. // initialize the authz res mgr.
  197. //
  198. if ( !CALLFUNC(m_pApi,AuthzInitializeResourceManager)
  199. ( AUTHZ_RM_FLAG_NO_AUDIT,
  200. NULL,
  201. ComputeDynamicGroups,
  202. FreeDynamicGroups,
  203. NULL,
  204. &m_hResMgr ) )
  205. {
  206. return HRESULT_FROM_WIN32( GetLastError() );
  207. }
  208. //
  209. // allocate and initialize well known sids for authz special casing.
  210. //
  211. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  212. if ( !AllocateAndInitializeSid( &id,
  213. 2,
  214. SECURITY_BUILTIN_DOMAIN_RID,
  215. DOMAIN_ALIAS_RID_ADMINS,
  216. 0,0,0,0,0,0,
  217. &m_pAdministratorsSid) )
  218. {
  219. return HRESULT_FROM_WIN32( GetLastError() );
  220. }
  221. if ( !AllocateAndInitializeSid( &id,
  222. 1,
  223. SECURITY_LOCAL_SYSTEM_RID,
  224. 0,0,0,0,0,0,0,
  225. &m_pLocalSystemSid) )
  226. {
  227. return HRESULT_FROM_WIN32( GetLastError() );
  228. }
  229. return WBEM_S_NO_ERROR;
  230. }
  231. STDMETHODIMP CWmiAuthz::Shutdown()
  232. {
  233. return WBEM_S_NO_ERROR;
  234. }
  235. CWmiAuthz::~CWmiAuthz()
  236. {
  237. if ( m_hResMgr != NULL )
  238. {
  239. CALLFUNC(m_pApi,AuthzFreeResourceManager)( m_hResMgr );
  240. }
  241. if ( m_pApi != NULL )
  242. {
  243. delete m_pApi;
  244. }
  245. if ( m_pAdministratorsSid != NULL )
  246. {
  247. FreeSid( m_pAdministratorsSid );
  248. }
  249. if ( m_pLocalSystemSid != NULL )
  250. {
  251. FreeSid( m_pLocalSystemSid );
  252. }
  253. }
  254. STDMETHODIMP CWmiAuthz::GetToken( const BYTE* pSid, IWbemToken** ppToken )
  255. {
  256. HRESULT hr;
  257. *ppToken = NULL;
  258. hr = EnsureInitialized();
  259. if ( SUCCEEDED( hr ) )
  260. {
  261. AUTHZ_CLIENT_CONTEXT_HANDLE hCtx = NULL;
  262. LUID luid;
  263. ZeroMemory( &luid, sizeof(LUID) );
  264. DWORD dwFlags = 0;
  265. BOOL bLocalSystem = FALSE;
  266. if ( EqualSid( PSID(pSid), m_pAdministratorsSid ) )
  267. {
  268. //
  269. // this is a group sid, so specify this in the flags so
  270. // authz can handle it properly.
  271. //
  272. dwFlags = AUTHZ_SKIP_TOKEN_GROUPS;
  273. }
  274. else if ( EqualSid( PSID(pSid), m_pLocalSystemSid ) )
  275. {
  276. //
  277. // authz doesn't handle local system so have to workaround
  278. // by disabling authz's group computation and do it ourselves.
  279. //
  280. bLocalSystem = TRUE;
  281. dwFlags = AUTHZ_SKIP_TOKEN_GROUPS;
  282. }
  283. if ( !CALLFUNC(m_pApi,AuthzInitializeContextFromSid)( dwFlags,
  284. PSID(pSid),
  285. m_hResMgr,
  286. NULL,
  287. luid,
  288. &bLocalSystem,
  289. &hCtx ) )
  290. {
  291. return HRESULT_FROM_WIN32( GetLastError() );
  292. }
  293. *ppToken = new CWmiAuthzToken( this, hCtx );
  294. if ( *ppToken == NULL )
  295. {
  296. CALLFUNC(m_pApi,AuthzFreeContext)(hCtx);
  297. return WBEM_E_OUT_OF_MEMORY;
  298. }
  299. (*ppToken)->AddRef();
  300. return WBEM_S_NO_ERROR;
  301. }
  302. return hr;
  303. }
  304. /***************************************************************************
  305. CWmiAuthzToken
  306. ****************************************************************************/
  307. CWmiAuthzToken::CWmiAuthzToken( CWmiAuthz* pOwner, AUTHZ_CLIENT_CONTEXT_HANDLE hCtx )
  308. : CUnkBase<IWbemToken,&IID_IWbemToken>(NULL), m_hCtx(hCtx), m_pOwner(pOwner)
  309. {
  310. //
  311. // we want to keep the owner alive, in case the caller has released theirs
  312. //
  313. m_pOwner->AddRef();
  314. }
  315. CWmiAuthzToken::~CWmiAuthzToken()
  316. {
  317. CWmiAuthzApi* pApi = m_pOwner->GetApi();
  318. CALLFUNC(pApi,AuthzFreeContext)(m_hCtx);
  319. m_pOwner->Release();
  320. }
  321. STDMETHODIMP CWmiAuthzToken::AccessCheck( DWORD dwDesiredAccess,
  322. const BYTE* pSD,
  323. DWORD* pdwGrantedAccess )
  324. {
  325. HRESULT hr;
  326. AUTHZ_ACCESS_REQUEST AccessReq;
  327. ZeroMemory( &AccessReq, sizeof(AUTHZ_ACCESS_REQUEST) );
  328. AccessReq.DesiredAccess = dwDesiredAccess;
  329. AUTHZ_ACCESS_REPLY AccessRep;
  330. DWORD dwError;
  331. ZeroMemory( &AccessRep, sizeof(AUTHZ_ACCESS_REPLY) );
  332. AccessRep.GrantedAccessMask = pdwGrantedAccess;
  333. AccessRep.ResultListLength = 1;
  334. AccessRep.Error = &dwError;
  335. AccessRep.SaclEvaluationResults = NULL;
  336. CWmiAuthzApi* pApi = m_pOwner->GetApi();
  337. if ( !CALLFUNC(pApi,AuthzAccessCheck)( 0,
  338. m_hCtx,
  339. &AccessReq,
  340. NULL,
  341. PSECURITY_DESCRIPTOR(pSD),
  342. NULL,
  343. NULL,
  344. &AccessRep,
  345. NULL ) )
  346. {
  347. return HRESULT_FROM_WIN32( GetLastError() );
  348. }
  349. return WBEM_S_NO_ERROR;
  350. }
  351. /****************************************************************************
  352. WILL NOT BE COMPILED IN PRESENCE OF AUTHZ LIBRARY
  353. *****************************************************************************/
  354. #ifndef __AUTHZ_H__
  355. #include <ArrTempl.h>
  356. #include <lmaccess.h>
  357. #include <lmapibuf.h>
  358. #include <lmwksta.h>
  359. #include <wbemcomn.h>
  360. #include <comutl.h>
  361. /****************************************************************************
  362. CWmiNoAuthzToken
  363. *****************************************************************************/
  364. STDMETHODIMP CWmiNoAuthzToken::AccessCheck( DWORD dwDesiredAccess,
  365. const BYTE* pSD,
  366. DWORD* pdwGrantedAccess )
  367. {
  368. PACL pDacl;
  369. BOOL bDaclPresent, bDaclDefault;
  370. *pdwGrantedAccess = 0;
  371. if ( !GetSecurityDescriptorDacl( PSECURITY_DESCRIPTOR(pSD),
  372. &bDaclPresent,
  373. &pDacl,
  374. &bDaclDefault) )
  375. {
  376. return HRESULT_FROM_WIN32( GetLastError() );
  377. }
  378. if ( !bDaclPresent )
  379. {
  380. *pdwGrantedAccess = 0xffffffff;
  381. }
  382. NTSTATUS stat = WmiAuthzGetAccessMask( m_Sid.GetPtr(), pDacl, pdwGrantedAccess );
  383. if ( stat != 0 )
  384. {
  385. return HRESULT_FROM_WIN32( GetLastError() );
  386. }
  387. return WBEM_S_NO_ERROR;
  388. }
  389. /***************************************************************************
  390. Functions moved from GroupForUser
  391. ****************************************************************************/
  392. // critical section to keep us from tripping over our threads
  393. // during initialization
  394. CCritSec CSSamStartup;
  395. CCritSec CSNetAPIStartup;
  396. CCritSec CSAdvAPIStartup;
  397. // copied here to make it easy for this file to be included elsewhere
  398. bool IsPlatformNT(void)
  399. {
  400. OSVERSIONINFO os;
  401. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  402. if(!GetVersionEx(&os))
  403. return false; // should never happen
  404. return os.dwPlatformId == VER_PLATFORM_WIN32_NT;
  405. }
  406. class CUnicodeString : public UNICODE_STRING
  407. {
  408. public:
  409. CUnicodeString()
  410. {
  411. MaximumLength = Length = 0;
  412. Buffer = NULL;
  413. }
  414. CUnicodeString(LPCWSTR wsz)
  415. {
  416. Buffer = NULL;
  417. MaximumLength = Length = 0;
  418. *this = wsz;
  419. }
  420. ~CUnicodeString()
  421. {
  422. delete [] Buffer;
  423. }
  424. void operator=(LPCWSTR wsz)
  425. {
  426. delete [] Buffer;
  427. MaximumLength = sizeof(WCHAR) * (wcslen(wsz)+1);
  428. Buffer = new WCHAR[MaximumLength];
  429. Length = MaximumLength - sizeof(WCHAR);
  430. wcscpy(Buffer, wsz);
  431. }
  432. operator LPCWSTR() {return Buffer;}
  433. };
  434. typedef NTSTATUS (NTAPI *PSamConnect)(IN PUNICODE_STRING ServerName,
  435. OUT PSAM_HANDLE ServerHandle, IN ACCESS_MASK DesiredAccess,
  436. IN POBJECT_ATTRIBUTES ObjectAttributes);
  437. typedef NTSTATUS (NTAPI *PSamCloseHandle)( OUT SAM_HANDLE SamHandle );
  438. typedef NTSTATUS (NTAPI *PSamFreeMemory)( PVOID p );
  439. typedef NTSTATUS (NTAPI *PSamLookupDomainInSamServer)(
  440. IN SAM_HANDLE ServerHandle,
  441. IN PUNICODE_STRING Name, OUT PSID * DomainId );
  442. typedef NTSTATUS (NTAPI *PSamLookupNamesInDomain)(
  443. IN SAM_HANDLE DomainHandle, IN ULONG Count,
  444. IN PUNICODE_STRING Names, OUT PULONG *RelativeIds,
  445. OUT PSID_NAME_USE *Use);
  446. typedef NTSTATUS (NTAPI *PSamOpenDomain)( IN SAM_HANDLE ServerHandle,
  447. IN ACCESS_MASK DesiredAccess,
  448. IN PSID DomainId, OUT PSAM_HANDLE DomainHandle );
  449. typedef NTSTATUS (NTAPI *PSamOpenUser)( IN SAM_HANDLE DomainHandle,
  450. IN ACCESS_MASK DesiredAccess,
  451. IN ULONG UserId, OUT PSAM_HANDLE UserHandle );
  452. typedef NTSTATUS (NTAPI *PSamGetGroupsForUser)( IN SAM_HANDLE UserHandle,
  453. OUT PGROUP_MEMBERSHIP * Groups, OUT PULONG MembershipCount);
  454. typedef NTSTATUS (NTAPI *PSamGetAliasMembership)( IN SAM_HANDLE DomainHandle, IN ULONG PassedCount,
  455. IN PSID *Sids, OUT PULONG MembershipCount, OUT PULONG *Aliases);
  456. // class to encapsulate the SAM APIs
  457. // make sure that we always free the lib, etc.
  458. class CSamRun
  459. {
  460. public:
  461. CSamRun()
  462. {
  463. }
  464. ~CSamRun()
  465. {
  466. // oh, all right - DON'T free the lib.
  467. // FreeLibrary(m_hSamDll);
  468. }
  469. bool RunSamRun(void);
  470. //protected:
  471. // okay, so I should make these all protected
  472. // and write accessor functions. Maybe I will someday.
  473. static HINSTANCE m_hSamDll;
  474. static PSamConnect m_pfnSamConnect;
  475. static PSamCloseHandle m_pfnSamCloseHandle;
  476. static PSamFreeMemory m_pfnSamFreeMemory;
  477. static PSamLookupDomainInSamServer m_pfnSamLookupDomainInSamServer;
  478. static PSamLookupNamesInDomain m_pfnSamLookupNamesInDomain;
  479. static PSamOpenDomain m_pfnSamOpenDomain;
  480. static PSamOpenUser m_pfnSamOpenUser;
  481. static PSamGetGroupsForUser m_pfnSamGetGroupsForUser;
  482. static PSamGetAliasMembership m_pfnSamGetAliasMembership;
  483. };
  484. HINSTANCE CSamRun::m_hSamDll = NULL;
  485. PSamConnect CSamRun::m_pfnSamConnect = NULL;
  486. PSamCloseHandle CSamRun::m_pfnSamCloseHandle = NULL;
  487. PSamFreeMemory CSamRun::m_pfnSamFreeMemory = NULL;
  488. PSamLookupDomainInSamServer CSamRun::m_pfnSamLookupDomainInSamServer = NULL;
  489. PSamLookupNamesInDomain CSamRun::m_pfnSamLookupNamesInDomain = NULL;
  490. PSamOpenDomain CSamRun::m_pfnSamOpenDomain = NULL;
  491. PSamOpenUser CSamRun::m_pfnSamOpenUser = NULL;
  492. PSamGetGroupsForUser CSamRun::m_pfnSamGetGroupsForUser = NULL;
  493. PSamGetAliasMembership CSamRun::m_pfnSamGetAliasMembership = NULL;
  494. bool CSamRun::RunSamRun()
  495. {
  496. CInCritSec runInACriticalSectionSam(&CSSamStartup);
  497. if(m_hSamDll)
  498. return true;
  499. m_hSamDll = LoadLibrary(_T("samlib.dll"));
  500. if(m_hSamDll == NULL)
  501. return false;
  502. m_pfnSamConnect =
  503. (PSamConnect)GetProcAddress(m_hSamDll, "SamConnect");
  504. if(m_pfnSamConnect == NULL)
  505. return false;
  506. m_pfnSamCloseHandle =
  507. (PSamCloseHandle)GetProcAddress(m_hSamDll, "SamCloseHandle");
  508. if(m_pfnSamCloseHandle == NULL)
  509. return false;
  510. m_pfnSamFreeMemory =
  511. (PSamFreeMemory)GetProcAddress(m_hSamDll, "SamFreeMemory");
  512. if(m_pfnSamFreeMemory == NULL)
  513. return false;
  514. m_pfnSamLookupDomainInSamServer =
  515. (PSamLookupDomainInSamServer)GetProcAddress(m_hSamDll,
  516. "SamLookupDomainInSamServer");
  517. if(m_pfnSamLookupDomainInSamServer == NULL)
  518. return false;
  519. m_pfnSamLookupNamesInDomain =
  520. (PSamLookupNamesInDomain)GetProcAddress(m_hSamDll,
  521. "SamLookupNamesInDomain");
  522. if(m_pfnSamLookupNamesInDomain == NULL)
  523. return false;
  524. m_pfnSamOpenDomain =
  525. (PSamOpenDomain)GetProcAddress(m_hSamDll,
  526. "SamOpenDomain");
  527. if(m_pfnSamOpenDomain == NULL)
  528. return false;
  529. m_pfnSamOpenUser =
  530. (PSamOpenUser)GetProcAddress(m_hSamDll,
  531. "SamOpenUser");
  532. if(m_pfnSamOpenUser == NULL)
  533. return false;
  534. m_pfnSamGetGroupsForUser =
  535. (PSamGetGroupsForUser)GetProcAddress(m_hSamDll,
  536. "SamGetGroupsForUser");
  537. if(m_pfnSamGetGroupsForUser == NULL)
  538. return false;
  539. m_pfnSamGetAliasMembership =
  540. (PSamGetAliasMembership)GetProcAddress(m_hSamDll,
  541. "SamGetAliasMembership");
  542. if(m_pfnSamGetAliasMembership == NULL)
  543. return false;
  544. return true;
  545. }
  546. typedef BOOL (NTAPI* PLookupAccountSidW) (
  547. LPCWSTR lpSystemName, // name of local or remote computer
  548. PSID Sid, // security identifier
  549. LPWSTR Name, // account name buffer
  550. LPDWORD cbName, // size of account name buffer
  551. LPWSTR DomainName, // domain name
  552. LPDWORD cbDomainName, // size of domain name buffer
  553. PSID_NAME_USE peUse // SID type
  554. );
  555. typedef NET_API_STATUS (NTAPI* PNetGetAnyDCName)(
  556. LPCWSTR servername,
  557. LPCWSTR domainname,
  558. LPBYTE *bufptr
  559. );
  560. typedef NET_API_STATUS (NTAPI* PNetGetDCName)(
  561. LPCWSTR servername,
  562. LPCWSTR domainname,
  563. LPBYTE *bufptr
  564. );
  565. typedef NET_API_STATUS (NTAPI* PNetApiBufferFree)(
  566. LPVOID Buffer
  567. );
  568. typedef NET_API_STATUS (NTAPI* PNetWkstaGetInfo)(
  569. LPWSTR servername,
  570. DWORD level,
  571. LPBYTE *bufptr
  572. );
  573. // dynamically load NetAPI32.DLL
  574. // so we can run without it on 9X
  575. class NetApiDLL
  576. {
  577. public:
  578. bool Init(void);
  579. static PNetGetAnyDCName m_pfnNetGetAnyDCName;
  580. static PNetGetAnyDCName m_pfnNetGetDCName;
  581. static PNetApiBufferFree m_pfnNetApiBufferFree;
  582. static PNetWkstaGetInfo m_pfnNetWkstaGetInfo;
  583. static HINSTANCE m_hDll;
  584. };
  585. PNetGetAnyDCName NetApiDLL::m_pfnNetGetAnyDCName = NULL;
  586. PNetGetDCName NetApiDLL::m_pfnNetGetDCName = NULL;
  587. PNetApiBufferFree NetApiDLL::m_pfnNetApiBufferFree = NULL;
  588. PNetWkstaGetInfo NetApiDLL::m_pfnNetWkstaGetInfo = NULL;
  589. HINSTANCE NetApiDLL::m_hDll = NULL;
  590. bool NetApiDLL::Init(void)
  591. {
  592. CInCritSec inCS(&CSNetAPIStartup);
  593. bool bRet = false;
  594. if (m_hDll)
  595. bRet = true;
  596. else if (m_hDll = LoadLibrary(_T("NetAPI32.dll")))
  597. {
  598. m_pfnNetGetAnyDCName = (PNetGetAnyDCName) GetProcAddress(m_hDll, "NetGetAnyDCName");
  599. m_pfnNetGetDCName = (PNetGetDCName) GetProcAddress(m_hDll, "NetGetDCName");
  600. m_pfnNetApiBufferFree = (PNetApiBufferFree) GetProcAddress(m_hDll, "NetApiBufferFree");
  601. m_pfnNetWkstaGetInfo = (PNetWkstaGetInfo) GetProcAddress(m_hDll, "NetWkstaGetInfo");
  602. bRet = ((m_pfnNetGetAnyDCName != NULL) &&
  603. (m_pfnNetGetDCName != NULL) &&
  604. (m_pfnNetApiBufferFree != NULL) &&
  605. (m_pfnNetWkstaGetInfo != NULL));
  606. if (!bRet)
  607. {
  608. FreeLibrary(m_hDll);
  609. m_hDll = NULL;
  610. }
  611. }
  612. else
  613. ERRORTRACE((LOG_ESS, "Failed to load NetAPI32.dll, 0x%X", GetLastError()));
  614. return bRet;
  615. }
  616. // dynamically load AdvAPI32.DLL
  617. // so we can run without it on 9X
  618. class AdvApiDLL
  619. {
  620. public:
  621. bool Init(void);
  622. static PLookupAccountSidW m_pfnLookupAccountSidW;
  623. static HINSTANCE m_hDll;
  624. };
  625. PLookupAccountSidW AdvApiDLL::m_pfnLookupAccountSidW = NULL;
  626. HINSTANCE AdvApiDLL::m_hDll = NULL;
  627. bool AdvApiDLL::Init(void)
  628. {
  629. CInCritSec inCS(&CSAdvAPIStartup);
  630. bool bRet = false;
  631. if (m_hDll)
  632. bRet = true;
  633. else if (m_hDll = LoadLibrary(_T("AdvAPI32.dll")))
  634. {
  635. m_pfnLookupAccountSidW = (PLookupAccountSidW) GetProcAddress(m_hDll, "LookupAccountSidW");
  636. bRet = (m_pfnLookupAccountSidW != NULL);
  637. }
  638. else
  639. ERRORTRACE((LOG_ESS, "Failed to load AdvAPI32.dll, 0x%X", GetLastError()));
  640. return bRet;
  641. }
  642. class CSamHandle
  643. {
  644. private:
  645. SAM_HANDLE m_hHandle;
  646. CSamRun& m_sam;
  647. protected:
  648. void Close();
  649. public:
  650. CSamHandle(CSamRun& sam) : m_sam(sam), m_hHandle(NULL)
  651. { }
  652. ~CSamHandle();
  653. // same as operator SAM_HANDLE*()
  654. // gosh, I sure do love C!
  655. operator void**()
  656. {return &((void*)m_hHandle); }
  657. operator SAM_HANDLE()
  658. {return m_hHandle; }
  659. };
  660. CSamHandle::~CSamHandle()
  661. {
  662. Close();
  663. }
  664. void CSamHandle::Close()
  665. {
  666. if (m_hHandle)
  667. m_sam.m_pfnSamCloseHandle(m_hHandle);
  668. m_hHandle = NULL;
  669. }
  670. class CSamFreeMe
  671. {
  672. protected:
  673. void* m_p;
  674. CSamRun m_sam;
  675. public:
  676. CSamFreeMe(CSamRun& sam, void* p) : m_p(p), m_sam(sam) {}
  677. ~CSamFreeMe() {m_sam.m_pfnSamFreeMemory(m_p);}
  678. };
  679. class CHeapFreeMe
  680. {
  681. protected:
  682. void* m_p;
  683. public:
  684. CHeapFreeMe(void* p) : m_p(p){}
  685. ~CHeapFreeMe()
  686. {
  687. if (m_p)
  688. HeapFree(GetProcessHeap(), 0, m_p);
  689. }
  690. };
  691. PSID CreateUserSid(PSID pDomainSid, DWORD dwUserRid)
  692. {
  693. DWORD dwOldLen = GetLengthSid(pDomainSid);
  694. // PISID pSid = (PISID)new BYTE[dwOldLen + sizeof(DWORD)];
  695. PISID pSid = (PISID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwOldLen + sizeof(DWORD));
  696. if (pSid)
  697. {
  698. memcpy(pSid, pDomainSid, dwOldLen);
  699. pSid->SubAuthority[pSid->SubAuthorityCount] = dwUserRid;
  700. pSid->SubAuthorityCount++;
  701. }
  702. return pSid;
  703. }
  704. class CHeapBigPointerArrayCleanerUpper
  705. {
  706. public:
  707. CHeapBigPointerArrayCleanerUpper(void** pArray = NULL, DWORD count = 0) :
  708. m_pArray(pArray), m_count(count) {}
  709. ~CHeapBigPointerArrayCleanerUpper()
  710. {
  711. if (m_pArray)
  712. for (DWORD i = 0; i < m_count; i++)
  713. if (m_pArray[i])
  714. HeapFree(GetProcessHeap(), 0, m_pArray[i]);
  715. }
  716. protected:
  717. void** m_pArray;
  718. DWORD m_count;
  719. };
  720. // returns STATUS_SUCCESS if user is in group
  721. // STATUS_ACCESS_DENIED if not
  722. // some error code or other on error
  723. NTSTATUS IsUserInGroup(PSID pSidUser, PSID pSidGroup)
  724. {
  725. if (!IsPlatformNT())
  726. return STATUS_NOT_SUPPORTED;
  727. PSID* pSids = NULL;
  728. DWORD dwCount;
  729. NTSTATUS stat = EnumGroupsForUser(pSidUser, NULL, &pSids, &dwCount);
  730. // if we can't get to the domain controller, try just local groups
  731. if (stat)
  732. {
  733. WCHAR machineName[MAX_COMPUTERNAME_LENGTH + 1];
  734. DWORD size = MAX_COMPUTERNAME_LENGTH +1;
  735. GetComputerNameW(machineName, &size);
  736. stat = EnumGroupsForUser(pSidUser, machineName, &pSids, &dwCount);
  737. }
  738. // arrange for clean up no matter how we exit
  739. CHeapFreeMe freeArray(pSids);
  740. CHeapBigPointerArrayCleanerUpper cleanSids(pSids, dwCount);
  741. if (stat == STATUS_SUCCESS)
  742. {
  743. stat = STATUS_ACCESS_DENIED;
  744. for(DWORD i = 0; i < dwCount; i++)
  745. if (EqualSid(pSidGroup, pSids[i]))
  746. stat = STATUS_SUCCESS;
  747. }
  748. return stat;
  749. }
  750. // returns STATUS_SUCCESS if user is in admin group
  751. // STATUS_ACCESS_DENIED if not
  752. // some error code or other on error
  753. NTSTATUS IsUserAdministrator(PSID pSidUser)
  754. {
  755. if (!IsPlatformNT())
  756. return STATUS_NOT_SUPPORTED;
  757. NTSTATUS stat = STATUS_ACCESS_DENIED;
  758. PSID pSidAdmins;
  759. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  760. if (AllocateAndInitializeSid(&id, 2,
  761. SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
  762. 0,0,0,0,0,0,&pSidAdmins))
  763. {
  764. stat = WmiAuthzIsUserInGroup(pSidUser, pSidAdmins);
  765. // We're done with this
  766. FreeSid(pSidAdmins);
  767. }
  768. else
  769. {
  770. stat = GetLastError();
  771. ERRORTRACE((LOG_ESS, "AllocateAndInitializeSid failed, error 0x%X\n", stat));
  772. }
  773. return stat;
  774. }
  775. // retireves access mask corresponding to permissions granted
  776. // by dacl to account denoted in pSid
  777. // only deals with the ACCESS_ALLOWED/DENIED type aces
  778. // including the ACCESS_ALLOWED/DENIED_OBJECT_ACEs
  779. // - will error out if it finds a SYSTEM_AUDIT or unrecognized type.
  780. NTSTATUS GetAccessMask(PSID pSid, PACL pDacl, DWORD* pAccessMask)
  781. {
  782. if (!IsPlatformNT())
  783. return STATUS_NOT_SUPPORTED;
  784. NTSTATUS stat = STATUS_SUCCESS;
  785. // let's zero this puppy out
  786. // lest someone not check the return code & compare against garbage
  787. *pAccessMask = 0;
  788. // will compute each & knock them against each other
  789. DWORD accessAllowed = 0;
  790. DWORD accessDenied = 0;
  791. PSID* pSids = NULL;
  792. DWORD dwCount;
  793. LPVOID pAce;
  794. stat = EnumGroupsForUser(pSid, NULL, &pSids, &dwCount);
  795. // arrange for clean up no matter how we exit
  796. CHeapFreeMe freeArray(pSids);
  797. CHeapBigPointerArrayCleanerUpper cleanSids(pSids, dwCount);
  798. // de buggy test harness
  799. // char name[300];
  800. // char domain[300];
  801. // DWORD x = 300, y = 300;
  802. // SID_NAME_USE eUse;
  803. //for (int q = 0; q < dwCount; q++)
  804. //{
  805. // x = y = 300;
  806. // LookupAccountSid(NULL, pSids[q], name, &x, domain, &y, &eUse);
  807. //}
  808. if (stat == STATUS_SUCCESS)
  809. // iterate through all of the ACE's in the ACL
  810. // for each, iterate through all of the groups for the user
  811. // if one matches, OR in its allowed/disallowed mask
  812. for (DWORD nAce = 0; nAce < pDacl->AceCount; nAce++)
  813. if (GetAce(pDacl, nAce, &pAce))
  814. {
  815. // de buggy test harness
  816. // x = y = 300;
  817. // LookupAccountSid(NULL, &(((ACCESS_ALLOWED_ACE*)pAce)->SidStart), name, &x, domain, &y, &eUse);
  818. for (DWORD nSid = 0; nSid < dwCount; nSid++)
  819. {
  820. // de buggy test harness
  821. // x = y = 300;
  822. // if (!LookupAccountSid(NULL, pSids[nSid], name, &x, domain, &y, &eUse))
  823. // DWORD gubl = GetLastError();
  824. switch (((ACE_HEADER*)pAce)->AceType)
  825. {
  826. case ACCESS_ALLOWED_ACE_TYPE:
  827. if (EqualSid(&(((ACCESS_ALLOWED_ACE*)pAce)->SidStart), pSids[nSid]))
  828. accessAllowed |= ((ACCESS_ALLOWED_ACE*)pAce)->Mask;
  829. break;
  830. case ACCESS_DENIED_ACE_TYPE:
  831. if (EqualSid(&(((ACCESS_DENIED_ACE*)pAce)->SidStart), pSids[nSid]))
  832. accessDenied |= ((ACCESS_DENIED_ACE*)pAce)->Mask;
  833. break;
  834. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  835. if (EqualSid(&(((ACCESS_ALLOWED_OBJECT_ACE*)pAce)->SidStart), pSids[nSid]))
  836. accessAllowed |= ((ACCESS_ALLOWED_OBJECT_ACE*)pAce)->Mask;
  837. break;
  838. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  839. if (EqualSid(&(((ACCESS_DENIED_OBJECT_ACE*)pAce)->SidStart), pSids[nSid]))
  840. accessDenied |= ((ACCESS_DENIED_OBJECT_ACE*)pAce)->Mask;
  841. break;
  842. default:
  843. // in too deep - bail!
  844. return STATUS_INVALID_PARAMETER;
  845. }
  846. }
  847. }
  848. else
  849. {
  850. // GetAce failed
  851. DWORD dwErr = GetLastError();
  852. ERRORTRACE((LOG_ESS, "GetAce failed, error 0x%X", dwErr));
  853. return dwErr;
  854. }
  855. if (stat == STATUS_SUCCESS)
  856. *pAccessMask = accessAllowed & ~accessDenied;
  857. return stat;
  858. }
  859. // given a SID & server name
  860. // will return all groups from the local domain of which user is a member
  861. // callers responsibility to HeapFree apSids & the memory to which they point.
  862. // pdwCount points to dword to receive count of group sids returned.
  863. // serverName may be NULL, in which case this function will look up
  864. // the sid on the local computer
  865. NTSTATUS EnumGroupsForUser(PSID pSid, LPCWSTR serverName, PSID** apGroupSids, DWORD* pdwCount)
  866. {
  867. if (!IsPlatformNT())
  868. return STATUS_NOT_SUPPORTED;
  869. NTSTATUS status = STATUS_SUCCESS;
  870. NetApiDLL netDll;
  871. AdvApiDLL advDll;
  872. if (!(netDll.Init() && advDll.Init()))
  873. status = STATUS_DLL_INIT_FAILED;
  874. else
  875. {
  876. // retrieve user name & domain name
  877. DWORD domainSize = 0,
  878. nameSize = 0;
  879. SID_NAME_USE sidUse;
  880. // call once to find out how big a buffer we need
  881. advDll.m_pfnLookupAccountSidW(serverName, pSid, NULL, &nameSize, NULL, &domainSize, &sidUse);
  882. // buy bunches o' bigger buffers
  883. LPWSTR pAccountName = NULL,
  884. pDomainName = NULL;
  885. pAccountName = new WCHAR[nameSize];
  886. pDomainName = new WCHAR[domainSize];
  887. CDeleteMe<WCHAR> delAcct(pAccountName);
  888. CDeleteMe<WCHAR> delDomain(pDomainName);
  889. if (pAccountName && pDomainName)
  890. {
  891. if (advDll.m_pfnLookupAccountSidW(serverName, pSid,
  892. pAccountName, &nameSize,
  893. pDomainName, &domainSize,
  894. &sidUse))
  895. {
  896. WKSTA_INFO_100 *pstInfo = NULL ;
  897. LPWSTR samServerName;
  898. // may not get filled in, careful...
  899. WCHAR serverNameBuffer[MAX_COMPUTERNAME_LENGTH +1] = L"\0";
  900. if (serverName == NULL)
  901. {
  902. DWORD dNameSize = MAX_COMPUTERNAME_LENGTH +1;
  903. WCHAR computerName[MAX_COMPUTERNAME_LENGTH +1] = L"\0";
  904. GetComputerNameW(computerName, &dNameSize);
  905. if (_wcsicmp(computerName, pDomainName) == 0)
  906. // local domain is the machine
  907. samServerName = pDomainName;
  908. else
  909. // go grab the Domain Controller
  910. {
  911. // use the local domain!
  912. status = netDll.m_pfnNetWkstaGetInfo( NULL , 100 , ( LPBYTE * ) &pstInfo );
  913. if (status == 0)
  914. {
  915. LPBYTE dcName = NULL;
  916. status = netDll.m_pfnNetGetDCName(NULL, pstInfo->wki100_langroup, &dcName);
  917. // if we can't find a/the PDC, try for a backup...
  918. // if ((status == 0x54B) || (status == 0x995))
  919. if (status)
  920. status = netDll.m_pfnNetGetAnyDCName(NULL, pstInfo->wki100_langroup, &dcName);
  921. netDll.m_pfnNetApiBufferFree(pstInfo);
  922. if (status == 0)
  923. {
  924. LPWSTR dcNameWithoutWhacks = (LPWSTR)dcName;
  925. // name is prefaced with "\\"
  926. dcNameWithoutWhacks += 2;
  927. wcscpy(serverNameBuffer, dcNameWithoutWhacks);
  928. samServerName = serverNameBuffer;
  929. netDll.m_pfnNetApiBufferFree(dcName);
  930. }
  931. }
  932. }
  933. }
  934. else
  935. // tweren't NULL - we'll use it
  936. samServerName = (LPWSTR)serverName;
  937. if (status == 0)
  938. status = EnumGroupsForUser(pAccountName, pDomainName, samServerName, apGroupSids, pdwCount);
  939. }
  940. else
  941. {
  942. // lookup account sid failed - dunno why.
  943. status = GetLastError();
  944. ERRORTRACE((LOG_ESS, "LookupAccountSid failed: 0x%X\n", status));
  945. }
  946. }
  947. else
  948. {
  949. ERRORTRACE((LOG_ESS, "Allocation Failure\n"));
  950. // couldn't allocate name buffers
  951. status = STATUS_NO_MEMORY;
  952. }
  953. } // if netDll.Init
  954. return status;
  955. }
  956. // given user name, domain name & server name
  957. // will return all groups of which user is a member
  958. // callers responsibility to HeapFree apSids & the memory to which they point.
  959. // pdwCount points to dword to receive count of group sids returned.
  960. NTSTATUS EnumGroupsForUser(LPCWSTR userName, LPCWSTR domainName, LPCWSTR serverName, PSID** apGroupSids, DWORD* pdwCount)
  961. {
  962. if (!IsPlatformNT())
  963. return STATUS_NOT_SUPPORTED;
  964. CSamRun sam;
  965. if (!sam.RunSamRun())
  966. return STATUS_DLL_INIT_FAILED;
  967. else
  968. {
  969. // will reuse this puppy without remorse.
  970. CUnicodeString buffer;
  971. NTSTATUS ntst = STATUS_SUCCESS;
  972. // get local handles
  973. CSamHandle hLocalSam(sam);
  974. ntst = sam.m_pfnSamConnect(NULL, (void**)hLocalSam,
  975. SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
  976. NULL);
  977. if(ntst)
  978. {
  979. ERRORTRACE((LOG_ESS, "SamConnect Failed, error 0x%X\n", ntst));
  980. return ntst;
  981. }
  982. PSID pBuiltinDomainId = NULL;
  983. buffer = L"BUILTIN";
  984. ntst = sam.m_pfnSamLookupDomainInSamServer(hLocalSam, &buffer, &pBuiltinDomainId);
  985. if(ntst)
  986. {
  987. ERRORTRACE((LOG_ESS, "SamLookupDomainInSamServer Failed on BUILTIN domain, error 0x%X\n", ntst));
  988. return ntst;
  989. }
  990. CSamFreeMe freeBuiltinDomain(sam, pBuiltinDomainId);
  991. CSamHandle hBuiltinDomain(sam);
  992. ntst = sam.m_pfnSamOpenDomain(hLocalSam,
  993. DOMAIN_GET_ALIAS_MEMBERSHIP | DOMAIN_LOOKUP,
  994. pBuiltinDomainId, (void**)hBuiltinDomain);
  995. if(ntst)
  996. {
  997. ERRORTRACE((LOG_ESS, "SamOpenDomain Failed on BUILTIN domain, error 0x%X\n", ntst));
  998. return ntst;
  999. }
  1000. // make an 'everyone' sid
  1001. PSID pSidEveryoneHeapAlloc = NULL;
  1002. PSID pSidEveryone = NULL;
  1003. SID_IDENTIFIER_AUTHORITY sa = SECURITY_WORLD_SID_AUTHORITY;
  1004. if (AllocateAndInitializeSid(&sa, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &pSidEveryone))
  1005. {
  1006. DWORD len = GetLengthSid(pSidEveryone);
  1007. pSidEveryoneHeapAlloc = (PISID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
  1008. if (!pSidEveryoneHeapAlloc)
  1009. {
  1010. FreeSid(pSidEveryone);
  1011. return WBEM_E_OUT_OF_MEMORY;
  1012. }
  1013. memcpy(pSidEveryoneHeapAlloc, pSidEveryone, len);
  1014. FreeSid(pSidEveryone);
  1015. pSidEveryone = NULL;
  1016. }
  1017. else
  1018. {
  1019. ntst = GetLastError();
  1020. ERRORTRACE((LOG_ESS, "AllocateAndInitializeSid failed, error 0x%X\n", ntst));
  1021. return ntst;
  1022. }
  1023. CSamHandle hSam(sam);
  1024. // connect & determine global groups
  1025. buffer = serverName;
  1026. ntst = sam.m_pfnSamConnect(&buffer, (void **)hSam,
  1027. SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
  1028. NULL);
  1029. if (ntst)
  1030. {
  1031. ERRORTRACE((LOG_ESS, "SamConnect Failed on %S, error 0x%X\n", serverName, ntst));
  1032. return ntst;
  1033. }
  1034. DWORD dwMembershipCount;
  1035. DWORD dwUserId;
  1036. PSID* apSids;
  1037. PSID pDomainId = NULL;
  1038. buffer = domainName;
  1039. ntst = sam.m_pfnSamLookupDomainInSamServer((SAM_HANDLE)hSam, &buffer, &pDomainId);
  1040. if ( ntst == 0 )
  1041. {
  1042. CSamFreeMe freeDomain(sam, pDomainId);
  1043. CSamHandle hDomain(sam);
  1044. ntst = sam.m_pfnSamOpenDomain((SAM_HANDLE)hSam,
  1045. DOMAIN_GET_ALIAS_MEMBERSHIP | DOMAIN_LOOKUP,
  1046. pDomainId, (void**)hDomain);
  1047. if(ntst)
  1048. return ntst;
  1049. CSamHandle hUser(sam);
  1050. buffer = userName;
  1051. ULONG* pdwUserId = NULL;
  1052. SID_NAME_USE* psnu = NULL;
  1053. ntst = sam.m_pfnSamLookupNamesInDomain(hDomain, 1, &buffer, &pdwUserId, &psnu);
  1054. if(ntst)
  1055. {
  1056. ERRORTRACE((LOG_ESS, "SamLookupNamesInDomain Failed on %S, error 0x%X\n", userName, ntst));
  1057. return ntst;
  1058. }
  1059. CSamFreeMe freeSnu(sam, psnu);
  1060. dwUserId = *pdwUserId;
  1061. sam.m_pfnSamFreeMemory(pdwUserId);
  1062. ntst = sam.m_pfnSamOpenUser(hDomain, USER_LIST_GROUPS, dwUserId, (void**)hUser);
  1063. if(ntst)
  1064. return ntst;
  1065. GROUP_MEMBERSHIP* aMemberships = NULL;
  1066. ntst = sam.m_pfnSamGetGroupsForUser(hUser, &aMemberships, &dwMembershipCount);
  1067. if(ntst)
  1068. return ntst;
  1069. CSamFreeMe freeMembers(sam, aMemberships);
  1070. // got everything we need for the first bunch...
  1071. apSids = (PSID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PSID) * (dwMembershipCount +2));
  1072. if (apSids)
  1073. {
  1074. PSID pSid = CreateUserSid(pDomainId, dwUserId);
  1075. if (!pSid)
  1076. return STATUS_NO_MEMORY;
  1077. apSids[0] = pSid;
  1078. apSids[1] = pSidEveryoneHeapAlloc;
  1079. for(DWORD i = 0; i < dwMembershipCount; i++)
  1080. {
  1081. pSid = CreateUserSid(pDomainId, aMemberships[i].RelativeId);
  1082. if (pSid)
  1083. apSids[i+2] = pSid;
  1084. else
  1085. {
  1086. CHeapBigPointerArrayCleanerUpper cleanSids(apSids, dwMembershipCount +1);
  1087. return STATUS_NO_MEMORY;
  1088. }
  1089. }
  1090. }
  1091. else
  1092. return STATUS_NO_MEMORY;
  1093. }
  1094. else
  1095. {
  1096. apSids = (PSID*) HeapAlloc( GetProcessHeap(),
  1097. HEAP_ZERO_MEMORY,
  1098. sizeof(PSID) * 2 );
  1099. if (!apSids)
  1100. {
  1101. return STATUS_NO_MEMORY;
  1102. }
  1103. WCHAR wszDomain[256];
  1104. DWORD cDomain = 256;
  1105. SID_NAME_USE psnu;
  1106. DWORD cSid = 256;
  1107. apSids[0] = (PSID)HeapAlloc( GetProcessHeap(),
  1108. HEAP_ZERO_MEMORY,
  1109. cSid );
  1110. if ( apSids[0] == NULL )
  1111. {
  1112. return STATUS_NO_MEMORY;
  1113. }
  1114. //
  1115. // have to join the domain name and user name strings. This is
  1116. // to qualify the name passed to LookupAccountName, but it also
  1117. // provides a significant performance improvement in the call.
  1118. //
  1119. WCHAR wszFullName[512];
  1120. int cDomainName = wcslen(domainName);
  1121. wcscpy(wszFullName,domainName);
  1122. wszFullName[cDomainName] = '\\';
  1123. wcscpy(wszFullName+cDomainName+1, userName);
  1124. if ( !LookupAccountNameW( NULL,
  1125. wszFullName,
  1126. apSids[0],
  1127. &cSid,
  1128. wszDomain,
  1129. &cDomain,
  1130. &psnu ) )
  1131. {
  1132. return GetLastError();
  1133. }
  1134. dwMembershipCount = 0;
  1135. apSids[1] = pSidEveryoneHeapAlloc;
  1136. }
  1137. CHeapFreeMe freeArray(apSids);
  1138. // do it again for the local case
  1139. DWORD dwLocalGroupCount;
  1140. DWORD* pdwLocalGroups;
  1141. ntst = sam.m_pfnSamGetAliasMembership(hBuiltinDomain, dwMembershipCount+2, apSids, &dwLocalGroupCount,
  1142. &pdwLocalGroups);
  1143. if (ntst)
  1144. {
  1145. ERRORTRACE((LOG_ESS, "SamGetAliasMembership Failed, error 0x%X\n", ntst));
  1146. return ntst;
  1147. }
  1148. CSamFreeMe freeGroups(sam, pdwLocalGroups);
  1149. // got both the global & the local - build us an array to hold them all:
  1150. PSID* apAllSids = (PSID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PSID) * (dwMembershipCount + dwLocalGroupCount +2));
  1151. if (apSids)
  1152. {
  1153. for(DWORD i = 0; i < dwMembershipCount +2; i++)
  1154. apAllSids[i] = apSids[i];
  1155. for (i = 0; i < dwLocalGroupCount; i++)
  1156. {
  1157. PSID pSid = CreateUserSid(pBuiltinDomainId, pdwLocalGroups[i]);
  1158. if (pSid)
  1159. apAllSids[i +dwMembershipCount +2] = pSid;
  1160. else
  1161. // lazy man's cleanup - let the dtors do all the work;
  1162. {
  1163. ERRORTRACE((LOG_ESS, "Allocation Failure\n"));
  1164. CHeapFreeMe freeArray(apAllSids);
  1165. CHeapBigPointerArrayCleanerUpper cleanAllSids(apAllSids, dwMembershipCount + dwLocalGroupCount +1);
  1166. return STATUS_NO_MEMORY;
  1167. }
  1168. }
  1169. *apGroupSids = apAllSids;
  1170. *pdwCount = dwMembershipCount + dwLocalGroupCount +2;
  1171. }
  1172. else
  1173. {
  1174. ERRORTRACE((LOG_ESS, "Allocation Failure\n"));
  1175. return STATUS_NO_MEMORY;
  1176. }
  1177. }
  1178. return STATUS_SUCCESS;
  1179. }
  1180. #endif