Proper nested indentation
[hcoop/zz_old/domtool2-proto.git] / src / plugins / apache.sml
CommitLineData
d68ab27c 1(* HCoop Domtool (http://hcoop.sourceforge.net/)
3eb5fd92 2 * Copyright (c) 2006-2007, Adam Chlipala
d68ab27c 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(* Apache HTTPD handling *)
20
21structure Apache :> APACHE = struct
22
23open Ast
24
4cb2e7e7 25val _ = Env.type_one "web_node"
26 Env.string
27 (fn node =>
c829302a 28 List.exists (fn (x, _) => x = node) Config.Apache.webNodes_all
1bb29dea 29 orelse (Domain.hasPriv "www"
c829302a 30 andalso List.exists (fn (x, _) => x = node) Config.Apache.webNodes_admin))
4cb2e7e7 31
19bdfddd 32val _ = Env.registerFunction ("web_node_to_node",
33 fn [e] => SOME e
34 | _ => NONE)
35
697d1a52 36val _ = Env.type_one "proxy_port"
37 Env.int
169731e9 38 (fn n => n > 1024)
39
40val _ = Env.type_one "proxy_target"
41 Env.string
42 (fn s =>
43 let
44 fun default () = List.exists (fn s' => s = s') Config.Apache.proxyTargets
45 in
46 case String.fields (fn ch => ch = #":") s of
47 ["http", "//localhost", rest] =>
48 (case String.fields (fn ch => ch = #"/") rest of
49 port :: _ =>
50 (case Int.fromString port of
51 NONE => default ()
52 | SOME n => n > 1024 orelse default ())
53 | _ => default ())
54 | _ => default ()
55 end)
697d1a52 56
57val _ = Env.type_one "rewrite_arg"
58 Env.string
59 (CharVector.all Char.isAlphaNum)
60
25c7a818 61val _ = Env.type_one "suexec_flag"
62 Env.bool
63 (fn b => b orelse Domain.hasPriv "www")
64
ff2a424a 65fun validLocation s =
66 size s > 0 andalso size s < 1000 andalso CharVector.all
67 (fn ch => Char.isAlphaNum ch
68 orelse ch = #"-"
69 orelse ch = #"_"
70 orelse ch = #"."
71 orelse ch = #"/") s
72
73val _ = Env.type_one "location"
74 Env.string
75 validLocation
76
d858369d 77fun validCert s = Acl.query {user = Domain.getUser (),
78 class = "cert",
79 value = s}
80
81val _ = Env.type_one "ssl_cert_path"
82 Env.string
83 validCert
84
85fun ssl e = case e of
86 (EVar "no_ssl", _) => SOME NONE
87 | (EApp ((EVar "use_cert", _), s), _) => Option.map SOME (Env.string s)
88 | _ => NONE
89
d68ab27c 90val dl = ErrorMsg.dummyLoc
91
53d222a3 92val _ = Defaults.registerDefault ("WebNodes",
4cb2e7e7 93 (TList (TBase "web_node", dl), dl),
94 (fn () => (EList (map (fn s => (EString s, dl)) Config.Apache.webNodes_default), dl)))
d68ab27c 95
53d222a3 96val _ = Defaults.registerDefault ("SSL",
5d5309ef 97 (TBase "ssl", dl),
3d8d63c2 98 (fn () => (EVar "no_ssl", dl)))
d68ab27c 99
53d222a3 100val _ = Defaults.registerDefault ("User",
101 (TBase "your_user", dl),
102 (fn () => (EString (Domain.getUser ()), dl)))
d68ab27c 103
53d222a3 104val _ = Defaults.registerDefault ("Group",
105 (TBase "your_group", dl),
fdd6551b 106 (fn () => (EString "nogroup", dl)))
d68ab27c 107
53d222a3 108val _ = Defaults.registerDefault ("DocumentRoot",
109 (TBase "your_path", dl),
73e665f1 110 (fn () => (EString (Domain.homedir () ^ "/" ^ Config.Apache.public_html), dl)))
d68ab27c 111
53d222a3 112val _ = Defaults.registerDefault ("ServerAdmin",
113 (TBase "email", dl),
114 (fn () => (EString (Domain.getUser () ^ "@" ^ Config.defaultDomain), dl)))
d68ab27c 115
25c7a818 116val _ = Defaults.registerDefault ("SuExec",
117 (TBase "suexec_flag", dl),
d858369d 118 (fn () => (EVar "true", dl)))
697d1a52 119
120val redirect_code = fn (EVar "temp", _) => SOME "temp"
121 | (EVar "permanent", _) => SOME "permanent"
122 | (EVar "seeother", _) => SOME "seeother"
123 | (EVar "redir300", _) => SOME "300"
124 | (EVar "redir301", _) => SOME "301"
125 | (EVar "redir302", _) => SOME "302"
126 | (EVar "redir303", _) => SOME "303"
127 | (EVar "redir304", _) => SOME "304"
128 | (EVar "redir305", _) => SOME "305"
129 | (EVar "redir307", _) => SOME "307"
130 | _ => NONE
131
132val flag = fn (EVar "redirect", _) => SOME "R"
133 | (EVar "forbidden", _) => SOME "F"
134 | (EVar "gone", _) => SOME "G"
135 | (EVar "last", _) => SOME "L"
136 | (EVar "chain", _) => SOME "C"
137 | (EVar "nosubreq", _) => SOME "NS"
138 | (EVar "nocase", _) => SOME "NC"
139 | (EVar "qsappend", _) => SOME "QSA"
140 | (EVar "noescape", _) => SOME "NE"
141 | (EVar "passthrough", _) => SOME "PT"
142 | (EApp ((EVar "mimeType", _), e), _) =>
143 Option.map (fn s => "T=" ^ s) (Env.string e)
144 | (EApp ((EVar "redirectWith", _), e), _) =>
145 Option.map (fn s => "R=" ^ s) (redirect_code e)
146 | (EApp ((EVar "skip", _), e), _) =>
147 Option.map (fn n => "S=" ^ Int.toString n) (Env.int e)
148 | (EApp ((EApp ((EVar "env", _), e1), _), e2), _) =>
149 (case Env.string e1 of
150 NONE => NONE
151 | SOME s1 => Option.map (fn s2 => "E=" ^ s1 ^ ":" ^ s2)
152 (Env.string e2))
153
154 | _ => NONE
155
169731e9 156val cond_flag = fn (EVar "cond_nocase", _) => SOME "NC"
157 | (EVar "ornext", _) => SOME "OR"
158 | _ => NONE
159
ff8db773 160val apache_option = fn (EVar "execCGI", _) => SOME "ExecCGI"
161 | (EVar "includesNOEXEC", _) => SOME "IncludesNOEXEC"
162 | (EVar "indexes", _) => SOME "Indexes"
163 | _ => NONE
164
db9c7cb7 165val autoindex_width = fn (EVar "autofit", _) => SOME "*"
166 | (EApp ((EVar "characters", _), n), _) =>
167 Option.map Int.toString (Env.int n)
168 | _ => NONE
169
170val autoindex_option = fn (EApp ((EVar "descriptionWidth", _), w), _) =>
171 Option.map (fn w => ("DescriptionWidth", SOME w))
172 (autoindex_width w)
173 | (EVar "fancyIndexing", _) => SOME ("FancyIndexing", NONE)
174 | (EVar "foldersFirst", _) => SOME ("FoldersFirst", NONE)
175 | (EVar "htmlTable", _) => SOME ("HTMLTable", NONE)
176 | (EVar "iconsAreLinks", _) => SOME ("IconsAreLinks", NONE)
177 | (EApp ((EVar "iconHeight", _), n), _) =>
178 Option.map (fn w => ("IconHeight", SOME (Int.toString w)))
179 (Env.int n)
180 | (EApp ((EVar "iconWidth", _), n), _) =>
181 Option.map (fn w => ("IconWidth", SOME (Int.toString w)))
182 (Env.int n)
183 | (EVar "ignoreCase", _) => SOME ("IgnoreCase", NONE)
184 | (EVar "ignoreClient", _) => SOME ("IgnoreClient", NONE)
185 | (EApp ((EVar "nameWidth", _), w), _) =>
186 Option.map (fn w => ("NameWidth", SOME w))
187 (autoindex_width w)
188 | (EVar "scanHtmlTitles", _) => SOME ("ScanHTMLTitles", NONE)
189 | (EVar "suppressColumnSorting", _) => SOME ("SuppressColumnSorting", NONE)
190 | (EVar "suppressDescription", _) => SOME ("SuppressDescription", NONE)
191 | (EVar "suppressHtmlPreamble", _) => SOME ("SuppressHTMLPreamble", NONE)
192 | (EVar "suppressIcon", _) => SOME ("SuppressIcon", NONE)
193 | (EVar "suppressLastModified", _) => SOME ("SuppressLastModified", NONE)
194 | (EVar "suppressRules", _) => SOME ("SuppressRules", NONE)
195 | (EVar "suppressSize", _) => SOME ("SuppressSize", NONE)
196 | (EVar "trackModified", _) => SOME ("TrackModified", NONE)
197 | (EVar "versionSort", _) => SOME ("VersionSort", NONE)
198 | (EVar "xhtml", _) => SOME ("XHTML", NONE)
199
200 | _ => NONE
697d1a52 201
d68ab27c 202val vhostsChanged = ref false
8bd6a399 203val logDeleted = ref false
d68ab27c 204
205val () = Slave.registerPreHandler
8bd6a399 206 (fn () => (vhostsChanged := false;
207 logDeleted := false))
d68ab27c 208
acb4199f 209fun findVhostUser fname =
210 let
211 val inf = TextIO.openIn fname
212
213 fun loop () =
214 case TextIO.inputLine inf of
215 NONE => NONE
216 | SOME line =>
25c7a818 217 if String.isPrefix "# Owner: " line then
218 case String.tokens Char.isSpace line of
219 [_, _, user] => SOME user
220 | _ => NONE
221 else
222 loop ()
acb4199f 223 in
224 loop ()
225 before TextIO.closeIn inf
2ec5502f 226 end handle _ => NONE
acb4199f 227
c829302a 228val webNodes_full = Config.Apache.webNodes_all @ Config.Apache.webNodes_admin
229
230fun isVersion1 node =
3410e495 231 List.exists (fn (n, {version = ConfigTypes.APACHE_1_3, ...}) => n = node
232 | _ => false) webNodes_full
c829302a 233
234fun imVersion1 () = isVersion1 (Slave.hostname ())
235
3410e495 236fun isWaklog node =
237 List.exists (fn (n, {auth = ConfigTypes.MOD_WAKLOG, ...}) => n = node
238 | _ => false) webNodes_full
239
c829302a 240fun down () = if imVersion1 () then Config.Apache.down1 else Config.Apache.down
241fun undown () = if imVersion1 () then Config.Apache.undown1 else Config.Apache.undown
242fun reload () = if imVersion1 () then Config.Apache.reload1 else Config.Apache.reload
243
ef021e72 244fun logDir {user, node, vhostId} =
dc99a551 245 String.concat [Config.Apache.logDirOf (isVersion1 node) user,
244a93c6 246 "/",
ef021e72 247 node,
248 "/",
249 vhostId]
250
d68ab27c 251val () = Slave.registerFileHandler (fn fs =>
037af74e 252 let
253 val spl = OS.Path.splitDirFile (#file fs)
254 in
255 if String.isSuffix ".vhost" (#file spl)
2ec5502f 256 orelse String.isSuffix ".vhost_ssl" (#file spl) then let
257 val realVhostFile = OS.Path.joinDirFile
258 {dir = Config.Apache.confDir,
259 file = #file spl}
260
261 val user = findVhostUser (#file fs)
262 val oldUser = findVhostUser realVhostFile
263 in
264 if (oldUser = NONE andalso #action fs <> Slave.Add)
265 orelse (user = NONE andalso #action fs <> Slave.Delete) then
266 print ("Can't find user in " ^ #file fs ^ " or " ^ realVhostFile ^ "! Taking no action.\n")
267 else
268 let
3cac59ff 269 val vhostId = if OS.Path.ext (#file spl) = SOME "vhost_ssl" then
ef021e72 270 OS.Path.base (#file spl) ^ ".ssl"
271 else
272 OS.Path.base (#file spl)
273
2ec5502f 274 fun realLogDir user =
ef021e72 275 logDir {user = valOf user,
276 node = Slave.hostname (),
277 vhostId = vhostId}
2ec5502f 278 in
279 vhostsChanged := true;
280 case #action fs of
281 Slave.Delete =>
282 (if !logDeleted then
283 ()
284 else
c829302a 285 (ignore (OS.Process.system (down ()));
2ec5502f 286 logDeleted := true);
287 ignore (OS.Process.system (Config.rm
288 ^ " -rf "
289 ^ realVhostFile));
290 ignore (OS.Process.system (Config.rm
291 ^ " -rf "
292 ^ realLogDir oldUser)))
293 | Slave.Add =>
294 let
295 val rld = realLogDir user
296 in
297 ignore (OS.Process.system (Config.cp
298 ^ " "
299 ^ #file fs
300 ^ " "
301 ^ realVhostFile));
302 if Posix.FileSys.access (rld, []) then
303 ()
304 else
244a93c6 305 Slave.mkDirAll rld
2ec5502f 306 end
307
308 | _ =>
309 (ignore (OS.Process.system (Config.cp
310 ^ " "
311 ^ #file fs
312 ^ " "
313 ^ realVhostFile));
314 if user <> oldUser then
315 let
316 val old = realLogDir oldUser
317 val rld = realLogDir user
318 in
319 if !logDeleted then
320 ()
321 else
c829302a 322 (ignore (OS.Process.system (down ()));
2ec5502f 323 logDeleted := true);
324 ignore (OS.Process.system (Config.rm
325 ^ " -rf "
326 ^ realLogDir oldUser));
327 if Posix.FileSys.access (rld, []) then
328 ()
329 else
244a93c6 330 Slave.mkDirAll rld
2ec5502f 331 end
332 else
333 ())
334 end
335 end
037af74e 336 else
337 ()
338 end)
d68ab27c 339
340val () = Slave.registerPostHandler
341 (fn () =>
342 (if !vhostsChanged then
c829302a 343 Slave.shellF ([if !logDeleted then undown () else reload ()],
d68ab27c 344 fn cl => "Error reloading Apache with " ^ cl)
345 else
346 ()))
347
037af74e 348val vhostFiles : (string * TextIO.outstream) list ref = ref []
349fun write' s = app (fn (node, file) => TextIO.output (file, s node)) (!vhostFiles)
350fun write s = app (fn (_, file) => TextIO.output (file, s)) (!vhostFiles)
d68ab27c 351
697d1a52 352val rewriteEnabled = ref false
19bdfddd 353val localRewriteEnabled = ref false
3d3acca9 354val currentVhost = ref ""
355val currentVhostId = ref ""
3eb5fd92 356val sslEnabled = ref false
697d1a52 357
037af74e 358val pre = ref (fn _ : {user : string, nodes : string list, id : string, hostname : string} => ())
e1cb845e 359fun registerPre f =
360 let
361 val old = !pre
362 in
363 pre := (fn x => (old x; f x))
364 end
365
366val post = ref (fn () => ())
367fun registerPost f =
368 let
369 val old = !post
370 in
371 post := (fn () => (old (); f ()))
372 end
373
374val aliaser = ref (fn _ : string => ())
375fun registerAliaser f =
376 let
377 val old = !aliaser
378 in
379 aliaser := (fn x => (old x; f x))
380 end
381
d68ab27c 382val () = Env.containerV_one "vhost"
383 ("host", Env.string)
384 (fn (env, host) =>
385 let
386 val nodes = Env.env (Env.list Env.string) (env, "WebNodes")
387
d858369d 388 val ssl = Env.env ssl (env, "SSL")
d68ab27c 389 val user = Env.env Env.string (env, "User")
390 val group = Env.env Env.string (env, "Group")
391 val docroot = Env.env Env.string (env, "DocumentRoot")
392 val sadmin = Env.env Env.string (env, "ServerAdmin")
d858369d 393 val suexec = Env.env Env.bool (env, "SuExec")
d68ab27c 394
395 val fullHost = host ^ "." ^ Domain.currentDomain ()
d858369d 396 val vhostId = fullHost ^ (if Option.isSome ssl then ".ssl" else "")
397 val confFile = fullHost ^ (if Option.isSome ssl then ".vhost_ssl" else ".vhost")
d68ab27c 398 in
3d3acca9 399 currentVhost := fullHost;
400 currentVhostId := vhostId;
3eb5fd92 401 sslEnabled := Option.isSome ssl;
3d3acca9 402
697d1a52 403 rewriteEnabled := false;
19bdfddd 404 localRewriteEnabled := false;
d68ab27c 405 vhostFiles := map (fn node =>
406 let
407 val file = Domain.domainFile {node = node,
408 name = confFile}
dc99a551 409
410 val ld = logDir {user = user, node = node, vhostId = vhostId}
d68ab27c 411 in
25c7a818 412 TextIO.output (file, "# Owner: ");
413 TextIO.output (file, user);
414 TextIO.output (file, "\n<VirtualHost ");
d68ab27c 415 TextIO.output (file, Domain.nodeIp node);
416 TextIO.output (file, ":");
d858369d 417 TextIO.output (file, case ssl of
418 SOME _ => "443"
419 | NONE => "80");
d68ab27c 420 TextIO.output (file, ">\n");
037af74e 421 TextIO.output (file, "\tErrorLog ");
dc99a551 422 TextIO.output (file, ld);
037af74e 423 TextIO.output (file, "/error.log\n\tCustomLog ");
dc99a551 424 TextIO.output (file, ld);
037af74e 425 TextIO.output (file, "/access.log combined\n");
c829302a 426 TextIO.output (file, "\tServerName ");
427 TextIO.output (file, fullHost);
d3c9f0c6 428 app
429 (fn dom => (TextIO.output (file, "\n\tServerAlias ");
430 TextIO.output (file, host);
431 TextIO.output (file, ".");
432 TextIO.output (file, dom)))
433 (Domain.currentAliasDomains ());
640d7ace 434
c829302a 435 if suexec then
436 if isVersion1 node then
437 (TextIO.output (file, "\n\tUser ");
438 TextIO.output (file, user);
439 TextIO.output (file, "\n\tGroup ");
440 TextIO.output (file, group))
441 else
442 (TextIO.output (file, "\n\tSuexecUserGroup ");
443 TextIO.output (file, user);
444 TextIO.output (file, " ");
445 TextIO.output (file, group))
446 else
447 ();
640d7ace 448
3410e495 449 if isWaklog node then
d29832ae 450 (TextIO.output (file, "\n\tWaklogEnabled on\n\tWaklogLocationPrincipal ");
3410e495 451 TextIO.output (file, user);
c56e702d 452 TextIO.output (file, "/daemon@HCOOP.NET /etc/keytabs/user.daemon/");
3410e495 453 TextIO.output (file, user))
454 else
455 ();
640d7ace 456
8c06608a 457 TextIO.output (file, "\n\tDAVLockDB /var/lock/apache2/dav/");
640d7ace 458 TextIO.output (file, user);
459 TextIO.output (file, "/DAVLock");
460
dc99a551 461 (ld, file)
d68ab27c 462 end)
463 nodes;
d68ab27c 464 write "\n\tDocumentRoot ";
465 write docroot;
466 write "\n\tServerAdmin ";
467 write sadmin;
d858369d 468 case ssl of
469 SOME cert =>
470 (write "\n\tSSLEngine on\n\tSSLCertificateFile ";
471 write cert)
472 | NONE => ();
037af74e 473 write "\n";
8a2bb410 474 !pre {user = user, nodes = nodes, id = vhostId, hostname = fullHost};
475 app (fn dom => !aliaser (host ^ "." ^ dom)) (Domain.currentAliasDomains ())
d68ab27c 476 end,
e1cb845e 477 fn () => (!post ();
478 write "</VirtualHost>\n";
037af74e 479 app (TextIO.closeOut o #2) (!vhostFiles)))
d68ab27c 480
19bdfddd 481val inLocal = ref false
482
ff2a424a 483val () = Env.container_one "location"
484 ("prefix", Env.string)
485 (fn prefix =>
486 (write "\t<Location ";
487 write prefix;
19bdfddd 488 write ">\n";
489 inLocal := true),
490 fn () => (write "\t</Location>\n";
491 inLocal := false;
492 localRewriteEnabled := false))
ff2a424a 493
494val () = Env.container_one "directory"
495 ("directory", Env.string)
496 (fn directory =>
497 (write "\t<Directory ";
498 write directory;
19bdfddd 499 write ">\n";
500 inLocal := true),
501 fn () => (write "\t</Directory>\n";
502 inLocal := false;
503 localRewriteEnabled := false))
ff2a424a 504
697d1a52 505fun checkRewrite () =
19bdfddd 506 if !inLocal then
507 if !rewriteEnabled orelse !localRewriteEnabled then
508 ()
509 else
510 (write "\tRewriteEngine on\n";
511 localRewriteEnabled := true)
512 else if !rewriteEnabled then
697d1a52 513 ()
514 else
515 (write "\tRewriteEngine on\n";
516 rewriteEnabled := true)
517
518val () = Env.action_three "localProxyRewrite"
519 ("from", Env.string, "to", Env.string, "port", Env.int)
520 (fn (from, to, port) =>
521 (checkRewrite ();
522 write "\tRewriteRule\t";
523 write from;
524 write "\thttp://localhost:";
525 write (Int.toString port);
526 write "/";
527 write to;
528 write " [P]\n"))
529
169731e9 530val () = Env.action_two "proxyPass"
531 ("from", Env.string, "to", Env.string)
532 (fn (from, to) =>
533 (write "\tProxyPass\t";
534 write from;
535 write "\t";
536 write to;
537 write "\n"))
538
539val () = Env.action_two "proxyPassReverse"
540 ("from", Env.string, "to", Env.string)
541 (fn (from, to) =>
542 (write "\tProxyPassReverse\t";
543 write from;
544 write "\t";
545 write to;
546 write "\n"))
697d1a52 547
548val () = Env.action_three "rewriteRule"
549 ("from", Env.string, "to", Env.string, "flags", Env.list flag)
550 (fn (from, to, flags) =>
551 (checkRewrite ();
552 write "\tRewriteRule\t";
553 write from;
554 write "\t";
555 write to;
556 case flags of
557 [] => ()
558 | flag::rest => (write " [";
559 write flag;
560 app (fn flag => (write ",";
561 write flag)) rest;
562 write "]");
563 write "\n"))
564
169731e9 565val () = Env.action_three "rewriteCond"
566 ("test", Env.string, "pattern", Env.string, "flags", Env.list cond_flag)
567 (fn (from, to, flags) =>
568 (checkRewrite ();
569 write "\tRewriteCond\t";
570 write from;
571 write "\t";
572 write to;
573 case flags of
574 [] => ()
575 | flag::rest => (write " [";
576 write flag;
577 app (fn flag => (write ",";
578 write flag)) rest;
579 write "]");
580 write "\n"))
581
e28c342c 582val () = Env.action_one "rewriteBase"
583 ("prefix", Env.string)
584 (fn prefix =>
585 (checkRewrite ();
586 write "\tRewriteBase\t";
587 write prefix;
588 write "\n"))
589
3d3acca9 590val () = Env.action_one "rewriteLogLevel"
591 ("level", Env.int)
592 (fn level =>
593 (checkRewrite ();
594 write "\tRewriteLog ";
037af74e 595 write' (fn x => x);
3d3acca9 596 write "/rewrite.log\n\tRewriteLogLevel ";
597 write (Int.toString level);
598 write "\n"))
599
0279185b 600val () = Env.action_two "alias"
601 ("from", Env.string, "to", Env.string)
602 (fn (from, to) =>
603 (write "\tAlias\t";
604 write from;
605 write " ";
606 write to;
607 write "\n"))
608
609val () = Env.action_two "scriptAlias"
610 ("from", Env.string, "to", Env.string)
611 (fn (from, to) =>
612 (write "\tScriptAlias\t";
613 write from;
614 write " ";
615 write to;
616 write "\n"))
617
618val () = Env.action_two "errorDocument"
619 ("code", Env.string, "handler", Env.string)
620 (fn (code, handler) =>
621 (write "\tErrorDocument\t";
622 write code;
623 write " ";
624 write handler;
625 write "\n"))
626
ff8db773 627val () = Env.action_one "options"
628 ("options", Env.list apache_option)
629 (fn opts =>
630 case opts of
631 [] => ()
632 | _ => (write "\tOptions";
633 app (fn opt => (write " "; write opt)) opts;
634 write "\n"))
635
636val () = Env.action_one "set_options"
637 ("options", Env.list apache_option)
638 (fn opts =>
639 case opts of
640 [] => ()
641 | _ => (write "\tOptions";
642 app (fn opt => (write " +"; write opt)) opts;
643 write "\n"))
644
645val () = Env.action_one "unset_options"
646 ("options", Env.list apache_option)
647 (fn opts =>
648 case opts of
649 [] => ()
650 | _ => (write "\tOptions";
651 app (fn opt => (write " -"; write opt)) opts;
652 write "\n"))
0279185b 653
69d98465 654val () = Env.action_one "directoryIndex"
655 ("filenames", Env.list Env.string)
656 (fn opts =>
657 (write "\tDirectoryIndex";
658 app (fn opt => (write " "; write opt)) opts;
659 write "\n"))
660
d3c9f0c6 661val () = Env.action_one "serverAliasHost"
69d98465 662 ("host", Env.string)
663 (fn host =>
664 (write "\tServerAlias ";
665 write host;
e1cb845e 666 write "\n";
667 !aliaser host))
69d98465 668
d3c9f0c6 669val () = Env.action_one "serverAlias"
670 ("host", Env.string)
671 (fn host =>
672 (app
673 (fn dom =>
674 let
675 val full = host ^ "." ^ dom
676 in
677 write "\tServerAlias ";
678 write full;
679 write "\n";
680 !aliaser full
681 end)
682 (Domain.currentDomains ())))
683
684val () = Env.action_none "serverAliasDefault"
685 (fn () =>
686 (app
687 (fn dom =>
688 (write "\tServerAlias ";
689 write dom;
690 write "\n";
691 !aliaser dom))
692 (Domain.currentDomains ())))
693
00e4345d 694val authType = fn (EVar "basic", _) => SOME "basic"
695 | (EVar "digest", _) => SOME "digest"
7fb3d705 696 | (EVar "kerberos", _) => SOME "kerberos"
00e4345d 697 | _ => NONE
698
3eb5fd92 699fun allowAuthType "kerberos" = !sslEnabled
700 | allowAuthType _ = true
701
00e4345d 702val () = Env.action_one "authType"
703 ("type", authType)
704 (fn ty =>
3eb5fd92 705 if allowAuthType ty then
706 (write "\tAuthType ";
707 write ty;
708 write "\n";
709 case ty of
710 "kerberos" =>
711 write "\tKrbMethodNegotiate off\n\tKrbMethodK5Passwd on\n\tKrbVerifyKDC off\n\tKrbAuthRealms HCOOP.NET\n\tKrbSaveCredentials on\n"
712 | _ => ())
713 else
714 print "WARNING: Skipped Kerberos authType because this isn't an SSL vhost.\n")
00e4345d 715
716val () = Env.action_one "authName"
717 ("name", Env.string)
718 (fn name =>
719 (write "\tAuthName \"";
720 write name;
721 write "\"\n"))
722
723val () = Env.action_one "authUserFile"
724 ("file", Env.string)
725 (fn name =>
726 (write "\tAuthUserFile ";
727 write name;
728 write "\n"))
729
730val () = Env.action_none "requireValidUser"
731 (fn () => write "\tRequire valid-user\n")
732
733val () = Env.action_one "requireUser"
734 ("users", Env.list Env.string)
735 (fn names =>
736 case names of
737 [] => ()
738 | _ => (write "\tRequire user";
739 app (fn name => (write " "; write name)) names;
740 write "\n"))
741
742val () = Env.action_one "requireGroup"
743 ("groups", Env.list Env.string)
744 (fn names =>
745 case names of
746 [] => ()
747 | _ => (write "\tRequire group";
748 app (fn name => (write " "; write name)) names;
749 write "\n"))
750
751val () = Env.action_none "orderAllowDeny"
752 (fn () => write "\tOrder allow,deny\n")
753
754val () = Env.action_none "orderDenyAllow"
755 (fn () => write "\tOrder deny,allow\n")
756
757val () = Env.action_none "allowFromAll"
758 (fn () => write "\tAllow from all\n")
759
760val () = Env.action_one "allowFrom"
761 ("entries", Env.list Env.string)
762 (fn names =>
763 case names of
764 [] => ()
765 | _ => (write "\tAllow from";
766 app (fn name => (write " "; write name)) names;
767 write "\n"))
768
769val () = Env.action_none "denyFromAll"
770 (fn () => write "\tDeny from all\n")
771
772val () = Env.action_one "denyFrom"
773 ("entries", Env.list Env.string)
774 (fn names =>
775 case names of
776 [] => ()
777 | _ => (write "\tDeny from";
778 app (fn name => (write " "; write name)) names;
779 write "\n"))
780
781val () = Env.action_none "satisfyAll"
782 (fn () => write "\tSatisfy all\n")
783
784val () = Env.action_none "satisfyAny"
785 (fn () => write "\tSatisfy any\n")
786
4cc63b03 787val () = Env.action_one "forceType"
788 ("type", Env.string)
789 (fn ty => (write "\tForceType ";
790 write ty;
791 write "\n"))
792
793val () = Env.action_none "forceTypeOff"
794 (fn () => write "\tForceType None\n")
795
796val () = Env.action_two "action"
797 ("what", Env.string, "how", Env.string)
798 (fn (what, how) => (write "\tAction ";
799 write what;
800 write " ";
801 write how;
802 write "\n"))
803
804val () = Env.action_one "addDefaultCharset"
805 ("charset", Env.string)
806 (fn ty => (write "\tAddDefaultCharset ";
807 write ty;
808 write "\n"))
809
26716b02 810(*val () = Env.action_one "davSvn"
efffba2a 811 ("path", Env.string)
812 (fn path => (write "\tDAV svn\n\tSVNPath ";
813 write path;
814 write "\n"))
815
816val () = Env.action_one "authzSvnAccessFile"
817 ("path", Env.string)
818 (fn path => (write "\tAuthzSVNAccessFile ";
819 write path;
26716b02 820 write "\n"))*)
efffba2a 821
2aa13b91 822val () = Env.action_none "davFilesystem"
823 (fn path => write "\tDAV filesystem\n")
824
db9c7cb7 825val () = Env.action_two "addDescription"
826 ("description", Env.string, "patterns", Env.list Env.string)
827 (fn (desc, pats) =>
828 case pats of
829 [] => ()
830 | _ => (write "\tAddDescription \"";
831 write (String.toString desc);
832 write "\"";
833 app (fn pat => (write " "; write pat)) pats;
834 write "\n"))
835
836val () = Env.action_one "indexOptions"
837 ("options", Env.list autoindex_option)
838 (fn opts =>
839 case opts of
840 [] => ()
841 | _ => (write "\tIndexOptions";
842 app (fn (opt, arg) =>
843 (write " ";
844 write opt;
845 Option.app (fn arg =>
846 (write "="; write arg)) arg)) opts;
847 write "\n"))
848
849val () = Env.action_one "set_indexOptions"
850 ("options", Env.list autoindex_option)
851 (fn opts =>
852 case opts of
853 [] => ()
854 | _ => (write "\tIndexOptions";
855 app (fn (opt, arg) =>
856 (write " +";
857 write opt;
858 Option.app (fn arg =>
859 (write "="; write arg)) arg)) opts;
860 write "\n"))
861
862val () = Env.action_one "unset_indexOptions"
863 ("options", Env.list autoindex_option)
864 (fn opts =>
865 case opts of
866 [] => ()
867 | _ => (write "\tIndexOptions";
868 app (fn (opt, _) =>
869 (write " -";
870 write opt)) opts;
871 write "\n"))
872
873val () = Env.action_one "headerName"
874 ("name", Env.string)
875 (fn name => (write "\tHeaderName ";
876 write name;
877 write "\n"))
878
879val () = Env.action_one "readmeName"
880 ("name", Env.string)
881 (fn name => (write "\tReadmeName ";
882 write name;
883 write "\n"))
884
d71ae374 885val () = Env.action_two "setEnv"
886 ("key", Env.string, "value", Env.string)
887 (fn (key, value) => (write "\tSetEnv \"";
888 write key;
889 write "\" \"";
3a319372 890 write (String.translate (fn #"\"" => "\\\""
891 | ch => str ch) value);
d71ae374 892 write "\"\n"))
893
0ea0ecfa 894val () = Domain.registerResetLocal (fn () =>
895 ignore (OS.Process.system (Config.rm ^ " -rf /var/domtool/vhosts/*")))
896
d68ab27c 897end