Crate nonstick

Crate nonstick 

Source
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 libpam submodule (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.

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§

AuthnFlags
Flags for authentication and account management.
AuthtokFlags
Flags for changing the authentication token.
BaseFlags
Common flag(s) shared by all PAM actions.
BinaryData
Owned binary data.
LibPamHandle
An owned variation of a basic PAM handle.
LibPamTransaction
An owned PAM handle.
TransactionBuilder
Builder to start a LibPamTransaction.

Enums§

AuthtokAction
The action that a module should take during a change_authtok call.
CredAction
The credential management action that should take place.
ErrorCode
The PAM error return codes.

Traits§

Conversation
A channel for PAM modules to request information from the user.
ConversationAdapter
A conversation trait for asking or answering one question at a time.
EnvironMap
A read-only key/value map for environment variables, as OsStrings.
EnvironMapMut
A read/write key/value map for environment variables as OsStrings.
ModuleClient
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.

Type Aliases§

Result
A PAM-specific Result type with an ErrorCode error.