Generation of slash-tilde waklog directives for each user
[hcoop/domtool2.git] / src / plugins / apache.sml
index 11b4ab3..0b0b11d 100644 (file)
@@ -68,13 +68,19 @@ val _ = Env.type_one "proxy_target"
                fun default () = List.exists (fn s' => s = s') Config.Apache.proxyTargets
            in
                case String.fields (fn ch => ch = #":") s of
-                   ["http", "//localhost", rest] =>
-                   (case String.fields (fn ch => ch = #"/") rest of
-                        port :: _ =>
-                        (case Int.fromString port of
-                             NONE => default ()
-                           | SOME n => n > 1024 orelse default ())
-                      | _ => default ())
+                   "http" :: "//localhost" :: rest =>
+                   let
+                       val rest = String.concatWith ":" rest
+                   in
+                       CharVector.all (fn ch => Char.isPrint ch andalso not (Char.isSpace ch)
+                                                andalso ch <> #"\"" andalso ch <> #"'") rest
+                       andalso case String.fields (fn ch => ch = #"/") rest of
+                                   port :: _ =>
+                                   (case Int.fromString port of
+                                        NONE => default ()
+                                      | SOME n => n > 1024 orelse default ())
+                                 | _ => default ()
+                   end
                  | _ => default ()
            end)
 
@@ -96,7 +102,8 @@ fun validLocation s =
                                                           orelse ch = #"-"
                                                           orelse ch = #"_"
                                                           orelse ch = #"."
-                                                          orelse ch = #"/") s
+                                                          orelse ch = #"/"
+                                                          orelse ch = #"~") s
 
 val _ = Env.type_one "location"
        Env.string
@@ -144,7 +151,10 @@ val defaults = [("WebPlaces",
                 (fn () => (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl))),
                ("SuExec",
                 (TBase "suexec_flag", dl),
-                (fn () => (EVar "true", dl)))]
+                (fn () => (EVar "true", dl))),
+               ("PhpVersion",
+                (TBase "php_version", dl),
+                (fn () => (EVar "php4", dl)))]
 
 val () = app Defaults.registerDefault defaults
 
@@ -233,10 +243,12 @@ val autoindex_option = fn (EApp ((EVar "descriptionWidth", _), w), _) =>
 
 val vhostsChanged = ref false
 val logDeleted = ref false
+val delayedLogMoves = ref (fn () => ())
 
 val () = Slave.registerPreHandler
             (fn () => (vhostsChanged := false;
-                       logDeleted := false))
+                       logDeleted := false;
+                       delayedLogMoves := (fn () => print "Executing delayed log moves/deletes.\n")))
 
 fun findVhostUser fname =
     let
@@ -329,18 +341,20 @@ val () = Slave.registerFileHandler (fn fs =>
                                                               Slave.Delete _ =>
                                                               let
                                                                   val ldir = realLogDir oldUser
+                                                                  val dlm = !delayedLogMoves
                                                               in
                                                                   if !logDeleted then
                                                                       ()
                                                                   else
-                                                                      (ignore (OS.Process.system (down ()));
+                                                                      ((*ignore (OS.Process.system (down ()));*)
                                                                        ignore (OS.Process.system (fixperms ()));
                                                                        logDeleted := true);
                                                                   ignore (OS.Process.system (Config.rm
                                                                                              ^ " -rf "
                                                                                              ^ realVhostFile));
-                                                                  Slave.moveDirCreate {from = ldir,
-                                                                                       to = backupLogs ()}
+                                                                  delayedLogMoves := (fn () => (dlm ();
+                                                                                                Slave.moveDirCreate {from = ldir,
+                                                                                                                     to = backupLogs ()}))
                                                               end
                                                             | Slave.Add =>
                                                               let
@@ -368,15 +382,18 @@ val () = Slave.registerFileHandler (fn fs =>
                                                                    let
                                                                        val old = realLogDir oldUser
                                                                        val rld = realLogDir user
+
+                                                                       val dlm = !delayedLogMoves
                                                                    in
                                                                        if !logDeleted then
                                                                            ()
                                                                        else
-                                                                           (ignore (OS.Process.system (down ()));
+                                                                           ((*ignore (OS.Process.system (down ()));*)
                                                                             logDeleted := true);
-                                                                       ignore (OS.Process.system (Config.rm
-                                                                                                  ^ " -rf "
-                                                                                                  ^ realLogDir oldUser));
+                                                                       delayedLogMoves := (fn () => (dlm ();
+                                                                                                     ignore (OS.Process.system (Config.rm
+                                                                                                                                ^ " -rf "
+                                                                                                                                ^ realLogDir oldUser))));
                                                                        if Posix.FileSys.access (rld, []) then
                                                                            ()
                                                                        else
@@ -393,8 +410,9 @@ val () = Slave.registerFileHandler (fn fs =>
 val () = Slave.registerPostHandler
         (fn () =>
             (if !vhostsChanged then
-                 Slave.shellF ([if !logDeleted then undown () else reload ()],
-                               fn cl => "Error reloading Apache with " ^ cl)
+                 (Slave.shellF ([reload ()],
+                             fn cl => "Error reloading Apache with " ^ cl);
+                  if !logDeleted then !delayedLogMoves () else ())
              else
                  ()))
 
@@ -439,6 +457,10 @@ fun vhostPost () = (!post ();
                    write "</VirtualHost>\n";
                    app (TextIO.closeOut o #2) (!vhostFiles))
 
+val php_version = fn (EVar "php4", _) => SOME 4
+                  | (EVar "php5", _) => SOME 5
+                  | _ => NONE
+
 fun vhostBody (env, makeFullHost) =
     let
        val places = Env.env (Env.list webPlace) (env, "WebPlaces")
@@ -449,6 +471,7 @@ fun vhostBody (env, makeFullHost) =
        val docroot = Env.env Env.string (env, "DocumentRoot")
        val sadmin = Env.env Env.string (env, "ServerAdmin")
        val suexec = Env.env Env.bool (env, "SuExec")
+       val php = Env.env php_version (env, "PhpVersion")
 
        val fullHost = makeFullHost (Domain.currentDomain ())
        val vhostId = fullHost ^ (if Option.isSome ssl then ".ssl" else "")
@@ -496,6 +519,10 @@ fun vhostBody (env, makeFullHost) =
                                           TextIO.output (file, group))
                                      else
                                          (TextIO.output (file, "\n\tSuexecUserGroup ");
+                                          TextIO.output (file, user);
+                                          TextIO.output (file, " ");
+                                          TextIO.output (file, group);
+                                          TextIO.output (file, "\n\tsuPHP_UserGroup ");
                                           TextIO.output (file, user);
                                           TextIO.output (file, " ");
                                           TextIO.output (file, group))
@@ -514,6 +541,13 @@ fun vhostBody (env, makeFullHost) =
                                  TextIO.output (file, user);
                                  TextIO.output (file, "/DAVLock");
 
+                                 if php <> Config.Apache.defaultPhpVersion then
+                                     (TextIO.output (file, "\n\tAddHandler x-httpd-php");
+                                      TextIO.output (file, Int.toString php);
+                                      TextIO.output (file, " .php .phtml"))
+                                 else
+                                     ();
+
                                  (ld, file)
                              end)
                          places;
@@ -564,6 +598,15 @@ val () = Env.container_one "directory"
                    inLocal := false;
                    localRewriteEnabled := false))
 
+val () = Env.container_one "filesMatch"
+        ("regexp", Env.string)
+        (fn prefix =>
+            (write "\t<FilesMatch \"";
+             write prefix;
+             write "\">\n"),
+         fn () => (write "\t</FilesMatch>\n";
+                   localRewriteEnabled := false))
+
 fun checkRewrite () =
     if !inLocal then
        if !localRewriteEnabled then
@@ -581,9 +624,9 @@ val () = Env.action_three "localProxyRewrite"
         ("from", Env.string, "to", Env.string, "port", Env.int)
         (fn (from, to, port) =>
             (checkRewrite ();
-             write "\tRewriteRule\t";
+             write "\tRewriteRule\t\"";
              write from;
-             write "\thttp://localhost:";
+             write "\"\thttp://localhost:";
              write (Int.toString port);
              write "/";
              write to;
@@ -611,10 +654,11 @@ val () = Env.action_three "rewriteRule"
         ("from", Env.string, "to", Env.string, "flags", Env.list flag)
         (fn (from, to, flags) =>
             (checkRewrite ();
-             write "\tRewriteRule\t";
+             write "\tRewriteRule\t\"";
              write from;
-             write "\t";
+             write "\"\t\"";
              write to;
+             write "\"";
              case flags of
                  [] => ()
                | flag::rest => (write " [";
@@ -628,10 +672,11 @@ val () = Env.action_three "rewriteCond"
         ("test", Env.string, "pattern", Env.string, "flags", Env.list cond_flag)
         (fn (from, to, flags) =>
             (checkRewrite ();
-             write "\tRewriteCond\t";
+             write "\tRewriteCond\t\"";
              write from;
-             write "\t";
+             write "\"\t\"";
              write to;
+             write "\"";
              case flags of
                  [] => ()
                | flag::rest => (write " [";
@@ -645,9 +690,9 @@ val () = Env.action_one "rewriteBase"
         ("prefix", Env.string)
         (fn prefix =>
             (checkRewrite ();
-             write "\tRewriteBase\t";
+             write "\tRewriteBase\t\"";
              write prefix;
-             write "\n"))
+             write "\"\n"))
 
 val () = Env.action_one "rewriteLogLevel"
         ("level", Env.int)
@@ -913,6 +958,17 @@ val () = Env.action_two "addDescription"
                       app (fn pat => (write " "; write pat)) pats;
                       write "\n"))
 
+val () = Env.action_two "addIcon"
+        ("icon", Env.string, "patterns", Env.list Env.string)
+        (fn (icon, pats) =>
+            case pats of
+                [] => ()
+              | _ => (write "\tAddIcon \"";
+                      write icon;
+                      write "\"";
+                      app (fn pat => (write " "; write pat)) pats;
+                      write "\n"))
+
 val () = Env.action_one "indexOptions"
         ("options", Env.list autoindex_option)
         (fn opts =>
@@ -926,6 +982,15 @@ val () = Env.action_one "indexOptions"
                                               (write "="; write arg)) arg)) opts;
                       write "\n"))
 
+val () = Env.action_one "indexIgnore"
+        ("patterns", Env.list Env.string)
+        (fn pats =>
+            case pats of
+                [] => ()
+              | _ => (write "\tIndexIgnore";
+                      app (fn pat => (write " "; write pat)) pats;
+                      write "\n"))
+
 val () = Env.action_one "set_indexOptions"
         ("options", Env.list autoindex_option)
         (fn opts =>
@@ -976,7 +1041,35 @@ val () = Env.action_one "diskCache"
         (fn path => (write "\tCacheEnable disk \"";
                      write path;
                      write "\"\n"))
-        
+
+val () = Env.action_one "phpVersion"
+        ("version", php_version)
+        (fn version => (write "\tAddHandler x-httpd-php";
+                        write (Int.toString version);
+                        write " .php .phtml\n"))
+
+val () = Env.action_two "addType"
+        ("mime type", Env.string, "extension", Env.string)
+        (fn (mt, ext) => (write "\tAddType ";
+                          write mt;
+                          write " ";
+                          write ext;
+                          write "\n"))
+
+val filter = fn (EVar "includes", _) => SOME "INCLUDES"
+             | (EVar "deflate", _) => SOME "DEFLATE"
+             | _ => NONE
+
+val () = Env.action_two "addOutputFilter"
+        ("filters", Env.list filter, "extensions", Env.list Env.string)
+        (fn (f :: fs, exts as (_ :: _)) =>
+            (write "\tAddOutputFilter ";
+             write f;
+             app (fn f => (write ";"; write f)) fs;
+             app (fn ext => (write " "; write ext)) exts;
+             write "\n")
+          | _ => ())
+
 val () = Domain.registerResetLocal (fn () =>
                                       ignore (OS.Process.system (Config.rm ^ " -rf /var/domtool/vhosts/*")))
 
@@ -986,4 +1079,27 @@ val () = Domain.registerDescriber (Domain.considerAll
                                    Domain.Extension {extension = "vhost_ssl",
                                                      heading = fn host => "SSL web vhost " ^ host ^ ":"}])
 
+val () = Env.action_none "testNoHtaccess"
+        (fn path => write "\tAllowOverride None\n")
+
+fun writeWaklogUserFile () =
+    let
+       val users = Acl.users ()
+       val outf = TextIO.openOut Config.Apache.waklogUserFile
+    in
+       app (fn user => if String.isSuffix "_admin" user then
+                           ()
+                       else
+                           (TextIO.output (outf, "<Location /~");
+                            TextIO.output (outf, user);
+                            TextIO.output (outf, ">\n\tWaklogEnabled on\n\tWaklogLocationPrincipal ");
+                            TextIO.output (outf, user);
+                            TextIO.output (outf, "/daemon@HCOOP.NET /etc/keytabs/user.daemon/");
+                            TextIO.output (outf, user);
+                            TextIO.output (outf, "\n</Location>\n\n"))) users;
+       TextIO.closeOut outf
+    end
+
+val () = Domain.registerOnUsersChange writeWaklogUserFile
+
 end