security_framework/
access_control.rs

1//! Access Control support.
2
3use crate::base::{Error, Result};
4use core_foundation::base::{kCFAllocatorDefault, CFOptionFlags, TCFType};
5use core_foundation::string::CFString;
6use core_foundation::{declare_TCFType, impl_TCFType};
7use security_framework_sys::access_control::{
8    kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
9    kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAttrAccessibleWhenUnlocked,
10    kSecAttrAccessibleWhenUnlockedThisDeviceOnly, SecAccessControlCreateWithFlags,
11    SecAccessControlGetTypeID,
12};
13use security_framework_sys::base::{errSecParam, SecAccessControlRef};
14use std::fmt;
15use std::ptr;
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        }).unwrap_or_else(|| {
66            unsafe { CFString::wrap_under_get_rule(kSecAttrAccessibleWhenUnlocked) }
67        });
68        unsafe {
69            let access_control = SecAccessControlCreateWithFlags(
70                kCFAllocatorDefault,
71                protection_val.as_CFTypeRef(),
72                flags,
73                ptr::null_mut(),
74            );
75            if access_control.is_null() {
76                Err(Error::from_code(errSecParam))
77            } else {
78                Ok(Self::wrap_under_create_rule(access_control))
79            }
80        }
81    }
82}
83
84impl fmt::Debug for SecAccessControl {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        f.debug_struct("SecAccessControl").finish_non_exhaustive()
87    }
88}