Mercurial > crates > nonstick
comparison pam/src/module.rs @ 34:ec70822cbdef
Overhaul
| author | Andy Caldwell <andrew.caldwell@metaswitch.com> |
|---|---|
| date | Sun, 24 Apr 2022 03:42:11 +0100 |
| parents | 4263c1d83d5b |
| children | 50371046c61a |
comparison
equal
deleted
inserted
replaced
| 32:ea5f195f035f | 34:ec70822cbdef |
|---|---|
| 1 //! Functions for use in pam modules. | 1 //! Functions for use in pam modules. |
| 2 | 2 |
| 3 use libc::c_char; | 3 use libc::c_char; |
| 4 use std::{mem, ptr}; | |
| 5 use std::ffi::{CStr, CString}; | 4 use std::ffi::{CStr, CString}; |
| 6 | 5 |
| 7 use constants::{PamResultCode, PamItemType, PamFlag}; | 6 use constants::{PamFlag, PamResultCode}; |
| 8 | 7 |
| 9 /// Opaque type, used as a pointer when making pam API calls. | 8 /// Opaque type, used as a pointer when making pam API calls. |
| 10 /// | 9 /// |
| 11 /// A module is invoked via an external function such as `pam_sm_authenticate`. | 10 /// 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 | 11 /// Such a call provides a pam handle pointer. The same pointer should be given |
| 13 /// as an argument when making API calls. | 12 /// as an argument when making API calls. |
| 14 #[allow(missing_copy_implementations)] | 13 #[repr(C)] |
| 15 pub enum PamHandle {} | 14 pub struct PamHandle { |
| 16 | 15 _data: [u8; 0], |
| 17 #[allow(missing_copy_implementations)] | 16 } |
| 18 enum PamItemT {} | |
| 19 | |
| 20 #[allow(missing_copy_implementations)] | |
| 21 pub enum PamDataT {} | |
| 22 | 17 |
| 23 #[link(name = "pam")] | 18 #[link(name = "pam")] |
| 24 extern "C" { | 19 extern "C" { |
| 25 fn pam_get_data(pamh: *const PamHandle, | 20 fn pam_get_data( |
| 26 module_data_name: *const c_char, | 21 pamh: *const PamHandle, |
| 27 data: &mut *const PamDataT) | 22 module_data_name: *const c_char, |
| 28 -> PamResultCode; | 23 data: &mut *const libc::c_void, |
| 29 | 24 ) -> PamResultCode; |
| 30 fn pam_set_data(pamh: *const PamHandle, | 25 |
| 31 module_data_name: *const c_char, | 26 fn pam_set_data( |
| 32 data: Box<PamDataT>, | 27 pamh: *const PamHandle, |
| 33 cleanup: extern "C" fn(pamh: *const PamHandle, | 28 module_data_name: *const c_char, |
| 34 data: Box<PamDataT>, | 29 data: *mut libc::c_void, |
| 35 error_status: PamResultCode)) | 30 cleanup: extern "C" fn( |
| 36 -> PamResultCode; | 31 pamh: *const PamHandle, |
| 37 | 32 data: *mut libc::c_void, |
| 38 fn pam_get_item(pamh: *const PamHandle, | 33 error_status: PamResultCode, |
| 39 item_type: PamItemType, | 34 ), |
| 40 item: &mut *const PamItemT) | 35 ) -> PamResultCode; |
| 41 -> PamResultCode; | 36 |
| 42 | 37 fn pam_get_item( |
| 43 fn pam_set_item(pamh: *mut PamHandle, | 38 pamh: *const PamHandle, |
| 44 item_type: PamItemType, | 39 item_type: crate::items::ItemType, |
| 45 item: &PamItemT) | 40 item: &mut *const libc::c_void, |
| 46 -> PamResultCode; | 41 ) -> PamResultCode; |
| 47 | 42 |
| 48 fn pam_get_user(pamh: *const PamHandle, | 43 fn pam_set_item( |
| 49 user: &*mut c_char, | 44 pamh: *mut PamHandle, |
| 50 prompt: *const c_char) | 45 item_type: crate::items::ItemType, |
| 51 -> PamResultCode; | 46 item: *const libc::c_void, |
| 52 } | 47 ) -> PamResultCode; |
| 53 | 48 |
| 54 #[no_mangle] | 49 fn pam_get_user( |
| 55 pub extern "C" fn cleanup<T>(_: *const PamHandle, c_data: Box<PamDataT>, _: PamResultCode) { | 50 pamh: *const PamHandle, |
| 51 user: &*mut c_char, | |
| 52 prompt: *const c_char, | |
| 53 ) -> PamResultCode; | |
| 54 } | |
| 55 | |
| 56 pub extern "C" fn cleanup<T>(_: *const PamHandle, c_data: *mut libc::c_void, _: PamResultCode) { | |
| 56 unsafe { | 57 unsafe { |
| 57 let data: Box<T> = mem::transmute(c_data); | 58 let _data: Box<T> = Box::from_raw(c_data.cast::<T>()); |
| 58 mem::drop(data); | |
| 59 } | 59 } |
| 60 } | 60 } |
| 61 | 61 |
| 62 pub type PamResult<T> = Result<T, PamResultCode>; | 62 pub type PamResult<T> = Result<T, PamResultCode>; |
| 63 | |
| 64 /// Type-level mapping for safely retrieving values with `get_item`. | |
| 65 /// | |
| 66 /// See `pam_get_item` in | |
| 67 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html | |
| 68 pub trait PamItem { | |
| 69 /// Maps a Rust type to a pam constant. | |
| 70 /// | |
| 71 /// For example, the type PamConv maps to the constant PAM_CONV. The pam | |
| 72 /// API contract specifies that when the API function `pam_get_item` is | |
| 73 /// called with the constant PAM_CONV, it will return a value of type | |
| 74 /// `PamConv`. | |
| 75 fn item_type() -> PamItemType; | |
| 76 } | |
| 77 | |
| 78 | 63 |
| 79 impl PamHandle { | 64 impl PamHandle { |
| 80 /// Gets some value, identified by `key`, that has been set by the module | 65 /// Gets some value, identified by `key`, that has been set by the module |
| 81 /// previously. | 66 /// previously. |
| 82 /// | 67 /// |
| 83 /// See `pam_get_data` in | 68 /// See `pam_get_data` in |
| 84 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html | 69 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html |
| 70 /// | |
| 71 /// # Errors | |
| 72 /// | |
| 73 /// Returns an error if the underlying PAM function call fails. | |
| 74 /// | |
| 75 /// # Safety | |
| 76 /// | |
| 77 /// The data stored under the provided key must be of type `T` otherwise the | |
| 78 /// behaviour of this funtion is undefined. | |
| 85 pub unsafe fn get_data<'a, T>(&'a self, key: &str) -> PamResult<&'a T> { | 79 pub unsafe fn get_data<'a, T>(&'a self, key: &str) -> PamResult<&'a T> { |
| 86 let c_key = CString::new(key).unwrap().as_ptr(); | 80 let c_key = CString::new(key).unwrap(); |
| 87 let mut ptr: *const PamDataT = ptr::null(); | 81 let mut ptr: *const libc::c_void = std::ptr::null(); |
| 88 let res = pam_get_data(self, c_key, &mut ptr); | 82 let res = pam_get_data(self, c_key.as_ptr(), &mut ptr); |
| 89 if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() { | 83 if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() { |
| 90 let typed_ptr: *const T = mem::transmute(ptr); | 84 let typed_ptr = ptr.cast::<T>(); |
| 91 let data: &T = &*typed_ptr; | 85 let data: &T = &*typed_ptr; |
| 92 Ok(data) | 86 Ok(data) |
| 93 } else { | 87 } else { |
| 94 Err(res) | 88 Err(res) |
| 95 } | 89 } |
| 98 /// Stores a value that can be retrieved later with `get_data`. The value lives | 92 /// Stores a value that can be retrieved later with `get_data`. The value lives |
| 99 /// as long as the current pam cycle. | 93 /// as long as the current pam cycle. |
| 100 /// | 94 /// |
| 101 /// See `pam_set_data` in | 95 /// See `pam_set_data` in |
| 102 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html | 96 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html |
| 97 /// | |
| 98 /// # Errors | |
| 99 /// | |
| 100 /// Returns an error if the underlying PAM function call fails. | |
| 103 pub fn set_data<T>(&self, key: &str, data: Box<T>) -> PamResult<()> { | 101 pub fn set_data<T>(&self, key: &str, data: Box<T>) -> PamResult<()> { |
| 104 let c_key = CString::new(key).unwrap().as_ptr(); | 102 let c_key = CString::new(key).unwrap(); |
| 105 let res = unsafe { | 103 let res = unsafe { |
| 106 let c_data: Box<PamDataT> = mem::transmute(data); | 104 pam_set_data( |
| 107 pam_set_data(self, c_key, c_data, cleanup::<T>) | 105 self, |
| 106 c_key.as_ptr(), | |
| 107 Box::into_raw(data).cast::<libc::c_void>(), | |
| 108 cleanup::<T>, | |
| 109 ) | |
| 108 }; | 110 }; |
| 109 if PamResultCode::PAM_SUCCESS == res { | 111 if PamResultCode::PAM_SUCCESS == res { |
| 110 Ok(()) | 112 Ok(()) |
| 111 } else { | 113 } else { |
| 112 Err(res) | 114 Err(res) |
| 113 } | 115 } |
| 114 } | 116 } |
| 115 | 117 |
| 116 | |
| 117 | |
| 118 /// Retrieves a value that has been set, possibly by the pam client. This is | 118 /// Retrieves a value that has been set, possibly by the pam client. This is |
| 119 /// particularly useful for getting a `PamConv` reference. | 119 /// particularly useful for getting a `PamConv` reference. |
| 120 /// | 120 /// |
| 121 /// See `pam_get_item` in | 121 /// See `pam_get_item` in |
| 122 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html | 122 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html |
| 123 pub fn get_item<'a, T: PamItem>(&self) -> PamResult<&'a T> { | 123 /// |
| 124 let mut ptr: *const PamItemT = ptr::null(); | 124 /// # Errors |
| 125 /// | |
| 126 /// Returns an error if the underlying PAM function call fails. | |
| 127 pub fn get_item<T: crate::items::Item>(&self) -> PamResult<Option<T>> { | |
| 128 let mut ptr: *const libc::c_void = std::ptr::null(); | |
| 125 let (res, item) = unsafe { | 129 let (res, item) = unsafe { |
| 126 let r = pam_get_item(self, T::item_type(), &mut ptr); | 130 let r = pam_get_item(self, T::type_id(), &mut ptr); |
| 127 let typed_ptr: *const T = mem::transmute(ptr); | 131 let typed_ptr = ptr.cast::<T::Raw>(); |
| 128 let t: &T = &*typed_ptr; | 132 let t = if typed_ptr.is_null() { |
| 133 None | |
| 134 } else { | |
| 135 Some(T::from_raw(typed_ptr)) | |
| 136 }; | |
| 129 (r, t) | 137 (r, t) |
| 130 }; | 138 }; |
| 131 if PamResultCode::PAM_SUCCESS == res { | 139 if PamResultCode::PAM_SUCCESS == res { |
| 132 Ok(item) | 140 Ok(item) |
| 133 } else { | 141 } else { |
| 140 /// | 148 /// |
| 141 /// Note that all items are strings, except `PAM_CONV` and `PAM_FAIL_DELAY`. | 149 /// Note that all items are strings, except `PAM_CONV` and `PAM_FAIL_DELAY`. |
| 142 /// | 150 /// |
| 143 /// See `pam_set_item` in | 151 /// See `pam_set_item` in |
| 144 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html | 152 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html |
| 145 pub fn set_item_str<T: PamItem>(&mut self, item: &str) -> PamResult<()> { | 153 /// |
| 146 let c_item = CString::new(item).unwrap().as_ptr(); | 154 /// # Errors |
| 147 | 155 /// |
| 148 let res = unsafe { | 156 /// Returns an error if the underlying PAM function call fails. |
| 149 pam_set_item(self, | 157 /// |
| 150 T::item_type(), | 158 /// # Panics |
| 151 | 159 /// |
| 152 // unwrapping is okay here, as c_item will not be a NULL | 160 /// Panics if the provided item key contains a nul byte |
| 153 // pointer | 161 pub fn set_item_str<T: crate::items::Item>(&mut self, item: T) -> PamResult<()> { |
| 154 (c_item as *const PamItemT).as_ref().unwrap()) | 162 let res = |
| 155 }; | 163 unsafe { pam_set_item(self, T::type_id(), item.into_raw().cast::<libc::c_void>())}; |
| 156 if PamResultCode::PAM_SUCCESS == res { | 164 if PamResultCode::PAM_SUCCESS == res { |
| 157 Ok(()) | 165 Ok(()) |
| 158 } else { | 166 } else { |
| 159 Err(res) | 167 Err(res) |
| 160 } | 168 } |
| 164 /// | 172 /// |
| 165 /// This is really a specialization of `get_item`. | 173 /// This is really a specialization of `get_item`. |
| 166 /// | 174 /// |
| 167 /// See `pam_get_user` in | 175 /// See `pam_get_user` in |
| 168 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html | 176 /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html |
| 177 /// | |
| 178 /// # Errors | |
| 179 /// | |
| 180 /// Returns an error if the underlying PAM function call fails. | |
| 181 /// | |
| 182 /// # Panics | |
| 183 /// | |
| 184 /// Panics if the provided prompt string contains a nul byte | |
| 169 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> { | 185 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> { |
| 170 let ptr: *mut c_char = ptr::null_mut(); | 186 let ptr: *mut c_char = std::ptr::null_mut(); |
| 187 let prompt_string; | |
| 171 let c_prompt = match prompt { | 188 let c_prompt = match prompt { |
| 172 Some(p) => CString::new(p).unwrap().as_ptr(), | 189 Some(p) => { |
| 173 None => ptr::null(), | 190 prompt_string = CString::new(p).unwrap(); |
| 191 prompt_string.as_ptr() | |
| 192 } | |
| 193 None => std::ptr::null(), | |
| 174 }; | 194 }; |
| 175 let res = unsafe { pam_get_user(self, &ptr, c_prompt) }; | 195 let res = unsafe { pam_get_user(self, &ptr, c_prompt) }; |
| 176 if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() { | 196 if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() { |
| 177 let const_ptr = ptr as *const c_char; | 197 let const_ptr = ptr as *const c_char; |
| 178 let bytes = unsafe { CStr::from_ptr(const_ptr).to_bytes() }; | 198 let bytes = unsafe { CStr::from_ptr(const_ptr).to_bytes() }; |
| 193 /// This function performs the task of establishing whether the user is permitted to gain access at | 213 /// This function performs the task of establishing whether the user is permitted to gain access at |
| 194 /// this time. It should be understood that the user has previously been validated by an | 214 /// this time. It should be understood that the user has previously been validated by an |
| 195 /// authentication module. This function checks for other things. Such things might be: the time of | 215 /// authentication module. This function checks for other things. Such things might be: the time of |
| 196 /// day or the date, the terminal line, remote hostname, etc. This function may also determine | 216 /// day or the date, the terminal line, remote hostname, etc. This function may also determine |
| 197 /// things like the expiration on passwords, and respond that the user change it before continuing. | 217 /// things like the expiration on passwords, and respond that the user change it before continuing. |
| 198 fn acct_mgmt(pamh: &PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { | 218 fn acct_mgmt(pamh: &mut PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { |
| 199 PamResultCode::PAM_IGNORE | 219 PamResultCode::PAM_IGNORE |
| 200 } | 220 } |
| 201 | 221 |
| 202 /// This function performs the task of authenticating the user. | 222 /// This function performs the task of authenticating the user. |
| 203 fn sm_authenticate(pamh: &PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { | 223 fn sm_authenticate(pamh: &mut PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { |
| 204 PamResultCode::PAM_IGNORE | 224 PamResultCode::PAM_IGNORE |
| 205 } | 225 } |
| 206 | 226 |
| 207 /// This function is used to (re-)set the authentication token of the user. | 227 /// This function is used to (re-)set the authentication token of the user. |
| 208 /// | 228 /// |
| 209 /// The PAM library calls this function twice in succession. The first time with | 229 /// The PAM library calls this function twice in succession. The first time with |
| 210 /// PAM_PRELIM_CHECK and then, if the module does not return PAM_TRY_AGAIN, subsequently with | 230 /// `PAM_PRELIM_CHECK` and then, if the module does not return `PAM_TRY_AGAIN`, subsequently with |
| 211 /// PAM_UPDATE_AUTHTOK. It is only on the second call that the authorization token is | 231 /// `PAM_UPDATE_AUTHTOK`. It is only on the second call that the authorization token is |
| 212 /// (possibly) changed. | 232 /// (possibly) changed. |
| 213 fn sm_chauthtok(pamh: &PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { | 233 fn sm_chauthtok(pamh: &mut PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { |
| 214 PamResultCode::PAM_IGNORE | 234 PamResultCode::PAM_IGNORE |
| 215 } | 235 } |
| 216 | 236 |
| 217 /// This function is called to terminate a session. | 237 /// This function is called to terminate a session. |
| 218 fn sm_close_session(pamh: &PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { | 238 fn sm_close_session(pamh: &mut PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { |
| 219 PamResultCode::PAM_IGNORE | 239 PamResultCode::PAM_IGNORE |
| 220 } | 240 } |
| 221 | 241 |
| 222 /// This function is called to commence a session. | 242 /// This function is called to commence a session. |
| 223 fn sm_open_session(pamh: &PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { | 243 fn sm_open_session(pamh: &mut PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { |
| 224 PamResultCode::PAM_IGNORE | 244 PamResultCode::PAM_IGNORE |
| 225 } | 245 } |
| 226 | 246 |
| 227 /// This function performs the task of altering the credentials of the user with respect to the | 247 /// This function performs the task of altering the credentials of the user with respect to the |
| 228 /// corresponding authorization scheme. Generally, an authentication module may have access to more | 248 /// corresponding authorization scheme. Generally, an authentication module may have access to more |
| 229 /// information about a user than their authentication token. This function is used to make such | 249 /// information about a user than their authentication token. This function is used to make such |
| 230 /// information available to the application. It should only be called after the user has been | 250 /// information available to the application. It should only be called after the user has been |
| 231 /// authenticated but before a session has been established. | 251 /// authenticated but before a session has been established. |
| 232 fn sm_setcred(pamh: &PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { | 252 fn sm_setcred(pamh: &mut PamHandle, args: Vec<&CStr>, flags: PamFlag) -> PamResultCode { |
| 233 PamResultCode::PAM_IGNORE | 253 PamResultCode::PAM_IGNORE |
| 234 } | 254 } |
| 235 } | 255 } |
