//+------------------------------------------------------------------
//
// Copyright (C) 1995, Microsoft Corporation.
//
// File:        filesec.cxx
//
// Classes:     CFileSecurity class encapsulating SECURITY_DESCRIPTOR
//
// History:     Nov-93      DaveMont         Created.
//
//-------------------------------------------------------------------

#include <filesec.hxx>
//+---------------------------------------------------------------------------
// Function:    Add2Ptr
//
// Synopsis:    Add an unscaled increment to a ptr regardless of type.
//
// Arguments:   [pv]	-- Initial ptr.
//              [cb]	-- Increment
//
// Returns:     Incremented ptr.
//
//----------------------------------------------------------------------------
VOID * Add2Ptr(VOID *pv, ULONG cb)
{
    return((BYTE *) pv + cb);
}
//+---------------------------------------------------------------------------
//
//  Member:     CFileSecurity::CFileSecurity, public
//
//  Synopsis:   initializes data members
//              constructor will not throw
//
//  Arguments:  [filename] - name of file to apply security descriptor to
//
//----------------------------------------------------------------------------
CFileSecurity::CFileSecurity(WCHAR *filename)
    : _psd(NULL),
      _pwfilename(filename)
{
}
//+---------------------------------------------------------------------------
//
//  Member:     CFileSecurity::Init, public
//
//  Synopsis:   Init must be called before any other methods - this
//              is not enforced.  gets security descriptor from file
//
//  Arguments:  none
//
//----------------------------------------------------------------------------
ULONG CFileSecurity::Init()
{
    ULONG ret;
    ULONG cpsd;

    // get the size of the security buffer

    if (!GetFileSecurity(_pwfilename,
                         DACL_SECURITY_INFORMATION |
                         GROUP_SECURITY_INFORMATION |
                         OWNER_SECURITY_INFORMATION,
                         NULL,
                         0,
                         &cpsd) )
    {
        if (ERROR_INSUFFICIENT_BUFFER == (ret = GetLastError()))
        {
            if (NULL == (_psd = (BYTE *)LocalAlloc(LMEM_FIXED, cpsd)))
            {
                 return(ERROR_NOT_ENOUGH_MEMORY);
            }

            // actually get the buffer this time

            if ( GetFileSecurity(_pwfilename,
                                 DACL_SECURITY_INFORMATION |
                                 GROUP_SECURITY_INFORMATION |
                                 OWNER_SECURITY_INFORMATION,
                                 _psd,
                                 cpsd,
                                 &cpsd) )
                ret = ERROR_SUCCESS;
            else
                ret = GetLastError();

        }
    } else
        return(ERROR_NO_SECURITY_ON_OBJECT);
    return(ret);
}
//+---------------------------------------------------------------------------
//
//  Member:     Dtor, public
//
//  Synopsis:   frees security descriptor if allocated
//
//  Arguments:  none
//
//----------------------------------------------------------------------------
CFileSecurity::~CFileSecurity()
{
    if (_psd)
    {
        LocalFree(_psd);
    }
}

//+---------------------------------------------------------------------------
//
//  Member:     CFileSecurity::SetFS, public
//
//  Synopsis:   sets or modifies the security descriptor DACL on the specified file
//
//  Arguments:  IN - [fmodify] - TRUE = modify ACL, FALSE = replace ACL
//              IN - [pcdw]    - wrapper around new ACEs
//              IN - [fdir]    - TRUE = directory
//
//  Returns:    status
//
//----------------------------------------------------------------------------
ULONG CFileSecurity::SetFS(BOOL fmodify, CDaclWrap *pcdw, BOOL fdir)
{
   BOOL fdaclpresent;
   BOOL cod;
   ACL *pdacl;
   ULONG ret;

   // get the ACL from the security descriptor

   if ( GetSecurityDescriptorDacl(_psd,
                                  &fdaclpresent,
                                  &pdacl,
                                  &cod) )

   {
       if (fdaclpresent && (NULL != pdacl))
       {
           // build the new ACL (from the new ACEs and the old ACL)

           ACL *pnewdacl = NULL;

           if (ERROR_SUCCESS == (ret =  pcdw->BuildAcl(&pnewdacl, fmodify ? pdacl : NULL, pdacl->AclRevision, fdir)))
           {
               // make a new security descriptor

               SECURITY_DESCRIPTOR newsd;
               newsd.Revision = ((SECURITY_DESCRIPTOR*) _psd)->Revision;
               newsd.Sbz1 = 0;
               newsd.Control = SE_DACL_PRESENT;
               newsd.Owner = _psd + (ULONG)((SECURITY_DESCRIPTOR*)_psd)->Owner; // convert to absolute
               newsd.Group = _psd + (ULONG)((SECURITY_DESCRIPTOR*)_psd)->Group; // convert to absolute
               newsd.Sacl  = (ACL *) (_psd + (ULONG)((SECURITY_DESCRIPTOR*)_psd)->Sacl); // convert to absolute
               newsd.Dacl = pnewdacl;

               // apply it to the file

               if (!SetFileSecurity(_pwfilename,
                                    DACL_SECURITY_INFORMATION,
                                    &newsd))
               {
                   ret = GetLastError();
               }
               LocalFree(pnewdacl);
           }
       }
       else
           return(ERROR_NO_SECURITY_ON_OBJECT);
    } else
    {
        ret = GetLastError();
    }

    return(ret);
}
