chiark / gitweb /
cgroup: kill processes even in cgroups that aren't realized
[elogind.git] / src / gnome-ask-password-agent.vala
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
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.
10
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.
15
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/>.
18 ***/
19
20 using Gtk;
21 using GLib;
22 using Linux;
23 using Posix;
24 using Notify;
25
26 [CCode (cheader_filename = "time.h")]
27 extern int clock_gettime(int id, out timespec ts);
28
29 public class PasswordDialog : Dialog {
30
31         public Entry entry;
32
33         public PasswordDialog(string message, string icon) {
34                 set_title("System Password");
35                 set_has_separator(false);
36                 set_border_width(8);
37                 set_default_response(ResponseType.OK);
38                 set_icon_name(icon);
39
40 #if LIBNOTIFY07
41                 add_button(Stock.CANCEL, ResponseType.CANCEL);
42                 add_button(Stock.OK, ResponseType.OK);
43 #else
44                 add_button(STOCK_CANCEL, ResponseType.CANCEL);
45                 add_button(STOCK_OK, ResponseType.OK);
46 #endif
47
48                 Container content = (Container) get_content_area();
49
50                 Box hbox = new HBox(false, 16);
51                 hbox.set_border_width(8);
52                 content.add(hbox);
53
54                 Image image = new Image.from_icon_name(icon, IconSize.DIALOG);
55                 hbox.pack_start(image, false, false);
56
57                 Box vbox = new VBox(false, 8);
58                 hbox.pack_start(vbox, true, true);
59
60                 Label label = new Label(message);
61                 vbox.pack_start(label, false, false);
62
63                 entry = new Entry();
64                 entry.set_visibility(false);
65                 entry.set_activates_default(true);
66                 vbox.pack_start(entry, false, false);
67
68                 entry.activate.connect(on_entry_activated);
69
70                 show_all();
71         }
72
73         public void on_entry_activated() {
74                 response(ResponseType.OK);
75         }
76 }
77
78 public class MyStatusIcon : StatusIcon {
79
80         File directory;
81         File current;
82         FileMonitor file_monitor;
83
84         string message;
85         string icon;
86         string socket;
87
88         PasswordDialog password_dialog;
89
90         public MyStatusIcon() throws GLib.Error {
91                 GLib.Object(icon_name : "dialog-password");
92                 set_title("System Password Request");
93
94                 directory = File.new_for_path("/run/systemd/ask-password/");
95                 file_monitor = directory.monitor_directory(0);
96                 file_monitor.changed.connect(file_monitor_changed);
97
98                 current = null;
99                 look_for_password();
100
101                 activate.connect(status_icon_activate);
102         }
103
104         void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) {
105
106                 if (!file.get_basename().has_prefix("ask."))
107                         return;
108
109                 if (event_type == FileMonitorEvent.CREATED ||
110                     event_type == FileMonitorEvent.DELETED) {
111                         try {
112                                 look_for_password();
113                         } catch (Error e) {
114                                 show_error(e.message);
115                         }
116                 }
117         }
118
119         void look_for_password() throws GLib.Error {
120
121                 if (current != null) {
122                         if (!current.query_exists()) {
123                                 current = null;
124                                 if (password_dialog != null)
125                                         password_dialog.response(ResponseType.REJECT);
126                         }
127                 }
128
129                 if (current == null) {
130                         FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
131
132                         FileInfo i;
133                         while ((i = enumerator.next_file()) != null) {
134                                 if (!i.get_name().has_prefix("ask."))
135                                         continue;
136
137                                 current = directory.get_child(i.get_name());
138
139                                 if (load_password())
140                                         break;
141
142                                 current = null;
143                         }
144                 }
145
146                 if (current == null)
147                         set_visible(false);
148         }
149
150         bool load_password() throws GLib.Error {
151
152                 KeyFile key_file = new KeyFile();
153
154                 try {
155                         timespec ts;
156
157                         key_file.load_from_file(current.get_path(), KeyFileFlags.NONE);
158
159                         string not_after_as_string = key_file.get_string("Ask", "NotAfter");
160
161                         clock_gettime(1, out ts);
162                         uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
163
164                         uint64 not_after;
165                         if (not_after_as_string.scanf("%llu", out not_after) != 1)
166                                 return false;
167
168                         if (not_after > 0 && not_after < now)
169                                 return false;
170
171                         socket = key_file.get_string("Ask", "Socket");
172                 } catch (GLib.Error e) {
173                         return false;
174                 }
175
176                 try {
177                         message = key_file.get_string("Ask", "Message").compress();
178                 } catch (GLib.Error e) {
179                         message = "Please Enter System Password!";
180                 }
181
182                 set_tooltip_text(message);
183
184                 try {
185                         icon = key_file.get_string("Ask", "Icon");
186                 } catch (GLib.Error e) {
187                         icon = "dialog-password";
188                 }
189                 set_from_icon_name(icon);
190
191                 set_visible(true);
192
193 #if LIBNOTIFY07
194                 Notification n = new Notification(title, message, icon);
195 #else
196                 Notification n = new Notification(title, message, icon, null);
197                 n.attach_to_status_icon(this);
198 #endif
199                 n.set_timeout(5000);
200                 n.show();
201
202                 return true;
203         }
204
205         void status_icon_activate() {
206
207                 if (current == null)
208                         return;
209
210                 if (password_dialog != null) {
211                         password_dialog.present();
212                         return;
213                 }
214
215                 password_dialog = new PasswordDialog(message, icon);
216
217                 int result = password_dialog.run();
218                 string password = password_dialog.entry.get_text();
219
220                 password_dialog.destroy();
221                 password_dialog = null;
222
223                 if (result == ResponseType.REJECT ||
224                     result == ResponseType.DELETE_EVENT)
225                         return;
226
227                 int to_process;
228
229                 try {
230                         Process.spawn_async_with_pipes(
231                                         null,
232                                         { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket },
233                                         null,
234                                         0,
235                                         null,
236                                         null,
237                                         out to_process,
238                                         null,
239                                         null);
240
241                         OutputStream stream = new UnixOutputStream(to_process, true);
242 #if VALA_0_12
243                         stream.write(password.data, null);
244 #else
245                         stream.write(password, password.length, null);
246 #endif
247                 } catch (Error e) {
248                         show_error(e.message);
249                 }
250         }
251 }
252
253 static const OptionEntry entries[] = {
254         { null }
255 };
256
257 void show_error(string e) {
258         var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e);
259         m.run();
260         m.destroy();
261 }
262
263 int main(string[] args) {
264         try {
265                 Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent");
266                 Notify.init("Password Agent");
267
268                 MyStatusIcon i = new MyStatusIcon();
269                 Gtk.main();
270
271         } catch (GLib.Error e) {
272                 show_error(e.message);
273         }
274
275         return 0;
276 }