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

View File

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