(* HCoop Domtool (http://hcoop.sourceforge.net/)
* Copyright (c) 2006-2007, Adam Chlipala
+ * Copyright (c) 2011 Clinton Ebadi
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*)
-(* Firewall rule querying *)
+(* Firewall management *)
+
+(* Contains portions from Fwtool Copyright (C) 2005 Adam Chlipala, GPL v2 or later *)
structure Firewall :> FIREWALL = struct
+structure StringMap = DataStructures.StringMap
+
+fun parseRules _ =
+ let
+ val inf = TextIO.openIn Config.Firewall.firewallRules
+ val out_lines = ref StringMap.empty
+ val in_lines = ref StringMap.empty
+
+ fun confLine r (uname, line) =
+ let
+ val line = String.concat ["\t", line, "\n"]
+ val lines = case StringMap.find (!r, uname) of
+ NONE => []
+ | SOME lines => lines
+ in
+ r := StringMap.insert (!r, uname, line :: lines)
+ end
+
+ val confLine_in = confLine in_lines
+ val confLine_out = confLine out_lines
+
+ fun parsePorts ports =
+ case String.fields (fn ch => ch = #",") ports of
+ [pp] => pp
+ | pps => String.concat ["(", String.concatWith " " pps, ")"]
+
+ fun parseHosts addr hosts =
+ case hosts of
+ [] => ""
+ | [host] => String.concat [" ", addr, " ", host]
+ | _ => String.concat [" ", addr, " (", String.concatWith " " hosts, ")"]
+
+ fun loop () =
+ case TextIO.inputLine inf of
+ NONE => ()
+ | SOME line =>
+ case String.tokens Char.isSpace line of
+ uname :: rest =>
+ (case rest of
+ "Client" :: ports :: hosts =>
+ confLine_out (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"])
+ | "Server" :: ports :: hosts =>
+ confLine_in (uname, String.concat ["dport ", parsePorts ports, parseHosts "daddr" hosts, " ACCEPT;"])
+ | ["LocalServer", ports] =>
+ confLine_in (uname, String.concat ["saddr $WE dport ", parsePorts ports, " ACCEPT;"])
+ | _ => print "Invalid config line\n";
+ loop ())
+ | _ => loop ()
+ val _ = loop ()
+ in
+ {server_rules = !in_lines, client_rules = !out_lines}
+ end
+
fun query uname =
let
- val inf = TextIO.openIn "/etc/firewall/users.rules"
-
- fun loop rules =
- case TextIO.inputLine inf of
- NONE => List.rev rules
- | SOME line =>
- if String.sub (line, 0) = #"#" then
- loop rules
- else case String.tokens Char.isSpace line of
- uname'::rest =>
- if uname = uname' then
- loop (String.concatWith " " rest :: rules)
- else
- loop rules
- | _ => loop rules
+ val rules = parseRules ()
in
- loop []
- before TextIO.closeIn inf
- end handle IO.Io _ => []
+ getOpt (StringMap.find (#server_rules rules, uname), []) @ getOpt (StringMap.find (#client_rules rules, uname), [])
+ end
+
+fun generateFirewallConfig _ =
+(* rule generation must happen on the node (not really, but I'd rather
+ avoid codifying that uids must be consistent between hosts) *)
+ let
+ val {server_rules, client_rules} = parseRules ()
+ val users_tcp_out_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users_tcp_out.conf")
+ val users_tcp_in_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users_tcp_in.conf")
+ val users_conf = TextIO.openOut (Config.Firewall.firewallDir ^ "/users.conf")
+
+ fun write_user_tcp_conf (rules, outf, suffix) =
+ StringMap.appi (fn (uname, lines) =>
+ let
+ val uid = SysWord.toInt (Posix.ProcEnv.uidToWord (Posix.SysDB.Passwd.uid (Posix.SysDB.getpwnam uname)))
+ in
+ TextIO.output (outf, String.concat
+ ["mod owner uid-owner ",
+ Int.toString uid,
+ " { goto user_",
+ uname,
+ suffix,
+ "; goto lreject; }\n"]);
+ (* Is there any point to splitting the rules like this? *)
+ TextIO.output (users_conf,
+ String.concat ("chain user_"
+ :: uname
+ :: suffix
+ :: " proto tcp {\n"
+ :: lines
+ @ ["}\n\n"]))
+ end handle OS.SysErr _ => print "Invalid user in firewall config, skipping.\n")
+ rules
+ in
+ write_user_tcp_conf (server_rules, users_tcp_in_conf, "_tcp_in");
+ write_user_tcp_conf (client_rules, users_tcp_out_conf, "_tcp_out");
+ TextIO.closeOut users_conf;
+ TextIO.closeOut users_tcp_out_conf;
+ TextIO.closeOut users_tcp_in_conf
+ end
+
end