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
1356 lines
38 KiB
/*---------------------------------------------------------------------------
|
|
File: UserRights.cpp
|
|
|
|
Comments: COM object to update user rights.
|
|
|
|
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
Revision By: Christy Boles
|
|
Revised on 02/15/99 11:34:35
|
|
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
// UserRights.cpp : Implementation of CUserRights
|
|
#include "stdafx.h"
|
|
#include "WorkObj.h"
|
|
#include "UserRts.h"
|
|
#include "Common.hpp"
|
|
#include "TNode.hpp"
|
|
#include "UString.hpp"
|
|
#include "ErrDct.hpp"
|
|
#include "TxtSid.h"
|
|
#include "LSAUtils.h"
|
|
#include "EaLen.hpp"
|
|
#include "ntsecapi.h"
|
|
|
|
#include <lm.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
extern TErrorDct err;
|
|
#define LEN_SID 200
|
|
|
|
|
|
#ifndef SE_DENY_INTERACTIVE_LOGON_NAME
|
|
#define SE_DENY_INTERACTIVE_LOGON_NAME TEXT("SeDenyInteractiveLogonRight")
|
|
#endif
|
|
#ifndef SE_DENY_NETWORK_LOGON_NAME
|
|
#define SE_DENY_NETWORK_LOGON_NAME TEXT("SeDenyNetworkLogonRight")
|
|
#endif
|
|
#ifndef SE_DENY_BATCH_LOGON_NAME
|
|
#define SE_DENY_BATCH_LOGON_NAME TEXT("SeDenyBatchLogonRight")
|
|
#endif
|
|
#ifndef SE_DENY_SERVICE_LOGON_NAME
|
|
#define SE_DENY_SERVICE_LOGON_NAME TEXT("SeDenyServiceLogonRight")
|
|
#endif
|
|
|
|
//
|
|
|
|
// this function wasn't defined in the header file.
|
|
extern "C" {
|
|
NTSTATUS
|
|
NTAPI
|
|
LsaEnumeratePrivileges(
|
|
LSA_HANDLE PolicyHandle,
|
|
LSA_ENUMERATION_HANDLE * eHandle,
|
|
LPVOID * enumBuffer,
|
|
ULONG prefMaxLen,
|
|
ULONG * countReturned
|
|
);
|
|
|
|
};
|
|
//The following definition was in ntsecapi.h but was mistakenly taken out
|
|
//in the W2K build version.
|
|
//
|
|
// The following data type is used to return information about privileges
|
|
// defined on a system.
|
|
//
|
|
|
|
typedef struct _POLICY_PRIVILEGE_DEFINITION {
|
|
|
|
LSA_UNICODE_STRING Name;
|
|
LUID LocalValue;
|
|
|
|
} POLICY_PRIVILEGE_DEFINITION, *PPOLICY_PRIVILEGE_DEFINITION;
|
|
|
|
|
|
class PrivNode : public TNode
|
|
{
|
|
WCHAR name[200];
|
|
|
|
public:
|
|
PrivNode(WCHAR * str, USHORT length ) { UStrCpy(name,str,length+1); name[length] = 0; }
|
|
|
|
WCHAR * Name() { return name; }
|
|
};
|
|
|
|
class PrivList : public TNodeListSortable
|
|
{
|
|
protected:
|
|
static TNodeCompare(CompareName)
|
|
{
|
|
PrivNode * p1 = (PrivNode *)v1;
|
|
PrivNode * p2 = (PrivNode *)v2;
|
|
|
|
return UStrICmp(p1->Name(),p2->Name());
|
|
}
|
|
static TNodeCompareValue(CompareValue)
|
|
{
|
|
PrivNode * p = (PrivNode *)tnode;
|
|
WCHAR * str = (WCHAR *)value;
|
|
|
|
return UStrICmp(p->Name(),str);
|
|
}
|
|
public:
|
|
PrivList() { TypeSetSorted(); CompareSet(&CompareName); }
|
|
~PrivList() { DeleteAllListItems(PrivNode); }
|
|
void InsertPrivilege(PrivNode * p) { SortedInsertIfNew((TNode *)p); }
|
|
BOOL Contains(WCHAR * priv) { return ( NULL != Find(&CompareValue,(void*)priv) ); }
|
|
|
|
};
|
|
|
|
DWORD
|
|
BuildPrivilegeList(
|
|
LSA_HANDLE policy, // in - handle to LSA
|
|
WCHAR * account, // in - account to list privileges for
|
|
WCHAR * strSid, // in - textual form of account's sid, if known
|
|
WCHAR * computer, // in - computer name
|
|
PrivList * privList, // i/o- list of privileges
|
|
PSID * ppSid // out- SID for the account
|
|
);
|
|
|
|
DWORD
|
|
BuildPrivilegeList(
|
|
LSA_HANDLE policy, // in - handle to LSA
|
|
PSID pSid, // in - sid of account to list privileges for
|
|
PrivList * privList // i/o- list of privileges
|
|
);
|
|
|
|
NTSTATUS
|
|
OpenPolicy(
|
|
LPWSTR ServerName, // machine to open policy on (Unicode)
|
|
DWORD DesiredAccess, // desired access to policy
|
|
PLSA_HANDLE PolicyHandle // resultant policy handle
|
|
);
|
|
|
|
BOOL
|
|
GetAccountSid(
|
|
LPTSTR SystemName, // where to lookup account
|
|
LPTSTR AccountName, // account of interest
|
|
PSID *Sid // resultant buffer containing SID
|
|
);
|
|
|
|
NTSTATUS
|
|
SetPrivilegeOnAccount(
|
|
LSA_HANDLE PolicyHandle, // open policy handle
|
|
PSID AccountSid, // SID to grant privilege to
|
|
LPWSTR PrivilegeName, // privilege to grant (Unicode)
|
|
BOOL bEnable // enable or disable
|
|
);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CUserRights
|
|
|
|
CUserRights::~CUserRights()
|
|
{
|
|
if ( m_SrcPolicy )
|
|
{
|
|
LsaClose(m_SrcPolicy);
|
|
}
|
|
if ( m_TgtPolicy )
|
|
{
|
|
LsaClose(m_TgtPolicy);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::OpenSourceServer(
|
|
BSTR serverName // in - computer name (DC) for source domain
|
|
)
|
|
{
|
|
DWORD rc;
|
|
|
|
if ( m_SrcPolicy )
|
|
{
|
|
LsaClose(m_SrcPolicy);
|
|
m_SrcPolicy = NULL;
|
|
}
|
|
rc = OpenPolicy( serverName, POLICY_LOOKUP_NAMES, &m_SrcPolicy );
|
|
m_SourceComputer = serverName;
|
|
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::OpenTargetServer(
|
|
BSTR computerName // in - computer name (DC) for target domain
|
|
)
|
|
{
|
|
DWORD rc;
|
|
|
|
if ( m_TgtPolicy )
|
|
{
|
|
LsaClose(m_TgtPolicy);
|
|
m_TgtPolicy = NULL;
|
|
}
|
|
rc = OpenPolicy( computerName,POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES ,&m_TgtPolicy);
|
|
m_TargetComputer = computerName;
|
|
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::CopyUserRights(
|
|
BSTR sourceUserName, // in - source domain account to copy rights from
|
|
BSTR targetUserName // in - target domain account to copy rights to
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD rc;
|
|
|
|
// Make sure source and target are open
|
|
if ( m_SrcPolicy && m_TgtPolicy )
|
|
{
|
|
rc = CopyUserRightsInternal(sourceUserName,targetUserName,L"",L"",m_bNoChange,m_bRemove);
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CUserRights::CopyUserRightsWithSids(
|
|
BSTR sourceUserName, // in - source domain account to copy rights from
|
|
BSTR sourceSID, // in - source account SID (in string format)
|
|
BSTR targetUserName, // in - target domain account to copy rights to
|
|
BSTR targetSID // in - target account SID (in string format)
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD rc;
|
|
|
|
// Make sure source and target are open
|
|
if ( m_SrcPolicy && m_TgtPolicy )
|
|
{
|
|
rc = CopyUserRightsInternal(sourceUserName,targetUserName,sourceSID,targetSID,m_bNoChange,m_bRemove);
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
STDMETHODIMP CUserRights::get_NoChange(BOOL *pVal) // out- value
|
|
{
|
|
(*pVal) = m_bNoChange;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUserRights::put_NoChange(BOOL newVal) // in - new value
|
|
{
|
|
m_bNoChange = newVal;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUserRights::get_RemoveOldRightsFromTargetAccounts(BOOL *pVal) // out- value
|
|
{
|
|
(*pVal) = m_bRemove;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CUserRights::put_RemoveOldRightsFromTargetAccounts(BOOL newVal) // in - new value
|
|
{
|
|
m_bRemove = newVal;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CUserRights::ExportUserRights(
|
|
BSTR server, // in - computer to read rights from
|
|
BSTR filename, // in - filename to export list of rights to
|
|
BOOL bAppendToFile // in - flag, append or overwrite file if it exists
|
|
)
|
|
{
|
|
LSA_HANDLE policy;
|
|
HRESULT hr = S_OK;
|
|
DWORD rc;
|
|
|
|
rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
|
|
if ( ! rc )
|
|
{
|
|
CommaDelimitedLog log;
|
|
|
|
if ( log.LogOpen(filename,FALSE,bAppendToFile) )
|
|
{
|
|
// Enumerate the privileges on this machine
|
|
|
|
// arguments for LsaEnumeratePrivileges
|
|
ULONG countOfRights;
|
|
DWORD prefMax = 0xffffffff;
|
|
LSA_ENUMERATION_HANDLE handle = 0;
|
|
POLICY_PRIVILEGE_DEFINITION * pRights = NULL;
|
|
|
|
do
|
|
{
|
|
rc = LsaEnumeratePrivileges(policy,&handle,(LPVOID*)&pRights,prefMax,&countOfRights);
|
|
if ( rc )
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
if ( rc == ERROR_NO_MORE_ITEMS )
|
|
rc = 0;
|
|
break;
|
|
}
|
|
// For each right, enumerate the accounts that have that right
|
|
if ( ! rc )
|
|
{
|
|
|
|
for ( UINT right = 0 ;right < countOfRights ; right++ )
|
|
{
|
|
rc = EnumerateAccountsWithRight(policy,server,&pRights[right].Name,&log);
|
|
}
|
|
LsaFreeMemory(pRights);
|
|
|
|
LSA_UNICODE_STRING lsaRight;
|
|
// For some reason, LsaEnumeratePrivileges doesn't return these rights
|
|
// They are defined in "ntsecapi.h", and not with the rest of the privileges in "winnt.h"
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_INTERACTIVE_LOGON_NAME);
|
|
rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_NETWORK_LOGON_NAME);
|
|
rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_BATCH_LOGON_NAME);
|
|
rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_SERVICE_LOGON_NAME);
|
|
rc = EnumerateAccountsWithRight(policy,server,&lsaRight,&log);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
}
|
|
}
|
|
while ( ! rc );
|
|
log.LogClose();
|
|
}
|
|
else
|
|
{
|
|
rc = GetLastError();
|
|
}
|
|
LsaClose(policy);
|
|
}
|
|
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
return hr;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CUserRights::EnumerateAccountsWithRight(
|
|
LSA_HANDLE policy, // in - handle to LSA
|
|
WCHAR * server, // in - computer name
|
|
LSA_UNICODE_STRING * pRight, // in - user right
|
|
CommaDelimitedLog * pLog // in - pointer to log object to log information to
|
|
)
|
|
{
|
|
|
|
DWORD rc = 0;
|
|
WCHAR account[LEN_Account];
|
|
WCHAR domain[LEN_Domain];
|
|
WCHAR domacct[LEN_Domain + LEN_Account];
|
|
WCHAR szRight[LEN_Account];
|
|
WCHAR szDisplayName[LEN_DisplayName];
|
|
DWORD lenAccount = DIM(account);
|
|
DWORD lenDomain = DIM(domain);
|
|
DWORD lenDisplayName = DIM(szDisplayName);
|
|
SID_NAME_USE snu;
|
|
DWORD lid;
|
|
BOOL bUseDisplayName;
|
|
|
|
// arguments for LsaEnumerateAccountsWithUserRight
|
|
ULONG countOfUsers;
|
|
LSA_ENUMERATION_INFORMATION * pInfo = NULL;
|
|
|
|
UStrCpy(szRight,pRight->Buffer,pRight->Length/(sizeof WCHAR) + 1);
|
|
bUseDisplayName = m_bUseDisplayName && LookupPrivilegeDisplayName(server,szRight,szDisplayName,&lenDisplayName,&lid);
|
|
|
|
|
|
rc = LsaEnumerateAccountsWithUserRight(policy,pRight,(PVOID*)&pInfo,&countOfUsers);
|
|
|
|
if ( ! rc )
|
|
{
|
|
for ( UINT user = 0 ; user < countOfUsers ; user++ )
|
|
{
|
|
if ( ! pInfo[user].Sid )
|
|
{
|
|
break; // something is wrong
|
|
}
|
|
domain[0] = 0;
|
|
account[0] = 0;
|
|
lenDomain = DIM(domain);
|
|
lenAccount = DIM(account);
|
|
if ( LookupAccountSid(server,pInfo[user].Sid,account,&lenAccount,domain,&lenDomain,&snu) )
|
|
{
|
|
if ( *account )
|
|
{
|
|
swprintf(domacct,L"%s\\%s",domain,account);
|
|
}
|
|
else
|
|
{
|
|
lenAccount = DIM(account);
|
|
GetTextualSid(pInfo[user].Sid,account,&lenAccount);
|
|
if ( snu == SidTypeDeletedAccount )
|
|
{
|
|
swprintf(domacct,L"%s\\<Deleted Account: %s>",domain,account);
|
|
}
|
|
else
|
|
{
|
|
swprintf(domacct,L"%s\\<%s>",domain,account);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lenAccount = DIM(account);
|
|
GetTextualSid(pInfo[user].Sid,domacct,&lenAccount);
|
|
}
|
|
if ( bUseDisplayName )
|
|
{
|
|
pLog->MsgWrite(L"%s, %s, %s",server,domacct,szDisplayName);
|
|
}
|
|
else
|
|
{
|
|
pLog->MsgWrite(L"%s, %s, %s",server,domacct,szRight);
|
|
}
|
|
}
|
|
LsaFreeMemory(pInfo);
|
|
}
|
|
else
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
if ( rc == ERROR_NO_MORE_ITEMS )
|
|
rc = 0;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
CUserRights::CopyUserRightsInternal(
|
|
WCHAR * srcAccount, // in - source account to copy rights from
|
|
WCHAR * tgtAccount, // in - account to copy rights to
|
|
WCHAR * srcSidStr, // in - sid for source account, in string format
|
|
WCHAR * tgtSidStr, // in - sid for target account, in string format
|
|
BOOL bNoChange, // in - flag, whether to write changes
|
|
BOOL bRemove // in - flag, whether to revoke rights from target if not held by source
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
PrivList srcList;
|
|
PrivList tgtList;
|
|
PSID pSidSrc = NULL;
|
|
PSID pSidTgt = NULL;
|
|
|
|
// Get a list of the privileges held by srcAccount
|
|
rc = BuildPrivilegeList(m_SrcPolicy,srcAccount,srcSidStr,m_SourceComputer,&srcList,&pSidSrc);
|
|
if ( ! rc )
|
|
{
|
|
rc = BuildPrivilegeList(m_TgtPolicy,tgtAccount,tgtSidStr,m_TargetComputer,&tgtList,&pSidTgt);
|
|
if ( ! rc )
|
|
{
|
|
if ( bRemove )
|
|
{
|
|
// Get a list of privileges held by tgtAccount
|
|
// Remove old privileges
|
|
TNodeListEnum tEnum;
|
|
PrivNode * p;
|
|
|
|
for ( p = (PrivNode *)tEnum.OpenFirst(&tgtList) ; p ; p = (PrivNode*)tEnum.Next() )
|
|
{
|
|
if ( ! srcList.Contains(p->Name()) )
|
|
{
|
|
// The source account doesn't have this privilege - remove it
|
|
if (! bNoChange )
|
|
{
|
|
rc = SetPrivilegeOnAccount(m_TgtPolicy,pSidTgt,p->Name(),FALSE);
|
|
}
|
|
if ( rc )
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
err.MsgWrite(ErrE,DCT_MSG_REMOVE_RIGHT_FAILED_SSD,p->Name(),tgtAccount,rc);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
err.MsgWrite(0,DCT_MSG_REMOVED_RIGHT_SS,p->Name(), tgtAccount);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err.MsgWrite(0,DCT_MSG_USER_HAS_RIGHT_SS,tgtAccount,p->Name());
|
|
}
|
|
}
|
|
}
|
|
// Grant privileges to new account
|
|
TNodeListEnum tEnum;
|
|
PrivNode * p;
|
|
|
|
for ( p = (PrivNode *)tEnum.OpenFirst(&srcList) ; p ; p = (PrivNode*)tEnum.Next() )
|
|
{
|
|
if ( ! tgtList.Contains(p->Name()) )
|
|
{
|
|
if ( ! bNoChange )
|
|
{
|
|
rc = SetPrivilegeOnAccount(m_TgtPolicy,pSidTgt,p->Name(),TRUE);
|
|
if ( rc )
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
err.MsgWrite(ErrE,DCT_MSG_ADD_RIGHT_FAILED_SSD,p->Name(),tgtAccount,rc);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
err.MsgWrite(0,DCT_MSG_RIGHT_GRANTED_SS,p->Name(),tgtAccount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up SIDs
|
|
if(pSidSrc != NULL)
|
|
{
|
|
FreeSid(pSidSrc);
|
|
}
|
|
|
|
if(pSidTgt != NULL)
|
|
{
|
|
FreeSid(pSidTgt);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Managing user privileges can be achieved programmatically using the
|
|
following steps:
|
|
|
|
1. Open the policy on the target machine with LsaOpenPolicy(). To grant
|
|
privileges, open the policy with POLICY_CREATE_ACCOUNT and
|
|
POLICY_LOOKUP_NAMES access. To revoke privileges, open the policy with
|
|
POLICY_LOOKUP_NAMES access.
|
|
|
|
2. Obtain a SID (security identifier) representing the user/group of
|
|
interest. The LookupAccountName() and LsaLookupNames() APIs can obtain a
|
|
SID from an account name.
|
|
|
|
3. Call LsaAddAccountRights() to grant privileges to the user(s)
|
|
represented by the supplied SID.
|
|
|
|
4. Call LsaRemoveAccountRights() to revoke privileges from the user(s)
|
|
represented by the supplied SID.
|
|
|
|
5. Close the policy with LsaClose().
|
|
|
|
To successfully grant and revoke privileges, the caller needs to be an
|
|
administrator on the target system.
|
|
|
|
The LSA API LsaEnumerateAccountRights() can be used to determine which
|
|
privileges have been granted to an account.
|
|
|
|
The LSA API LsaEnumerateAccountsWithUserRight() can be used to determine
|
|
which accounts have been granted a specified privilege.
|
|
|
|
Documentation and header files for these LSA APIs is provided in the
|
|
Windows 32 SDK in the MSTOOLS\SECURITY directory.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
|
|
#define RTN_OK 0
|
|
#define RTN_USAGE 1
|
|
#define RTN_ERROR 13
|
|
|
|
DWORD
|
|
BuildPrivilegeList(
|
|
LSA_HANDLE policy, // in - handle to LSA
|
|
PSID pSid, // in - SID for account
|
|
PrivList * privList // i/o- list of rights held by the account
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
ULONG countOfRights = 0;
|
|
PLSA_UNICODE_STRING pUserRights = NULL;
|
|
|
|
rc = LsaEnumerateAccountRights(policy,pSid,&pUserRights,&countOfRights);
|
|
rc = LsaNtStatusToWinError(rc);
|
|
if ( rc == ERROR_FILE_NOT_FOUND )
|
|
{
|
|
// This account has no privileges
|
|
rc = 0;
|
|
countOfRights = 0;
|
|
}
|
|
if ( ! rc )
|
|
{
|
|
for ( UINT i = 0 ; i < countOfRights ; i++ )
|
|
{
|
|
PrivNode * p = new PrivNode(pUserRights[i].Buffer,pUserRights[i].Length/2);
|
|
privList->InsertPrivilege(p);
|
|
}
|
|
LsaFreeMemory(pUserRights);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
DWORD
|
|
BuildPrivilegeList(
|
|
LSA_HANDLE policy, // in - handle to LSA
|
|
WCHAR * account, // in - account name to list rights for
|
|
WCHAR * strSid, // in - text format of the accounts SID, if known
|
|
WCHAR * computer, // in - computer to list rights on
|
|
PrivList * privList, // i/o- list of rights held by account
|
|
PSID * ppSid // out- SID for account
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
PSID pSid = NULL;
|
|
|
|
if ( strSid && (*strSid) )
|
|
{
|
|
// use the provided SID
|
|
pSid = SidFromString(strSid);
|
|
if ( ! pSid )
|
|
{
|
|
rc = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no SID provided, so look it up on the domain
|
|
if ( !GetAccountSid(computer,account,&pSid) )
|
|
{
|
|
rc = GetLastError();
|
|
}
|
|
}
|
|
|
|
if ( rc )
|
|
{
|
|
(*ppSid) = NULL;
|
|
if(pSid != NULL)
|
|
{
|
|
FreeSid(pSid);
|
|
pSid = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*ppSid) = pSid;
|
|
}
|
|
|
|
if ( pSid )
|
|
{
|
|
rc = BuildPrivilegeList(policy,pSid,privList);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetAccountSid(
|
|
LPTSTR SystemName, // in - computer name to lookup sid on
|
|
LPTSTR AccountName, // in - account name
|
|
PSID *Sid // out- SID for account
|
|
)
|
|
{
|
|
WCHAR ReferencedDomain[LEN_Domain];
|
|
DWORD cbSid=128; // initial allocation attempt
|
|
DWORD cbReferencedDomain=DIM(ReferencedDomain); // initial allocation size
|
|
SID_NAME_USE peUse;
|
|
BOOL bSuccess=FALSE; // assume this function will fail
|
|
PSID pTempSid = NULL;
|
|
|
|
*Sid = NULL;
|
|
|
|
__try {
|
|
|
|
//
|
|
// initial memory allocations
|
|
//
|
|
if((pTempSid=HeapAlloc(
|
|
GetProcessHeap(),
|
|
0,
|
|
cbSid
|
|
)) == NULL) __leave;
|
|
|
|
//
|
|
// Obtain the SID of the specified account on the specified system.
|
|
//
|
|
while(!LookupAccountName(
|
|
SystemName, // machine to lookup account on
|
|
AccountName, // account to lookup
|
|
pTempSid, // SID of interest
|
|
&cbSid, // size of SID
|
|
ReferencedDomain, // domain account was found on
|
|
&cbReferencedDomain,
|
|
&peUse
|
|
)) {
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
//
|
|
// reallocate memory
|
|
//
|
|
|
|
PSID psid = HeapReAlloc(GetProcessHeap(), 0, pTempSid, cbSid);
|
|
|
|
if (psid != NULL)
|
|
{
|
|
pTempSid = psid;
|
|
}
|
|
else
|
|
{
|
|
__leave;
|
|
}
|
|
}
|
|
else __leave;
|
|
}
|
|
|
|
//
|
|
// Indicate success.
|
|
//
|
|
bSuccess=TRUE;
|
|
|
|
} // finally
|
|
__finally {
|
|
|
|
//
|
|
// Cleanup and indicate failure, if appropriate.
|
|
//
|
|
|
|
if(!bSuccess) {
|
|
if(pTempSid!= NULL) {
|
|
HeapFree(GetProcessHeap(), 0, pTempSid);
|
|
pTempSid = NULL;
|
|
}
|
|
}
|
|
|
|
} // finally
|
|
|
|
// we need to copy the sid over if previous operation succeeded
|
|
if(bSuccess)
|
|
{
|
|
*Sid = SafeCopySid(pTempSid);
|
|
if(!(*Sid))
|
|
{
|
|
// safecopysid failed for some reason, we need to update the return value
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
// need to free the temporary sid
|
|
if(pTempSid)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, pTempSid);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
NTSTATUS
|
|
SetPrivilegeOnAccount(
|
|
LSA_HANDLE PolicyHandle, // open policy handle
|
|
PSID AccountSid, // SID to grant privilege to
|
|
LPWSTR PrivilegeName, // privilege to grant (Unicode)
|
|
BOOL bEnable // enable or disable
|
|
)
|
|
{
|
|
LSA_UNICODE_STRING PrivilegeString;
|
|
|
|
//
|
|
// Create a LSA_UNICODE_STRING for the privilege name.
|
|
//
|
|
InitLsaString(&PrivilegeString, PrivilegeName);
|
|
|
|
//
|
|
// grant or revoke the privilege, accordingly
|
|
//
|
|
if(bEnable) {
|
|
return LsaAddAccountRights(
|
|
PolicyHandle, // open policy handle
|
|
AccountSid, // target SID
|
|
&PrivilegeString, // privileges
|
|
1 // privilege count
|
|
);
|
|
}
|
|
else {
|
|
return LsaRemoveAccountRights(
|
|
PolicyHandle, // open policy handle
|
|
AccountSid, // target SID
|
|
FALSE, // do not disable all rights
|
|
&PrivilegeString, // privileges
|
|
1 // privilege count
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CUserRights::AddUserRight(
|
|
BSTR server, // in - computer to grant right on
|
|
BSTR strSid, // in - textual form of sid for account to grant right to
|
|
BSTR right // in - right to grant to account
|
|
)
|
|
{
|
|
LSA_HANDLE policy;
|
|
HRESULT hr = S_OK;
|
|
DWORD rc;
|
|
PSID pSid = SidFromString(strSid);
|
|
|
|
rc = OpenPolicy(server, POLICY_LOOKUP_NAMES|POLICY_CREATE_ACCOUNT, &policy);
|
|
if ( ! rc )
|
|
{
|
|
if ( ! m_bNoChange )
|
|
{
|
|
rc = SetPrivilegeOnAccount(policy,pSid,right,TRUE);
|
|
}
|
|
if ( rc )
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
LsaClose(policy);
|
|
}
|
|
FreeSid(pSid);
|
|
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::RemoveUserRight(
|
|
BSTR server, // in - computer to revoke right on
|
|
BSTR strSid, // in - textual sid of account to revoke right for
|
|
BSTR right // in - right to revoke
|
|
)
|
|
{
|
|
LSA_HANDLE policy;
|
|
HRESULT hr = S_OK;
|
|
DWORD rc;
|
|
PSID pSid = SidFromString(strSid);
|
|
|
|
rc = OpenPolicy(server, POLICY_LOOKUP_NAMES|POLICY_CREATE_ACCOUNT, &policy);
|
|
if ( ! rc )
|
|
{
|
|
if ( ! m_bNoChange )
|
|
{
|
|
rc = SetPrivilegeOnAccount(policy,pSid,right,FALSE);
|
|
}
|
|
if ( rc )
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
}
|
|
LsaClose(policy);
|
|
}
|
|
FreeSid(pSid);
|
|
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
DWORD
|
|
CUserRights::SafeArrayFromPrivList(
|
|
PrivList * privList, // in - list of user rights
|
|
SAFEARRAY ** pArray // out- safearray containing list contents
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
HRESULT hr;
|
|
TNodeListEnum e;
|
|
SAFEARRAYBOUND bound;
|
|
LONG ndx[1];
|
|
|
|
bound.lLbound = 0;
|
|
bound.cElements = privList->Count();
|
|
|
|
(*pArray) = SafeArrayCreate(VT_BSTR,1,&bound);
|
|
|
|
if ( (*pArray) )
|
|
{
|
|
PrivNode * p;
|
|
UINT i;
|
|
|
|
for ( p=(PrivNode*)e.OpenFirst(privList) , i = 0 ;
|
|
p ;
|
|
p = (PrivNode*)e.Next() , i++ )
|
|
{
|
|
ndx[0] = i;
|
|
|
|
hr = SafeArrayPutElement((*pArray),ndx,SysAllocString(p->Name()));
|
|
if ( FAILED(hr) )
|
|
{
|
|
rc = hr;
|
|
break;
|
|
}
|
|
}
|
|
e.Close();
|
|
}
|
|
else
|
|
{
|
|
rc = GetLastError();
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::GetRights(
|
|
BSTR server, // in - computer
|
|
SAFEARRAY ** pRightsArray // out- list of rights on computer
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PrivList priv;
|
|
DWORD rc = 0;
|
|
|
|
LSA_HANDLE policy = NULL;
|
|
|
|
rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
|
|
// Enumerate the privileges on this machine
|
|
|
|
// arguments for LsaEnumeratePrivileges
|
|
ULONG countOfRights;
|
|
DWORD prefMax = 0xffffffff;
|
|
LSA_ENUMERATION_HANDLE handle = 0;
|
|
POLICY_PRIVILEGE_DEFINITION * pRights = NULL;
|
|
|
|
do
|
|
{
|
|
if ( rc )
|
|
break;
|
|
rc = LsaEnumeratePrivileges(policy,&handle,(LPVOID*)&pRights,prefMax,&countOfRights);
|
|
if ( rc )
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
if ( rc == ERROR_NO_MORE_ITEMS )
|
|
rc = 0;
|
|
break;
|
|
}
|
|
if ( ! rc )
|
|
{
|
|
|
|
PrivNode * p = NULL;
|
|
|
|
for ( UINT right = 0 ;right < countOfRights ; right++ )
|
|
{
|
|
// Length is in bytes
|
|
p = new PrivNode(pRights[right].Name.Buffer,pRights[right].Name.Length/2);
|
|
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
LsaFreeMemory(pRights);
|
|
|
|
LSA_UNICODE_STRING lsaRight;
|
|
// For some reason, LsaEnumeratePrivileges doesn't return these rights
|
|
// They are defined in "ntsecapi.h", and not with the rest of the privileges in "winnt.h"
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_INTERACTIVE_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_NETWORK_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_BATCH_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_SERVICE_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
|
|
// Check the OS version on the server
|
|
WKSTA_INFO_100 * pInfo;
|
|
BOOL bIsWin2K = TRUE;
|
|
DWORD rcInfo = NetWkstaGetInfo(server,100,(LPBYTE*)&pInfo);
|
|
|
|
if ( ! rcInfo )
|
|
{
|
|
if ( pInfo->wki100_ver_major < 5 )
|
|
{
|
|
bIsWin2K = FALSE;
|
|
}
|
|
NetApiBufferFree(pInfo);
|
|
}
|
|
|
|
// The 4 "deny" rights are only defined on Windows 2000.
|
|
if ( bIsWin2K )
|
|
{
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_DENY_INTERACTIVE_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_DENY_NETWORK_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_DENY_BATCH_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
|
|
if ( ! rc )
|
|
{
|
|
InitLsaString(&lsaRight,SE_DENY_SERVICE_LOGON_NAME);
|
|
p = new PrivNode(lsaRight.Buffer,lsaRight.Length/2);
|
|
priv.InsertPrivilege(p);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
}
|
|
} while ( false);
|
|
|
|
if ( policy )
|
|
{
|
|
LsaClose(policy);
|
|
}
|
|
// Build a safearray of BSTRs from the priv-list
|
|
rc = SafeArrayFromPrivList(&priv,pRightsArray);
|
|
|
|
hr = HRESULT_FROM_WIN32(rc);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::GetUsersWithRight(
|
|
BSTR server, // in - computer name
|
|
BSTR right, // in - right to lookup
|
|
SAFEARRAY ** users // out- list of accounts that hold right
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
LSA_UNICODE_STRING Right;
|
|
WCHAR strSid[LEN_SID];
|
|
DWORD lenStrSid = DIM(strSid);
|
|
PrivList plist;
|
|
LSA_HANDLE policy = NULL;
|
|
|
|
rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
|
|
|
|
// arguments for LsaEnumerateAccountsWithUserRight
|
|
ULONG countOfUsers;
|
|
LSA_ENUMERATION_INFORMATION * pInfo = NULL;
|
|
|
|
InitLsaString(&Right,right);
|
|
|
|
rc = LsaEnumerateAccountsWithUserRight(policy,&Right,(PVOID*)&pInfo,&countOfUsers);
|
|
|
|
if ( ! rc )
|
|
{
|
|
for ( UINT user = 0 ; user < countOfUsers ; user++ )
|
|
{
|
|
if ( ! pInfo[user].Sid )
|
|
{
|
|
continue; // something is wrong
|
|
}
|
|
|
|
GetTextualSid(pInfo[user].Sid,strSid,&lenStrSid);
|
|
PrivNode * p = new PrivNode(strSid,(USHORT) UStrLen(strSid));
|
|
|
|
plist.InsertPrivilege(p);
|
|
}
|
|
LsaFreeMemory(pInfo);
|
|
}
|
|
else
|
|
{
|
|
rc = LsaNtStatusToWinError(rc);
|
|
if ( rc == ERROR_NO_MORE_ITEMS )
|
|
rc = 0;
|
|
}
|
|
if ( ! rc )
|
|
{
|
|
rc = SafeArrayFromPrivList(&plist,users);
|
|
}
|
|
if ( policy )
|
|
LsaClose(policy);
|
|
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CUserRights::GetRightsOfUser(
|
|
BSTR server, // in - computer name
|
|
BSTR strSid, // in - textual sid for account
|
|
SAFEARRAY ** rights // out- list of rights held by account on server
|
|
)
|
|
{
|
|
DWORD rc = 0;
|
|
PSID pSid = SidFromString(strSid);
|
|
LSA_HANDLE policy = NULL;
|
|
PrivList plist;
|
|
|
|
rc = OpenPolicy(server,POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,&policy);
|
|
if ( ! rc )
|
|
{
|
|
rc = BuildPrivilegeList(policy,pSid,&plist);
|
|
if ( ! rc )
|
|
{
|
|
rc = SafeArrayFromPrivList(&plist,rights);
|
|
}
|
|
LsaClose(policy);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// AddUserRights Method
|
|
//
|
|
// Synopsis
|
|
// Add user rights for specified account.
|
|
//
|
|
// Arguments
|
|
// IN bstrServer - domain controller to perform operation on
|
|
// IN bstrSid - SID of account
|
|
// IN psaRights - list of rights
|
|
//
|
|
// Return
|
|
// Standard HRESULT error status.
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CUserRights::AddUserRights(BSTR bstrServer, BSTR bstrSid, SAFEARRAY* psaRights)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
HRESULT hr;
|
|
|
|
if ((bstrServer != NULL) && (bstrSid != NULL) && (psaRights != NULL))
|
|
{
|
|
PSID pSid = SidFromString(OLE2W(bstrSid));
|
|
|
|
if (pSid != NULL)
|
|
{
|
|
hr = SetRights(OLE2W(bstrServer), pSid, psaRights, true);
|
|
|
|
FreeSid(pSid);
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// RemoveUserRights Method
|
|
//
|
|
// Synopsis
|
|
// Remove user rights for specified account.
|
|
//
|
|
// Arguments
|
|
// IN bstrServer - domain controller to perform operation on
|
|
// IN bstrSid - SID of account
|
|
// IN psaRights - list of rights
|
|
//
|
|
// Return
|
|
// Standard HRESULT error status.
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CUserRights::RemoveUserRights(BSTR bstrServer, BSTR bstrSid, SAFEARRAY* psaRights)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
HRESULT hr;
|
|
|
|
if ((bstrServer != NULL) && (bstrSid != NULL) && (psaRights != NULL))
|
|
{
|
|
PSID pSid = SidFromString(OLE2W(bstrSid));
|
|
|
|
if (pSid != NULL)
|
|
{
|
|
hr = SetRights(OLE2W(bstrServer), pSid, psaRights, false);
|
|
|
|
FreeSid(pSid);
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SetRights Method
|
|
//
|
|
// Synopsis
|
|
// Add or remove user rights for specified account.
|
|
//
|
|
// Arguments
|
|
// IN pszServer - domain controller to perform operation on
|
|
// IN pSid - SID of account
|
|
// IN psaRights - list of rights
|
|
// IN bEnable - whether to add or remove rights
|
|
//
|
|
// Return
|
|
// HRESULT error status.
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT CUserRights::SetRights(PWSTR pszServer, PSID pSid, SAFEARRAY* psaRights, bool bEnable)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Open LSA policy object on specified server with access required to add or remove rights.
|
|
//
|
|
|
|
LSA_HANDLE hPolicy = NULL;
|
|
NTSTATUS ntsStatus = OpenPolicy(pszServer, POLICY_CREATE_ACCOUNT|POLICY_LOOKUP_NAMES, &hPolicy);
|
|
|
|
if (ntsStatus == STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Generate array of unicode strings from BSTR array.
|
|
//
|
|
|
|
BSTR* pbstrRight;
|
|
hr = SafeArrayAccessData(psaRights, (void**)&pbstrRight);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULONG ulCount = psaRights->rgsabound[0].cElements;
|
|
|
|
if (ulCount > 0)
|
|
{
|
|
PLSA_UNICODE_STRING plsausRights = new LSA_UNICODE_STRING[ulCount];
|
|
|
|
if (plsausRights)
|
|
{
|
|
for (ULONG ulIndex = 0; ulIndex < ulCount; ulIndex++)
|
|
{
|
|
InitLsaString(&plsausRights[ulIndex], pbstrRight[ulIndex]);
|
|
}
|
|
|
|
//
|
|
// If not test mode, add or remove rights.
|
|
//
|
|
|
|
if (!m_bNoChange)
|
|
{
|
|
NTSTATUS ntsStatus;
|
|
|
|
if (bEnable)
|
|
{
|
|
ntsStatus = LsaAddAccountRights(hPolicy, pSid, plsausRights, ulCount);
|
|
}
|
|
else
|
|
{
|
|
ntsStatus = LsaRemoveAccountRights(hPolicy, pSid, FALSE, plsausRights, ulCount);
|
|
}
|
|
|
|
if (ntsStatus != STATUS_SUCCESS)
|
|
{
|
|
DWORD dwError = LsaNtStatusToWinError(ntsStatus);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
}
|
|
|
|
delete [] plsausRights;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
SafeArrayUnaccessData(psaRights);
|
|
}
|
|
|
|
LsaClose(hPolicy);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError = LsaNtStatusToWinError(ntsStatus);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
return hr;
|
|
}
|