1591 lines
43 KiB
C++
1591 lines
43 KiB
C++
|
/*Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved.
|
||
|
===============================================================================
|
||
|
Module - SecureObject.cpp
|
||
|
System - Domain Consolidation Toolkit.
|
||
|
Author - Christy Boles
|
||
|
Created - 97/06/27
|
||
|
Description - Classes for objects that have security descriptors.
|
||
|
|
||
|
TSecurableObject has a derived class for each type of object
|
||
|
we will process security descriptors for. This class handles reading
|
||
|
and writing the security descriptor. It contains a TSD object, which
|
||
|
will handle manipulation of the SD while it is in memory.
|
||
|
|
||
|
The TSecurableObject class also contains functions to translate a security
|
||
|
descriptor, given an account mapping cache. These routines are only included
|
||
|
in the class if the preprocessor directive SDRESOLVE is #defined. This allows
|
||
|
the TSecurableObject class to be used for generic security descriptor manipulation,
|
||
|
where the rest of the ACL translation code is not needed.
|
||
|
|
||
|
Updates -
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
#ifdef USE_STDAFX
|
||
|
# include "stdafx.h"
|
||
|
#else
|
||
|
# include <windows.h>
|
||
|
# include <process.h>
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <iostream.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
#include "common.hpp"
|
||
|
#include "ErrDct.hpp"
|
||
|
#include "Ustring.hpp"
|
||
|
#include "sd.hpp"
|
||
|
#include "SecObj.hpp"
|
||
|
|
||
|
|
||
|
#ifdef SDRESOLVE
|
||
|
#include "sidcache.hpp"
|
||
|
#include "enumvols.hpp"
|
||
|
#include "txtsid.h"
|
||
|
#endif
|
||
|
|
||
|
#define PRINT_BUFFER_SIZE 2000
|
||
|
|
||
|
extern TErrorDct err;
|
||
|
|
||
|
|
||
|
TSecurableObject::~TSecurableObject()
|
||
|
{
|
||
|
#ifdef SDRESOLVE
|
||
|
TStatNode *node;
|
||
|
for ( node = (TStatNode *)changelog.Head() ; node ; node = (TStatNode * )changelog.Head() )
|
||
|
{
|
||
|
changelog.Remove((TNode *)node);
|
||
|
delete node;
|
||
|
}
|
||
|
#endif
|
||
|
if ( handle != INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
CloseHandle(handle);
|
||
|
handle = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
|
||
|
if ( m_sd )
|
||
|
{
|
||
|
delete m_sd;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef SDRESOLVE
|
||
|
PACL // ret -pointer to Resolved ACL
|
||
|
TSecurableObject::ResolveACL(
|
||
|
PACL oldacl, // in -acl to resolve
|
||
|
TAccountCache * cache, // in -cache to lookup sids
|
||
|
TSDResolveStats * stat, // in -stats object
|
||
|
bool * changes, // i/o-flag whether this SD has been modified
|
||
|
BOOL verbose, // in -flag whether to display lots of junk
|
||
|
int opType, // in - ADD_SECURITY, REPLACE_SECURITY, or REMOVE_SECURITY
|
||
|
objectType objType, // in - the type of the object
|
||
|
BOOL bUseMapFile // in - flag - whether we are using a sID mapping file
|
||
|
)
|
||
|
{
|
||
|
int nAces,curr;
|
||
|
TRidNode * tnode;
|
||
|
PSID ps;
|
||
|
bool aclchanges = false;
|
||
|
PACL acl = oldacl;
|
||
|
void * pAce;
|
||
|
|
||
|
nAces = m_sd->ACLGetNumAces(acl);
|
||
|
|
||
|
for ( curr = 0 ; curr < nAces; )
|
||
|
{
|
||
|
pAce = m_sd->ACLGetAce(acl,curr);
|
||
|
if ( pAce )
|
||
|
{
|
||
|
TACE ace(pAce);
|
||
|
ps = ace.GetSid();
|
||
|
|
||
|
if (!bUseMapFile)
|
||
|
tnode =(TRidNode *)cache->Lookup(ps);
|
||
|
else
|
||
|
tnode =(TRidNode *)((TSDRidCache*)cache)->LookupWODomain(ps);
|
||
|
|
||
|
if ( ace.GetType() == SYSTEM_AUDIT_ACE_TYPE )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementSACEExamined();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( stat)
|
||
|
stat->IncrementDACEExamined();
|
||
|
}
|
||
|
|
||
|
if ( tnode == NULL )
|
||
|
{
|
||
|
if ( ace.GetType() == SYSTEM_AUDIT_ACE_TYPE )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementSACENotSelected(this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( stat)
|
||
|
stat->IncrementDACENotSelected(this);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// if ( (int)tnode == -1 ) // from Totally unknown
|
||
|
if ( tnode == (TRidNode*)-1 ) // from Totally unknown
|
||
|
{
|
||
|
if ( ace.GetType() == SYSTEM_AUDIT_ACE_TYPE )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementSACEUnknown(this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( stat)
|
||
|
stat->IncrementDACEUnknown(this);
|
||
|
}
|
||
|
tnode = NULL;
|
||
|
}
|
||
|
|
||
|
if ( tnode )
|
||
|
{
|
||
|
if ( ace.GetType() == SYSTEM_AUDIT_ACE_TYPE )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementSACEChange(tnode,objType,this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( stat)
|
||
|
stat->IncrementDACEChange(tnode,objType,this);
|
||
|
}
|
||
|
}
|
||
|
if ( tnode && ! tnode->IsValidOnTgt() )
|
||
|
{
|
||
|
if ( ace.GetType() == SYSTEM_AUDIT_ACE_TYPE )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementSACENoTarget(this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( stat)
|
||
|
stat->IncrementDACENoTarget(this);
|
||
|
}
|
||
|
}
|
||
|
if ( tnode && tnode->IsValidOnTgt() )
|
||
|
{
|
||
|
if ( verbose )
|
||
|
DisplaySid(ps,cache);
|
||
|
|
||
|
if (!bUseMapFile)
|
||
|
ps = cache->GetTgtSid(tnode);
|
||
|
else
|
||
|
ps = ((TSDRidCache*)cache)->GetTgtSidWODomain(tnode);
|
||
|
switch ( opType )
|
||
|
{
|
||
|
case REPLACE_SECURITY:
|
||
|
aclchanges = true;
|
||
|
ace.SetSid(ps);
|
||
|
curr++;
|
||
|
break;
|
||
|
case ADD_SECURITY:
|
||
|
{
|
||
|
TACE otherAce(ace.GetType(),ace.GetFlags(),ace.GetMask(),ps);
|
||
|
|
||
|
PACL tempAcl = acl;
|
||
|
|
||
|
// check to make sure we're not adding duplicates
|
||
|
// check the next ace, to see if it matches the one we're about to add
|
||
|
BOOL bOkToAdd = TRUE;
|
||
|
|
||
|
// Check the ace where we are
|
||
|
if ( EqualSid(otherAce.GetSid(),ace.GetSid()) )
|
||
|
{
|
||
|
bOkToAdd = FALSE;
|
||
|
}
|
||
|
|
||
|
// check the next ace, if any
|
||
|
if ( curr+1 < nAces )
|
||
|
{
|
||
|
TACE nextAce(m_sd->ACLGetAce(acl,curr+1));
|
||
|
|
||
|
if ( EqualSid(otherAce.GetSid(),nextAce.GetSid()) )
|
||
|
{
|
||
|
bOkToAdd = FALSE;
|
||
|
}
|
||
|
}
|
||
|
// check the previous ace, if any
|
||
|
if ( curr > 0 )
|
||
|
{
|
||
|
TACE prevAce(m_sd->ACLGetAce(acl,curr-1));
|
||
|
|
||
|
if ( EqualSid(prevAce.GetSid(),otherAce.GetSid()) )
|
||
|
{
|
||
|
bOkToAdd = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( bOkToAdd )
|
||
|
{
|
||
|
m_sd->ACLAddAce(&acl,&otherAce,curr);
|
||
|
if (acl)
|
||
|
aclchanges = true;
|
||
|
curr += 2;
|
||
|
nAces++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
curr++;
|
||
|
}
|
||
|
|
||
|
if ( acl != tempAcl )
|
||
|
{
|
||
|
// we had to reallocate when we added the ace
|
||
|
if ( tempAcl != oldacl )
|
||
|
{
|
||
|
// we had already reallocated once before -- free the intermediate acl
|
||
|
free(tempAcl);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case REMOVE_SECURITY:
|
||
|
aclchanges = true;
|
||
|
m_sd->ACLDeleteAce(acl,curr);
|
||
|
nAces--;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
free(ps);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
curr++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ( ! aclchanges )
|
||
|
{
|
||
|
acl = NULL;
|
||
|
}
|
||
|
if ( aclchanges )
|
||
|
{
|
||
|
(*changes) = true;
|
||
|
}
|
||
|
return acl;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool
|
||
|
TSecurableObject::ResolveSD(
|
||
|
SecurityTranslatorArgs * args, // in -translation settings
|
||
|
TSDResolveStats * stat, // in -stats object to increment counters
|
||
|
objectType objType, // in -is this file, dir or share
|
||
|
TSecurableObject * Last // in -Last SD for cache comparison
|
||
|
)
|
||
|
{
|
||
|
bool changes;
|
||
|
bool iWillBeNewLast;
|
||
|
|
||
|
if ( ! m_sd->m_absSD ) // Couldn't get SD for this object (or it doesn't have one).
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
MCSASSERT( m_sd && m_sd->IsValid() );
|
||
|
|
||
|
if ( stat )
|
||
|
stat->IncrementExamined(objType);
|
||
|
|
||
|
if ( args->LogVerbose() )
|
||
|
err.MsgWrite(0,DCT_MSG_EXAMINED_S,pathname);
|
||
|
|
||
|
if ( ! Last || m_sd != Last->m_sd )
|
||
|
{
|
||
|
changes = ResolveSDInternal(args->Cache(),stat,args->LogVerbose(),args->TranslationMode(),objType,args->UsingMapFile());
|
||
|
if ( changes )
|
||
|
{
|
||
|
if ( stat )
|
||
|
{
|
||
|
stat->IncrementChanged(objType);
|
||
|
}
|
||
|
if ( args->LogFileDetails() )
|
||
|
err.MsgWrite(0,DCT_MSG_CHANGED_S,pathname);
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"BEFORE:************Security Descriptor for %ls*************",pathname);
|
||
|
PermsPrint(pathname,objType);
|
||
|
}
|
||
|
if ( ! args->NoChange() )
|
||
|
{
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"IN MEMORY:*********************************************",pathname);
|
||
|
PrintSD(m_sd->m_absSD,pathname);
|
||
|
}
|
||
|
WriteSD();
|
||
|
}
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"AFTER:************Security Descriptor for %ls*************",pathname);
|
||
|
PermsPrint(pathname,objType);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"UNCHANGED:************Security Descriptor for %ls*************",pathname);
|
||
|
PermsPrint(pathname,objType);
|
||
|
}
|
||
|
}
|
||
|
iWillBeNewLast = true;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{ // cache hit
|
||
|
if ( stat )
|
||
|
stat->IncrementLastFileChanges(Last,objType);
|
||
|
iWillBeNewLast = false;
|
||
|
if ( Last->Changed() )
|
||
|
{
|
||
|
Last->CopyAccessData(this);
|
||
|
if ( args->LogFileDetails() )
|
||
|
err.MsgWrite(0,DCT_MSG_CHANGED_S,pathname);
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"BEFORE:************Security Descriptor for %ls*************",pathname);
|
||
|
PermsPrint(pathname,objType);
|
||
|
}
|
||
|
if ( ! args->NoChange() )
|
||
|
Last->WriteSD();
|
||
|
|
||
|
if ( args->LogFileDetails() )
|
||
|
err.MsgWrite(0,DCT_MSG_CHANGED_S,pathname);
|
||
|
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"AFTER:************Security Descriptor for %ls*************",pathname);
|
||
|
PermsPrint(pathname,objType);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( args->LogMassive() )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"UNCHANGED:************Security Descriptor for %ls*************",pathname);
|
||
|
PermsPrint(pathname,objType);
|
||
|
}
|
||
|
}
|
||
|
if ( stat )
|
||
|
stat->IncrementCacheHit(objType);
|
||
|
|
||
|
}
|
||
|
return iWillBeNewLast;
|
||
|
}
|
||
|
|
||
|
bool // ret -true if changes made, otherwise false
|
||
|
TSecurableObject::ResolveSDInternal(
|
||
|
TAccountCache * cache, // in -cache to lookup sids
|
||
|
TSDResolveStats * stat, // in -stats object
|
||
|
BOOL verbose, // in -flag - whether to display stuff
|
||
|
int opType, // in -operation type Add, Replace, or Remove
|
||
|
objectType objType, // in - type of object
|
||
|
BOOL bUseMapFile // in - flag - whether we are using a sID mapping file
|
||
|
)
|
||
|
{
|
||
|
/* Examine each part of the SD, looking for SIDs in the cache */
|
||
|
PSID ps;
|
||
|
TRidNode * acct;
|
||
|
bool changes = false;
|
||
|
PACL pacl;
|
||
|
PACL newacl;
|
||
|
PSID newsid;
|
||
|
|
||
|
MCSVERIFY(m_sd);
|
||
|
|
||
|
// Process owner part of SD
|
||
|
ps = m_sd->GetOwner();
|
||
|
if ( ps )
|
||
|
{
|
||
|
if (!bUseMapFile)
|
||
|
acct = (TRidNode *)cache->Lookup(ps); // See if owner SID is in the cache
|
||
|
else
|
||
|
acct = (TRidNode *)((TSDRidCache*)cache)->LookupWODomain(ps); // See if owner SID is in the cache
|
||
|
if ( stat)
|
||
|
stat->IncrementOwnerExamined();
|
||
|
if (acct == NULL )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementOwnerNotSelected();
|
||
|
}
|
||
|
// else if ((int)acct == -1 )
|
||
|
else if (acct == (TRidNode*)-1 )
|
||
|
{
|
||
|
if (stat)
|
||
|
stat->IncrementOwnerUnknown();
|
||
|
unkown = true;
|
||
|
acct = NULL;
|
||
|
}
|
||
|
if ( acct && stat )
|
||
|
{
|
||
|
stat->IncrementOwnerChange(acct,objType,this);
|
||
|
}
|
||
|
if ( acct && acct->IsValidOnTgt() )
|
||
|
{
|
||
|
changes = true;
|
||
|
if ( verbose )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"Owner: ");
|
||
|
DisplaySid(ps,cache);
|
||
|
}
|
||
|
owner_changed = true;
|
||
|
if (!bUseMapFile)
|
||
|
newsid = cache->GetTgtSid(acct);
|
||
|
else
|
||
|
newsid = ((TSDRidCache*)cache)->GetTgtSidWODomain(acct);
|
||
|
m_sd->SetOwner(newsid);
|
||
|
//free(newsid);
|
||
|
}
|
||
|
}
|
||
|
// Process primary group part of SD
|
||
|
ps = m_sd->GetGroup();
|
||
|
if ( ps )
|
||
|
{
|
||
|
if (!bUseMapFile)
|
||
|
acct = (TRidNode *)cache->Lookup(ps);
|
||
|
else
|
||
|
acct = (TRidNode *)((TSDRidCache*)cache)->LookupWODomain(ps);
|
||
|
if ( stat)
|
||
|
stat->IncrementGroupExamined();
|
||
|
if (acct == NULL )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementGroupNotSelected();
|
||
|
}
|
||
|
// else if ((int)acct == -1 )
|
||
|
else if (acct == (TRidNode*)-1 )
|
||
|
{
|
||
|
if (stat)
|
||
|
stat->IncrementGroupUnknown();
|
||
|
acct = NULL;
|
||
|
unkgrp = true;
|
||
|
}
|
||
|
if ( acct && stat )
|
||
|
{
|
||
|
stat->IncrementGroupChange(acct,objType,this);
|
||
|
}
|
||
|
if ( acct && acct->IsValidOnTgt() )
|
||
|
{
|
||
|
changes = true;
|
||
|
if ( verbose )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"Group: ");
|
||
|
DisplaySid(ps,cache);
|
||
|
}
|
||
|
group_changed = true;
|
||
|
if (!bUseMapFile)
|
||
|
newsid = cache->GetTgtSid(acct);
|
||
|
else
|
||
|
newsid = ((TSDRidCache*)cache)->GetTgtSidWODomain(acct);
|
||
|
m_sd->SetGroup(newsid);
|
||
|
//free(newsid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pacl = m_sd->GetDacl();
|
||
|
if ( pacl && m_sd->IsDaclPresent() )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementDACLExamined();
|
||
|
if ( verbose )
|
||
|
err.DbgMsgWrite(0,L"DACL");
|
||
|
if (!bUseMapFile)
|
||
|
newacl = ResolveACL(pacl,cache,stat,&changes,verbose,opType,objType, FALSE);
|
||
|
else
|
||
|
newacl = ResolveACL(pacl,cache,stat,&changes,verbose,opType,objType, TRUE);
|
||
|
if ( newacl )
|
||
|
{
|
||
|
m_sd->SetDacl(newacl,m_sd->IsDaclPresent());
|
||
|
dacl_changed = true;
|
||
|
if ( stat )
|
||
|
stat->IncrementDACLChanged();
|
||
|
}
|
||
|
}
|
||
|
pacl = NULL;
|
||
|
pacl = m_sd->GetSacl();
|
||
|
|
||
|
if ( pacl && m_sd->IsSaclPresent() )
|
||
|
{
|
||
|
if ( stat )
|
||
|
stat->IncrementSACLExamined();
|
||
|
if ( verbose )
|
||
|
err.DbgMsgWrite(0,L"SACL");
|
||
|
if (!bUseMapFile)
|
||
|
newacl = ResolveACL(pacl,cache,stat,&changes,verbose,opType,objType, FALSE);
|
||
|
else
|
||
|
newacl = ResolveACL(pacl,cache,stat,&changes,verbose,opType,objType, TRUE);
|
||
|
if ( newacl )
|
||
|
{
|
||
|
m_sd->SetSacl(newacl,m_sd->IsSaclPresent());
|
||
|
sacl_changed = true;
|
||
|
if ( stat )
|
||
|
stat->IncrementSACLChanged();
|
||
|
}
|
||
|
}
|
||
|
return changes;
|
||
|
}
|
||
|
#else
|
||
|
|
||
|
WCHAR * // ret -machine-name prefix of pathname if pathname is a UNC path, otherwise returns NULL
|
||
|
GetMachineName(
|
||
|
const LPWSTR pathname // in -pathname from which to extract machine name
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
WCHAR * machinename = NULL;
|
||
|
if ( pathname
|
||
|
&& pathname[0] == L'\\'
|
||
|
&& pathname[1] == L'\\'
|
||
|
)
|
||
|
{
|
||
|
for ( i = 2 ; pathname[i] && pathname[i] != L'\\' ; i++ )
|
||
|
;
|
||
|
machinename = new WCHAR[i+2];
|
||
|
if (machinename)
|
||
|
{
|
||
|
UStrCpy(machinename,pathname,i+1);
|
||
|
machinename[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
return machinename;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void
|
||
|
TSecurableObject::CopyAccessData(
|
||
|
TSecurableObject * sourceFSD // in - sd from which to copy name & handle
|
||
|
)
|
||
|
{
|
||
|
|
||
|
pathname[0] = 0;
|
||
|
safecopy(pathname,sourceFSD->GetPathName());
|
||
|
if ( handle != INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
CloseHandle(handle);
|
||
|
}
|
||
|
handle = sourceFSD->handle;
|
||
|
sourceFSD->ResetHandle();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/************************************************TFileSD Implementation*************************/
|
||
|
TFileSD::TFileSD(
|
||
|
const LPWSTR path // in -pathname for this SD
|
||
|
)
|
||
|
{
|
||
|
daceNS = 0;
|
||
|
saceNS = 0;
|
||
|
daceEx = 0;
|
||
|
saceEx = 0;
|
||
|
daceU = 0;
|
||
|
saceU = 0;
|
||
|
daceNT = 0;
|
||
|
saceNT = 0;
|
||
|
unkown = false;
|
||
|
unkgrp = false;
|
||
|
|
||
|
if ( path )
|
||
|
{
|
||
|
safecopy(pathname,path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
path[0] = 0;
|
||
|
}
|
||
|
handle = INVALID_HANDLE_VALUE;
|
||
|
ReadSD(path);
|
||
|
}
|
||
|
|
||
|
|
||
|
TFileSD::~TFileSD()
|
||
|
{
|
||
|
if ( handle != INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
CloseHandle(handle);
|
||
|
handle = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
pathname[0]=0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// writes the Absolute SD to the file "pathname"
|
||
|
bool // ret -true iff successful
|
||
|
TFileSD::WriteSD()
|
||
|
{
|
||
|
// DWORD rc = 0;
|
||
|
bool error = false;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
MCSVERIFY( m_sd && m_sd->IsValid() );
|
||
|
|
||
|
if ( handle == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
err.MsgWrite(ErrS,DCT_MSG_FST_WRITESD_INVALID);
|
||
|
error = true;
|
||
|
}
|
||
|
SECURITY_INFORMATION si;
|
||
|
if ( ! error )
|
||
|
{
|
||
|
si = 0;
|
||
|
if ( m_sd->IsOwnerChanged() )
|
||
|
si |= OWNER_SECURITY_INFORMATION;
|
||
|
if ( m_sd->IsGroupChanged() )
|
||
|
si |= GROUP_SECURITY_INFORMATION;
|
||
|
if ( m_sd->IsDACLChanged() )
|
||
|
si |= DACL_SECURITY_INFORMATION;
|
||
|
if ( m_sd->IsSACLChanged() )
|
||
|
si |= SACL_SECURITY_INFORMATION;
|
||
|
|
||
|
sd = m_sd->MakeAbsSD();
|
||
|
if (!sd)
|
||
|
return false;
|
||
|
if ( ! SetKernelObjectSecurity(handle, si, sd ) )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_FILE_WRITESD_FAILED_SD,pathname,GetLastError());
|
||
|
error = true;
|
||
|
}
|
||
|
m_sd->FreeAbsSD(sd);
|
||
|
}
|
||
|
return ! error;
|
||
|
}
|
||
|
|
||
|
bool // ret -pointer to SD, (or NULL if failure)
|
||
|
TFileSD::ReadSD(
|
||
|
const LPWSTR path // in -file to get SD from
|
||
|
)
|
||
|
{
|
||
|
DWORD req;
|
||
|
DWORD rc;
|
||
|
// void * r = NULL;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
bool error = false;
|
||
|
WCHAR * longpath= NULL;
|
||
|
|
||
|
if ( handle != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(handle);
|
||
|
handle = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
owner_changed = 0;
|
||
|
group_changed = 0;
|
||
|
dacl_changed = 0;
|
||
|
sacl_changed = 0;
|
||
|
|
||
|
|
||
|
if ( UStrLen(path) >= MAX_PATH && path[2] != L'?' )
|
||
|
{
|
||
|
longpath = new WCHAR[UStrLen(path) + 10];
|
||
|
if (!longpath)
|
||
|
return true;
|
||
|
UStrCpy(longpath,L"\\\\?\\");
|
||
|
UStrCpy(longpath + UStrLen(longpath),path);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
longpath = path;
|
||
|
}
|
||
|
handle = CreateFileW(longpath,
|
||
|
READ_CONTROL | ACCESS_SYSTEM_SECURITY | WRITE_OWNER |WRITE_DAC ,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_BACKUP_SEMANTICS,
|
||
|
0);
|
||
|
if ( handle == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
if ( rc == ERROR_SHARING_VIOLATION )
|
||
|
{
|
||
|
err.MsgWrite(ErrW, DCT_MSG_FST_FILE_IN_USE_S,path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE, rc, DCT_MSG_FST_FILE_OPEN_FAILED_SD,longpath,rc);
|
||
|
}
|
||
|
error = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sd = (SECURITY_DESCRIPTOR *)malloc(SD_DEFAULT_SIZE);
|
||
|
if (!sd)
|
||
|
{
|
||
|
if ( longpath != path )
|
||
|
delete [] longpath;
|
||
|
return true;
|
||
|
}
|
||
|
req = 0;
|
||
|
if ( ! GetKernelObjectSecurity(handle, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
|
||
|
| DACL_SECURITY_INFORMATION
|
||
|
| SACL_SECURITY_INFORMATION
|
||
|
,
|
||
|
sd,
|
||
|
SD_DEFAULT_SIZE,
|
||
|
&req) )
|
||
|
{
|
||
|
if ( req <= SD_DEFAULT_SIZE )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE, GetLastError(), DCT_MSG_FST_GET_FILE_SECURITY_FAILED_SD,
|
||
|
longpath, GetLastError());
|
||
|
error = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
free(sd);
|
||
|
sd = (SECURITY_DESCRIPTOR *)malloc(req);
|
||
|
if (!sd)
|
||
|
{
|
||
|
if ( longpath != path )
|
||
|
delete [] longpath;
|
||
|
return true;
|
||
|
}
|
||
|
if ( ! GetKernelObjectSecurity(handle,OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
|
||
|
| DACL_SECURITY_INFORMATION
|
||
|
| SACL_SECURITY_INFORMATION
|
||
|
,
|
||
|
sd,
|
||
|
req,
|
||
|
&req) )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE, GetLastError(), DCT_MSG_FST_GET_FILE_SECURITY_FAILED_SD,
|
||
|
longpath, GetLastError());
|
||
|
error = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( error && sd ) // free the space allocated
|
||
|
{
|
||
|
free(sd);
|
||
|
sd = NULL;
|
||
|
}
|
||
|
if ( sd )
|
||
|
{
|
||
|
m_sd = new TSD(sd,McsFileSD,TRUE);
|
||
|
if (!m_sd)
|
||
|
error = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_sd = NULL;
|
||
|
}
|
||
|
if (! error )
|
||
|
{
|
||
|
safecopy(pathname,longpath);
|
||
|
}
|
||
|
if ( longpath != path )
|
||
|
delete [] longpath;
|
||
|
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
//////////////////////////TShareSD implementation///////////////////////////////////////////////////////////
|
||
|
TShareSD::TShareSD(
|
||
|
const LPWSTR path // in -pathname for this SD
|
||
|
)
|
||
|
{
|
||
|
daceNS = 0;
|
||
|
saceNS = 0;
|
||
|
daceEx = 0;
|
||
|
saceEx = 0;
|
||
|
daceU = 0;
|
||
|
saceU = 0;
|
||
|
daceNT = 0;
|
||
|
saceNT = 0;
|
||
|
unkown = false;
|
||
|
unkgrp = false;
|
||
|
shareInfo = NULL;
|
||
|
|
||
|
if ( path )
|
||
|
{
|
||
|
safecopy(pathname,path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
path[0] = 0;
|
||
|
}
|
||
|
handle = INVALID_HANDLE_VALUE;
|
||
|
ReadSD(path);
|
||
|
}
|
||
|
|
||
|
bool // ret-error=true
|
||
|
TShareSD::ReadSD(
|
||
|
const LPWSTR path // in -sharename
|
||
|
)
|
||
|
{
|
||
|
DWORD rc;
|
||
|
// void * r = NULL;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
bool error = false;
|
||
|
DWORD lenServerName = 0;
|
||
|
|
||
|
if ( m_sd )
|
||
|
{
|
||
|
delete m_sd;
|
||
|
}
|
||
|
|
||
|
owner_changed = 0;
|
||
|
group_changed = 0;
|
||
|
dacl_changed = 0;
|
||
|
sacl_changed = 0;
|
||
|
|
||
|
serverName = GetMachineName(path);
|
||
|
|
||
|
if ( serverName )
|
||
|
lenServerName = UStrLen(serverName) + 1;
|
||
|
|
||
|
safecopy(pathname,path + lenServerName);
|
||
|
|
||
|
|
||
|
rc = NetShareGetInfo(serverName, pathname, 502, (LPBYTE *)&shareInfo);
|
||
|
if ( rc )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE, rc, DCT_MSG_FST_GET_SHARE_SECURITY_FAILED_SD,
|
||
|
path, rc);
|
||
|
error = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sd = (SECURITY_DESCRIPTOR *)shareInfo->shi502_security_descriptor;
|
||
|
if ( sd )
|
||
|
{
|
||
|
m_sd = new TSD(sd,McsShareSD,FALSE);
|
||
|
if (!m_sd)
|
||
|
error = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_sd = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool // ret-error=true
|
||
|
TShareSD::WriteSD()
|
||
|
{
|
||
|
bool error = false;
|
||
|
DWORD rc = 0;
|
||
|
DWORD parmErr = 0;
|
||
|
SECURITY_DESCRIPTOR * pSD = NULL;
|
||
|
|
||
|
// Build an absolute SD
|
||
|
if ( m_sd )
|
||
|
{
|
||
|
pSD = m_sd->MakeAbsSD();
|
||
|
if (!pSD)
|
||
|
return false;
|
||
|
shareInfo->shi502_security_descriptor = pSD;
|
||
|
|
||
|
rc = NetShareSetInfo(serverName,pathname,502,(BYTE *)shareInfo,&parmErr);
|
||
|
if ( rc )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE,rc,DCT_MSG_FST_SHARE_WRITESD_FAILED_SD,pathname,rc);
|
||
|
}
|
||
|
free(pSD);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MCSASSERT(FALSE); // SD does not exist
|
||
|
}
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
|
||
|
TRegSD::TRegSD(
|
||
|
const LPWSTR path, // in -pathname for this SD
|
||
|
HKEY hKey // in -handle for the registry key
|
||
|
)
|
||
|
{
|
||
|
daceNS = 0;
|
||
|
saceNS = 0;
|
||
|
daceEx = 0;
|
||
|
saceEx = 0;
|
||
|
daceU = 0;
|
||
|
saceU = 0;
|
||
|
daceNT = 0;
|
||
|
saceNT = 0;
|
||
|
unkown = false;
|
||
|
unkgrp = false;
|
||
|
|
||
|
if ( path )
|
||
|
{
|
||
|
safecopy(pathname,path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
path[0] = 0;
|
||
|
}
|
||
|
m_hKey = hKey;
|
||
|
ReadSD(m_hKey);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
TRegSD::ReadSD(HKEY hKey)
|
||
|
{
|
||
|
DWORD rc = 0;
|
||
|
DWORD lenBuffer = SD_DEFAULT_SIZE;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
|
||
|
m_hKey = hKey;
|
||
|
|
||
|
sd = (SECURITY_DESCRIPTOR *)malloc(SD_DEFAULT_SIZE);
|
||
|
if (!sd)
|
||
|
return false;
|
||
|
|
||
|
rc = RegGetKeySecurity(hKey,OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
|
||
|
| DACL_SECURITY_INFORMATION
|
||
|
| SACL_SECURITY_INFORMATION,
|
||
|
sd,&lenBuffer);
|
||
|
|
||
|
if ( rc == ERROR_INSUFFICIENT_BUFFER )
|
||
|
{
|
||
|
free(sd);
|
||
|
|
||
|
sd = (SECURITY_DESCRIPTOR *)malloc(lenBuffer);
|
||
|
if (!sd)
|
||
|
return false;
|
||
|
rc = RegGetKeySecurity(hKey,OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
|
||
|
| DACL_SECURITY_INFORMATION
|
||
|
| SACL_SECURITY_INFORMATION,
|
||
|
sd,&lenBuffer);
|
||
|
}
|
||
|
|
||
|
if ( rc )
|
||
|
{
|
||
|
free(sd);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_sd = new TSD(sd,McsRegistrySD,TRUE);
|
||
|
if (!m_sd)
|
||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
return ( rc == 0 );
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
TRegSD::WriteSD()
|
||
|
{
|
||
|
DWORD rc = 0;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
|
||
|
MCSVERIFY( m_sd && m_sd->IsValid() );
|
||
|
|
||
|
SECURITY_INFORMATION si;
|
||
|
|
||
|
si = 0;
|
||
|
if ( m_sd->IsOwnerChanged() )
|
||
|
si |= OWNER_SECURITY_INFORMATION;
|
||
|
if ( m_sd->IsGroupChanged() )
|
||
|
si |= GROUP_SECURITY_INFORMATION;
|
||
|
if ( m_sd->IsDACLChanged() )
|
||
|
si |= DACL_SECURITY_INFORMATION;
|
||
|
if ( m_sd->IsSACLChanged() )
|
||
|
si |= SACL_SECURITY_INFORMATION;
|
||
|
|
||
|
sd = m_sd->MakeAbsSD();
|
||
|
if (!sd)
|
||
|
return false;
|
||
|
|
||
|
rc = RegSetKeySecurity(m_hKey,si,sd);
|
||
|
|
||
|
if ( rc )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE,rc,DCT_MSG_REG_SD_WRITE_FAILED_SD,name,rc);
|
||
|
}
|
||
|
m_sd->FreeAbsSD(sd);
|
||
|
|
||
|
return ( rc == 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//////////////////////////TPrintSD implementation///////////////////////////////////////////////////////////
|
||
|
TPrintSD::TPrintSD(
|
||
|
const LPWSTR path // in -pathname for this SD
|
||
|
)
|
||
|
{
|
||
|
daceNS = 0;
|
||
|
saceNS = 0;
|
||
|
daceEx = 0;
|
||
|
saceEx = 0;
|
||
|
daceU = 0;
|
||
|
saceU = 0;
|
||
|
daceNT = 0;
|
||
|
saceNT = 0;
|
||
|
unkown = false;
|
||
|
unkgrp = false;
|
||
|
buffer = NULL;
|
||
|
|
||
|
if ( path )
|
||
|
{
|
||
|
safecopy(pathname,path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
path[0] = 0;
|
||
|
}
|
||
|
handle = INVALID_HANDLE_VALUE;
|
||
|
ReadSD(path);
|
||
|
}
|
||
|
|
||
|
bool // ret-error=true
|
||
|
TPrintSD::ReadSD(
|
||
|
const LPWSTR path // in -sharename
|
||
|
)
|
||
|
{
|
||
|
DWORD rc = 0;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
|
||
|
if ( m_sd )
|
||
|
{
|
||
|
delete m_sd;
|
||
|
}
|
||
|
|
||
|
owner_changed = 0;
|
||
|
group_changed = 0;
|
||
|
dacl_changed = 0;
|
||
|
sacl_changed = 0;
|
||
|
|
||
|
PRINTER_DEFAULTS defaults;
|
||
|
DWORD needed = 0;
|
||
|
PRINTER_INFO_3 * pInfo;
|
||
|
|
||
|
defaults.DesiredAccess = READ_CONTROL | PRINTER_ACCESS_ADMINISTER | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY;
|
||
|
defaults.pDatatype = NULL;
|
||
|
defaults.pDevMode = NULL;
|
||
|
|
||
|
buffer = new BYTE[PRINT_BUFFER_SIZE];
|
||
|
if (!buffer)
|
||
|
return false;
|
||
|
|
||
|
// Get the security descriptor for the printer
|
||
|
if ( ! OpenPrinter(path,&hPrinter,&defaults) )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
err.SysMsgWrite(ErrE,rc,DCT_MSG_OPEN_PRINTER_FAILED_SD,path,rc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( ! GetPrinter(hPrinter,3,buffer,PRINT_BUFFER_SIZE,&needed) )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
if ( rc == ERROR_INSUFFICIENT_BUFFER )
|
||
|
{
|
||
|
delete [] buffer;
|
||
|
buffer = new BYTE[needed];
|
||
|
if (!buffer)
|
||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
else if (! GetPrinter(hPrinter,3,buffer, needed, &needed ) )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( rc )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE,rc,DCT_MSG_GET_PRINTER_FAILED_SD,path,rc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pInfo = (PRINTER_INFO_3*)buffer;
|
||
|
|
||
|
sd = (SECURITY_DESCRIPTOR *)pInfo->pSecurityDescriptor;
|
||
|
|
||
|
if ( sd )
|
||
|
{
|
||
|
m_sd = new TSD(sd,McsPrinterSD,FALSE);
|
||
|
if (!m_sd)
|
||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_sd = NULL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
return (rc == 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool // ret-error=true
|
||
|
TPrintSD::WriteSD()
|
||
|
{
|
||
|
// bool error = false;
|
||
|
DWORD rc = 0;
|
||
|
SECURITY_DESCRIPTOR * pSD = NULL;
|
||
|
PRINTER_INFO_3 pInfo;
|
||
|
|
||
|
// Build an absolute SD
|
||
|
MCSVERIFY(hPrinter != INVALID_HANDLE_VALUE);
|
||
|
if ( m_sd )
|
||
|
{
|
||
|
pSD = m_sd->MakeAbsSD();
|
||
|
if (!pSD)
|
||
|
return false;
|
||
|
pInfo.pSecurityDescriptor = pSD;
|
||
|
|
||
|
SetLastError(0);
|
||
|
// Clear the primary group from the security descriptor, since in NT 4, setting a security descriptor
|
||
|
// with a non-NULL primary group sometimes doesn't work
|
||
|
SetSecurityDescriptorGroup(pSD,NULL,FALSE);
|
||
|
|
||
|
if (! SetPrinter(hPrinter,3,(LPBYTE)&pInfo,0) )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
}
|
||
|
if ( rc )
|
||
|
{
|
||
|
err.SysMsgWrite(ErrE,rc,DCT_MSG_PRINTER_WRITESD_FAILED_SD,pathname,rc);
|
||
|
}
|
||
|
free(pSD);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MCSASSERT(FALSE); // SD does not exist
|
||
|
}
|
||
|
return (rc == 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef SDRESOLVE
|
||
|
/////////////////////////////////////////////////Utility routines to print security descriptors for debug logging
|
||
|
//#pragma title("PrintSD- Formats/prints security info")
|
||
|
// Author - Tom Bernhardt
|
||
|
// Created- 09/11/93
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <windows.h>
|
||
|
#include <malloc.h>
|
||
|
#include <winbase.h>
|
||
|
#include <lm.h>
|
||
|
|
||
|
|
||
|
|
||
|
#include "common.hpp"
|
||
|
#include "err.hpp"
|
||
|
#include "Ustring.hpp"
|
||
|
|
||
|
#define SDBUFFSIZE (sizeof (SECURITY_DESCRIPTOR) + 10000)
|
||
|
static const char sidType[][16]= {"--0--" , "User" ,
|
||
|
"Group" , "Domain" ,
|
||
|
"Alias" , "WellKnownGroup",
|
||
|
"Deleted", "Invalid" ,
|
||
|
"Unknown"};
|
||
|
|
||
|
|
||
|
class SidTree
|
||
|
{
|
||
|
public:
|
||
|
SidTree * left;
|
||
|
SidTree * right;
|
||
|
SID_NAME_USE sidUse;
|
||
|
USHORT lenSid;
|
||
|
char buffer[1]; // contains sid, account name and domain
|
||
|
|
||
|
SidTree() {};
|
||
|
SidTree * // ret-found/created node
|
||
|
Find(
|
||
|
SidTree ** sidTree ,// i/o-head of extension tree
|
||
|
PSID const pSid // in -file extension
|
||
|
);
|
||
|
};
|
||
|
|
||
|
static char *
|
||
|
AclType(
|
||
|
BOOL isPresent ,// in -1 if present
|
||
|
BOOL isDefault // in -1 if default ACL
|
||
|
)
|
||
|
{
|
||
|
if ( !isPresent )
|
||
|
return "none";
|
||
|
if ( isDefault )
|
||
|
return "default";
|
||
|
return "present";
|
||
|
}
|
||
|
|
||
|
|
||
|
//#pragma page()
|
||
|
// For each "on" bit in the bitmap, appends the corresponding char in
|
||
|
// mapStr to retStr, thus forming a recognizable form of the bit string.
|
||
|
static
|
||
|
int _stdcall // ret-legngth of string written
|
||
|
BitMapStr(
|
||
|
DWORD bitmap ,// in -bits to map
|
||
|
char const * mapStr ,// in -map character array string
|
||
|
char * retStr // out-return selected map char string
|
||
|
)
|
||
|
{
|
||
|
char const * m;
|
||
|
char * r = retStr;
|
||
|
|
||
|
for ( m = mapStr; *m; m++, bitmap >>= 1 )
|
||
|
if ( bitmap & 1 ) // if current permission on
|
||
|
*r++ = *m; // set output string to corresponding char
|
||
|
*r = '\0';
|
||
|
|
||
|
return (int)(r - retStr);
|
||
|
}
|
||
|
|
||
|
//#pragma page()
|
||
|
// converts an ACE access mask to a semi-undertandable string
|
||
|
static
|
||
|
char * _stdcall
|
||
|
PermStr(
|
||
|
DWORD access ,// in -access mask
|
||
|
char * retStr // out-return permissions string
|
||
|
)
|
||
|
{
|
||
|
// static char const fileSpecific[] = "R W WaErEwX . ArAw";
|
||
|
// static char const dirSpecific[] = "L C M ErEwT D ArAw";
|
||
|
static char const specific[] = "RWbeEXDaA.......",
|
||
|
standard[] = "DpPOs...",
|
||
|
generic[] = "SM..AXWR";
|
||
|
char * o = retStr;
|
||
|
|
||
|
if ( (access & FILE_ALL_ACCESS) == FILE_ALL_ACCESS )
|
||
|
*o++ = '*';
|
||
|
else
|
||
|
o += BitMapStr(access, specific, o);
|
||
|
|
||
|
access >>= 16;
|
||
|
*o++ = '-';
|
||
|
if ( (access & (STANDARD_RIGHTS_ALL >> 16)) == (STANDARD_RIGHTS_ALL >> 16) )
|
||
|
*o++ = '*';
|
||
|
else
|
||
|
o += BitMapStr(access, standard, o);
|
||
|
|
||
|
access >>= 8;
|
||
|
if ( access )
|
||
|
{
|
||
|
*o++ = '-';
|
||
|
o += BitMapStr(access, generic, o);
|
||
|
}
|
||
|
*o = '\0'; // null terminate string
|
||
|
|
||
|
return retStr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//#pragma page()
|
||
|
// Binary tree insertion/searching of Sids that obviates the constant
|
||
|
// use of LookupAccount and speeds execution by 100x!!!!!
|
||
|
SidTree * // ret-found/created node
|
||
|
SidTree::Find(
|
||
|
SidTree ** sidTree ,// i/o-head of extension tree
|
||
|
PSID const pSid // in -file extension
|
||
|
)
|
||
|
{
|
||
|
SidTree * curr,
|
||
|
** prevNext = sidTree; // &forward-chain
|
||
|
int cmp; // compare result
|
||
|
DWORD lenSid;
|
||
|
WCHAR name[60],
|
||
|
domain[60];
|
||
|
DWORD lenName,
|
||
|
lenDomain,
|
||
|
rc;
|
||
|
SID_NAME_USE sidUse;
|
||
|
static int nUnknown = 0;
|
||
|
|
||
|
for ( curr = *prevNext; curr; curr = *prevNext )
|
||
|
{
|
||
|
if ( (cmp = memcmp(pSid, curr->buffer, curr->lenSid)) < 0 )
|
||
|
prevNext = &curr->left; // go down left side
|
||
|
else if ( cmp > 0 )
|
||
|
prevNext = &curr->right; // go down right side
|
||
|
else
|
||
|
return curr; // found it and return address
|
||
|
}
|
||
|
|
||
|
// not found in tree -- create it
|
||
|
lenName = DIM(name);
|
||
|
lenDomain = DIM(domain);
|
||
|
if ( !LookupAccountSid(NULL, pSid, name, &lenName,
|
||
|
domain, &lenDomain, &sidUse) )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
if ( rc != ERROR_NONE_MAPPED )
|
||
|
err.DbgMsgWrite(0, L"LookupAccountSid()=%ld", rc);
|
||
|
lenName = swprintf(name, L"**Unknown%d**", ++nUnknown);
|
||
|
UStrCpy(domain, "-unknown-");
|
||
|
lenDomain = 9;
|
||
|
sidUse = (_SID_NAME_USE)0;
|
||
|
}
|
||
|
|
||
|
lenSid = GetLengthSid(pSid);
|
||
|
*prevNext = (SidTree *)malloc(sizeof **prevNext + lenSid + lenName + lenDomain + 1);
|
||
|
if (!(*prevNext))
|
||
|
return NULL;
|
||
|
memset(*prevNext, '\0', sizeof **prevNext);
|
||
|
memcpy((*prevNext)->buffer, pSid, lenSid);
|
||
|
(*prevNext)->lenSid = (USHORT)lenSid;
|
||
|
(*prevNext)->sidUse = sidUse;
|
||
|
UStrCpy((*prevNext)->buffer + lenSid, name, lenName + 1);
|
||
|
UStrCpy((*prevNext)->buffer + lenSid + lenName + 1, domain, lenDomain + 1);
|
||
|
return *prevNext;
|
||
|
}
|
||
|
|
||
|
|
||
|
//#pragma page()
|
||
|
SidTree gSidTree;
|
||
|
SidTree * sidHead = &gSidTree;
|
||
|
SECURITY_DESCRIPTOR * sd = NULL;
|
||
|
|
||
|
|
||
|
// Formats and prints (to stdout) the contents of the argment ACL
|
||
|
static
|
||
|
void _stdcall
|
||
|
PrintACL(
|
||
|
const PACL acl ,// in -ACL (SACL or DACL)
|
||
|
WCHAR const * resource // in -resource name
|
||
|
)
|
||
|
{
|
||
|
ACCESS_ALLOWED_ACE * ace;
|
||
|
DWORD nAce;
|
||
|
static char const typeStr[] = "+-A*";
|
||
|
SidTree * sidTree;
|
||
|
char permStr[33],
|
||
|
inherStr[5];
|
||
|
WCHAR txtSid[200];
|
||
|
char sTxtSid[200];
|
||
|
DWORD txtSidLen = DIM(txtSid);
|
||
|
err.DbgMsgWrite(0,L" T Fl Acc Mask Permissions Account name "
|
||
|
L"Domain Acct Type");
|
||
|
|
||
|
for ( nAce = 0; nAce < acl->AceCount; nAce++ )
|
||
|
{
|
||
|
if ( !GetAce(acl, nAce, (LPVOID *)&ace) )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"GetAclInformation()=%ld ", GetLastError());
|
||
|
return;
|
||
|
}
|
||
|
sidTree = sidHead->Find(&sidHead, &ace->SidStart);
|
||
|
BitMapStr(ace->Header.AceFlags, "FDNI", inherStr);
|
||
|
txtSid[0] = 0;
|
||
|
txtSidLen = DIM(txtSid);
|
||
|
GetTextualSid(&ace->SidStart,txtSid,&txtSidLen);
|
||
|
safecopy(sTxtSid,txtSid);
|
||
|
err.DbgMsgWrite(0,L" %c%-3S %08x %-16S %-16S %-14S %S",
|
||
|
typeStr[ace->Header.AceType],
|
||
|
inherStr,
|
||
|
ace->Mask,
|
||
|
PermStr(ace->Mask, permStr),
|
||
|
(*(sidTree->buffer + sidTree->lenSid)) ? (sidTree->buffer + sidTree->lenSid) : sTxtSid,
|
||
|
sidTree->buffer + sidTree->lenSid + strlen(sidTree->buffer + sidTree->lenSid) + 1,
|
||
|
sidType[sidTree->sidUse]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
SECURITY_DESCRIPTOR *
|
||
|
GetSD(
|
||
|
WCHAR * path
|
||
|
)
|
||
|
{ //added by christy
|
||
|
//this does the same stuff as
|
||
|
// PermsPrint, but doesn't print
|
||
|
|
||
|
DWORD req;
|
||
|
|
||
|
HANDLE hSrc;
|
||
|
DWORD rc = 0;
|
||
|
|
||
|
// void * r = NULL;
|
||
|
// WIN32_STREAM_ID * s = (WIN32_STREAM_ID *)copyBuffer;
|
||
|
char static const * streamName[] = {"Err", "Data", "EA", "Security", "Alternate", "Link", "Err6"};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
hSrc = CreateFile(path,
|
||
|
GENERIC_READ |ACCESS_SYSTEM_SECURITY,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_BACKUP_SEMANTICS,
|
||
|
0);
|
||
|
|
||
|
if ( hSrc == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
if ( rc == ERROR_SHARING_VIOLATION )
|
||
|
err.DbgMsgWrite(ErrE, L"Source file in use %S", path );
|
||
|
else
|
||
|
err.DbgMsgWrite(ErrS,L"OpenR(%S) ", path);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if ( ! GetKernelObjectSecurity(hSrc, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
|
||
|
| DACL_SECURITY_INFORMATION
|
||
|
| SACL_SECURITY_INFORMATION
|
||
|
,
|
||
|
sd,
|
||
|
SDBUFFSIZE,
|
||
|
&req) )
|
||
|
{
|
||
|
err.DbgMsgWrite(0, L"GetKernelObjectSecurity(%S)=%ld req=%ld ",
|
||
|
path, GetLastError(),req);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
CloseHandle(hSrc);
|
||
|
|
||
|
return sd;
|
||
|
}
|
||
|
|
||
|
|
||
|
//#pragma page()
|
||
|
// Gets the security descriptors for a resource (path), format the owner
|
||
|
// information, gets the ACL and SACL and prints them.
|
||
|
|
||
|
DWORD
|
||
|
PermsPrint(
|
||
|
WCHAR * path, // in -iterate directory paths
|
||
|
objectType objType // in -type of the object
|
||
|
)
|
||
|
{
|
||
|
TFileSD fsd(path);
|
||
|
TShareSD ssd(path);
|
||
|
TPrintSD psd(path);
|
||
|
TRegSD rsd(path,NULL);
|
||
|
SECURITY_DESCRIPTOR const* pSD = NULL;
|
||
|
|
||
|
switch ( objType )
|
||
|
{
|
||
|
case file:
|
||
|
case directory:
|
||
|
fsd.ReadSD(path);
|
||
|
if ( fsd.GetSecurity() )
|
||
|
{
|
||
|
pSD = fsd.GetSecurity()->GetSD();
|
||
|
}
|
||
|
break;
|
||
|
case printer:
|
||
|
psd.ReadSD(path);
|
||
|
if ( psd.GetSecurity() )
|
||
|
{
|
||
|
pSD = psd.GetSecurity()->GetSD();
|
||
|
}
|
||
|
break;
|
||
|
case share:
|
||
|
ssd.ReadSD(path);
|
||
|
if ( ssd.GetSecurity() )
|
||
|
{
|
||
|
pSD = ssd.GetSecurity()->GetSD();
|
||
|
}
|
||
|
break;
|
||
|
case regkey:
|
||
|
rsd.ReadSD(path);
|
||
|
if ( rsd.GetSecurity() )
|
||
|
{
|
||
|
pSD = rsd.GetSecurity()->GetSD();
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
if ( pSD )
|
||
|
{
|
||
|
PrintSD(const_cast<SECURITY_DESCRIPTOR*>(pSD),path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"Couldn't load Security descriptor for %ls",path);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
DWORD PrintSD(SECURITY_DESCRIPTOR * sd,WCHAR const * path)
|
||
|
{
|
||
|
BOOL isPresent,
|
||
|
isDefault;
|
||
|
PACL dacl;
|
||
|
PACL sacl;
|
||
|
PSID pSidOwner;
|
||
|
SidTree * sidTree = &gSidTree;
|
||
|
|
||
|
// DWORD rc = 0;
|
||
|
|
||
|
if ( !GetSecurityDescriptorOwner(sd, &pSidOwner, &isDefault) )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"GetSecurityDescriptorOwner()=%ld ", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
err.DbgMsgWrite(0,L"%s",path);
|
||
|
if ( pSidOwner )
|
||
|
{
|
||
|
sidTree = sidHead->Find(&sidHead, pSidOwner);
|
||
|
if (sidTree)
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"owner=%S\\%S, type=%S, ",
|
||
|
//path,
|
||
|
sidTree->buffer + sidTree->lenSid + strlen(sidTree->buffer + sidTree->lenSid) + 1,
|
||
|
sidTree->buffer + sidTree->lenSid,
|
||
|
sidType[sidTree->sidUse]);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"owner=NULL");
|
||
|
}
|
||
|
if ( !GetSecurityDescriptorDacl(sd, &isPresent, &dacl, &isDefault) )
|
||
|
{
|
||
|
err.DbgMsgWrite(0, L"GetSecurityDescriptorDacl()=%ld ", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
err.DbgMsgWrite(0,L" DACL=%S", AclType(isPresent, isDefault) );
|
||
|
if ( dacl )
|
||
|
PrintACL(dacl, path);
|
||
|
|
||
|
if ( !GetSecurityDescriptorSacl(sd, &isPresent, &sacl, &isDefault) )
|
||
|
{
|
||
|
err.DbgMsgWrite(0, L"GetSecurityDescriptorSacl()=%ld ", GetLastError());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if ( isPresent )
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L" SACL %S", AclType(isPresent, isDefault) );
|
||
|
if (!sacl)
|
||
|
{
|
||
|
err.DbgMsgWrite(0,L"SACL is empty.");
|
||
|
}
|
||
|
else PrintACL(sacl, path);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|