comparison src/module.rs @ 59:3f4a77aa88be

Fix string copyting and improve error situation. This change is too big and includes several things: - Fix copying strings from PAM by fixing const and mut on pam funcs. - Improve error enums by simplifying conversions and removing unnecessary and ambiguous "success" variants. - Make a bunch of casts nicer. - Assorted other cleanup.
author Paul Fisher <paul@pfish.zone>
date Wed, 21 May 2025 00:27:18 -0400
parents daa2cde64601
children 05cc2c27334f
comparison
equal deleted inserted replaced
58:868a278a362c 59:3f4a77aa88be
1 //! Functions for use in pam modules. 1 //! Functions for use in pam modules.
2 2
3 use crate::constants::{Flags, PamResult, ErrorCode}; 3 use crate::constants::{ErrorCode, Flags, PamResult};
4 use crate::items::{Item, ItemType}; 4 use crate::items::{Item, ItemType};
5 use libc::c_char; 5 use libc::c_char;
6 use secure_string::SecureString;
6 use std::ffi::{c_int, CStr, CString}; 7 use std::ffi::{c_int, CStr, CString};
7 use secure_string::SecureString;
8 8
9 /// Opaque type, used as a pointer when making pam API calls. 9 /// Opaque type, used as a pointer when making pam API calls.
10 /// 10 ///
11 /// A module is invoked via an external function such as `pam_sm_authenticate`. 11 /// A module is invoked via an external function such as `pam_sm_authenticate`.
12 /// Such a call provides a pam handle pointer. The same pointer should be given 12 /// Such a call provides a pam handle pointer. The same pointer should be given
25 ) -> c_int; 25 ) -> c_int;
26 26
27 fn pam_set_data( 27 fn pam_set_data(
28 pamh: *const PamHandle, 28 pamh: *const PamHandle,
29 module_data_name: *const c_char, 29 module_data_name: *const c_char,
30 data: *mut libc::c_void, 30 data: *const libc::c_void,
31 cleanup: extern "C" fn( 31 cleanup: extern "C" fn(
32 pamh: *const PamHandle, 32 pamh: *const PamHandle,
33 data: *mut libc::c_void, 33 data: *mut libc::c_void,
34 error_status: c_int, 34 error_status: c_int,
35 ), 35 ),
41 item: &mut *const libc::c_void, 41 item: &mut *const libc::c_void,
42 ) -> c_int; 42 ) -> c_int;
43 43
44 fn pam_set_item(pamh: *mut PamHandle, item_type: c_int, item: *const libc::c_void) -> c_int; 44 fn pam_set_item(pamh: *mut PamHandle, item_type: c_int, item: *const libc::c_void) -> c_int;
45 45
46 fn pam_get_user(pamh: *const PamHandle, user: &*mut c_char, prompt: *const c_char) -> c_int; 46 fn pam_get_user(
47 pamh: *const PamHandle,
48 user: &mut *const c_char,
49 prompt: *const c_char,
50 ) -> c_int;
47 51
48 fn pam_get_authtok( 52 fn pam_get_authtok(
49 pamh: *const PamHandle, 53 pamh: *const PamHandle,
50 item_type: c_int, 54 item_type: c_int,
51 data: &*mut c_char, 55 data: &mut *const c_char,
52 prompt: *const c_char, 56 prompt: *const c_char,
53 ) -> c_int; 57 ) -> c_int;
54 58
55 } 59 }
56 60
58 /// a value previously provided to PAM in a `pam_set_data` call. 62 /// a value previously provided to PAM in a `pam_set_data` call.
59 /// 63 ///
60 /// You should never call this yourself. 64 /// You should never call this yourself.
61 extern "C" fn cleanup<T>(_: *const PamHandle, c_data: *mut libc::c_void, _: c_int) { 65 extern "C" fn cleanup<T>(_: *const PamHandle, c_data: *mut libc::c_void, _: c_int) {
62 unsafe { 66 unsafe {
63 let _data: Box<T> = Box::from_raw(c_data.cast::<T>()); 67 let _data: Box<T> = Box::from_raw(c_data.cast());
64 } 68 }
65 } 69 }
66 70
67 impl PamHandle { 71 impl PamHandle {
68 /// Gets some value, identified by `key`, that has been set by the module 72 /// Gets some value, identified by `key`, that has been set by the module
86 let mut ptr: *const libc::c_void = std::ptr::null(); 90 let mut ptr: *const libc::c_void = std::ptr::null();
87 ErrorCode::result_from(pam_get_data(self, c_key.as_ptr(), &mut ptr))?; 91 ErrorCode::result_from(pam_get_data(self, c_key.as_ptr(), &mut ptr))?;
88 match ptr.is_null() { 92 match ptr.is_null() {
89 true => Ok(None), 93 true => Ok(None),
90 false => { 94 false => {
91 let typed_ptr = ptr.cast::<T>(); 95 let typed_ptr = ptr.cast();
92 Ok(Some(&*typed_ptr)) 96 Ok(Some(&*typed_ptr))
93 } 97 }
94 } 98 }
95 } 99 }
96 100
107 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; 111 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?;
108 let ret = unsafe { 112 let ret = unsafe {
109 pam_set_data( 113 pam_set_data(
110 self, 114 self,
111 c_key.as_ptr(), 115 c_key.as_ptr(),
112 Box::into_raw(data).cast::<libc::c_void>(), 116 Box::into_raw(data).cast(),
113 cleanup::<T>, 117 cleanup::<T>,
114 ) 118 )
115 }; 119 };
116 ErrorCode::result_from(ret) 120 ErrorCode::result_from(ret)
117 } 121 }
131 pub fn get_item<T: crate::items::Item>(&self) -> PamResult<Option<T>> { 135 pub fn get_item<T: crate::items::Item>(&self) -> PamResult<Option<T>> {
132 let mut ptr: *const libc::c_void = std::ptr::null(); 136 let mut ptr: *const libc::c_void = std::ptr::null();
133 let out = unsafe { 137 let out = unsafe {
134 let ret = pam_get_item(self, T::type_id().into(), &mut ptr); 138 let ret = pam_get_item(self, T::type_id().into(), &mut ptr);
135 ErrorCode::result_from(ret)?; 139 ErrorCode::result_from(ret)?;
136 let typed_ptr = ptr.cast::<T::Raw>(); 140 let typed_ptr: *const T::Raw = ptr.cast();
137 match typed_ptr.is_null() { 141 match typed_ptr.is_null() {
138 true => None, 142 true => None,
139 false => Some(T::from_raw(typed_ptr)), 143 false => Some(T::from_raw(typed_ptr)),
140 } 144 }
141 }; 145 };
149 /// 153 ///
150 /// # Errors 154 /// # Errors
151 /// 155 ///
152 /// Returns an error if the underlying PAM function call fails. 156 /// Returns an error if the underlying PAM function call fails.
153 pub fn set_item<T: Item>(&mut self, item: T) -> PamResult<()> { 157 pub fn set_item<T: Item>(&mut self, item: T) -> PamResult<()> {
154 let ret = 158 let ret = unsafe { pam_set_item(self, T::type_id().into(), item.into_raw().cast()) };
155 unsafe { pam_set_item(self, T::type_id().into(), item.into_raw().cast::<libc::c_void>()) };
156 ErrorCode::result_from(ret) 159 ErrorCode::result_from(ret)
157 } 160 }
158 161
159 /// Retrieves the name of the user who is authenticating or logging in. 162 /// Retrieves the name of the user who is authenticating or logging in.
160 /// 163 ///
166 /// # Errors 169 /// # Errors
167 /// 170 ///
168 /// Returns an error if the underlying PAM function call fails. 171 /// Returns an error if the underlying PAM function call fails.
169 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> { 172 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> {
170 let prompt = option_cstr(prompt)?; 173 let prompt = option_cstr(prompt)?;
171 let output: *mut c_char = std::ptr::null_mut(); 174 let mut output: *const c_char = std::ptr::null_mut();
172 let ret = unsafe { pam_get_user(self, &output, prompt_ptr(prompt.as_ref())) }; 175 let ret = unsafe { pam_get_user(self, &mut output, prompt_ptr(prompt.as_ref())) };
173 ErrorCode::result_from(ret)?; 176 ErrorCode::result_from(ret)?;
174 copy_pam_string(output) 177 copy_pam_string(output)
175 } 178 }
176 179
177 /// Retrieves the authentication token from the user. 180 /// Retrieves the authentication token from the user.
184 /// # Errors 187 /// # Errors
185 /// 188 ///
186 /// Returns an error if the underlying PAM function call fails. 189 /// Returns an error if the underlying PAM function call fails.
187 pub fn get_authtok(&self, prompt: Option<&str>) -> PamResult<SecureString> { 190 pub fn get_authtok(&self, prompt: Option<&str>) -> PamResult<SecureString> {
188 let prompt = option_cstr(prompt)?; 191 let prompt = option_cstr(prompt)?;
189 let output: *mut c_char = std::ptr::null_mut(); 192 let mut output: *const c_char = std::ptr::null_mut();
190 let res = unsafe { 193 let res = unsafe {
191 pam_get_authtok( 194 pam_get_authtok(
192 self, 195 self,
193 ItemType::AuthTok.into(), 196 ItemType::AuthTok.into(),
194 &output, 197 &mut output,
195 prompt_ptr(prompt.as_ref()), 198 prompt_ptr(prompt.as_ref()),
196 ) 199 )
197 }; 200 };
198 ErrorCode::result_from(res)?; 201 ErrorCode::result_from(res)?;
199 copy_pam_string(output).map(SecureString::from) 202 copy_pam_string(output).map(SecureString::from)