mirror of
https://github.com/boltgolt/howdy.git
synced 2024-09-19 09:51:19 +02:00
refactor: add function to format success message
This commit is contained in:
parent
fa2607db7d
commit
d77dd94ec0
1 changed files with 71 additions and 72 deletions
143
src/pam/main.cc
143
src/pam/main.cc
|
@ -3,10 +3,9 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <poll.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <spawn.h>
|
#include <spawn.h>
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <sys/signalfd.h>
|
#include <sys/signalfd.h>
|
||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -44,21 +43,20 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace boost::locale;
|
using namespace boost::locale;
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspect the status code returned by the compare process
|
* Inspect the status code returned by the compare process
|
||||||
* @param code The status code
|
* @param status The status code
|
||||||
* @param conv_function The PAM conversation function
|
* @param conv_function The PAM conversation function
|
||||||
* @return A PAM return code
|
* @return A PAM return code
|
||||||
*/
|
*/
|
||||||
int on_howdy_auth(int code, function<int(int, const char *)> conv_function) {
|
int howdy_error(int status, function<int(int, const char *)> conv_function) {
|
||||||
// If the process has exited
|
// If the process has exited
|
||||||
if (!WIFEXITED(code)) {
|
if (!WIFEXITED(status)) {
|
||||||
// Get the status code returned
|
// Get the status code returned
|
||||||
code = WEXITSTATUS(code);
|
status = WEXITSTATUS(status);
|
||||||
|
|
||||||
switch (code) {
|
switch (status) {
|
||||||
// Status 10 means we couldn't find any face models
|
// Status 10 means we couldn't find any face models
|
||||||
case 10:
|
case 10:
|
||||||
conv_function(PAM_ERROR_MSG,
|
conv_function(PAM_ERROR_MSG,
|
||||||
|
@ -81,10 +79,10 @@ int on_howdy_auth(int code, function<int(int, const char *)> conv_function) {
|
||||||
break;
|
break;
|
||||||
// Otherwise, we can't describe what happened but it wasn't successful
|
// Otherwise, we can't describe what happened but it wasn't successful
|
||||||
default:
|
default:
|
||||||
conv_function(
|
conv_function(PAM_ERROR_MSG, string(dgettext("pam", "Unknown error:") +
|
||||||
PAM_ERROR_MSG,
|
to_string(status))
|
||||||
string(dgettext("pam", "Unknown error:") + to_string(code)).c_str());
|
.c_str());
|
||||||
syslog(LOG_INFO, "Failure, unknown error %d", code);
|
syslog(LOG_INFO, "Failure, unknown error %d", status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +91,34 @@ int on_howdy_auth(int code, function<int(int, const char *)> conv_function) {
|
||||||
return PAM_AUTH_ERR;
|
return PAM_AUTH_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the success message if the status is successful or log the error in
|
||||||
|
* the other case
|
||||||
|
* @param username Username
|
||||||
|
* @param status Status code
|
||||||
|
* @param reader INI configuration
|
||||||
|
* @param conv_function PAM conversation function
|
||||||
|
* @return Returns the conversation function return code
|
||||||
|
*/
|
||||||
|
int howdy_msg(char *username, int status, INIReader &reader,
|
||||||
|
function<int(int, const char *)> conv_function) {
|
||||||
|
if (status != EXIT_SUCCESS) {
|
||||||
|
return howdy_error(status, conv_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reader.GetBoolean("core", "no_confirmation", true)) {
|
||||||
|
// Construct confirmation text from i18n string
|
||||||
|
string confirm_text = dgettext("pam", "Identified face as {}");
|
||||||
|
string identify_msg =
|
||||||
|
confirm_text.replace(confirm_text.find("{}"), 2, string(username));
|
||||||
|
conv_function(PAM_TEXT_INFO, identify_msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "Login approved");
|
||||||
|
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format and send a message to PAM
|
* Format and send a message to PAM
|
||||||
* @param conv PAM conversation function
|
* @param conv PAM conversation function
|
||||||
|
@ -130,10 +156,11 @@ int identify(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
||||||
string workaround = reader.GetString("core", "workaround", "input");
|
string workaround = reader.GetString("core", "workaround", "input");
|
||||||
|
|
||||||
// In this case, we are not asking for the password
|
// In this case, we are not asking for the password
|
||||||
if (workaround == Workaround::Off && auth_tok)
|
if (workaround == Workaround::Off && auth_tok) {
|
||||||
auth_tok = false;
|
auth_tok = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Will contain PAM conversation function
|
// Will contain PAM conversation structure
|
||||||
struct pam_conv *conv = nullptr;
|
struct pam_conv *conv = nullptr;
|
||||||
// Will contain the responses from PAM functions
|
// Will contain the responses from PAM functions
|
||||||
int pam_res = PAM_IGNORE;
|
int pam_res = PAM_IGNORE;
|
||||||
|
@ -210,8 +237,8 @@ int identify(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the username from PAM, needed to match correct face model
|
// Get the username from PAM, needed to match correct face model
|
||||||
char *user_ptr = nullptr;
|
char *username = nullptr;
|
||||||
if ((pam_res = pam_get_user(pamh, (const char **)&user_ptr, nullptr)) !=
|
if ((pam_res = pam_get_user(pamh, (const char **)&username, nullptr)) !=
|
||||||
PAM_SUCCESS) {
|
PAM_SUCCESS) {
|
||||||
syslog(LOG_ERR, "Failed to get username");
|
syslog(LOG_ERR, "Failed to get username");
|
||||||
return pam_res;
|
return pam_res;
|
||||||
|
@ -225,7 +252,7 @@ int identify(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
||||||
posix_spawn_file_actions_addclose(&file_actions, STDIN_FILENO);
|
posix_spawn_file_actions_addclose(&file_actions, STDIN_FILENO);
|
||||||
|
|
||||||
const char *const args[] = {
|
const char *const args[] = {
|
||||||
"/usr/bin/python3", "/lib/security/howdy/compare.py", user_ptr, nullptr};
|
"/usr/bin/python3", "/lib/security/howdy/compare.py", username, nullptr};
|
||||||
pid_t child_pid;
|
pid_t child_pid;
|
||||||
|
|
||||||
// Start the python subprocess
|
// Start the python subprocess
|
||||||
|
@ -235,7 +262,7 @@ int identify(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
||||||
return PAM_SYSTEM_ERR;
|
return PAM_SYSTEM_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We could replace mutex and condition_variable by atomic wait, but
|
// NOTE: We should replace mutex and condition_variable by atomic wait, but
|
||||||
// it's too recent (C++20)
|
// it's too recent (C++20)
|
||||||
mutex m;
|
mutex m;
|
||||||
condition_variable cv;
|
condition_variable cv;
|
||||||
|
@ -301,66 +328,38 @@ int identify(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
||||||
}
|
}
|
||||||
int howdy_status = child_task.get();
|
int howdy_status = child_task.get();
|
||||||
|
|
||||||
// If exited successfully
|
return howdy_msg(username, howdy_status, reader, conv_function);
|
||||||
if (howdy_status == 0) {
|
} else {
|
||||||
if (!reader.GetBoolean("core", "no_confirmation", true)) {
|
// The password has been entered
|
||||||
// Construct confirmation text from i18n string
|
|
||||||
string confirm_text = dgettext("pam", "Identified face as {}");
|
// We need to be sure that we're not going to block forever if the
|
||||||
string identify_msg(
|
// child has a problem
|
||||||
confirm_text.replace(confirm_text.find("{}"), 2, string(user_ptr)));
|
if (child_task.wait(1.5s) == future_status::timeout) {
|
||||||
// Send confirmation message to user
|
kill(child_pid, SIGTERM);
|
||||||
conv_function(PAM_TEXT_INFO, identify_msg.c_str());
|
}
|
||||||
}
|
child_task.stop(false);
|
||||||
syslog(LOG_INFO, "Login approved");
|
|
||||||
return PAM_SUCCESS;
|
// We just wait for the thread to stop since it's this one which sent us the
|
||||||
|
// confirmation type
|
||||||
|
if (workaround == Workaround::Input && auth_tok) {
|
||||||
|
pass_task.stop(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We got an error
|
char *password = nullptr;
|
||||||
return on_howdy_auth(howdy_status, conv_function);
|
tie(pam_res, password) = pass_task.get();
|
||||||
}
|
|
||||||
|
|
||||||
// The password has been entered
|
if (pam_res != PAM_SUCCESS)
|
||||||
|
return pam_res;
|
||||||
|
|
||||||
// Again, we need to be sure that we're not going to block forever if the
|
int howdy_status = child_task.get();
|
||||||
// child has a problem
|
// If python process (or user) sent Enter key
|
||||||
if (child_task.wait(1.5s) == future_status::timeout) {
|
if (strlen(password) == 0) {
|
||||||
kill(child_pid, SIGTERM);
|
return howdy_msg(username, howdy_status, reader, conv_function);
|
||||||
}
|
|
||||||
child_task.stop(false);
|
|
||||||
|
|
||||||
// We just wait for the thread to stop since it's this one which sent us the
|
|
||||||
// confirmation type
|
|
||||||
if (workaround == Workaround::Input && auth_tok) {
|
|
||||||
pass_task.stop(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *password = nullptr;
|
|
||||||
tie(pam_res, password) = pass_task.get();
|
|
||||||
|
|
||||||
if (pam_res != PAM_SUCCESS)
|
|
||||||
return pam_res;
|
|
||||||
|
|
||||||
int howdy_status = child_task.get();
|
|
||||||
// If python process sent Enter key
|
|
||||||
if (strlen(password) == 0) {
|
|
||||||
if (howdy_status == 0) {
|
|
||||||
if (!reader.GetBoolean("core", "no_confirmation", true)) {
|
|
||||||
// Construct confirmation text from i18n string
|
|
||||||
string confirm_text = dgettext("pam", "Identified face as {}");
|
|
||||||
string identify_msg(
|
|
||||||
confirm_text.replace(confirm_text.find("{}"), 2, string(user_ptr)));
|
|
||||||
// Send confirmation message to user
|
|
||||||
conv_function(PAM_TEXT_INFO, identify_msg.c_str());
|
|
||||||
}
|
|
||||||
syslog(LOG_INFO, "Login approved");
|
|
||||||
return PAM_SUCCESS;
|
|
||||||
} else {
|
|
||||||
return on_howdy_auth(howdy_status, conv_function);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// The password has been entered, we are passing it to PAM stack
|
// The password has been entered, we are passing it to PAM stack
|
||||||
return PAM_IGNORE;
|
return PAM_IGNORE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by PAM when a user needs to be authenticated, for example by running
|
// Called by PAM when a user needs to be authenticated, for example by running
|
||||||
|
|
Loading…
Reference in a new issue