use bitflags::bitflags;
use std::{
ffi::{OsStr, c_void},
io,
ops::Deref,
os::windows::io::AsRawHandle,
ptr,
};
use windows_sys::Win32::{
Foundation::{ERROR_SUCCESS, LocalFree},
Security::{
ACL,
Authorization::{
GetNamedSecurityInfoW, GetSecurityInfo, SE_FILE_OBJECT, SE_KERNEL_OBJECT, SE_LMSHARE,
SE_PRINTER, SE_REGISTRY_KEY, SE_SERVICE, SE_UNKNOWN_OBJECT_TYPE, SE_WINDOW_OBJECT,
SE_WMIGUID_OBJECT,
},
DACL_SECURITY_INFORMATION, GROUP_SECURITY_INFORMATION, IsWellKnownSid,
OWNER_SECURITY_INFORMATION, PSID, SACL_SECURITY_INFORMATION, SECURITY_DESCRIPTOR,
SECURITY_MAX_SID_SIZE, WinAccountAdministratorSid, WinAccountCertAdminsSid,
WinAccountCloneableControllersSid, WinAccountComputersSid, WinAccountControllersSid,
WinAccountDefaultSystemManagedSid, WinAccountDomainAdminsSid, WinAccountDomainGuestsSid,
WinAccountDomainUsersSid, WinAccountEnterpriseAdminsSid, WinAccountEnterpriseKeyAdminsSid,
WinAccountGuestSid, WinAccountKeyAdminsSid, WinAccountKrbtgtSid, WinAccountPolicyAdminsSid,
WinAccountProtectedUsersSid, WinAccountRasAndIasServersSid,
WinAccountReadonlyControllersSid, WinAnonymousSid, WinApplicationPackageAuthoritySid,
WinAuthenticatedUserSid, WinAuthenticationAuthorityAssertedSid,
WinAuthenticationFreshKeyAuthSid, WinAuthenticationKeyPropertyAttestationSid,
WinAuthenticationKeyPropertyMFASid, WinAuthenticationKeyTrustSid,
WinAuthenticationServiceAssertedSid, WinBatchSid,
WinBuiltinAccessControlAssistanceOperatorsSid, WinBuiltinAccountOperatorsSid,
WinBuiltinAdministratorsSid, WinBuiltinAnyPackageSid, WinBuiltinAuthorizationAccessSid,
WinBuiltinBackupOperatorsSid, WinBuiltinCertSvcDComAccessGroup,
WinBuiltinCryptoOperatorsSid, WinBuiltinDCOMUsersSid,
WinBuiltinDefaultSystemManagedGroupSid, WinBuiltinDeviceOwnersSid, WinBuiltinDomainSid,
WinBuiltinEventLogReadersGroup, WinBuiltinGuestsSid, WinBuiltinHyperVAdminsSid,
WinBuiltinIUsersSid, WinBuiltinIncomingForestTrustBuildersSid,
WinBuiltinNetworkConfigurationOperatorsSid, WinBuiltinPerfLoggingUsersSid,
WinBuiltinPerfMonitoringUsersSid, WinBuiltinPowerUsersSid,
WinBuiltinPreWindows2000CompatibleAccessSid, WinBuiltinPrintOperatorsSid,
WinBuiltinRDSEndpointServersSid, WinBuiltinRDSManagementServersSid,
WinBuiltinRDSRemoteAccessServersSid, WinBuiltinRemoteDesktopUsersSid,
WinBuiltinRemoteManagementUsersSid, WinBuiltinReplicatorSid,
WinBuiltinStorageReplicaAdminsSid, WinBuiltinSystemOperatorsSid,
WinBuiltinTerminalServerLicenseServersSid, WinBuiltinUsersSid,
WinCacheablePrincipalsGroupSid, WinCapabilityAppointmentsSid, WinCapabilityContactsSid,
WinCapabilityDocumentsLibrarySid, WinCapabilityEnterpriseAuthenticationSid,
WinCapabilityInternetClientServerSid, WinCapabilityInternetClientSid,
WinCapabilityMusicLibrarySid, WinCapabilityPicturesLibrarySid,
WinCapabilityPrivateNetworkClientServerSid, WinCapabilityRemovableStorageSid,
WinCapabilitySharedUserCertificatesSid, WinCapabilityVideosLibrarySid, WinConsoleLogonSid,
WinCreatorGroupServerSid, WinCreatorGroupSid, WinCreatorOwnerRightsSid,
WinCreatorOwnerServerSid, WinCreatorOwnerSid, WinDialupSid, WinDigestAuthenticationSid,
WinEnterpriseControllersSid, WinEnterpriseReadonlyControllersSid, WinHighLabelSid,
WinIUserSid, WinInteractiveSid, WinLocalAccountAndAdministratorSid, WinLocalAccountSid,
WinLocalLogonSid, WinLocalServiceSid, WinLocalSid, WinLocalSystemSid, WinLogonIdsSid,
WinLowLabelSid, WinMediumLabelSid, WinMediumPlusLabelSid, WinNTLMAuthenticationSid,
WinNetworkServiceSid, WinNetworkSid, WinNewEnterpriseReadonlyControllersSid,
WinNonCacheablePrincipalsGroupSid, WinNtAuthoritySid, WinNullSid, WinOtherOrganizationSid,
WinProxySid, WinRemoteLogonIdSid, WinRestrictedCodeSid, WinSChannelAuthenticationSid,
WinSelfSid, WinServiceSid, WinSystemLabelSid, WinTerminalServerSid,
WinThisOrganizationCertificateSid, WinThisOrganizationSid, WinUntrustedLabelSid,
WinUserModeDriversSid, WinWorldSid, WinWriteRestrictedCodeSid,
},
};
use crate::util::string_to_null_terminated_utf16;
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ObjectType {
Unknown = SE_UNKNOWN_OBJECT_TYPE,
File = SE_FILE_OBJECT,
Service = SE_SERVICE,
Printer = SE_PRINTER,
RegistryKey = SE_REGISTRY_KEY,
LmShare = SE_LMSHARE,
KernelObject = SE_KERNEL_OBJECT,
WindowObject = SE_WINDOW_OBJECT,
WmiGuidObject = SE_WMIGUID_OBJECT,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SecurityInformation: u32 {
const OWNER = OWNER_SECURITY_INFORMATION;
const GROUP = GROUP_SECURITY_INFORMATION;
const DACL = DACL_SECURITY_INFORMATION;
const SACL = SACL_SECURITY_INFORMATION;
}
}
pub fn get_security_info<T: AsRawHandle>(
handle: &T,
object_type: ObjectType,
info: SecurityInformation,
) -> io::Result<SecurityInfo> {
SecurityInfo::from_handle(handle, object_type, info)
}
pub fn get_named_security_info(
name: impl AsRef<OsStr>,
object_type: ObjectType,
info: SecurityInformation,
) -> io::Result<SecurityInfo> {
SecurityInfo::from_name(name, object_type, info)
}
pub struct SecurityInfo {
owner: Option<&'static Sid>,
group: Option<&'static Sid>,
security_descriptor: *mut SECURITY_DESCRIPTOR,
}
impl SecurityInfo {
fn from_handle<T: AsRawHandle>(
handle: &T,
object_type: ObjectType,
info: SecurityInformation,
) -> io::Result<SecurityInfo> {
Self::new_inner(|owner_ptr, group_ptr, dacl_ptr, sacl_ptr, sd_ptr| {
unsafe {
GetSecurityInfo(
handle.as_raw_handle(),
object_type as i32,
info.bits(),
owner_ptr,
group_ptr,
dacl_ptr,
sacl_ptr,
sd_ptr as *mut *mut c_void,
)
}
})
}
fn from_name(
name: impl AsRef<OsStr>,
object_type: ObjectType,
info: SecurityInformation,
) -> io::Result<SecurityInfo> {
let name_wide: Vec<u16> = string_to_null_terminated_utf16(name);
Self::new_inner(|owner_ptr, group_ptr, dacl_ptr, sacl_ptr, sd_ptr| {
unsafe {
GetNamedSecurityInfoW(
name_wide.as_ptr(),
object_type as i32,
info.bits(),
owner_ptr,
group_ptr,
dacl_ptr,
sacl_ptr,
sd_ptr as *mut *mut c_void,
)
}
})
}
fn new_inner(
make_descriptor: impl FnOnce(
*mut PSID,
*mut PSID,
*mut *mut ACL,
*mut *mut ACL,
*mut *mut SECURITY_DESCRIPTOR,
) -> u32,
) -> io::Result<Self> {
let mut security_descriptor: *mut SECURITY_DESCRIPTOR = ptr::null_mut();
let mut owner: PSID = ptr::null_mut();
let mut group: PSID = ptr::null_mut();
let mut dacl: *mut ACL = ptr::null_mut();
let mut sacl: *mut ACL = ptr::null_mut();
let result = make_descriptor(
&mut owner,
&mut group,
&mut dacl,
&mut sacl,
&mut security_descriptor,
);
if result != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(result as i32));
}
let _ = dacl;
let _ = sacl;
Ok(SecurityInfo {
owner: if owner.is_null() {
None
} else {
Some(unsafe { Sid::new(owner) })
},
group: if group.is_null() {
None
} else {
Some(unsafe { Sid::new(group) })
},
security_descriptor,
})
}
pub fn owner(&self) -> Option<&Sid> {
self.owner
}
pub fn group(&self) -> Option<&Sid> {
self.group
}
}
impl Drop for SecurityInfo {
fn drop(&mut self) {
unsafe { LocalFree(self.security_descriptor.cast()) };
}
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WellKnownSidType {
Null = WinNullSid,
World = WinWorldSid,
Local = WinLocalSid,
CreatorOwner = WinCreatorOwnerSid,
CreatorGroup = WinCreatorGroupSid,
CreatorOwnerServerSid = WinCreatorOwnerServerSid,
CreatorGroupServerSid = WinCreatorGroupServerSid,
NtAuthority = WinNtAuthoritySid,
Dialup = WinDialupSid,
Network = WinNetworkSid,
Batch = WinBatchSid,
Interactive = WinInteractiveSid,
Service = WinServiceSid,
Anonymous = WinAnonymousSid,
Proxy = WinProxySid,
EnterpriseDomainControllers = WinEnterpriseControllersSid,
Principal = WinSelfSid,
AuthenticatedUser = WinAuthenticatedUserSid,
RestrictedCode = WinRestrictedCodeSid,
TerminalServer = WinTerminalServerSid,
RemoteLogonId = WinRemoteLogonIdSid,
LoginIds = WinLogonIdsSid,
LocalSystem = WinLocalSystemSid,
LocalService = WinLocalServiceSid,
NetworkService = WinNetworkServiceSid,
BuiltinDomain = WinBuiltinDomainSid,
BuiltinAdministrators = WinBuiltinAdministratorsSid,
BuiltinUsers = WinBuiltinUsersSid,
BuiltinGuests = WinBuiltinGuestsSid,
BuiltinPowerUsers = WinBuiltinPowerUsersSid,
BuiltinAccountOperators = WinBuiltinAccountOperatorsSid,
BuiltinSystemOperators = WinBuiltinSystemOperatorsSid,
BuiltinPrintOperators = WinBuiltinPrintOperatorsSid,
BuiltinBackupOperators = WinBuiltinBackupOperatorsSid,
BuiltinReplicator = WinBuiltinReplicatorSid,
BuiltinPreWindows2000CompatibleAccess = WinBuiltinPreWindows2000CompatibleAccessSid,
BuiltinRemoteDesktopUsers = WinBuiltinRemoteDesktopUsersSid,
BuiltinNetworkConfigurationOperators = WinBuiltinNetworkConfigurationOperatorsSid,
AccountAdministrator = WinAccountAdministratorSid,
AccountGuest = WinAccountGuestSid,
AccountKrbtgt = WinAccountKrbtgtSid,
AccountDomainAdmins = WinAccountDomainAdminsSid,
AccountDomainUsers = WinAccountDomainUsersSid,
AccountDomainGuests = WinAccountDomainGuestsSid,
AccountComputers = WinAccountComputersSid,
AccountControllers = WinAccountControllersSid,
AccountCertAdmins = WinAccountCertAdminsSid,
AccountEnterpriseAdmins = WinAccountEnterpriseAdminsSid,
AccountPolicyAdmins = WinAccountPolicyAdminsSid,
AccountRasAndIasServers = WinAccountRasAndIasServersSid,
NtlmAuthentication = WinNTLMAuthenticationSid,
DigestAuthentication = WinDigestAuthenticationSid,
SChannelAuthentication = WinSChannelAuthenticationSid,
ThisOrganization = WinThisOrganizationSid,
OtherOrganization = WinOtherOrganizationSid,
BuiltinIncomingForestTrustBuilders = WinBuiltinIncomingForestTrustBuildersSid,
BuiltinPerfMonitoringUsers = WinBuiltinPerfMonitoringUsersSid,
BuiltinPerfLoggingUsers = WinBuiltinPerfLoggingUsersSid,
BuiltinAuthorizationAccess = WinBuiltinAuthorizationAccessSid,
BuiltinTerminalServerLicenseServers = WinBuiltinTerminalServerLicenseServersSid,
BuiltinDcomUsers = WinBuiltinDCOMUsersSid,
BuiltinIUsers = WinBuiltinIUsersSid,
IUser = WinIUserSid,
BuiltinCryptoOperators = WinBuiltinCryptoOperatorsSid,
UntrustedLabel = WinUntrustedLabelSid,
LowLabel = WinLowLabelSid,
MediumLabel = WinMediumLabelSid,
HighLabel = WinHighLabelSid,
SystemLabel = WinSystemLabelSid,
WriteRestrictedCode = WinWriteRestrictedCodeSid,
CreatorOwnerRights = WinCreatorOwnerRightsSid,
CacheablePrincipalsGroup = WinCacheablePrincipalsGroupSid,
NonCacheablePrincipalsGroup = WinNonCacheablePrincipalsGroupSid,
EnterpriseReadonlyControllers = WinEnterpriseReadonlyControllersSid,
AccountReadonlyControllers = WinAccountReadonlyControllersSid,
BuiltinEventLogReaders = WinBuiltinEventLogReadersGroup,
NewEnterpriseReadonlyControllers = WinNewEnterpriseReadonlyControllersSid,
BuiltinCertSvcDComAccess = WinBuiltinCertSvcDComAccessGroup,
MediumPlusLabel = WinMediumPlusLabelSid,
LocalLogon = WinLocalLogonSid,
ConsoleLogon = WinConsoleLogonSid,
ThisOrganizationCertificate = WinThisOrganizationCertificateSid,
ApplicationPackageAuthority = WinApplicationPackageAuthoritySid,
BuiltinAnyPackage = WinBuiltinAnyPackageSid,
CapabilityInternetClient = WinCapabilityInternetClientSid,
CapabilityInternetClientServer = WinCapabilityInternetClientServerSid,
CapabilityPrivateNetworkClientServer = WinCapabilityPrivateNetworkClientServerSid,
CapabilityPicturesLibrary = WinCapabilityPicturesLibrarySid,
CapabilityVideosLibrary = WinCapabilityVideosLibrarySid,
CapabilityMusicLibrary = WinCapabilityMusicLibrarySid,
CapabilityDocumentsLibrary = WinCapabilityDocumentsLibrarySid,
CapabilitySharedUserCertificates = WinCapabilitySharedUserCertificatesSid,
CapabilityEnterpriseAuthentication = WinCapabilityEnterpriseAuthenticationSid,
CapabilityRemovableStorage = WinCapabilityRemovableStorageSid,
BuiltinRDSRemoteAccessServers = WinBuiltinRDSRemoteAccessServersSid,
BuiltinRDSEndpointServers = WinBuiltinRDSEndpointServersSid,
BuiltinRDSManagementServers = WinBuiltinRDSManagementServersSid,
UserModeDrivers = WinUserModeDriversSid,
BuiltinHyperVAdmins = WinBuiltinHyperVAdminsSid,
AccountCloneableControllers = WinAccountCloneableControllersSid,
BuiltinAccessControlAssistanceOperators = WinBuiltinAccessControlAssistanceOperatorsSid,
BuiltinRemoteManagementUsers = WinBuiltinRemoteManagementUsersSid,
AuthenticationAuthorityAsserted = WinAuthenticationAuthorityAssertedSid,
AuthenticationServiceAsserted = WinAuthenticationServiceAssertedSid,
LocalAccount = WinLocalAccountSid,
LocalAccountAndAdministrator = WinLocalAccountAndAdministratorSid,
AccountProtectedUsers = WinAccountProtectedUsersSid,
CapabilityAppointments = WinCapabilityAppointmentsSid,
CapabilityContacts = WinCapabilityContactsSid,
AccountDefaultSystemManaged = WinAccountDefaultSystemManagedSid,
BuiltinDefaultSystemManagedGroup = WinBuiltinDefaultSystemManagedGroupSid,
BuiltinStorageReplicaAdmins = WinBuiltinStorageReplicaAdminsSid,
AccountKeyAdmins = WinAccountKeyAdminsSid,
AccountEnterpriseKeyAdmins = WinAccountEnterpriseKeyAdminsSid,
AuthenticationKeyTrust = WinAuthenticationKeyTrustSid,
AuthenticationKeyPropertyMFA = WinAuthenticationKeyPropertyMFASid,
AuthenticationKeyPropertyAttestation = WinAuthenticationKeyPropertyAttestationSid,
AuthenticationFreshKeyAuth = WinAuthenticationFreshKeyAuthSid,
BuiltinDeviceOwners = WinBuiltinDeviceOwnersSid,
}
pub fn is_well_known_sid(sid: &Sid, sid_type: WellKnownSidType) -> bool {
sid.is_well_known_sid(sid_type)
}
#[repr(transparent)]
pub struct Sid {
sid: PSID,
}
impl Sid {
pub unsafe fn new<'a>(sid: PSID) -> &'a Self {
let ppsid = &sid as *const PSID;
unsafe { &*(ppsid.cast()) }
}
pub fn is_well_known_sid(&self, sid_type: WellKnownSidType) -> bool {
unsafe { IsWellKnownSid(self.sid, sid_type as i32) != 0 }
}
}
impl AsRawHandle for Sid {
fn as_raw_handle(&self) -> *mut c_void {
self.sid
}
}
pub fn create_well_known_sid(sid_type: WellKnownSidType) -> io::Result<OwnedSid> {
OwnedSid::create_well_known(sid_type)
}
pub struct OwnedSid {
sid: Vec<u8>,
}
impl OwnedSid {
fn create_well_known(sid_type: WellKnownSidType) -> io::Result<Self> {
use windows_sys::Win32::Security::CreateWellKnownSid;
let mut sid_size = SECURITY_MAX_SID_SIZE;
let mut sid_buffer = vec![0u8; sid_size as usize];
let result = unsafe {
CreateWellKnownSid(
sid_type as i32,
ptr::null_mut(),
sid_buffer.as_mut_ptr() as PSID,
&mut sid_size,
)
};
if result == 0 {
return Err(io::Error::last_os_error());
}
sid_buffer.truncate(sid_size as usize);
Ok(OwnedSid { sid: sid_buffer })
}
fn as_sid(&self) -> &Sid {
unsafe { Sid::new(self.sid.as_ptr() as PSID) }
}
}
impl Deref for OwnedSid {
type Target = Sid;
fn deref(&self) -> &Self::Target {
self.as_sid()
}
}
#[repr(i32)]
pub enum ImpersonationLevel {
Anonymous,
Identification,
Impersonation,
Delegation,
}
pub fn impersonate_self(level: ImpersonationLevel) -> io::Result<()> {
use windows_sys::Win32::Security::ImpersonateSelf;
let result = unsafe { ImpersonateSelf(level as i32) };
if result == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
pub fn revert_to_self() -> io::Result<()> {
use windows_sys::Win32::Security::RevertToSelf;
let result = unsafe { RevertToSelf() };
if result == 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[cfg(test)]
mod tests {
use std::os::windows::fs::OpenOptionsExt;
use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS;
use super::*;
#[test]
fn test_well_known_sid() {
let admin_sid = create_well_known_sid(WellKnownSidType::BuiltinAdministrators)
.expect("Failed to create well-known SID");
let admin_sid_ref = admin_sid.as_sid();
assert!(admin_sid_ref.is_well_known_sid(WellKnownSidType::BuiltinAdministrators));
assert!(!admin_sid_ref.is_well_known_sid(WellKnownSidType::LocalSystem));
}
#[test]
fn test_security_info_handle() {
let path = std::fs::File::options()
.read(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.open(r"C:\Windows\Temp")
.unwrap();
let temp_info = get_security_info(&path, ObjectType::File, SecurityInformation::OWNER)
.expect("Failed to get security info by name");
let owner = temp_info.owner().unwrap();
assert!(
owner.is_well_known_sid(WellKnownSidType::LocalSystem)
|| owner.is_well_known_sid(WellKnownSidType::BuiltinAdministrators)
);
}
}