Mercurial > crates > nonstick
comparison src/pam_ffi/module.rs @ 74:c7c596e6388f
Make conversations type-safe (last big reorg) (REAL) (NOT CLICKBAIT)
In previous versions of Conversation, you could send messages and then
return messages of the wrong type or in the wrong order or whatever.
The receiver would then have to make sure that there were the right
number of messages and that each message was the right type.
That's annoying.
This change makes the `Message` enum a two-way channel, where the asker
puts their question into it, and then the answerer (the conversation)
puts the answer in and returns control to the asker. The asker then
only has to pull the Answer of the type they wanted out of the message.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 06 Jun 2025 22:21:17 -0400 |
parents | src/module.rs@ac6881304c78 |
children |
comparison
equal
deleted
inserted
replaced
73:ac6881304c78 | 74:c7c596e6388f |
---|---|
1 use std::ffi::CStr; | |
2 | |
3 /// Generates the dynamic library entry points for a [PamModule] implementation. | |
4 /// | |
5 /// Calling `pam_hooks!(SomeType)` on a type that implements [PamModule] will | |
6 /// generate the exported `extern "C"` functions that PAM uses to call into | |
7 /// your module. | |
8 /// | |
9 /// ## Examples: | |
10 /// | |
11 /// Here is full example of a PAM module that would authenticate and authorize everybody: | |
12 /// | |
13 /// ``` | |
14 /// use nonstick::{Flags, OwnedLibPamHandle, PamModule, PamHandleModule, Result as PamResult, pam_hooks}; | |
15 /// use std::ffi::CStr; | |
16 /// # fn main() {} | |
17 /// | |
18 /// struct MyPamModule; | |
19 /// pam_hooks!(MyPamModule); | |
20 /// | |
21 /// impl<T: PamHandleModule> PamModule<T> for MyPamModule { | |
22 /// fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | |
23 /// let password = handle.get_authtok(Some("what's your password?"))?; | |
24 /// handle.info_msg(fmt!("If you say your password is {password:?}, who am I to disagree?")); | |
25 /// } | |
26 /// | |
27 /// fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | |
28 /// let username = handle.get_user(None)?; | |
29 /// handle.info_msg(fmt!("Hello {username}! I trust you unconditionally.")) | |
30 /// Ok(()) | |
31 /// } | |
32 /// } | |
33 /// ``` | |
34 #[macro_export] | |
35 macro_rules! pam_hooks { | |
36 ($ident:ident) => { | |
37 mod _pam_hooks_scope { | |
38 use std::ffi::{c_char, c_int, CStr}; | |
39 use $crate::{ErrorCode, Flags, LibPamHandle, PamModule}; | |
40 | |
41 #[no_mangle] | |
42 extern "C" fn pam_sm_acct_mgmt( | |
43 pamh: *mut libc::c_void, | |
44 flags: Flags, | |
45 argc: c_int, | |
46 argv: *const *const c_char, | |
47 ) -> c_int { | |
48 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
49 let args = extract_argv(argc, argv); | |
50 ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags)) | |
51 } else { | |
52 ErrorCode::Ignore as c_int | |
53 } | |
54 } | |
55 | |
56 #[no_mangle] | |
57 extern "C" fn pam_sm_authenticate( | |
58 pamh: *mut libc::c_void, | |
59 flags: Flags, | |
60 argc: c_int, | |
61 argv: *const *const c_char, | |
62 ) -> c_int { | |
63 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
64 let args = extract_argv(argc, argv); | |
65 ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags)) | |
66 } else { | |
67 ErrorCode::Ignore as c_int | |
68 } | |
69 } | |
70 | |
71 #[no_mangle] | |
72 extern "C" fn pam_sm_chauthtok( | |
73 pamh: *mut libc::c_void, | |
74 flags: Flags, | |
75 argc: c_int, | |
76 argv: *const *const c_char, | |
77 ) -> c_int { | |
78 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
79 let args = extract_argv(argc, argv); | |
80 ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, flags)) | |
81 } else { | |
82 ErrorCode::Ignore as c_int | |
83 } | |
84 } | |
85 | |
86 #[no_mangle] | |
87 extern "C" fn pam_sm_close_session( | |
88 pamh: *mut libc::c_void, | |
89 flags: Flags, | |
90 argc: c_int, | |
91 argv: *const *const c_char, | |
92 ) -> c_int { | |
93 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
94 let args = extract_argv(argc, argv); | |
95 ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags)) | |
96 } else { | |
97 ErrorCode::Ignore as c_int | |
98 } | |
99 } | |
100 | |
101 #[no_mangle] | |
102 extern "C" fn pam_sm_open_session( | |
103 pamh: *mut libc::c_void, | |
104 flags: Flags, | |
105 argc: c_int, | |
106 argv: *const *const c_char, | |
107 ) -> c_int { | |
108 let args = extract_argv(argc, argv); | |
109 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
110 ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags)) | |
111 } else { | |
112 ErrorCode::Ignore as c_int | |
113 } | |
114 } | |
115 | |
116 #[no_mangle] | |
117 extern "C" fn pam_sm_setcred( | |
118 pamh: *mut libc::c_void, | |
119 flags: Flags, | |
120 argc: c_int, | |
121 argv: *const *const c_char, | |
122 ) -> c_int { | |
123 let args = extract_argv(argc, argv); | |
124 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
125 ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, flags)) | |
126 } else { | |
127 ErrorCode::Ignore as c_int | |
128 } | |
129 } | |
130 | |
131 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. | |
132 /// | |
133 /// # Safety | |
134 /// | |
135 /// We use this only with arguments we get from `libpam`, which we kind of have to trust. | |
136 fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { | |
137 (0..argc) | |
138 .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) | |
139 .collect() | |
140 } | |
141 } | |
142 }; | |
143 } | |
144 | |
145 #[cfg(test)] | |
146 mod tests { | |
147 // Compile-time test that the `pam_hooks` macro compiles. | |
148 use crate::{PamHandleModule, PamModule}; | |
149 struct Foo; | |
150 impl<T: PamHandleModule> PamModule<T> for Foo {} | |
151 | |
152 pam_hooks!(Foo); | |
153 } |