diff --git a/howdy-gtk/src/onboarding.py b/howdy-gtk/src/onboarding.py index e23257f..d0f0e9c 100644 --- a/howdy-gtk/src/onboarding.py +++ b/howdy-gtk/src/onboarding.py @@ -64,6 +64,8 @@ class OnboardingWindow(gtk.Window): self.execute_slide5() def execute_slide1(self): + conf_path = "/etc/howdy" + self.downloadoutputlabel = self.builder.get_object("downloadoutputlabel") eventbox = self.builder.get_object("downloadeventbox") eventbox.modify_bg(gtk.StateType.NORMAL, gdk.Color(red=0, green=0, blue=0)) @@ -74,10 +76,10 @@ class OnboardingWindow(gtk.Window): else: lib_site = None - if lib_site: - conf_path = lib_site + "/security/howdy" - else: - conf_path = "/etc/howdy" + if lib_site is None: + self.downloadoutputlabel.set_text(_("Unable to find Howdy's installation location")) + return + if os.path.exists(conf_path + "/dlib-data/shape_predictor_5_face_landmarks.dat"): self.downloadoutputlabel.set_text(_("Datafiles have already been downloaded!\nClick Next to continue")) diff --git a/howdy/debian/postinst b/howdy/debian/postinst index 1cf7b43..ebfdfdd 100755 --- a/howdy/debian/postinst +++ b/howdy/debian/postinst @@ -106,11 +106,6 @@ if "upgrade" in sys.argv: sys.exit(0) -log("Downloading and unpacking data files") - -# Run the bash script to download and unpack the .dat files needed -handleStatus(subprocess.call(["./install.sh"], shell=True, cwd="/etc/howdy/dlib-data")) - log("Downloading dlib") dlib_archive = "/tmp/v19.16.tar.gz" diff --git a/howdy/debian/preinst b/howdy/debian/preinst index f0ac832..1171e99 100755 --- a/howdy/debian/preinst +++ b/howdy/debian/preinst @@ -9,24 +9,17 @@ import sys if "upgrade" in sys.argv: # Try to copy the config file as a backup try: - if os.path.exists("/lib/security/howdy/config.ini") and not os.path.exists("/etc/howdy/config.ini"): - subprocess.call(["cp /lib/security/howdy/config.ini /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini"], shell=True) - else os.path.exists("/etc/howdy/config.ini"): + # Try to copy the new location first + if os.path.exists("/etc/howdy/config.ini"): subprocess.call(["cp /etc/howdy/config.ini /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini"], shell=True) + # If that does not exist, try copying the old location + else: + subprocess.call(["cp /lib/security/howdy/config.ini /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini"], shell=True) # Let the user know so he knows where to look on a failed install print("Backup of Howdy config file created in /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini") except subprocess.CalledProcessError: - try: - if os.path.exists("/lib/security/howdy/config.ini") and not os.path.exists("/etc/howdy/config.ini"): - subprocess.call(["cp /lib/security/howdy/config.ini /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini"], shell=True) - else os.path.exists("/etc/howdy/config.ini"): - subprocess.call(["cp /etc/howdy/config.ini /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini"], shell=True) - - # Let the user know so he knows where to look on a failed install - print("Backup of Howdy config file created in /tmp/howdy_config_backup_v" + sys.argv[2] + ".ini") - except subprocess.CalledProcessError: - print("Could not make an backup of old Howdy config file") + print("Could not make an backup of old Howdy config file") # Don't continue setup when we're just upgrading sys.exit(0) diff --git a/howdy/src/cli/add.py b/howdy/src/cli/add.py index c4e1e8e..99104c6 100644 --- a/howdy/src/cli/add.py +++ b/howdy/src/cli/add.py @@ -26,15 +26,13 @@ except ImportError as err: # OpenCV needs to be imported after dlib import cv2 -# Get the absolute path to the current directory -path = os.path.abspath(__file__ + "/..") +# Define the absolute path to the config directory config_path = "/etc/howdy" -models_path = "/etc/howdy/models" # Test if at lest 1 of the data files is there and abort if it's not -if not os.path.isfile(path + "/../dlib-data/shape_predictor_5_face_landmarks.dat"): +if not os.path.isfile(config_path + "/dlib-data/shape_predictor_5_face_landmarks.dat"): print(_("Data files have not been downloaded, please run the following commands:")) - print("\n\tcd " + os.path.realpath(path + "/../dlib-data")) + print("\n\tcd " + config_path + "/dlib-data") print("\tsudo ./install.sh\n") sys.exit(1) @@ -44,23 +42,23 @@ config.read(config_path + "/config.ini") use_cnn = config.getboolean("core", "use_cnn", fallback=False) if use_cnn: - face_detector = dlib.cnn_face_detection_model_v1(path + "/../dlib-data/mmod_human_face_detector.dat") + face_detector = dlib.cnn_face_detection_model_v1(config_path + "/dlib-data/mmod_human_face_detector.dat") else: face_detector = dlib.get_frontal_face_detector() -pose_predictor = dlib.shape_predictor(path + "/../dlib-data/shape_predictor_5_face_landmarks.dat") -face_encoder = dlib.face_recognition_model_v1(path + "/../dlib-data/dlib_face_recognition_resnet_model_v1.dat") +pose_predictor = dlib.shape_predictor(config_path + "/dlib-data/shape_predictor_5_face_landmarks.dat") +face_encoder = dlib.face_recognition_model_v1(config_path + "/dlib-data/dlib_face_recognition_resnet_model_v1.dat") user = builtins.howdy_user # The permanent file to store the encoded model in -enc_file = models_path + "/" + user + ".dat" +enc_file = config_path + "/models/" + user + ".dat" # Known encodings encodings = [] # Make the ./models folder if it doesn't already exist -if not os.path.exists(models_path): +if not os.path.exists(config_path + "/models"): print(_("No face model folder found, creating one")) - os.makedirs(models_path) + os.makedirs(config_path + "/models") # To try read a premade encodings file if it exists try: diff --git a/howdy/src/cli/clear.py b/howdy/src/cli/clear.py index 686e84a..6fa5f3e 100644 --- a/howdy/src/cli/clear.py +++ b/howdy/src/cli/clear.py @@ -30,7 +30,7 @@ if not builtins.howdy_args.y: # Abort if they don't answer y or Y if (ans.lower() != "y"): - print(_('\nInerpeting as a "NO", aborting')) + print(_('\nInterpreting as a "NO", aborting')) sys.exit(1) # Delete otherwise diff --git a/howdy/src/cli/list.py b/howdy/src/cli/list.py index ab26c4d..b079580 100644 --- a/howdy/src/cli/list.py +++ b/howdy/src/cli/list.py @@ -50,7 +50,7 @@ for enc in encodings: # Format the time as ISO in the local timezone print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(enc["time"])), end="") - # Seperate with commas again for machines, spaces otherwise + # Separate with commas again for machines, spaces otherwise print("," if builtins.howdy_args.plain else " ", end="") # End with the label diff --git a/howdy/src/compare.py b/howdy/src/compare.py index 92bab60..f654963 100644 --- a/howdy/src/compare.py +++ b/howdy/src/compare.py @@ -129,7 +129,7 @@ face_encoder = None # Try to load the face model from the models folder try: - models = json.load(open("/etc/howdy/models/" + user + ".dat")) + models = json.load(open(PATH + "/models/" + user + ".dat")) for model in models: encodings += model["data"] @@ -142,7 +142,7 @@ if len(models) < 1: # Read config from disk config = configparser.ConfigParser() -config.read("/etc/howdy/config.ini") +config.read(PATH + "/config.ini") # Get all config values needed use_cnn = config.getboolean("core", "use_cnn", fallback=False) diff --git a/howdy/src/pam.py b/howdy/src/pam.py deleted file mode 100644 index e7b598b..0000000 --- a/howdy/src/pam.py +++ /dev/null @@ -1,130 +0,0 @@ -# PAM interface in python, launches compare.py - -# Import required modules -import subprocess -import os -import glob -import syslog - -# 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("/etc/howdy") + "/config.ini") - - -def doAuth(pamh): - """Starts authentication in a seperate process""" - - # Abort if Howdy is disabled - if config.getboolean("core", "disabled"): - return pamh.PAM_AUTHINFO_UNAVAIL - - # Abort if we're in a remote SSH env - if config.getboolean("core", "ignore_ssh"): - if "SSH_CONNECTION" in os.environ or "SSH_CLIENT" in os.environ or "SSHD_OPTS" in os.environ: - return pamh.PAM_AUTHINFO_UNAVAIL - - # Abort if lid is closed - if config.getboolean("core", "ignore_closed_lid"): - if any("closed" in open(f).read() for f in glob.glob("/proc/acpi/button/lid/*/state")): - return pamh.PAM_AUTHINFO_UNAVAIL - - # Abort if the video device does not exist - if not os.path.exists(config.get("video", "device_path")): - if config.getboolean("video", "warn_no_device"): - print("Camera path is not configured correctly, please edit the 'device_path' config value.") - return pamh.PAM_AUTHINFO_UNAVAIL - - # Set up syslog - syslog.openlog("[HOWDY]", 0, syslog.LOG_AUTH) - - # Alert the user that we are doing face detection - if config.getboolean("core", "detection_notice"): - pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Attempting face detection")) - - syslog.syslog(syslog.LOG_INFO, "Attempting facial authentication for user " + pamh.get_user()) - - # Run compare as python3 subprocess to circumvent python version and import issues - status = subprocess.call(["/usr/bin/python3", os.path.dirname(os.path.abspath(__file__)) + "/compare.py", pamh.get_user()]) - - # Status 10 means we couldn't find any face models - if status == 10: - if not config.getboolean("core", "suppress_unknown"): - pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "No face model known")) - - syslog.syslog(syslog.LOG_NOTICE, "Failure, no face model known") - syslog.closelog() - return pamh.PAM_USER_UNKNOWN - - # Status 11 means we exceded the maximum retry count - elif status == 11: - if config.getboolean("core", "timeout_notice"): - pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Face detection timeout reached")) - syslog.syslog(syslog.LOG_INFO, "Failure, timeout reached") - syslog.closelog() - return pamh.PAM_AUTH_ERR - - # Status 12 means we aborted - elif status == 12: - syslog.syslog(syslog.LOG_INFO, "Failure, general abort") - syslog.closelog() - return pamh.PAM_AUTH_ERR - - # Status 13 means the image was too dark - elif status == 13: - pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Face detection image too dark")) - syslog.syslog(syslog.LOG_INFO, "Failure, image too dark") - syslog.closelog() - return pamh.PAM_AUTH_ERR - - # Status 14 means a rubberstamp could not be given - elif status == 14: - pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Rubberstamp denied")) - syslog.syslog(syslog.LOG_INFO, "Failure, rubberstamp did not succeed") - syslog.closelog() - return pamh.PAM_AUTH_ERR - - # Status 1 is probably a python crash - elif status == 1: - pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Howdy encountered error, check stderr")) - syslog.syslog(syslog.LOG_INFO, "Failure, process crashed while authenticating") - syslog.closelog() - return pamh.PAM_SYSTEM_ERR - - # Status 0 is a successful exit - elif status == 0: - # Show the success message if it isn't suppressed - if not config.getboolean("core", "no_confirmation"): - pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Identified face as " + pamh.get_user())) - - syslog.syslog(syslog.LOG_INFO, "Login approved") - syslog.closelog() - return pamh.PAM_SUCCESS - - # Otherwise, we can't discribe what happend but it wasn't successful - pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Unknown error: " + str(status))) - syslog.syslog(syslog.LOG_INFO, "Failure, unknown error" + str(status)) - syslog.closelog() - return pamh.PAM_SYSTEM_ERR - - -def pam_sm_authenticate(pamh, flags, args): - """Called by PAM when the user wants to authenticate, in sudo for example""" - return doAuth(pamh) - - -def pam_sm_open_session(pamh, flags, args): - """Called when starting a session, such as su""" - return doAuth(pamh) - - -def pam_sm_close_session(pamh, flags, argv): - """We don't need to clean anyting up at the end of a session, so returns true""" - return pamh.PAM_SUCCESS - - -def pam_sm_setcred(pamh, flags, argv): - """We don't need set any credentials, so returns true""" - return pamh.PAM_SUCCESS