Win32-security-0.1: src/System/Win32/Security/SecurityInfo.hsc
{-# LANGUAGE CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving, OverloadedStrings, RankNTypes #-}
module System.Win32.Security.SecurityInfo
( SecurityDescriptor
, SecurityObjectType
, securityObjectUnknown
, securityObjectFile
, securityObjectService
, securityObjectPrinter
, securityObjectRegistryKey
, securityObjectLMShare
, securityObjectKernelObject
, securityObjectDSObject
, securityObjectDSObjectAll
, securityObjectProviderDefined
, securityObjectWMIGuid
, securityObjectRegistryWow6432Key
, SecurityInformation
, securityInformationOwner
, securityInformationGroup
, securityInformationDacl
, securityInformationSacl
, securityInformationAll
, GetSecurityInfoResult (..)
, getNamedSecurityInfo
, SetSecurityInfoAcl (..)
, setNamedSecurityInfo
) where
import Foreign
import System.Win32.Types
import System.Win32.Security
import System.Win32.Security.Sid
import System.Win32.Security.AccessControl
import qualified Data.Text as T
import qualified System.Win32.Error.Foreign as E
import qualified System.Win32.Security.MarshalText as T
#include <windows.h>
#include <AccCtrl.h>
newtype SecurityDescriptor = SecurityDescriptor (ForeignPtr SECURITY_DESCRIPTOR)
-- | newtype wrapper around Windows SDK SE_OBJECT_TYPE enumeration
newtype SecurityObjectType = SecurityObjectType BYTE
#{enum SecurityObjectType, SecurityObjectType
, securityObjectUnknown = SE_UNKNOWN_OBJECT_TYPE
, securityObjectFile = SE_FILE_OBJECT
, securityObjectService = SE_SERVICE
, securityObjectPrinter = SE_PRINTER
, securityObjectRegistryKey = SE_REGISTRY_KEY
, securityObjectLMShare = SE_LMSHARE
, securityObjectKernelObject = SE_KERNEL_OBJECT
, securityObjectDSObject = SE_DS_OBJECT
, securityObjectDSObjectAll = SE_DS_OBJECT_ALL
, securityObjectProviderDefined = SE_PROVIDER_DEFINED_OBJECT
, securityObjectWMIGuid = SE_WMIGUID_OBJECT
, securityObjectRegistryWow6432Key = SE_REGISTRY_WOW64_32KEY
}
newtype SecurityInformation = SecurityInformation DWORD
deriving (Bits, Eq)
securityInformationOwner :: SecurityInformation
securityInformationOwner = SecurityInformation oWNER_SECURITY_INFORMATION
securityInformationGroup :: SecurityInformation
securityInformationGroup = SecurityInformation gROUP_SECURITY_INFORMATION
securityInformationDacl :: SecurityInformation
securityInformationDacl = SecurityInformation dACL_SECURITY_INFORMATION
securityInformationSacl :: SecurityInformation
securityInformationSacl = SecurityInformation sACL_SECURITY_INFORMATION
securityInformationAll :: SecurityInformation
securityInformationAll = SecurityInformation $
oWNER_SECURITY_INFORMATION .|. gROUP_SECURITY_INFORMATION .|.
dACL_SECURITY_INFORMATION .|. sACL_SECURITY_INFORMATION
foreign import WINDOWS_CCONV unsafe "windows.h GetNamedSecurityInfoW"
c_GetNamedSecurityInfoW
:: LPWSTR -- pObjectName
-> BYTE -- ObjectType
-> DWORD -- SecurityInformation
-> Ptr PSID -- ppsidOwner
-> Ptr PSID -- ppsidGroup
-> Ptr PACL -- ppDacl
-> Ptr PACL -- ppSacl
-> Ptr (Ptr SECURITY_DESCRIPTOR) -- ppSecurityDescriptor
-> IO DWORD
data GetSecurityInfoResult = GetSecurityInfoResult
{ securityInfoOwner :: Maybe Sid
, securityInfoGroup :: Maybe Sid
, securityInfoDacl :: Maybe Acl
, securityInfoSacl :: Maybe Acl
, securityInfoDescriptor :: SecurityDescriptor
}
getNamedSecurityInfo :: T.Text -> SecurityObjectType -> SecurityInformation -> IO GetSecurityInfoResult
getNamedSecurityInfo objectName (SecurityObjectType objectType) (SecurityInformation securityInfo) =
T.useAsPtr0 objectName $ \pObjectName ->
alloca $ \ppSidOwner ->
alloca $ \ppSidGroup ->
alloca $ \ppDacl ->
alloca $ \ppSacl ->
alloca $ \ppSecurityDescriptor -> do
E.failUnlessSuccess "GetNamedSecurityInfoW" $
c_GetNamedSecurityInfoW pObjectName objectType securityInfo ppSidOwner ppSidGroup ppDacl ppSacl ppSecurityDescriptor
sdPtr <- peek ppSecurityDescriptor
sd <- newForeignPtr localFreeFinaliser sdPtr
ownerSid <- if securityInfo .&. oWNER_SECURITY_INFORMATION /= 0
then do
pSidOwner <- peek ppSidOwner
return . Just $ Sid $ \act -> withForeignPtr sd $ \_ -> act pSidOwner
else
return Nothing
groupSid <- if securityInfo .&. gROUP_SECURITY_INFORMATION /= 0
then do
pSidGroup <- peek ppSidGroup
return . Just $ Sid $ \act -> withForeignPtr sd $ \_ -> act pSidGroup
else
return Nothing
dacl <- if securityInfo .&. dACL_SECURITY_INFORMATION /= 0
then do
pDacl <- peek ppDacl
return . Just $ Acl $ \act -> withForeignPtr sd $ \_ -> act pDacl
else
return Nothing
sacl <- if securityInfo .&. sACL_SECURITY_INFORMATION /= 0
then do
pSacl <- peek ppSacl
return . Just $ Acl $ \act -> withForeignPtr sd $ \_ -> act pSacl
else
return Nothing
return GetSecurityInfoResult
{ securityInfoOwner = ownerSid
, securityInfoGroup = groupSid
, securityInfoDacl = dacl
, securityInfoSacl = sacl
, securityInfoDescriptor = SecurityDescriptor sd
}
{-# CFILES cbits/Win32Security.c #-}
foreign import ccall "Win32Security.h &LocalFreeFinaliser"
localFreeFinaliser :: FunPtr (Ptr a -> IO ())
data SetSecurityInfoAcl
= DontSetAcl
-- | Set ACL and prevent inheritable ACEs from propagating
| ProtectedAcl Acl
-- | Set ACL and allow inheritable ACEs to propagate
| UnprotectedAcl Acl
setNamedSecurityInfo :: T.Text -> SecurityObjectType -> Maybe Sid -> Maybe Sid -> SetSecurityInfoAcl -> SetSecurityInfoAcl -> IO ()
setNamedSecurityInfo objectName (SecurityObjectType objectType) maybeOwner maybeGroup ssiDacl ssiSacl =
T.useAsPtr0 objectName $ \pObjectName ->
maybe ($ nullPtr) withSidPtr maybeOwner $ \psidOwner ->
maybe ($ nullPtr) withSidPtr maybeGroup $ \psidGroup ->
withSecurityInfoAcl ssiDacl $ \pDacl ->
withSecurityInfoAcl ssiSacl $ \pSacl ->
let securityInfo = 0
.|. if psidOwner /= nullPtr then oWNER_SECURITY_INFORMATION else 0
.|. if psidGroup /= nullPtr then gROUP_SECURITY_INFORMATION else 0
.|. case ssiDacl of
DontSetAcl -> 0
ProtectedAcl _ -> dACL_SECURITY_INFORMATION .|. #{const PROTECTED_DACL_SECURITY_INFORMATION}
UnprotectedAcl _ -> dACL_SECURITY_INFORMATION
.|. case ssiSacl of
DontSetAcl -> 0
ProtectedAcl _ -> sACL_SECURITY_INFORMATION .|. #{const PROTECTED_SACL_SECURITY_INFORMATION}
UnprotectedAcl _ -> sACL_SECURITY_INFORMATION
in E.failUnlessSuccess "SetNamedSecurityInfoW" $
c_SetNamedSecurityInfoW pObjectName objectType securityInfo psidOwner psidGroup pDacl pSacl
where
withSecurityInfoAcl :: SetSecurityInfoAcl -> (Ptr ACL -> IO a) -> IO a
withSecurityInfoAcl ssia act = case ssia of
DontSetAcl -> act $ nullPtr
ProtectedAcl x -> withAclPtr x act
UnprotectedAcl x -> withAclPtr x act
foreign import WINDOWS_CCONV "windows.h SetNamedSecurityInfoW"
c_SetNamedSecurityInfoW
:: LPWSTR -- pObjectName
-> BYTE -- ObjectType
-> DWORD -- SecurityInfo
-> PSID -- psidOwner
-> PSID -- psidGroup
-> PACL -- pDacl
-> PACL -- pSacl
-> IO DWORD