Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Tree: 109d6693eb
Fetching contributors…

Cannot retrieve contributors at this time

executable file 145 lines (113 sloc) 4.424 kB
# -*- coding: utf-8 -*-
# Name: Advanced Yubico PAM module
# Description: Python PAM module which allows you to integrate the Yubikey
# into your existing user authentication infrastructure.
# This module supports online, failback and offline mode.
# For more information about the original C module visit the documentation at
# Author: Tomaž Muraus (
# Version: 0.4.0-dev
# Requirements:
# - Python >= 2.6
# - pam
# - python-pam
# - pam-python (
import os
import sys
import logging
from pam_yubico import settings, ykcheck
from pam_yubico.database import methods as database
# Setup logging
logging.basicConfig(filename = settings.LOG_PATH, filemode = 'a', level = logging.DEBUG, format = '%(asctime)s %(levelname)-8s %(message)s', datefmt = '%d.%m.%Y %H:%M:%S')
class MessagePrompt():
# Dummy Message class
msg = ''
msg_style = 0
def pam_sm_authenticate(pamh, flags, argv):
user = pamh.user
arguments = _parse_arguments(argv)
ykCheck = ykcheck.YubiKeyCheck()
ykCheck.username = user
if not database.entry_exists(username = user):
# No user id is set for this username
logging.debug('No YubiKey is set for user %s' % (user))
prompt = MessagePrompt()
prompt.msg = 'Yubikey for `%s`: ' % (user)
prompt.msg_style = pamh.PAM_PROMPT_ECHO_OFF
response = pamh.conversation(prompt).resp
otp = response
logging.debug('OTP = %s' % (otp))
if arguments['alwaysok'] == 1:
# Presentation mode is enabled
logging.debug('Presenation mode is ON')
return pamh.PAM_SUCCESS
if not otp:
# No OTP is provided by the user
logging.debug('No OTP provided')
return pamh.PAM_AUTH_ERR
if len(otp) < ykcheck.TOKEN_MIN_LENGTH:
# Invalid OTP length
logging.debug('Invalid OTP length')
return pamh.PAM_AUTH_ERR
user_id = otp[:12]
logging.debug('user ID = %s' % (user_id))
ykCheck.user_id = user_id
ykCheck.otp = otp
if not database.check_user_is_enabled(ykCheck.username, ykCheck.user_id):
logging.debug('YubiKey for user %s is disabled' % (user))
return pamh.PAM_AUTH_ERR
if not database.check_user_id_matches_one_provided(ykCheck.username, ykCheck.user_id):
# User ID is not matching
logging.debug('User ID in the database does not match the one provided by the OTP')
return pamh.PAM_AUTH_ERR
valid_otp = ykCheck.validate_otp()
if not valid_otp:
logging.debug('Error, the provided OTP is invalid')
return pamh.PAM_AUTH_ERR
# Everything went well and the provided OTP is valid
logging.debug('Success, the provided OTP is OK')
return pamh.PAM_SUCCESS
def pam_sm_setcred(pamh, flags, argv):
# @todo: not implemented
return pamh.PAM_CRED_UNAVAIL
def pam_sm_acct_mgmt(pamh, flags, argv):
# @todo: not implemented
return pamh.PAM_SUCCESS
def pam_sm_chauthtok(pamh, flags, argv):
# @todo: not implemented
return pamh.PAM_SUCCESS
def pam_sm_open_session(pamh, flags, argv):
# @todo: not implemented
return pamh.PAM_SUCCESS
def pam_sm_close_session(pamh, flags, argv):
# @todo: not implemented
return pamh.PAM_SUCCESS
def _parse_arguments(args = None):
""" Parses the provided arguments. """
arguments = {
'debug': False,
'alwaysok': 0,
if args:
if 'debug' in args:
arguments['debug'] = True
args = args[1:]
for argument in args:
if len(argument.split('=')) == 2:
(key, value) = argument.split('=')
if key in arguments:
if key in ['alwaysok']:
value = int(value)
logging.debug('%s = %s' % (key, value))
arguments[key] = value
logging.debug('%s' % (argument))
return arguments
Jump to Line
Something went wrong with that request. Please try again.