Mercurial > crates > nonstick
comparison src/libpam/environ.rs @ 141:a508a69c068a
Remove a lot of Results from functions.
Many functions are documented to only return failing Results when given
improper inputs or when there is a memory allocation failure (which
can be verified by looking at the source). In cases where we know our
input is correct, we don't need to check for memory allocation errors
for the same reason that Rust doesn't do so when you, e.g., create a
new Vec.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 05 Jul 2025 17:16:56 -0400 |
parents | 33b9622ed6d2 |
children | ebb71a412b58 |
comparison
equal
deleted
inserted
replaced
140:add7228adb2f | 141:a508a69c068a |
---|---|
1 use crate::constants::{ErrorCode, Result}; | |
2 use crate::environ::{EnvironMap, EnvironMapMut}; | 1 use crate::environ::{EnvironMap, EnvironMapMut}; |
3 use crate::libpam::memory::CHeapString; | 2 use crate::libpam::memory::{CHeapBox, CHeapString}; |
4 use crate::libpam::{memory, LibPamHandle}; | 3 use crate::libpam::{memory, RawPamHandle}; |
5 use std::ffi::{c_char, CStr, CString, OsStr, OsString}; | 4 use std::ffi::{c_char, CStr, CString, OsStr, OsString}; |
6 use std::marker::PhantomData; | 5 use std::marker::PhantomData; |
7 use std::os::unix::ffi::{OsStrExt, OsStringExt}; | 6 use std::os::unix::ffi::{OsStrExt, OsStringExt}; |
8 use std::ptr; | 7 use std::ptr; |
9 use std::ptr::NonNull; | 8 use std::ptr::NonNull; |
10 | 9 |
11 pub struct LibPamEnviron<'a> { | 10 impl RawPamHandle { |
12 source: &'a LibPamHandle, | |
13 } | |
14 | |
15 pub struct LibPamEnvironMut<'a> { | |
16 source: &'a mut LibPamHandle, | |
17 } | |
18 | |
19 impl LibPamHandle { | |
20 fn environ_get(&self, key: &OsStr) -> Option<OsString> { | 11 fn environ_get(&self, key: &OsStr) -> Option<OsString> { |
21 let key = CString::new(key.as_bytes()).ok()?; | 12 let key = CString::new(key.as_bytes()).ok()?; |
22 // SAFETY: We are a valid handle and are calling with a good key. | 13 // SAFETY: We are a valid handle and are calling with a good key. |
23 unsafe { copy_env(libpam_sys::pam_getenv(self.0.as_ref(), key.as_ptr())) } | 14 let src = unsafe { libpam_sys::pam_getenv(self.raw_ref(), key.as_ptr()) }; |
24 } | 15 let val = match NonNull::new(src) { |
25 | 16 None => return None, |
26 fn environ_set(&mut self, key: &OsStr, value: Option<&OsStr>) -> Result<Option<OsString>> { | 17 Some(ptr) => ptr.as_ptr(), |
18 }; | |
19 // SAFETY: We were just returned this string from PAM. | |
20 // We have to trust it. | |
21 let c_str = unsafe { CStr::from_ptr(val) }; | |
22 Some(OsString::from_vec(c_str.to_bytes().to_vec())) | |
23 } | |
24 | |
25 fn environ_set(&mut self, key: &OsStr, value: Option<&OsStr>) -> Option<OsString> { | |
27 let old = self.environ_get(key); | 26 let old = self.environ_get(key); |
28 if old.is_none() && value.is_none() { | 27 if old.is_none() && value.is_none() { |
29 // pam_putenv returns an error if we try to remove a non-existent | 28 // pam_putenv returns an error if we try to remove a non-existent |
30 // environment variable, so just avoid that entirely. | 29 // environment variable, so just avoid that entirely. |
31 return Ok(None); | 30 return None; |
32 } | 31 } |
33 let total_len = key.len() + value.map(OsStr::len).unwrap_or_default() + 2; | 32 let total_len = key.len() + value.map(OsStr::len).unwrap_or_default() + 2; |
34 let mut result = Vec::with_capacity(total_len); | 33 let mut result = Vec::with_capacity(total_len); |
35 result.extend(key.as_bytes()); | 34 result.extend(key.as_bytes()); |
36 if let Some(value) = value { | 35 if let Some(value) = value { |
37 result.push(b'='); | 36 result.push(b'='); |
38 result.extend(value.as_bytes()); | 37 result.extend(value.as_bytes()); |
39 } | 38 } |
40 let put = CString::new(result).map_err(|_| ErrorCode::ConversationError)?; | 39 let put = CString::new(result).unwrap(); |
41 // SAFETY: This is a valid handle and a valid environment string. | 40 // SAFETY: This is a valid handle and a valid environment string. |
42 ErrorCode::result_from(unsafe { libpam_sys::pam_putenv(self.0.as_mut(), put.as_ptr()) })?; | 41 // pam_putenv is only ever going to |
43 Ok(old) | 42 let _ = unsafe { libpam_sys::pam_putenv(self.raw_mut(), put.as_ptr()) }; |
44 } | 43 old |
45 | 44 } |
46 fn environ_iter(&self) -> Result<impl Iterator<Item = (OsString, OsString)>> { | 45 |
46 fn environ_iter(&self) -> impl Iterator<Item = (OsString, OsString)> { | |
47 // SAFETY: This is a valid PAM handle. It will return valid data. | 47 // SAFETY: This is a valid PAM handle. It will return valid data. |
48 unsafe { | 48 unsafe { |
49 NonNull::new(libpam_sys::pam_getenvlist(self.0.as_ref())) | 49 NonNull::new(libpam_sys::pam_getenvlist(self.raw_ref())) |
50 .map(|ptr| EnvList::from_ptr(ptr.cast())) | 50 .map(|ptr| EnvList::from_ptr(ptr.cast())) |
51 .ok_or(ErrorCode::BufferError) | 51 .unwrap_or_else(EnvList::empty) |
52 } | 52 } |
53 } | 53 } |
54 } | 54 } |
55 | 55 |
56 /// Copies the data of the given C string pointer to an OsString, | 56 /// A view to the environment stored in a PAM handle. |
57 /// or None if src is null. | 57 pub struct LibPamEnviron<'a> { |
58 unsafe fn copy_env(src: *const c_char) -> Option<OsString> { | 58 source: &'a RawPamHandle, |
59 let val = match NonNull::new(src.cast_mut()) { | 59 } |
60 None => return None, | 60 |
61 Some(ptr) => ptr.as_ptr(), | 61 /// A mutable view to the environment stored in a PAM handle. |
62 }; | 62 pub struct LibPamEnvironMut<'a> { |
63 // SAFETY: We were just returned this string from PAM. | 63 source: &'a mut RawPamHandle, |
64 // We have to trust it. | |
65 let c_str = unsafe { CStr::from_ptr(val) }; | |
66 Some(OsString::from_vec(c_str.to_bytes().to_vec())) | |
67 } | 64 } |
68 | 65 |
69 impl<'a> LibPamEnviron<'a> { | 66 impl<'a> LibPamEnviron<'a> { |
70 pub fn new(source: &'a LibPamHandle) -> Self { | 67 pub fn new(source: &'a RawPamHandle) -> Self { |
71 Self { source } | 68 Self { source } |
72 } | 69 } |
73 } | 70 } |
74 | 71 |
75 impl<'a> LibPamEnvironMut<'a> { | 72 impl<'a> LibPamEnvironMut<'a> { |
76 pub fn new(source: &'a mut LibPamHandle) -> Self { | 73 pub fn new(source: &'a mut RawPamHandle) -> Self { |
77 Self { source } | 74 Self { source } |
78 } | 75 } |
79 } | 76 } |
80 | 77 |
81 impl EnvironMap<'_> for LibPamEnviron<'_> { | 78 impl EnvironMap<'_> for LibPamEnviron<'_> { |
82 fn get(&self, key: impl AsRef<OsStr>) -> Option<OsString> { | 79 fn get(&self, key: impl AsRef<OsStr>) -> Option<OsString> { |
83 self.source.environ_get(key.as_ref()) | 80 self.source.environ_get(key.as_ref()) |
84 } | 81 } |
85 | 82 |
86 fn iter(&self) -> Result<impl Iterator<Item = (OsString, OsString)>> { | 83 fn iter(&self) -> impl Iterator<Item = (OsString, OsString)> { |
87 self.source.environ_iter() | 84 self.source.environ_iter() |
88 } | 85 } |
89 } | 86 } |
90 | 87 |
91 impl EnvironMap<'_> for LibPamEnvironMut<'_> { | 88 impl EnvironMap<'_> for LibPamEnvironMut<'_> { |
92 fn get(&self, key: impl AsRef<OsStr>) -> Option<OsString> { | 89 fn get(&self, key: impl AsRef<OsStr>) -> Option<OsString> { |
93 self.source.environ_get(key.as_ref()) | 90 self.source.environ_get(key.as_ref()) |
94 } | 91 } |
95 | 92 |
96 fn iter(&self) -> Result<impl Iterator<Item = (OsString, OsString)>> { | 93 fn iter(&self) -> impl Iterator<Item = (OsString, OsString)> { |
97 self.source.environ_iter() | 94 self.source.environ_iter() |
98 } | 95 } |
99 } | 96 } |
100 | 97 |
101 impl EnvironMapMut<'_> for LibPamEnvironMut<'_> { | 98 impl EnvironMapMut<'_> for LibPamEnvironMut<'_> { |
102 fn insert( | 99 fn insert(&mut self, key: impl AsRef<OsStr>, val: impl AsRef<OsStr>) -> Option<OsString> { |
103 &mut self, | |
104 key: impl AsRef<OsStr>, | |
105 val: impl AsRef<OsStr>, | |
106 ) -> Result<Option<OsString>> { | |
107 self.source.environ_set(key.as_ref(), Some(val.as_ref())) | 100 self.source.environ_set(key.as_ref(), Some(val.as_ref())) |
108 } | 101 } |
109 | 102 |
110 fn remove(&mut self, key: impl AsRef<OsStr>) -> Result<Option<OsString>> { | 103 fn remove(&mut self, key: impl AsRef<OsStr>) -> Option<OsString> { |
111 self.source.environ_set(key.as_ref(), None) | 104 self.source.environ_set(key.as_ref(), None) |
112 } | 105 } |
113 } | 106 } |
114 | 107 |
115 struct EnvList<'a> { | 108 struct EnvList<'a> { |
118 /// This can't be a `CHeapBox` because it's not just a single | 111 /// This can't be a `CHeapBox` because it's not just a single |
119 /// `Option<EnvVar>`. | 112 /// `Option<EnvVar>`. |
120 start: NonNull<Option<EnvVar>>, | 113 start: NonNull<Option<EnvVar>>, |
121 /// The environment variable we're about to iterate into. | 114 /// The environment variable we're about to iterate into. |
122 current: NonNull<Option<EnvVar>>, | 115 current: NonNull<Option<EnvVar>>, |
123 _owner: PhantomData<&'a LibPamHandle>, | 116 _owner: PhantomData<&'a RawPamHandle>, |
124 } | 117 } |
125 | 118 |
126 impl EnvList<'_> { | 119 impl EnvList<'_> { |
120 fn empty() -> Self { | |
121 let none: CHeapBox<Option<EnvVar>> = CHeapBox::new(None); | |
122 let ptr = CHeapBox::into_ptr(none); | |
123 Self { | |
124 start: ptr, | |
125 current: ptr, | |
126 _owner: PhantomData, | |
127 } | |
128 } | |
127 unsafe fn from_ptr(ptr: NonNull<*mut c_char>) -> Self { | 129 unsafe fn from_ptr(ptr: NonNull<*mut c_char>) -> Self { |
128 Self { | 130 Self { |
129 start: ptr.cast(), | 131 start: ptr.cast(), |
130 current: ptr.cast(), | 132 current: ptr.cast(), |
131 _owner: Default::default(), | 133 _owner: Default::default(), |