summaryrefslogtreecommitdiff
path: root/src/ask-password-agent.vala
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-09-17 01:26:29 +0200
committerLennart Poettering <lennart@poettering.net>2010-09-17 01:26:29 +0200
commit490aed584944b684026a3fd01f8d81f2881e38d6 (patch)
tree959f9d1f831752a33ae8ef541fd9e952ce5c2312 /src/ask-password-agent.vala
parent1ebdf5b6847b6a52480a6e9382c1cb70f931a535 (diff)
ask-password: add minimal framework to allow services query SSL/harddisk passphrases from the user
Diffstat (limited to 'src/ask-password-agent.vala')
-rw-r--r--src/ask-password-agent.vala250
1 files changed, 250 insertions, 0 deletions
diff --git a/src/ask-password-agent.vala b/src/ask-password-agent.vala
new file mode 100644
index 0000000000..5355bb4694
--- /dev/null
+++ b/src/ask-password-agent.vala
@@ -0,0 +1,250 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+using Gtk;
+using GLib;
+using DBus;
+using Linux;
+using Posix;
+
+[CCode (cheader_filename = "time.h")]
+extern int clock_gettime(int id, out timespec ts);
+
+public class PasswordDialog : Dialog {
+
+ public Entry entry;
+
+ public PasswordDialog(string message, string icon) {
+ set_title("System Password");
+ set_has_separator(false);
+ set_border_width(8);
+ set_default_response(ResponseType.OK);
+ set_icon_name(icon);
+
+ add_button(STOCK_CANCEL, ResponseType.CANCEL);
+ add_button(STOCK_OK, ResponseType.OK);
+
+ Container content = (Container) get_content_area();
+
+ Box hbox = new HBox(false, 16);
+ hbox.set_border_width(8);
+ content.add(hbox);
+
+ Image image = new Image.from_icon_name(icon, IconSize.DIALOG);
+ hbox.pack_start(image, false, false);
+
+ Box vbox = new VBox(false, 8);
+ hbox.pack_start(vbox, true, true);
+
+ Label label = new Label(message);
+ vbox.pack_start(label, false, false);
+
+ entry = new Entry();
+ entry.set_visibility(false);
+ entry.set_activates_default(true);
+ vbox.pack_start(entry, false, false);
+
+ entry.activate.connect(on_entry_activated);
+
+ show_all();
+ }
+
+ public void on_entry_activated() {
+ response(ResponseType.OK);
+ }
+}
+
+public class MyStatusIcon : StatusIcon {
+
+ File directory;
+ File current;
+ FileMonitor file_monitor;
+
+ string message;
+ string icon;
+ string socket;
+
+ PasswordDialog password_dialog;
+
+ public MyStatusIcon() throws GLib.Error {
+ GLib.Object(icon_name : "dialog-password");
+ set_title("System Password Agent");
+
+ directory = File.new_for_path("/dev/.systemd/ask-password/");
+ file_monitor = directory.monitor_directory(0);
+ file_monitor.changed.connect(file_monitor_changed);
+
+ current = null;
+ look_for_password();
+
+ activate.connect(status_icon_activate);
+ }
+
+ void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) throws GLib.Error {
+
+ if (!file.get_basename().has_prefix("ask."))
+ return;
+
+ if (event_type == FileMonitorEvent.CREATED ||
+ event_type == FileMonitorEvent.DELETED)
+ look_for_password();
+ }
+
+ 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) {
+ FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
+
+ FileInfo i;
+ while ((i = enumerator.next_file()) != null) {
+ if (!i.get_name().has_prefix("ask."))
+ continue;
+
+ current = directory.get_child(i.get_name());
+
+ if (load_password())
+ break;
+
+ current = null;
+ }
+ }
+
+ if (current == null)
+ set_visible(false);
+
+ }
+
+ bool load_password() {
+
+ KeyFile key_file = new KeyFile();
+
+ try {
+ timespec ts;
+
+ key_file.load_from_file(current.get_path(), KeyFileFlags.NONE);
+
+ string not_after_as_string = key_file.get_string("Ask", "NotAfter");
+
+ clock_gettime(1, out ts);
+ uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
+
+ uint64 not_after;
+ if (not_after_as_string.scanf("%llu", out not_after) != 1)
+ return false;
+
+ if (not_after < now)
+ return false;
+
+ socket = key_file.get_string("Ask", "Socket");
+ } catch (GLib.Error e) {
+ return false;
+ }
+
+ try {
+ message = key_file.get_string("Ask", "Message").compress();
+ } catch (GLib.Error e) {
+ message = "Please Enter System Password!";
+ }
+ set_tooltip_text(message);
+
+ try {
+ icon = key_file.get_string("Ask", "Icon");
+ } catch (GLib.Error e) {
+ icon = "dialog-password";
+ }
+ set_from_icon_name(icon);
+
+ set_visible(true);
+ return true;
+ }
+
+ void status_icon_activate() throws GLib.Error {
+
+ 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)
+ return;
+
+ int to_process;
+
+ Process.spawn_async_with_pipes(
+ null,
+ { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket },
+ null,
+ 0,
+ null,
+ null,
+ out to_process,
+ null,
+ null);
+
+ OutputStream stream = new UnixOutputStream(to_process, true);
+
+ stream.write(password, password.length, null);
+ }
+}
+
+static const OptionEntry entries[] = {
+ { null }
+};
+
+void show_error(string e) {
+ var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
+ m.run();
+ m.destroy();
+}
+
+int main(string[] args) {
+ try {
+ Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent");
+
+ MyStatusIcon i = new MyStatusIcon();
+ Gtk.main();
+
+ } catch (DBus.Error e) {
+ show_error(e.message);
+ } catch (GLib.Error e) {
+ show_error(e.message);
+ }
+
+ return 0;
+}