structure Sec :> SEC = struct open Init Util Sql structure Req = Request(struct val table = "Sec" val adminGroup = "server" fun subject _ = "Security permissions change request" val template = "sec" val descr = "change" fun body (mail, req) = (Mail.mwrite (mail, req); Mail.mwrite (mail, "\n")) end) fun findSubusers uname = let val uname_under = uname ^ "_" val inf = TextIO.openIn "/etc/passwd" fun loop subs = case TextIO.inputLine inf of NONE => ListMergeSort.sort (fn (x, y) => String.compare (x, y) = GREATER) subs | SOME line => case String.fields (fn ch => ch = #":") line of uname'::_ => if size uname' >= size uname_under andalso String.substring (uname', 0, size uname_under) = uname_under then loop (uname' :: subs) else loop subs | _ => loop subs in loop [] before TextIO.closeIn inf end datatype socket_perms = ANY | CLIENT_ONLY | SERVER_ONLY | NADA fun inGroup (uname, grp) = let val uname_under = uname ^ "_" val inf = TextIO.openIn "/etc/group" fun loop () = case TextIO.inputLine inf of NONE => false | SOME line => case String.fields (fn ch => ch = #":") line of [gname, _, _, members] => if gname = grp then mem (uname, String.fields (fn ch => ch = #",") members) else loop () | _ => loop () in loop () before TextIO.closeIn inf end fun socketPerms uname = if inGroup (uname, "no-sockets") then NADA else if inGroup (uname, "no-cli-sockets") then if inGroup (uname, "no-serv-sockets") then NADA else SERVER_ONLY else if inGroup (uname, "no-serv-sockets") then CLIENT_ONLY else ANY fun isTpe uname = inGroup (uname, "only-tpe") fun findFirewallRules 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 in loop [] before TextIO.closeIn inf end fun somethingAllowed fname uname = let val inf = TextIO.openIn fname val uname' = uname ^ "\n" fun loop () = case TextIO.inputLine inf of NONE => false | SOME line => line = uname' orelse loop () in loop () before TextIO.closeIn inf end val cronAllowed = somethingAllowed "/etc/cron.allow" val ftpAllowed = somethingAllowed "/etc/ftpusers" end