X-Git-Url: https://git.hcoop.net/hcoop/domtool2.git/blobdiff_plain/38971ee6cddd6f7a18b9dcfb050c8c5688f04bdf..7ad80c2038b827f5f47a2768b790967cc9e12b7d:/src/plugins/apache.sml diff --git a/src/plugins/apache.sml b/src/plugins/apache.sml index e2f70d3..d4f7fc8 100644 --- a/src/plugins/apache.sml +++ b/src/plugins/apache.sml @@ -1,5 +1,6 @@ (* HCoop Domtool (http://hcoop.sourceforge.net/) - * Copyright (c) 2006-2007, Adam Chlipala + * Copyright (c) 2006-2009, Adam Chlipala + * Copyright (c) 2013 Clinton Ebadi * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -68,18 +69,22 @@ 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 => + "http" :: host :: 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 () + if List.exists (fn h' => host = h') (map (fn h => String.concat ["//", h]) Config.Apache.proxyHosts) + then + 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 () + else + default () end | _ => default () end) @@ -113,10 +118,18 @@ fun validCert s = Acl.query {user = Domain.getUser (), class = "cert", value = s} +fun validCaCert s = Acl.query {user = Domain.getUser (), + class = "cacert", + value = s} + val _ = Env.type_one "ssl_cert_path" Env.string validCert +val _ = Env.type_one "ssl_cacert_path" + Env.string + validCaCert + fun ssl e = case e of (EVar "no_ssl", _) => SOME NONE | (EApp ((EVar "use_cert", _), s), _) => Option.map SOME (Env.string s) @@ -131,32 +144,9 @@ val _ = Env.type_one "file_extension" Env.string validExtension -val defaults = [("WebPlaces", - (TList (TBase "web_place", dl), dl), - (fn () => (EList (map webPlaceDefault Config.Apache.webNodes_default), dl))), - ("SSL", - (TBase "ssl", dl), - (fn () => (EVar "no_ssl", dl))), - ("User", - (TBase "your_user", dl), - (fn () => (EString (Domain.getUser ()), dl))), - ("Group", - (TBase "your_group", dl), - (fn () => (EString "nogroup", dl))), - ("DocumentRoot", - (TBase "your_path", dl), - (fn () => (EString (Domain.homedir () ^ "/" ^ Config.Apache.public_html), dl))), - ("ServerAdmin", - (TBase "email", dl), - (fn () => (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl))), - ("SuExec", - (TBase "suexec_flag", dl), - (fn () => (EVar "true", dl))), - ("PhpVersion", - (TBase "php_version", dl), - (fn () => (EVar "php4", dl)))] - -val () = app Defaults.registerDefault defaults +val _ = Env.registerFunction ("defaultServerAdmin", + fn [] => SOME (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl) + | _ => NONE) val redirect_code = fn (EVar "temp", _) => SOME "temp" | (EVar "permanent", _) => SOME "permanent" @@ -202,6 +192,7 @@ val apache_option = fn (EVar "execCGI", _) => SOME "ExecCGI" | (EVar "includesNOEXEC", _) => SOME "IncludesNOEXEC" | (EVar "indexes", _) => SOME "Indexes" | (EVar "followSymLinks", _) => SOME "FollowSymLinks" + | (EVar "multiViews", _) => SOME "MultiViews" | _ => NONE val autoindex_width = fn (EVar "autofit", _) => SOME "*" @@ -241,12 +232,27 @@ val autoindex_option = fn (EApp ((EVar "descriptionWidth", _), w), _) => | _ => NONE +val interval_base = fn (EVar "access", _) => SOME "access" + | (EVar "modification", _) => SOME "modification" + | _ => NONE + +val interval = fn (EVar "years", _) => SOME "years" + | (EVar "months", _) => SOME "months" + | (EVar "weeks", _) => SOME "weeks" + | (EVar "days", _) => SOME "days" + | (EVar "hours", _) => SOME "hours" + | (EVar "minutes", _) => SOME "minutes" + | (EVar "seconds", _) => SOME "seconds" + | _ => NONE + 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 @@ -339,18 +345,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 @@ -378,15 +386,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 @@ -403,8 +414,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 ())) @@ -414,6 +426,8 @@ fun write s = app (fn (_, file) => TextIO.output (file, s)) (!vhostFiles) val rewriteEnabled = ref false val localRewriteEnabled = ref false +val expiresEnabled = ref false +val localExpiresEnabled = ref false val currentVhost = ref "" val currentVhostId = ref "" val sslEnabled = ref false @@ -449,8 +463,7 @@ fun vhostPost () = (!post (); write "\n"; app (TextIO.closeOut o #2) (!vhostFiles)) -val php_version = fn (EVar "php4", _) => SOME 4 - | (EVar "php5", _) => SOME 5 +val php_version = fn (EVar "php5", _) => SOME 5 | _ => NONE fun vhostBody (env, makeFullHost) = @@ -475,6 +488,8 @@ fun vhostBody (env, makeFullHost) = rewriteEnabled := false; localRewriteEnabled := false; + expiresEnabled := false; + localExpiresEnabled := false; vhostFiles := map (fn (node, ip) => let val file = Domain.domainFile {node = node, @@ -511,6 +526,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)) @@ -573,7 +592,8 @@ val () = Env.container_one "location" inLocal := true), fn () => (write "\t\n"; inLocal := false; - localRewriteEnabled := false)) + localRewriteEnabled := false; + localExpiresEnabled := false)) val () = Env.container_one "directory" ("directory", Env.string) @@ -584,7 +604,18 @@ val () = Env.container_one "directory" inLocal := true), fn () => (write "\t\n"; inLocal := false; - localRewriteEnabled := false)) + localRewriteEnabled := false; + localExpiresEnabled := false)) + +val () = Env.container_one "filesMatch" + ("regexp", Env.string) + (fn prefix => + (write "\t\n"), + fn () => (write "\t\n"; + localRewriteEnabled := false; + localExpiresEnabled := false)) fun checkRewrite () = if !inLocal then @@ -599,6 +630,19 @@ fun checkRewrite () = (write "\tRewriteEngine on\n"; rewriteEnabled := true) +fun checkExpires () = + if !inLocal then + if !localExpiresEnabled then + () + else + (write "\tExpiresActive on\n"; + localExpiresEnabled := true) + else if !expiresEnabled then + () + else + (write "\tExpiresActive on\n"; + expiresEnabled := true) + val () = Env.action_three "localProxyRewrite" ("from", Env.string, "to", Env.string, "port", Env.int) (fn (from, to, port) => @@ -611,6 +655,24 @@ val () = Env.action_three "localProxyRewrite" write to; write " [P]\n")) +val () = Env.action_four "expiresByType" + ("mime", Env.string, "base", interval_base, "num", Env.int, "inter", interval) + (fn (mime, base, num, inter) => + (checkExpires (); + write "\tExpiresByType\t\""; + write mime; + write "\"\t\""; + write base; + write " plus "; + if num < 0 then + (write "-"; + write (Int.toString (~num))) + else + write (Int.toString num); + write " "; + write inter; + write "\"\n")) + val () = Env.action_two "proxyPass" ("from", Env.string, "to", Env.string) (fn (from, to) => @@ -831,6 +893,13 @@ val () = Env.action_one "authUserFile" write name; write "\n")) +val () = Env.action_one "authGroupFile" + ("file", Env.string) + (fn name => + (write "\tAuthGroupFile "; + write name; + write "\n")) + val () = Env.action_none "requireValidUser" (fn () => write "\tRequire valid-user\n") @@ -1049,8 +1118,18 @@ val () = Env.action_two "addOutputFilter" write "\n") | _ => ()) +val () = Env.action_one "sslCertificateChainFile" + ("ssl_cacert_path", Env.string) + (fn cacert => + if !sslEnabled then + (write "\tSSLCertificateChainFile \""; + write cacert; + write "\"\n") + else + print "WARNING: Skipped sslCertificateChainFile because this isn't an SSL vhost.\n") + val () = Domain.registerResetLocal (fn () => - ignore (OS.Process.system (Config.rm ^ " -rf /var/domtool/vhosts/*"))) + ignore (OS.Process.system (Config.rm ^ " -rf " ^ Config.Apache.confDir ^ "/*"))) val () = Domain.registerDescriber (Domain.considerAll [Domain.Extension {extension = "vhost", @@ -1061,4 +1140,24 @@ val () = Domain.registerDescriber (Domain.considerAll 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, "\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\n\n"))) users; + TextIO.closeOut outf + end + +val () = Domain.registerOnUsersChange writeWaklogUserFile + end