From 02c6f45ea57b3b12de237b13f1676657c132150c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 01/12] gnome-ask-password-agent: support user password requests New in systemd 257 --- src/gnome-ask-password-agent.vala | 51 ++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 7124d3f8..425ba06f 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -70,10 +70,14 @@ public class PasswordDialog : Dialog { public class MyStatusIcon : StatusIcon { - File directory; File current; + + File directory; FileMonitor file_monitor; + File? user_directory; + FileMonitor? user_file_monitor; + string message; string icon; string socket; @@ -89,6 +93,17 @@ public class MyStatusIcon : StatusIcon { file_monitor = directory.monitor_directory(0); file_monitor.changed.connect(file_monitor_changed); + string? xdg_runtime_dir = Environment.get_variable("XDG_RUNTIME_DIR"); + if (xdg_runtime_dir != null) { + user_directory = File.new_for_path((!) xdg_runtime_dir + "/systemd/ask-password/"); + if (user_directory.query_exists()) { + user_file_monitor = user_directory.monitor_directory(0); + user_file_monitor.changed.connect(file_monitor_changed); + } else { + user_directory = null; + } + } + current = null; look_for_password(); @@ -120,25 +135,33 @@ public class MyStatusIcon : StatusIcon { } } + if (current == null && user_directory != null) { + look_in_directory((!) user_directory); + } + if (current == null) { - FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); + look_in_directory(directory); + } - FileInfo i; - while ((i = enumerator.next_file()) != null) { - if (!i.get_name().has_prefix("ask.")) - continue; + if (current == null) + set_visible(false); + } - current = directory.get_child(i.get_name()); + void look_in_directory(File dir) throws GLib.Error { + FileEnumerator enumerator = dir.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); - if (load_password()) - break; + FileInfo i; + while ((i = enumerator.next_file()) != null) { + if (!i.get_name().has_prefix("ask.")) + continue; - current = null; - } - } + current = dir.get_child(i.get_name()); - if (current == null) - set_visible(false); + if (load_password()) + break; + + current = null; + } } bool load_password() throws GLib.Error { From d151c81b672d48a6dbee90c531e2d5527547a1d2 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 02/12] gnome-ask-password-agent: use `NotAfter` to set a timeout --- src/gnome-ask-password-agent.vala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 425ba06f..75995fc4 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -167,6 +167,7 @@ public class MyStatusIcon : StatusIcon { bool load_password() throws GLib.Error { KeyFile key_file = new KeyFile(); + int timeout = 5000; try { timespec ts; @@ -186,6 +187,9 @@ public class MyStatusIcon : StatusIcon { if (not_after > 0 && not_after < now) return false; + if (not_after > 0) + timeout = (int)(not_after - now) / 1000; + socket = key_file.get_string("Ask", "Socket"); } catch (GLib.Error e) { return false; @@ -207,7 +211,7 @@ public class MyStatusIcon : StatusIcon { set_from_icon_name(icon); n = new Notify.Notification(title, message, icon); - n.set_timeout(5000); + n.set_timeout(timeout); n.closed.connect(() => { set_visible(true); }); From 6414c45ef9d9be2c828bfc5b44d18bc7e04666ea Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 03/12] gnome-ask-password-agent: port to use `Gtk.Application` This is needed to use `GIO.Notification`, the replacement for `Gtk.StatusIcon`. --- src/gnome-ask-password-agent.vala | 40 +++++++++++-------- src/meson.build | 1 + ...p.systemd.gnome-ask-password-agent.desktop | 11 +++++ 3 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 src/org.freedesktop.systemd.gnome-ask-password-agent.desktop diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 75995fc4..e78af22b 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -270,10 +270,6 @@ public class MyStatusIcon : StatusIcon { } } -const OptionEntry entries[] = { - { null } -}; - void show_error(string e) { Posix.stderr.printf("%s\n", e); var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e); @@ -281,18 +277,30 @@ void show_error(string e) { m.destroy(); } -int main(string[] args) { - try { - Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent"); - Notify.init("Password Agent"); - - MyStatusIcon i = new MyStatusIcon(); - Gtk.main(); - } catch (IOError e) { - show_error(e.message); - } catch (GLib.Error e) { - Posix.stderr.printf("%s\n", e.message); +class Application : Gtk.Application { + public Application() { + Object(application_id: "org.freedesktop.systemd.gnome-ask-password-agent", + flags: GLib.ApplicationFlags.IS_SERVICE); + } + + protected override void startup() { + // TODO: watch the system. + // TODO: watch the user. + } + + private Watch? add_watch(string domain, string path) { + // TODO: implement + return null; } - return 0; + public static int main(string[] args) { + try { + Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent"); + } catch (GLib.Error e) { + Posix.stderr.printf("%s\n", e.message); + return 1; + } + Application app = new Application(); + return app.run(args); + } } diff --git a/src/meson.build b/src/meson.build index 449a4770..7d088cb3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,6 +10,7 @@ sgapa_files = files('gnome-ask-password-agent.vala') sgapa = executable('systemd-gnome-ask-password-agent', sgapa_files, dependencies: [common_flags, gtk3, gee, gio_unix, libnotify, posix], install: true) +install_data('org.freedesktop.systemd.gnome-ask-password-agent.desktop', install_dir: applicationsdir) install_data('systemd-gnome-ask-password-agent.rules', install_dir: polkitrulesdir) sgapa_units = files('systemd-gnome-ask-password-agent.path', 'systemd-gnome-ask-password-agent.service') diff --git a/src/org.freedesktop.systemd.gnome-ask-password-agent.desktop b/src/org.freedesktop.systemd.gnome-ask-password-agent.desktop new file mode 100644 index 00000000..fbcab9df --- /dev/null +++ b/src/org.freedesktop.systemd.gnome-ask-password-agent.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=systemd GNOME ask password agent +Comment=Agent for system- and user-level password requests +Exec=systemd-gnome-ask-password-agent +Icon=org.freedesktop.systemd.gnome-ask-password-agent +Terminal=false +Type=Application +Categories=Utility +StartupNotify=true +DBusActivatable=true +X-GNOME-UsesNotifications=true From 2a5620b56072350f626874c19cf1ffca371e61af Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 04/12] gnome-ask-password-agent: make `Watch` work on a single directory This separates the watching for things to send notifications from the handling of actual requests. --- meson.build | 1 - src/gnome-ask-password-agent.vala | 129 ++++++++++-------------------- src/meson.build | 2 +- 3 files changed, 42 insertions(+), 90 deletions(-) diff --git a/meson.build b/meson.build index b53590c3..2b08ec2a 100644 --- a/meson.build +++ b/meson.build @@ -143,7 +143,6 @@ glib = dependency('glib-2.0', version: '> 2.26') gio_unix = dependency('gio-unix-2.0') gee = dependency('gee-0.8') gtk3 = dependency('gtk+-3.0') -libnotify = dependency('libnotify') posix = meson.get_compiler('vala').find_library('posix') ##################################################################### diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index e78af22b..5ee697e9 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -20,7 +20,6 @@ using Gtk; using GLib; using Posix; -using Notify; [CCode (cheader_filename = "time.h")] extern int clock_gettime(int id, out timespec ts); @@ -68,111 +67,65 @@ public class PasswordDialog : Dialog { } } -public class MyStatusIcon : StatusIcon { - - File current; - +class Watch : GLib.Object { File directory; FileMonitor file_monitor; - File? user_directory; - FileMonitor? user_file_monitor; - - string message; - string icon; - string socket; + string title; + string domain_display; + string domain; - PasswordDialog password_dialog; - Notify.Notification n; + public Watch(string domain, string path) throws GLib.Error { - public MyStatusIcon() throws GLib.Error { - GLib.Object(icon_name : "dialog-password"); - set_title("System Password Request"); - - directory = File.new_for_path("/run/systemd/ask-password/"); + directory = File.new_for_path(path); file_monitor = directory.monitor_directory(0); file_monitor.changed.connect(file_monitor_changed); - string? xdg_runtime_dir = Environment.get_variable("XDG_RUNTIME_DIR"); - if (xdg_runtime_dir != null) { - user_directory = File.new_for_path((!) xdg_runtime_dir + "/systemd/ask-password/"); - if (user_directory.query_exists()) { - user_file_monitor = user_directory.monitor_directory(0); - user_file_monitor.changed.connect(file_monitor_changed); - } else { - user_directory = null; - } - } + domain_display = "%s%s".printf(domain.ascii_up(1), domain.substring(1)); + title = "Password Request (%s)".printf(domain_display); + this.domain = domain; - current = null; - look_for_password(); + look_in_directory(directory); + } + + void look_in_directory(File dir) throws GLib.Error { + FileEnumerator enumerator = dir.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); + + FileInfo i; + while ((i = enumerator.next_file()) != null) { + if (!i.get_name().has_prefix("ask.")) { + continue; + } - activate.connect(status_icon_activate); + load_password(dir.get_child(i.get_name())); + } } void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) { - if (!file.get_basename().has_prefix("ask.")) return; if (event_type == FileMonitorEvent.CREATED || event_type == FileMonitorEvent.DELETED) { try { - look_for_password(); + load_password(file); } catch (Error e) { show_error(e.message); } } } - void look_for_password() throws GLib.Error { - - if (current != null) { - if (!current.query_exists()) { - current = null; - if (password_dialog != null) - password_dialog.response(ResponseType.REJECT); - } - } - - if (current == null && user_directory != null) { - look_in_directory((!) user_directory); - } - - if (current == null) { - look_in_directory(directory); - } - - if (current == null) - set_visible(false); - } - - void look_in_directory(File dir) throws GLib.Error { - FileEnumerator enumerator = dir.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); - - FileInfo i; - while ((i = enumerator.next_file()) != null) { - if (!i.get_name().has_prefix("ask.")) - continue; - - current = dir.get_child(i.get_name()); - - if (load_password()) - break; - - current = null; - } - } - - bool load_password() throws GLib.Error { - + bool load_password(File file) throws GLib.Error { KeyFile key_file = new KeyFile(); int timeout = 5000; + string socket; + string message; + string icon; try { timespec ts; - key_file.load_from_file(current.get_path(), KeyFileFlags.NONE); + key_file.load_from_file(file.get_path(), KeyFileFlags.NONE); string not_after_as_string = key_file.get_string("Ask", "NotAfter"); @@ -198,29 +151,22 @@ public class MyStatusIcon : StatusIcon { try { message = key_file.get_string("Ask", "Message").compress(); } catch (GLib.Error e) { - message = "Please Enter System Password!"; + message = "Please Enter %s Password!".printf(domain_display); } - set_tooltip_text(message); - try { icon = key_file.get_string("Ask", "Icon"); } catch (GLib.Error e) { icon = "dialog-password"; } - set_from_icon_name(icon); - n = new Notify.Notification(title, message, icon); - n.set_timeout(timeout); - n.closed.connect(() => { - set_visible(true); - }); - n.add_action("enter_pw", "Enter password", status_icon_activate); - n.show(); + // TODO: send a notification return true; } +} +#if 0 void status_icon_activate() { if (current == null) @@ -268,7 +214,7 @@ public class MyStatusIcon : StatusIcon { show_error(e.message); } } -} +#endif void show_error(string e) { Posix.stderr.printf("%s\n", e); @@ -289,7 +235,14 @@ class Application : Gtk.Application { } private Watch? add_watch(string domain, string path) { - // TODO: implement + try { + return new Watch domain, path); + } catch (IOError e) { + show_error("failed to set up %s watches on %s: %s".printf(domain, path, e.message)); + } catch (GLib.Error e) { + show_error("failed to set up %s watches on %s: %s".printf(domain, path, e.message)); + } + return null; } diff --git a/src/meson.build b/src/meson.build index 7d088cb3..c8039614 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,7 +8,7 @@ install_data('systemadm.appdata.xml', install_dir: appdatadir) sgapa_files = files('gnome-ask-password-agent.vala') sgapa = executable('systemd-gnome-ask-password-agent', sgapa_files, - dependencies: [common_flags, gtk3, gee, gio_unix, libnotify, posix], + dependencies: [common_flags, gtk3, gee, gio_unix, posix], install: true) install_data('org.freedesktop.systemd.gnome-ask-password-agent.desktop', install_dir: applicationsdir) install_data('systemd-gnome-ask-password-agent.rules', install_dir: polkitrulesdir) From 0603eb7e735a179606213db5efbadb5d3b030fbf Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 05/12] gnome-ask-password-agent: parse `--system` to watch for system passwords --- src/gnome-ask-password-agent.vala | 21 +++++++++++++++++++- src/systemd-gnome-ask-password-agent.service | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 5ee697e9..52f07517 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -224,14 +224,33 @@ void show_error(string e) { } class Application : Gtk.Application { + private static bool system = false; + + private Watch? system_watch = null; + + private const OptionEntry entries[] = { + { "system", 's', OptionFlags.NONE, OptionArg.NONE, ref system, "Watch for system requests", null }, + { null } + }; + public Application() { Object(application_id: "org.freedesktop.systemd.gnome-ask-password-agent", flags: GLib.ApplicationFlags.IS_SERVICE); + add_main_option_entries(entries); } protected override void startup() { - // TODO: watch the system. + if (system) { + system_watch = add_watch("system", "/run/systemd/ask-password/"); + } + // TODO: watch the user. + + if (system_watch != null) { + hold(); + } else { + show_error("no watches requested"); + } } private Watch? add_watch(string domain, string path) { diff --git a/src/systemd-gnome-ask-password-agent.service b/src/systemd-gnome-ask-password-agent.service index 983d0d4d..744163e4 100644 --- a/src/systemd-gnome-ask-password-agent.service +++ b/src/systemd-gnome-ask-password-agent.service @@ -12,4 +12,4 @@ Description=Forward Password Requests to GNOME Password Agent After=systemd-user-sessions.service [Service] -ExecStart=systemd-gnome-ask-password-agent +ExecStart=systemd-gnome-ask-password-agent --system From 2c9ff99f3c63de0655da4ed5c9e260e5635c6788 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 06/12] gnome-ask-password-agent: parse `--user` to watch for user passwords --- src/gnome-ask-password-agent.vala | 14 ++++++++++++-- src/systemd-gnome-ask-password-agent.service | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 52f07517..09c27d74 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -225,11 +225,14 @@ void show_error(string e) { class Application : Gtk.Application { private static bool system = false; + private static bool user = false; private Watch? system_watch = null; + private Watch? user_watch = null; private const OptionEntry entries[] = { { "system", 's', OptionFlags.NONE, OptionArg.NONE, ref system, "Watch for system requests", null }, + { "user", 'u', OptionFlags.NONE, OptionArg.NONE, ref user, "Watch for system requests", null }, { null } }; @@ -244,9 +247,16 @@ class Application : Gtk.Application { system_watch = add_watch("system", "/run/systemd/ask-password/"); } - // TODO: watch the user. + if (user) { + string? xdg_runtime_dir = Environment.get_variable("XDG_RUNTIME_DIR"); + if (xdg_runtime_dir == null) { + show_error("no user XDG runtime directory"); + } else { + add_watch("user", (!) xdg_runtime_dir + "/systemd/ask-password/"); + } + } - if (system_watch != null) { + if (system_watch != null || user_watch != null) { hold(); } else { show_error("no watches requested"); diff --git a/src/systemd-gnome-ask-password-agent.service b/src/systemd-gnome-ask-password-agent.service index 744163e4..e8b627e9 100644 --- a/src/systemd-gnome-ask-password-agent.service +++ b/src/systemd-gnome-ask-password-agent.service @@ -12,4 +12,4 @@ Description=Forward Password Requests to GNOME Password Agent After=systemd-user-sessions.service [Service] -ExecStart=systemd-gnome-ask-password-agent --system +ExecStart=systemd-gnome-ask-password-agent --system --user From fd711e8099ec963a9d6837042cb4575ac1a3b5ae Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 07/12] gnome-ask-password-agent: construct the notification --- src/gnome-ask-password-agent.vala | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 09c27d74..4fa40086 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -71,11 +71,14 @@ class Watch : GLib.Object { File directory; FileMonitor file_monitor; + private weak Application app; + string title; string domain_display; string domain; - public Watch(string domain, string path) throws GLib.Error { + public Watch(Application gapp, string domain, string path) throws GLib.Error { + app = gapp; directory = File.new_for_path(path); file_monitor = directory.monitor_directory(0); @@ -160,7 +163,14 @@ class Watch : GLib.Object { icon = "dialog-password"; } - // TODO: send a notification + GLib.Notification n = new GLib.Notification(title); + n.set_category("password.request." + domain); + n.set_body(message); + n.set_priority(GLib.NotificationPriority.NORMAL); + n.set_icon(new ThemedIcon(icon)); + n.add_button_with_target("Enter password", "app.password-request", "(ssss)", domain, message, icon, socket); + + app.send_notification("password-request-%s".printf(socket), n); return true; } @@ -265,7 +275,7 @@ class Application : Gtk.Application { private Watch? add_watch(string domain, string path) { try { - return new Watch domain, path); + return new Watch(this, domain, path); } catch (IOError e) { show_error("failed to set up %s watches on %s: %s".printf(domain, path, e.message)); } catch (GLib.Error e) { From 2dd09861f1e77b1e9d9c8755db67f531ee20e7f2 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 08/12] gnome-ask-password-agent: request the dialog as an action --- src/gnome-ask-password-agent.vala | 111 ++++++++++++++++-------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 4fa40086..b663866b 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -28,8 +28,8 @@ public class PasswordDialog : Dialog { public Entry entry; - public PasswordDialog(string message, string icon) { - set_title("System Password"); + public PasswordDialog(string domain, string message, string icon) { + set_title("%s Password".printf(domain)); set_border_width(8); set_default_response(ResponseType.OK); set_icon_name(icon); @@ -176,56 +176,6 @@ class Watch : GLib.Object { } } -#if 0 - void status_icon_activate() { - - if (current == null) - return; - - if (password_dialog != null) { - password_dialog.present(); - return; - } - - password_dialog = new PasswordDialog(message, icon); - - int result = password_dialog.run(); - string password = password_dialog.entry.get_text(); - - password_dialog.destroy(); - password_dialog = null; - - if (result == ResponseType.REJECT || - result == ResponseType.DELETE_EVENT || - result == ResponseType.CANCEL) - return; - - Pid child_pid; - int to_process; - - try { - Process.spawn_async_with_pipes( - null, - { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket }, - null, - SpawnFlags.DO_NOT_REAP_CHILD, - null, - out child_pid, - out to_process, - null, - null); - ChildWatch.add(child_pid, (pid, status) => { - Process.close_pid(pid); - }); - - OutputStream stream = new UnixOutputStream(to_process, true); - stream.write(password.data, null); - } catch (Error e) { - show_error(e.message); - } - } -#endif - void show_error(string e) { Posix.stderr.printf("%s\n", e); var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e); @@ -246,10 +196,15 @@ class Application : Gtk.Application { { null } }; + private const GLib.ActionEntry actions[] = { + { "password-request", password_request, "(ssss)" }, + }; + public Application() { Object(application_id: "org.freedesktop.systemd.gnome-ask-password-agent", flags: GLib.ApplicationFlags.IS_SERVICE); add_main_option_entries(entries); + add_action_entries(actions, this); } protected override void startup() { @@ -285,6 +240,58 @@ class Application : Gtk.Application { return null; } + private static void password_request(GLib.SimpleAction action, GLib.Variant? variant) { + if (variant.n_children() != 4) { + return; + } + + string domain = variant.get_child_value(0).get_string(); + string message = variant.get_child_value(1).get_string(); + string icon = variant.get_child_value(2).get_string(); + string socket = variant.get_child_value(3).get_string(); + + if (domain.length == 0 || message.length == 0 || icon.length == 0 || socket.length == 0) { + show_error("invalid password request (domain: '%s', message: '%s', icon: '%s', socket: '%s')".printf(domain, message, icon, socket)); + return; + } + + PasswordDialog password_dialog = new PasswordDialog(domain, message, icon); + + int result = password_dialog.run(); + string password = password_dialog.entry.get_text(); + password_dialog.destroy(); + + if (result == ResponseType.REJECT || + result == ResponseType.DELETE_EVENT || + result == ResponseType.CANCEL) { + return; + } + + Pid child_pid; + int to_process; + + try { + Process.spawn_async_with_pipes( + null, + { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket }, + null, + SpawnFlags.DO_NOT_REAP_CHILD, + null, + out child_pid, + out to_process, + null, + null); + ChildWatch.add(child_pid, (pid, status) => { + Process.close_pid(pid); + }); + + OutputStream stream = new UnixOutputStream(to_process, true); + stream.write(password.data, null); + } catch (Error e) { + show_error(e.message); + } + } + public static int main(string[] args) { try { Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent"); From acc7eff30258e5b0bb49339c2cf2b9d31f65232e Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 09/12] gnome-ask-password-agent: implement timeouts on requests --- src/gnome-ask-password-agent.vala | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index b663866b..8fe018d6 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -17,6 +17,7 @@ along with systemd; If not, see . ***/ +using Gee; using Gtk; using GLib; using Posix; @@ -170,7 +171,13 @@ class Watch : GLib.Object { n.set_icon(new ThemedIcon(icon)); n.add_button_with_target("Enter password", "app.password-request", "(ssss)", domain, message, icon, socket); - app.send_notification("password-request-%s".printf(socket), n); + string n_id = "password-request-%s".printf(socket); + app.send_notification(n_id, n); + uint s = GLib.Timeout.add_once(timeout, () => { + app.withdraw_notification(n_id); + app.timeouts.unset(socket); + }); + app.timeouts[socket] = s; return true; } @@ -190,6 +197,8 @@ class Application : Gtk.Application { private Watch? system_watch = null; private Watch? user_watch = null; + public Gee.HashMap timeouts; + private const OptionEntry entries[] = { { "system", 's', OptionFlags.NONE, OptionArg.NONE, ref system, "Watch for system requests", null }, { "user", 'u', OptionFlags.NONE, OptionArg.NONE, ref user, "Watch for system requests", null }, @@ -205,6 +214,9 @@ class Application : Gtk.Application { flags: GLib.ApplicationFlags.IS_SERVICE); add_main_option_entries(entries); add_action_entries(actions, this); + set_default(this); + + timeouts = new Gee.HashMap(); } protected override void startup() { @@ -241,6 +253,12 @@ class Application : Gtk.Application { } private static void password_request(GLib.SimpleAction action, GLib.Variant? variant) { + var gapp = GLib.Application.get_default(); + if (gapp == null) { + return; + } + var app = (Application) (!) gapp; + if (variant.n_children() != 4) { return; } @@ -261,6 +279,11 @@ class Application : Gtk.Application { string password = password_dialog.entry.get_text(); password_dialog.destroy(); + uint n_id; + if (app.timeouts.unset(socket, out n_id)) { + GLib.Source.remove(n_id); + } + if (result == ResponseType.REJECT || result == ResponseType.DELETE_EVENT || result == ResponseType.CANCEL) { From 6e6fdb7d14c2fb5eef0c2d9e57a5997a38a6cf20 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 10/12] gnome-ask-password-agent: add braces to all blocks --- src/gnome-ask-password-agent.vala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 8fe018d6..e41d0228 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -106,8 +106,9 @@ class Watch : GLib.Object { } void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) { - if (!file.get_basename().has_prefix("ask.")) + if (!file.get_basename().has_prefix("ask.")) { return; + } if (event_type == FileMonitorEvent.CREATED || event_type == FileMonitorEvent.DELETED) { @@ -138,14 +139,17 @@ class Watch : GLib.Object { uint64 not_after = uint64.parse(not_after_as_string);; if ((not_after == 0 && GLib.errno == Posix.EINVAL) || - (not_after == int64.MAX && GLib.errno == Posix.ERANGE)) + (not_after == int64.MAX && GLib.errno == Posix.ERANGE)) { return false; + } - if (not_after > 0 && not_after < now) + if (not_after > 0 && not_after < now) { return false; + } - if (not_after > 0) + if (not_after > 0) { timeout = (int)(not_after - now) / 1000; + } socket = key_file.get_string("Ask", "Socket"); } catch (GLib.Error e) { From 2b6f9de60fb277f3b29520fbc87a1160b8625e1b Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 30 Dec 2024 23:29:17 +0100 Subject: [PATCH 11/12] gnome-ask-password-agent: add copyright line I've probably done enough surgery to warrant it at this point. --- src/gnome-ask-password-agent.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index e41d0228..6d0a4d35 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -2,6 +2,7 @@ This file is part of systemd. Copyright 2010 Lennart Poettering + Copyright 2024 Ben Boeckel systemd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 5dda745edc69f3a6b0081d2608be821a69495cee Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 19 Mar 2025 09:09:51 +0100 Subject: [PATCH 12/12] gnome-ask-password-agent: support no-timeout requests --- src/gnome-ask-password-agent.vala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 6d0a4d35..f77a14d8 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -123,7 +123,7 @@ class Watch : GLib.Object { bool load_password(File file) throws GLib.Error { KeyFile key_file = new KeyFile(); - int timeout = 5000; + int? timeout = null; string socket; string message; string icon; @@ -178,11 +178,13 @@ class Watch : GLib.Object { string n_id = "password-request-%s".printf(socket); app.send_notification(n_id, n); - uint s = GLib.Timeout.add_once(timeout, () => { - app.withdraw_notification(n_id); - app.timeouts.unset(socket); + if (timeout != null) { + uint s = GLib.Timeout.add_once((!) timeout, () => { + app.withdraw_notification(n_id); + app.timeouts.unset(socket); }); - app.timeouts[socket] = s; + app.timeouts[socket] = s; + } return true; }