From 889d5235dd80549f75b22f43cbd5512f72fd35b2 Mon Sep 17 00:00:00 2001 From: Rael Gugelmin Cunha Date: Tue, 4 Apr 2023 12:03:05 -0300 Subject: [PATCH 1/5] Adding missing `v4l-utils` utils to Ubuntu dependencies --- howdy/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/howdy/debian/control b/howdy/debian/control index d164854..a8b52df 100644 --- a/howdy/debian/control +++ b/howdy/debian/control @@ -9,7 +9,7 @@ Vcs-Git: https://github.com/boltgolt/howdy Package: howdy Homepage: https://github.com/boltgolt/howdy Architecture: amd64 -Depends: ${misc:Depends}, libc6, libgcc-s1, libpam0g, libstdc++6, curl | wget, python3, python3-pip, python3-dev, python3-setuptools, python3-numpy, python-opencv | python3-opencv, libopencv-dev, cmake, libinih-dev +Depends: ${misc:Depends}, libc6, libgcc-s1, libpam0g, libstdc++6, curl | wget, python3, python3-pip, python3-dev, python3-setuptools, python3-numpy, python-opencv | python3-opencv, libopencv-dev, cmake, libinih-dev, v4l-utils Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev, howdy-gtk Suggests: nvidia-cuda-dev (>= 7.5) Description: Howdy: Windows Hello style authentication for Linux. From 4061b6573a775a0c29f0526af11c8afa1652ad65 Mon Sep 17 00:00:00 2001 From: Rael Gugelmin Cunha Date: Sun, 25 Jun 2023 08:49:20 -0300 Subject: [PATCH 2/5] Make v4l-utils a recommended package --- howdy/debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/howdy/debian/control b/howdy/debian/control index a8b52df..aca922a 100644 --- a/howdy/debian/control +++ b/howdy/debian/control @@ -9,8 +9,8 @@ Vcs-Git: https://github.com/boltgolt/howdy Package: howdy Homepage: https://github.com/boltgolt/howdy Architecture: amd64 -Depends: ${misc:Depends}, libc6, libgcc-s1, libpam0g, libstdc++6, curl | wget, python3, python3-pip, python3-dev, python3-setuptools, python3-numpy, python-opencv | python3-opencv, libopencv-dev, cmake, libinih-dev, v4l-utils -Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev, howdy-gtk +Depends: ${misc:Depends}, libc6, libgcc-s1, libpam0g, libstdc++6, curl | wget, python3, python3-pip, python3-dev, python3-setuptools, python3-numpy, python-opencv | python3-opencv, libopencv-dev, cmake, libinih-dev +Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev, howdy-gtk, v4l-utils Suggests: nvidia-cuda-dev (>= 7.5) Description: Howdy: Windows Hello style authentication for Linux. Use your built-in IR emitters and camera in combination with face recognition From 1b4f1c2d8524058644333a4cb4d182914fc0c600 Mon Sep 17 00:00:00 2001 From: Anton Golubev Date: Mon, 7 Aug 2023 18:11:20 +0300 Subject: [PATCH 3/5] Change the display order of PAM messages - do not show a message if the face model is not found - show a message if the user could not be recognized - show prompt if face model found (and enabled option) - enable the "detection_notice" option by default as this will only be shown to users who created the face model --- howdy/src/compare.py | 5 +++++ howdy/src/config.ini | 2 +- howdy/src/pam/main.cc | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/howdy/src/compare.py b/howdy/src/compare.py index 99f5285..7efb41c 100644 --- a/howdy/src/compare.py +++ b/howdy/src/compare.py @@ -140,6 +140,11 @@ except FileNotFoundError: if len(models) < 1: exit(10) +# notify the PAM module so that it issues a message +sys.stdout.flush() +print("HAS_MODEL") +sys.stdout.flush() + # Read config from disk config = configparser.ConfigParser() config.read(PATH + "/config.ini") diff --git a/howdy/src/config.ini b/howdy/src/config.ini index 27ab823..0514f3e 100644 --- a/howdy/src/config.ini +++ b/howdy/src/config.ini @@ -3,7 +3,7 @@ [core] # Print that face detection is being attempted -detection_notice = false +detection_notice = true # Print that face detection has timed out timeout_notice = true diff --git a/howdy/src/pam/main.cc b/howdy/src/pam/main.cc index 290a549..e60a915 100644 --- a/howdy/src/pam/main.cc +++ b/howdy/src/pam/main.cc @@ -66,10 +66,10 @@ auto howdy_error(int status, switch (status) { case CompareError::NO_FACE_MODEL: - conv_function(PAM_ERROR_MSG, S("There is no face model known")); syslog(LOG_NOTICE, "Failure, no face model known"); break; case CompareError::TIMEOUT_REACHED: + conv_function(PAM_ERROR_MSG, S("Failure, timeout reached")); syslog(LOG_ERR, "Failure, timeout reached"); break; case CompareError::ABORT: @@ -244,12 +244,7 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, textdomain(GETTEXT_PACKAGE); // If enabled, send a notice to the user that facial login is being attempted - if (config.GetBoolean("core", "detection_notice", false)) { - if ((conv_function(PAM_TEXT_INFO, S("Attempting facial authentication"))) != - PAM_SUCCESS) { - syslog(LOG_ERR, "Failed to send detection notice"); - } - } + bool detection_notice = config.GetBoolean("core", "detection_notice", true); // Get the username from PAM, needed to match correct face model char *username = nullptr; @@ -259,18 +254,46 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, return pam_res; } + int conv_pipe[2]; + + if (pipe (conv_pipe)) { + syslog(LOG_ERR, "Pipe failed."); + return PAM_SYSTEM_ERR; + } + + posix_spawn_file_actions_t action; + posix_spawn_file_actions_init(&action); + posix_spawn_file_actions_addclose(&action, conv_pipe[0]); + posix_spawn_file_actions_adddup2(&action, conv_pipe[1], 1); + posix_spawn_file_actions_addclose(&action, conv_pipe[1]); + const char *const args[] = {PYTHON_EXECUTABLE, // NOLINT COMPARE_PROCESS_PATH, username, nullptr}; pid_t child_pid; // Start the python subprocess - if (posix_spawnp(&child_pid, PYTHON_EXECUTABLE, nullptr, nullptr, + if (posix_spawnp(&child_pid, PYTHON_EXECUTABLE, &action, nullptr, const_cast(args), nullptr) != 0) { syslog(LOG_ERR, "Can't spawn the howdy process: %s (%d)", strerror(errno), errno); return PAM_SYSTEM_ERR; } + // show the PAM message from the compare script + optional_task child_conv([&] { + char buffer[100]; + while(read(conv_pipe[0], buffer, 100)) { + if (!strncmp(buffer, "HAS_MODEL", 9) && detection_notice) { + if ((conv_function(PAM_TEXT_INFO, + S("Attempting facial authentication"))) != + PAM_SUCCESS) { + syslog(LOG_ERR, "Failed to send detection notice"); + } + } + } + }); + child_conv.activate(); + // NOTE: We should replace mutex and condition_variable by atomic wait, but // it's too recent (C++20) std::mutex mutx; @@ -347,6 +370,7 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, // The compare process has finished its execution child_task.stop(false); + child_conv.stop(true); // Get python process status code int status = child_task.get(); From a5184dc663969960dd1cd7a543ff2df646e22392 Mon Sep 17 00:00:00 2001 From: Anton Golubev Date: Fri, 11 Aug 2023 10:10:45 +0300 Subject: [PATCH 4/5] Fixup: check if the user has a model directry in the PAM module Revert the use of pipe to signal from the script that the face model is not found and do it directly in the module. --- howdy/src/compare.py | 5 ----- howdy/src/pam/main.cc | 42 +++++++++++------------------------------- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/howdy/src/compare.py b/howdy/src/compare.py index 7efb41c..99f5285 100644 --- a/howdy/src/compare.py +++ b/howdy/src/compare.py @@ -140,11 +140,6 @@ except FileNotFoundError: if len(models) < 1: exit(10) -# notify the PAM module so that it issues a message -sys.stdout.flush() -print("HAS_MODEL") -sys.stdout.flush() - # Read config from disk config = configparser.ConfigParser() config.read(PATH + "/config.ini") diff --git a/howdy/src/pam/main.cc b/howdy/src/pam/main.cc index e60a915..89c7e98 100644 --- a/howdy/src/pam/main.cc +++ b/howdy/src/pam/main.cc @@ -243,9 +243,6 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); textdomain(GETTEXT_PACKAGE); - // If enabled, send a notice to the user that facial login is being attempted - bool detection_notice = config.GetBoolean("core", "detection_notice", true); - // Get the username from PAM, needed to match correct face model char *username = nullptr; if ((pam_res = pam_get_user(pamh, const_cast(&username), @@ -254,46 +251,30 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, return pam_res; } - int conv_pipe[2]; - - if (pipe (conv_pipe)) { - syslog(LOG_ERR, "Pipe failed."); - return PAM_SYSTEM_ERR; + // pre-check if this user has face model file + auto model_path = std::string("/etc/howdy/models/") + username + ".dat"; + if (!std::ifstream(model_path)) { + return howdy_status(username, CompareError::NO_FACE_MODEL, config, + conv_function); + } else if (config.GetBoolean("core", "detection_notice", true)) { + if ((conv_function(PAM_TEXT_INFO, S("Attempting facial authentication"))) != + PAM_SUCCESS) { + syslog(LOG_ERR, "Failed to send detection notice"); + } } - posix_spawn_file_actions_t action; - posix_spawn_file_actions_init(&action); - posix_spawn_file_actions_addclose(&action, conv_pipe[0]); - posix_spawn_file_actions_adddup2(&action, conv_pipe[1], 1); - posix_spawn_file_actions_addclose(&action, conv_pipe[1]); - const char *const args[] = {PYTHON_EXECUTABLE, // NOLINT COMPARE_PROCESS_PATH, username, nullptr}; pid_t child_pid; // Start the python subprocess - if (posix_spawnp(&child_pid, PYTHON_EXECUTABLE, &action, nullptr, + if (posix_spawnp(&child_pid, PYTHON_EXECUTABLE, nullptr, nullptr, const_cast(args), nullptr) != 0) { syslog(LOG_ERR, "Can't spawn the howdy process: %s (%d)", strerror(errno), errno); return PAM_SYSTEM_ERR; } - // show the PAM message from the compare script - optional_task child_conv([&] { - char buffer[100]; - while(read(conv_pipe[0], buffer, 100)) { - if (!strncmp(buffer, "HAS_MODEL", 9) && detection_notice) { - if ((conv_function(PAM_TEXT_INFO, - S("Attempting facial authentication"))) != - PAM_SUCCESS) { - syslog(LOG_ERR, "Failed to send detection notice"); - } - } - } - }); - child_conv.activate(); - // NOTE: We should replace mutex and condition_variable by atomic wait, but // it's too recent (C++20) std::mutex mutx; @@ -370,7 +351,6 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, // The compare process has finished its execution child_task.stop(false); - child_conv.stop(true); // Get python process status code int status = child_task.get(); From 40720bbf87a7d650b629d4c86f8c4ea2c83ea3a1 Mon Sep 17 00:00:00 2001 From: Anton Golubev Date: Wed, 6 Sep 2023 11:49:43 +0300 Subject: [PATCH 5/5] Fixup: don't else after return and no det. notice --- howdy/src/config.ini | 2 +- howdy/src/pam/main.cc | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/howdy/src/config.ini b/howdy/src/config.ini index 0514f3e..27ab823 100644 --- a/howdy/src/config.ini +++ b/howdy/src/config.ini @@ -3,7 +3,7 @@ [core] # Print that face detection is being attempted -detection_notice = true +detection_notice = false # Print that face detection has timed out timeout_notice = true diff --git a/howdy/src/pam/main.cc b/howdy/src/pam/main.cc index 89c7e98..69d9d53 100644 --- a/howdy/src/pam/main.cc +++ b/howdy/src/pam/main.cc @@ -256,7 +256,9 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, if (!std::ifstream(model_path)) { return howdy_status(username, CompareError::NO_FACE_MODEL, config, conv_function); - } else if (config.GetBoolean("core", "detection_notice", true)) { + } + + if (config.GetBoolean("core", "detection_notice", true)) { if ((conv_function(PAM_TEXT_INFO, S("Attempting facial authentication"))) != PAM_SUCCESS) { syslog(LOG_ERR, "Failed to send detection notice");