-
-
Notifications
You must be signed in to change notification settings - Fork 312
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: MusiKid <[email protected]>
- Loading branch information
1 parent
fc14425
commit 45a152f
Showing
6 changed files
with
244 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
subprojects/*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Howdy PAM module | ||
|
||
## Build | ||
|
||
```sh | ||
meson setup --wipe build -Dinih:with_INIReader=true | ||
meson compile build | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
#include <INIReader.h> | ||
#include <errno.h> | ||
#include <glob.h> | ||
#include <sys/syslog.h> | ||
#include <syslog.h> | ||
#include <unistd.h> | ||
|
||
#include <chrono> | ||
#include <condition_variable> | ||
#include <cstring> | ||
#include <functional> | ||
#include <future> | ||
#include <iostream> | ||
#include <iterator> | ||
#include <memory> | ||
#include <string> | ||
#include <system_error> | ||
#include <thread> | ||
#include <tuple> | ||
#include <vector> | ||
|
||
#include <boost/asio/io_context.hpp> | ||
#include <boost/asio/read.hpp> | ||
#include <boost/process/async.hpp> | ||
#include <boost/process/detail/child_decl.hpp> | ||
#include <boost/process/detail/on_exit.hpp> | ||
#include <boost/process/env.hpp> | ||
#include <boost/process/extend.hpp> | ||
#include <boost/process/io.hpp> | ||
#include <boost/process/search_path.hpp> | ||
|
||
#include <security/pam_appl.h> | ||
#include <security/pam_ext.h> | ||
#include <security/pam_modules.h> | ||
|
||
using namespace std; | ||
namespace bp = boost::process; | ||
|
||
int on_howdy_auth(int code, function<int()> conv_function, | ||
struct pam_message *msg) { | ||
|
||
switch (code) { | ||
case 10: | ||
msg->msg = "Image is too dark"; | ||
msg->msg_style = PAM_ERROR_MSG; | ||
conv_function(); | ||
syslog(LOG_NOTICE, "Failure, no face model known"); | ||
break; | ||
case 11: | ||
syslog(LOG_INFO, "Failure, timeout reached"); | ||
break; | ||
case 12: | ||
syslog(LOG_INFO, "Failure, general abort"); | ||
break; | ||
case 13: | ||
syslog(LOG_INFO, "Failure, image too dark"); | ||
break; | ||
default: | ||
msg->msg = string("Unknown error:" + to_string(code)).c_str(); | ||
msg->msg_style = PAM_ERROR_MSG; | ||
conv_function(); | ||
syslog(LOG_INFO, "Failure, unknown error %d", code); | ||
} | ||
|
||
return PAM_AUTH_ERR; | ||
} | ||
|
||
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, | ||
const char **argv) { | ||
INIReader reader("/lib/security/howdy/config.ini"); | ||
openlog("[PAM_HOWDY]", 0, LOG_AUTHPRIV); | ||
|
||
struct pam_conv *conv = nullptr; | ||
int pam_res = PAM_IGNORE; | ||
|
||
// No need to free this, it's allocated on the stack | ||
struct pam_message msg = {}; | ||
struct pam_message *msgp = &msg; | ||
|
||
struct pam_response res_ = {}; | ||
struct pam_response *resp_ = &res_; | ||
|
||
if ((pam_res = pam_get_item(pamh, PAM_CONV, (const void **)&conv)) != | ||
PAM_SUCCESS) { | ||
syslog(LOG_ERR, "Failed to acquire conversation"); | ||
return pam_res; | ||
} | ||
|
||
auto conv_function = bind( | ||
(*conv->conv), 1, (const struct pam_message **)&msgp, &resp_, nullptr); | ||
|
||
if (reader.ParseError() < 0) { | ||
syslog(LOG_ERR, "Failed to parse the configuration"); | ||
return PAM_SYSTEM_ERR; | ||
} | ||
|
||
if (reader.GetBoolean("core", "disabled", false)) { | ||
return PAM_AUTHINFO_UNAVAIL; | ||
} | ||
|
||
if (reader.GetBoolean("core", "ignore_ssh", true)) { | ||
if (getenv("SSH_CONNECTION") != nullptr || | ||
getenv("SSH_CLIENT") != nullptr || getenv("SSHD_OPTS") != nullptr) { | ||
return PAM_AUTHINFO_UNAVAIL; | ||
} | ||
} | ||
|
||
if (reader.GetBoolean("core", "detection_notice", false)) { | ||
msg.msg_style = PAM_TEXT_INFO; | ||
msg.msg = "Attempting facial authentication"; | ||
|
||
if ((pam_res = conv_function()) != PAM_SUCCESS) { | ||
syslog(LOG_ERR, "Failed to send detection notice"); | ||
return pam_res; | ||
} | ||
} | ||
|
||
if (reader.GetBoolean("core", "ignore_closed_lid", true)) { | ||
glob_t glob_result{}; | ||
|
||
int return_value = | ||
glob("/proc/acpi/button/lid/*/state", 0, nullptr, &glob_result); | ||
|
||
// TODO: We ignore the result | ||
if (return_value != 0) { | ||
globfree(&glob_result); | ||
} | ||
|
||
for (size_t i = 0; i < glob_result.gl_pathc; ++i) { | ||
ifstream file(string(glob_result.gl_pathv[i])); | ||
string lid_state; | ||
getline(file, lid_state, (char)file.eof()); | ||
if (lid_state.find("closed") != std::string::npos) { | ||
globfree(&glob_result); | ||
return PAM_AUTHINFO_UNAVAIL; | ||
} | ||
} | ||
|
||
globfree(&glob_result); | ||
} | ||
|
||
char *user_ptr = nullptr; | ||
if ((pam_res = pam_get_user(pamh, (const char **)&user_ptr, nullptr)) != | ||
PAM_SUCCESS) { | ||
syslog(LOG_ERR, "Failed to get username"); | ||
return pam_res; | ||
} | ||
string user(user_ptr); | ||
|
||
boost::asio::io_context ios; | ||
bp::async_pipe pipe(ios); | ||
|
||
array<char, 1> _buf; | ||
atomic<bool> is_howdy_enter(false); | ||
boost::asio::async_read(pipe, boost::asio::buffer(_buf, 1), | ||
[&](auto ec, auto size) { | ||
if (size >= 1) | ||
is_howdy_enter = true; | ||
}); | ||
pipe.async_close(); | ||
|
||
int howdy_status; | ||
bp::child howdy( | ||
bp::search_path("python"), "/lib/security/howdy/compare.py", user, ios, | ||
bp::std_err > bp::null, bp::std_out > bp::null, | ||
bp::env["PIPE_FD"] = to_string(pipe.native_source()), | ||
bp::on_exit = [&](int exit, const error_code &_ec) { | ||
howdy_status = exit; | ||
}); | ||
|
||
auto _ = async(launch::async, [&] { ios.run(); }); | ||
|
||
auto pass_future = async(launch::async, [&] { | ||
char *auth_tok_ptr = nullptr; | ||
int pam_res = pam_get_authtok(pamh, PAM_AUTHTOK, | ||
(const char **)&auth_tok_ptr, nullptr); | ||
return make_pair(auth_tok_ptr, pam_res); | ||
}); | ||
|
||
auto pass = pass_future.get(); | ||
|
||
if (is_howdy_enter) { | ||
if (!howdy.wait_for(1s)) | ||
howdy.terminate(); | ||
} else { | ||
howdy.terminate(); | ||
} | ||
|
||
if (is_howdy_enter && howdy_status == 0) { | ||
|
||
if (!reader.GetBoolean("section", "no_confirmation", true)) { | ||
string identify_msg("Identified face as "); | ||
identify_msg.append(user); | ||
msg.msg_style = PAM_TEXT_INFO; | ||
msg.msg = identify_msg.c_str(); | ||
conv_function(); | ||
} | ||
|
||
syslog(LOG_INFO, "Login approved"); | ||
return PAM_SUCCESS; | ||
} else if (get<int>(pass) == PAM_SUCCESS && get<char *>(pass) != nullptr && | ||
!string(get<char *>(pass)).empty()) { | ||
return PAM_IGNORE; | ||
} else { | ||
return on_howdy_auth(howdy_status, conv_function, msgp); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
project('pam_howdy', 'cpp', version: '0.1.0') | ||
|
||
inih = subproject('inih') | ||
inih_cpp = inih.get_variable('INIReader_dep') | ||
|
||
libpam = meson.get_compiler('c').find_library('pam') | ||
boost = dependency('boost', modules: ['filesystem']) | ||
threads = dependency('threads') | ||
shared_library('pam_howdy', 'main.cc', soversion: '', dependencies: [boost, libpam, inih_cpp, threads], install: true, install_dir: '/lib/security/') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[wrap-git] | ||
url = https://github.com/benhoyt/inih.git | ||
revision = r52 |