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 } |