#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
#include <string.h>
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "../ppport.h"
#undef New
#undef Newc
#define New(x,v,n,t) (v = (t*)LocalAlloc( LPTR, (MEM_SIZE)((n) * sizeof(t))))
#define Newc(x,v,n,t,c) (v = (c*)LocalAlloc( LPTR, (MEM_SIZE)((n) * sizeof(t))))
#define RETURNRESULT(x) if((x)){ XST_mYES(0); }\
else
{ XST_mNO(0); }\
XSRETURN(1)
#define SETIV(index,value) sv_setiv(ST(index), value)
#define SETPV(index,string) sv_setpv(ST(index), string)
#undef compstr
#define compstr( str1, str2 ) tolower( *str1 ) == tolower( *str2 ) && ! stricmp( str1, str2 )
#undef checkfree
#define checkfree(x) if ( x != NULL ) LocalFree( x ) ;
#define GENERIC_RIGHTS_MASK (0xF0010000L)
#define GENERIC_RIGHTS_CHK (0xF0000000L)
#define REST_RIGHTS_MASK (0x001FFFFFL)
#define NUM_SPECIAL_SID 1
#define MAXIMUM_NAME_LENGTH 256
#define ALLOW_ACE_LENGTH sizeof( ACCESS_ALLOWED_ACE ) + 50
static
DWORD
nRights[] =
{
DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER,
SYNCHRONIZE, STANDARD_RIGHTS_REQUIRED,
STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE,
STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_ALL,
SPECIFIC_RIGHTS_ALL, ACCESS_SYSTEM_SECURITY,
MAXIMUM_ALLOWED, GENERIC_READ, GENERIC_WRITE,
GENERIC_EXECUTE, GENERIC_ALL,
FILE_GENERIC_READ | FILE_EXECUTE,
FILE_GENERIC_READ | FILE_EXECUTE,
FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_EXECUTE | DELETE,
FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_EXECUTE | DELETE,
0x001201bf,
0x001201bf,
STANDARD_RIGHTS_ALL | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
STANDARD_RIGHTS_ALL | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE | FILE_DELETE_CHILD |
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
} ;
static
char
*szRights[] =
{
"DELETE"
,
"READ_CONTROL"
,
"WRITE_DAC"
,
"WRITE_OWNER"
,
"SYNCHRONIZE"
,
"STANDARD_RIGHTS_REQUIRED"
,
"STANDARD_RIGHTS_READ"
,
"STANDARD_RIGHTS_WRITE"
,
"STANDARD_RIGHTS_EXECUTE"
,
"STANDARD_RIGHTS_ALL"
,
"SPECIFIC_RIGHTS_ALL"
,
"ACCESS_SYSTEM_SECURITY"
,
"MAXIMUM_ALLOWED"
,
"GENERIC_READ"
,
"GENERIC_WRITE"
,
"GENERIC_EXECUTE"
,
"GENERIC_ALL"
,
"R"
,
"READ"
,
"C"
,
"CHANGE"
,
"A"
,
"ADD"
,
"F"
,
"FULL"
, NULL
} ;
static
char
*szLocalLookup[] = {
"BUILTIN"
,
"NT AUTHORITY"
, NULL } ;
static
long
constant(
char
*name ) {
int
i;
errno
= 0;
for
( i = 0; szRights[i] ; i++ ) {
if
( compstr( name, szRights[i] ) ) {
return
nRights[i] ;
}
}
errno
= EINVAL ;
return
0 ;
}
void
ErrorHandler(
const
char
*ErrName ) {
dTHX;
SV* sv = NULL ;
if
( sv == NULL ) {
croak(
"Error handling error: %u, %s"
, GetLastError(), ErrName ) ;
}
else
{
sv_setpv( sv, (
char
*) ErrName ) ;
sv_setiv( sv, GetLastError() ) ;
SvPOK_on(sv) ;
}
}
MODULE = Win32::FileSecurity PACKAGE = Win32::FileSecurity
PROTOTYPES: DISABLE
long
constant(name)
char
*name
CODE:
RETVAL = constant(name);
OUTPUT:
RETVAL
I32
MakeMask(...)
CODE:
{
int
i, j ;
STRLEN len ;
char
*name ;
I32 Mask = 0 ;
for
( i = 0 ; i < items ; i++ ) {
if
( ! SvPOK( ST(i) ) )
continue
;
name = SvPV( ST(i), len ) ;
for
( j = 0; szRights[j]; j++ ) {
if
( compstr( name, szRights[j] ) ) {
Mask |= nRights[j] ;
break
;
}
}
}
RETVAL = Mask;
}
OUTPUT:
RETVAL
bool
EnumerateRights(Mask,av)
I32 Mask
SV *av
CODE:
{
int
j ;
if
(!(av && SvROK(av) && (av = SvRV(av)) && SvTYPE(av) == SVt_PVAV))
croak(
"second arg must be ARRAYREF"
) ;
av_clear( (AV*)av ) ;
for
( j = 0; szRights[j]; j++ ) {
if
(
strlen
( szRights[j] ) == 1 )
continue
;
if
( ! ( ( nRights[j] & Mask ) ^ nRights[j] ) ) {
av_push((AV*)av,
newSVpv(szRights[j],
strlen
((
const
char
*)szRights[j])));
}
}
RETVAL = 1;
}
OUTPUT:
RETVAL
bool
Get(filename, hv)
char
*filename
SV *hv
CODE:
{
SV* sv;
SV** psv;
PSECURITY_DESCRIPTOR pSecDesc = NULL;
SECURITY_DESCRIPTOR_CONTROL Control = 0;
BOOL
bDaclPresent, bDaclDefaulted ;
PACL pDacl ;
PACE_HEADER pAce ;
PACCESS_ALLOWED_ACE pAllAce ;
LPTSTR
FullName, Name = NULL, DName = NULL, NoName =
"Unknown\000"
;
DWORD
bFN = MAXIMUM_NAME_LENGTH << 1,
bName = MAXIMUM_NAME_LENGTH, bDName = MAXIMUM_NAME_LENGTH;
SID_NAME_USE eUse ;
DWORD
nLength = 0, nLengthNeeded = 1, tries = 2, Revision = 0 ;
DWORD
error, i ;
BOOL
bResult;
RETVAL = FALSE;
if
(!(hv && SvROK(hv) && (hv = SvRV(hv)) && SvTYPE(hv) == SVt_PVHV))
croak(
"second arg must be HASHREF"
) ;
hv_clear( (HV*)hv ) ;
while
( nLengthNeeded && tries ) {
tries-- ;
bResult = GetFileSecurityA(
filename,
DACL_SECURITY_INFORMATION,
pSecDesc,
nLength,
&nLengthNeeded
);
if
(bResult) {
break
;
}
else
{
if
( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
switch
( error = GetLastError() ) {
case
ERROR_FILE_NOT_FOUND :
ErrorHandler(
"File not found."
) ;
goto
GetCleanup ;
default
:
ErrorHandler(
"GetFileSecurity"
) ;
goto
GetCleanup ;
}
}
}
nLength = nLengthNeeded ;
Newc( 1, pSecDesc, nLength,
char
, SECURITY_DESCRIPTOR ) ;
if
( pSecDesc == NULL ) {
ErrorHandler(
"Newc pSecDesc"
) ;
}
}
if
( ! GetSecurityDescriptorControl(
pSecDesc,
&Control,
(
LPDWORD
) &Revision
) ) {
ErrorHandler(
"GetSecurityDescriptorControl"
) ;
}
if
( ! ( Control & 0x0004 ) ) {
ErrorHandler(
"No DACL present: explicit deny all"
) ;
goto
GetCleanup ;
}
if
( ! GetSecurityDescriptorDacl(
pSecDesc,
(
LPBOOL
) &bDaclPresent,
&pDacl,
(
LPBOOL
) &bDaclDefaulted
) ) {
ErrorHandler(
"GetSecurityDescriptorDacl"
) ;
goto
GetCleanup ;
}
if
( pDacl == NULL ) {
ErrorHandler(
"Dacl is NULL: implicit access grant"
) ;
goto
GetCleanup ;
}
New( 2, FullName, bFN,
char
);
New( 2, Name, bName,
char
);
New( 3, DName, bDName,
char
);
if
( FullName == NULL || Name == NULL || DName == NULL ) {
ErrorHandler(
"New names"
) ;
goto
GetCleanup ;
}
for
( i = 0; i < pDacl->AceCount; i++ ) {
if
( ! GetAce( pDacl, i, (
void
**) &pAce ) ) {
continue
;
}
bDName = bName = MAXIMUM_NAME_LENGTH ;
switch
( pAce->AceType ) {
case
ACCESS_ALLOWED_ACE_TYPE :
pAllAce = (PACCESS_ALLOWED_ACE) pAce ;
bName = bDName = MAXIMUM_NAME_LENGTH ;
bResult = LookupAccountSidA(
NULL,
(PSID) &(pAllAce->SidStart),
Name,
&bName,
DName,
&bDName,
&eUse
);
if
(!bResult) {
Name = NoName ;
bDName = 0;
bName =
strlen
(Name);
}
if
( bDName ) {
strcpy
( FullName, DName );
strcat
( FullName,
"\\"
);
strcat
( FullName, Name );
bFN = bName + bDName + 1 ;
}
else
{
strcpy
( FullName, Name ) ;
bFN = bName ;
}
if
( hv_exists( (HV*)hv, FullName, (U32) bFN ) ) {
psv = hv_fetch( (HV*)hv, FullName, (U32) bFN, FALSE ) ;
if
( psv && (sv = *psv) && SvIOK( sv ) ) {
sv_setiv( sv, SvIV( sv ) | (IV) pAllAce->Mask ) ;
}
else
croak(
"MaskBuilder: Not an integer."
) ;
}
else
{
hv_store( (HV*)hv, FullName, (U32) bFN, sv = newSViv( (IV) pAllAce->Mask ), 0 );
}
break
;
default
:
;
}
}
RETVAL = TRUE ;
GetCleanup:
checkfree( pSecDesc ) ;
checkfree( Name ) ;
checkfree( DName ) ;
checkfree( FullName ) ;
}
OUTPUT:
RETVAL
bool
Set(filename, hv)
char
*filename
SV *hv
CODE:
{
SV* sv;
PACL pACLNew = NULL;
PACCESS_ALLOWED_ACE pAllAce;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD
cbACL = 1024, i;
PSID pSID = NULL;
DWORD
cbSID = 1024;
ACCESS_MASK AccountRights;
LPSTR
lpszAccount, lpszDomain, lpszServer, lpszTemp;
DWORD
cchDomainName = 80, tries;
PSID_NAME_USE psnuType = NULL;
I32 AccountLen;
BOOL
bResult;
RETVAL = FALSE;
if
(!(hv && SvROK(hv) && (hv = SvRV(hv)) && SvTYPE(hv) == SVt_PVHV))
croak(
"second arg must be HASHREF"
) ;
Newc( 4, pSD, SECURITY_DESCRIPTOR_MIN_LENGTH,
char
, SECURITY_DESCRIPTOR );
if
(pSD == NULL) {
ErrorHandler(
"Newc SECURITY_DESCRIPTOR"
);
goto
SetCleanup ;
}
if
(!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION)) {
ErrorHandler(
"InitializeSecurityDescriptor"
);
goto
SetCleanup;
}
Newc( 5, pACLNew, cbACL,
char
, ACL ) ;
if
(pACLNew == NULL) {
ErrorHandler(
"Newc pACLNew"
) ;
goto
SetCleanup;
}
if
(!InitializeAcl(pACLNew, cbACL, ACL_REVISION2)) {
ErrorHandler(
"InitializeAcl"
);
goto
SetCleanup;
}
Newc( 6, pSID, cbSID,
char
, PSID ) ;
Newc( 7, psnuType, 1024,
char
, SID_NAME_USE ) ;
Newc( 8, pAllAce, ALLOW_ACE_LENGTH,
char
, ACCESS_ALLOWED_ACE ) ;
New( 9, lpszDomain, cchDomainName,
char
) ;
if
(pSID == NULL || psnuType == NULL
|| lpszDomain == NULL || pAllAce == NULL ) {
ErrorHandler(
"Newc names/ace"
);
goto
SetCleanup;
}
pAllAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE ;
for
( hv_iterinit( (HV*)hv ),
sv = hv_iternextsv( (HV*)hv, &lpszAccount, &AccountLen ) ;
1 ;
sv = hv_iternextsv( (HV*)hv, &lpszAccount, &AccountLen ) ) {
if
( sv == NULL )
break
;
if
(!SvOK( sv ) )
break
;
if
( SvNOK( sv ) ) {
sv_setiv( sv, (IV) SvNV( sv ) ) ;
}
if
( !SvIOK( sv ) ) {
continue
;
}
cbSID = 1024 ;
cchDomainName = 80 ;
if
( lpszTemp =
strchr
( lpszAccount,
'\\'
) ) {
lpszServer = lpszAccount ;
*lpszTemp =
'\0'
;
lpszAccount = lpszTemp + 1 ;
}
else
{
lpszServer = NULL ;
}
if
( lpszServer != NULL ) {
for
( i = 0; szLocalLookup[i] != NULL; i++ ) {
if
( stricmp( szLocalLookup[i], lpszServer ) == 0 ) {
lpszServer = NULL ;
break
;
}
}
}
bResult = LookupAccountNameA((
LPCSTR
) lpszServer,
(
LPCSTR
) lpszAccount,
pSID,
&cbSID,
lpszDomain,
&cchDomainName,
psnuType);
if
(!bResult) {
printf
(
"%s\\%s\n"
, lpszServer ? lpszServer :
""
, lpszAccount ) ;
ErrorHandler(
"LookupAccountName"
);
goto
SetCleanup;
}
if
(!CopySid(
ALLOW_ACE_LENGTH -
sizeof
( ACCESS_ALLOWED_ACE ),
(PSID) &pAllAce->SidStart,
pSID
) ) {
ErrorHandler(
"CopySid"
);
goto
SetCleanup;
}
if
( AccountRights = GENERIC_ALL & (ACCESS_MASK) SvIV( sv ) ) {
}
else
if
( GENERIC_RIGHTS_CHK & (ACCESS_MASK) SvIV( sv ) ) {
AccountRights = GENERIC_RIGHTS_MASK & (ACCESS_MASK)SvIV(sv);
}
else
{
AccountRights = 0;
}
pAllAce->Header.AceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE ;
tries = 2 ;
while
(tries--) {
if
( AccountRights ) {
pAllAce->Header.AceSize =
sizeof
( ACCESS_ALLOWED_ACE ) -
sizeof
(
DWORD
) + GetLengthSid( (PSID) pSID ) ;
pAllAce->Mask = (ACCESS_MASK) AccountRights ;
if
(!AddAce(
pACLNew,
ACL_REVISION2,
MAXDWORD,
pAllAce,
pAllAce->Header.AceSize
)) {
ErrorHandler(
"AddAce"
);
goto
SetCleanup;
}
pAllAce->Header.AceFlags = CONTAINER_INHERIT_ACE ;
}
else
{
pAllAce->Header.AceFlags = 0 ;
}
AccountRights = REST_RIGHTS_MASK & (ACCESS_MASK) SvIV( sv ) ;
}
}
if
(!SetSecurityDescriptorDacl(pSD,
TRUE,
pACLNew,
FALSE)) {
ErrorHandler(
"SetSecurityDescriptorDacl"
);
goto
SetCleanup;
}
bResult = SetFileSecurityA(filename,
DACL_SECURITY_INFORMATION,
pSD);
if
(!bResult) {
ErrorHandler(
"SetFileSecurity"
);
goto
SetCleanup;
}
RETVAL = TRUE;
SetCleanup:
FreeSid( pSID ) ;
checkfree( pSD ) ;
checkfree( pACLNew ) ;
checkfree( psnuType ) ;
checkfree( lpszDomain ) ;
}
OUTPUT:
RETVAL