Skip to content

Commit 07b4602

Browse files
authored
Add KeyRing::get_persistent (#3)
* Add KeyRing::get_persistent * Update example to use search API * Improve doc commments and deny warnings * Ensure persistent User ring is different than the user ring * Update readme, bump version, add comments to example. Co-authored-by: landhb <[email protected]>
1 parent b016eff commit 07b4602

File tree

7 files changed

+81
-27
lines changed

7 files changed

+81
-27
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "linux-keyutils"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
edition = "2021"
55
authors = ["landhb <[email protected]>"]
66
description = """

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To use `linux-keyutils`, first add this to your `Cargo.toml`:
1212
linux_keyutils = "0.1"
1313
```
1414

15-
For more information please view the full [documentation](https://docs.rs/linux-keyutils).
15+
For more information please view the full [documentation](https://docs.rs/linux-keyutils). There is also a small example program in the [examples directory](examples/keyctl.rs).
1616

1717
## Features
1818

examples/keyctl.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
//!
44
//! Demo code for the linux_keyutils crate.
55
use clap::Parser;
6-
use linux_keyutils::{Key, KeyRing, KeyRingIdentifier, KeySerialId};
76
use linux_keyutils::{KeyPermissionsBuilder, Permission};
7+
use linux_keyutils::{KeyRing, KeyRingIdentifier};
88
use std::error::Error;
99
use zeroize::Zeroizing;
1010

@@ -28,12 +28,12 @@ enum Command {
2828
/// Read the secret from a key
2929
Read {
3030
#[clap(short, long)]
31-
id: i32,
31+
description: String,
3232
},
3333
/// Change ownership of a key
3434
Chown {
3535
#[clap(short, long)]
36-
id: i32,
36+
description: String,
3737

3838
#[clap(short, long)]
3939
uid: Option<u32>,
@@ -44,12 +44,12 @@ enum Command {
4444
/// Change permissions of a key
4545
Chmod {
4646
#[clap(short, long)]
47-
id: i32,
47+
description: String,
4848
},
4949
/// Invalidate a key
5050
Invalidate {
5151
#[clap(short, long)]
52-
id: i32,
52+
description: String,
5353
},
5454
}
5555

@@ -59,35 +59,48 @@ fn main() -> Result<(), Box<dyn Error>> {
5959
// Obtain the default User keyring for the current UID/user
6060
// See [KeyRingIdentifier] and `man 2 keyctl` for more information on default
6161
// keyrings for processes.
62-
let ring = KeyRing::from_special_id(KeyRingIdentifier::User, false)?;
62+
let ring = KeyRing::get_persistent(KeyRingIdentifier::User)?;
6363

6464
_ = match args.subcommand {
65+
// Add a new key to the keyring
6566
Command::Create {
6667
description,
6768
secret,
6869
} => {
6970
let key = ring.add_key(&description, &secret)?;
7071
println!("Created key with ID {:?}", key.get_id());
7172
}
72-
Command::Read { id } => {
73-
let key = Key::from_id(KeySerialId(id));
73+
// Search for an existing key by description and read the secret
74+
// data from the keyring
75+
Command::Read { description } => {
76+
let key = ring.search(&description)?;
7477
let mut buf = Zeroizing::new([0u8; 2048]);
7578
let len = key.read(&mut buf)?;
7679
println!("Secret {:?}", std::str::from_utf8(&buf[..len])?);
7780
}
78-
Command::Chown { id, uid, gid } => {
79-
let key = Key::from_id(KeySerialId(id));
81+
// Search for an existing key by description and attempt to
82+
// change ownership of the key
83+
Command::Chown {
84+
description,
85+
uid,
86+
gid,
87+
} => {
88+
let key = ring.search(&description)?;
8089
key.chown(uid, gid)?;
8190
}
82-
Command::Chmod { id } => {
83-
let key = Key::from_id(KeySerialId(id));
91+
// Search for an existing key by description and attempt to
92+
// change permissions of the key
93+
Command::Chmod { description } => {
94+
let key = ring.search(&description)?;
8495
let perms = KeyPermissionsBuilder::builder()
8596
.user(Permission::ALL)
8697
.build();
8798
key.set_perm(perms)?;
8899
}
89-
Command::Invalidate { id } => {
90-
let key = Key::from_id(KeySerialId(id));
100+
// Search for an existing key by description and attempt to
101+
// invalidate they key
102+
Command::Invalidate { description } => {
103+
let key = ring.search(&description)?;
91104
key.invalidate()?;
92105
}
93106
};

src/ffi/functions.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,25 @@ pub(crate) fn add_key(
2222
ktype: KeyType,
2323
keyring: libc::c_ulong,
2424
description: &str,
25-
payload: &[u8],
25+
payload: Option<&[u8]>,
2626
) -> Result<KeySerialId, KeyError> {
2727
// Perform conversion into a c string
2828
let description = CString::new(description).or(Err(KeyError::InvalidDescription))?;
2929

30+
// When creating keyrings the payload will be NULL
31+
let (payload, plen) = match payload {
32+
Some(p) => (p.as_ptr(), p.len()),
33+
None => (core::ptr::null(), 0),
34+
};
35+
3036
// Perform the actual system call
3137
let res = unsafe {
3238
libc::syscall(
3339
libc::SYS_add_key,
3440
Into::<&'static CStr>::into(ktype).as_ptr(),
3541
description.as_ptr(),
36-
payload.as_ptr(),
37-
payload.len() as libc::size_t,
42+
payload,
43+
plen as libc::size_t,
3844
keyring as u32,
3945
)
4046
};

src/key.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ impl Key {
155155
///
156156
/// The key is scheduled for garbage collection; it will no longer be findable,
157157
/// and will be unavailable for further operations. Further attempts to use the
158-
/// key will fail with the error EKEYREVOKED.
158+
/// key will fail with the error `EKEYREVOKED`.
159159
///
160160
/// The caller must have write or setattr permission on the key.
161161
pub fn revoke(&self) -> Result<(), KeyError> {

src/keyring.rs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ pub struct KeyRing {
1212
}
1313

1414
impl KeyRing {
15-
/// Create a new keyring with the given description
16-
pub fn create<D: AsRef<str> + ?Sized>(_description: &D) -> Result<Self, KeyError> {
17-
todo!()
18-
}
19-
2015
/// Obtain a KeyRing from its special identifier.
2116
///
2217
/// If the create argument is true, then this method will attempt
@@ -36,6 +31,36 @@ impl KeyRing {
3631
Ok(Self { id })
3732
}
3833

34+
/// Get the persistent keyring (persistent-keyring(7)) of the current user
35+
/// and link it to a specified keyring.
36+
///
37+
/// If the call is successful, a link to the persistent keyring is added to the
38+
/// keyring specified in the `link_with` argument.
39+
///
40+
/// The caller must have write permission on the keyring.
41+
///
42+
/// The persistent keyring will be created by the kernel if it does not yet exist.
43+
///
44+
/// Each time the [KeyRing::get_persistent] operation is performed, the persistent
45+
/// keyring will have its expiration timeout reset to the value in:
46+
///
47+
/// `/proc/sys/kernel/keys/persistent_keyring_expiry`
48+
///
49+
/// Should the timeout be reached, the persistent keyring will be removed and
50+
/// everything it pins can then be garbage collected.
51+
///
52+
/// Persistent keyrings were added to Linux in kernel version 3.13.
53+
pub fn get_persistent(link_with: KeyRingIdentifier) -> Result<Self, KeyError> {
54+
let id: KeySerialId = ffi::keyctl!(
55+
KeyCtlOperation::GetPersistent,
56+
u32::MAX as _,
57+
link_with as libc::c_ulong
58+
)?
59+
.try_into()
60+
.or(Err(KeyError::InvalidIdentifier))?;
61+
Ok(Self { id })
62+
}
63+
3964
/// Creates or updates a key of the given type and description, instantiates
4065
/// it with the payload of length plen, attaches it to the User keyring.
4166
///
@@ -53,7 +78,7 @@ impl KeyRing {
5378
KeyType::User,
5479
self.id.as_raw_id() as libc::c_ulong,
5580
description.as_ref(),
56-
secret.as_ref(),
81+
Some(secret.as_ref()),
5782
)?;
5883
Ok(Key::from_id(id))
5984
}
@@ -154,6 +179,16 @@ mod test {
154179
assert!(ring.id.as_raw_id() > 0);
155180
}
156181

182+
#[test]
183+
fn tet_get_persistent() {
184+
// Test that a keyring that should already exist is returned
185+
let user_ring = KeyRing::from_special_id(KeyRingIdentifier::User, false).unwrap();
186+
assert!(user_ring.id.as_raw_id() > 0);
187+
188+
let user_perm_ring = KeyRing::get_persistent(KeyRingIdentifier::User).unwrap();
189+
assert_ne!(user_ring.id.as_raw_id(), user_perm_ring.id.as_raw_id());
190+
}
191+
157192
#[test]
158193
fn test_search_existing_key() {
159194
// Test that a keyring that normally doesn't exist by default is

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
//! }
5555
//! ```
5656
#![cfg_attr(not(feature = "std"), no_std)]
57-
//#![deny(warnings)]
57+
#![deny(warnings)]
5858

5959
// no_std CStr/CString support stabilized in Rust 1.64.0
6060
// CString requires alloc however

0 commit comments

Comments
 (0)