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(),