Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
feat(linux): adding pam support
Browse files Browse the repository at this point in the history
  • Loading branch information
RossComputerGuy committed Apr 29, 2024
1 parent e5f9d0a commit 8052db0
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 5 deletions.
5 changes: 3 additions & 2 deletions linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
project(runner LANGUAGES CXX C)

# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
Expand Down Expand Up @@ -64,6 +64,7 @@ add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
add_executable(${BINARY_NAME}
"main.cc"
"application.cc"
"channels/auth.cc"
"channels/outputs.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
Expand All @@ -74,7 +75,7 @@ apply_standard_settings(${BINARY_NAME})

# Add dependency libraries. Add any application-specific dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK PkgConfig::PAM)

# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
Expand Down
1 change: 1 addition & 0 deletions linux/application-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ struct _GenesisShellApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
FlMethodChannel* outputs;
FlMethodChannel* auth;
GtkWindow* win;
};
16 changes: 13 additions & 3 deletions linux/application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "application.h"
#include "application-priv.h"
#include "channels/auth.h"
#include "channels/outputs.h"

#include <flutter_linux/flutter_linux.h>
Expand Down Expand Up @@ -32,9 +33,17 @@ static void genesis_shell_application_activate(GApplication* application) {

fl_register_plugins(FL_PLUGIN_REGISTRY(view));

g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
self->outputs = fl_method_channel_new(fl_engine_get_binary_messenger(fl_view_get_engine(view)), "com.expidusos.genesis.shell/outputs", FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(self->outputs, outputs_method_call_handler, self, nullptr);
{
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
self->outputs = fl_method_channel_new(fl_engine_get_binary_messenger(fl_view_get_engine(view)), "com.expidusos.genesis.shell/outputs", FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(self->outputs, outputs_method_call_handler, self, nullptr);
}

{
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
self->auth = fl_method_channel_new(fl_engine_get_binary_messenger(fl_view_get_engine(view)), "com.expidusos.genesis.shell/auth", FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(self->auth, auth_method_call_handler, self, nullptr);
}

gtk_widget_grab_focus(GTK_WIDGET(view));
}
Expand Down Expand Up @@ -81,6 +90,7 @@ static void genesis_shell_application_dispose(GObject* object) {
GenesisShellApplication* self = GENESIS_SHELL_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
g_clear_object(&self->outputs);
g_clear_object(&self->auth);
G_OBJECT_CLASS(genesis_shell_application_parent_class)->dispose(object);
}

Expand Down
94 changes: 94 additions & 0 deletions linux/channels/auth.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <flutter_linux/flutter_linux.h>

#include <security/pam_appl.h>
#include <security/pam_misc.h>

#include "outputs.h"
#include "../application-priv.h"

static void message_callback(GObject* obj, GAsyncResult* result, gpointer user_data) {
GArray* array_resp = (GArray*)user_data;

g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(FL_METHOD_CHANNEL(obj), result, nullptr);
g_autoptr(FlValue) resp_value = fl_method_response_get_result(response, nullptr);

struct pam_response resp;
resp.resp_retcode = 0;
resp.resp = g_strdup(fl_value_get_string(resp_value));
g_array_append_val(array_resp, resp);
}

static int conversation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) {
GenesisShellApplication* self = GENESIS_SHELL_APPLICATION(appdata_ptr);

GArray* array_resp = g_array_new(false, true, sizeof (struct pam_response));

for (int i = 0; i < num_msg; i++) {
const char* msg_content = msg[i]->msg;

fl_method_channel_invoke_method(self->auth, "ask", fl_value_new_string(msg_content), nullptr, message_callback, array_resp);
}

while (true) {
if ((array_resp->len / sizeof (struct pam_response)) == num_msg) {
break;
}
}

*resp = static_cast<struct pam_response*>(g_array_steal(array_resp, nullptr));
return PAM_SUCCESS;
}

void auth_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) {
g_autoptr(FlMethodResponse) response = nullptr;
if (strcmp(fl_method_call_get_name(method_call), "start") == 0) {
FlValue* args = fl_method_call_get_args(method_call);

gchar* username = nullptr;
if (fl_value_lookup_string(args, "username") != nullptr) {
username = (gchar*)fl_value_get_string(fl_value_lookup_string(args, "username"));
}

struct pam_conv* conv = (struct pam_conv*)malloc(sizeof(struct pam_conv));
conv->conv = conversation;
conv->appdata_ptr = user_data;

pam_handle_t* handle = NULL;
int r = pam_start("genesis-shell", username, conv, &handle);
if (r != PAM_SUCCESS) {
fl_method_call_respond_error(method_call, "PAM", "pam_start failed", fl_value_new_string(pam_strerror(handle, r)), NULL);
pam_end(handle, r);
free(conv);
return;
}

r = pam_authenticate(handle, PAM_SILENT);
if (r != PAM_SUCCESS) {
fl_method_call_respond_error(method_call, "PAM", "pam_authenticate failed", fl_value_new_string(pam_strerror(handle, r)), NULL);
pam_end(handle, r);
free(conv);
return;
}

r = pam_acct_mgmt(handle, PAM_SILENT);
if (r != PAM_SUCCESS) {
fl_method_call_respond_error(method_call, "PAM", "pam_acct_mgmt failed", fl_value_new_string(pam_strerror(handle, r)), NULL);
pam_end(handle, r);
free(conv);
return;
}

pam_get_item(handle, PAM_USER, (const void**)&username);
pam_end(handle, r);
free(conv);

response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_string(username)));
} else {
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
}

g_autoptr(GError) error = nullptr;
if (!fl_method_call_respond(method_call, response, &error)) {
g_warning("Failed to send response: %s", error->message);
}
}
7 changes: 7 additions & 0 deletions linux/channels/auth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include <flutter_linux/flutter_linux.h>

#include "../application.h"

void auth_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data);

0 comments on commit 8052db0

Please sign in to comment.