Commit | Line | Data |
---|---|---|
f9548f16 AC |
1 | (* HCoop Domtool (http://hcoop.sourceforge.net/) |
2 | * Copyright (c) 2006-2007, Adam Chlipala | |
ec95f39f | 3 | * Copyright (c) 2011 Clinton Ebadi |
f9548f16 AC |
4 | * |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation; either version 2 | |
8 | * of the License, or (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
18 | *) | |
19 | ||
ec95f39f CE |
20 | (* Firewall management *) |
21 | ||
22 | (* Contains portions from Fwtool Copyright (C) 2005 Adam Chlipala, GPL v2 or later *) | |
f9548f16 AC |
23 | |
24 | structure Firewall :> FIREWALL = struct | |
25 | ||
ec95f39f CE |
26 | structure StringMap = DataStructures.StringMap |
27 | ||
28 | fun parseRules _ = | |
29 | let | |
30 | val inf = TextIO.openIn Config.Firewall.firewallRules | |
31 | val out_lines = ref StringMap.empty | |
32 | val in_lines = ref StringMap.empty | |
33 | ||
34 | fun confLine r (uname, line) = | |
35 | let | |
36 | val line = String.concat ["\t", line, "\n"] | |
37 | val lines = case StringMap.find (!r, uname) of | |
38 | NONE => [] | |
39 | | SOME lines => lines | |
40 | in | |
41 | r := StringMap.insert (!r, uname, line :: lines) | |
42 | end | |
43 | ||
44 | val confLine_in = confLine in_lines | |
45 | val confLine_out = confLine out_lines | |
46 | ||
47 | fun parsePorts ports = | |
48 | case String.fields (fn ch => ch = #",") ports of | |
49 | [pp] => pp | |
50 | | pps => String.concat ["(", String.concatWith " " pps, ")"] | |
51 | ||
52 | fun parseHosts addr hosts = | |
53 | case hosts of | |
54 | [] => "" | |
55 | | [host] => String.concat [" ", addr, " ", host] | |
56 | | _ => String.concat [" ", addr, " (", String.concatWith " " hosts, ")"] | |
57 | ||
58 | fun loop () = | |
59 | case TextIO.inputLine inf of | |
60 | NONE => () | |
61 | | SOME line => | |
62 | case String.tokens Char.isSpace line of | |
63 | uname :: rest => | |
64 | (case rest of | |
65 | "Client" :: ports :: hosts => | |
66 | confLine_out (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"]) | |
67 | | "Server" :: ports :: hosts => | |
68 | confLine_in (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"]) | |
69 | | ["LocalServer", ports] => | |
70 | confLine_in (uname, String.concat ["saddr $WE dport ", parsePorts ports, " ACCEPT;"]) | |
71 | | _ => print "Invalid config line\n"; | |
72 | loop ()) | |
73 | | _ => loop () | |
74 | val _ = loop () | |
75 | in | |
76 | {server_rules = !in_lines, client_rules = !out_lines} | |
77 | end | |
78 | ||
f9548f16 AC |
79 | fun query uname = |
80 | let | |
ec95f39f | 81 | val rules = parseRules () |
f9548f16 | 82 | in |
ec95f39f CE |
83 | getOpt (StringMap.find (#server_rules rules, uname), []) @ getOpt (StringMap.find (#client_rules rules, uname), []) |
84 | end | |
85 | ||
f9548f16 | 86 | |
ec95f39f CE |
87 | fun generateFirewallConfig _ = |
88 | (* rule generation must happen on the node (not really, but I'd rather | |
89 | avoid codifying that uids must be consistent between hosts) *) | |
90 | let | |
91 | val {server_rules, client_rules} = parseRules () | |
92 | val users_tcp_out_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users_tcp_out.conf") | |
93 | val users_tcp_in_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users_tcp_in.conf") | |
94 | val users_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users.conf") | |
95 | ||
96 | fun write_user_tcp_conf (rules, outf, suffix) = | |
97 | StringMap.appi (fn (uname, lines) => | |
98 | let | |
99 | val uid = SysWord.toInt (Posix.ProcEnv.uidToWord (Posix.SysDB.Passwd.uid (Posix.SysDB.getpwnam uname))) | |
100 | in | |
101 | TextIO.output (outf, String.concat | |
102 | ["mod owner uid-owner ", | |
103 | Int.toString uid, | |
104 | " { goto user_", | |
105 | uname, | |
106 | suffix, | |
107 | "; goto lreject; }\n"]); | |
108 | (* Is there any point to splitting the rules like this? *) | |
109 | TextIO.output (users_conf, | |
110 | String.concat ("chain user_" | |
111 | :: uname | |
112 | :: suffix | |
113 | :: " proto tcp {\n" | |
114 | :: lines | |
115 | @ ["}\n\n"])) | |
116 | end handle OS.SysErr _ => print "Invalid user in firewall config, skipping.\n") | |
117 | rules | |
118 | in | |
119 | write_user_tcp_conf (server_rules, users_tcp_in_conf, "_tcp_in"); | |
120 | write_user_tcp_conf (client_rules, users_tcp_out_conf, "_tcp_out"); | |
f9548f16 | 121 | |
ec95f39f CE |
122 | TextIO.closeOut users_conf; |
123 | TextIO.closeOut users_tcp_out_conf; | |
124 | TextIO.closeOut users_tcp_in_conf | |
125 | end | |
126 | ||
f9548f16 | 127 | end |