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.

1356 lines
38 KiB

  1. /*---------------------------------------------------------------------------
  2. File: UserRights.cpp
  3. Comments: COM object to update user rights.
  4. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  5. Proprietary and confidential to Mission Critical Software, Inc.
  6. REVISION LOG ENTRY
  7. Revision By: Christy Boles
  8. Revised on 02/15/99 11:34:35
  9. ---------------------------------------------------------------------------
  10. */
  11. // UserRights.cpp : Implementation of CUserRights
  12. #include "stdafx.h"
  13. #include "WorkObj.h"
  14. #include "UserRts.h"
  15. #include "Common.hpp"
  16. #include "TNode.hpp"
  17. #include "UString.hpp"
  18. #include "ErrDct.hpp"
  19. #include "TxtSid.h"
  20. #include "LSAUtils.h"
  21. #include "EaLen.hpp"
  22. #include "ntsecapi.h"
  23. #include <lm.h>
  24. #ifdef _DEBUG
  25. #define new DEBUG_NEW
  26. #undef THIS_FILE
  27. static char THIS_FILE[] = __FILE__;
  28. #endif
  29. extern TErrorDct err;
  30. #define LEN_SID 200
  31. #ifndef SE_DENY_INTERACTIVE_LOGON_NAME
  32. #define SE_DENY_INTERACTIVE_LOGON_NAME TEXT("SeDenyInteractiveLogonRight")
  33. #endif
  34. #ifndef SE_DENY_NETWORK_LOGON_NAME
  35. #define SE_DENY_NETWORK_LOGON_NAME TEXT("SeDenyNetworkLogonRight")
  36. #endif
  37. #ifndef SE_DENY_BATCH_LOGON_NAME
  38. #define SE_DENY_BATCH_LOGON_NAME TEXT("SeDenyBatchLogonRight")
  39. #endif
  40. #ifndef SE_DENY_SERVICE_LOGON_NAME
  41. #define SE_DENY_SERVICE_LOGON_NAME TEXT("SeDenyServiceLogonRight")
  42. #endif
  43. //
  44. // this function wasn't defined in the header file.
  45. extern "C" {
  46. NTSTATUS
  47. NTAPI
  48. LsaEnumeratePrivileges(
  49. LSA_HANDLE PolicyHandle,
  50. LSA_ENUMERATION_HANDLE * eHandle,
  51. LPVOID * enumBuffer,
  52. ULONG prefMaxLen,
  53. ULONG * countReturned
  54. );
  55. };
  56. //The following definition was in ntsecapi.h but was mistakenly taken out
  57. //in the W2K build version.
  58. //
  59. // The following data type is used to return information about privileges
  60. // defined on a system.
  61. //
  62. typedef struct _POLICY_PRIVILEGE_DEFINITION {
  63. LSA_UNICODE_STRING Name;
  64. LUID LocalValue;
  65. } POLICY_PRIVILEGE_DEFINITION, *PPOLICY_PRIVILEGE_DEFINITION;
  66. class PrivNode : public TNode
  67. {
  68. WCHAR name[200];
  69. public:
  70. PrivNode(WCHAR * str, USHORT length ) { UStrCpy(name,str,length+1); name[length] = 0; }
  71. WCHAR * Name() { return name; }
  72. };
  73. class PrivList : public TNodeListSortable
  74. {
  75. protected:
  76. static TNodeCompare(CompareName)
  77. {
  78. PrivNode * p1 = (PrivNode *)v1;
  79. PrivNode * p2 = (PrivNode *)v2;
  80. return UStrICmp(p1->Name(),p2->Name());
  81. }
  82. static TNodeCompareValue(CompareValue)
  83. {
  84. PrivNode * p = (PrivNode *)tnode;
  85. WCHAR * str = (WCHAR *)value;
  86. return UStrICmp(p->Name(),str);
  87. }
  88. public:
  89. PrivList() { TypeSetSorted(); CompareSet(&CompareName); }
  90. ~PrivList() { DeleteAllListItems(PrivNode); }
  91. void InsertPrivilege(PrivNode * p) { SortedInsertIfNew((TNode *)p); }
  92. BOOL Contains(WCHAR * priv) { return ( NULL != Find(&CompareValue,(void*)priv) ); }
  93. };
  94. DWORD
  95. BuildPrivilegeList(
  96. LSA_HANDLE policy, // in - handle to LSA
  97. WCHAR * account, // in - account to list privileges for
  98. WCHAR * strSid, // in - textual form of account's sid, if known
  99. WCHAR * computer, // in - computer name
  100. PrivList * privList, // i/o- list of privileges
  101. PSID * ppSid // out- SID for the account
  102. );
  103. DWORD
  104. BuildPrivilegeList(
  105. LSA_HANDLE policy, // in - handle to LSA
  106. PSID pSid, // in - sid of account to list privileges for
  107. PrivList * privList // i/o- list of privileges
  108. );
  109. NTSTATUS
  110. OpenPolicy(
  111. LPWSTR ServerName, // machine to open policy on (Unicode)
  112. DWORD DesiredAccess, // desired access to policy
  113. PLSA_HANDLE PolicyHandle // resultant policy handle
  114. );
  115. BOOL
  116. GetAccountSid(
  117. LPTSTR SystemName, // where to lookup account
  118. LPTSTR AccountName, // account of interest
  119. PSID *Sid // resultant buffer containing SID
  120. );
  121. NTSTATUS
  122. SetPrivilegeOnAccount(
  123. LSA_HANDLE PolicyHandle, // open policy handle
  124. PSID AccountSid, // SID to grant privilege to
  125. LPWSTR PrivilegeName, // privilege to grant (Unicode)
  126. BOOL bEnable // enable or disable
  127. );
  128. /////////////////////////////////////////////////////////////////////////////
  129. // CUserRights
  130. CUserRights::~CUserRights()
  131. {
  132. if ( m_SrcPolicy )
  133. {
  134. LsaClose(m_SrcPolicy);
  135. }
  136. if ( m_TgtPolicy )
  137. {
  138. LsaClose(m_TgtPolicy);
  139. }
  140. }
  141. STDMETHODIMP
  142. CUserRights::OpenSourceServer(
  143. BSTR serverName // in - computer name (DC) for source domain
  144. )
  145. {
  146. DWORD rc;
  147. if ( m_SrcPolicy )
  148. {
  149. LsaClose(m_SrcPolicy);
  150. m_SrcPolicy = NULL;
  151. }
  152. rc = OpenPolicy( serverName, POLICY_LOOKUP_NAMES, &m_SrcPolicy );
  153. m_SourceComputer = serverName;
  154. return HRESULT_FROM_WIN32(rc);
  155. }
  156. STDMETHODIMP
  157. CUserRights::OpenTargetServer(
  158. BSTR computerName // in - computer name (DC) for target domain
  159. )
  160. {
  161. DWORD rc;
  162. if ( m_TgtPolicy )
  163. {
  164. LsaClose(m_TgtPolicy);
  165. m_TgtPolicy = NULL;
  166. }
  167. rc = OpenPolicy( computerName,POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES ,&m_TgtPolicy);
  168. m_TargetComputer = computerName;
  169. return HRESULT_FROM_WIN32(rc);
  170. }
  171. STDMETHODIMP
  172. CUserRights::CopyUserRights(
  173. BSTR sourceUserName, // in - source domain account to copy rights from
  174. BSTR targetUserName // in - target domain account to copy rights to
  175. )
  176. {
  177. HRESULT hr = S_OK;
  178. DWORD rc;
  179. // Make sure source and target are open
  180. if ( m_SrcPolicy && m_TgtPolicy )
  181. {
  182. rc = CopyUserRightsInternal(sourceUserName,targetUserName,L"",L"",m_bNoChange,m_bRemove);
  183. hr = HRESULT_FROM_WIN32(rc);
  184. }
  185. else
  186. {
  187. hr = E_FAIL;
  188. }
  189. return S_OK;
  190. }
  191. STDMETHODIMP
  192. CUserRights::CopyUserRightsWithSids(
  193. BSTR sourceUserName, // in - source domain account to copy rights from
  194. BSTR sourceSID, // in - source account SID (in string format)
  195. BSTR targetUserName, // in - target domain account to copy rights to
  196. BSTR targetSID // in - target account SID (in string format)
  197. )
  198. {
  199. HRESULT hr = S_OK;
  200. DWORD rc;
  201. // Make sure source and target are open
  202. if ( m_SrcPolicy && m_TgtPolicy )
  203. {
  204. rc = CopyUserRightsInternal(sourceUserName,targetUserName,sourceSID,targetSID,m_bNoChange,m_bRemove);
  205. hr = HRESULT_FROM_WIN32(rc);
  206. }
  207. else
  208. {
  209. hr = E_FAIL;
  210. }
  211. return S_OK;
  212. }
  213. STDMETHODIMP CUserRights::get_NoChange(BOOL *pVal) // out- value
  214. {
  215. (*pVal) = m_bNoChange;
  216. return S_OK;
  217. }
  218. STDMETHODIMP CUserRights::put_NoChange(BOOL newVal) // in - new value
  219. {
  220. m_bNoChange = newVal;
  221. return S_OK;
  222. }
  223. STDMETHODIMP CUserRights::get_RemoveOldRightsFromTargetAccounts(BOOL *pVal) // out- value
  224. {
  225. (*pVal) = m_bRemove;
  226. return S_OK;
  227. }
  228. STDMETHODIMP CUserRights::put_RemoveOldRightsFromTargetAccounts(BOOL newVal) // in - new value
  229. {
  230. m_bRemove = newVal;
  231. return S_OK;
  232. }
  233. STDMETHODIMP
  234. CUserRights::ExportUserRights(
  235. BSTR server, // in - computer to read rights from
  236. BSTR filename, // in - filename to export list of rights to
  237. BOOL bAppendToFile // in - flag, append or overwrite file if it exists
  238. )
  239. {
  240. LSA_HANDLE policy;
  241. HRESULT hr = S_OK;
  242. DWORD rc;
  243. rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
  244. if ( ! rc )
  245. {
  246. CommaDelimitedLog log;
  247. if ( log.LogOpen(filename,FALSE,bAppendToFile) )
  248. {
  249. // Enumerate the privileges on this machine
  250. // arguments for LsaEnumeratePrivileges
  251. ULONG countOfRights;
  252. DWORD prefMax = 0xffffffff;
  253. LSA_ENUMERATION_HANDLE handle = 0;
  254. POLICY_PRIVILEGE_DEFINITION * pRights = NULL;
  255. do
  256. {
  257. rc = LsaEnumeratePrivileges(policy,&handle,(LPVOID*)&pRights,prefMax,&countOfRights);
  258. if ( rc )
  259. {
  260. rc = LsaNtStatusToWinError(rc);
  261. if ( rc == ERROR_NO_MORE_ITEMS )
  262. rc = 0;
  263. break;
  264. }
  265. // For each right, enumerate the accounts that have that right
  266. if ( ! rc )
  267. {
  268. for ( UINT right = 0 ;right < countOfRights ; right++ )
  269. {
  270. rc = EnumerateAccountsWithRight(policy,server,&pRights[right].Name,&log);
  271. }
  272. LsaFreeMemory(pRights);
  273. LSA_UNICODE_STRING lsaRight;
  274. // For some reason, LsaEnumeratePrivileges doesn't return these rights
  275. // They are defined in "ntsecapi.h", and not with the rest of the privileges in "winnt.h"
  276. if ( ! rc )
  277. {
  278. InitLsaString(&lsaRight,SE_INTERACTIVE_LOGON_NAME);
  279. rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
  280. }
  281. if ( ! rc )
  282. {
  283. InitLsaString(&lsaRight,SE_NETWORK_LOGON_NAME);
  284. rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
  285. }
  286. if ( ! rc )
  287. {
  288. InitLsaString(&lsaRight,SE_BATCH_LOGON_NAME);
  289. rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
  290. }
  291. if ( ! rc )
  292. {
  293. InitLsaString(&lsaRight,SE_SERVICE_LOGON_NAME);
  294. rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
  295. }
  296. }
  297. else
  298. {
  299. rc = LsaNtStatusToWinError(rc);
  300. }
  301. }
  302. while ( ! rc );
  303. log.LogClose();
  304. }
  305. else
  306. {
  307. rc = GetLastError();
  308. }
  309. LsaClose(policy);
  310. }
  311. hr = HRESULT_FROM_WIN32(rc);
  312. return hr;
  313. }
  314. DWORD
  315. CUserRights::EnumerateAccountsWithRight(
  316. LSA_HANDLE policy, // in - handle to LSA
  317. WCHAR * server, // in - computer name
  318. LSA_UNICODE_STRING * pRight, // in - user right
  319. CommaDelimitedLog * pLog // in - pointer to log object to log information to
  320. )
  321. {
  322. DWORD rc = 0;
  323. WCHAR account[LEN_Account];
  324. WCHAR domain[LEN_Domain];
  325. WCHAR domacct[LEN_Domain + LEN_Account];
  326. WCHAR szRight[LEN_Account];
  327. WCHAR szDisplayName[LEN_DisplayName];
  328. DWORD lenAccount = DIM(account);
  329. DWORD lenDomain = DIM(domain);
  330. DWORD lenDisplayName = DIM(szDisplayName);
  331. SID_NAME_USE snu;
  332. DWORD lid;
  333. BOOL bUseDisplayName;
  334. // arguments for LsaEnumerateAccountsWithUserRight
  335. ULONG countOfUsers;
  336. LSA_ENUMERATION_INFORMATION * pInfo = NULL;
  337. UStrCpy(szRight,pRight->Buffer,pRight->Length/(sizeof WCHAR) + 1);
  338. bUseDisplayName = m_bUseDisplayName && LookupPrivilegeDisplayName(server,szRight,szDisplayName,&lenDisplayName,&lid);
  339. rc = LsaEnumerateAccountsWithUserRight(policy,pRight,(PVOID*)&pInfo,&countOfUsers);
  340. if ( ! rc )
  341. {
  342. for ( UINT user = 0 ; user < countOfUsers ; user++ )
  343. {
  344. if ( ! pInfo[user].Sid )
  345. {
  346. break; // something is wrong
  347. }
  348. domain[0] = 0;
  349. account[0] = 0;
  350. lenDomain = DIM(domain);
  351. lenAccount = DIM(account);
  352. if ( LookupAccountSid(server,pInfo[user].Sid,account,&lenAccount,domain,&lenDomain,&snu) )
  353. {
  354. if ( *account )
  355. {
  356. swprintf(domacct,L"%s\\%s",domain,account);
  357. }
  358. else
  359. {
  360. lenAccount = DIM(account);
  361. GetTextualSid(pInfo[user].Sid,account,&lenAccount);
  362. if ( snu == SidTypeDeletedAccount )
  363. {
  364. swprintf(domacct,L"%s\\<Deleted Account: %s>",domain,account);
  365. }
  366. else
  367. {
  368. swprintf(domacct,L"%s\\<%s>",domain,account);
  369. }
  370. }
  371. }
  372. else
  373. {
  374. lenAccount = DIM(account);
  375. GetTextualSid(pInfo[user].Sid,domacct,&lenAccount);
  376. }
  377. if ( bUseDisplayName )
  378. {
  379. pLog->MsgWrite(L"%s, %s, %s",server,domacct,szDisplayName);
  380. }
  381. else
  382. {
  383. pLog->MsgWrite(L"%s, %s, %s",server,domacct,szRight);
  384. }
  385. }
  386. LsaFreeMemory(pInfo);
  387. }
  388. else
  389. {
  390. rc = LsaNtStatusToWinError(rc);
  391. if ( rc == ERROR_NO_MORE_ITEMS )
  392. rc = 0;
  393. }
  394. return rc;
  395. }
  396. DWORD
  397. CUserRights::CopyUserRightsInternal(
  398. WCHAR * srcAccount, // in - source account to copy rights from
  399. WCHAR * tgtAccount, // in - account to copy rights to
  400. WCHAR * srcSidStr, // in - sid for source account, in string format
  401. WCHAR * tgtSidStr, // in - sid for target account, in string format
  402. BOOL bNoChange, // in - flag, whether to write changes
  403. BOOL bRemove // in - flag, whether to revoke rights from target if not held by source
  404. )
  405. {
  406. DWORD rc = 0;
  407. PrivList srcList;
  408. PrivList tgtList;
  409. PSID pSidSrc = NULL;
  410. PSID pSidTgt = NULL;
  411. // Get a list of the privileges held by srcAccount
  412. rc = BuildPrivilegeList(m_SrcPolicy,srcAccount,srcSidStr,m_SourceComputer,&srcList,&pSidSrc);
  413. if ( ! rc )
  414. {
  415. rc = BuildPrivilegeList(m_TgtPolicy,tgtAccount,tgtSidStr,m_TargetComputer,&tgtList,&pSidTgt);
  416. if ( ! rc )
  417. {
  418. if ( bRemove )
  419. {
  420. // Get a list of privileges held by tgtAccount
  421. // Remove old privileges
  422. TNodeListEnum tEnum;
  423. PrivNode * p;
  424. for ( p = (PrivNode *)tEnum.OpenFirst(&tgtList) ; p ; p = (PrivNode*)tEnum.Next() )
  425. {
  426. if ( ! srcList.Contains(p->Name()) )
  427. {
  428. // The source account doesn't have this privilege - remove it
  429. if (! bNoChange )
  430. {
  431. rc = SetPrivilegeOnAccount(m_TgtPolicy,pSidTgt,p->Name(),FALSE);
  432. }
  433. if ( rc )
  434. {
  435. rc = LsaNtStatusToWinError(rc);
  436. err.MsgWrite(ErrE,DCT_MSG_REMOVE_RIGHT_FAILED_SSD,p->Name(),tgtAccount,rc);
  437. break;
  438. }
  439. else
  440. {
  441. err.MsgWrite(0,DCT_MSG_REMOVED_RIGHT_SS,p->Name(), tgtAccount);
  442. }
  443. }
  444. else
  445. {
  446. err.MsgWrite(0,DCT_MSG_USER_HAS_RIGHT_SS,tgtAccount,p->Name());
  447. }
  448. }
  449. }
  450. // Grant privileges to new account
  451. TNodeListEnum tEnum;
  452. PrivNode * p;
  453. for ( p = (PrivNode *)tEnum.OpenFirst(&srcList) ; p ; p = (PrivNode*)tEnum.Next() )
  454. {
  455. if ( ! tgtList.Contains(p->Name()) )
  456. {
  457. if ( ! bNoChange )
  458. {
  459. rc = SetPrivilegeOnAccount(m_TgtPolicy,pSidTgt,p->Name(),TRUE);
  460. if ( rc )
  461. {
  462. rc = LsaNtStatusToWinError(rc);
  463. err.MsgWrite(ErrE,DCT_MSG_ADD_RIGHT_FAILED_SSD,p->Name(),tgtAccount,rc);
  464. break;
  465. }
  466. else
  467. {
  468. err.MsgWrite(0,DCT_MSG_RIGHT_GRANTED_SS,p->Name(),tgtAccount);
  469. }
  470. }
  471. }
  472. }
  473. }
  474. }
  475. // Clean up SIDs
  476. if(pSidSrc != NULL)
  477. {
  478. FreeSid(pSidSrc);
  479. }
  480. if(pSidTgt != NULL)
  481. {
  482. FreeSid(pSidTgt);
  483. }
  484. return rc;
  485. }
  486. /*++
  487. Managing user privileges can be achieved programmatically using the
  488. following steps:
  489. 1. Open the policy on the target machine with LsaOpenPolicy(). To grant
  490. privileges, open the policy with POLICY_CREATE_ACCOUNT and
  491. POLICY_LOOKUP_NAMES access. To revoke privileges, open the policy with
  492. POLICY_LOOKUP_NAMES access.
  493. 2. Obtain a SID (security identifier) representing the user/group of
  494. interest. The LookupAccountName() and LsaLookupNames() APIs can obtain a
  495. SID from an account name.
  496. 3. Call LsaAddAccountRights() to grant privileges to the user(s)
  497. represented by the supplied SID.
  498. 4. Call LsaRemoveAccountRights() to revoke privileges from the user(s)
  499. represented by the supplied SID.
  500. 5. Close the policy with LsaClose().
  501. To successfully grant and revoke privileges, the caller needs to be an
  502. administrator on the target system.
  503. The LSA API LsaEnumerateAccountRights() can be used to determine which
  504. privileges have been granted to an account.
  505. The LSA API LsaEnumerateAccountsWithUserRight() can be used to determine
  506. which accounts have been granted a specified privilege.
  507. Documentation and header files for these LSA APIs is provided in the
  508. Windows 32 SDK in the MSTOOLS\SECURITY directory.
  509. --*/
  510. #define RTN_OK 0
  511. #define RTN_USAGE 1
  512. #define RTN_ERROR 13
  513. DWORD
  514. BuildPrivilegeList(
  515. LSA_HANDLE policy, // in - handle to LSA
  516. PSID pSid, // in - SID for account
  517. PrivList * privList // i/o- list of rights held by the account
  518. )
  519. {
  520. DWORD rc = 0;
  521. ULONG countOfRights = 0;
  522. PLSA_UNICODE_STRING pUserRights = NULL;
  523. rc = LsaEnumerateAccountRights(policy,pSid,&pUserRights,&countOfRights);
  524. rc = LsaNtStatusToWinError(rc);
  525. if ( rc == ERROR_FILE_NOT_FOUND )
  526. {
  527. // This account has no privileges
  528. rc = 0;
  529. countOfRights = 0;
  530. }
  531. if ( ! rc )
  532. {
  533. for ( UINT i = 0 ; i < countOfRights ; i++ )
  534. {
  535. PrivNode * p = new PrivNode(pUserRights[i].Buffer,pUserRights[i].Length/2);
  536. privList->InsertPrivilege(p);
  537. }
  538. LsaFreeMemory(pUserRights);
  539. }
  540. return rc;
  541. }
  542. DWORD
  543. BuildPrivilegeList(
  544. LSA_HANDLE policy, // in - handle to LSA
  545. WCHAR * account, // in - account name to list rights for
  546. WCHAR * strSid, // in - text format of the accounts SID, if known
  547. WCHAR * computer, // in - computer to list rights on
  548. PrivList * privList, // i/o- list of rights held by account
  549. PSID * ppSid // out- SID for account
  550. )
  551. {
  552. DWORD rc = 0;
  553. PSID pSid = NULL;
  554. if ( strSid && (*strSid) )
  555. {
  556. // use the provided SID
  557. pSid = SidFromString(strSid);
  558. if ( ! pSid )
  559. {
  560. rc = GetLastError();
  561. }
  562. }
  563. else
  564. {
  565. // no SID provided, so look it up on the domain
  566. if ( !GetAccountSid(computer,account,&pSid) )
  567. {
  568. rc = GetLastError();
  569. }
  570. }
  571. if ( rc )
  572. {
  573. (*ppSid) = NULL;
  574. if(pSid != NULL)
  575. {
  576. FreeSid(pSid);
  577. pSid = NULL;
  578. }
  579. }
  580. else
  581. {
  582. (*ppSid) = pSid;
  583. }
  584. if ( pSid )
  585. {
  586. rc = BuildPrivilegeList(policy,pSid,privList);
  587. }
  588. return rc;
  589. }
  590. BOOL
  591. GetAccountSid(
  592. LPTSTR SystemName, // in - computer name to lookup sid on
  593. LPTSTR AccountName, // in - account name
  594. PSID *Sid // out- SID for account
  595. )
  596. {
  597. WCHAR ReferencedDomain[LEN_Domain];
  598. DWORD cbSid=128; // initial allocation attempt
  599. DWORD cbReferencedDomain=DIM(ReferencedDomain); // initial allocation size
  600. SID_NAME_USE peUse;
  601. BOOL bSuccess=FALSE; // assume this function will fail
  602. PSID pTempSid = NULL;
  603. *Sid = NULL;
  604. __try {
  605. //
  606. // initial memory allocations
  607. //
  608. if((pTempSid=HeapAlloc(
  609. GetProcessHeap(),
  610. 0,
  611. cbSid
  612. )) == NULL) __leave;
  613. //
  614. // Obtain the SID of the specified account on the specified system.
  615. //
  616. while(!LookupAccountName(
  617. SystemName, // machine to lookup account on
  618. AccountName, // account to lookup
  619. pTempSid, // SID of interest
  620. &cbSid, // size of SID
  621. ReferencedDomain, // domain account was found on
  622. &cbReferencedDomain,
  623. &peUse
  624. )) {
  625. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  626. //
  627. // reallocate memory
  628. //
  629. PSID psid = HeapReAlloc(GetProcessHeap(), 0, pTempSid, cbSid);
  630. if (psid != NULL)
  631. {
  632. pTempSid = psid;
  633. }
  634. else
  635. {
  636. __leave;
  637. }
  638. }
  639. else __leave;
  640. }
  641. //
  642. // Indicate success.
  643. //
  644. bSuccess=TRUE;
  645. } // finally
  646. __finally {
  647. //
  648. // Cleanup and indicate failure, if appropriate.
  649. //
  650. if(!bSuccess) {
  651. if(pTempSid!= NULL) {
  652. HeapFree(GetProcessHeap(), 0, pTempSid);
  653. pTempSid = NULL;
  654. }
  655. }
  656. } // finally
  657. // we need to copy the sid over if previous operation succeeded
  658. if(bSuccess)
  659. {
  660. *Sid = SafeCopySid(pTempSid);
  661. if(!(*Sid))
  662. {
  663. // safecopysid failed for some reason, we need to update the return value
  664. bSuccess = FALSE;
  665. }
  666. // need to free the temporary sid
  667. if(pTempSid)
  668. {
  669. HeapFree(GetProcessHeap(), 0, pTempSid);
  670. }
  671. }
  672. return bSuccess;
  673. }
  674. NTSTATUS
  675. SetPrivilegeOnAccount(
  676. LSA_HANDLE PolicyHandle, // open policy handle
  677. PSID AccountSid, // SID to grant privilege to
  678. LPWSTR PrivilegeName, // privilege to grant (Unicode)
  679. BOOL bEnable // enable or disable
  680. )
  681. {
  682. LSA_UNICODE_STRING PrivilegeString;
  683. //
  684. // Create a LSA_UNICODE_STRING for the privilege name.
  685. //
  686. InitLsaString(&PrivilegeString, PrivilegeName);
  687. //
  688. // grant or revoke the privilege, accordingly
  689. //
  690. if(bEnable) {
  691. return LsaAddAccountRights(
  692. PolicyHandle, // open policy handle
  693. AccountSid, // target SID
  694. &PrivilegeString, // privileges
  695. 1 // privilege count
  696. );
  697. }
  698. else {
  699. return LsaRemoveAccountRights(
  700. PolicyHandle, // open policy handle
  701. AccountSid, // target SID
  702. FALSE, // do not disable all rights
  703. &PrivilegeString, // privileges
  704. 1 // privilege count
  705. );
  706. }
  707. }
  708. STDMETHODIMP
  709. CUserRights::AddUserRight(
  710. BSTR server, // in - computer to grant right on
  711. BSTR strSid, // in - textual form of sid for account to grant right to
  712. BSTR right // in - right to grant to account
  713. )
  714. {
  715. LSA_HANDLE policy;
  716. HRESULT hr = S_OK;
  717. DWORD rc;
  718. PSID pSid = SidFromString(strSid);
  719. rc = OpenPolicy(server, POLICY_LOOKUP_NAMES|POLICY_CREATE_ACCOUNT, &policy);
  720. if ( ! rc )
  721. {
  722. if ( ! m_bNoChange )
  723. {
  724. rc = SetPrivilegeOnAccount(policy,pSid,right,TRUE);
  725. }
  726. if ( rc )
  727. {
  728. rc = LsaNtStatusToWinError(rc);
  729. hr = HRESULT_FROM_WIN32(rc);
  730. }
  731. LsaClose(policy);
  732. }
  733. FreeSid(pSid);
  734. return HRESULT_FROM_WIN32(rc);
  735. }
  736. STDMETHODIMP
  737. CUserRights::RemoveUserRight(
  738. BSTR server, // in - computer to revoke right on
  739. BSTR strSid, // in - textual sid of account to revoke right for
  740. BSTR right // in - right to revoke
  741. )
  742. {
  743. LSA_HANDLE policy;
  744. HRESULT hr = S_OK;
  745. DWORD rc;
  746. PSID pSid = SidFromString(strSid);
  747. rc = OpenPolicy(server, POLICY_LOOKUP_NAMES|POLICY_CREATE_ACCOUNT, &policy);
  748. if ( ! rc )
  749. {
  750. if ( ! m_bNoChange )
  751. {
  752. rc = SetPrivilegeOnAccount(policy,pSid,right,FALSE);
  753. }
  754. if ( rc )
  755. {
  756. rc = LsaNtStatusToWinError(rc);
  757. hr = HRESULT_FROM_WIN32(rc);
  758. }
  759. LsaClose(policy);
  760. }
  761. FreeSid(pSid);
  762. return HRESULT_FROM_WIN32(rc);
  763. }
  764. DWORD
  765. CUserRights::SafeArrayFromPrivList(
  766. PrivList * privList, // in - list of user rights
  767. SAFEARRAY ** pArray // out- safearray containing list contents
  768. )
  769. {
  770. DWORD rc = 0;
  771. HRESULT hr;
  772. TNodeListEnum e;
  773. SAFEARRAYBOUND bound;
  774. LONG ndx[1];
  775. bound.lLbound = 0;
  776. bound.cElements = privList->Count();
  777. (*pArray) = SafeArrayCreate(VT_BSTR,1,&bound);
  778. if ( (*pArray) )
  779. {
  780. PrivNode * p;
  781. UINT i;
  782. for ( p=(PrivNode*)e.OpenFirst(privList) , i = 0 ;
  783. p ;
  784. p = (PrivNode*)e.Next() , i++ )
  785. {
  786. ndx[0] = i;
  787. hr = SafeArrayPutElement((*pArray),ndx,SysAllocString(p->Name()));
  788. if ( FAILED(hr) )
  789. {
  790. rc = hr;
  791. break;
  792. }
  793. }
  794. e.Close();
  795. }
  796. else
  797. {
  798. rc = GetLastError();
  799. }
  800. return rc;
  801. }
  802. STDMETHODIMP
  803. CUserRights::GetRights(
  804. BSTR server, // in - computer
  805. SAFEARRAY ** pRightsArray // out- list of rights on computer
  806. )
  807. {
  808. HRESULT hr = S_OK;
  809. PrivList priv;
  810. DWORD rc = 0;
  811. LSA_HANDLE policy = NULL;
  812. rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
  813. // Enumerate the privileges on this machine
  814. // arguments for LsaEnumeratePrivileges
  815. ULONG countOfRights;
  816. DWORD prefMax = 0xffffffff;
  817. LSA_ENUMERATION_HANDLE handle = 0;
  818. POLICY_PRIVILEGE_DEFINITION * pRights = NULL;
  819. do
  820. {
  821. if ( rc )
  822. break;
  823. rc = LsaEnumeratePrivileges(policy,&handle,(LPVOID*)&pRights,prefMax,&countOfRights);
  824. if ( rc )
  825. {
  826. rc = LsaNtStatusToWinError(rc);
  827. if ( rc == ERROR_NO_MORE_ITEMS )
  828. rc = 0;
  829. break;
  830. }
  831. if ( ! rc )
  832. {
  833. PrivNode * p = NULL;
  834. for ( UINT right = 0 ;right < countOfRights ; right++ )
  835. {
  836. // Length is in bytes
  837. p = new PrivNode(pRights[right].Name.Buffer,pRights[right].Name.Length/2);
  838. priv.InsertPrivilege(p);
  839. }
  840. LsaFreeMemory(pRights);
  841. LSA_UNICODE_STRING lsaRight;
  842. // For some reason, LsaEnumeratePrivileges doesn't return these rights
  843. // They are defined in "ntsecapi.h", and not with the rest of the privileges in "winnt.h"
  844. if ( ! rc )
  845. {
  846. InitLsaString(&lsaRight,SE_INTERACTIVE_LOGON_NAME);
  847. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  848. priv.InsertPrivilege(p);
  849. }
  850. if ( ! rc )
  851. {
  852. InitLsaString(&lsaRight,SE_NETWORK_LOGON_NAME);
  853. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  854. priv.InsertPrivilege(p);
  855. }
  856. if ( ! rc )
  857. {
  858. InitLsaString(&lsaRight,SE_BATCH_LOGON_NAME);
  859. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  860. priv.InsertPrivilege(p);
  861. }
  862. if ( ! rc )
  863. {
  864. InitLsaString(&lsaRight,SE_SERVICE_LOGON_NAME);
  865. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  866. priv.InsertPrivilege(p);
  867. }
  868. // Check the OS version on the server
  869. WKSTA_INFO_100 * pInfo;
  870. BOOL bIsWin2K = TRUE;
  871. DWORD rcInfo = NetWkstaGetInfo(server,100,(LPBYTE*)&pInfo);
  872. if ( ! rcInfo )
  873. {
  874. if ( pInfo->wki100_ver_major < 5 )
  875. {
  876. bIsWin2K = FALSE;
  877. }
  878. NetApiBufferFree(pInfo);
  879. }
  880. // The 4 "deny" rights are only defined on Windows 2000.
  881. if ( bIsWin2K )
  882. {
  883. if ( ! rc )
  884. {
  885. InitLsaString(&lsaRight,SE_DENY_INTERACTIVE_LOGON_NAME);
  886. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  887. priv.InsertPrivilege(p);
  888. }
  889. if ( ! rc )
  890. {
  891. InitLsaString(&lsaRight,SE_DENY_NETWORK_LOGON_NAME);
  892. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  893. priv.InsertPrivilege(p);
  894. }
  895. if ( ! rc )
  896. {
  897. InitLsaString(&lsaRight,SE_DENY_BATCH_LOGON_NAME);
  898. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  899. priv.InsertPrivilege(p);
  900. }
  901. if ( ! rc )
  902. {
  903. InitLsaString(&lsaRight,SE_DENY_SERVICE_LOGON_NAME);
  904. p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
  905. priv.InsertPrivilege(p);
  906. }
  907. }
  908. }
  909. else
  910. {
  911. rc = LsaNtStatusToWinError(rc);
  912. }
  913. } while ( false);
  914. if ( policy )
  915. {
  916. LsaClose(policy);
  917. }
  918. // Build a safearray of BSTRs from the priv-list
  919. rc = SafeArrayFromPrivList(&priv,pRightsArray);
  920. hr = HRESULT_FROM_WIN32(rc);
  921. return hr;
  922. }
  923. STDMETHODIMP
  924. CUserRights::GetUsersWithRight(
  925. BSTR server, // in - computer name
  926. BSTR right, // in - right to lookup
  927. SAFEARRAY ** users // out- list of accounts that hold right
  928. )
  929. {
  930. DWORD rc = 0;
  931. LSA_UNICODE_STRING Right;
  932. WCHAR strSid[LEN_SID];
  933. DWORD lenStrSid = DIM(strSid);
  934. PrivList plist;
  935. LSA_HANDLE policy = NULL;
  936. rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
  937. // arguments for LsaEnumerateAccountsWithUserRight
  938. ULONG countOfUsers;
  939. LSA_ENUMERATION_INFORMATION * pInfo = NULL;
  940. InitLsaString(&Right,right);
  941. rc = LsaEnumerateAccountsWithUserRight(policy,&Right,(PVOID*)&pInfo,&countOfUsers);
  942. if ( ! rc )
  943. {
  944. for ( UINT user = 0 ; user < countOfUsers ; user++ )
  945. {
  946. if ( ! pInfo[user].Sid )
  947. {
  948. continue; // something is wrong
  949. }
  950. GetTextualSid(pInfo[user].Sid,strSid,&lenStrSid);
  951. PrivNode * p = new PrivNode(strSid,(USHORT) UStrLen(strSid));
  952. plist.InsertPrivilege(p);
  953. }
  954. LsaFreeMemory(pInfo);
  955. }
  956. else
  957. {
  958. rc = LsaNtStatusToWinError(rc);
  959. if ( rc == ERROR_NO_MORE_ITEMS )
  960. rc = 0;
  961. }
  962. if ( ! rc )
  963. {
  964. rc = SafeArrayFromPrivList(&plist,users);
  965. }
  966. if ( policy )
  967. LsaClose(policy);
  968. return HRESULT_FROM_WIN32(rc);
  969. }
  970. STDMETHODIMP
  971. CUserRights::GetRightsOfUser(
  972. BSTR server, // in - computer name
  973. BSTR strSid, // in - textual sid for account
  974. SAFEARRAY ** rights // out- list of rights held by account on server
  975. )
  976. {
  977. DWORD rc = 0;
  978. PSID pSid = SidFromString(strSid);
  979. LSA_HANDLE policy = NULL;
  980. PrivList plist;
  981. rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
  982. if ( ! rc )
  983. {
  984. rc = BuildPrivilegeList(policy,pSid,&plist);
  985. if ( ! rc )
  986. {
  987. rc = SafeArrayFromPrivList(&plist,rights);
  988. }
  989. LsaClose(policy);
  990. }
  991. return HRESULT_FROM_WIN32(rc);
  992. }
  993. //---------------------------------------------------------------------------
  994. // AddUserRights Method
  995. //
  996. // Synopsis
  997. // Add user rights for specified account.
  998. //
  999. // Arguments
  1000. // IN bstrServer - domain controller to perform operation on
  1001. // IN bstrSid - SID of account
  1002. // IN psaRights - list of rights
  1003. //
  1004. // Return
  1005. // Standard HRESULT error status.
  1006. //---------------------------------------------------------------------------
  1007. STDMETHODIMP CUserRights::AddUserRights(BSTR bstrServer, BSTR bstrSid, SAFEARRAY* psaRights)
  1008. {
  1009. USES_CONVERSION;
  1010. HRESULT hr;
  1011. if ((bstrServer != NULL) && (bstrSid != NULL) && (psaRights != NULL))
  1012. {
  1013. PSID pSid = SidFromString(OLE2W(bstrSid));
  1014. if (pSid != NULL)
  1015. {
  1016. hr = SetRights(OLE2W(bstrServer), pSid, psaRights, true);
  1017. FreeSid(pSid);
  1018. }
  1019. else
  1020. {
  1021. hr = E_INVALIDARG;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. hr = E_INVALIDARG;
  1027. }
  1028. return hr;
  1029. }
  1030. //---------------------------------------------------------------------------
  1031. // RemoveUserRights Method
  1032. //
  1033. // Synopsis
  1034. // Remove user rights for specified account.
  1035. //
  1036. // Arguments
  1037. // IN bstrServer - domain controller to perform operation on
  1038. // IN bstrSid - SID of account
  1039. // IN psaRights - list of rights
  1040. //
  1041. // Return
  1042. // Standard HRESULT error status.
  1043. //---------------------------------------------------------------------------
  1044. STDMETHODIMP CUserRights::RemoveUserRights(BSTR bstrServer, BSTR bstrSid, SAFEARRAY* psaRights)
  1045. {
  1046. USES_CONVERSION;
  1047. HRESULT hr;
  1048. if ((bstrServer != NULL) && (bstrSid != NULL) && (psaRights != NULL))
  1049. {
  1050. PSID pSid = SidFromString(OLE2W(bstrSid));
  1051. if (pSid != NULL)
  1052. {
  1053. hr = SetRights(OLE2W(bstrServer), pSid, psaRights, false);
  1054. FreeSid(pSid);
  1055. }
  1056. else
  1057. {
  1058. hr = E_INVALIDARG;
  1059. }
  1060. }
  1061. else
  1062. {
  1063. hr = E_INVALIDARG;
  1064. }
  1065. return hr;
  1066. }
  1067. //---------------------------------------------------------------------------
  1068. // SetRights Method
  1069. //
  1070. // Synopsis
  1071. // Add or remove user rights for specified account.
  1072. //
  1073. // Arguments
  1074. // IN pszServer - domain controller to perform operation on
  1075. // IN pSid - SID of account
  1076. // IN psaRights - list of rights
  1077. // IN bEnable - whether to add or remove rights
  1078. //
  1079. // Return
  1080. // HRESULT error status.
  1081. //---------------------------------------------------------------------------
  1082. HRESULT CUserRights::SetRights(PWSTR pszServer, PSID pSid, SAFEARRAY* psaRights, bool bEnable)
  1083. {
  1084. HRESULT hr = S_OK;
  1085. //
  1086. // Open LSA policy object on specified server with access required to add or remove rights.
  1087. //
  1088. LSA_HANDLE hPolicy = NULL;
  1089. NTSTATUS ntsStatus = OpenPolicy(pszServer, POLICY_CREATE_ACCOUNT|POLICY_LOOKUP_NAMES, &hPolicy);
  1090. if (ntsStatus == STATUS_SUCCESS)
  1091. {
  1092. //
  1093. // Generate array of unicode strings from BSTR array.
  1094. //
  1095. BSTR* pbstrRight;
  1096. hr = SafeArrayAccessData(psaRights, (void**)&pbstrRight);
  1097. if (SUCCEEDED(hr))
  1098. {
  1099. ULONG ulCount = psaRights->rgsabound[0].cElements;
  1100. if (ulCount > 0)
  1101. {
  1102. PLSA_UNICODE_STRING plsausRights = new LSA_UNICODE_STRING[ulCount];
  1103. if (plsausRights)
  1104. {
  1105. for (ULONG ulIndex = 0; ulIndex < ulCount; ulIndex++)
  1106. {
  1107. InitLsaString(&plsausRights[ulIndex], pbstrRight[ulIndex]);
  1108. }
  1109. //
  1110. // If not test mode, add or remove rights.
  1111. //
  1112. if (!m_bNoChange)
  1113. {
  1114. NTSTATUS ntsStatus;
  1115. if (bEnable)
  1116. {
  1117. ntsStatus = LsaAddAccountRights(hPolicy, pSid, plsausRights, ulCount);
  1118. }
  1119. else
  1120. {
  1121. ntsStatus = LsaRemoveAccountRights(hPolicy, pSid, FALSE, plsausRights, ulCount);
  1122. }
  1123. if (ntsStatus != STATUS_SUCCESS)
  1124. {
  1125. DWORD dwError = LsaNtStatusToWinError(ntsStatus);
  1126. hr = HRESULT_FROM_WIN32(dwError);
  1127. }
  1128. }
  1129. delete [] plsausRights;
  1130. }
  1131. else
  1132. {
  1133. hr = E_OUTOFMEMORY;
  1134. }
  1135. }
  1136. SafeArrayUnaccessData(psaRights);
  1137. }
  1138. LsaClose(hPolicy);
  1139. }
  1140. else
  1141. {
  1142. DWORD dwError = LsaNtStatusToWinError(ntsStatus);
  1143. hr = HRESULT_FROM_WIN32(dwError);
  1144. }
  1145. return hr;
  1146. }