PAMELA: Python PAM Interface
Pamela is a Python wrapper for Pluggable Authentication Modules (PAM) that utilizes `ctypes` to interface with the system's PAM libraries. It merges functionality from previously abandoned Python PAM projects (gnosek/python-pam and simplepam) to provide robust Python 3 support, raise informative `PamError` exceptions on failure, and manage PAM sessions. Maintained by Project Jupyter, it aims to offer a reliable and up-to-date solution for system authentication on Unix-like operating systems. The current version is 1.2.0, released in August 2024, indicating active development.
Common errors
-
TypeError: LoadLibrary() argument 1 must be str, not None
cause This error typically occurs when `ctypes.util.find_library('c')` or `find_library('pam')` returns `None`, meaning the underlying C or PAM library cannot be located on the system. This is common on Windows or minimalist Linux environments.fixPamela is designed for Unix-like systems. Ensure you are running on a compatible OS (Linux, macOS). On some minimal Linux distributions, you may need to install development packages for PAM (e.g., `libpam-dev` or `pam-devel`). -
pamela.PAMError: [PAM Error 26] Critical error - immediate abort
cause This error has been observed in testing environments, particularly with Python 3.14 beta versions, indicating a critical PAM operation failure.fixIf encountering this error, verify your Python version. This might be a compatibility issue with newer Python releases; consider downgrading to Python 3.13 or earlier. Check the `jupyterhub/pamela` GitHub issues for updates on Python 3.14 compatibility. -
ModuleNotFoundError: No module named 'pamela'
cause The `pamela` package is not installed in the active Python environment or the Python interpreter cannot find it.fixInstall the package using pip: `pip install pamela`. If using a virtual environment, ensure it's activated before installation and execution. -
Authentication failed for user: <username>.
cause This generic message from `pamela.authenticate` usually means the provided username/password combination is incorrect for the specified PAM service, or the PAM service itself is misconfigured.fixDouble-check the username and password. Verify that the PAM service (e.g., 'login', 'sudo') exists and is correctly configured on your system (e.g., by inspecting files in `/etc/pam.d/`). Test with a known working username/password for the target service.
Warnings
- breaking Unlike some older Python PAM wrappers (e.g., `gnosek/python-pam`), Pamela raises a `PamError` exception for critical failures instead of simply returning `False`.
- gotcha Pamela relies on underlying system PAM libraries (e.g., `libpam.so`, `libc.so`). It is inherently OS-specific and only functions on Unix-like operating systems (Linux, macOS POSIX). It will not work on Windows without a PAM compatibility layer.
- gotcha There are reported issues with `pamela` on Python 3.14 (specifically with beta versions), where `test_environment` can fail with `PAMError: [PAM Error 26] Critical error - immediate abort`.
- gotcha Using `pamela` for authentication in `sudo` or similar privileged contexts requires careful configuration of PAM service files (e.g., `/etc/pam.d/sudo`). Incorrect or insecure PAM configurations can expose the system.
Install
-
pip install pamela
Imports
- authenticate
from pamela import authenticate
- open_session
from pamela import open_session
- close_session
from pamela import close_session
- check_account
from pamela import check_account
- change_password
from pamela import change_password
- PAMError
from pam import PAMError
from pamela import PAMError
Quickstart
import getpass
from pamela import authenticate, PAMError
def verify_user_pam(username, password, service='login'):
try:
# The 'login' service is a common default, but can be changed.
# On some systems, `auth` might also be a default.
# A common test is `python -m pamela -a $(whoami)`
if authenticate(username, password, service=service):
print(f"Authentication successful for user: {username}")
return True
else:
# authenticate returns False for simple failures (e.g., bad password)
# but can also raise PAMError for more critical issues.
print(f"Authentication failed for user: {username}.")
return False
except PAMError as e:
print(f"PAM error during authentication for {username}: {e}")
return False
except Exception as e:
print(f"An unexpected error occurred: {e}")
return False
if __name__ == '__main__':
user = getpass.getuser()
pwd = getpass.getpass(f"Password for {user}: ")
# Example with default 'login' service
print("\n--- Testing 'login' service ---")
verify_user_pam(user, pwd, service='login')
# Example with a custom service, e.g., 'sudo' (requires appropriate PAM setup)
# For this to work, a PAM configuration for 'sudo' might be needed, or ensure
# the user has permissions for this service.
# print("\n--- Testing 'sudo' service (if configured) ---")
# verify_user_pam(user, pwd, service='sudo')