]>
Commit | Line | Data |
---|---|---|
490aed58 LP |
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; | |
490aed58 LP |
22 | using Linux; |
23 | using Posix; | |
efb3237e | 24 | using Notify; |
490aed58 LP |
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 | ||
d0ef2204 | 40 | #if LIBNOTIFY07 |
230e5a3f KS |
41 | add_button(Stock.CANCEL, ResponseType.CANCEL); |
42 | add_button(Stock.OK, ResponseType.OK); | |
d0ef2204 KS |
43 | #else |
44 | add_button(STOCK_CANCEL, ResponseType.CANCEL); | |
45 | add_button(STOCK_OK, ResponseType.OK); | |
46 | #endif | |
490aed58 LP |
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"); | |
820fa964 | 92 | set_title("System Password Request"); |
490aed58 | 93 | |
820fa964 | 94 | directory = File.new_for_path("/var/run/systemd/ask-password/"); |
490aed58 LP |
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 | ||
26742b3f | 104 | void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) { |
490aed58 LP |
105 | |
106 | if (!file.get_basename().has_prefix("ask.")) | |
107 | return; | |
108 | ||
109 | if (event_type == FileMonitorEvent.CREATED || | |
26742b3f LP |
110 | event_type == FileMonitorEvent.DELETED) { |
111 | try { | |
112 | look_for_password(); | |
113 | } catch (Error e) { | |
114 | show_error(e.message); | |
115 | } | |
116 | } | |
490aed58 LP |
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); | |
490aed58 LP |
148 | } |
149 | ||
efb3237e | 150 | bool load_password() throws GLib.Error { |
490aed58 LP |
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 < 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 | } | |
820fa964 | 181 | |
490aed58 LP |
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); | |
efb3237e | 192 | |
d0ef2204 | 193 | #if LIBNOTIFY07 |
230e5a3f | 194 | Notification n = new Notification(title, message, icon); |
d0ef2204 KS |
195 | #else |
196 | Notification n = new Notification(title, message, icon, null); | |
197 | n.attach_to_status_icon(this); | |
198 | #endif | |
efb3237e LP |
199 | n.set_timeout(5000); |
200 | n.show(); | |
201 | ||
490aed58 LP |
202 | return true; |
203 | } | |
204 | ||
26742b3f | 205 | void status_icon_activate() { |
490aed58 LP |
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 | ||
26742b3f LP |
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); | |
e75c0580 | 242 | #if VALA_0_12 |
202df05e | 243 | stream.write(password.data, null); |
e75c0580 KS |
244 | #else |
245 | stream.write(password, password.length, null); | |
e8bf3c88 | 246 | #endif |
26742b3f LP |
247 | } catch (Error e) { |
248 | show_error(e.message); | |
249 | } | |
490aed58 LP |
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"); | |
efb3237e | 266 | Notify.init("Password Agent"); |
490aed58 LP |
267 | |
268 | MyStatusIcon i = new MyStatusIcon(); | |
269 | Gtk.main(); | |
270 | ||
490aed58 LP |
271 | } catch (GLib.Error e) { |
272 | show_error(e.message); | |
273 | } | |
274 | ||
275 | return 0; | |
276 | } |