security_framework/
access_control.rs

1//! Access Control support.
2
3use std::fmt;
4use std::ptr::{self, null};
5use crate::base::{Error, Result};
6use core_foundation::{declare_TCFType, impl_TCFType};
7use core_foundation::base::{kCFAllocatorDefault, CFOptionFlags, TCFType};
8use core_foundation::string::CFString;
9use security_framework_sys::access_control::{
10    kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
11    kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAttrAccessibleWhenUnlocked,
12    kSecAttrAccessibleWhenUnlockedThisDeviceOnly, SecAccessControlCreateWithFlags,
13    SecAccessControlGetTypeID,
14};
15use security_framework_sys::base::{errSecParam, SecAccessControlRef};
16
17declare_TCFType! {
18    /// A type representing sec access control settings.
19    SecAccessControl, SecAccessControlRef
20}
21impl_TCFType!(
22    SecAccessControl,
23    SecAccessControlRef,
24    SecAccessControlGetTypeID
25);
26
27unsafe impl Sync for SecAccessControl {}
28unsafe impl Send for SecAccessControl {}
29
30/// Specify when an item is available.
31pub enum ProtectionMode {
32    /// The data in the keychain can only be accessed when the device is
33    /// unlocked. Only available if a passcode is set on the device.
34    AccessibleWhenPasscodeSetThisDeviceOnly,
35    ///The data in the keychain item can be accessed only while the device is
36    /// unlocked by the user.
37    AccessibleWhenUnlockedThisDeviceOnly,
38    /// The data in the keychain item can be accessed only while the device is
39    /// unlocked by the user.
40    AccessibleWhenUnlocked,
41    /// The data in the keychain item cannot be accessed after a restart until
42    /// the device has been unlocked once by the user.
43    AccessibleAfterFirstUnlockThisDeviceOnly,
44    /// The data in the keychain item cannot be accessed after a restart until
45    /// the device has been unlocked once by the user.
46    AccessibleAfterFirstUnlock,
47}
48
49impl SecAccessControl {
50    /// Create `AccessControl` object from flags
51    pub fn create_with_flags(flags: CFOptionFlags) -> Result<Self> {
52        Self::create_with_protection(None, flags)
53    }
54
55    /// Create `AccessControl` object from a protection value and flags.
56    pub fn create_with_protection(protection: Option<ProtectionMode>, flags: CFOptionFlags) -> Result<Self> {
57        let protection_val = protection.map(|v| {
58            match v {
59                ProtectionMode::AccessibleWhenPasscodeSetThisDeviceOnly => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) },
60                ProtectionMode::AccessibleWhenUnlockedThisDeviceOnly => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenUnlockedThisDeviceOnly) },
61                ProtectionMode::AccessibleWhenUnlocked => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenUnlocked) },
62                ProtectionMode::AccessibleAfterFirstUnlockThisDeviceOnly => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) },
63                ProtectionMode::AccessibleAfterFirstUnlock => unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleAfterFirstUnlock) },
64            }
65        });
66        unsafe {
67            let access_control = SecAccessControlCreateWithFlags(
68                kCFAllocatorDefault,
69                protection_val.map(|v| v.as_CFTypeRef()).unwrap_or(null()),
70                flags,
71                ptr::null_mut(),
72            );
73            if access_control.is_null() {
74                Err(Error::from_code(errSecParam))
75            } else {
76                Ok(Self::wrap_under_create_rule(access_control))
77            }
78        }
79    }
80}
81
82impl fmt::Debug for SecAccessControl {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        f.debug_struct("SecAccessControl").finish_non_exhaustive()
85    }
86}