Make domtool-tail actually work
[hcoop/domtool2.git] / src / tail / tail.sml
... / ...
CommitLineData
1(* HCoop Domtool (http://hcoop.sourceforge.net/)
2 * Copyright (c) 2008, Adam Chlipala
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *)
18
19(* Tailing Apache log files (locally) that you are allowed to see *)
20
21fun hostname () =
22 let
23 val inf = TextIO.openIn "/etc/hostname"
24 in
25 case TextIO.inputLine inf of
26 NONE => (TextIO.closeIn inf; raise Fail "No line in /etc/hostname")
27 | SOME line => (TextIO.closeIn inf; String.substring (line, 0, size line - 1))
28 end
29
30fun main args =
31 let
32 val (f, args) = foldl (fn (arg, (f, args)) =>
33 case arg of
34 "-f" => (true, args)
35 | _ => (f, arg :: args))
36 (false, []) args
37 val args = rev args
38 in
39 case args of
40 [vhost, kind] =>
41 let
42 val () = case kind of
43 "access" => ()
44 | "error" => ()
45 | "rewrite" => ()
46 | _ => (print "Unsupported logfile kind. Use 'access', 'error', or 'rewrite'.\n";
47 OS.Process.exit OS.Process.failure)
48
49 val uid = Posix.ProcEnv.getuid ()
50 val uname = Posix.SysDB.Passwd.name (Posix.SysDB.getpwuid uid)
51
52 val proc = Unix.execute ("/usr/local/bin/domtool-admin", ["perms", uname])
53 val inf = Unix.textInstreamOf proc
54
55 fun allowed () =
56 case TextIO.inputLine inf of
57 NONE => []
58 | SOME line =>
59 case String.tokens Char.isSpace line of
60 "domain:" :: domains => domains
61 | _ => allowed ()
62
63 val domains = allowed ()
64
65 fun inDomains d = List.exists (fn s => s = d) domains
66
67 fun checker pieces =
68 case pieces of
69 [] => false
70 | _ :: pieces =>
71 inDomains (String.concatWith "." pieces)
72 orelse checker pieces
73
74 val tailArgs = ["/var/log/apache2/user/"
75 ^ String.substring (uname, 0, 1)
76 ^ "/"
77 ^ String.substring (uname, 0, 2)
78 ^ "/"
79 ^ uname
80 ^ "/apache/log/"
81 ^ hostname ()
82 ^ "/"
83 ^ vhost
84 ^ "/"
85 ^ kind
86 ^ ".log"]
87
88 val tailArgs =
89 if f then
90 "-f" :: tailArgs
91 else
92 tailArgs
93 in
94 ignore (Unix.reap proc);
95 if inDomains vhost orelse checker (String.fields (fn ch => ch = #".") vhost) then
96 Posix.Process.exec ("/usr/bin/tail", "/usr/bin/tail" :: tailArgs)
97 else
98 (print "You're not authorized to view the logs for that vhost.\n";
99 OS.Process.exit OS.Process.failure)
100 end
101 | _ => (print "Invalid arguments\n";
102 OS.Process.exit OS.Process.failure)
103 end
104
105val () = main (CommandLine.arguments ())