Fix inherited objects problem. (#59)

This commit is contained in:
Eugene Kabanov 2020-10-20 17:43:38 +03:00 committed by GitHub
parent 7018fb0b5e
commit bc3b4cf2de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 17 deletions

View File

@ -28,8 +28,11 @@ const
PROTECTED_DACL_SECURITY_INFORMATION = 0x8000_0000'u32
SE_FILE_OBJECT = 0x0000_0001'u32
ERROR_SUCCESS = 0x0000_0000'u32
ERROR_PATH_NOT_FOUND = 0x0000_0003'u32
SECURITY_DESCRIPTOR_MIN_LENGTH = 40
SECURITY_DESCRIPTOR_REVISION = 1'u32
ACCESS_ALLOWED_ACE_TYPE = 0x00'u8
SE_DACL_PROTECTED = 0x1000'u16
type
ACL {.pure, final.} = object
@ -65,6 +68,9 @@ type
mask: uint32
sidStart: uint32
SecDescriptorKind = enum
File, Folder
proc closeHandle(hobj: uint): int32 {.
importc: "CloseHandle", dynlib: "kernel32", stdcall, sideEffect.}
proc localFree(p: pointer): uint {.
@ -117,6 +123,10 @@ proc addAccessAllowedAceEx(pAcl: PACL, dwAceRevision: uint32,
sideEffect.}
proc getAce(pAcl: PACL, dwAceIndex: uint32, pAce: pointer): int32 {.
importc: "GetAce", dynlib: "advapi32", stdcall, sideEffect.}
proc setSecurityDescriptorControl(pSD: pointer, bitsOfInterest: uint16,
bitsToSet: uint16): int32 {.
importc: "SetSecurityDescriptorControl", dynlib: "advapi32", stdcall,
sideEffect.}
proc len*(sid: SID): int = len(sid.data)
@ -181,7 +191,7 @@ template getAddr*(sid: SID): pointer =
## Obtain Windows specific SID pointer.
unsafeAddr sid.data[0]
proc createCurrentUserOnlyAcl(): IoResult[seq[byte]] =
proc createCurrentUserOnlyAcl(kind: SecDescriptorKind): IoResult[seq[byte]] =
let aceMask = FILE_ALL_ACCESS
var userSid = ? getCurrentUserSid()
let size =
@ -193,7 +203,11 @@ proc createCurrentUserOnlyAcl(): IoResult[seq[byte]] =
if initializeAcl(pdacl, uint32(size), ACL_REVISION) == 0:
err(ioLastError())
else:
let aceFlags = OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
let aceFlags =
if kind == Folder:
OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
else:
0'u32
if addAccessAllowedAceEx(pdacl, ACL_REVISION, aceFlags,
aceMask, userSid.getAddr()) == 0:
err(ioLastError())
@ -204,7 +218,16 @@ proc setCurrentUserOnlyAccess*(path: string): IoResult[void] =
## Set file or folder with path ``path`` to be accessed only by current
## process' user. All other user's and user's group access will be
## prohibited.
var buffer = ? createCurrentUserOnlyAcl()
if not(fileAccessible(path, {})):
return err(IoErrorCode(ERROR_PATH_NOT_FOUND))
let descriptorKind =
if isDir(path):
Folder
else:
File
var buffer = ? createCurrentUserOnlyAcl(descriptorKind)
var pdacl = cast[PACL](addr buffer[0])
let dflags = DACL_SECURITY_INFORMATION or
@ -216,21 +239,33 @@ proc setCurrentUserOnlyAccess*(path: string): IoResult[void] =
else:
ok()
proc createCurrentUserOnlySecurityDescriptor*(): IoResult[SD] =
## Create security descriptor which can be used to limit access to resource
## to current process user.
var dacl = ? createCurrentUserOnlyAcl()
proc createUserOnlySecurityDescriptor(kind: SecDescriptorKind): IoResult[SD] =
var dacl = ? createCurrentUserOnlyAcl(kind)
var buffer = newSeq[byte](SECURITY_DESCRIPTOR_MIN_LENGTH)
if initializeSecurityDescriptor(addr buffer[0],
SECURITY_DESCRIPTOR_REVISION) == 0:
err(ioLastError())
else:
var res = SD(sddata: buffer, acldata: dacl)
if setSecurityDescriptorDacl(addr res.sddata[0], 1'i32,
addr res.acldata[0], 0'i32) == 0:
let bits = SE_DACL_PROTECTED
if setSecurityDescriptorControl(addr res.sddata[0], bits, bits) == 0:
err(ioLastError())
else:
ok(res)
if setSecurityDescriptorDacl(addr res.sddata[0], 1'i32,
addr res.acldata[0], 0'i32) == 0:
err(ioLastError())
else:
ok(res)
proc createFoldersUserOnlySecurityDescriptor*(): IoResult[SD] {.inline.} =
## Create security descriptor which can be used to restrict folder access to
## only the current process user.
createUserOnlySecurityDescriptor(Folder)
proc createFilesUserOnlySecurityDescriptor*(): IoResult[SD] {.inline.} =
## Create security descriptor which can be used to restrict file access to
## only the current process user.
createUserOnlySecurityDescriptor(File)
proc isEmpty*(sd: SD): bool =
## Returns ``true`` is security descriptor ``sd`` is not initialized.
@ -247,7 +282,6 @@ proc checkCurrentUserOnlyACL*(path: string): IoResult[bool] =
sdesc: pointer
pdacl: PACL
let aceFlags = OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
let userSid = ? getCurrentUserSid()
let gres = getNamedSecurityInfo(newWideCString(path), SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION, nil, nil,
@ -273,10 +307,17 @@ proc checkCurrentUserOnlyACL*(path: string): IoResult[bool] =
discard localFree(sdesc)
err(errCode)
else:
let expectedFlags =
if isDir(path):
OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
else:
0x00'u32
var psid = cast[pointer](addr ace.sidStart)
if isValidSid(psid) != 0:
if equalSid(psid, userSid.getAddr()) != 0:
if ace[].header.aceFlags == aceFlags and
if ace[].header.aceType == ACCESS_ALLOWED_ACE_TYPE and
ace[].header.aceFlags == expectedFlags and
ace[].mask == FILE_ALL_ACCESS:
ok(true)
else:

View File

@ -8,16 +8,27 @@ suite "Windows security descriptor tests suite":
test "File/Folder user-only ACL create/verify test":
when defined(windows):
proc performTest(path1: string, path2: string): IoResult[bool] =
var sd = ? createCurrentUserOnlySecurityDescriptor()
let path3 = path1 & "\\" & path1
let path4 = path1 & "\\" & path2
var sdd = ? createFoldersUserOnlySecurityDescriptor()
var sdf = ? createFilesUserOnlySecurityDescriptor()
# Create directory
? createPath(path1, secDescriptor = sd.getDescriptor())
# Create file
? writeFile(path2, "TESTBLOB", secDescriptor = sd.getDescriptor())
? createPath(path1, secDescriptor = sdd.getDescriptor())
# Create file outside of directory
? writeFile(path2, "TESTBLOB", secDescriptor = sdf.getDescriptor())
# Create directory inside of directory
? createPath(path3, secDescriptor = sdd.getDescriptor())
# Create file inside of directory
? writeFile(path4, "TESTLBOB", secDescriptor = sdf.getDescriptor())
let res1 = ? checkCurrentUserOnlyACL(path1)
let res2 = ? checkCurrentUserOnlyACL(path2)
let res3 = ? checkCurrentUserOnlyACL(path3)
let res4 = ? checkCurrentUserOnlyACL(path4)
? removeFile(path4)
? removeDir(path3)
? removeFile(path2)
? removeDir(path1)
if res1 and res2:
if res1 and res2 and res3 and res4:
ok(true)
else:
err(IoErrorCode(UserErrorCode))