comparison libpam-sys/src/lib.rs @ 136:efbc235f01d3 default tip

Separate libpam-sys-helpers from libpam-sys. This separates the parts of libpam-sys that don't need linking against libpam from the parts that do need to link against libpam.
author Paul Fisher <paul@pfish.zone>
date Thu, 03 Jul 2025 14:28:04 -0400
parents libpam-sys/src/ffi.rs@6c1e1bdb4164
children
comparison
equal deleted inserted replaced
135:b52594841480 136:efbc235f01d3
1 #![doc = include_str!("../README.md")] 1 //! `libpam-sys` provides low-level access to `libpam`.
2 //! 2 //!
3 //! ## PAM implementation 3 //! Everything in here is directly as exported from the `libpam` library or
4 //! its header files, with limited exceptions:
4 //! 5 //!
5 #![doc = concat!("This documentation was built for the **", env!("LIBPAMSYS_IMPL"), "** implementation.")] 6 //! - The [`pam_impl`] submodule (and the [`pam_impl_name!`] macro) contains
6 7 //! tools for detecting the current PAM library.
7 mod constants; 8 //! - [`AppData`] is an opaque pointer newtype.
8 mod ffi; 9 //! - [`ConversationCallback`] and [`CleanupCallback`] are aliases for
9 pub mod helpers; 10 //! what are otherwise anonymous function types.
10 pub mod pam_impl; 11 //!
12 #![doc = concat!("This documentation was built for the **", pam_impl_name!(), "** implementation.")]
13 //!
14 //! You can override this **at build time** by setting the `LIBPAMSYS_IMPL`
15 //! environment variable to one of the values of the [`pam_impl::PamImpl`] enum.
16 //!
17 //! For more information about configuration, see [the README](https://crates.io/crate/libpam-sys).
18 #![allow(non_camel_case_types)]
19 #![allow(unused_imports)]
11 20
12 #[doc(inline)] 21 #[doc(inline)]
13 pub use crate::{constants::*, ffi::*, pam_impl::*}; 22 pub use libpam_sys_helpers::constants::*;
23 #[doc(inline)]
24 pub use libpam_sys_helpers::{pam_impl, pam_impl_name};
25 use num_enum::{IntoPrimitive, TryFromPrimitive};
26 use std::ffi::{c_char, c_int, c_uint, c_void};
27 use std::fmt;
28 use std::marker::{PhantomData, PhantomPinned};
29
30 /// A marker struct to make whatever it's in `!Sync`, `!Send`, and `!Unpin`.
31 #[derive(Default, PartialOrd, PartialEq, Ord, Eq)]
32 #[repr(C)]
33 struct ExtremelyUnsafe {
34 _value: (),
35 _marker: PhantomData<(PhantomPinned, *mut c_void)>,
36 }
37
38 impl fmt::Debug for ExtremelyUnsafe {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "ExtremelyUnsafe({self:p})")
41 }
42 }
43
44 /// An opaque structure that PAM uses to communicate.
45 ///
46 /// This is only ever returned in pointer form and cannot be constructed.
47 #[repr(C)]
48 pub struct pam_handle(ExtremelyUnsafe);
49
50 impl fmt::Debug for pam_handle {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 write!(f, "pam_handle({self:p}")
53 }
54 }
55
56 /// An opaque structure that is passed through PAM in a conversation.
57 #[repr(C)]
58 pub struct AppData(ExtremelyUnsafe);
59
60 impl fmt::Debug for AppData {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "AppData({self:p}")
63 }
64 }
65
66 /// Just an alias for the type of [`pam_conv::conv`].
67 ///
68 /// For important details about the format of `messages`,
69 /// see [`libpam_sys_helpers::memory::PtrPtrVec`].
70 ///
71 /// ```no_run
72 /// # use libpam_sys::{ConversationCallback, pam_conv};
73 /// fn convo() -> ConversationCallback {
74 /// // ...
75 /// # unimplemented!()
76 /// }
77 /// let conv = pam_conv{conv: convo(), appdata_ptr: std::ptr::null_mut()};
78 /// ```
79 pub type ConversationCallback = unsafe extern "C" fn(
80 num_msg: c_int,
81 msg: *const *const pam_message,
82 resp: *mut *mut pam_response,
83 appdata: *mut AppData,
84 ) -> c_int;
85
86 /// Alias for the callback to [`pam_set_data`].
87 ///
88 /// ```no_run
89 /// # use std::ffi::CString;
90 /// use libpam_sys::{CleanupCallback, pam_set_data};
91 /// # use libpam_sys::pam_handle;
92 /// # let handle: *mut pam_handle = std::ptr::null_mut();
93 /// # let mut my_data = 100;
94 /// # let data_ptr = &mut my_data as *mut i32;
95 /// fn cleanup() -> CleanupCallback {
96 /// // ...
97 /// # unimplemented!()
98 /// }
99 /// let name = CString::new("name").unwrap();
100 /// unsafe {
101 /// pam_set_data(handle, name.as_ptr().cast_mut(), data_ptr.cast(), cleanup());
102 /// }
103 /// ```
104 pub type CleanupCallback =
105 unsafe extern "C" fn(pamh: *mut pam_handle, data: *mut c_void, pam_end_status: c_int);
106
107 /// Used by PAM to communicate between the module and the application.
108 #[repr(C)]
109 pub struct pam_conv {
110 pub conv: unsafe extern "C" fn(
111 num_msg: c_int,
112 msg: *const *const pam_message,
113 resp: *mut *mut pam_response,
114 appdata: *mut AppData,
115 ) -> c_int,
116 pub appdata_ptr: *mut AppData,
117 }
118
119 /// A message sent into a PAM conversation.
120 #[repr(C)]
121 pub struct pam_message {
122 pub msg_style: c_int,
123 pub msg: *const c_char,
124 }
125
126 /// A response returned from a PAM conversation.
127 #[repr(C)]
128 pub struct pam_response {
129 pub resp: *mut c_char,
130 /// Completely unused.
131 pub resp_retcode: c_int,
132 }
133
134 /// Definition of the PAM_XAUTHDATA item. Compatible with `xcb_auth_info_t`.
135 #[cfg(pam_impl = "LinuxPam")]
136 #[repr(C)]
137 pub struct pam_xauth_data {
138 pub namelen: c_int,
139 pub name: *mut c_char,
140 pub datalen: c_int,
141 pub data: *mut c_char,
142 }
143
144 #[cfg(pam_impl = "LinuxPam")]
145 #[derive(Debug)]
146 #[repr(C)]
147 pub struct pam_modutil_privs {
148 pub grplist: *mut libc::gid_t,
149 pub number_of_groups: c_int,
150 pub allocated: c_int,
151 pub old_gid: libc::gid_t,
152 pub old_uid: libc::uid_t,
153 pub is_dropped: c_int,
154 }
155
156 #[cfg(pam_impl = "OpenPam")]
157 pub type pam_func_t = unsafe extern "C" fn(
158 handle: *mut pam_handle,
159 flags: c_int,
160 argc: c_int,
161 argv: *const *const c_char,
162 ) -> c_int;
163
164 #[cfg(pam_impl = "OpenPam")]
165 #[derive(Debug)]
166 #[repr(C)]
167 pub struct pam_module {
168 pub path: *mut c_char,
169 pub func: [pam_func_t; 6],
170 pub dlh: *mut c_void,
171 }
172
173 #[cfg(pam_impl = "OpenPam")]
174 #[derive(Debug)]
175 #[repr(C)]
176 pub struct pam_repository {
177 pub typ: *mut c_char,
178 pub scope: *mut c_void,
179 pub scope_len: usize,
180 }
181
182 // These are the functions specified in X/SSO. Everybody exports them.
183 #[link(name = "pam")]
184 extern "C" {
185 /// Account validation.
186 pub fn pam_acct_mgmt(pamh: *mut pam_handle, flags: c_int) -> c_int;
187
188 /// Authenticate a user.
189 pub fn pam_authenticate(pamh: *mut pam_handle, flags: c_int) -> c_int;
190
191 // Nobody implements pam_authenticate_secondary.
192
193 /// Manage authentication tokens.
194 pub fn pam_chauthtok(pamh: *mut pam_handle, flags: c_int) -> c_int;
195
196 /// Close an opened user session.
197 pub fn pam_close_session(pamh: *mut pam_handle, flags: c_int) -> c_int;
198
199 /// Ends the PAM transaction.
200 pub fn pam_end(pamh: *mut pam_handle, flags: c_int) -> c_int;
201
202 /// Gets module-specific data. PAM still owns the data.
203 pub fn pam_get_data(
204 pamh: *mut pam_handle,
205 module_data_name: *const c_char,
206 data: *mut *const c_void,
207 ) -> c_int;
208
209 /// Gets an environment variable. You own the return value.
210 pub fn pam_getenv(pamh: *const pam_handle, name: *const c_char) -> *mut c_char;
211
212 /// Gets all the environment variables. You own everything it points to.
213 pub fn pam_getenvlist(pamh: *const pam_handle) -> *mut *mut c_char;
214
215 /// Get information about the transaction.
216 ///
217 /// The item is owned by PAM.
218 pub fn pam_get_item(
219 pamh: *const pam_handle,
220 item_type: c_int,
221 item: *mut *const c_void,
222 ) -> c_int;
223
224 // Nobody implements pam_get_mapped_authtok.
225 // Nobody implements pam_get_mapped_username.
226
227 /// Get the username. PAM owns it.
228 pub fn pam_get_user(
229 pamh: *mut pam_handle,
230 user: *mut *const c_char,
231 prompt: *const c_char,
232 ) -> c_int;
233
234 /// Opens a user session.
235 pub fn pam_open_session(pamh: *mut pam_handle, flags: c_int) -> c_int;
236
237 /// Sets the value of an environment variable. `namevalue` is copied.
238 pub fn pam_putenv(pamh: *mut pam_handle, namevalue: *const c_char) -> c_int;
239
240 /// Update or delete user credentials.
241 pub fn pam_setcred(pamh: *mut pam_handle, flags: c_int) -> c_int;
242
243 /// Set module-specific data. PAM will call `cleanup` when completed.
244 pub fn pam_set_data(
245 pamh: *mut pam_handle,
246 module_data_name: *const c_char,
247 data: *mut c_void,
248 cleanup: unsafe extern "C" fn(
249 pamh: *mut pam_handle,
250 data: *mut c_void,
251 pam_end_status: c_int,
252 ),
253 ) -> c_int;
254
255 /// Set information about the transaction. The `item` is copied.
256 pub fn pam_set_item(pamh: *mut pam_handle, item_type: c_int, item: *const c_void) -> c_int;
257
258 // Nobody implements pam_set_mapped_authtok.
259 // Nobody implements pam_set_mapped_username.
260
261 // The pam_sm_whatever functions are prototypes for the functions that
262 // a PAM module should implement, not symbols provided by PAM.
263
264 // Nobody implements pam_authenticate_secondary.
265
266 /// Starts a PAM transaction. The `conv` may or may not be copied.
267 pub fn pam_start(
268 service: *const c_char,
269 user: *const c_char,
270 pam_conv: *mut pam_conv,
271 pamh: *mut *mut pam_handle,
272 ) -> c_int;
273
274 /// Gets a statically-allocated error string.
275 ///
276 /// All implementations of PAM known to this library (Linux-PAM, OpenPAM,
277 /// and Sun) ignore `pamh` and will accept a null pointer.
278 pub fn pam_strerror(pamh: *const pam_handle, error_number: c_int) -> *mut c_char;
279 }
280
281 #[cfg(any(pam_impl = "LinuxPam", pam_impl = "OpenPam"))]
282 extern "C" {
283 /// Gets `PAM_AUTHTOK`, or asks the user if that is unset.
284 pub fn pam_get_authtok(
285 pamh: *mut pam_handle,
286 item: c_int,
287 authtok: *mut *const c_char,
288 prompt: *const c_char,
289 ) -> c_int;
290
291 pub fn pam_prompt(
292 pamh: *const pam_handle,
293 style: c_int,
294 response: *mut *mut c_char,
295 fmt: *const c_char,
296 ...
297 ) -> c_int;
298
299 }
300
301 #[cfg(pam_impl = "LinuxPam")]
302 extern "C" {
303 pub fn pam_fail_delay(pamh: *mut pam_handle, musec_delay: c_uint) -> c_int;
304
305 /// Start a PAM transaction based on configuration in the given directory.
306 pub fn pam_start_confdir(
307 service_name: *const c_char,
308 user: *const c_char,
309 pam_conversation: *mut pam_conv,
310 confdir: *const c_char,
311 pamh: *mut *mut pam_handle,
312 ) -> c_int;
313
314 // We don't export the v-variants of the formatting functions.
315
316 pub fn pam_syslog(pamh: *const pam_handle, priority: c_int, fmt: *const c_char, ...);
317
318 pub fn pam_get_authtok_noverify(
319 pamh: *const pam_handle,
320 authtok: *mut *const c_char,
321 prompt: *const c_char,
322 ) -> c_int;
323
324 pub fn pam_get_authtok_verify(
325 pamh: *const pam_handle,
326 authtok: *mut *const c_char,
327 prompt: *const c_char,
328 ) -> c_int;
329
330 // pam_modutil also lives in libpam for Linux.
331
332 pub fn pam_modutil_check_user_in_passwd(
333 pamh: *mut pam_handle,
334 user_name: *const c_char,
335 file_name: *const c_char,
336 ) -> c_int;
337
338 pub fn pam_modutil_getpwnam(pamh: *mut pam_handle, user: *const c_char) -> *mut libc::passwd;
339
340 pub fn pam_modutil_getpwuid(pamh: *mut pam_handle, uid: libc::uid_t) -> *mut libc::passwd;
341
342 pub fn pam_modutil_getgrnam(pamh: *mut pam_handle, group: *const c_char) -> *mut libc::group;
343
344 pub fn pam_modutil_getgrgid(pamh: *mut pam_handle, gid: libc::gid_t) -> *mut libc::group;
345
346 pub fn pam_modutil_getspnam(pamh: *mut pam_handle, user: *const c_char) -> *mut libc::spwd;
347
348 pub fn pam_modutil_user_in_group_nam_nam(
349 pamh: *mut pam_handle,
350 user: *const c_char,
351 group: *const c_char,
352 ) -> c_int;
353 pub fn pam_modutil_user_in_group_nam_gid(
354 pamh: *mut pam_handle,
355 user: *const c_char,
356 group: libc::gid_t,
357 ) -> c_int;
358
359 pub fn pam_modutil_user_in_group_uid_nam(
360 pamh: *mut pam_handle,
361 user: libc::uid_t,
362 group: *const c_char,
363 ) -> c_int;
364
365 pub fn pam_modutil_user_in_group_uid_gid(
366 pamh: *mut pam_handle,
367 user: libc::uid_t,
368 group: libc::gid_t,
369 ) -> c_int;
370
371 pub fn pam_modutil_getlogin(pamh: *mut pam_handle) -> *const c_char;
372
373 pub fn pam_modutil_read(fd: c_int, buffer: *mut c_char, count: c_int) -> c_int;
374
375 pub fn pam_modutil_write(fd: c_int, buffer: *const c_char, count: c_int) -> c_int;
376
377 pub fn pam_modutil_audit_write(
378 pamh: *mut pam_handle,
379 typ: c_int,
380 message: *const c_char,
381 retval: c_int,
382 ) -> c_int;
383
384 pub fn pam_modutil_drop_priv(
385 pamh: *mut pam_handle,
386 p: *mut pam_modutil_privs,
387 pw: *const libc::passwd,
388 ) -> c_int;
389
390 pub fn pam_modutil_regain_priv(pamh: *mut pam_handle, p: *mut pam_modutil_privs) -> c_int;
391
392 pub fn pam_modutil_sanitize_helper_fds(
393 pamh: *mut pam_handle,
394 redirect_stdin: pam_modutil_redirect_fd,
395 redirect_stdout: pam_modutil_redirect_fd,
396 redirect_stderr: pam_modutil_redirect_fd,
397 ) -> c_int;
398
399 pub fn pam_modutil_search_key(
400 pamh: *mut pam_handle,
401 file_name: *const c_char,
402 key: *const c_char,
403 ) -> *mut c_char;
404 }
405
406 #[cfg(pam_impl = "OpenPam")]
407 extern "C" {
408 pub fn openpam_borrow_cred(pamh: *mut pam_handle, passwd: *const libc::passwd) -> c_int;
409
410 pub fn openpam_subst(
411 pamh: *const pam_handle,
412 buf: *mut c_char,
413 _bufsize: *mut usize,
414 _template: *const c_char,
415 ) -> c_int;
416
417 pub fn openpam_free_data(pamh: *mut pam_handle, data: *mut c_void, status: c_int);
418
419 pub fn openpam_free_envlist(_envlist: *mut *mut c_char);
420
421 pub fn openpam_get_option(_pamh: *mut pam_handle, _option: *const c_char) -> *const c_char;
422
423 pub fn openpam_restore_cred(pamh: *mut pam_handle) -> c_int;
424
425 pub fn openpam_set_option(
426 _pamh: *mut pam_handle,
427 _option: *const c_char,
428 _value: *const c_char,
429 ) -> c_int;
430
431 pub fn pam_error(pamh: *const pam_handle, _fmt: *const c_char, ...) -> c_int;
432
433 pub fn pam_info(_pamh: *const pam_handle, _fmt: *const c_char, ...) -> c_int;
434
435 pub fn openpam_readline(
436 _f: *mut libc::FILE,
437 _lineno: *mut c_int,
438 _lenp: *mut usize,
439 ) -> *mut c_char;
440
441 pub fn openpam_readlinev(
442 _f: *mut libc::FILE,
443 _lineno: *mut c_int,
444 _lenp: *mut c_int,
445 ) -> *mut *mut c_char;
446
447 pub fn openpam_readword(
448 _f: *mut libc::FILE,
449 _lineno: *mut c_int,
450 _lenp: *mut usize,
451 ) -> *mut c_char;
452
453 pub fn openpam_straddch(
454 _str: *mut *mut c_char,
455 _sizep: *mut usize,
456 _lenp: *mut usize,
457 ch: c_int,
458 ) -> c_int;
459
460 pub fn openpam_set_feature(_feature: c_int, _onoff: c_int) -> c_int;
461
462 pub fn openpam_get_feature(_feature: c_int, _onoff: *mut c_int) -> c_int;
463
464 pub fn _openpam_log(_level: c_int, _func: *const c_char, _fmt: *const c_char, ...);
465
466 /// A premade conversation function that talks to the TTY.
467 ///
468 /// ```no_run
469 /// # use std::ffi::CString;
470 /// # use std::ptr;
471 /// use libpam_sys::*;
472 /// # let service = CString::new("whatever").unwrap();
473 /// # let user = CString::new("whatever").unwrap();
474 /// let mut handle: *mut pam_handle = ptr::null_mut();
475 /// let mut conv = pam_conv{
476 /// conv: openpam_ttyconv,
477 /// appdata_ptr: ptr::null_mut(),
478 /// };
479 /// let result = unsafe { pam_start(
480 /// service.as_ptr(), user.as_ptr(), &mut conv, &mut handle
481 /// ) };
482 /// ```
483 pub fn openpam_ttyconv(
484 n: c_int,
485 _msg: *const *const pam_message,
486 _resp: *mut *mut pam_response,
487 _data: *mut AppData,
488 ) -> c_int;
489
490 pub static mut openpam_ttyconv_timeout: c_int;
491
492 /// A null conversation function.
493 ///
494 /// ```no_run
495 /// # use std::ffi::CString;
496 /// # use std::ptr;
497 /// use libpam_sys::*;
498 /// # let service = CString::new("whatever").unwrap();
499 /// # let user = CString::new("whatever").unwrap();
500 /// let mut handle: *mut pam_handle = ptr::null_mut();
501 /// let mut conv = pam_conv{
502 /// conv: openpam_nullconv,
503 /// appdata_ptr: ptr::null_mut(),
504 /// };
505 /// let result = unsafe { pam_start(
506 /// service.as_ptr(), user.as_ptr(), &mut conv, &mut handle
507 /// ) };
508 /// ```
509 pub fn openpam_nullconv(
510 n: c_int,
511 _msg: *const *const pam_message,
512 _resp: *mut *mut pam_response,
513 _data: *mut AppData,
514 ) -> c_int;
515 }