Merge lp:~elementary-apps/switchboard-plug-parental-controls/saving-rewrite into lp:~elementary-pantheon/switchboard-plug-parental-controls/trunk
- saving-rewrite
- Merge into trunk
Proposed by
Adam Bieńkowski
Status: | Merged |
---|---|
Approved by: | Danielle Foré |
Approved revision: | 232 |
Merged at revision: | 280 |
Proposed branch: | lp:~elementary-apps/switchboard-plug-parental-controls/saving-rewrite |
Merge into: | lp:~elementary-pantheon/switchboard-plug-parental-controls/trunk |
Diff against target: |
1129 lines (+502/-418) 14 files modified
lib/exec-monitor.c (+2/-2) src/daemon/CMakeLists.txt (+7/-4) src/daemon/IptablesHelper.vala (+0/-105) src/daemon/ProcessWatcher.vala (+0/-110) src/daemon/Restriction.vala (+60/-0) src/daemon/RestrictionController.vala (+48/-0) src/daemon/Restrictions/AppRestriction.vala (+114/-0) src/daemon/Restrictions/TimeRestriction.vala (+118/-0) src/daemon/Restrictions/WebRestriction.vala (+82/-0) src/daemon/SessionHandler.vala (+59/-34) src/daemon/SessionManager.vala (+7/-12) src/daemon/Timer.vala (+0/-116) src/daemon/UserConfig.vala (+3/-33) vapi/exec-monitor.vapi (+2/-2) |
To merge this branch: | bzr merge lp:~elementary-apps/switchboard-plug-parental-controls/saving-rewrite |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Corentin Noël | code | Approve | |
Review via email: mp+320256@code.launchpad.net |
Commit message
* Rework daemon backend
Description of the change
This branch reworks the way backend is set up. The restrictions are now based on abstract Restriction class, they can start, stop, store their targets etc. The behaviour of the daemon should not change in any way. I want to also make some improvements to the AppRestriction and WebRestriction but for now the core code remains the same.
Before approving, please test every feature & if it works how it should.
To post a comment you must log in.
- 232. By Adam Bieńkowski
-
Resolve conflicts
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/exec-monitor.c' |
2 | --- lib/exec-monitor.c 2016-08-30 18:01:00 +0000 |
3 | +++ lib/exec-monitor.c 2017-03-17 20:20:51 +0000 |
4 | @@ -74,7 +74,7 @@ |
5 | } |
6 | |
7 | void |
8 | -exec_monitor_start (ExecMonitor *self, |
9 | +exec_monitor_start_monitor (ExecMonitor *self, |
10 | GAsyncReadyCallback callback, |
11 | gpointer user_data) |
12 | { |
13 | @@ -102,7 +102,7 @@ |
14 | } |
15 | |
16 | void |
17 | -exec_monitor_stop (ExecMonitor *self) |
18 | +exec_monitor_stop_monitor (ExecMonitor *self) |
19 | { |
20 | ExecMonitorInterface *iface; |
21 | |
22 | |
23 | === modified file 'src/daemon/CMakeLists.txt' |
24 | --- src/daemon/CMakeLists.txt 2016-09-10 22:16:01 +0000 |
25 | +++ src/daemon/CMakeLists.txt 2017-03-17 20:20:51 +0000 |
26 | @@ -9,15 +9,17 @@ |
27 | |
28 | vala_precompile (VALA_C ${DAEMON_EXEC_NAME} |
29 | Daemon.vala |
30 | - ProcessWatcher.vala |
31 | Process.vala |
32 | - IptablesHelper.vala |
33 | - Timer.vala |
34 | SessionManager.vala |
35 | SessionHandler.vala |
36 | Interfaces.vala |
37 | UserConfig.vala |
38 | Server.vala |
39 | + Restriction.vala |
40 | + Restrictions/AppRestriction.vala |
41 | + Restrictions/TimeRestriction.vala |
42 | + Restrictions/WebRestriction.vala |
43 | + RestrictionController.vala |
44 | ${CMAKE_SOURCE_DIR}/src/shared/Constants.vala |
45 | ${CMAKE_SOURCE_DIR}/src/shared/Utils.vala |
46 | ${CMAKE_SOURCE_DIR}/src/shared/PAM/Token.vala |
47 | @@ -28,6 +30,7 @@ |
48 | accountsservice |
49 | polkit-gobject-1 |
50 | gio-2.0 |
51 | + gee-0.8 |
52 | exec-monitor |
53 | OPTIONS |
54 | --vapidir=${CMAKE_SOURCE_DIR}/vapi/ |
55 | @@ -42,4 +45,4 @@ |
56 | |
57 | # Installation |
58 | install (TARGETS ${DAEMON_EXEC_NAME} RUNTIME DESTINATION bin) |
59 | -install (TARGETS ${EXEC_MONITOR_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) |
60 | \ No newline at end of file |
61 | +install (TARGETS ${EXEC_MONITOR_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) |
62 | |
63 | === removed file 'src/daemon/IptablesHelper.vala' |
64 | --- src/daemon/IptablesHelper.vala 2016-09-10 22:16:01 +0000 |
65 | +++ src/daemon/IptablesHelper.vala 1970-01-01 00:00:00 +0000 |
66 | @@ -1,105 +0,0 @@ |
67 | -// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
68 | -/*- |
69 | - * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls) |
70 | - * |
71 | - * This library is free software; you can redistribute it and/or |
72 | - * modify it under the terms of the GNU Library General Public |
73 | - * License as published by the Free Software Foundation; either |
74 | - * version 3 of the License, or (at your option) any later version. |
75 | - * |
76 | - * This library is distributed in the hope that it will be useful, |
77 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
78 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
79 | - * Library General Public License for more details. |
80 | - * |
81 | - * You should have received a copy of the GNU Library General Public |
82 | - * License along with this library; if not, write to the |
83 | - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
84 | - * Boston, MA 02111-1307, USA. |
85 | - * |
86 | - * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
87 | - */ |
88 | - |
89 | - namespace PC.Daemon { |
90 | - public class IptablesHelper : Object { |
91 | - private const string IPTABLES_EXEC = "iptables"; |
92 | - private const int DPORT = 80; |
93 | - |
94 | - private UserConfig config; |
95 | - private string[] current_urls; |
96 | - |
97 | - public static bool get_can_start () { |
98 | - return Environment.find_program_in_path (IPTABLES_EXEC) != null; |
99 | - } |
100 | - |
101 | - public IptablesHelper (UserConfig config) { |
102 | - this.config = config; |
103 | - } |
104 | - |
105 | - public void start () { |
106 | - this.current_urls = config.get_block_urls (); |
107 | - add_rules (); |
108 | - } |
109 | - |
110 | - public void restart () { |
111 | - remove_rules (); |
112 | - |
113 | - current_urls = config.get_block_urls (); |
114 | - add_rules (); |
115 | - } |
116 | - |
117 | - public void stop () { |
118 | - remove_rules (); |
119 | - } |
120 | - |
121 | - private void add_rules () { |
122 | - foreach (string url in current_urls) { |
123 | - string[] addresses = get_addresses_from_name (url); |
124 | - foreach (string address in addresses) { |
125 | - process_adress (address, "-A"); |
126 | - } |
127 | - } |
128 | - } |
129 | - |
130 | - private string[] get_addresses_from_name (string name) { |
131 | - string[] address_list = {}; |
132 | - var resolver = Resolver.get_default (); |
133 | - try { |
134 | - var addresses = resolver.lookup_by_name (name, null); |
135 | - foreach (InetAddress address in addresses) { |
136 | - if (address.get_family () == SocketFamily.IPV4) { |
137 | - address_list += address.to_string (); |
138 | - } |
139 | - } |
140 | - } catch (Error e) { |
141 | - warning (e.message); |
142 | - } |
143 | - |
144 | - return address_list; |
145 | - } |
146 | - |
147 | - private void process_adress (string address, string option) { |
148 | - try { |
149 | - GLib.Process.spawn_sync ("/", |
150 | - { IPTABLES_EXEC, option, "OUTPUT", "-p", "tcp", "-d", address, "--dport", DPORT.to_string (), "-j", "REJECT" }, |
151 | - Environ.get (), |
152 | - SpawnFlags.SEARCH_PATH, |
153 | - null, |
154 | - null, |
155 | - null, |
156 | - null); |
157 | - } catch (SpawnError e) { |
158 | - warning ("%s\n", e.message); |
159 | - } |
160 | - } |
161 | - |
162 | - private void remove_rules () { |
163 | - foreach (string url in current_urls) { |
164 | - string[] addresses = get_addresses_from_name (url); |
165 | - foreach (string address in addresses) { |
166 | - process_adress (address, "-D"); |
167 | - } |
168 | - } |
169 | - } |
170 | - } |
171 | -} |
172 | \ No newline at end of file |
173 | |
174 | === removed file 'src/daemon/ProcessWatcher.vala' |
175 | --- src/daemon/ProcessWatcher.vala 2016-12-09 17:17:31 +0000 |
176 | +++ src/daemon/ProcessWatcher.vala 1970-01-01 00:00:00 +0000 |
177 | @@ -1,110 +0,0 @@ |
178 | -// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
179 | -/*- |
180 | - * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls) |
181 | - * |
182 | - * This library is free software; you can redistribute it and/or |
183 | - * modify it under the terms of the GNU Library General Public |
184 | - * License as published by the Free Software Foundation; either |
185 | - * version 3 of the License, or (at your option) any later version. |
186 | - * |
187 | - * This library is distributed in the hope that it will be useful, |
188 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
189 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
190 | - * Library General Public License for more details. |
191 | - * |
192 | - * You should have received a copy of the GNU Library General Public |
193 | - * License along with this library; if not, write to the |
194 | - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
195 | - * Boston, MA 02111-1307, USA. |
196 | - * |
197 | - * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
198 | - */ |
199 | - |
200 | -namespace PC.Daemon { |
201 | - public class ProcessWatcher : GLib.Object, ExecMonitor { |
202 | - public UserConfig? config = null; |
203 | - private List<string> allowed_executables; |
204 | - private Polkit.Authority authority; |
205 | - |
206 | - public ProcessWatcher () { |
207 | - allowed_executables = new List<string> (); |
208 | - |
209 | - try { |
210 | - authority = Polkit.Authority.get_sync (); |
211 | - } catch (Error e) { |
212 | - warning ("%s\n", e.message); |
213 | - } |
214 | - } |
215 | - |
216 | - public void set_config (UserConfig? config) { |
217 | - this.config = config; |
218 | - allowed_executables = new List<string> (); |
219 | - } |
220 | - |
221 | - private void handle_pid (int pid) { |
222 | - if (config == null || !config.get_active ()) { |
223 | - return; |
224 | - } |
225 | - |
226 | - var process = new Process (pid); |
227 | - |
228 | - string? command = process.get_command (); |
229 | - if (command == null || command == "") { |
230 | - return; |
231 | - } |
232 | - |
233 | - string[]? args = {}; |
234 | - try { |
235 | - Shell.parse_argv (command, out args); |
236 | - if (args == null || args.length < 1) { |
237 | - return; |
238 | - } |
239 | - } catch (ShellError e) { |
240 | - warning ("%s\n", e.message); |
241 | - return; |
242 | - } |
243 | - |
244 | - string executable = args[0]; |
245 | - |
246 | - if (!executable.has_prefix (Path.DIR_SEPARATOR_S)) { |
247 | - executable = Environment.find_program_in_path (executable); |
248 | - } |
249 | - |
250 | - unowned List<string> link = allowed_executables.find_custom (executable, strcmp); |
251 | - if (link != null) { |
252 | - allowed_executables.remove_link (link); |
253 | - return; |
254 | - } |
255 | - |
256 | - if (executable != null && executable in config.get_targets ()) { |
257 | - process.kill (); |
258 | - |
259 | - var server = Server.get_default (); |
260 | - if (config.get_admin () && authority != null) { |
261 | - ulong signal_id = 0; |
262 | - signal_id = server.app_authorization_ended.connect ((client_pid) => { |
263 | - try { |
264 | - var unix_user = new Polkit.UnixUser.for_name (config.username); |
265 | - var result = authority.check_authorization_sync (new Polkit.UnixProcess.for_owner (client_pid, 0, unix_user.get_uid ()), |
266 | - Constants.PARENTAL_CONTROLS_ACTION_ID, |
267 | - null, |
268 | - Polkit.CheckAuthorizationFlags.NONE); |
269 | - if (result.get_is_authorized ()) { |
270 | - allowed_executables.append (executable); |
271 | - server.launch (args); |
272 | - } |
273 | - } catch (Error e) { |
274 | - warning ("%s\n", e.message); |
275 | - } |
276 | - |
277 | - server.disconnect (signal_id); |
278 | - }); |
279 | - |
280 | - server.app_authorize (config.username, executable, Constants.PARENTAL_CONTROLS_ACTION_ID); |
281 | - } else { |
282 | - server.show_app_unavailable (executable); |
283 | - } |
284 | - } |
285 | - } |
286 | - } |
287 | -} |
288 | |
289 | === added file 'src/daemon/Restriction.vala' |
290 | --- src/daemon/Restriction.vala 1970-01-01 00:00:00 +0000 |
291 | +++ src/daemon/Restriction.vala 2017-03-17 20:20:51 +0000 |
292 | @@ -0,0 +1,60 @@ |
293 | +/*- |
294 | + * Copyright (c) 2016 elementary LLC (https://elementary.io) |
295 | + * |
296 | + * This library is free software; you can redistribute it and/or |
297 | + * modify it under the terms of the GNU Library General Public |
298 | + * License as published by the Free Software Foundation; either |
299 | + * version 3 of the License, or (at your option) any later version. |
300 | + * |
301 | + * This library is distributed in the hope that it will be useful, |
302 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
303 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
304 | + * Library General Public License for more details. |
305 | + * |
306 | + * You should have received a copy of the GNU Library General Public |
307 | + * License along with this library; if not, write to the |
308 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
309 | + * Boston, MA 02111-1307, USA. |
310 | + * |
311 | + * Authored by: Felipe Escoto <felescoto95@hotmail.com> |
312 | + */ |
313 | + |
314 | +namespace PC.Daemon { |
315 | + public abstract class Restriction<T> : Object { |
316 | + public GLib.List<T> targets; |
317 | + |
318 | + construct { |
319 | + targets = new GLib.List<T> (); |
320 | + } |
321 | + |
322 | + public static bool get_supported () { |
323 | + return true; |
324 | + } |
325 | + |
326 | + public abstract void start (); |
327 | + public abstract void stop (); |
328 | + |
329 | + public void add_target (T item) { |
330 | + targets.append (item); |
331 | + } |
332 | + |
333 | + public void remove_target (T item) { |
334 | + targets.remove (item); |
335 | + } |
336 | + |
337 | + public void update_targets (GLib.List<T> new_targets) { |
338 | + stop (); |
339 | + clear_targets (); |
340 | + |
341 | + foreach (T target in new_targets) { |
342 | + add_target (target); |
343 | + } |
344 | + |
345 | + start (); |
346 | + } |
347 | + |
348 | + public void clear_targets () { |
349 | + targets.remove (targets.data); |
350 | + } |
351 | + } |
352 | +} |
353 | \ No newline at end of file |
354 | |
355 | === added file 'src/daemon/RestrictionController.vala' |
356 | --- src/daemon/RestrictionController.vala 1970-01-01 00:00:00 +0000 |
357 | +++ src/daemon/RestrictionController.vala 2017-03-17 20:20:51 +0000 |
358 | @@ -0,0 +1,48 @@ |
359 | +/*- |
360 | + * Copyright (c) 2016 elementary LLC (https://elementary.io) |
361 | + * |
362 | + * This library is free software; you can redistribute it and/or |
363 | + * modify it under the terms of the GNU Library General Public |
364 | + * License as published by the Free Software Foundation; either |
365 | + * version 3 of the License, or (at your option) any later version. |
366 | + * |
367 | + * This library is distributed in the hope that it will be useful, |
368 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
369 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
370 | + * Library General Public License for more details. |
371 | + * |
372 | + * You should have received a copy of the GNU Library General Public |
373 | + * License along with this library; if not, write to the |
374 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
375 | + * Boston, MA 02111-1307, USA. |
376 | + * |
377 | + * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
378 | + */ |
379 | + |
380 | +namespace PC.Daemon { |
381 | + public class RestrictionController : Object { |
382 | + private Gee.ArrayList<Restriction> restrictions; |
383 | + |
384 | + construct { |
385 | + restrictions = new Gee.ArrayList<Restriction> (); |
386 | + } |
387 | + |
388 | + public void add_restriction (Restriction restriction) { |
389 | + if (restrictions.contains (restriction)) { |
390 | + return; |
391 | + } |
392 | + |
393 | + restrictions.add (restriction); |
394 | + restriction.start (); |
395 | + } |
396 | + |
397 | + public void remove_restriction (Restriction restriction) { |
398 | + if (!restrictions.contains (restriction)) { |
399 | + return; |
400 | + } |
401 | + |
402 | + restrictions.remove (restriction); |
403 | + restriction.stop (); |
404 | + } |
405 | + } |
406 | +} |
407 | \ No newline at end of file |
408 | |
409 | === added directory 'src/daemon/Restrictions' |
410 | === added file 'src/daemon/Restrictions/AppRestriction.vala' |
411 | --- src/daemon/Restrictions/AppRestriction.vala 1970-01-01 00:00:00 +0000 |
412 | +++ src/daemon/Restrictions/AppRestriction.vala 2017-03-17 20:20:51 +0000 |
413 | @@ -0,0 +1,114 @@ |
414 | +// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
415 | +/*- |
416 | + * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls) |
417 | + * |
418 | + * This library is free software; you can redistribute it and/or |
419 | + * modify it under the terms of the GNU Library General Public |
420 | + * License as published by the Free Software Foundation; either |
421 | + * version 3 of the License, or (at your option) any later version. |
422 | + * |
423 | + * This library is distributed in the hope that it will be useful, |
424 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
425 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
426 | + * Library General Public License for more details. |
427 | + * |
428 | + * You should have received a copy of the GNU Library General Public |
429 | + * License along with this library; if not, write to the |
430 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
431 | + * Boston, MA 02111-1307, USA. |
432 | + * |
433 | + * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
434 | + */ |
435 | + |
436 | +namespace PC.Daemon { |
437 | + public class AppRestriction : Restriction<string>, ExecMonitor { |
438 | + public string username { get; set; } |
439 | + public bool admin { get; set; } |
440 | + |
441 | + private Gee.ArrayList<string> allowed_executables; |
442 | + private Polkit.Authority authority; |
443 | + |
444 | + construct { |
445 | + allowed_executables = new Gee.ArrayList<string> (); |
446 | + |
447 | + try { |
448 | + authority = Polkit.Authority.get_sync (); |
449 | + } catch (Error e) { |
450 | + warning ("%s\n", e.message); |
451 | + } |
452 | + } |
453 | + |
454 | + public override void start () { |
455 | + start_monitor.begin (); |
456 | + } |
457 | + |
458 | + public override void stop () { |
459 | + stop_monitor (); |
460 | + allowed_executables.clear (); |
461 | + } |
462 | + |
463 | + private void handle_pid (int pid) { |
464 | + var process = new Process (pid); |
465 | + |
466 | + string? command = process.get_command (); |
467 | + if (command == null || command == "") { |
468 | + return; |
469 | + } |
470 | + |
471 | + string[]? args = {}; |
472 | + try { |
473 | + Shell.parse_argv (command, out args); |
474 | + if (args == null || args.length < 1) { |
475 | + return; |
476 | + } |
477 | + } catch (ShellError e) { |
478 | + warning ("%s\n", e.message); |
479 | + return; |
480 | + } |
481 | + |
482 | + string executable = args[0]; |
483 | + |
484 | + if (!executable.has_prefix (Path.DIR_SEPARATOR_S)) { |
485 | + executable = Environment.find_program_in_path (executable); |
486 | + } |
487 | + |
488 | + if (allowed_executables.contains (executable)) { |
489 | + allowed_executables.remove (executable); |
490 | + return; |
491 | + } |
492 | + |
493 | + if (executable == null || targets.find_custom (executable, strcmp) == null) { |
494 | + return; |
495 | + } |
496 | + |
497 | + process.kill (); |
498 | + |
499 | + var server = Server.get_default (); |
500 | + if (!admin || authority == null) { |
501 | + server.show_app_unavailable (executable); |
502 | + return; |
503 | + } |
504 | + |
505 | + ulong signal_id = 0; |
506 | + signal_id = server.app_authorization_ended.connect ((client_pid) => { |
507 | + try { |
508 | + var unix_user = (Polkit.UnixUser)Polkit.UnixUser.new_for_name (username); |
509 | + var result = authority.check_authorization_sync (Polkit.UnixProcess.new_for_owner (client_pid, 0, unix_user.get_uid ()), |
510 | + Constants.PARENTAL_CONTROLS_ACTION_ID, |
511 | + null, |
512 | + Polkit.CheckAuthorizationFlags.NONE); |
513 | + if (result.get_is_authorized ()) { |
514 | + allowed_executables.add (executable); |
515 | + server.launch (args); |
516 | + } |
517 | + } catch (Error e) { |
518 | + warning ("%s\n", e.message); |
519 | + } |
520 | + |
521 | + server.disconnect (signal_id); |
522 | + }); |
523 | + |
524 | + server.app_authorize (username, executable, Constants.PARENTAL_CONTROLS_ACTION_ID); |
525 | + } |
526 | + } |
527 | +} |
528 | \ No newline at end of file |
529 | |
530 | === added file 'src/daemon/Restrictions/TimeRestriction.vala' |
531 | --- src/daemon/Restrictions/TimeRestriction.vala 1970-01-01 00:00:00 +0000 |
532 | +++ src/daemon/Restrictions/TimeRestriction.vala 2017-03-17 20:20:51 +0000 |
533 | @@ -0,0 +1,118 @@ |
534 | +// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
535 | +/*- |
536 | + * Copyright (c) 2016 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls) |
537 | + * |
538 | + * This library is free software; you can redistribute it and/or |
539 | + * modify it under the terms of the GNU Library General Public |
540 | + * License as published by the Free Software Foundation; either |
541 | + * version 3 of the License, or (at your option) any later version. |
542 | + * |
543 | + * This library is distributed in the hope that it will be useful, |
544 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
545 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
546 | + * Library General Public License for more details. |
547 | + * |
548 | + * You should have received a copy of the GNU Library General Public |
549 | + * License along with this library; if not, write to the |
550 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
551 | + * Boston, MA 02111-1307, USA. |
552 | + * |
553 | + * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
554 | + */ |
555 | + |
556 | +namespace PC.Daemon { |
557 | + public class TimeRestriction : Restriction<PAM.Token> { |
558 | + private const int MINUTE_INTERVAL = 60; |
559 | + private const int HOUR_INTERVAL = 3600; |
560 | + |
561 | + public signal void terminate (); |
562 | + |
563 | + private uint[] timeout_ids; |
564 | + |
565 | + public override void start () { |
566 | + foreach (PAM.Token token in targets) { |
567 | + process_token (token); |
568 | + } |
569 | + } |
570 | + |
571 | + private void process_token (PAM.Token token) { |
572 | + var times_info = token.get_times_info (); |
573 | + if (times_info.length () == 0) { |
574 | + return; |
575 | + } |
576 | + |
577 | + PAM.TimeInfo? current = null; |
578 | + |
579 | + int day_of_week = new DateTime.now_local ().get_day_of_week (); |
580 | + foreach (PAM.TimeInfo info in times_info) { |
581 | + if ((day_of_week < 6 && info.day_type == PAM.DayType.WEEKDAY) |
582 | + || (day_of_week >= 6 && info.day_type == PAM.DayType.WEEKEND) |
583 | + || info.day_type == PAM.DayType.ALL) { |
584 | + current = info; |
585 | + break; |
586 | + } |
587 | + } |
588 | + |
589 | + if (current == null) { |
590 | + return; |
591 | + } |
592 | + |
593 | + var span = get_difference_span (current.to); |
594 | + int minutes = ((int)(span / GLib.TimeSpan.MINUTE)).abs (); |
595 | + |
596 | + if (minutes > 0) { |
597 | + start_loop (minutes); |
598 | + } else { |
599 | + terminate (); |
600 | + } |
601 | + |
602 | + timeout_ids += Timeout.add_seconds (HOUR_INTERVAL * 24, () => { |
603 | + stop (); |
604 | + start (); |
605 | + return true; |
606 | + }); |
607 | + } |
608 | + |
609 | + public override void stop () { |
610 | + foreach (uint timeout_id in timeout_ids) { |
611 | + GLib.Source.remove (timeout_id); |
612 | + } |
613 | + } |
614 | + |
615 | + private TimeSpan get_difference_span (string estimated_time_str) { |
616 | + int hour = int.parse (estimated_time_str.slice (0, 2)); |
617 | + int minute = int.parse (estimated_time_str.substring (2)); |
618 | + |
619 | + if (hour == 24) { |
620 | + hour = 0; |
621 | + } |
622 | + |
623 | + var current_date = new DateTime.now_local (); |
624 | + var estimated_date = current_date.add_full (0, 0, |
625 | + (hour < current_date.get_hour ()) ? 1 : 0, |
626 | + hour - current_date.get_hour (), |
627 | + minute - current_date.get_minute (), |
628 | + 0); |
629 | + return estimated_date.difference (current_date); |
630 | + } |
631 | + |
632 | + private void start_loop (int minutes) { |
633 | + Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL); |
634 | + timeout_ids += Timeout.add_seconds (MINUTE_INTERVAL, () => { |
635 | + minutes--; |
636 | + if (minutes == MINUTE_INTERVAL || |
637 | + minutes == 10 || |
638 | + minutes == 5 || |
639 | + minutes == 1) { |
640 | + Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL); |
641 | + } |
642 | + |
643 | + if (minutes == 0) { |
644 | + terminate (); |
645 | + } |
646 | + |
647 | + return (minutes > 0); |
648 | + }); |
649 | + } |
650 | + } |
651 | +} |
652 | \ No newline at end of file |
653 | |
654 | === added file 'src/daemon/Restrictions/WebRestriction.vala' |
655 | --- src/daemon/Restrictions/WebRestriction.vala 1970-01-01 00:00:00 +0000 |
656 | +++ src/daemon/Restrictions/WebRestriction.vala 2017-03-17 20:20:51 +0000 |
657 | @@ -0,0 +1,82 @@ |
658 | +// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
659 | +/*- |
660 | + * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls) |
661 | + * |
662 | + * This library is free software; you can redistribute it and/or |
663 | + * modify it under the terms of the GNU Library General Public |
664 | + * License as published by the Free Software Foundation; either |
665 | + * version 3 of the License, or (at your option) any later version. |
666 | + * |
667 | + * This library is distributed in the hope that it will be useful, |
668 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
669 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
670 | + * Library General Public License for more details. |
671 | + * |
672 | + * You should have received a copy of the GNU Library General Public |
673 | + * License along with this library; if not, write to the |
674 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
675 | + * Boston, MA 02111-1307, USA. |
676 | + * |
677 | + * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
678 | + */ |
679 | + |
680 | + namespace PC.Daemon { |
681 | + public class WebRestriction : Restriction<string> { |
682 | + private const string IPTABLES_EXEC = "iptables"; |
683 | + private const int DPORT = 80; |
684 | + |
685 | + public new static bool get_supported () { |
686 | + return Environment.find_program_in_path (IPTABLES_EXEC) != null; |
687 | + } |
688 | + |
689 | + public override void start () { |
690 | + foreach (string url in targets) { |
691 | + string[] addresses = get_addresses_from_name (url); |
692 | + foreach (string address in addresses) { |
693 | + process_adress (address, "-A"); |
694 | + } |
695 | + } |
696 | + } |
697 | + |
698 | + public override void stop () { |
699 | + foreach (string url in targets) { |
700 | + string[] addresses = get_addresses_from_name (url); |
701 | + foreach (string address in addresses) { |
702 | + process_adress (address, "-D"); |
703 | + } |
704 | + } |
705 | + } |
706 | + |
707 | + private string[] get_addresses_from_name (string name) { |
708 | + string[] address_list = {}; |
709 | + var resolver = Resolver.get_default (); |
710 | + try { |
711 | + var addresses = resolver.lookup_by_name (name, null); |
712 | + foreach (InetAddress address in addresses) { |
713 | + if (address.get_family () == SocketFamily.IPV4) { |
714 | + address_list += address.to_string (); |
715 | + } |
716 | + } |
717 | + } catch (Error e) { |
718 | + warning (e.message); |
719 | + } |
720 | + |
721 | + return address_list; |
722 | + } |
723 | + |
724 | + private void process_adress (string address, string option) { |
725 | + try { |
726 | + GLib.Process.spawn_sync ("/", |
727 | + { IPTABLES_EXEC, option, "OUTPUT", "-p", "tcp", "-d", address, "--dport", DPORT.to_string (), "-j", "REJECT" }, |
728 | + Environ.get (), |
729 | + SpawnFlags.SEARCH_PATH, |
730 | + null, |
731 | + null, |
732 | + null, |
733 | + null); |
734 | + } catch (SpawnError e) { |
735 | + warning ("%s\n", e.message); |
736 | + } |
737 | + } |
738 | + } |
739 | +} |
740 | \ No newline at end of file |
741 | |
742 | === modified file 'src/daemon/SessionHandler.vala' |
743 | --- src/daemon/SessionHandler.vala 2016-09-10 22:16:01 +0000 |
744 | +++ src/daemon/SessionHandler.vala 2017-03-17 20:20:51 +0000 |
745 | @@ -22,8 +22,11 @@ |
746 | |
747 | namespace PC.Daemon { |
748 | public class SessionHandler : Object { |
749 | - private IptablesHelper iptables_helper; |
750 | - private Timer? timer; |
751 | + private RestrictionController controller; |
752 | + |
753 | + private AppRestriction app_restriction; |
754 | + private WebRestriction web_restriction; |
755 | + private TimeRestriction time_restriction; |
756 | |
757 | private UserConfig config; |
758 | public ISession session; |
759 | @@ -41,19 +44,19 @@ |
760 | return; |
761 | } |
762 | |
763 | - iptables_helper = new IptablesHelper (config); |
764 | - |
765 | - var token = PAM.Reader.get_token_for_user (Constants.PAM_TIME_CONF_PATH, session.name); |
766 | - if (token != null) { |
767 | - timer = new Timer (token); |
768 | - timer.terminate.connect (() => { |
769 | - try { |
770 | - session.terminate (); |
771 | - } catch (IOError e) { |
772 | - warning (e.message); |
773 | - } |
774 | - }); |
775 | - } |
776 | + controller = new RestrictionController (); |
777 | + |
778 | + app_restriction = new AppRestriction (); |
779 | + web_restriction = new WebRestriction (); |
780 | + |
781 | + time_restriction = new TimeRestriction (); |
782 | + time_restriction.terminate.connect (() => { |
783 | + try { |
784 | + session.terminate (); |
785 | + } catch (IOError e) { |
786 | + warning (e.message); |
787 | + } |
788 | + }); |
789 | } |
790 | |
791 | public string get_id () { |
792 | @@ -69,35 +72,57 @@ |
793 | return; |
794 | } |
795 | |
796 | - if (IptablesHelper.get_can_start ()) { |
797 | - iptables_helper.start (); |
798 | - } |
799 | - |
800 | - if (timer != null) { |
801 | - timer.start (); |
802 | - } |
803 | + app_restriction.username = config.username; |
804 | + app_restriction.admin = config.get_admin (); |
805 | + |
806 | + foreach (string target in config.get_targets ()) { |
807 | + app_restriction.add_target (target); |
808 | + } |
809 | + |
810 | + controller.add_restriction (app_restriction); |
811 | + |
812 | + if (WebRestriction.get_supported ()) { |
813 | + foreach (string url in config.get_block_urls ()) { |
814 | + web_restriction.add_target (url); |
815 | + } |
816 | + |
817 | + controller.add_restriction (web_restriction); |
818 | + } |
819 | + |
820 | + var token = PAM.Reader.get_token_for_user (Constants.PAM_TIME_CONF_PATH, session.name); |
821 | + time_restriction.add_target (token); |
822 | + |
823 | + controller.add_restriction (time_restriction); |
824 | } |
825 | |
826 | public void update () { |
827 | if (!config.get_active ()) { |
828 | - iptables_helper.stop (); |
829 | - if (timer != null) { |
830 | - timer.stop (); |
831 | - } |
832 | - |
833 | + stop (); |
834 | return; |
835 | } |
836 | |
837 | - if (IptablesHelper.get_can_start ()) { |
838 | - iptables_helper.restart (); |
839 | - } |
840 | + app_restriction.username = config.username; |
841 | + app_restriction.admin = config.get_admin (); |
842 | + |
843 | + var new_targets = new GLib.List<string> (); |
844 | + foreach (string target in config.get_targets ()) { |
845 | + new_targets.append (target); |
846 | + } |
847 | + |
848 | + app_restriction.update_targets (new_targets); |
849 | + |
850 | + new_targets = new GLib.List<string> (); |
851 | + foreach (string url in config.get_block_urls ()) { |
852 | + new_targets.append (url); |
853 | + } |
854 | + |
855 | + web_restriction.update_targets (new_targets); |
856 | } |
857 | |
858 | public void stop () { |
859 | - iptables_helper.stop (); |
860 | - if (timer != null) { |
861 | - timer.stop (); |
862 | - } |
863 | + controller.remove_restriction (app_restriction); |
864 | + controller.remove_restriction (web_restriction); |
865 | + controller.remove_restriction (time_restriction); |
866 | } |
867 | } |
868 | } |
869 | \ No newline at end of file |
870 | |
871 | === modified file 'src/daemon/SessionManager.vala' |
872 | --- src/daemon/SessionManager.vala 2016-09-10 22:16:01 +0000 |
873 | +++ src/daemon/SessionManager.vala 2017-03-17 20:20:51 +0000 |
874 | @@ -25,7 +25,6 @@ |
875 | public SessionHandler? current_handler = null; |
876 | private IManager? manager = null; |
877 | private DBusConnection? conn = null; |
878 | - private ProcessWatcher pwatcher; |
879 | |
880 | private uint[] signal_ids; |
881 | |
882 | @@ -45,9 +44,6 @@ |
883 | } catch (IOError e) { |
884 | warning ("%s\n", e.message); |
885 | } |
886 | - |
887 | - pwatcher = new ProcessWatcher (); |
888 | - pwatcher.start.begin (); |
889 | } |
890 | |
891 | public void start () { |
892 | @@ -107,13 +103,14 @@ |
893 | |
894 | stop_current_handler (); |
895 | |
896 | - if (session != null && |
897 | - session.name != null && |
898 | - !(session.name in Constants.DAEMON_IGNORED_USERS)) { |
899 | - current_handler = new SessionHandler (session); |
900 | - current_handler.start (); |
901 | - pwatcher.set_config (current_handler.get_config ()); |
902 | + if (session == null || |
903 | + session.name == null || |
904 | + session.name in Constants.DAEMON_IGNORED_USERS) { |
905 | + return; |
906 | } |
907 | + |
908 | + current_handler = new SessionHandler (session); |
909 | + current_handler.start (); |
910 | } |
911 | |
912 | private void stop_current_handler () { |
913 | @@ -121,8 +118,6 @@ |
914 | current_handler.stop (); |
915 | current_handler = null; |
916 | } |
917 | - |
918 | - pwatcher.set_config (null); |
919 | } |
920 | } |
921 | } |
922 | \ No newline at end of file |
923 | |
924 | === removed file 'src/daemon/Timer.vala' |
925 | --- src/daemon/Timer.vala 2016-08-30 17:28:55 +0000 |
926 | +++ src/daemon/Timer.vala 1970-01-01 00:00:00 +0000 |
927 | @@ -1,116 +0,0 @@ |
928 | -// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
929 | -/*- |
930 | - * Copyright (c) 2016 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls) |
931 | - * |
932 | - * This library is free software; you can redistribute it and/or |
933 | - * modify it under the terms of the GNU Library General Public |
934 | - * License as published by the Free Software Foundation; either |
935 | - * version 3 of the License, or (at your option) any later version. |
936 | - * |
937 | - * This library is distributed in the hope that it will be useful, |
938 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
939 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
940 | - * Library General Public License for more details. |
941 | - * |
942 | - * You should have received a copy of the GNU Library General Public |
943 | - * License along with this library; if not, write to the |
944 | - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
945 | - * Boston, MA 02111-1307, USA. |
946 | - * |
947 | - * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
948 | - */ |
949 | - |
950 | -namespace PC.Daemon { |
951 | - public class Timer : Object { |
952 | - private const int MINUTE_INTERVAL = 60; |
953 | - private const int HOUR_INTERVAL = 3600; |
954 | - |
955 | - public signal void terminate (); |
956 | - |
957 | - private PAM.Token token; |
958 | - private uint[] timeout_ids; |
959 | - |
960 | - public Timer (PAM.Token token) { |
961 | - this.token = token; |
962 | - } |
963 | - |
964 | - public void start () { |
965 | - var times_info = token.get_times_info (); |
966 | - if (times_info.length () == 0) { |
967 | - return; |
968 | - } |
969 | - |
970 | - PAM.TimeInfo? current = null; |
971 | - |
972 | - int day_of_week = new DateTime.now_local ().get_day_of_week (); |
973 | - foreach (PAM.TimeInfo info in times_info) { |
974 | - if ((day_of_week < 6 && info.day_type == PAM.DayType.WEEKDAY) |
975 | - || (day_of_week >= 6 && info.day_type == PAM.DayType.WEEKEND) |
976 | - || info.day_type == PAM.DayType.ALL) { |
977 | - current = info; |
978 | - break; |
979 | - } |
980 | - } |
981 | - |
982 | - if (current == null) { |
983 | - return; |
984 | - } |
985 | - |
986 | - var span = get_difference_span (current.to); |
987 | - int minutes = ((int)(span / GLib.TimeSpan.MINUTE)).abs (); |
988 | - |
989 | - if (minutes > 0) { |
990 | - start_loop (minutes); |
991 | - } else { |
992 | - terminate (); |
993 | - } |
994 | - |
995 | - timeout_ids += Timeout.add_seconds (HOUR_INTERVAL * 24, () => { |
996 | - start (); |
997 | - return true; |
998 | - }); |
999 | - } |
1000 | - |
1001 | - public void stop () { |
1002 | - foreach (uint timeout_id in timeout_ids) { |
1003 | - GLib.Source.remove (timeout_id); |
1004 | - } |
1005 | - } |
1006 | - |
1007 | - private TimeSpan get_difference_span (string estimated_time_str) { |
1008 | - int hour = int.parse (estimated_time_str.slice (0, 2)); |
1009 | - int minute = int.parse (estimated_time_str.substring (2)); |
1010 | - |
1011 | - if (hour == 24) { |
1012 | - hour = 0; |
1013 | - } |
1014 | - |
1015 | - var current_date = new DateTime.now_local (); |
1016 | - var estimated_date = current_date.add_full (0, 0, |
1017 | - (hour < current_date.get_hour ()) ? 1 : 0, |
1018 | - hour - current_date.get_hour (), |
1019 | - minute - current_date.get_minute (), |
1020 | - 0); |
1021 | - return estimated_date.difference (current_date); |
1022 | - } |
1023 | - |
1024 | - private void start_loop (int minutes) { |
1025 | - Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL); |
1026 | - timeout_ids += Timeout.add_seconds (MINUTE_INTERVAL, () => { |
1027 | - minutes--; |
1028 | - if (minutes == MINUTE_INTERVAL || |
1029 | - minutes == 10 || |
1030 | - minutes == 5 || |
1031 | - minutes == 1) { |
1032 | - Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL); |
1033 | - } |
1034 | - |
1035 | - if (minutes == 0) { |
1036 | - terminate (); |
1037 | - } |
1038 | - |
1039 | - return (minutes > 0); |
1040 | - }); |
1041 | - } |
1042 | - } |
1043 | -} |
1044 | \ No newline at end of file |
1045 | |
1046 | === modified file 'src/daemon/UserConfig.vala' |
1047 | --- src/daemon/UserConfig.vala 2016-09-10 22:16:01 +0000 |
1048 | +++ src/daemon/UserConfig.vala 2017-03-17 20:20:51 +0000 |
1049 | @@ -22,7 +22,7 @@ |
1050 | |
1051 | namespace PC.Daemon { |
1052 | public class UserConfig : Object { |
1053 | - public string username; |
1054 | + public string username { get; set; } |
1055 | |
1056 | private static KeyFile key; |
1057 | private static List<UserConfig> config_list; |
1058 | @@ -63,12 +63,7 @@ |
1059 | warning (e.message); |
1060 | } |
1061 | |
1062 | - foreach (Act.User user in Utils.get_usermanager ().list_users ()) { |
1063 | - string username = user.get_user_name (); |
1064 | - if (!key.has_group (username)) { |
1065 | - continue; |
1066 | - } |
1067 | - |
1068 | + foreach (string username in key.get_groups ()) { |
1069 | var user_config = new UserConfig (username); |
1070 | config_list.append (user_config); |
1071 | } |
1072 | @@ -77,25 +72,10 @@ |
1073 | private static bool init_config_file () { |
1074 | var file = File.new_for_path (Constants.DAEMON_CONF_FILE); |
1075 | if (!file.query_exists ()) { |
1076 | - critical ("Could not found daemon config file: %s does not exist".printf (file.get_path ())); |
1077 | + critical ("Could not find daemon config file: %s does not exist".printf (file.get_path ())); |
1078 | return false; |
1079 | } |
1080 | |
1081 | - try { |
1082 | - var monitor = file.monitor (FileMonitorFlags.NONE, null); |
1083 | - monitor.changed.connect ((src, dest, event) => { |
1084 | - if (event == FileMonitorEvent.CHANGES_DONE_HINT) { |
1085 | - foreach (UserConfig config in config_list) { |
1086 | - config.update_key (); |
1087 | - } |
1088 | - |
1089 | - Server.get_default ().config_changed (); |
1090 | - } |
1091 | - }); |
1092 | - } catch (Error e) { |
1093 | - warning (e.message); |
1094 | - } |
1095 | - |
1096 | return true; |
1097 | } |
1098 | |
1099 | @@ -175,16 +155,6 @@ |
1100 | return false; |
1101 | } |
1102 | |
1103 | - public void update_key () { |
1104 | - try { |
1105 | - key.load_from_file (Constants.DAEMON_CONF_FILE, KeyFileFlags.KEEP_COMMENTS | KeyFileFlags.KEEP_TRANSLATIONS); |
1106 | - } catch (KeyFileError e) { |
1107 | - warning (e.message); |
1108 | - } catch (FileError e) { |
1109 | - warning (e.message); |
1110 | - } |
1111 | - } |
1112 | - |
1113 | private void save () { |
1114 | try { |
1115 | key.save_to_file (Constants.DAEMON_CONF_FILE); |
1116 | |
1117 | === modified file 'vapi/exec-monitor.vapi' |
1118 | --- vapi/exec-monitor.vapi 2016-02-21 18:52:25 +0000 |
1119 | +++ vapi/exec-monitor.vapi 2017-03-17 20:20:51 +0000 |
1120 | @@ -1,6 +1,6 @@ |
1121 | [CCode (cheader_filename = "exec-monitor.h", type_id = "exec_monitor_get_type ()")] |
1122 | public interface ExecMonitor : GLib.Object { |
1123 | - public virtual async void start (); |
1124 | - public virtual void stop (); |
1125 | + public virtual async void start_monitor (); |
1126 | + public virtual void stop_monitor (); |
1127 | public abstract void handle_pid (int pid); |
1128 | } |
1129 | \ No newline at end of file |
The code looks good to me, it only requires more testing