| 1 | structure Sec :> SEC = struct |
| 2 | |
| 3 | open Init Util Sql |
| 4 | |
| 5 | structure Req = Request(struct |
| 6 | val table = "Sec" |
| 7 | val adminGroup = "server" |
| 8 | fun subject _ = "Security permissions change request" |
| 9 | val template = "sec" |
| 10 | val descr = "change" |
| 11 | fun body (mail, req) = |
| 12 | (Mail.mwrite (mail, req); |
| 13 | Mail.mwrite (mail, "\n")) |
| 14 | end) |
| 15 | |
| 16 | fun findSubusers uname = |
| 17 | let |
| 18 | val uname_under = uname ^ "_" |
| 19 | val inf = TextIO.openIn "/etc/passwd" |
| 20 | |
| 21 | fun loop subs = |
| 22 | case TextIO.inputLine inf of |
| 23 | NONE => ListMergeSort.sort (fn (x, y) => String.compare (x, y) = GREATER) subs |
| 24 | | SOME line => |
| 25 | case String.fields (fn ch => ch = #":") line of |
| 26 | uname'::_ => |
| 27 | if size uname' >= size uname_under |
| 28 | andalso String.substring (uname', 0, size uname_under) = uname_under then |
| 29 | loop (uname' :: subs) |
| 30 | else |
| 31 | loop subs |
| 32 | | _ => loop subs |
| 33 | in |
| 34 | loop [] |
| 35 | before TextIO.closeIn inf |
| 36 | end |
| 37 | |
| 38 | datatype socket_perms = |
| 39 | ANY |
| 40 | | CLIENT_ONLY |
| 41 | | SERVER_ONLY |
| 42 | | NADA |
| 43 | |
| 44 | fun inGroup (uname, grp) = |
| 45 | let |
| 46 | val uname_under = uname ^ "_" |
| 47 | val inf = TextIO.openIn "/etc/group" |
| 48 | |
| 49 | fun loop () = |
| 50 | case TextIO.inputLine inf of |
| 51 | NONE => false |
| 52 | | SOME line => |
| 53 | case String.fields (fn ch => ch = #":") line of |
| 54 | [gname, _, _, members] => |
| 55 | if gname = grp then |
| 56 | mem (uname, String.fields (fn ch => ch = #",") members) |
| 57 | else |
| 58 | loop () |
| 59 | | _ => loop () |
| 60 | in |
| 61 | loop () |
| 62 | before TextIO.closeIn inf |
| 63 | end |
| 64 | |
| 65 | fun socketPerms uname = |
| 66 | if inGroup (uname, "no-sockets") then |
| 67 | NADA |
| 68 | else if inGroup (uname, "no-cli-sockets") then |
| 69 | if inGroup (uname, "no-serv-sockets") then |
| 70 | NADA |
| 71 | else |
| 72 | SERVER_ONLY |
| 73 | else if inGroup (uname, "no-serv-sockets") then |
| 74 | CLIENT_ONLY |
| 75 | else |
| 76 | ANY |
| 77 | |
| 78 | fun isTpe uname = inGroup (uname, "only-tpe") |
| 79 | |
| 80 | fun findFirewallRules uname = |
| 81 | let |
| 82 | val inf = TextIO.openIn "/etc/firewall/users.rules" |
| 83 | |
| 84 | fun loop rules = |
| 85 | case TextIO.inputLine inf of |
| 86 | NONE => List.rev rules |
| 87 | | SOME line => |
| 88 | if String.sub (line, 0) = #"#" then |
| 89 | loop rules |
| 90 | else case String.tokens Char.isSpace line of |
| 91 | uname'::rest => |
| 92 | if uname = uname' then |
| 93 | loop (String.concatWith " " rest :: rules) |
| 94 | else |
| 95 | loop rules |
| 96 | | _ => loop rules |
| 97 | in |
| 98 | loop [] |
| 99 | before TextIO.closeIn inf |
| 100 | end |
| 101 | |
| 102 | fun somethingAllowed fname uname = |
| 103 | let |
| 104 | val inf = TextIO.openIn fname |
| 105 | val uname' = uname ^ "\n" |
| 106 | |
| 107 | fun loop () = |
| 108 | case TextIO.inputLine inf of |
| 109 | NONE => false |
| 110 | | SOME line => line = uname' orelse loop () |
| 111 | in |
| 112 | loop () |
| 113 | before TextIO.closeIn inf |
| 114 | end |
| 115 | |
| 116 | val cronAllowed = somethingAllowed "/etc/cron.allow" |
| 117 | val ftpAllowed = somethingAllowed "/etc/ftpusers" |
| 118 | |
| 119 | end |