diff --git a/howdy/debian/control b/howdy/debian/control index d164854..aca922a 100644 --- a/howdy/debian/control +++ b/howdy/debian/control @@ -10,7 +10,7 @@ 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 -Recommends: libatlas-base-dev | libopenblas-dev | liblapack-dev, howdy-gtk +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 diff --git a/howdy/src/meson.build b/howdy/src/meson.build index cfb6cc5..57a6e70 100644 --- a/howdy/src/meson.build +++ b/howdy/src/meson.build @@ -49,10 +49,9 @@ else pysourcesinstalldir = get_option('py_sources_dir') != '' ? get_option('py_sources_dir') : join_paths(get_option('prefix'), get_option('libdir'), 'howdy') endif -pam_module_conf_data = configuration_data({ - 'compare_script_path': join_paths(pysourcesinstalldir, 'compare.py') , - 'config_file_path': config_path, -}) +pam_module_conf_data = configuration_data(paths_dict) +pam_module_conf_data.set('compare_script_path', join_paths(pysourcesinstalldir, 'compare.py')) +pam_module_conf_data.set('config_file_path', config_path) subdir('pam') if get_option('install_in_site_packages') diff --git a/howdy/src/pam/main.cc b/howdy/src/pam/main.cc index 05c54d9..a8843c5 100644 --- a/howdy/src/pam/main.cc +++ b/howdy/src/pam/main.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -66,10 +67,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: @@ -134,10 +135,11 @@ auto howdy_status(char *username, int status, const INIReader &config, * Check if Howdy should be enabled according to the configuration and the * environment. * @param config INI configuration + * @param username Username * @return Returns PAM_AUTHINFO_UNAVAIL if it shouldn't be enabled, * PAM_SUCCESS otherwise */ -auto check_enabled(const INIReader &config) -> int { +auto check_enabled(const INIReader &config, const char* username) -> int { // Stop executing if Howdy has been disabled in the config if (config.GetBoolean("core", "disabled", false)) { syslog(LOG_INFO, "Skipped authentication, Howdy is disabled"); @@ -183,6 +185,13 @@ auto check_enabled(const INIReader &config) -> int { globfree(&glob_result); } + // pre-check if this user has face model file + auto model_path = std::string(USER_MODELS_DIR) + "/" + username + ".dat"; + struct stat s_; + if (stat(model_path.c_str(), &s_) != 0) { + return PAM_AUTHINFO_UNAVAIL; + } + return PAM_SUCCESS; } @@ -210,8 +219,16 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv, // Will contain the responses from PAM functions int pam_res = PAM_IGNORE; + // Get the username from PAM, needed to match correct face model + char *username = nullptr; + if ((pam_res = pam_get_user(pamh, const_cast(&username), + nullptr)) != PAM_SUCCESS) { + syslog(LOG_ERR, "Failed to get username"); + return pam_res; + } + // Check if we should continue - if ((pam_res = check_enabled(config)) != PAM_SUCCESS) { + if ((pam_res = check_enabled(config, username)) != PAM_SUCCESS) { return pam_res; } @@ -244,22 +261,13 @@ 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 - if (config.GetBoolean("core", "detection_notice", false)) { + 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"); } } - // Get the username from PAM, needed to match correct face model - char *username = nullptr; - if ((pam_res = pam_get_user(pamh, const_cast(&username), - nullptr)) != PAM_SUCCESS) { - syslog(LOG_ERR, "Failed to get username"); - return pam_res; - } - const char *const args[] = {PYTHON_EXECUTABLE, // NOLINT COMPARE_PROCESS_PATH, username, nullptr}; pid_t child_pid; diff --git a/howdy/src/pam/paths.hh.in b/howdy/src/pam/paths.hh.in index 055e0d4..771db2a 100644 --- a/howdy/src/pam/paths.hh.in +++ b/howdy/src/pam/paths.hh.in @@ -1,2 +1,3 @@ const auto COMPARE_PROCESS_PATH = "@compare_script_path@"; -const auto CONFIG_FILE_PATH = "@config_file_path@"; \ No newline at end of file +const auto CONFIG_FILE_PATH = "@config_file_path@"; +const auto USER_MODELS_DIR = "@user_models_dir@"; \ No newline at end of file