Mercurial > crates > nonstick
comparison src/libpam/module.rs @ 171:e27c5c667a5a
Create full new types for return code and flags, separate end to end.
This plumbs the ReturnCode and RawFlags types through the places where
we call into or are called from PAM.
Also adds Sun documentation to the project.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 25 Jul 2025 20:52:14 -0400 |
parents | 2f5913131295 |
children | 6727cbe56f4a |
comparison
equal
deleted
inserted
replaced
170:f052e2417195 | 171:e27c5c667a5a |
---|---|
1 use crate::constants::{ErrorCode, RawFlags, Result}; | |
2 use crate::libpam::handle::LibPamHandle; | |
3 use crate::module::PamModule; | |
4 use crate::{AuthnFlags, AuthtokAction, BaseFlags, CredAction}; | |
5 use std::ffi::{c_char, c_int, c_void, CStr}; | |
6 | |
1 /// Generates the dynamic library entry points for a PAM module | 7 /// Generates the dynamic library entry points for a PAM module |
2 /// | 8 /// |
3 /// Calling `pam_hooks!(SomeType)` on a type that implements | 9 /// Calling `pam_hooks!(SomeType)` on a type that implements |
4 /// [`PamModule`](crate::PamModule) will generate the exported | 10 /// [`PamModule`] will generate the exported |
5 /// `extern "C"` functions that PAM uses to call into your module. | 11 /// `extern "C"` functions that PAM uses to call into your module. |
6 /// | 12 /// |
7 /// ## Examples: | 13 /// ## Examples: |
8 /// | 14 /// |
9 /// Here is full example of a PAM module that would authenticate | 15 /// Here is full example of a PAM module that would authenticate |
39 /// ``` | 45 /// ``` |
40 #[macro_export] | 46 #[macro_export] |
41 macro_rules! pam_hooks { | 47 macro_rules! pam_hooks { |
42 ($ident:ident) => { | 48 ($ident:ident) => { |
43 mod _pam_hooks_scope { | 49 mod _pam_hooks_scope { |
44 use std::ffi::{c_char, c_int, c_void, CStr}; | 50 use std::ffi::{c_char, c_int, c_void}; |
45 use $crate::{ | 51 use $crate::ModuleExporter; |
46 AuthnFlags, AuthtokAction, BaseFlags, CredAction, ErrorCode, LibPamHandle, | 52 use $crate::constants::{RawFlags, ReturnCode}; |
47 PamModule, | |
48 }; | |
49 | 53 |
50 macro_rules! handle { | 54 macro_rules! export { |
51 ($pamh:ident) => { | 55 ($func:ident) => { |
52 match unsafe { $pamh.cast::<LibPamHandle>().as_mut() } { | 56 #[no_mangle] |
53 Some(handle) => handle, | 57 unsafe extern "C" fn $func( |
54 None => return ErrorCode::Ignore.into(), | 58 pamh: *mut c_void, |
59 flags: RawFlags, | |
60 argc: c_int, | |
61 argv: *const *const c_char, | |
62 ) -> c_int { | |
63 let ret: ReturnCode = ModuleExporter::$func::<super::$ident>( | |
64 pamh, flags, argc, argv | |
65 ).into(); | |
66 ret.into() | |
55 } | 67 } |
56 }; | 68 }; |
57 } | 69 } |
58 | 70 |
59 #[no_mangle] | 71 export!(pam_sm_acct_mgmt); |
60 extern "C" fn pam_sm_acct_mgmt( | 72 export!(pam_sm_authenticate); |
61 pamh: *mut c_void, | 73 export!(pam_sm_chauthtok); |
62 flags: AuthnFlags, | 74 export!(pam_sm_close_session); |
63 argc: c_int, | 75 export!(pam_sm_open_session); |
64 argv: *const *const c_char, | 76 export!(pam_sm_setcred); |
65 ) -> c_int { | |
66 let handle = handle!(pamh); | |
67 let args = extract_argv(argc, argv); | |
68 ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags)) | |
69 } | |
70 | |
71 #[no_mangle] | |
72 extern "C" fn pam_sm_authenticate( | |
73 pamh: *mut c_void, | |
74 flags: AuthnFlags, | |
75 argc: c_int, | |
76 argv: *const *const c_char, | |
77 ) -> c_int { | |
78 let handle = handle!(pamh); | |
79 let args = extract_argv(argc, argv); | |
80 ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags)) | |
81 } | |
82 | |
83 #[no_mangle] | |
84 extern "C" fn pam_sm_chauthtok( | |
85 pamh: *mut c_void, | |
86 flags: c_int, | |
87 argc: c_int, | |
88 argv: *const *const c_char, | |
89 ) -> c_int { | |
90 let handle = handle!(pamh); | |
91 let (action, flags) = match AuthtokAction::extract(flags) { | |
92 Ok(val) => val, | |
93 Err(e) => return e.into(), | |
94 }; | |
95 let args = extract_argv(argc, argv); | |
96 ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, action, flags)) | |
97 } | |
98 | |
99 #[no_mangle] | |
100 extern "C" fn pam_sm_close_session( | |
101 pamh: *mut c_void, | |
102 flags: BaseFlags, | |
103 argc: c_int, | |
104 argv: *const *const c_char, | |
105 ) -> c_int { | |
106 let handle = handle!(pamh); | |
107 let args = extract_argv(argc, argv); | |
108 ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags)) | |
109 } | |
110 | |
111 #[no_mangle] | |
112 extern "C" fn pam_sm_open_session( | |
113 pamh: *mut c_void, | |
114 flags: BaseFlags, | |
115 argc: c_int, | |
116 argv: *const *const c_char, | |
117 ) -> c_int { | |
118 let handle = handle!(pamh); | |
119 let args = extract_argv(argc, argv); | |
120 ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags)) | |
121 } | |
122 | |
123 #[no_mangle] | |
124 extern "C" fn pam_sm_setcred( | |
125 pamh: *mut c_void, | |
126 flags: c_int, | |
127 argc: c_int, | |
128 argv: *const *const c_char, | |
129 ) -> c_int { | |
130 let handle = handle!(pamh); | |
131 let (action, flags) = match CredAction::extract(flags) { | |
132 Ok(val) => val, | |
133 Err(e) => return e.into(), | |
134 }; | |
135 let args = extract_argv(argc, argv); | |
136 ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, action, flags)) | |
137 } | |
138 | |
139 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. | |
140 /// | |
141 /// # Safety | |
142 /// | |
143 /// We use this only with arguments we get from `libpam`, which we kind of have to trust. | |
144 fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { | |
145 (0..argc) | |
146 .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) | |
147 .collect() | |
148 } | |
149 } | 77 } |
150 }; | 78 }; |
79 } | |
80 | |
81 #[doc(hidden)] | |
82 pub struct ModuleExporter; | |
83 | |
84 // All of the below are only intended to be called directly from C. | |
85 #[allow(clippy::missing_safety_doc)] | |
86 impl ModuleExporter { | |
87 pub unsafe fn pam_sm_acct_mgmt<M: PamModule<LibPamHandle>>( | |
88 pamh: *mut c_void, | |
89 flags: RawFlags, | |
90 argc: c_int, | |
91 argv: *const *const c_char, | |
92 ) -> Result<()> { | |
93 let handle = wrap(pamh)?; | |
94 let args = extract_argv(argc, argv); | |
95 M::account_management(handle, args, AuthnFlags::from(flags)) | |
96 } | |
97 | |
98 pub unsafe fn pam_sm_authenticate<M: PamModule<LibPamHandle>>( | |
99 pamh: *mut c_void, | |
100 flags: RawFlags, | |
101 argc: c_int, | |
102 argv: *const *const c_char, | |
103 ) -> Result<()> { | |
104 let handle = wrap(pamh)?; | |
105 let args = extract_argv(argc, argv); | |
106 M::authenticate(handle, args, AuthnFlags::from(flags)) | |
107 } | |
108 | |
109 pub unsafe fn pam_sm_chauthtok<M: PamModule<LibPamHandle>>( | |
110 pamh: *mut c_void, | |
111 flags: RawFlags, | |
112 argc: c_int, | |
113 argv: *const *const c_char, | |
114 ) -> Result<()> { | |
115 let handle = wrap(pamh)?; | |
116 let (action, flags) = AuthtokAction::extract(flags)?; | |
117 let args = extract_argv(argc, argv); | |
118 M::change_authtok(handle, args, action, flags) | |
119 } | |
120 | |
121 pub unsafe fn pam_sm_close_session<M: PamModule<LibPamHandle>>( | |
122 pamh: *mut c_void, | |
123 flags: RawFlags, | |
124 argc: c_int, | |
125 argv: *const *const c_char, | |
126 ) -> Result<()> { | |
127 let handle = wrap(pamh)?; | |
128 let args = extract_argv(argc, argv); | |
129 M::close_session(handle, args, BaseFlags::from(flags)) | |
130 } | |
131 | |
132 pub unsafe fn pam_sm_open_session<M: PamModule<LibPamHandle>>( | |
133 pamh: *mut c_void, | |
134 flags: RawFlags, | |
135 argc: c_int, | |
136 argv: *const *const c_char, | |
137 ) -> Result<()> { | |
138 let handle = wrap(pamh)?; | |
139 let args = extract_argv(argc, argv); | |
140 M::open_session(handle, args, BaseFlags::from(flags)) | |
141 } | |
142 | |
143 pub unsafe fn pam_sm_setcred<M: PamModule<LibPamHandle>>( | |
144 pamh: *mut c_void, | |
145 flags: RawFlags, | |
146 argc: c_int, | |
147 argv: *const *const c_char, | |
148 ) -> Result<()> { | |
149 let handle = wrap(pamh)?; | |
150 let (action, flags) = CredAction::extract(flags)?; | |
151 let args = extract_argv(argc, argv); | |
152 M::set_credentials(handle, args, action, flags) | |
153 } | |
154 } | |
155 | |
156 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. | |
157 /// | |
158 /// # Safety | |
159 /// | |
160 /// We use this only with arguments we get from `libpam`, which we kind of have to trust. | |
161 unsafe fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { | |
162 (0..argc) | |
163 .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) | |
164 .collect() | |
165 } | |
166 | |
167 /// Wraps the pointer in a PAM handle, or returns an error if it's null. | |
168 /// | |
169 /// # Safety | |
170 /// | |
171 /// It's up to you to pass a valid handle. | |
172 unsafe fn wrap<'a>(handle: *mut c_void) -> Result<&'a mut LibPamHandle> { | |
173 handle.cast::<LibPamHandle>().as_mut().ok_or(ErrorCode::SystemError) | |
151 } | 174 } |
152 | 175 |
153 #[cfg(test)] | 176 #[cfg(test)] |
154 mod tests { | 177 mod tests { |
155 // Compile-time test that the `pam_hooks` macro compiles. | 178 // Compile-time test that the `pam_hooks` macro compiles. |