diff --git a/.gitignore b/.gitignore index 92f9881..112d262 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,3 @@ ENV/ # generated models /models - -# config file -config.py diff --git a/README.md b/README.md index 11802b6..ecea2cb 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ sudo apt install libpam-python fswebcam libopencv-dev python-opencv After that, install the face_recognition python module. There's an excellent step by step guide on how to do this on [its github page](https://github.com/ageitgey/face_recognition#installation). -In the root of your cloned repo is a file called `config_template.py`. Duplicate this file and call it `config.py`. The `device_id` variable in this file is important, make sure it is the IR camera and not your normal webcam. +In the root of your cloned repo is a file called `config.ini`. The `device_id` variable in this file is important, make sure it is the IR camera and not your normal webcam. Now it's time to let Howdy learn your face. The learn.py script will make 3 models of your face and store them as an encoded set in the `models` folder. To run the script, open a terminal, navigate to this repository and run: @@ -22,7 +22,7 @@ python3 learn.py The script should guide you through the process. -Finally we need to tell PAM that there's a new module installed. Open `/etc/pam.d/sudo` as root (`sudo nano /etc/pam.d/sudo`) and add the following line to the top of the file: +Finally we need to tell PAM that there's a new module installed. Open `/etc/pam.d/common-auth` as root (`sudo nano /etc/pam.d/common-auth`) and add the following line to the top of the file: ``` auth sufficient pam_python.so /path/to/pam.py diff --git a/compair.py b/compair.py index ba7a6c5..ec4d8b8 100644 --- a/compair.py +++ b/compair.py @@ -7,9 +7,11 @@ import cv2 import sys import os import json +import configparser -# Import config -import config +# Read config from disk +config = configparser.ConfigParser() +config.read(os.path.dirname(__file__) + "/config.ini") def stop(status): """Stop the execution and close video stream""" @@ -34,14 +36,14 @@ tries = 0 try: encodings = json.load(open(os.path.dirname(__file__) + "/models/" + user + ".dat")) except FileNotFoundError: - stop(10) + sys.exit(10) # Verify that we have a valid model file if len(encodings) < 3: - stop(1) + sys.exit(1) # Start video capture on the IR camera -video_capture = cv2.VideoCapture(config.device_id) +video_capture = cv2.VideoCapture(int(config.get("video", "device_id"))) while True: # Grab a single frame of video @@ -57,11 +59,11 @@ while True: # Check if any match is certain enough to be the user we're looking for for match in matches: - if match < config.certainty and match > 0: + if match < int(config.get("video", "certainty")) and match > 0: stop(0) # Stop if we've exceded the maximum retry count - if tries > config.frame_count: + if tries > int(config.get("video", "frame_count")): stop(11) tries += 1 diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..1e6d031 --- /dev/null +++ b/config.ini @@ -0,0 +1,19 @@ +[core] +# Do not print anything when a face vericication succeeds +no_confirmation = false + +# When a user without a known face model tries to use this script, don't +# show an error but fail silently +supress_unknown = false + +[video] +# The certainty of the detected face belonging to the user of the account +# On a scale from 1 to 10, values above 5 are not recomended +certainty = 3 + +# The number of frames to capture and to process before timing out +frame_count = 30 + +# The /dev/videoX id to capture frames from +# In my case, video0 is the normal camera and video1 is the IR version +device_id = 1 diff --git a/config_template.py b/config_template.py deleted file mode 100644 index 9ba9900..0000000 --- a/config_template.py +++ /dev/null @@ -1,10 +0,0 @@ -# The certainty of the detected face belonging to the user of the account -# On a scale from 1 to 10, values above 5 are not recomended -certainty = 3 - -# The number of frames to capture and to process before timing out -frame_count = 80 - -# The /dev/videoX id to capture frames from -# On my laptop, video0 is the normal camera and video1 is the IR version -device_id = 1 diff --git a/pam.py b/pam.py index 25a87ff..4a32770 100644 --- a/pam.py +++ b/pam.py @@ -5,6 +5,13 @@ import subprocess import sys import os +# pam-python is running python 2, so we use the old module here +import ConfigParser + +# Read config from disk +config = ConfigParser.ConfigParser() +config.read(os.path.dirname(__file__) + "/config.ini") + def doAuth(pamh): """Start authentication in a seperate process""" @@ -13,19 +20,21 @@ def doAuth(pamh): # Status 10 means we couldn't find any face models if status == 10: - print("No face model is known for this user, skiping") - return pamh.PAM_SYSTEM_ERR + if config.get("core", "supress_unknown") != "true": + pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "No face model known")) + return pamh.PAM_USER_UNKNOWN # Status 11 means we exceded the maximum retry count if status == 11: - print("Timeout reached, could not find a known face") - return pamh.PAM_SYSTEM_ERR + pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Face detection timeout reached")) + return pamh.PAM_AUTH_ERR # Status 0 is a successful exit if status == 0: - print("Identified face as " + os.environ.get("USER")) + if config.get("core", "no_confirmation") != "true": + pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Identified face as " + pamh.get_user())) return pamh.PAM_SUCCESS # Otherwise, we can't discribe what happend but it wasn't successful - print("Unknown error: " + str(status)) + pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Unknown error: " + str(status))) return pamh.PAM_SYSTEM_ERR def pam_sm_authenticate(pamh, flags, args):