comparison src/libpam/module.rs @ 166:2f5913131295

Separate flag/action flags into flags and action. This also individualizes the type of flag for each PAM function, so that you can only call a function with the right flags and values.
author Paul Fisher <paul@pfish.zone>
date Tue, 15 Jul 2025 00:32:24 -0400
parents 1bc52025156b
children e27c5c667a5a
comparison
equal deleted inserted replaced
165:c4b1e280463c 166:2f5913131295
9 /// Here is full example of a PAM module that would authenticate 9 /// Here is full example of a PAM module that would authenticate
10 /// and authorize everybody: 10 /// and authorize everybody:
11 /// 11 ///
12 /// ```no_run 12 /// ```no_run
13 /// use nonstick::{ 13 /// use nonstick::{
14 /// pam_hooks, ConversationAdapter, Flags, LibPamTransaction, ModuleClient, PamModule, 14 /// pam_hooks, ConversationAdapter, AuthnFlags, LibPamTransaction, ModuleClient, PamModule,
15 /// Result as PamResult, 15 /// Result as PamResult,
16 /// }; 16 /// };
17 /// use std::ffi::CStr; 17 /// use std::ffi::CStr;
18 /// # fn main() {} 18 /// # fn main() {}
19 /// 19 ///
20 /// struct MyPamModule; 20 /// struct MyPamModule;
21 /// pam_hooks!(MyPamModule); 21 /// pam_hooks!(MyPamModule);
22 /// 22 ///
23 /// impl<T: ModuleClient> PamModule<T> for MyPamModule { 23 /// impl<T: ModuleClient> PamModule<T> for MyPamModule {
24 /// fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { 24 /// fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: AuthnFlags) -> PamResult<()> {
25 /// let password = handle.authtok(Some("what's your password?".as_ref()))?; 25 /// let password = handle.authtok(Some("what's your password?".as_ref()))?;
26 /// let response = 26 /// let response =
27 /// format!("If you say your password is {password:?}, who am I to disagree?"); 27 /// format!("If you say your password is {password:?}, who am I to disagree?");
28 /// handle.info_msg(&response); 28 /// handle.info_msg(&response);
29 /// Ok(()) 29 /// Ok(())
30 /// } 30 /// }
31 /// 31 ///
32 /// fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { 32 /// fn account_management(handle: &mut T, args: Vec<&CStr>, flags: AuthnFlags) -> PamResult<()> {
33 /// let username = handle.username(None)?; 33 /// let username = handle.username(None)?;
34 /// let response = format!("Hello {username:?}! I trust you unconditionally."); 34 /// let response = format!("Hello {username:?}! I trust you unconditionally.");
35 /// handle.info_msg(&response); 35 /// handle.info_msg(&response);
36 /// Ok(()) 36 /// Ok(())
37 /// } 37 /// }
40 #[macro_export] 40 #[macro_export]
41 macro_rules! pam_hooks { 41 macro_rules! pam_hooks {
42 ($ident:ident) => { 42 ($ident:ident) => {
43 mod _pam_hooks_scope { 43 mod _pam_hooks_scope {
44 use std::ffi::{c_char, c_int, c_void, CStr}; 44 use std::ffi::{c_char, c_int, c_void, CStr};
45 use $crate::{ErrorCode, Flags, LibPamHandle, PamModule}; 45 use $crate::{
46 AuthnFlags, AuthtokAction, BaseFlags, CredAction, ErrorCode, LibPamHandle,
47 PamModule,
48 };
49
50 macro_rules! handle {
51 ($pamh:ident) => {
52 match unsafe { $pamh.cast::<LibPamHandle>().as_mut() } {
53 Some(handle) => handle,
54 None => return ErrorCode::Ignore.into(),
55 }
56 };
57 }
46 58
47 #[no_mangle] 59 #[no_mangle]
48 extern "C" fn pam_sm_acct_mgmt( 60 extern "C" fn pam_sm_acct_mgmt(
49 pamh: *mut c_void, 61 pamh: *mut c_void,
50 flags: Flags, 62 flags: AuthnFlags,
51 argc: c_int, 63 argc: c_int,
52 argv: *const *const c_char, 64 argv: *const *const c_char,
53 ) -> c_int { 65 ) -> c_int {
54 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { 66 let handle = handle!(pamh);
55 let args = extract_argv(argc, argv); 67 let args = extract_argv(argc, argv);
56 ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags)) 68 ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags))
57 } else {
58 ErrorCode::Ignore as c_int
59 }
60 } 69 }
61 70
62 #[no_mangle] 71 #[no_mangle]
63 extern "C" fn pam_sm_authenticate( 72 extern "C" fn pam_sm_authenticate(
64 pamh: *mut c_void, 73 pamh: *mut c_void,
65 flags: Flags, 74 flags: AuthnFlags,
66 argc: c_int, 75 argc: c_int,
67 argv: *const *const c_char, 76 argv: *const *const c_char,
68 ) -> c_int { 77 ) -> c_int {
69 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { 78 let handle = handle!(pamh);
70 let args = extract_argv(argc, argv); 79 let args = extract_argv(argc, argv);
71 ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags)) 80 ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags))
72 } else {
73 ErrorCode::Ignore as c_int
74 }
75 } 81 }
76 82
77 #[no_mangle] 83 #[no_mangle]
78 extern "C" fn pam_sm_chauthtok( 84 extern "C" fn pam_sm_chauthtok(
79 pamh: *mut c_void, 85 pamh: *mut c_void,
80 flags: Flags, 86 flags: c_int,
81 argc: c_int, 87 argc: c_int,
82 argv: *const *const c_char, 88 argv: *const *const c_char,
83 ) -> c_int { 89 ) -> c_int {
84 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { 90 let handle = handle!(pamh);
85 let args = extract_argv(argc, argv); 91 let (action, flags) = match AuthtokAction::extract(flags) {
86 ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, flags)) 92 Ok(val) => val,
87 } else { 93 Err(e) => return e.into(),
88 ErrorCode::Ignore as c_int 94 };
89 } 95 let args = extract_argv(argc, argv);
96 ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, action, flags))
90 } 97 }
91 98
92 #[no_mangle] 99 #[no_mangle]
93 extern "C" fn pam_sm_close_session( 100 extern "C" fn pam_sm_close_session(
94 pamh: *mut c_void, 101 pamh: *mut c_void,
95 flags: Flags, 102 flags: BaseFlags,
96 argc: c_int, 103 argc: c_int,
97 argv: *const *const c_char, 104 argv: *const *const c_char,
98 ) -> c_int { 105 ) -> c_int {
99 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { 106 let handle = handle!(pamh);
100 let args = extract_argv(argc, argv); 107 let args = extract_argv(argc, argv);
101 ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags)) 108 ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags))
102 } else {
103 ErrorCode::Ignore as c_int
104 }
105 } 109 }
106 110
107 #[no_mangle] 111 #[no_mangle]
108 extern "C" fn pam_sm_open_session( 112 extern "C" fn pam_sm_open_session(
109 pamh: *mut c_void, 113 pamh: *mut c_void,
110 flags: Flags, 114 flags: BaseFlags,
111 argc: c_int, 115 argc: c_int,
112 argv: *const *const c_char, 116 argv: *const *const c_char,
113 ) -> c_int { 117 ) -> c_int {
118 let handle = handle!(pamh);
114 let args = extract_argv(argc, argv); 119 let args = extract_argv(argc, argv);
115 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { 120 ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags))
116 ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags))
117 } else {
118 ErrorCode::Ignore as c_int
119 }
120 } 121 }
121 122
122 #[no_mangle] 123 #[no_mangle]
123 extern "C" fn pam_sm_setcred( 124 extern "C" fn pam_sm_setcred(
124 pamh: *mut c_void, 125 pamh: *mut c_void,
125 flags: Flags, 126 flags: c_int,
126 argc: c_int, 127 argc: c_int,
127 argv: *const *const c_char, 128 argv: *const *const c_char,
128 ) -> c_int { 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 };
129 let args = extract_argv(argc, argv); 135 let args = extract_argv(argc, argv);
130 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { 136 ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, action, flags))
131 ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, flags))
132 } else {
133 ErrorCode::Ignore as c_int
134 }
135 } 137 }
136 138
137 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. 139 /// Turns `argc`/`argv` into a [Vec] of [CStr]s.
138 /// 140 ///
139 /// # Safety 141 /// # Safety