Expand description
🍳 A safe, nonstick interface to the Pluggable Authentication Modules framework.
Nonstick provides a fully type- and memory-safe interface to all implementations of PAM, both for PAM modules and PAM applications.
§Usage
nonstick can be used on either side of a PAM transaction, both to implement an application which calls into PAM, or a module which implements a PAM backend.
For more information about how PAM works in general, or more pointers on how to implement a PAM module or application, see the References section.
§PAM Application
To implement a PAM application, first implement a Conversation,
then build a Transaction with the TransactionBuilder.
This can be built into any standard Rust library or binary.
use nonstick::{
AuthnFlags, Conversation, ConversationAdapter, Result as PamResult, Transaction,
TransactionBuilder,
};
use std::ffi::{OsStr, OsString};
/// A basic Conversation that assumes that any "regular" prompt is for
/// the username, and that any "masked" prompt is for the password.
///
/// A typical Conversation will provide the user with an interface
/// to interact with PAM, e.g. a dialogue box or a terminal prompt.
struct UsernamePassConvo {
username: String,
password: String,
}
// ConversationAdapter is a convenience wrapper for the common case
// of only handling one request at a time.
impl ConversationAdapter for UsernamePassConvo {
fn prompt(&self, request: impl AsRef<OsStr>) -> PamResult<OsString> {
Ok(OsString::from(&self.username))
}
fn masked_prompt(&self, request: impl AsRef<OsStr>) -> PamResult<OsString> {
Ok(OsString::from(&self.password))
}
fn error_msg(&self, message: impl AsRef<OsStr>) {
// Normally you would want to display this to the user somehow.
// In this case, we're just ignoring it.
}
fn info_msg(&self, message: impl AsRef<OsStr>) {
// ibid.
}
}
fn authenticate(username: &str, password: &str) -> PamResult<()> {
let user_pass = UsernamePassConvo {
username: username.into(),
password: password.into(),
};
let mut txn = TransactionBuilder::new_with_service("cortex-sso")
.username(username)
.build(user_pass.into_conversation())?;
// If authentication fails, this will return an error.
// We immediately give up rather than re-prompting the user.
txn.authenticate(AuthnFlags::empty())?;
txn.account_management(AuthnFlags::empty())?;
Ok(())
}PAM just tells you that the user is, in fact, who they say they are. It is up to your application to choose what to do with that information.
§PAM module
PAM modules are implemented as dynamic libraries loaded into
the address space of the calling application. To implement a module,
create a dylib crate and implement a PamModule, and export it
using the pam_export! macro.
# Your Cargo.toml
[package]
name = "samename"
description = "Checks that username and password are the same"
# ...
[lib]
crate-type = ["cdylib"]
[dependencies]
nonstick = "0.1"
# ...Once you’ve set up the dylib crate and added nonstick as a dependency,
you can write the code itself:
// Your lib.rs
use nonstick::{
pam_export, AuthnFlags, ErrorCode, ModuleClient, PamModule, Result as PamResult,
};
use std::ffi::CStr;
/// A module that only allows you to log in if your username
/// is the same as your password.
struct SameName;
pam_export!(SameName);
impl<M: ModuleClient> PamModule<M> for SameName {
fn authenticate(handle: &mut M, _args: Vec<&CStr>, _flags: AuthnFlags) -> PamResult<()> {
// Using `None` as the prompt parameter here will tell PAM
// to use the default prompt.
let username = handle.username(None)?;
let password = handle.authtok(None)?;
if username == password {
Ok(())
} else {
Err(ErrorCode::AuthenticationError)
}
}
// You can implement other methods of PamModule to provide additional
// features.
}This gets built into a shared object. By installing this into the PAM
library directory at a place like pam_samename.so and configuring PAM
to use it in the authentication stack (beyond the scope of this
documentation), it will be used to authenticate users.
§Configuration
There are a few different PAM implementations available. By default,
nonstick detects which implementation it should use for the current target.
If you need to choose a different implementation, set the LIBPAMSYS_IMPL
environment variable at build time. See the libpam_sys documentation.
This documentation was built for LinuxPam.
§Cargo features
This crate provides the following Cargo features:
- link (enabled by default): Actually link against PAM, rather than just providing an abstract PAM interface. Enabling this will fail if extensions incompatible with the PAM implementation you’re linking against are also enabled.
- Extensions beyond the PAM specification provided by various PAM
implementations:
- basic-ext: Enable extensions provided by both Linux-PAM and OpenPAM. This is limited to a few return enums.
- linux-pam-ext (includes basic-ext): Enable extensions provided by Linux-PAM. This includes enum values and the ability to send binary messages between the PAM module and the application.
- openpam-ext (includes basic-ext): Enable extensions provided by OpenPAM. This includes enum values.
- sun-ext: Enable extensions provided by Sun PAM. This includes enum values.
§Design
This library consists of two parts:
-
The generic PAM interface, a set of traits describing the behavior of PAM and the API we export. It is independent of the PAM library itself and could be implemented by any crate to provide PAM-like services. This is primarily intended to allow a developer to test their PAM modules and applications by writing mock implementations to verify their application (or module) code’s interactions with PAM itself.
-
The bindings to LibPAM itself. This part is included only when link is enabled. These live in the
libpamsubmodule (with a few exceptions for constant-related code).
§References
These documents were used when authoring this library and will probably be of value if you want to implement a PAM module or a PAM application.
- The Linux-PAM guides provide information for a variety of audiences. While some of it is specific to Linux-PAM, much of it applies to other PAM implementations:
- PAM framework man pages for developers:
- PAM framework man pages for system administrators:
- The original PAM specification (mostly of historical interest)
- Wikipedia: Cooking spray
Modules§
- constants
- Constants and enum values from the PAM library.
- conv
- The PAM conversation and associated Stuff.
- handle
- The wrapper types and traits for handles into the PAM library.
- items
- libpam
- The implementation of the PAM interface that wraps
libpam. - logging
- PAM logging variables and macros.
- module
- Functions and types useful for implementing a PAM module.
- pam_
impl - Information about the current PAM implementation (or the implementation that is being built for).
Macros§
- debug
- Logs a message at debug level via the given PAM handle.
- error
- Logs a message at error level via the given PAM handle.
- info
- Logs a message at info level via the given PAM handle.
- pam_
export - Generates the dynamic library entry points for a PAM module
- warn
- Logs a message at warning level via the given PAM handle.
Structs§
- Authn
Flags - Flags for authentication and account management.
- Authtok
Flags - Flags for changing the authentication token.
- Base
Flags - Common flag(s) shared by all PAM actions.
- Binary
Data - Owned binary data.
- LibPam
Handle - An owned variation of a basic PAM handle.
- LibPam
Transaction - An owned PAM handle.
- Transaction
Builder - Builder to start a
LibPamTransaction.
Enums§
- Authtok
Action - The action that a module should take during a
change_authtokcall. - Cred
Action - The credential management action that should take place.
- Error
Code - The PAM error return codes.
Traits§
- Conversation
- A channel for PAM modules to request information from the user.
- Conversation
Adapter - A conversation trait for asking or answering one question at a time.
- Environ
Map - A read-only key/value map for environment variables, as
OsStrings. - Environ
MapMut - A read/write key/value map for environment variables as
OsStrings. - Module
Client - Functionality of a PAM handle that can be expected by a PAM module.
- PamModule
- A trait for a PAM module to implement.
- PamShared
- Functionality for both PAM applications and PAM modules.
- Transaction
- Functionality of a PAM handle that can be expected by a PAM application.