Skip to content

Commit 4ab5596

Browse files
committed
Switching from PAM to Polkit.
1 parent 152acc8 commit 4ab5596

13 files changed

Lines changed: 228 additions & 269 deletions

File tree

lib/utils/local_authentication/method_channel.dart

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,56 +12,7 @@ class LocalAuthenticationMethodChannel extends LocalAuthentication {
1212
final MethodChannel _methodChannel = const MethodChannel('app.openauthenticator.localauth');
1313

1414
@override
15-
Future<bool> authenticate(BuildContext context, String reason) async {
16-
String? realName = await _methodChannel.invokeMethod<String>('localAuth.getRealName');
17-
String? avatarPath = await _methodChannel.invokeMethod<String>('localAuth.getAvatarPath');
18-
File? avatarFile = avatarPath == null ? null : File(avatarPath);
19-
if (avatarFile != null && !avatarFile.existsSync()) {
20-
avatarFile = null;
21-
}
22-
23-
String? password;
24-
bool isValid = false;
25-
while (!isValid) {
26-
if (!context.mounted) {
27-
return isValid;
28-
}
29-
password = await TextInputDialog.prompt(
30-
context,
31-
title: translations.localAuth.methodChannel.title,
32-
message: reason,
33-
initialValue: password,
34-
validator: password == null ? null : ((input) => input == password ? translations.localAuth.methodChannel.wrongPassword : null),
35-
children: [
36-
if (avatarFile != null)
37-
Center(
38-
child: Padding(
39-
padding: EdgeInsets.only(top: 20, bottom: 10),
40-
child: CircleAvatar(
41-
backgroundImage: FileImage(avatarFile),
42-
radius: 50,
43-
),
44-
),
45-
),
46-
if (avatarPath != null && realName != null)
47-
Padding(
48-
padding: EdgeInsets.only(bottom: 20),
49-
child: Text(
50-
realName,
51-
style: Theme.of(context).textTheme.titleMedium,
52-
textAlign: TextAlign.center,
53-
),
54-
),
55-
],
56-
password: true,
57-
);
58-
if (password == null) {
59-
break;
60-
}
61-
isValid = await _methodChannel.invokeMethod<bool>('localAuth.authenticate', {'password': password}) == true;
62-
}
63-
return isValid;
64-
}
15+
Future<bool> authenticate(BuildContext context, String _) async => await _methodChannel.invokeMethod<bool>('localAuth.authenticate') == true;
6516

6617
@override
6718
Future<bool> isSupported() async => (await _methodChannel.invokeMethod<bool>('localAuth.isDeviceSupported')) == true;

linux/CMakeLists.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,8 @@ target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
7676

7777
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
7878

79-
find_package(PAM REQUIRED)
80-
81-
target_include_directories(${BINARY_NAME} PRIVATE ${PAM_INCLUDE_DIRS})
82-
target_link_libraries(${BINARY_NAME} PRIVATE ${PAM_LIBRARIES})
83-
79+
pkg_check_modules(POLKIT REQUIRED IMPORTED_TARGET polkit-gobject-1)
80+
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::POLKIT)
8481

8582
# Run the Flutter tool portions of the build. This must not be removed.
8683
add_dependencies(${BINARY_NAME} flutter_assemble)

linux/cmake/modules/FindPAM.cmake

Lines changed: 0 additions & 76 deletions
This file was deleted.

linux/my_application.cc

Lines changed: 47 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
#include <gdk/gdkx.h>
66
#endif
77

8-
#include <pwd.h>
9-
#include <security/pam_appl.h>
10-
#include <sys/types.h>
11-
#include <unistd.h>
8+
#include <polkit/polkit.h>
129

1310
#include <iostream>
1411
#include <map>
@@ -21,149 +18,76 @@ struct _MyApplication {
2118
char** dart_entrypoint_arguments;
2219
};
2320

24-
struct pam_response_t {
25-
const char* password;
26-
};
27-
2821
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
2922

30-
static gboolean can_authenticate() {
31-
pam_handle_t* pamh = nullptr;
32-
struct pam_conv conv = {nullptr, nullptr};
33-
34-
int ret = pam_start("login", nullptr, &conv, &pamh);
35-
if (ret != PAM_SUCCESS) {
36-
return FALSE;
23+
static void can_authenticate(FlMethodCall* method_call) {
24+
GError* error = nullptr;
25+
PolkitAuthority* authority = polkit_authority_get_sync(nullptr, &error);
26+
if (error) {
27+
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_error_response_new("authCheckError", error->message, nullptr)), nullptr);
28+
g_clear_error(&error);
29+
return;
3730
}
38-
39-
pam_end(pamh, ret);
40-
return TRUE;
31+
if (authority == nullptr) {
32+
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(false))), nullptr);
33+
return;
34+
}
35+
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(true))), nullptr);
4136
}
4237

43-
static gchar* get_real_name() {
38+
static void authenticate_async_callback(PolkitAuthority* authority, GAsyncResult* result, gpointer user_data) {
4439
GError* error = nullptr;
45-
GDBusConnection* connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
46-
if (!connection) return strdup("Unknown");
47-
48-
gchar* user_path = nullptr;
49-
GVariant* result = g_dbus_connection_call_sync(
50-
connection,
51-
"org.freedesktop.Accounts",
52-
"/org/freedesktop/Accounts",
53-
"org.freedesktop.Accounts",
54-
"FindUserByName",
55-
g_variant_new("(s)", getenv("USER")),
56-
G_VARIANT_TYPE("(o)"),
57-
G_DBUS_CALL_FLAGS_NONE,
58-
-1,
59-
nullptr,
60-
&error
61-
);
62-
63-
if (!result) return strdup("Unknown");
64-
65-
g_variant_get(result, "(&o)", &user_path);
66-
67-
// Now get the RealName property
68-
GVariant* name_result = g_dbus_connection_call_sync(
69-
connection,
70-
"org.freedesktop.Accounts",
71-
user_path,
72-
"org.freedesktop.DBus.Properties",
73-
"Get",
74-
g_variant_new("(ss)", "org.freedesktop.Accounts.User", "RealName"),
75-
G_VARIANT_TYPE("(v)"),
76-
G_DBUS_CALL_FLAGS_NONE,
77-
-1,
78-
nullptr,
79-
&error
80-
);
81-
82-
if (!name_result) return strdup("Unknown");
83-
84-
GVariant* name_value = nullptr;
85-
g_variant_get(name_result, "(v)", &name_value);
86-
87-
const char* real_name = g_variant_get_string(name_value, nullptr);
88-
return strdup(real_name);
89-
}
9040

91-
static gchar* get_avatar_path() {
92-
std::string path = "/var/lib/AccountsService/icons/";
93-
path += getenv("USER");
94-
return strdup(path.c_str());
95-
}
96-
97-
static int pam_conversation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) {
98-
struct pam_response_t* data = static_cast<struct pam_response_t*>(appdata_ptr);
99-
// Allocate response memory
100-
*resp = static_cast<struct pam_response*>(
101-
calloc(num_msg, sizeof(struct pam_response)));
102-
103-
if (*resp == nullptr) {
104-
return PAM_CONV_ERR;
105-
}
41+
// Retrieve the result from the async operation
42+
PolkitAuthorizationResult* auth_result = polkit_authority_check_authorization_finish(authority, result, &error);
10643

107-
for (int i = 0; i < num_msg; i++) {
108-
(*resp)[i].resp = strdup(data->password);
44+
if (error) {
45+
std::cout << error->message << std::endl;
46+
fl_method_call_respond((FlMethodCall*)user_data, FL_METHOD_RESPONSE(fl_method_error_response_new("authError", error->message, nullptr)), nullptr);
47+
g_clear_error(&error);
48+
g_object_unref(user_data);
49+
return;
10950
}
110-
111-
return PAM_SUCCESS;
112-
}
113-
114-
static void authenticate(const gchar* password, FlMethodCall* method_call) {
115-
// Get the current username
116-
struct passwd* pw = getpwuid(getuid());
117-
if (pw == nullptr) {
118-
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_error_response_new("authError", "Cannot get current user.", nullptr)), nullptr);
51+
if (auth_result == nullptr) {
52+
fl_method_call_respond((FlMethodCall*)user_data, FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(false))), nullptr);
53+
g_object_unref(user_data);
11954
return;
12055
}
12156

122-
// Set up PAM conversation
123-
struct pam_response_t data;
124-
data.password = password;
57+
gboolean success = polkit_authorization_result_get_is_authorized(auth_result);
58+
fl_method_call_respond((FlMethodCall*)user_data, FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(success))), nullptr);
12559

126-
struct pam_conv conv;
127-
conv.conv = pam_conversation;
128-
conv.appdata_ptr = &data;
60+
g_object_unref(user_data); // Unref the method call after use
61+
}
12962

130-
// Start PAM session
131-
pam_handle_t* pamh = nullptr;
132-
int ret = pam_start("login", pw->pw_name, &conv, &pamh);
133-
if (ret != PAM_SUCCESS) {
134-
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_error_response_new("authError", "Could not start authentication session.", nullptr)), nullptr);
63+
static void authenticate(FlMethodCall* method_call) {
64+
GError* error = nullptr;
65+
PolkitAuthority* authority = polkit_authority_get_sync(nullptr, &error);
66+
if (error || authority == nullptr) {
67+
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_error_response_new("authError", error->message, nullptr)), nullptr);
13568
return;
13669
}
13770

138-
// Try to authenticate
139-
ret = pam_authenticate(pamh, 0);
140-
141-
// Clean up
142-
pam_end(pamh, ret);
143-
144-
FlValue* success = fl_value_new_bool(ret == PAM_SUCCESS);
145-
fl_method_call_respond(method_call, FL_METHOD_RESPONSE(fl_method_success_response_new(success)), nullptr);
71+
PolkitSubject* subject = polkit_unix_process_new_for_owner(getpid(), 0, -1);
72+
polkit_authority_check_authorization(
73+
authority,
74+
subject,
75+
"app.openauthenticator.authenticate",
76+
nullptr,
77+
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
78+
nullptr,
79+
(GAsyncReadyCallback) authenticate_async_callback,
80+
g_object_ref(method_call)
81+
);
14682
}
14783

14884
static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) {
14985
const gchar* method = fl_method_call_get_name(method_call);
15086

15187
if (strcmp(method, "localAuth.isDeviceSupported") == 0) {
152-
g_autoptr(FlValue) result = fl_value_new_bool(can_authenticate());
153-
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
154-
fl_method_call_respond(method_call, response, nullptr);
155-
} else if (strcmp(method, "localAuth.getRealName") == 0) {
156-
g_autoptr(FlValue) result = fl_value_new_string(get_real_name());
157-
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
158-
fl_method_call_respond(method_call, response, nullptr);
159-
} else if (strcmp(method, "localAuth.getAvatarPath") == 0) {
160-
g_autoptr(FlValue) result = fl_value_new_string(get_avatar_path());
161-
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
162-
fl_method_call_respond(method_call, response, nullptr);
88+
can_authenticate(method_call);
16389
} else if (strcmp(method, "localAuth.authenticate") == 0) {
164-
FlValue* args = fl_method_call_get_args(method_call);
165-
FlValue* password = fl_value_lookup_string(args, "password");
166-
authenticate(fl_value_get_string(password), method_call);
90+
authenticate(method_call);
16791
} else {
16892
g_autoptr(FlMethodResponse) response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
16993
fl_method_call_respond(method_call, response, nullptr);

0 commit comments

Comments
 (0)