Main Page   Namespace List   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

acl.cpp

Go to the documentation of this file.
00001 // recommended includes in stdafx.h (or in the precompiled header, to be precise):
00002 // windows.h, tchar.h, string, vector, algorithm, exception, sstream, iomanip
00003 
00004 #include "stdafx.h"
00005 #define FKSEC_NO_AUTO_INCLUDES 1
00006 #include "fksec.h"
00007 #include "ex.h"
00008 #include "sid.h"
00009 #include "ace.h"
00010 #include "acl.h"
00011 
00012 using namespace fksec;
00013 
00014 
00017 
00018 
00019 // --- ctors/dtor ---
00020 
00021 // construct an empty acl object
00024 acl::acl()
00025 {
00026     Init();
00027 }
00028 
00029 
00030 // construct from another acl object
00034 acl::acl( const acl &a )
00035 {
00036     Init();
00037     if ( a.IsValid() )
00038     {
00039         aces = a.aces;
00040         additionalBytes = a.additionalBytes;
00041     }
00042     else
00043         throw NEWEX( errInvalidAcl, "acl::acl(const acl&): invalid ACL" );
00044 
00045 }
00046 
00047 
00048 // construct from a PACL
00056 acl::acl( ACL *a )
00057 {
00058     ACL_SIZE_INFORMATION asi;
00059     DWORD i, n;
00060     void *pace;
00061 
00062     Init();
00063     if ( IsValidAcl( a ) && ( a->AclRevision == ACL_REVISION ||
00064         a->AclRevision == ACL_REVISION_DS ) )
00065     {
00066         GetAclInformation( a, &asi, sizeof asi, AclSizeInformation );
00067         additionalBytes = asi.AclBytesFree;
00068         n = asi.AceCount;
00069         for ( i = 0; i < n; ++ i )
00070         {
00071             if ( ::GetAce( a, i, &pace ) )
00072             {
00073                 try { AddAce( (DWORD) -1, pace ); }
00074                 catch ( ex *e )
00075                 {
00076                     e->FKSECADDHOP( "acl::ace(ACL *): failed to add an ACE" );
00077                     aces.clear();
00078                     throw;
00079                 }
00080             }
00081         }
00082     }
00083     else
00084         throw NEWEX( errInvalidAcl, "acl::acl(ACL *): invalid ACL, or bad revision" );
00085 }
00086 
00087 
00088 // clean up
00091 acl::~acl()
00092 {
00093     ReleasePACL();
00094     aces.clear();
00095 }
00096 
00097 
00098 
00099 // --- assignment ---
00100 
00101 // from another acl
00107 const acl &acl::operator=( const acl &s )
00108 {
00109     if ( this != &s )
00110     {
00111         ReleasePACL();
00112         if ( s.IsValid() )
00113         {
00114             aces = s.aces;
00115             additionalBytes = s.additionalBytes;
00116         }
00117         else
00118             throw NEWEX( errInvalidAcl, "acl::operator=(const acl&): invalid ACL" );
00119     }
00120 
00121     return *this;
00122 }
00123 
00124 
00125 // from PACL
00134 const acl &acl::operator=( ACL *s )
00135 {
00136     ACL_SIZE_INFORMATION asi;
00137     DWORD i, n;
00138     void *pace;
00139 
00140     if ( havePACL && pacl == s )
00141         return *this;
00142 
00143     ReleasePACL();
00144     Init();
00145     if ( IsValidAcl( s ) )
00146     {
00147         GetAclInformation( s, &asi, sizeof asi, AclSizeInformation );
00148         additionalBytes = asi.AclBytesFree;
00149         n = asi.AceCount;
00150         for ( i = 0; i < n; ++ i )
00151         {
00152             if ( ::GetAce( s, i, &pace ) )
00153             {
00154                 try { AddAce( (DWORD) -1, pace ); }
00155                 catch ( ex *e )
00156                 {
00157                     e->FKSECADDHOP( "acl::operator=(ACL *): failed to add an ACE" );
00158                     aces.clear();
00159                     throw;
00160                 }
00161             }
00162         }
00163     }
00164     else
00165         throw NEWEX( errInvalidAcl, "acl::operator=(ACL *): invalid ACL" );
00166 
00167     return *this;
00168 }
00169 
00170 
00171 
00172 // --- conversions ---
00173 
00174 // return a pointer to an internally-maintained ACL
00190 acl::operator ACL *() const
00191 {
00192     ACL *p;
00193 
00194     try { p = MakePACL(); }
00195     RETHROWEX( "acl::operator const ACL *(): MakePACL() failed" )
00196 
00197     return p;
00198 }
00199 
00200 
00201 
00202 // --- accessors ---
00203 
00204 // return a ref to the Nth ACE
00211 const ace &acl::GetAce( DWORD index ) const
00212 {
00213     if ( index >= GetCount() )
00214         throw NEWEX( errInvalidAceIndex, "acl::GetAce(): ACE index out of range" );
00215 
00216     return aces[index];
00217 }
00218 
00219 
00226 ace &acl::GetAce( DWORD index )
00227 {
00228     if ( index >= GetCount() )
00229         throw NEWEX( errInvalidAceIndex, "acl::GetAce(): ACE index out of range" );
00230 
00231     return aces[index];
00232 }
00233 
00234 
00235 // return bytes required incl. desired free bytes
00242 DWORD acl::GetSize() const
00243 {
00244     return GetLength() + additionalBytes;
00245 }
00246 
00247 
00248 // return count of ACEs
00252 DWORD acl::GetCount() const
00253 {
00254     return aces.size();
00255 }
00256 
00257 
00258 // set amount of free bytes desired in NT ACL
00264 void acl::SetFreeBytes( DWORD newAdditionalBytes )
00265 {
00266     additionalBytes = newAdditionalBytes;
00267 }
00268 
00269 
00270 // how many bytes are extra?
00275 DWORD acl::GetFreeBytes() const
00276 {
00277     return additionalBytes;
00278 }
00279 
00280 
00281 
00282 // --- utilities ---
00283 
00284 // add an ACE
00285 // index gives the position _before_ which the ACE will be inserted
00286 // (DWORD) -1 inserts at end
00287 // no need to worry about canonical order, you can always canonicalize() the ACL
00296 void acl::AddAce( DWORD index, const ace &a )
00297 {
00298     AceListIter i;
00299 
00300     if ( index >= aces.size() )
00301         i = aces.end();
00302     else
00303         i = &aces[index];
00304 
00305     aces.insert( i, a );
00306 }
00307 
00308 
00341 void acl::AddAce( DWORD index, byte type, byte flags, byte inheritance,
00342     ACCESS_MASK mask, const sid &newSid, const GUID &ObjectType /* = GUID_NULL */,
00343     const GUID &InheritedObjectType /* = GUID_NULL */ )
00344 {
00345     AceListIter i;
00346 
00347     if ( index >= aces.size() )
00348         i = aces.end();
00349     else
00350         i = &aces[index];
00351 
00352     aces.insert( i, ace( type, flags, inheritance, mask,
00353         newSid, ObjectType, InheritedObjectType ) );
00354 }
00355 
00356 
00357 // delete an ACE
00362 void acl::DeleteAce( DWORD index )
00363 {
00364     if ( index < aces.size() )
00365         aces.erase( &aces[index] );
00366     else
00367         throw NEWEX( errInvalidAceIndex, "acl::DeleteAce(): ACE index out of range" );
00368 }
00369 
00370 
00371 // delete all ACEs for the specified SID
00377 void acl::DeleteAcesForSid( const sid &delSid )
00378 {
00379     int i;
00380 
00381     for ( i = aces.size() - 1; i >= 0; -- i )
00382     {
00383         if ( aces[i].GetSid() == delSid )
00384             aces.erase( &aces[i] );
00385     }
00386 }
00387 
00388 
00413 ACCESS_MASK acl::GetEffectiveRights( const SidList& sids )
00414 {
00415     AceListConstIter i;
00416     ACCESS_MASK denied = 0, granted = 0;
00417 
00418     if ( ! IsValid() )
00419         throw NEWEX( errInvalidAcl, "acl::GetEffectiveRights(): invalid ACL" );
00420 
00421     for ( i = aces.begin(); i != aces.end(); ++ i )
00422     {
00423         // note: if sids.size() * aces.size() is large and
00424         // sids.size() is middling to large, it might be
00425         // worthwhile to create a hashed or treed copy of
00426         // the sids list and use that ...
00427         if ( sids.end() != std::find( sids.begin(), sids.end(), i->GetSid() ) )
00428         {
00429             switch ( i->GetType() )
00430             {
00431             case ACCESS_ALLOWED_ACE_TYPE:
00432             case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
00433             case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
00434                 granted |= i->GetMask();
00435                 break;
00436             case ACCESS_DENIED_ACE_TYPE:
00437             case ACCESS_DENIED_OBJECT_ACE_TYPE:
00438                 denied |= i->GetMask();
00439                 break;
00440             default:
00441                 throw NEWEX( errInvalidAcl, "acl::GetEffectiveRights(): only allow- and deny-ACEs are supported" );
00442             }
00443         }
00444     }
00445 
00446     granted &= ~denied;
00447     return granted;
00448 }
00449 
00450 
00451 // normalize ACEs -- ACEs with same type, flags, inheritance,
00452 // and SID are merged by ORing their masks. This means you can
00453 // just blindly add ACEs and then call normalize().
00454 void acl::normalize()
00455 {
00456     int i, j;
00457 
00458     for ( i = 0; i < aces.size() - 1; ++ i )
00459     {
00460         for ( j = aces.size() - 1; j > i; -- j )
00461         {
00462             if ( aces[i] == aces[j] )
00463             {
00464                 aces[i].SetMask( aces[i].GetMask() | aces[j].GetMask() );
00465                 aces.erase( &aces[j] );
00466             }
00467         }
00468     }
00469 }
00470 
00471 
00472 // sort ACEs into canonical order: deny-ACEs first, then allow-ACEs,
00473 // then all others. This is a stable sort.
00474 void acl::canonicalize()
00475 {
00476     std::sort( aces.begin(), aces.end() );
00477 }
00478 
00479 
00480 // how many bytes for an NT-formatted ACL, without extra free space?
00481 DWORD acl::GetLength() const
00482 {
00483     AceListConstIter i;
00484     DWORD totsize;
00485 
00486     for ( totsize = 0, i = aces.begin(); i != aces.end(); ++ i )
00487     {
00488         try { totsize += i->GetLength(); }
00489         RETHROWEX( "acl::GetLength(): failed to retrieve an ACE's size" )
00490     }
00491 
00492     totsize += sizeof ACL;
00493     return totsize;
00494 }
00495 
00496 
00497 // store a copy of the ACL where the caller wants it
00508 void acl::StoreAcl( ACL *p, DWORD sz ) const
00509 {
00510     AceListConstIter i;
00511     void *a;
00512     DWORD remaining, acelen;
00513 
00514     if ( ! IsValid() )
00515         throw NEWEX( errInvalidAcl, "acl::StoreAcl(): invalid ACL" );
00516 
00517     remaining = GetSize();
00518     if ( sz < remaining )
00519     {
00520         ex *e = NEWEX( errBufferTooSmall,
00521             "acl::StoreAcl(): insufficient buffer, see ex::GetData() for required size" );
00522         e->SetData( remaining );
00523         throw e;
00524     }
00525 
00526     if ( ! ::InitializeAcl( p, remaining, GetRequiredAclRevision() ) )
00527         throw NEWEX32( errInvalidAcl,
00528             "acl::StoreAcl(): ::InitializeAcl() failed, see ex::GetErrWin32",
00529             GetLastError() );
00530 
00531     p->AceCount = aces.size();
00532     a = (void *) &p[1]; // point to first ACE slot
00533     remaining -= sizeof ACL;
00534 
00535     for ( i = aces.begin(); i != aces.end(); ++ i )
00536     {
00537         try
00538         {
00539             acelen = i->GetLength();
00540             i->StoreAce( a, remaining );
00541         }
00542         RETHROWEX( "acl::StoreAcl(): ran into a stubborn ACE" )
00543         a = (void *) ( (byte *) a + acelen );
00544         remaining -= acelen;
00545     }
00546 
00547     // at this point, the remaining bytes should be exactly those that
00548     // the user wanted to be allocated in excess of the minimum.
00549     if ( remaining != additionalBytes || ! IsValidAcl( p ) )
00550         throw NEWEX( errInvalidAcl,
00551             "acl::StoreAcl(): size calculation incorrect, or invalid ACL produced" );
00552 }
00553 
00554 
00555 // test for validity
00565 bool acl::IsValid() const
00566 {
00567     bool result = true;
00568 
00569     try
00570     {
00571         for ( AceListConstIter i = aces.begin(); result && i != aces.end(); ++ i )
00572             result = result && i->IsValid();
00573     }
00574     catch ( ex *e )
00575     {
00576         delete e;
00577         return false;
00578     }
00579 
00580     if ( GetSize() > 65535 )
00581         return false;
00582 
00583     return true;
00584 }
00585 
00586 
00592 bool acl::IsObjectACL() const
00593 {
00594     AceListConstIter i;
00595 
00596     for ( i = aces.begin(); i != aces.end(); ++ i )
00597     {
00598         if ( i->IsObjectACE() )
00599             return true;
00600     }
00601     return false;
00602 }
00603 
00604 
00605 // what type of Acl Revision do we want
00614 DWORD acl::GetRequiredAclRevision() const
00615 {
00616     return IsObjectACL()? ACL_REVISION_DS: ACL_REVISION;
00617 }
00618 
00619 
00620 // --- inserters ---
00621 
00622 // dump this acl
00632 fkostream &fksec::operator<<( fkostream &o, const acl &a )
00633 {
00634     o << _T( "acl, " ) << a.aces.size() << _T( " ACEs, " )
00635         << a.additionalBytes << _T( " bytes extra space" ) << std::endl;
00636 
00637     for ( AceListConstIter i = a.aces.begin(); i != a.aces.end(); ++ i )
00638         o << _T( "  " ) << (*i) << std::endl;
00639 
00640     return o;
00641 }
00642 
00643 
00646 void acl::Init()
00647 {
00648     aces.clear();
00649     additionalBytes = 0;
00650     ClearPACL();
00651 }
00652 
00653 
00654 // initialize the PACL part
00657 void acl::ClearPACL() const
00658 {
00659     havePACL = false;
00660     pacl = 0;
00661 }
00662 
00663 
00664 // release the PACL part
00668 void acl::ReleasePACL() const
00669 {
00670     if ( havePACL )
00671     {
00672         delete [] (byte *) pacl;
00673         pacl = 0;
00674         havePACL = false;
00675     }
00676 }
00677 
00678 
00691 ACL *acl::MakePACL() const
00692 {
00693     DWORD sz;
00694 
00695     if ( ! havePACL )
00696     {
00697         if ( ! IsValid() )
00698             throw NEWEX( errInvalidAcl, "acl::MakePACL(): invalid ACL" );
00699 
00700         sz = GetSize();
00701 
00702         pacl = (ACL *) new byte[sz];
00703         if ( pacl == 0 )
00704             throw NEWEX( errNoMemory, "acl::MakePACL(): no memory for ACL buffer" );
00705 
00706         try { StoreAcl( pacl, sz ); }
00707         catch ( ex *e )
00708         {
00709             e->FKSECADDHOP( "acl::MakePACL(): StoreAcl() is insubordinate" );
00710             delete (byte *) pacl;
00711             throw;
00712         }
00713 
00714         havePACL = true;
00715     }
00716 
00717     return pacl;
00718 }

Generated at Mon Oct 16 06:14:07 2000 for fksec by doxygen1.2.2 written by Dimitri van Heesch, © 1997-2000