elseif $"cmd" = "rule" then
showNormal := false;
val rule = $"rule";
- %>Are you sure you want to request the firewall rule <b><% Web.html uname %> <% Web.html rule %></b> on <b><% Web.html nodeName %></b>?<br>
+
+ if Sec.validRule rule then
+ %>Are you sure you want to request the firewall rule <b><% Web.html uname %> <% Web.html rule %></b> on <b><% Web.html nodeName %></b>?<br>
<a href="sec?cmd=rule2&node=<% nodeNum %>&uname=<% Web.urlEncode uname %>&rule=<% Web.urlEncode rule %>&msg=<% Web.urlEncode ($"msg") %>">Yes, place the request!</a><%
+ else
+ %>"<% Web.html rule %>" is not a valid firewall rule! Please reread <a href="http://wiki.hcoop.net/wiki/FirewallRules">the instructions</a>, and remember to leave off the initial username portion.<%
+ end
+
elseif $"cmd" = "rule2" then
- val id = Sec.Req.add {usr = you, node = nodeNum, data = String.concat ["Add firewall rule \"", uname, " ", $"rule", "\""], msg = $"msg"};
- if not (Sec.Req.notifyNew id) then
- %><h3>Error sending e-mail notification</h3><%
+ val rule = $"rule";
+
+ if Sec.validRule rule then
+ val id = Sec.Req.add {usr = you, node = nodeNum, data = String.concat ["Add firewall rule \"", uname, " ", rule, "\""], msg = $"msg"};
+ if not (Sec.Req.notifyNew id) then
+ %><h3>Error sending e-mail notification</h3><%
+ end
+ %><h3>Request added</h3><%
+ else
+ %>"<% Web.html rule %>" is not a valid firewall rule! Please reread <a href="http://wiki.hcoop.net/wiki/FirewallRules">the instructions</a>, and remember to leave off the initial username portion.<%
end
- %><h3>Request added</h3><%
elseif $"modRule" <> "" then
showNormal := false;
val ftpAllowed : {node : int, uname : string} -> bool
val findFirewallRules : {node : int, uname : string} -> string list
+
+ val validRule : string -> bool
end
[]
end
+fun intFromString s =
+ if CharVector.all Char.isDigit s andalso size s > 0 then
+ Int.fromString s
+ else
+ NONE
+
+fun validPort port =
+ case intFromString port of
+ NONE => false
+ | SOME n => n > 0
+
+fun validPortPiece pp =
+ case String.fields (fn ch => ch = #":") pp of
+ [port] => validPort port
+ | [port1, port2] => validPort port1 andalso validPort port2
+
+fun validPorts ports =
+ List.all validPortPiece (String.fields (fn ch => ch = #",") ports)
+
+fun validIp s =
+ case map intFromString (String.fields (fn ch => ch = #".") s) of
+ [SOME n1, SOME n2, SOME n3, SOME n4] =>
+ n1 >= 0 andalso n1 < 256 andalso n2 >= 0 andalso n2 < 256 andalso n3 >= 0 andalso n3 < 256 andalso n4 >= 0 andalso n4 < 256
+ | _ => false
+
+fun isIdent ch = Char.isLower ch orelse Char.isDigit ch
+
+fun validHost s =
+ size s > 0 andalso size s < 20
+ andalso CharVector.all (fn ch => isIdent ch orelse ch = #"-") s
+
+fun validDomain s =
+ size s > 0 andalso size s < 100
+ andalso List.all validHost (String.fields (fn ch => ch = #".") s)
+
+val validHosts = List.all (fn x => validIp x orelse validDomain x)
+
+fun validRule rule =
+ case String.tokens Char.isSpace rule of
+ "Client" :: ports :: hosts => validPorts ports andalso validHosts hosts
+ | "Server" :: ports :: hosts => validPorts ports andalso validHosts hosts
+ | ["LocalServer", ports] => validPorts ports
+ | _ => false
+
end
msg TEXT NOT NULL,
status INTEGER NOT NULL,
stamp TIMESTAMP NOT NULL,
- FOREIGN KEY (usr) REFERENCES WebUser(id) ON DELETE CASCADE);
+ FOREIGN KEY (usr) REFERENCES WebUser(id) ON DELETE CASCADE,
+ FOREIGN KEY (node) REFERENCES WebNode(id) ON DELETE CASCADE);
CREATE SEQUENCE AptSeq START 1;
msg TEXT NOT NULL,
status INTEGER NOT NULL,
stamp TIMESTAMP NOT NULL,
- FOREIGN KEY (usr) REFERENCES WebUser(id) ON DELETE CASCADE);
+ FOREIGN KEY (usr) REFERENCES WebUser(id) ON DELETE CASCADE,
+ FOREIGN KEY (node) REFERENCES WebNode(id) ON DELETE CASCADE);
CREATE SEQUENCE SecSeq START 1;