linux_keyutils/
links.rs

1//! Helper types for iterating over keyring entries
2//!
3use crate::utils::Vec;
4use crate::{Key, KeyError, KeyRing, KeySerialId, KeyType, Metadata};
5use core::cmp::PartialEq;
6use core::ops::Deref;
7
8/// An item/node linked to a ring. Both keys and other keyrings
9/// can be linked to a particular keyring.
10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
11pub enum LinkNode {
12    KeyRing(KeyRing),
13    Key(Key),
14}
15
16/// A collection of LinkNodes, returned from [KeyRing::get_links]
17///
18/// For example:
19///
20/// ```
21/// use linux_keyutils::{Key, KeyRing, KeyRingIdentifier, KeyError};
22///
23/// // Test if a particular Key is linked to the user session KeyRing
24/// fn is_linked_to_user_session(key: &Key) -> Result<bool, KeyError> {
25///     // Get the  keyring
26///     let ring = KeyRing::from_special_id(KeyRingIdentifier::UserSession, false)?;
27///
28///     // Locate all the links
29///     let links = ring.get_links(200)?;
30///
31///     // Determine if the key is linked to the ring
32///     Ok(links.contains(key))
33/// }
34/// ```
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct Links(Vec<LinkNode>);
37
38impl PartialEq<Key> for LinkNode {
39    fn eq(&self, other: &Key) -> bool {
40        matches!(self, LinkNode::Key(x) if x == other)
41    }
42}
43
44impl PartialEq<Key> for &LinkNode {
45    fn eq(&self, other: &Key) -> bool {
46        matches!(self, LinkNode::Key(x) if x == other)
47    }
48}
49
50impl PartialEq<KeyRing> for LinkNode {
51    fn eq(&self, other: &KeyRing) -> bool {
52        matches!(self, LinkNode::KeyRing(x) if x == other)
53    }
54}
55
56impl PartialEq<KeyRing> for &LinkNode {
57    fn eq(&self, other: &KeyRing) -> bool {
58        matches!(self, LinkNode::KeyRing(x) if x == other)
59    }
60}
61
62impl LinkNode {
63    /// Internal method to construct a LinkNode from a raw ID
64    pub(crate) fn from_id(id: KeySerialId) -> Result<Self, KeyError> {
65        let metadata = Metadata::from_id(id)?;
66        let node = match metadata.get_type() {
67            KeyType::KeyRing => Self::KeyRing(KeyRing::from_id(id)),
68            KeyType::User => Self::Key(Key::from_id(id)),
69            _ => return Err(KeyError::OperationNotSupported),
70        };
71        Ok(node)
72    }
73
74    /// Attempt to convert this LinkNode to a Key
75    ///
76    /// Returns the key if the entry is a Key, None otherwise.
77    pub fn as_key(&self) -> Option<Key> {
78        match self {
79            Self::Key(inner) => Some(*inner),
80            _ => None,
81        }
82    }
83
84    /// Attempt to convert this LinkNode to a KeyRing
85    ///
86    /// Returns the ring if the entry is a KeyRing, None otherwise.
87    pub fn as_ring(&self) -> Option<KeyRing> {
88        match self {
89            Self::KeyRing(inner) => Some(*inner),
90            _ => None,
91        }
92    }
93}
94
95impl Deref for Links {
96    type Target = Vec<LinkNode>;
97
98    fn deref(&self) -> &Self::Target {
99        &self.0
100    }
101}
102
103impl FromIterator<LinkNode> for Links {
104    fn from_iter<T>(iter: T) -> Self
105    where
106        T: IntoIterator<Item = LinkNode>,
107    {
108        Self(iter.into_iter().collect())
109    }
110}
111
112impl Links {
113    /// Internal constructor to abstract the list of objects
114    pub fn new(inner: Vec<LinkNode>) -> Self {
115        Self(inner)
116    }
117
118    /// Obtain the entry with the provided ID/Key/Keyring
119    pub fn get<T>(&self, entry: &T) -> Option<&LinkNode>
120    where
121        LinkNode: PartialEq<T>,
122    {
123        self.0.iter().find(|v| *v == entry)
124    }
125
126    /// Check if the list contains the provided ID/Key/Keyring
127    pub fn contains<T>(&self, entry: &T) -> bool
128    where
129        LinkNode: PartialEq<T>,
130    {
131        self.0.iter().any(|v| v == entry)
132    }
133}