2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 [CCode (cheader_filename = "time.h")]
28 extern int clock_gettime(int id, out timespec ts);
30 public class PasswordDialog : Dialog {
34 public PasswordDialog(string message, string icon) {
35 set_title("System Password");
36 set_has_separator(false);
38 set_default_response(ResponseType.OK);
42 add_button(Stock.CANCEL, ResponseType.CANCEL);
43 add_button(Stock.OK, ResponseType.OK);
45 add_button(STOCK_CANCEL, ResponseType.CANCEL);
46 add_button(STOCK_OK, ResponseType.OK);
49 Container content = (Container) get_content_area();
51 Box hbox = new HBox(false, 16);
52 hbox.set_border_width(8);
55 Image image = new Image.from_icon_name(icon, IconSize.DIALOG);
56 hbox.pack_start(image, false, false);
58 Box vbox = new VBox(false, 8);
59 hbox.pack_start(vbox, true, true);
61 Label label = new Label(message);
62 vbox.pack_start(label, false, false);
65 entry.set_visibility(false);
66 entry.set_activates_default(true);
67 vbox.pack_start(entry, false, false);
69 entry.activate.connect(on_entry_activated);
74 public void on_entry_activated() {
75 response(ResponseType.OK);
79 public class MyStatusIcon : StatusIcon {
83 FileMonitor file_monitor;
89 PasswordDialog password_dialog;
91 public MyStatusIcon() throws GLib.Error {
92 GLib.Object(icon_name : "dialog-password");
93 set_title("System Password");
95 directory = File.new_for_path("/dev/.systemd/ask-password/");
96 file_monitor = directory.monitor_directory(0);
97 file_monitor.changed.connect(file_monitor_changed);
102 activate.connect(status_icon_activate);
105 void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) throws GLib.Error {
107 if (!file.get_basename().has_prefix("ask."))
110 if (event_type == FileMonitorEvent.CREATED ||
111 event_type == FileMonitorEvent.DELETED)
115 void look_for_password() throws GLib.Error {
117 if (current != null) {
118 if (!current.query_exists()) {
120 if (password_dialog != null)
121 password_dialog.response(ResponseType.REJECT);
125 if (current == null) {
126 FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
129 while ((i = enumerator.next_file()) != null) {
130 if (!i.get_name().has_prefix("ask."))
133 current = directory.get_child(i.get_name());
147 bool load_password() throws GLib.Error {
149 KeyFile key_file = new KeyFile();
154 key_file.load_from_file(current.get_path(), KeyFileFlags.NONE);
156 string not_after_as_string = key_file.get_string("Ask", "NotAfter");
158 clock_gettime(1, out ts);
159 uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
162 if (not_after_as_string.scanf("%llu", out not_after) != 1)
168 socket = key_file.get_string("Ask", "Socket");
169 } catch (GLib.Error e) {
174 message = key_file.get_string("Ask", "Message").compress();
175 } catch (GLib.Error e) {
176 message = "Please Enter System Password!";
178 set_tooltip_text(message);
181 icon = key_file.get_string("Ask", "Icon");
182 } catch (GLib.Error e) {
183 icon = "dialog-password";
185 set_from_icon_name(icon);
190 Notification n = new Notification(title, message, icon);
192 Notification n = new Notification(title, message, icon, null);
193 n.attach_to_status_icon(this);
201 void status_icon_activate() throws GLib.Error {
206 if (password_dialog != null) {
207 password_dialog.present();
211 password_dialog = new PasswordDialog(message, icon);
213 int result = password_dialog.run();
214 string password = password_dialog.entry.get_text();
216 password_dialog.destroy();
217 password_dialog = null;
219 if (result == ResponseType.REJECT ||
220 result == ResponseType.DELETE_EVENT)
225 Process.spawn_async_with_pipes(
227 { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket },
236 OutputStream stream = new UnixOutputStream(to_process, true);
239 stream.write(password.data, null);
241 stream.write(password, password.length, null);
246 static const OptionEntry entries[] = {
250 void show_error(string e) {
251 var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
256 int main(string[] args) {
258 Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent");
259 Notify.init("Password Agent");
261 MyStatusIcon i = new MyStatusIcon();
264 } catch (DBus.Error e) {
265 show_error(e.message);
266 } catch (GLib.Error e) {
267 show_error(e.message);