Recent changes to this wiki:

ah, i think i found a workaround
diff --git a/doc/bugs/wiki_creation_impossible.mdwn b/doc/bugs/wiki_creation_impossible.mdwn
index dd158ee..e4d9ee3 100644
--- a/doc/bugs/wiki_creation_impossible.mdwn
+++ b/doc/bugs/wiki_creation_impossible.mdwn
@@ -7,3 +7,14 @@ git config --global user.name admin
 fatal: failed to stat '.': Permission denied
 error: git failed
 """]]
+
+> Ah - it turns out that you can't run this command from a private directory (like `/root`) as ikiwiki calls `git config --global user.name admin` without changing directory first. `git`, in turn, does a `stat(".")` for some obscure reason, and fails miserably:
+> 
+>     [pid   597] getcwd("/root", 4096)       = 6
+>     [pid   597] stat(".", 0x7fffdc602e60)   = -1 EACCES (Permission denied)
+>     [pid   597] write(2, "fatal: failed to stat '.': Permi"..., 45fatal: failed to stat '.': Permission denied
+>     ) = 45
+>
+> A simple workaround: `cd /tmp` before running the command.
+> 
+> So this should be fairly simple to fix: just change the directory first. It's is probably safe to `chdir($HOME)` anyways... --[[anarcat]]

diff --git a/doc/bugs/wiki_creation_impossible.mdwn b/doc/bugs/wiki_creation_impossible.mdwn
new file mode 100644
index 0000000..dd158ee
--- /dev/null
+++ b/doc/bugs/wiki_creation_impossible.mdwn
@@ -0,0 +1,9 @@
+I have successfully created a few wikis with this in the past (on 15-12-2011 to be exact), but now this seems impossible. All I get is this error:
+
+[[!format txt """
+root@marcos:~# env LANG=C ikisite  --verbose create rococo.anarcat.ath.cx --admin https://id.koumbit.net/anarcat
+useradd a-rococo --create-home --skel /dev/null
+git config --global user.name admin
+fatal: failed to stat '.': Permission denied
+error: git failed
+"""]]

add post form
diff --git a/doc/bugs.mdwn b/doc/bugs.mdwn
index b4048cf..a1620a6 100644
--- a/doc/bugs.mdwn
+++ b/doc/bugs.mdwn
@@ -1,4 +1,4 @@
 Open bugs (link fixed ones to [[done]]):
 
 [[!inline pages="bugs/* and !bugs/*/* and !link(bugs/done) and !bugs/done"
-archive=yes]]
+archive=yes rootpage="bugs" postformtext="Add a new bug titled:" ]]

Add the ability to hardcode the site's IP address in ikiwiki-hosting.conf, rather than looking at interfaces. Thanks, Antoine Beaupré.
diff --git a/debian/changelog b/debian/changelog
index fee47a2..4191295 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+ikiwiki-hosting (0.20120132) UNRELEASED; urgency=low
+
+  * Add the ability to hardcode the site's IP address in ikiwiki-hosting.conf,
+    rather than looking at interfaces. Thanks, Antoine Beaupré.
+
+ -- Joey Hess <joeyh@debian.org>  Sun, 04 Mar 2012 18:16:54 -0400
+
 ikiwiki-hosting (0.20120131) unstable; urgency=low
 
   * Fix quoting issue in use of which to determine if package is installed.
diff --git a/doc/bugs/ipv6_should_be_priority.mdwn b/doc/bugs/ipv6_should_be_priority.mdwn
index 8df2321..0cde6ce 100644
--- a/doc/bugs/ipv6_should_be_priority.mdwn
+++ b/doc/bugs/ipv6_should_be_priority.mdwn
@@ -112,3 +112,5 @@ index f0f124f..ad8e14c 100644
 """]]]
 
 I am running with this patch in production now, seems to work okay. --[[anarcat]]
+
+> [[applied|done]] --[[Joey]] 

use CNAMEs?
diff --git a/doc/todo/multiple_servers.mdwn b/doc/todo/multiple_servers.mdwn
index 9d8c883..7a6a43c 100644
--- a/doc/todo/multiple_servers.mdwn
+++ b/doc/todo/multiple_servers.mdwn
@@ -19,3 +19,5 @@ sites.
 * `ikisite list` only lists local sites, and is used by controlpanel etc.
 
 We may want to mirror some sites to multiple servers, too.
+
+> One thing I am thinking of is that we could use CNAME records instead of A to point the domains to the relevant servers. Then it would be up to the admin to configure his DNS properly, and add the list of available servers to the configuration. This would fix the problem of hardcoded IPs, of different host keys (because the SSH hostname would simply change), and so on. I certainly already feel unconfortable with all those A records in my zones already: IP renumbering is then unreliable and flaky... -- [[anarcat]]

add a workaround for this issue, to hardcode the IP detection
diff --git a/doc/bugs/ipv6_should_be_priority.mdwn b/doc/bugs/ipv6_should_be_priority.mdwn
index 0296d62..8df2321 100644
--- a/doc/bugs/ipv6_should_be_priority.mdwn
+++ b/doc/bugs/ipv6_should_be_priority.mdwn
@@ -46,3 +46,69 @@ index b802f21..08365d2 100644
     [...]
 
 As I said, this is a rather naive patch. Maybe this kind of overall prioritisation should be a config option? Or should we have a way to override the IP detection? Not sure how to handle this, really... Maybe the simplest fix is to have a --force argument... -- [[anarcat]]
+
+----
+
+The following patch allows overriding the IP detection mechanism:
+
+[[!format diff """
+From: =?UTF-8?q?Antoine=20Beaupr=C3=A9?= <anarcat@koumbit.org>
+Date: Sat, 17 Dec 2011 14:13:29 -0500
+Subject: [PATCH] allow hardcoding the IPs
+
+---
+ IkiWiki/Hosting.pm   |    9 +++++++++
+ ikiwiki-hosting.conf |    6 ++++++
+ 2 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/IkiWiki/Hosting.pm b/IkiWiki/Hosting.pm
+index b802f21..f09dd3b 100644
+--- a/IkiWiki/Hosting.pm
++++ b/IkiWiki/Hosting.pm
+@@ -104,6 +104,9 @@ sub outtemplate {
+ sub site_addresses {
+ 	# Looks up the site's main addresses; those that have a default
+ 	# route.
++	if ($config{hardcode_ipv4} && $config{hardcode_ipv6}) {
++		return ($config{hardcode_ipv4}, $config{hardcode_ipv6});
++	}
+ 	my ($defiface) = `ip route` =~ m/^default via .* dev ([a-zA-Z0-9]+)/m;
+ 	if (! $defiface) {
+ 		# Maybe ipv6 only.
+@@ -115,6 +118,12 @@ sub site_addresses {
+ 	my $show=`ip addr show $defiface`;
+ 	my ($ipv4) = $show =~ m/inet (\d+\.\d+\.\d+\.\d+).*scope global/m;
+ 	my ($ipv6) = $show =~ m/inet6 ([a-zA-Z0-9:]+).*scope global/m;
++	if ($config{hardcode_ipv4}) {
++		$ipv4 = $config{hardcode_ipv4};
++	}
++	if ($config{hardcode_ipv6}) {
++		$ipv6 = $config{hardcode_ipv6};
++	}
+ 	return ($ipv4, $ipv6);
+ }
+ 
+diff --git a/ikiwiki-hosting.conf b/ikiwiki-hosting.conf
+index f0f124f..ad8e14c 100644
+--- a/ikiwiki-hosting.conf
++++ b/ikiwiki-hosting.conf
+@@ -24,6 +24,12 @@ allow_ipv4=0
+ allow_ipv6=0
+ # (Disable all of the above to disable auto-assignment of DNS addresses.)
+ 
++# by default, ikiwiki-hosting looks at the first IP on the interface
++# that has the default gateway, but this may fail if you're behind NAT
++# or else. those allow you to hardcode the IPs
++# hardcode_ipv4=10.0.0.1
++# hardcode_ipv6=fr00::0
++
+ # This is the DNS TTL to use when adding a hostname for a site.
+ ttl=28800
+ 
+-- 
+1.7.7.3
+
+
+"""]]]
+
+I am running with this patch in production now, seems to work okay. --[[anarcat]]

link to the relevant monkeysphere doc for user auth
diff --git a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
index 6c554d8..80337ed 100644
--- a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
+++ b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
@@ -39,6 +39,8 @@ display).
 Revocations of configured keys could also be scanned for, and the keys
 disabled. --[[Joey]] 
 
+> Great idea! Documentation to set something like this up is [[the Monkeysphere SSH admin guide|http://web.monkeysphere.info/getting-started-admin/]], see "Monkeysphere for user authentication". --[[anarcat]]
+
 ---
 
 Another use for monkeysphere is in distributing the per-site ssh user keys

diff --git a/doc/users/anarcat.mdwn b/doc/users/anarcat.mdwn
new file mode 100644
index 0000000..d868d74
--- /dev/null
+++ b/doc/users/anarcat.mdwn
@@ -0,0 +1 @@
+See <https://wiki.koumbit.net/TheAnarcat>

sign
diff --git a/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn b/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn
index 6bfc42e..c4fb666 100644
--- a/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn
+++ b/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn
@@ -1 +1 @@
-It seems that comments are stripped from SSH keys when uploaded. This is unfortunate as it makes it harder to figure out which key is which.
+It seems that comments are stripped from SSH keys when uploaded. This is unfortunate as it makes it harder to figure out which key is which. -- [[anarcat]]

rename bugs/do_not_strip_comments_from_ssh_keys.mdwn to todo/do_not_strip_comments_from_ssh_keys.mdwn
diff --git a/doc/bugs/do_not_strip_comments_from_ssh_keys.mdwn b/doc/bugs/do_not_strip_comments_from_ssh_keys.mdwn
deleted file mode 100644
index 6bfc42e..0000000
--- a/doc/bugs/do_not_strip_comments_from_ssh_keys.mdwn
+++ /dev/null
@@ -1 +0,0 @@
-It seems that comments are stripped from SSH keys when uploaded. This is unfortunate as it makes it harder to figure out which key is which.
diff --git a/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn b/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn
new file mode 100644
index 0000000..6bfc42e
--- /dev/null
+++ b/doc/todo/do_not_strip_comments_from_ssh_keys.mdwn
@@ -0,0 +1 @@
+It seems that comments are stripped from SSH keys when uploaded. This is unfortunate as it makes it harder to figure out which key is which.

diff --git a/doc/bugs/do_not_strip_comments_from_ssh_keys.mdwn b/doc/bugs/do_not_strip_comments_from_ssh_keys.mdwn
new file mode 100644
index 0000000..6bfc42e
--- /dev/null
+++ b/doc/bugs/do_not_strip_comments_from_ssh_keys.mdwn
@@ -0,0 +1 @@
+It seems that comments are stripped from SSH keys when uploaded. This is unfortunate as it makes it harder to figure out which key is which.

try to describe an issue with NAT and IPv6... oh boy..
diff --git a/doc/bugs/ipv6_should_be_priority.mdwn b/doc/bugs/ipv6_should_be_priority.mdwn
new file mode 100644
index 0000000..0296d62
--- /dev/null
+++ b/doc/bugs/ipv6_should_be_priority.mdwn
@@ -0,0 +1,48 @@
+I am trying to add an external alias for my site and, because of silly NAT, the IPv4 interface doesn't match what DNS (as opposed to /etc/hosts) returns. IPv6 works fine though, but since ikiwiki-hosting first looks for IPv4 records, it fails to pick that up. I have a crude hack to fix this, but it doesn't seem like the good approach. "Worked for me" though. ;)
+
+Example, without the patch:
+
+    root@marcos:/home/a-wiki# ikisite domains wiki.anarcat.ath.cx --external=anarcat.ath.cx --alias=wiki.anarcat.ath.cx  
+    DNS not configured correctly for anarcat.ath.cx - 72.0.72.144
+
+Note that I had to patch to even get that debugging information:
+
+[[!format diff """
+diff --git a/ikisite b/ikisite
+index adc5df3..82a29cb 100755
+--- a/ikisite
++++ b/ikisite
+@@ -1193,7 +1193,7 @@ sub domains {
+                }
+                if ($address ne $hostname) {
+                        if (! grep { defined $_ && $_ eq $address } site_addresses()) {
+-                               print STDERR "DNS not configured correctly for $options{external}\n";
++                               print STDERR "DNS not configured correctly for $options{external} - got $address\n";
+                                exit 3; # special code
+                        }
+                        else {
+"""]]
+
+With the following patch, the thing actually works:
+
+[[!format diff """
+diff --git a/IkiWiki/Hosting.pm b/IkiWiki/Hosting.pm
+index b802f21..08365d2 100644
+--- a/IkiWiki/Hosting.pm
++++ b/IkiWiki/Hosting.pm
+@@ -128,7 +128,7 @@ sub host_address_or_cname {
+        # cached NXDOMAIN from earlier tests. We want to see the current
+        # state of the DNS.
+        # dig has to be run a second time to check for ipv6 AAAA addresses.
+-       foreach my $atype (qw{A AAAA}) {
++       foreach my $atype (qw{AAAA A}) {
+                open(DIG, "-|", "dig", "-t$atype", "+nofail", "+trace", "$host.") || error "dig: $!";
+                while (<DIG>) {
+                        next if /^;/;
+"""]]
+
+    root@marcos:/home/a-wiki# ikisite domains wiki.anarcat.ath.cx --external=anarcat.ath.cx --alias=wiki.anarcat.ath.cx  
+    warning: DNS for anarcat.ath.cx hardcodes IP 2001:1928:1:9:beae:c5ff:fe89:e238
+    [...]
+
+As I said, this is a rather naive patch. Maybe this kind of overall prioritisation should be a config option? Or should we have a way to override the IP detection? Not sure how to handle this, really... Maybe the simplest fix is to have a --force argument... -- [[anarcat]]

Add the adduser_basedir configuration file setting, which can be used to create sites someplace other than /home. Thanks, Philip Hands.
diff --git a/debian/changelog b/debian/changelog
index 85f230b..7b82196 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+ikiwiki-hosting (0.20111006) UNRELEASED; urgency=low
+
+  * Add the adduser_basedir configuration file setting, which can be used
+    to create sites someplace other than /home. Thanks, Philip Hands.
+
+ -- Joey Hess <joeyh@debian.org>  Sun, 27 Nov 2011 13:28:51 -0400
+
 ikiwiki-hosting (0.20111005) unstable; urgency=low
 
   * ikisite-wrapper: Allow getsetup subcommand to access the branchable
diff --git a/doc/bugs/alternative_home_basedir.mdwn b/doc/bugs/alternative_home_basedir.mdwn
index a3b4935..7d1579d 100644
--- a/doc/bugs/alternative_home_basedir.mdwn
+++ b/doc/bugs/alternative_home_basedir.mdwn
@@ -49,3 +49,8 @@ index 0e54189..82952eb 100644
 Which does the job, but I'd imagine could be done more neatly, or with a better variable name.
 
 An alternative way of fixing the specific problem might be to be able to hive off the few suid needing files into their own path, so that the /home stuff didn't need any suid bits set anyway, but even then some other people may find it useful to segregate the homes of ikiwiki users from real users on their machines -[[fil]]
+
+> I've applied this patch. I don't see any benefit to splitting out the 
+> suid bits from the rest of the home directory, and there's a very nice
+> benefit in being able to move the site home directories to someplace
+> other than /home. So, [[done]] --[[Joey]] 
diff --git a/ikiwiki-hosting.conf b/ikiwiki-hosting.conf
index 82952eb..f0f124f 100644
--- a/ikiwiki-hosting.conf
+++ b/ikiwiki-hosting.conf
@@ -65,7 +65,8 @@ keydir=/etc/ikiwiki-hosting/keys
 # Per-site lock files are stored in this directory.
 lockdir=/var/lib/ikiwiki-hosting-web/lock
 
-# This can be used to set an alternative home directory in which to create new sites
+# This can be used to set an alternative home directory in which
+# to create new sites.
 #adduser_basedir=/some/other/home
 
 # Git daemon looks for vhosts in this directory.

patch to allow ikisite to create home dirs in an alternative basedir
diff --git a/doc/bugs/alternative_home_basedir.mdwn b/doc/bugs/alternative_home_basedir.mdwn
new file mode 100644
index 0000000..a3b4935
--- /dev/null
+++ b/doc/bugs/alternative_home_basedir.mdwn
@@ -0,0 +1,51 @@
+I don't enable suid bits on /home on at least one system where I'd like to run ikiwiki-hosting, so for those things that need suid I create their homes on another mount (/home/suid/).  That being the case, and since there are bits of the created ikiwiki sites that need suid, I've knocked up this patch:
+
+<pre>
+From 44c545ac28f641f462bfcaac328b62b50b1e4d09 Mon Sep 17 00:00:00 2001
+From: Philip Hands <phil@hands.com>
+Date: Thu, 24 Nov 2011 20:21:16 +0000
+Subject: [PATCH] allow sites to be created in an alternative home basedir
+
+---
+ ikisite              |    3 +++
+ ikiwiki-hosting.conf |    3 +++
+ 2 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/ikisite b/ikisite
+index 7678ea2..adc5df3 100755
+--- a/ikisite
++++ b/ikisite
+@@ -1291,9 +1291,12 @@ sub usercreate {
+ 	assert_wrapper_denied();
+ 
+ 	my $user=username($hostname);
++	my @useradd_opts = ( "--base-dir", $config{useradd_basedir} )
++		if ($config{useradd_basedir}) ;
+ 	shell("useradd", $user, 
+ 		"--create-home",
+ 		"--skel", "/dev/null", # disable /etc/skel files
++		@useradd_opts,
+ 	);
+ 
+ 	mkdir(rootconfig($hostname));
+diff --git a/ikiwiki-hosting.conf b/ikiwiki-hosting.conf
+index 0e54189..82952eb 100644
+--- a/ikiwiki-hosting.conf
++++ b/ikiwiki-hosting.conf
+@@ -65,6 +65,9 @@ keydir=/etc/ikiwiki-hosting/keys
+ # Per-site lock files are stored in this directory.
+ lockdir=/var/lib/ikiwiki-hosting-web/lock
+ 
++# This can be used to set an alternative home directory in which to create new sites
++#adduser_basedir=/some/other/home
++
+ # Git daemon looks for vhosts in this directory.
+ gitdaemondir=/var/lib/ikiwiki-hosting-web/git
+ 
+-- 
+1.7.2.5
+</pre>
+
+Which does the job, but I'd imagine could be done more neatly, or with a better variable name.
+
+An alternative way of fixing the specific problem might be to be able to hive off the few suid needing files into their own path, so that the /home stuff didn't need any suid bits set anyway, but even then some other people may find it useful to segregate the homes of ikiwiki users from real users on their machines -[[fil]]

add
diff --git a/doc/todo/ikisite-calendar-running.mdwn b/doc/todo/ikisite-calendar-running.mdwn
new file mode 100644
index 0000000..81e6e20
--- /dev/null
+++ b/doc/todo/ikisite-calendar-running.mdwn
@@ -0,0 +1,6 @@
+Should be a way to trigger an ikisite-calendar run. 
+
+The two cases seem to be a change to `archive_pagespec` or similar,
+which should probably just automatically trigger a rebuild of all the
+calendar pages; and pushing in past posts from someone else, in which case
+a way needs to be present to generate calendar pages for the past years.

More portable environment clearing.
diff --git a/debian/changelog b/debian/changelog
index d581978..f5f94ba 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,6 +6,7 @@ ikiwiki-hosting (0.20110516) UNRELEASED; urgency=low
   * Configure git-daemon to know about external domain names of sites.
   * missingsite: Stop providing an index.cgi, just use apache.conf.tmpl
     for the missingsite to DirectoryIndex index.html ikiwiki.cgi
+  * More portable environment clearing.
 
  -- Joey Hess <joeyh@debian.org>  Sun, 15 May 2011 17:46:32 -0400
 
diff --git a/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn b/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn
index 8926607..1ac33ac 100644
--- a/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn
+++ b/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn
@@ -1,4 +1,17 @@
-I decided to just give ikiwiki-hosting a spin on my mac for evaluation purposes for now, and it currently fails to build out of the box for me, here's a small patch to let it build and the tests pass as well, but it is not a good and general clearenv() subsitute. I've yet to experiment with the software.
+I decided to just give ikiwiki-hosting a spin on my mac for evaluation
+purposes for now, and it currently fails to build out of the box for me,
+here's a small patch to let it build and the tests pass as well, but it is
+not a good and general clearenv() subsitute. I've yet to experiment with
+the software.
+
+> I'm a bit surprised/confused by this being necessary, since ikiwiki 
+> itself uses clearenv in its wrapper. Why does the wrapper's C code
+> that runs clearenv apparently work on OSX, but not the code here?
+> 
+> Ah, I see, ikiwiki only uses clearenv in tcc mode, while manipulating
+> environ directly otherwise, and that is said to work on freebsd, so
+> probably also OSX.  I've done the same thing here now, let me know if it
+> doesn't work. [[done]] --[[Joey]] 
 
 <pre>
 From eee70a464c9a577f69b0e3a1cafec579c398eb12 Mon Sep 17 00:00:00 2001
diff --git a/ikisite-wrapper.c b/ikisite-wrapper.c
index f966515..794d9ea 100644
--- a/ikisite-wrapper.c
+++ b/ikisite-wrapper.c
@@ -45,10 +45,16 @@ int main (int argc, char **argv) {
 	}
 
 	/* suid safety */
+#ifdef __TINYC__
+	/* old tcc versions do not support modifying environ directly */
 	if (clearenv() != 0) {
 		perror("clearenv");
 		exit(1);
 	}
+#else
+	/* this is more portable on freebsd/osx, which lack clearenv */
+	*environ = NULL;
+#endif
 	if (setenv("PATH", "/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin", 1) != 0) {
 		perror("setenv");
 		exit(1);

diff --git a/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn b/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn
new file mode 100644
index 0000000..8926607
--- /dev/null
+++ b/doc/bugs/ikisite-wrapper_fails_to_build_on_osx_10.6.7.mdwn
@@ -0,0 +1,52 @@
+I decided to just give ikiwiki-hosting a spin on my mac for evaluation purposes for now, and it currently fails to build out of the box for me, here's a small patch to let it build and the tests pass as well, but it is not a good and general clearenv() subsitute. I've yet to experiment with the software.
+
+<pre>
+From eee70a464c9a577f69b0e3a1cafec579c398eb12 Mon Sep 17 00:00:00 2001
+From: Jimmy Tang <jtang@tchpc.tcd.ie>
+Date: Sun, 29 May 2011 16:36:45 +0100
+Subject: [PATCH] clearenv() is not available on OSX 10.6.7
+
+This patch is offers a simple clearenv alternative on OSX, and is
+directly taken from
+
+http://svn.deepdarc.com/code/miredo-osx/tags/prerelease-1/miredo/compat/clearenv.c
+
+It is only used when built on OSX.
+---
+ ikisite-wrapper.c |   15 +++++++++++++++
+ 1 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/ikisite-wrapper.c b/ikisite-wrapper.c
+index f966515..8b64468 100644
+--- a/ikisite-wrapper.c
++++ b/ikisite-wrapper.c
+@@ -18,7 +18,13 @@
+ #include <sys/types.h>
+ #include <string.h>
+ 
++#ifdef __APPLE__
++# include <crt_externs.h>
++# define environ (*_NSGetEnviron())
++int clearenv(void);
++#else
+ extern char **environ;
++#endif
+ 
+ int main (int argc, char **argv) {
+        int i;
+@@ -78,3 +84,12 @@ int main (int argc, char **argv) {
+        perror(args[0]);
+        exit(1);
+ }
++
++
++#ifdef __APPLE__
++int clearenv(void)
++{
++       *environ = NULL;
++       return 0;
++}
++#endif
+-- 
+1.7.5.2
+</pre>

Configure git-daemon to know about external domain names of sites.
diff --git a/debian/changelog b/debian/changelog
index e392c4f..36e377f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -3,6 +3,7 @@ ikiwiki-hosting (0.20110516) UNRELEASED; urgency=low
   * Set timezone to GMT in auto setup files, to avoid random system timezimes
     from leaking out to existing sites when changesetup or upgrade is run.
   * gitpush: Push non-master branches too.
+  * Configure git-daemon to know about external domain names of sites.
 
  -- Joey Hess <joeyh@debian.org>  Sun, 15 May 2011 17:46:32 -0400
 
diff --git a/doc/todo/anon_git_access_by_external_domain.mdwn b/doc/todo/anon_git_access_by_external_domain.mdwn
index b1901cd..f5b33e1 100644
--- a/doc/todo/anon_git_access_by_external_domain.mdwn
+++ b/doc/todo/anon_git_access_by_external_domain.mdwn
@@ -1,3 +1,7 @@
 Currently, git://externl.example.com/ doesn't work. For this to work,
 ikisite needs to manage links in /var/lib/ikiwiki-hosting-web/git/ for
 each configured external domain. --[[Joey]] 
+
+> [[done]] .. note that the Branchable tab still shows the internal
+> domain in git urls. It's generally ok to use, unless you have some existing
+> domain that is moving to Branchable, etc. --[[Joey]] 
diff --git a/ikisite b/ikisite
index 7abf2c1..c69eae2 100755
--- a/ikisite
+++ b/ikisite
@@ -1368,6 +1368,8 @@ sub enable {
 
 	my $user=username($hostname);
 	my $home=homedir($hostname);
+
+	my @hostnames=map { $_->host } urllist($user);
 	
 	# Lock down the public_html directory so only the site user and
 	# www-data can access it.
@@ -1379,12 +1381,14 @@ sub enable {
 	my $vcs=getsetup($hostname, "rcs");
 	if ($vcs eq "git") {
 		# Setup git-daemon.
-		my $dest="$config{gitdaemondir}/$hostname.git";
-		unlink($dest);
-		# The symlink is always made, but git-daemon will only
-		# serve the site if its repository contains
-		# git-daemon-export-ok.
-		symlink(repository($hostname), $dest);
+		foreach my $h (@hostnames) {
+			my $dest="$config{gitdaemondir}/$h.git";
+			unlink($dest);
+			# The symlink is always made, but git-daemon will only
+			# serve the site if its repository contains
+			# git-daemon-export-ok.
+			symlink(repository($hostname), $dest);
+		}
 		# Allow git-daemon to read and write to the repo via ACL.
 		readconfig();
 		eval { shell("setfacl", "-R", "-m", "d:g:$config{gitdaemonuser}:rwX,d:g:$user:rwX,g:$config{gitdaemonuser}:rwX,g:$user:rwX", "$home/source.git") };
@@ -1395,7 +1399,7 @@ sub enable {
 		# The branchable plugin will also create/remove it
 		# as needed when the setting is changed.
 		my $branchable=getsetup($hostname, "branchable");
-		my $flagfile="$dest/git-daemon-export-ok";
+		my $flagfile=repository($hostname)."/git-daemon-export-ok";
 		if ($branchable) {
 			open(FLAG, ">", $flagfile);
 			close FLAG;
@@ -1511,7 +1515,7 @@ sub enable {
 
 	# generate apache config files for alias urls, that redirect to the
 	# main url
-	foreach my $alias (map { $_->host } urllist(username($hostname))) {
+	foreach my $alias (@hostnames) {
 		next if $setup{$alias};
 		$setup{$alias}=1;
 		$apache_site="ikisite-$alias";
@@ -1565,15 +1569,18 @@ sub disable {
 
 	disabledns($hostname) unless $options{temporary};
 
+	my @urls=urllist(username($hostname));
+
 	my $vcs=getsetup($hostname, "rcs");
 	if ($vcs eq "git") {
-		my $dest="$config{gitdaemondir}/$hostname.git";
-		unlink($dest);
+		foreach my $h (map { $_->host } @urls) {
+			unlink("$config{gitdaemondir}/$h.git");
+		}
 	}
 	
 	# remove apache config file(s)
 	my $reload=0;
-	foreach my $url (urllist(username($hostname))) {
+	foreach my $url (@urls) {
 		my $apache_site="ikisite-".$url->host;
 		my $apache_conf_file="/etc/apache2/sites-available/$apache_site";
 		if (-e $apache_conf_file) {

todo
diff --git a/doc/todo/anon_git_access_by_external_domain.mdwn b/doc/todo/anon_git_access_by_external_domain.mdwn
new file mode 100644
index 0000000..b1901cd
--- /dev/null
+++ b/doc/todo/anon_git_access_by_external_domain.mdwn
@@ -0,0 +1,3 @@
+Currently, git://externl.example.com/ doesn't work. For this to work,
+ikisite needs to manage links in /var/lib/ikiwiki-hosting-web/git/ for
+each configured external domain. --[[Joey]] 

update
diff --git a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
index 29252be..6c554d8 100644
--- a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
+++ b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
@@ -38,3 +38,9 @@ display).
 
 Revocations of configured keys could also be scanned for, and the keys
 disabled. --[[Joey]] 
+
+---
+
+Another use for monkeysphere is in distributing the per-site ssh user keys
+used for automatic git pushes. Should be easy enough to commit those keys
+right into monkeysphere when they're generated.

Add gitpush plugin, which can be used to push changes to a site on to other git repositories.
diff --git a/IkiWiki/Plugin/gitpush.pm b/IkiWiki/Plugin/gitpush.pm
new file mode 100644
index 0000000..60baebb
--- /dev/null
+++ b/IkiWiki/Plugin/gitpush.pm
@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+package IkiWiki::Plugin::gitpush;
+
+use warnings;
+use strict;
+use IkiWiki 3.00;
+
+sub import {
+	hook(type => "getsetup", id => "gitpush", call => \&getsetup);
+	hook(type => "cgi", id => "gitpush",  call => \&cgi);
+	hook(type => "delete", id => "gitpush", call => \&push);
+	hook(type => "change", id => "gitpush", call => \&push);
+}
+
+sub getsetup () {
+	my $keyurl=cgiurl(do => "sshkey");
+	return
+		plugin => {
+			safe => 1,
+			rebuild => 0,
+			section => "rcs",
+		},
+		git_push_to => {
+			type => "string",
+			example => [],
+			description => "git repository urls that changes are pushed to",
+			link => "<a href=\"$keyurl\">ssh key</a>)",
+			safe => 1,
+			rebuild => 0,
+		},
+}
+
+sub cgi ($) {
+	my $cgi=shift;
+	my $do = $cgi->param('do');
+	if (defined $do && $do eq 'sshkey') {
+		print "Content-Type: text/plain\n\n";
+		print readfile(get_ssh_public_key())."\n";
+		exit 0;
+	}
+}
+
+my $pushed=0;
+
+sub push {
+	if (! $pushed && $config{rcs} eq 'git' && defined $config{push_to} &&
+	    ref($config{push_to}) eq 'ARRAY' && length @{$config{push_to}}) {
+		$pushed=1;
+		
+		# daemonise
+		defined(my $pid = fork) or error("Can't fork: $!");
+		return if $pid;
+		chdir '/';
+		open STDIN, '/dev/null';
+		open STDOUT, '>/dev/null';
+		POSIX::setsid() or error("Can't start a new session: $!");
+		open STDERR, '>&STDOUT' or error("Can't dup stdout: $!");
+		
+		# Don't need to keep a lock on the wiki as a daemon.
+		IkiWiki::unlockwiki();
+		
+		# Ensure we have a ssh key generated to use.
+		get_ssh_public_key();
+		# Avoid ssh host key checking prompts.
+		$ENV{GIT_SSH}="iki-ssh-unsafe";
+
+		foreach my $url (@{$config{push_to}}) {
+			IkiWiki::Plugin::git::run_or_cry(
+				'git', 'push', '--quiet', '--mirror', $url);
+		}
+
+		exit 0;
+	}
+}
+
+# Returns path of ssh public key.
+# If no key exists, one is created. (Can be a little slow.)
+sub get_ssh_public_key {
+	my @keys;
+	my $findkeys=sub { @keys=glob("$ENV{HOME}/.ssh/id_*.pub") };
+	$findkeys->();
+	if (! @keys) {
+		my $ret=system("ssh-keygen", "-q", "-t", "rsa",
+			"-f", "$ENV{HOME}/.ssh/id_rsa",
+			"-N", "",
+			"-C", $config{wikiname});
+		$findkeys->();
+		if ($ret !=0 || ! @keys) {
+			error "ssh-keygen failed";
+		}
+	}
+	return shift(@keys);
+}
+
+1
diff --git a/Makefile b/Makefile
index 962850b..8699355 100644
--- a/Makefile
+++ b/Makefile
@@ -5,10 +5,10 @@ MODDIR=$(DESTDIR)/usr/share/perl5/
 CFLAGS=-O2 -Wall -g
 BINS=iki-git-shell iki-git-hook-update ikisite-wrapper
 SCRIPTS=ikisite ikidns ikiwiki-hosting-web-daily ikiwiki-hosting-web-backup \
-	ikisite-delete-unfinished-site 
+	ikisite-delete-unfinished-site iki-ssh-unsafe
 MANS=ikisite ikidns ikisite-wrapper ikiwiki-hosting-web-daily \
      	ikiwiki-hosting-web-backup ikisite-delete-unfinished-site \
-	iki-git-hook-update iki-git-shell
+	iki-git-hook-update iki-git-shell iki-ssh-unsafe
 
 IKIWIKI=ikiwiki --wikiname "ikiwiki hosting internals" \
 		--no-usedirs --underlaydir=/dev/null \
diff --git a/debian/changelog b/debian/changelog
index f570568..6199456 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -22,6 +22,8 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
   * Support ipv6-only operation.
   * Remove dns key directory on purge. Closes: #625817
   * Don't run cron jobs once removed. Closes: #625815
+  * Add gitpush plugin, which can be used to push changes to a site on
+    to other git repositories.
 
  -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
 
diff --git a/debian/ikiwiki-hosting-web.install b/debian/ikiwiki-hosting-web.install
index a6067eb..bc35358 100644
--- a/debian/ikiwiki-hosting-web.install
+++ b/debian/ikiwiki-hosting-web.install
@@ -5,6 +5,7 @@ usr/bin/ikiwiki-hosting-web-daily
 usr/bin/ikiwiki-hosting-web-backup
 usr/bin/iki-git-shell
 usr/bin/iki-git-hook-update
+usr/bin/iki-ssh-unsafe
 etc/ikiwiki-hosting/autosetup
 var/lib/ikiwiki-hosting-web
 gitweb/robots.txt usr/share/gitweb
diff --git a/debian/ikiwiki-hosting-web.manpages b/debian/ikiwiki-hosting-web.manpages
index 0c13377..cb0966f 100644
--- a/debian/ikiwiki-hosting-web.manpages
+++ b/debian/ikiwiki-hosting-web.manpages
@@ -5,3 +5,4 @@ ikiwiki-hosting-web-daily.1
 ikiwiki-hosting-web-backup.1
 iki-git-shell.1
 iki-git-hook-update.1
+iki-ssh-unsafe.1
diff --git a/doc/iki-ssh-unsafe.mdwn b/doc/iki-ssh-unsafe.mdwn
new file mode 100644
index 0000000..6b67408
--- /dev/null
+++ b/doc/iki-ssh-unsafe.mdwn
@@ -0,0 +1,23 @@
+# NAME
+
+iki-ssh-unsafe - ikiwiki-hosting helper
+
+# SYNOPSIS
+
+iki-ssh-unsafe [ssh options]
+
+# DESCRIPTION
+
+This is a wrapper for ssh, and the parameters are passed
+on to that program. Strict host key checking is disabled.
+
+# SEE ALSO
+
+* [[ikisite]](1)
+* [[ssh]](1)
+
+# AUTHOR
+
+Joey Hess <joey@ikiwiki.info>
+
+Warning: this page is automatically made into a man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD).  Edit with care
diff --git a/doc/todo/git_remotes_configurator.mdwn b/doc/todo/git_remotes_configurator.mdwn
index 2af98b0..b5c744d 100644
--- a/doc/todo/git_remotes_configurator.mdwn
+++ b/doc/todo/git_remotes_configurator.mdwn
@@ -31,9 +31,6 @@ called when a change is made or received.
 
 The plugin should daemonize, drop locks, wait a short while to avoid
 contending with the main site build, and then push to configured remotes.
-Actually, let's make the pushing be done by an ikisite command, that way
-it can also be triggered manually at the console (eg for debugging), and
-queueing could later be added if necessary.
 
 ## gotchas
 
@@ -45,6 +42,9 @@ repository, an unsafe push could be done, exposing its contents.
 ssh (or http) could stall asking for a password. The daemonization should
 avoid this by ensuring that any controlling terminal is detached from.
 
-May need to force push if pushing to an empty remote.

(Diff truncated)
update
diff --git a/doc/todo/git_remotes_configurator.mdwn b/doc/todo/git_remotes_configurator.mdwn
index 615cc15..2af98b0 100644
--- a/doc/todo/git_remotes_configurator.mdwn
+++ b/doc/todo/git_remotes_configurator.mdwn
@@ -19,11 +19,10 @@ For each remote, the user only needs to configure:
 * Whether to make the remote a mirror. (`git push --mirror`; force-update
   the remote refs)
   Or find a sane default.
-* Possibly, the remote branch to push origin/master to. 
-  Since in ikisite only the master branch is likely to matter (pushing
-  setup is not necessary), mirroring probably is not relevant.
+* Possibly, the remote branch to push origin/master to. (Or a prefix, so
+  it pushes to foo/master, foo/setup, etc.)
   Being able to push origin/master to github/branchable might be nice,
-  but this feature could be imitted for simplicity initially.
+  but this feature could be omitted for simplicity initially.
 
 The pushing should be run by a post-update hook. Currently, the post-update
 hook is the ikiwiki wrapper. So, the pushing could be implemented by

update
diff --git a/doc/todo/git_remotes_configurator.mdwn b/doc/todo/git_remotes_configurator.mdwn
index 68165c3..615cc15 100644
--- a/doc/todo/git_remotes_configurator.mdwn
+++ b/doc/todo/git_remotes_configurator.mdwn
@@ -32,6 +32,9 @@ called when a change is made or received.
 
 The plugin should daemonize, drop locks, wait a short while to avoid
 contending with the main site build, and then push to configured remotes.
+Actually, let's make the pushing be done by an ikisite command, that way
+it can also be triggered manually at the console (eg for debugging), and
+queueing could later be added if necessary.
 
 ## gotchas
 

update
diff --git a/doc/todo/git_remotes_configurator.mdwn b/doc/todo/git_remotes_configurator.mdwn
index 54b432e..68165c3 100644
--- a/doc/todo/git_remotes_configurator.mdwn
+++ b/doc/todo/git_remotes_configurator.mdwn
@@ -43,4 +43,6 @@ repository, an unsafe push could be done, exposing its contents.
 ssh (or http) could stall asking for a password. The daemonization should
 avoid this by ensuring that any controlling terminal is detached from.
 
+May need to force push if pushing to an empty remote.
+
 [[!tag wishlist]]

todo
diff --git a/doc/todo/cia_integration.mdwn b/doc/todo/cia_integration.mdwn
new file mode 100644
index 0000000..4bd4d9b
--- /dev/null
+++ b/doc/todo/cia_integration.mdwn
@@ -0,0 +1,6 @@
+Would be nice if changes to sites could be communicated to cia.vc.
+
+This is similar to auto-pushing changes to
+[[git_remotes|git_remotes_configurator]] except of course CIA's nasty
+hook scripts have to be used, and some of their configuration exposed
+to the user.

design
diff --git a/doc/todo/git_remotes_configurator.mdwn b/doc/todo/git_remotes_configurator.mdwn
index 39f7246..54b432e 100644
--- a/doc/todo/git_remotes_configurator.mdwn
+++ b/doc/todo/git_remotes_configurator.mdwn
@@ -5,4 +5,42 @@ A web interface for git remotes configuration would be very handy.
 * A special case is pushing changes to a site over to a branch of that
   site.
 
+## design
+
+`ikisite` already handles backup/restore of `.ssh/id_*`, so ssh-keygen
+can be used a generate a passwordless ssh key for a site when remotes are
+first set up. Provide a way to download the ssh public key, to provide to
+github, etc.
+
+For each remote, the user only needs to configure:
+
+* The git URI, in any of the forms git recognises, *except* file:/// and 
+  a bare path to a local repo.
+* Whether to make the remote a mirror. (`git push --mirror`; force-update
+  the remote refs)
+  Or find a sane default.
+* Possibly, the remote branch to push origin/master to. 
+  Since in ikisite only the master branch is likely to matter (pushing
+  setup is not necessary), mirroring probably is not relevant.
+  Being able to push origin/master to github/branchable might be nice,
+  but this feature could be imitted for simplicity initially.
+
+The pushing should be run by a post-update hook. Currently, the post-update
+hook is the ikiwiki wrapper. So, the pushing could be implemented by
+an ikiwiki plugin. It could use the `refresh` hook, which will always be
+called when a change is made or received.
+
+The plugin should daemonize, drop locks, wait a short while to avoid
+contending with the main site build, and then push to configured remotes.
+
+## gotchas
+
+ssh host key checking needs to be dealt with somehow. By disabling
+StrictHostKeyChecking in `~/.ssh/config`? Should be ok for
+public/branchable repositories. The risk is that for a non-public
+repository, an unsafe push could be done, exposing its contents.
+
+ssh (or http) could stall asking for a password. The daemonization should
+avoid this by ensuring that any controlling terminal is detached from.
+
 [[!tag wishlist]]

anon git push beast appears slain!
diff --git a/debian/changelog b/debian/changelog
index 7b20c11..1a4938b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -12,7 +12,11 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     directory, but instead from /etc/ikiwiki-hosting/config/$username/.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
-    to upgrade them is highly recommended. 
+    to upgrade them is highly recommended.
+  * Added support for anonymous git push (disabled by default).
+    It will only work if the home directory of a site is on a
+    filesystem that supports POSIX ACLs, otherwise git-daemon
+    won't be able to write to the source.git directory.
 
  -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
 
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index bb7db72..3b46f1b 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -1,3 +1,5 @@
+[[done]].. needs some testing though
+
 <http://ikiwiki.info/tips/untrusted_git_push/>
 
 The main sticking point on this is that git-daemon runs as a single user,

code to enable git hook to check untrusted commits for anonpush
diff --git a/IkiWiki/Plugin/branchable.pm b/IkiWiki/Plugin/branchable.pm
index b2e7597..fddf566 100644
--- a/IkiWiki/Plugin/branchable.pm
+++ b/IkiWiki/Plugin/branchable.pm
@@ -10,11 +10,12 @@ sub import {
 	hook(type => "getsetup", id => "branchable",  call => \&getsetup);
 	hook(type => "checkconfig", id => "branchable",  call => \&checkconfig,
 		first => 1);
+	hook(type => "sessioncgi", id => "branchable", call => \&sessioncgi);
 	hook(type => "pageactions", id => "branchable", call => \&pageactions,
 		# Want it to be the last thing on the action bar.
 		last => 1);
-	hook(type => "sessioncgi", id => "branchable", call => \&sessioncgi);
-	hook(type => "genwrapper", id => "branchable", call => \&genwrapper);
+	hook(type => "genwrapper", id => "branchable", call => \&genwrapper,
+		last => 1);
 	hook(type => "disable", id => "branchable", call => \&disable);
 }
 
@@ -64,6 +65,21 @@ sub checkconfig {
 		delete $config{diffurl};
 		$config{anonpush}=0;
 	}
+	
+	# Sites with anonpush enabled have a git_test_receive_wrapper.
+	if ($config{anonpush}) {
+		my $repo=find_git_repository();
+		if (defined $repo) {
+			$config{git_test_receive_wrapper}="$repo/hooks/pre-receive";
+		}
+		else {
+			$config{anonpush}=0;
+			delete $config{git_test_receive_wrapper};
+		}
+	}
+	else {
+		delete $config{git_test_receive_wrapper};
+	}
 }
 
 my $inbranchable;
@@ -118,6 +134,8 @@ sub showbranchable ($$) {
 sub genwrapper {
 	# This hook is called whenever wrappers are being built,
 	# and that happens when configuration has changed.
+	# (This hook is set to run last, in order to run after
+	# the creation of the git_test_receive_wrapper.)
 	setbranchable();
 
 	# C code to inject into wrapper.
@@ -128,6 +146,7 @@ sub disable {
 	# When this plugin is disabled, clean up any previously
 	# configured branchability.
 	$config{branchable}=0;
+	$config{anonpush}=0;
 	setbranchable();
 }
 
@@ -153,6 +172,18 @@ sub setbranchable {
 			chmod(0700, $repo) || error "chmod $repo: $!";
 		}
 	}
+
+	if (defined $repo && $config{anonpush}) {
+		# Allow git daemon to push.
+		system("cd $repo && git config daemon.receivepack true");
+	}
+	else {
+		system("cd $repo && git config daemon.receivepack false");
+		# Delete unnecesary hook for speed.
+		if (defined $repo) {
+			unlink("$repo/hooks/pre-receive");
+		}
+	}
 }
 
 # Parses git_wrapper to find out where the git repository is.
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 644b25f..bb7db72 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -21,8 +21,10 @@ How about this:
   and when it's disabled, disable it, and delete the hook. (That
   hook slows down all commits some.. a C wrapper that
   just checks the uid of the committer would allow speeding it back up.)
-* When anonpush is enabled, run: `git config daemon.receivepack = true`
-  (and undo when disabled).
+  (done)
+* When anonpush is enabled, **after** wrapper setup. 
+  run: `git config daemon.receivepack = true`
+  (and undo when disabled). (done)
 * Set core.sharedRepository to true, in all bare repos. Needed to ensure
   dirs in bare repo are always made writable by group.
   (Already done, and spot checks indicate it's working; also tested

add gitdaemonuser to untrusted_committers
for new site and on upgrade
diff --git a/autosetup/auto-blog.setup b/autosetup/auto-blog.setup
index d8a9b25..565e92f 100644
--- a/autosetup/auto-blog.setup
+++ b/autosetup/auto-blog.setup
@@ -78,6 +78,8 @@ websetup_unsafe:
 websetup_show_unsafe: 0
 cgi_wrappermode: $ENV{IKIWIKI_CGI_WRAPPERMODE}
 git_wrappermode: $ENV{IKIWIKI_GIT_WRAPPERMODE}
+untrusted_committers:
+ - $ENV{IKIWIKI_GITDAEMONUSER}
 ENV:
  TMPDIR: '$ENV{HOME}/tmp'
 EOF
diff --git a/autosetup/auto.setup b/autosetup/auto.setup
index 5c7f9af..4b53e36 100644
--- a/autosetup/auto.setup
+++ b/autosetup/auto.setup
@@ -63,6 +63,8 @@ websetup_unsafe:
 websetup_show_unsafe: 0
 cgi_wrappermode: $ENV{IKIWIKI_CGI_WRAPPERMODE}
 git_wrappermode: $ENV{IKIWIKI_GIT_WRAPPERMODE}
+untrusted_committers:
+ - $ENV{IKIWIKI_GITDAEMONUSER}
 ENV:
  TMPDIR: '$ENV{HOME}/tmp'
 EOF
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 8a9e44c..644b25f 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -12,6 +12,7 @@ How about this:
   Should default to false, and be forced to false when branchable=0.
   (done)
 * Set `untrusted_committers` to ikiwiki-anon on all sites by default.
+  (done)
 * Set `git_wrappermode: 6755` on all sites. (ikiwiki-anon will run the
   wrapper when a commit is pushed; need to run it as the site user) (done)
 * Make ~/source.git and all its contents be writable be ikiwiki-anon.
diff --git a/ikisite b/ikisite
index 70385dc..f233c4f 100755
--- a/ikisite
+++ b/ikisite
@@ -72,6 +72,7 @@ sub create {
 	$ENV{IKIWIKI_CGIDIR}=cgidir($hostname);
 	$ENV{IKIWIKI_LOGDIR}=logdir($hostname);
 	$ENV{IKIWIKI_OPENID_REALM}=$config{openid_realm};
+	$ENV{IKIWIKI_GITDAEMONUSER}=$config{gitdaemonuser};
 	# This is normally 06755, but for new users (with suexec) we can't use
 	# suid/sgid
 	$ENV{IKIWIKI_CGI_WRAPPERMODE}="0755";
@@ -2433,6 +2434,24 @@ sub upgrade {
 		chown($uid, $gid, "$cgidir") || error "chown $cgidir: $!";
 		chmod(0755, "$cgidir") || error "chmod $cgidir: $!";
 
+		eval q{use YAML::Syck};
+		die $@ if $@;
+		readconfig();
+
+		changesetup($hostname,
+			rebuild => 0,
+			commit => 1,
+			message => "ikisite upgrade",
+			set => [
+				"cgi_wrapper" ."=". $cgidir."/ikiwiki.cgi",
+				"cgi_wrappermode" ."=". "0755",
+			],
+			# gitdaemonuser became an untrusted committer
+			'set-yaml' => [
+				"untrusted_committers=".Dump([$config{gitdaemonuser}]),
+			],
+		);
+
 		changesetup($hostname,
 			rebuild => 0,
 			commit => 1,

set git_wrapermode back to 06755
It got set to 755 in passing as part of smcv's changes to the cgi; cgi
remains non-suid, but the git wrapper needs to be suid for when it's called
by git-daemon.
diff --git a/autosetup/auto-blog.setup b/autosetup/auto-blog.setup
index 4eb280b..d8a9b25 100644
--- a/autosetup/auto-blog.setup
+++ b/autosetup/auto-blog.setup
@@ -76,8 +76,8 @@ websetup_unsafe:
  - indexpages
  - repositories
 websetup_show_unsafe: 0
-cgi_wrappermode: $ENV{IKIWIKI_WRAPPERMODE}
-git_wrappermode: $ENV{IKIWIKI_WRAPPERMODE}
+cgi_wrappermode: $ENV{IKIWIKI_CGI_WRAPPERMODE}
+git_wrappermode: $ENV{IKIWIKI_GIT_WRAPPERMODE}
 ENV:
  TMPDIR: '$ENV{HOME}/tmp'
 EOF
diff --git a/autosetup/auto.setup b/autosetup/auto.setup
index fa393f0..5c7f9af 100644
--- a/autosetup/auto.setup
+++ b/autosetup/auto.setup
@@ -61,8 +61,8 @@ websetup_unsafe:
  - indexpages
  - repositories
 websetup_show_unsafe: 0
-cgi_wrappermode: $ENV{IKIWIKI_WRAPPERMODE}
-git_wrappermode: $ENV{IKIWIKI_WRAPPERMODE}
+cgi_wrappermode: $ENV{IKIWIKI_CGI_WRAPPERMODE}
+git_wrappermode: $ENV{IKIWIKI_GIT_WRAPPERMODE}
 ENV:
  TMPDIR: '$ENV{HOME}/tmp'
 EOF
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 1ed3b05..8a9e44c 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -12,6 +12,8 @@ How about this:
   Should default to false, and be forced to false when branchable=0.
   (done)
 * Set `untrusted_committers` to ikiwiki-anon on all sites by default.
+* Set `git_wrappermode: 6755` on all sites. (ikiwiki-anon will run the
+  wrapper when a commit is pushed; need to run it as the site user) (done)
 * Make ~/source.git and all its contents be writable be ikiwiki-anon.
   Somehow. Note that normal unix permissions don't suffice. (done?)
 * When anonpush is enabled, enable `git_test_receive_wrapper` -- 
diff --git a/ikisite b/ikisite
index 2aee594..70385dc 100755
--- a/ikisite
+++ b/ikisite
@@ -74,7 +74,8 @@ sub create {
 	$ENV{IKIWIKI_OPENID_REALM}=$config{openid_realm};
 	# This is normally 06755, but for new users (with suexec) we can't use
 	# suid/sgid
-	$ENV{IKIWIKI_WRAPPERMODE}="0755";
+	$ENV{IKIWIKI_CGI_WRAPPERMODE}="0755";
+	$ENV{IKIWIKI_GIT_WRAPPERMODE}="6755";
 	my $autosetup=defined $options{type} ? "$config{autosetupdir}/auto-$options{type}.setup" : undef;
 	if (! defined $autosetup || ! -e $autosetup) {
 		$autosetup="$config{autosetupdir}/auto.setup";

add group
diff --git a/debian/ikiwiki-hosting-web.postinst b/debian/ikiwiki-hosting-web.postinst
index fa8cbcf..eec6d08 100755
--- a/debian/ikiwiki-hosting-web.postinst
+++ b/debian/ikiwiki-hosting-web.postinst
@@ -4,7 +4,7 @@ set -e
 if [ "$1" = configure ]; then
 	. /etc/ikiwiki-hosting/ikiwiki-hosting.conf || true
 	if [ -n "$gitdaemondir" ] && [ -n "$gitdaemonuser" ]; then
-		adduser --quiet --system --no-create-home --home "$gitdaemondir" "$gitdaemonuser"
+		adduser --quiet --system --group --no-create-home --home "$gitdaemondir" "$gitdaemonuser"
 	fi
 fi
 
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index e2309ae..1ed3b05 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -13,7 +13,7 @@ How about this:
   (done)
 * Set `untrusted_committers` to ikiwiki-anon on all sites by default.
 * Make ~/source.git and all its contents be writable be ikiwiki-anon.
-  Somehow. Note that normal unix permissions don't suffice.
+  Somehow. Note that normal unix permissions don't suffice. (done?)
 * When anonpush is enabled, enable `git_test_receive_wrapper` -- 
   and when it's disabled, disable it, and delete the hook. (That
   hook slows down all commits some.. a C wrapper that

set acl to allow gitdaemonuser to read and write source.git
Rely on git-daemon's configuration to prevent it from accepting pushes
when anonpush is disabled. And yeah, we trust that git-daemon won't be
compromised, or all source.git repos, even non-branchable ones, could be
accessed.
acl thoughts
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index a74c03f..5144f39 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -11,17 +11,8 @@ How about this:
 * In branchable plugin, add a new "anonpush" config setting.
   Should default to false, and be forced to false when branchable=0.
 * Set `untrusted_committers` to ikiwiki-anon on all sites by default.
-* Make ~/source.git be in group ikiwiki-anon, and mode 2775, when
-  branchable=1. (When branchable=0, keep current mode of 0700.)
-  (This could perhaps be improved to only when anonpush is enabled, but
-  either way, git-daemon is going to have write access to a lot of sites..
-  And if it's compromised it does not need to run the test hook either.)
-* Ensure that subdirs of ~/source.git are also group ikiwiki-anon, 
-  and that files are also in that group. (Dirs need to be in the group
-  so it can make new files.. Some files need to be in the group so it can
-  modify. Some files git creates but never modifies, and others it
-  may unlink and rewrite; in either case the file group doesn't really
-  matter. Git should do the right thing after initial group setup.)
+* Make ~/source.git and all its contents be writable be ikiwiki-anon.
+  Somehow. Note that normal unix permissions don't suffice.
 * When anonpush is enabled, enable `git_test_receive_wrapper` -- 
   and when it's disabled, disable it, and delete the hook. (That
   hook slows down all commits some.. a C wrapper that
@@ -39,30 +30,30 @@ How about this:
 
 All the above is reasonable except the bit about permissions. Problem is
 that both ikiwiki-anon and the site user need to be able to write to the
-git repo. But it's not enough to make it 02775 user:ikiwiki-anon, because
+git repo. But it's not enough to make it 02775 siteuser:ikiwiki-anon, because
 when ikiwiki-anon makes new directories like objects/xx/, it will own
 them, and as the site user is not in the ikiwiki-anon group, it will not
-be able to write to those subdirs, leading to later permissions trouble.
+be able to write to those subdirs, leading to later failure.
 Similarly, when the site user makes commits, it will make directories owned
 by it, that ikiwiki-anon cannot write to.
 
 The site user cannot be in the ikiwiki-anon group, because then they could
 access and write to other sites' repositories.
 
-Short of pre-creating all possible object subdirectories and ensuring they are
-02755 user:ikiwiki-anon, I'm not sure how to fix this. And, git-gc will
-delete empty object subdirectories.
+Pre-creating all possible object subdirectories and making them 
+02755 siteuser:ikiwiki-anon probalby won't work well; git-gc will
+delete empty object subdirectories, and it would be easy to miss some
+directory that git creates.
 
 Use ACLs? Would require filesystem support (ie, that ext234 filesystems be
-mounted with 'acl' option). 
+mounted with 'acl' option, which does not appear to be the default). 
 
 The magic settings seem to be:
 
-	chmod g+s source.git (already done by git init --bare --shared)
-	setfacl -R -m d:g:ikiwiki-anon:rwX,d:g:$siteuser:rwX,g:ikiwiki-anon:rwX,g:$siteuser:rwX source.git
- 
-(Note setfacl needs to be run by root.)
+	chmod g+s source.git # already done by git init --bare --shared
+	sudo setfacl -R -m d:g:ikiwiki-anon:rwX,d:g:$siteuser:rwX,g:ikiwiki-anon:rwX,g:$siteuser:rwX source.git
 
 This allows ikiwiki-anon to read/write to all files/dirs in the repo,
 and sets all directories to propigate the ACL to new files/dirs as they
-are created.
+are created. When ikiwiki-anon creates a file or directory, it will
+be owned by ikiwiki-anon:siteuser, and siteuser can always write to it.

update
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 8f6b65e..a74c03f 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -34,3 +34,35 @@ How about this:
   that it works when the sourcedir is temporarily 700 and a commit comes
   in.)
 * Update do=branchable page to say when anonpush is enabled.
+
+## permissions mess
+
+All the above is reasonable except the bit about permissions. Problem is
+that both ikiwiki-anon and the site user need to be able to write to the
+git repo. But it's not enough to make it 02775 user:ikiwiki-anon, because
+when ikiwiki-anon makes new directories like objects/xx/, it will own
+them, and as the site user is not in the ikiwiki-anon group, it will not
+be able to write to those subdirs, leading to later permissions trouble.
+Similarly, when the site user makes commits, it will make directories owned
+by it, that ikiwiki-anon cannot write to.
+
+The site user cannot be in the ikiwiki-anon group, because then they could
+access and write to other sites' repositories.
+
+Short of pre-creating all possible object subdirectories and ensuring they are
+02755 user:ikiwiki-anon, I'm not sure how to fix this. And, git-gc will
+delete empty object subdirectories.
+
+Use ACLs? Would require filesystem support (ie, that ext234 filesystems be
+mounted with 'acl' option). 
+
+The magic settings seem to be:
+
+	chmod g+s source.git (already done by git init --bare --shared)
+	setfacl -R -m d:g:ikiwiki-anon:rwX,d:g:$siteuser:rwX,g:ikiwiki-anon:rwX,g:$siteuser:rwX source.git
+ 
+(Note setfacl needs to be run by root.)
+
+This allows ikiwiki-anon to read/write to all files/dirs in the repo,
+and sets all directories to propigate the ACL to new files/dirs as they
+are created.

add anonpush setting
diff --git a/IkiWiki/Plugin/branchable.pm b/IkiWiki/Plugin/branchable.pm
index 459ae62..b27fbd2 100644
--- a/IkiWiki/Plugin/branchable.pm
+++ b/IkiWiki/Plugin/branchable.pm
@@ -32,6 +32,13 @@ sub getsetup () {
 			safe => 1,
 			rebuild => 1, # disables diffurl and historyurl
 		},
+		anonpush => {
+			type => "boolean",
+			example => 0,
+			description => "Allow anyone to git push verified changes to this site?",
+			safe => 1,
+			rebuild => 0,
+		},
 		branchable_action => {
 			type => "boolean",
 			example => 1,
@@ -51,9 +58,11 @@ sub checkconfig {
 	# Sites that are not branchable do not have gitweb configured, so
 	# automatically disable the historyurl and diffurl.
 	# TODO: store old values and re-enable if branchable is enabled
+	# Also, non-branchability disabled anonpush.
 	if (! $config{branchable}) {
 		delete $config{historyurl};
 		delete $config{diffurl};
+		$config{anonpush}=0;
 	}
 }
 
@@ -99,6 +108,7 @@ sub showbranchable ($$) {
 	$template->param(gitanonurl => gitanonurl());
 	$template->param(hostname => $config{hostname});
 	$template->param(branchable => $config{branchable});
+	$template->param(anonpush => $config{anonpush});
 	$template->param(controlsitecgiurl => $config{controlsitecgiurl});
 	IkiWiki::printheader($session);
 	print IkiWiki::cgitemplate($cgi, 'Branchable', $template->output);
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 8f6b65e..6e4d034 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -7,9 +7,10 @@ called for.. Or is it?
 How about this:
 
 * Add a "ikiwiki-anon" user, with locked password etc. Run git-daemon
-  as that user.
+  as that user. (done)
 * In branchable plugin, add a new "anonpush" config setting.
   Should default to false, and be forced to false when branchable=0.
+  (done)
 * Set `untrusted_committers` to ikiwiki-anon on all sites by default.
 * Make ~/source.git be in group ikiwiki-anon, and mode 2775, when
   branchable=1. (When branchable=0, keep current mode of 0700.)
@@ -33,4 +34,4 @@ How about this:
   (Already done, and spot checks indicate it's working; also tested
   that it works when the sourcedir is temporarily 700 and a commit comes
   in.)
-* Update do=branchable page to say when anonpush is enabled.
+* Update do=branchable page to say when anonpush is enabled. (done)
diff --git a/templates/branchable.tmpl b/templates/branchable.tmpl
index 79ca0f4..22dc2a3 100644
--- a/templates/branchable.tmpl
+++ b/templates/branchable.tmpl
@@ -7,6 +7,10 @@ Anyone can access its anonymous git repository:
 <pre>
 git clone <TMPL_VAR GITANONURL>
 </pre>
+<TMPL_IF ANONPUSH>
+Modifications to the site can be pushed to the anonymous git repository,
+but will be subject to verification.
+</TMPL_IF>
 </TMPL_IF>
 </p>
 

update
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 425db70..8f6b65e 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -11,7 +11,8 @@ How about this:
 * In branchable plugin, add a new "anonpush" config setting.
   Should default to false, and be forced to false when branchable=0.
 * Set `untrusted_committers` to ikiwiki-anon on all sites by default.
-* Make ~/source.git be in group ikiwiki-anon, and mode 2775, by default.
+* Make ~/source.git be in group ikiwiki-anon, and mode 2775, when
+  branchable=1. (When branchable=0, keep current mode of 0700.)
   (This could perhaps be improved to only when anonpush is enabled, but
   either way, git-daemon is going to have write access to a lot of sites..
   And if it's compromised it does not need to run the test hook either.)

update
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index 318de0e..425db70 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -15,6 +15,12 @@ How about this:
   (This could perhaps be improved to only when anonpush is enabled, but
   either way, git-daemon is going to have write access to a lot of sites..
   And if it's compromised it does not need to run the test hook either.)
+* Ensure that subdirs of ~/source.git are also group ikiwiki-anon, 
+  and that files are also in that group. (Dirs need to be in the group
+  so it can make new files.. Some files need to be in the group so it can
+  modify. Some files git creates but never modifies, and others it
+  may unlink and rewrite; in either case the file group doesn't really
+  matter. Git should do the right thing after initial group setup.)
 * When anonpush is enabled, enable `git_test_receive_wrapper` -- 
   and when it's disabled, disable it, and delete the hook. (That
   hook slows down all commits some.. a C wrapper that

thought
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index c1aa3cd..318de0e 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -26,3 +26,4 @@ How about this:
   (Already done, and spot checks indicate it's working; also tested
   that it works when the sourcedir is temporarily 700 and a commit comes
   in.)
+* Update do=branchable page to say when anonpush is enabled.

tentative design for anonpush
diff --git a/doc/todo/anonymous_git_push.mdwn b/doc/todo/anonymous_git_push.mdwn
index eb87d76..c1aa3cd 100644
--- a/doc/todo/anonymous_git_push.mdwn
+++ b/doc/todo/anonymous_git_push.mdwn
@@ -1,3 +1,28 @@
+<http://ikiwiki.info/tips/untrusted_git_push/>
+
 The main sticking point on this is that git-daemon runs as a single user,
 who cannot write to all the sites. Seems some sort of suid wrapper is
-called for..
+called for.. Or is it?
+
+How about this:
+
+* Add a "ikiwiki-anon" user, with locked password etc. Run git-daemon
+  as that user.
+* In branchable plugin, add a new "anonpush" config setting.
+  Should default to false, and be forced to false when branchable=0.
+* Set `untrusted_committers` to ikiwiki-anon on all sites by default.
+* Make ~/source.git be in group ikiwiki-anon, and mode 2775, by default.
+  (This could perhaps be improved to only when anonpush is enabled, but
+  either way, git-daemon is going to have write access to a lot of sites..
+  And if it's compromised it does not need to run the test hook either.)
+* When anonpush is enabled, enable `git_test_receive_wrapper` -- 
+  and when it's disabled, disable it, and delete the hook. (That
+  hook slows down all commits some.. a C wrapper that
+  just checks the uid of the committer would allow speeding it back up.)
+* When anonpush is enabled, run: `git config daemon.receivepack = true`
+  (and undo when disabled).
+* Set core.sharedRepository to true, in all bare repos. Needed to ensure
+  dirs in bare repo are always made writable by group.
+  (Already done, and spot checks indicate it's working; also tested
+  that it works when the sourcedir is temporarily 700 and a commit comes
+  in.)

rootconfig
diff --git a/Makefile b/Makefile
index 08c4fff..962850b 100644
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,7 @@ install:
 	install -d $(BINDIR)
 	install -m 0755 $(SCRIPTS) $(BINS) $(BINDIR)
 
-	install -d $(ETCDIR)/ikiwiki-hosting
+	install -d $(ETCDIR)/ikiwiki-hosting/config
 	install -m 0644 ikiwiki-hosting.conf $(ETCDIR)/ikiwiki-hosting
 	install -d $(ETCDIR)/ikiwiki-hosting/autosetup
 	cp autosetup/* $(ETCDIR)/ikiwiki-hosting/autosetup
diff --git a/debian/changelog b/debian/changelog
index bef85c2..7b20c11 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -8,6 +8,8 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
   * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore,
     public_html/, source/, apache/.
   * Lock down source.git, unless branchability is enabled.
+  * The apache.conf.tmpl files are no longer read from the user's home
+    directory, but instead from /etc/ikiwiki-hosting/config/$username/.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
     to upgrade them is highly recommended. 
diff --git a/debian/ikiwiki-hosting-common.install b/debian/ikiwiki-hosting-common.install
index a39ce7e..f63daf3 100644
--- a/debian/ikiwiki-hosting-common.install
+++ b/debian/ikiwiki-hosting-common.install
@@ -1,4 +1,5 @@
 etc/ikiwiki-hosting/ikiwiki-hosting.conf
 etc/ikiwiki-hosting/templates
+etc/ikiwiki-hosting/config
 usr/share/perl5
 var/log
diff --git a/doc/design.mdwn b/doc/design.mdwn
index 86f3095..6ff36ad 100644
--- a/doc/design.mdwn
+++ b/doc/design.mdwn
@@ -17,8 +17,7 @@ and data files associated with the site are stored in the user's home
 directory.
 
 Outside the home directory, runtime files for the site are managed in
-`/var/www/`, `/var/log/ikiwiki-hosting/`, and
-`/etc/apache2/sites-available/`.
+`/var/www/`, `/var/log/ikiwiki-hosting/`, and [[apacheconfig]].
 
 The home directory has these contents:
 
@@ -27,7 +26,6 @@ The home directory has these contents:
 * `source.git` - bare git repo (or similar for other VCS)
 * `source` - checkout of the wiki's source
 * `ikiwiki.setup` - config file for the site
-* `apache.conf.tmpl` - apache config fragment (see [[apacheinclude]])
 * `apache` - directory contains optional apache configs
    ssl certs, etc)
 * `tmp` - per-user temp directory
diff --git a/doc/design/apacheconfig.mdwn b/doc/design/apacheconfig.mdwn
new file mode 100644
index 0000000..44e1279
--- /dev/null
+++ b/doc/design/apacheconfig.mdwn
@@ -0,0 +1,41 @@
+A site's apache configuration is automatically generated in
+`/etc/apache2/sites-available/ikisite-*`.
+
+It can be useful to tweak apache settings for a single site. To allow this,
+use `/etc/ikiwiki-hosting/config/$username/apache.conf.tmpl`
+
+This is an apache2 config fragment, that, if present, is inserted into the
+site's generated apache config file by `ikisite enable`. Remeber to run
+`ikisite enable` if modifying it.
+
+It is inserted inside the `<VirtualHost>` tag in the apache config file,
+at the end. So it can override anything that comes before, add additional
+settings, etc. It is actually a HTML::Template template, and can contain
+the same variables as `apache-site.tmpl`. (HOSTNAME, HOME, etc.)
+
+Example:
+
+	<Directory <TMPL_VAR HOME>/public_html>
+		Options +Foo
+		AuthName "<TMPL_VAR HOSTNAME>"
+		AuthType Basic
+		AuthUserFile <TMPL_VAR HOME>/apache/htpasswd
+		Require valid-user
+	</Directory>
+
+Note the use of "+" to add to the default Options, rather than overriding it.
+
+**Crazy** example to add another, custom vhost:
+
+	</VirtualHost>
+
+	<VirtualHost>
+	...
+	</VirtualHost>
+
+Note that the advantage of using this, over just allowing a htaccess file,
+is that the site's owner could modify a htaccess file, but can't modify
+this file. This avoids needing to worry about security issues with htaccess
+files. (Also, apache's documentation warns about performance implications
+of enabling htaccess files.) Of course, if a htaccess file is really wanted
+for a given site, this file can be used to enable it.
diff --git a/doc/design/apacheinclude.mdwn b/doc/design/apacheinclude.mdwn
deleted file mode 100644
index ba7d59e..0000000
--- a/doc/design/apacheinclude.mdwn
+++ /dev/null
@@ -1,41 +0,0 @@
-The `~/apache.conf.tmpl` file is an apache2 config fragment, that, if
-present, is inserted into the site's generated apache config file by
-`ikisite enable`. Remeber to run `ikisite enable` if modifying it.
-
-It is inserted inside the `<VirtualHost>` tag in the apache config file,
-at the end. So it can override anything that comes before, add additional
-settings, etc. It is actually a HTML::Template template, and can contain
-the same variables as `apache-site.tmpl`. (HOSTNAME, HOME, etc.)
-
-Example:
-
-	<Directory <TMPL_VAR HOME>/public_html>
-		Options +Foo
-		AuthName "<TMPL_VAR HOSTNAME>"
-		AuthType Basic
-		AuthUserFile <TMPL_VAR HOME>/apache/htpasswd
-		Require valid-user
-	</Directory>
-
-Note the use of "+" to add to the default Options, rather than overriding it.
-
-**Crazy** example to add another, custom vhost:
-
-	</VirtualHost>
-
-	<VirtualHost>
-	...
-	</VirtualHost>
-
-## security
-
-Since this file configures the global apache, it should be owned by root,
-not by the site user. ikisite refuses to use the file if it is not owned by
-root.
-
-Note that the advantage of using this, over just allowing a htaccess file,
-is that the site's owner could modify a htaccess file, but can't modify
-this file. This avoids needing to worry about security issues with htaccess
-files. (Also, apache's documentation warns about performance implications
-of enabling htaccess files.) Of course, if a htaccess file is really wanted
-for a given site, this file can be used to enable it.
diff --git a/doc/design/backupformat.mdwn b/doc/design/backupformat.mdwn
index f47ea23..ee9726c 100644
--- a/doc/design/backupformat.mdwn
+++ b/doc/design/backupformat.mdwn
@@ -10,10 +10,12 @@ contains eg, passwords.
 * other files can be included in the tarball using the same
   filename as is used in the home directory. For example as
   `source/.ikiwiki/indexdb` and `source/.ikiwiki/userdb`.
+* the contents of the `rootconfig` directory in the tarball
+  are installed into `/etc/ikiwiki-hosting/config/$user`
 
 This format allows the backup to be created by serializing the vcs
 and then just tarring up selected files from the home directory of the
-site.
+site, along with any files from `/etc/ikiwiki-hosting/config/$user`.
 
 ## rsyncability
 
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 78cb057..a35737b 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -10,6 +10,8 @@ and so on.
 For this page I'll assume that the user trying to escalate privilege is
 `b-example`.
 
+> All issues raised here are [[done]] --[[Joey]] 
+
 [[!toc ]]
 
 # open issues
@@ -101,6 +103,13 @@ If the `HTML::Template` functionality is useful in practice (is it?),
 >> backups could be modified to include the site's file from /etc in them,
 >> and restore to restore them, I suppose.. --[[Joey]]
 
+>> Ok, I have done something based on this but without the includes.
+>> I did keep the `HTML::Template`
+>> functionality, it's useful to have branchable sites whose apache config
+>> tweaks follow them when branched. Generalized to a
+>> `/etc/ikiwiki-hosting/config/$user/` directory for root-owned configs.
+>> --[[Joey]] 
+
 # resolved issues
 
 ## IkiWiki CGI
diff --git a/ikisite b/ikisite
index f9376dd..f255ac2 100755
--- a/ikisite

(Diff truncated)
thoughts
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index b8b4a4d..78cb057 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -33,6 +33,23 @@ an untrusted backup is currently dangerous.
 >> to become `b-example` via sudo doesn't let him escalate privileges
 >> any further than that. --[[smcv]]
 
+>>> Ok, so the risk with apache.conf.tmpl is that while it's owned by root,
+>>> the site user can move it out of the way. This allows three attacks:
+>>> 
+>>> 1. find a somehow exploitable apache.conf.tmpl on the host that's owned
+>>>    by root, and move it into place.
+>>> 2. race `ikisite enable`, which test the file owner and then reads it,
+>>>    so it thinks it's reading a file owned by root.
+>>> 3. move it out of the way, put in a bad file, let `ikisite backup`, 
+>>>    back it up, and then use some method to get the site restored;
+>>>    restore will trust the file and make it owned by root.
+>>>
+>>> 1 is unlikely, 3 can be fixed in `ikisite backup` perhaps, 2 should
+>>> be solvable, with some difficulty (I think that hard linking the file
+>>> and checking the owner of the hard link, the reading the hard link,
+>>> would work?) Still, keeping the file in $HOME is not looking very
+>>> smart. --[[Joey]] 
+
 Since only root can set this up anyway, I'd personally be inclined to treat
 it as server-wide configuration that should be backed up as part of `/etc`,
 
@@ -48,6 +65,13 @@ it as server-wide configuration that should be backed up as part of `/etc`,
 > ikiwiki.setup hold the configuration for those variables.
 > --[[Joey]]
 
+>> My feeling about moving the config to a site-wide template file(s)
+>> that are then enabled by ikiwiki.setup settings is that it's great
+>> for common things, but it loses a lot of easy flexability of being able
+>> to go in and use the full power of apache to tweak sites, in an ad-hoc
+>> way. That is flexability and power that I'm uncertian about sacrificing.
+>> --[[Joey]] 
+
 create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:
 
     <VirtualHost *:80>
@@ -71,6 +95,12 @@ If the `HTML::Template` functionality is useful in practice (is it?),
 
 > I haven't done this on my branch so far. --[[smcv]]
 
+>> This is fine, except it adds a second thing that needs to be managed
+>> and transferred along with ikisite backups to move sites. It's important
+>> to me that ikisite sites be self-contained at the backup level. Now, the
+>> backups could be modified to include the site's file from /etc in them,
+>> and restore to restore them, I suppose.. --[[Joey]]
+
 # resolved issues
 
 ## IkiWiki CGI

lock down apache/
diff --git a/debian/changelog b/debian/changelog
index b9a2d8e..bef85c2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,7 +6,7 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     and using suexec with cgi programs moved to /var/www.
     Thanks, Simon McVittie
   * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore,
-    public_html/, source/.
+    public_html/, source/, apache/.
   * Lock down source.git, unless branchability is enabled.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 753773d..3bafb3e 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -18,7 +18,8 @@ down to 700?
 
 Things that need to be readable by other than the site user:
 
-* `~/apache.conf` and `~/apache` (owned by root:root)
+* `~/apache.conf` (owned by root:root, and should not contain sensative
+  stuff; the same info is filled into /etc/apache2 config files anyway)
 
 Things that are already appropriatly locked-down:
 
@@ -37,5 +38,6 @@ Things that are already appropriatly locked-down:
 * `~/source` as a whole
 * `~/source.git` (when branchability is disabled)
 * `~/customersite/`
+* `~/apache/` (750; group www-data)
 
 [[done]]
diff --git a/ikisite b/ikisite
index c012466..f9376dd 100755
--- a/ikisite
+++ b/ikisite
@@ -327,6 +327,11 @@ sub restore {
 	# Except, apache.conf.tmpl must be owned by root to be used.
 	shell("chown", "root:root", "apache.conf.tmpl")
 		if -e "apache.conf.tmpl";
+	# And, apache/ should be readable by www-data.
+	if (-d "apache") {
+		shell("chgrp", "www-data", "apache");
+		chmod(0750, "apache") || error "chmod apache: $!";
+	}
 
 	if (! $options{'no-sshkeys'}) {
 		# Restore ssh last, to ensure the git repo is set up
@@ -2403,6 +2408,12 @@ sub upgrade {
 			chmod(0700, "$home/$dir") || error "chmod $home/$dir: $!";
 		}
 	}
+	foreach my $dir ("apache") {
+		if (-e "$home/$dir") {
+			shell("chown", "$user:www-data", "$home/$dir");
+			chmod(0750, "$home/$dir") || error "chmod $home/$dir: $!";
+		}
+	}
 
 	# Disable and re-enable to write new apache configs, etc.
 	disable($hostname, temporary => 1);

typo
diff --git a/doc/design/customersite.mdwn b/doc/design/customersite.mdwn
index bf619e0..2f1d93e 100644
--- a/doc/design/customersite.mdwn
+++ b/doc/design/customersite.mdwn
@@ -30,7 +30,7 @@ in their filename.
 This design is intended to allow changes to be made to multiple branches
 of the customersite, and merged together with little chance of conflicts.
 Git's union merge driver can be used to merge the list files. Other
-fields may have customer merge drivers.
+fields may have custom merge drivers.
 
 ## locking
 

lock down perms of customersite checkout
umask is used to avoid it ever existing with unsafe perms
diff --git a/IkiWiki/Customer.pm b/IkiWiki/Customer.pm
index c3586ec..f5b6f5e 100644
--- a/IkiWiki/Customer.pm
+++ b/IkiWiki/Customer.pm
@@ -35,7 +35,9 @@ sub basedir (;$) {
 		$customersite);
 	return unless defined $username && length $username;
 	my $gitsshurl="ssh://$username\@$customersite/";
+	my $origumask=umask(077);
 	eval {IkiWiki::Hosting::shell("git", "clone", $gitsshurl, $dir)};
+	umask($origumask);
 	if ($@ || ! -d $dir) {
 		# This is bad, try to make the admins aware of the problem.
 		IkiWiki::Hosting::syslog("failed to clone $gitsshurl to $dir",
diff --git a/debian/changelog b/debian/changelog
index 52170cf..b9a2d8e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -10,7 +10,7 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
   * Lock down source.git, unless branchability is enabled.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
-    to upgrade them is highly recommended.
+    to upgrade them is highly recommended. 
 
  -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
 
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 4680b53..753773d 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -36,5 +36,6 @@ Things that are already appropriatly locked-down:
 * `~/source/.ikiwiki/gitweb*` (with suexec changes, gitweb runs as user)
 * `~/source` as a whole
 * `~/source.git` (when branchability is disabled)
+* `~/customersite/`
 
 [[done]]

lock down source.git when appropriate
diff --git a/IkiWiki/Plugin/branchable.pm b/IkiWiki/Plugin/branchable.pm
index acc1c8a..459ae62 100644
--- a/IkiWiki/Plugin/branchable.pm
+++ b/IkiWiki/Plugin/branchable.pm
@@ -124,7 +124,8 @@ sub disable {
 sub setbranchable {
 	# When the branchable setting is changed, we need to
 	# touch or remove the git-daemon-export-ok flag file,
-	# and the symlink to gitweb.conf.
+	# and the symlink to gitweb.conf, and tweak the permissions
+	# of the git repo.
 	# 
 	# For added evil, let's parse the git_wrapper to
 	# figure out where the git repository is!
@@ -138,10 +139,12 @@ sub setbranchable {
 			close FLAG;
 			unlink($gitweb_conf_file); # force refresh symlink
 			symlink("$gitweb_conf_file.real", $gitweb_conf_file);
+			chmod(0755, $repo) || error "chmod $repo: $!";
 		}
 		else {
 			unlink($flagfile);
 			unlink($gitweb_conf_file);
+			chmod(0700, $repo) || error "chmod $repo: $!";
 		}
 	}
 }
diff --git a/debian/changelog b/debian/changelog
index cb56499..52170cf 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,7 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     Thanks, Simon McVittie
   * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore,
     public_html/, source/.
+  * Lock down source.git, unless branchability is enabled.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
     to upgrade them is highly recommended.
diff --git a/debian/control b/debian/control
index 4c91eb4..7bc1be8 100644
--- a/debian/control
+++ b/debian/control
@@ -21,7 +21,7 @@ Description: ikiwiki hosting: common files
 
 Package: ikiwiki-hosting-web
 Architecture: any
-Depends: ${misc:Depends}, ${perl:Depends},
+Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}
 	ikiwiki-hosting-common,
 	ikiwiki (>= 3.20100723),
 	gcc | c-compiler,
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index a4ecc6d..4680b53 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -18,13 +18,7 @@ down to 700?
 
 Things that need to be readable by other than the site user:
 
-* `~/source.git`
-
-> `git-daemon` still
-> needs read access to each *branchable* site's `source.git` - perhaps
-> the branchable plugin could set/clear bits 005 as appropriate?
-
-* `~/apache.conf` and `~/apache` (could be root:root)
+* `~/apache.conf` and `~/apache` (owned by root:root)
 
 Things that are already appropriatly locked-down:
 
@@ -41,3 +35,6 @@ Things that are already appropriatly locked-down:
   located in here)
 * `~/source/.ikiwiki/gitweb*` (with suexec changes, gitweb runs as user)
 * `~/source` as a whole
+* `~/source.git` (when branchability is disabled)
+
+[[done]]
diff --git a/ikisite b/ikisite
index bfa89bf..9d01137 100755
--- a/ikisite
+++ b/ikisite
@@ -1343,13 +1343,15 @@ sub enable {
 			open(FLAG, ">", $flagfile);
 			close FLAG;
 			shell("chown", "$user:$user", $flagfile);
+			chmod(0755, "$home/source.git") || error "chmod $home/source.git: $!";
 		}
 		else {
 			unlink($flagfile);
+			chmod(0700, "$home/source.git") || error "chmod $home/source.git: $!";
 		}
 
 		# Setup gitweb.
-		# An environment variable to points gitweb it to
+		# An environment variable to points gitweb to
 		# this file. We make it a symlink pointing at the real 
 		# file, and only enable the link for branchable sites.
 		my $gitweb_conf_file=srcdir($hostname)."/.ikiwiki/gitweb.conf";

lock down source/
confirmed that gitweb still works, editing still works
diff --git a/debian/changelog b/debian/changelog
index 029f05f..cb56499 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,7 +6,7 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     and using suexec with cgi programs moved to /var/www.
     Thanks, Simon McVittie
   * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore,
-    public_html.
+    public_html/, source/.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
     to upgrade them is highly recommended.
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index e3d5295..a4ecc6d 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -16,34 +16,15 @@ down to 700?
 
 ---
 
-Things that are world-readable and need not be:
-
-* `~/source/.ikiwiki` (other than the gitweb config files randomly
-  located in here)
-* `~/source` as a whole
-
 Things that need to be readable by other than the site user:
 
-* `~/source/.ikiwiki/gitweb*`
 * `~/source.git`
 
-> It seems odd that the gitweb stuff is in `.ikiwiki`: it'd
-> make more sense to put it at top level, or even in `source.git`?
->
-> However, if you run each user's gitweb under `suexec` to avoid
-> [[privilege escalation]] to www-data, then only the site user needs
-> access to gitweb config as a nice side-effect. `git-daemon` still
+> `git-daemon` still
 > needs read access to each *branchable* site's `source.git` - perhaps
 > the branchable plugin could set/clear bits 005 as appropriate?
->
-> I've started to lock down permissions on the `smcv` branch in my
-> git repository. Not done yet: source.git, public_html. --[[smcv]]
-
-* `~/apache.conf` and `~/apache` (could be 640 user:www-data)
 
-> apache.conf.tmpl is root-equivalent, so it needs to be root:root.
-> As noted on [[privilege escalation]] I'm not sure that having it
-> in the homedir is such a great idea... --[[smcv]]
+* `~/apache.conf` and `~/apache` (could be root:root)
 
 Things that are already appropriatly locked-down:
 
@@ -56,3 +37,7 @@ Things that are already appropriatly locked-down:
 * `~/.git/`
 * `~/tmp/`
 * `~/public_html` (750; group www-data)
+* `~/source/.ikiwiki` (other than the gitweb config files randomly
+  located in here)
+* `~/source/.ikiwiki/gitweb*` (with suexec changes, gitweb runs as user)
+* `~/source` as a whole
diff --git a/ikisite b/ikisite
index d0ba5ad..bfa89bf 100755
--- a/ikisite
+++ b/ikisite
@@ -84,6 +84,7 @@ sub create {
 	runas(username($hostname), sub {
 		shell("ikiwiki", "-setup", $autosetup);
 		chmod(0600, "$home/ikiwiki.setup") || error "chmod $home/ikiwiki.setup: $!";
+		chmod(0700, "$home/source") || error "chmod $home/source: $!";
 	});
 	
 	if ($options{vcs} eq "git") {
@@ -301,6 +302,7 @@ sub restore {
 		shell("git", "clone", $repository, "home-tmp",
 			"--branch", "setup");
 
+		chmod(0700, "source") || error "chmod source: $!";
 		chmod(0700, "home-tmp/.git") || error "chmod home-tmp/.git: $!";
 		chmod(0600, "home-tmp/.gitignore") || error "chmod home-tmp/.gitignore: $!"
 			if -e "home-tmp/.gitignore";
@@ -2393,7 +2395,7 @@ sub upgrade {
 		}
 	}
 	# Dir perms were locked down.
-	foreach my $dir (".git") {
+	foreach my $dir (".git", "source") {
 		if (-e "$home/$dir") {
 			chmod(0700, "$home/$dir") || error "chmod $home/$dir: $!";
 		}

lock down public_html
I could find no better place to do it than ikisite enable.
diff --git a/debian/changelog b/debian/changelog
index ebeed8c..029f05f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,7 +5,8 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     home directory to /var/log/ikiwiki-hosting/,
     and using suexec with cgi programs moved to /var/www.
     Thanks, Simon McVittie
-  * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore
+  * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore,
+    public_html.
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
     to upgrade them is highly recommended.
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 10403b3..e3d5295 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -24,11 +24,6 @@ Things that are world-readable and need not be:
 
 Things that need to be readable by other than the site user:
 
-* `~/public_html`
-
-> `public_html` only needs to be written by the site user and read by www-data,
-> strictly speaking. It could be 750. --[[smcv]]
-
 * `~/source/.ikiwiki/gitweb*`
 * `~/source.git`
 
@@ -60,3 +55,4 @@ Things that are already appropriatly locked-down:
 * `~/.gitconfig`, `~/.gitignore`
 * `~/.git/`
 * `~/tmp/`
+* `~/public_html` (750; group www-data)
diff --git a/ikisite b/ikisite
index 6ae9faf..d0ba5ad 100755
--- a/ikisite
+++ b/ikisite
@@ -1314,6 +1314,14 @@ sub enable {
 	assert_wrapper_denied();
 
 	my $user=username($hostname);
+	my $home=homedir($hostname);
+	
+	# Lock down the public_html directory so only the site user and
+	# www-data can access it.
+	my $uid=int getpwnam($user);
+	my $www_data_gid=int getgrnam("www-data");
+	chown($uid, $www_data_gid, "$home/public_html") || error "chown $home/public_html: $!";
+	chmod(0750, "$home/public_html") || error "chmod $home/public_html: $!";
 
 	my $vcs=getsetup($hostname, "rcs");
 	if ($vcs eq "git") {
@@ -1363,7 +1371,7 @@ sub enable {
 		my $git_description=repository($hostname)."/description";
 		outtemplate("$gitweb_conf_file.real", "gitweb.conf.tmpl",
 			user => $user,
-			home => homedir($hostname),
+			home => $home,
 			destdir => destdir($hostname),
 			cgidir => cgidir($hostname),
 			logdir => logdir($hostname),

fix perms of .git, .gitignore when restoring
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 54de965..10403b3 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -58,4 +58,5 @@ Things that are already appropriatly locked-down:
 * backups
 * `~/ikiwiki.setup`
 * `~/.gitconfig`, `~/.gitignore`
-* `~/.git`
+* `~/.git/`
+* `~/tmp/`
diff --git a/ikisite b/ikisite
index 4b38501..6ae9faf 100755
--- a/ikisite
+++ b/ikisite
@@ -300,6 +300,10 @@ sub restore {
 		shell("git", "clone", $repository, "source");
 		shell("git", "clone", $repository, "home-tmp",
 			"--branch", "setup");
+
+		chmod(0700, "home-tmp/.git") || error "chmod home-tmp/.git: $!";
+		chmod(0600, "home-tmp/.gitignore") || error "chmod home-tmp/.gitignore: $!"
+			if -e "home-tmp/.gitignore";
 	}
 	else {
 		error "restore not implemented for $vcs";

lock down .git, .gitconfig, .gitignore
Have not tested that these persist across branch or backup/restore.
diff --git a/debian/changelog b/debian/changelog
index 3203834..ebeed8c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,7 +5,7 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     home directory to /var/log/ikiwiki-hosting/,
     and using suexec with cgi programs moved to /var/www.
     Thanks, Simon McVittie
-  * Lock down permissions of ikiwiki.setup.
+  * Lock down permissions of ikiwiki.setup, .git, .gitconfig, .gitignore
   * Note that previously created sites will continue using
     the old locations and permissions. Using "ikisite upgrade"
     to upgrade them is highly recommended.
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 4bf3f06..54de965 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -21,8 +21,6 @@ Things that are world-readable and need not be:
 * `~/source/.ikiwiki` (other than the gitweb config files randomly
   located in here)
 * `~/source` as a whole
-* `~/.git`
-* `~/.gitconfig`, `~/.gitignore`
 
 Things that need to be readable by other than the site user:
 
@@ -57,5 +55,7 @@ Things that are already appropriatly locked-down:
 * logs
 * `~/.ssh/authorized_keys`
 * `~/.ikisite-nonce` (transient file)
-* `~/ikiwiki.setup`
 * backups
+* `~/ikiwiki.setup`
+* `~/.gitconfig`, `~/.gitignore`
+* `~/.git`
diff --git a/ikisite b/ikisite
index 113fdc7..68aa4d8 100755
--- a/ikisite
+++ b/ikisite
@@ -1266,6 +1266,7 @@ sub usercreate {
 	runas(username($hostname), sub {
 		shell(qw{git config --global user.name admin});
 		shell(qw{git config --global user.email}, $config{adminemail});
+		chmod(0600, "$home/.gitconfig") || error "chmod $home/.gitconfig: $!";
 	});
 }
 
@@ -1656,9 +1657,11 @@ sub createsetupbranch {
 				error ".git directory already exists";
 			}
 			shell("git", "init");
+			chmod(0700, ".git") || error "chmod .git: $!";
 			# convince git to start committing to setup branch
 			writefile(".git/HEAD", ".", "ref: refs/heads/setup\n");
 			writefile(".gitignore", ".", join("\n", @ignores)."\n");
+			chmod(0600, ".gitignore") || error "chmod .gitignore: $!";
 			shell("git", "remote", "add", "origin", repository($hostname));
 	
 			commitsetup($hostname, message => "initial commit of setup files");
@@ -2372,7 +2375,17 @@ sub upgrade {
 	}
 
 	# File perms were locked down.
-	chmod(0600, "$home/ikiwiki.setup") || error "chmod $home/ikiwiki.setup: $!";
+	foreach my $file ("ikiwiki.setup", ".gitconfig", ".gitignore") {
+		if (-e "$home/$file") {
+			chmod(0600, "$home/$file") || error "chmod $home/$file: $!";
+		}
+	}
+	# Dir perms were locked down.
+	foreach my $dir (".git") {
+		if (-e "$home/$dir") {
+			chmod(0700, "$home/$dir") || error "chmod $home/$dir: $!";
+		}
+	}
 
 	# Disable and re-enable to write new apache configs, etc.
 	disable($hostname, temporary => 1);

lock down ikiwiki.setup
Tested, and file mode is preserved when changing setup via the web
interface.
Backup/restore should preserve all files modes too.
diff --git a/debian/changelog b/debian/changelog
index 85a5fb6..3203834 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,9 +5,10 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     home directory to /var/log/ikiwiki-hosting/,
     and using suexec with cgi programs moved to /var/www.
     Thanks, Simon McVittie
+  * Lock down permissions of ikiwiki.setup.
   * Note that previously created sites will continue using
-    the old locations. Using "ikisite upgrade" to upgrade them to the new
-    locations is highly recommended.
+    the old locations and permissions. Using "ikisite upgrade"
+    to upgrade them is highly recommended.
 
  -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
 
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 270e032..4bf3f06 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -22,7 +22,6 @@ Things that are world-readable and need not be:
   located in here)
 * `~/source` as a whole
 * `~/.git`
-* `~/ikiwiki.setup`
 * `~/.gitconfig`, `~/.gitignore`
 
 Things that need to be readable by other than the site user:
@@ -55,6 +54,8 @@ Things that need to be readable by other than the site user:
 
 Things that are already appropriatly locked-down:
 
-* `~/logs`
+* logs
 * `~/.ssh/authorized_keys`
 * `~/.ikisite-nonce` (transient file)
+* `~/ikiwiki.setup`
+* backups
diff --git a/ikisite b/ikisite
index d226612..113fdc7 100755
--- a/ikisite
+++ b/ikisite
@@ -52,6 +52,7 @@ sub create {
 
 	# Create user
 	usercreate($hostname);
+	my $home = homedir($hostname);
 
 	# Enable DNS early, to help give it time to propigate.
 	enabledns($hostname);
@@ -61,7 +62,7 @@ sub create {
 	$ENV{IKIWIKI_WIKINAME}=$options{wikiname};
 	$ENV{IKIWIKI_HOSTNAME}=$hostname;
 	$ENV{IKIWIKI_VCS}=$options{vcs};
-	$ENV{IKIWIKI_REPOSITORY}=homedir($hostname)."/source.$options{vcs}";
+	$ENV{IKIWIKI_REPOSITORY}=$home."/source.$options{vcs}";
 	$ENV{IKIWIKI_ADMIN}=$options{admin};
 	$ENV{IKIWIKI_OWNER}=$owner;
 	$ENV{IKIWIKI_CREATED}=time;
@@ -82,6 +83,7 @@ sub create {
 	$autosetup=abs_path($autosetup);
 	runas(username($hostname), sub {
 		shell("ikiwiki", "-setup", $autosetup);
+		chmod(0600, "$home/ikiwiki.setup") || error "chmod $home/ikiwiki.setup: $!";
 	});
 	
 	if ($options{vcs} eq "git") {
@@ -2369,6 +2371,9 @@ sub upgrade {
 		);
 	}
 
+	# File perms were locked down.
+	chmod(0600, "$home/ikiwiki.setup") || error "chmod $home/ikiwiki.setup: $!";
+
 	# Disable and re-enable to write new apache configs, etc.
 	disable($hostname, temporary => 1);
 	enable($hostname);

reorg
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 24cc4ee..b8b4a4d 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -10,6 +10,69 @@ and so on.
 For this page I'll assume that the user trying to escalate privilege is
 `b-example`.
 
+[[!toc ]]
+
+# open issues
+
+## apache.conf.tmpl
+
+`apache.conf.tmpl` is, if not root-equivalent, then at least `www-data`-equivalent,
+because it can set security-related Apache configuration. I've noticed that it's
+not backed up, but it *is* restored from backups and `chown`'d to root, so restoring
+an untrusted backup is currently dangerous.
+
+> `apache.conf.tmpl` *is* backed up; it's committed to the setup branch.
+> 
+> Restoring from an untrusted backup is dangerous anyway, because for
+> example `ikiwiki.setup` can be configured to make ikiwiki run arbitrary
+> code. All the dangerous stuff should be confined to the setup branch,
+> which is why pushing that branch is rejected. --[[Joey]]
+
+>> Right, but my goal with this stuff is more or less: if bob is a user
+>> with shell access and b-example is his website, giving bob permission
+>> to become `b-example` via sudo doesn't let him escalate privileges
+>> any further than that. --[[smcv]]
+
+Since only root can set this up anyway, I'd personally be inclined to treat
+it as server-wide configuration that should be backed up as part of `/etc`,
+
+> There will be frontends to configure common stuff in it later, and
+> it is site-specific apache configuration, that needs to be transferred
+> along with the site if it is, say, bundled and transferred to a different
+> server.
+> 
+> What could be done is to use `apache-site.tmpl`, and add to it variables
+> exposing and configuring stuff like htpasswd setup or whatever else
+> is needed (we have some collectd monitoring snippets in one of our
+> sites at branchable, for example). Then have
+> ikiwiki.setup hold the configuration for those variables.
+> --[[Joey]]
+
+create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:
+
+    <VirtualHost *:80>
+        ServerName <TMPL_VAR HOSTNAME>:80
+        ...
+        Include /etc/apache2/ikisite/<TMPL_VAR USER>.*.conf
+    </VirtualHost>
+
+    <VirtualHost *:80>
+        ServerName <TMPL_VAR HOSTNAME>:80
+        ...
+        Include /etc/apache2/ikisite/src.<TMPL_VAR USER>.*.conf
+    </VirtualHost>
+
+Then you can put whatever you want in those files. Note that Apache considers
+it to be a syntax error if an `Include` directory doesn't exist, but is
+perfectly happy if a glob fails to match any files.
+
+If the `HTML::Template` functionality is useful in practice (is it?),
+`ikisite` could perhaps automatically generate `foo.conf` from `foo.tmpl`.
+
+> I haven't done this on my branch so far. --[[smcv]]
+
+# resolved issues
+
 ## IkiWiki CGI
 
 If the user can remove the setuid/setgid bits from their ikiwiki.cgi wrapper
@@ -87,70 +150,6 @@ possibility of arbitrary code execution there.
 
 >> I haven't audited this thoroughly yet, but nothing jumps out at me... --[[smcv]]
 
-## apache.conf.tmpl
-
-`apache.conf.tmpl` is, if not root-equivalent, then at least `www-data`-equivalent,
-because it can set security-related Apache configuration. I've noticed that it's
-not backed up, but it *is* restored from backups and `chown`'d to root, so restoring
-an untrusted backup is currently dangerous.
-
-> `apache.conf.tmpl` *is* backed up; it's committed to the setup branch.
-> 
-> Restoring from an untrusted backup is dangerous anyway, because for
-> example `ikiwiki.setup` can be configured to make ikiwiki run arbitrary
-> code. All the dangerous stuff should be confined to the setup branch,
-> which is why pushing that branch is rejected. --[[Joey]]
-
->> Right, but my goal with this stuff is more or less: if bob is a user
->> with shell access and b-example is his website, giving bob permission
->> to become `b-example` via sudo doesn't let him escalate privileges
->> any further than that. --[[smcv]]
-
-Since only root can set this up anyway, I'd personally be inclined to treat
-it as server-wide configuration that should be backed up as part of `/etc`,
-
-> There will be frontends to configure common stuff in it later, and
-> it is site-specific apache configuration, that needs to be transferred
-> along with the site if it is, say, bundled and transferred to a different
-> server.
-> 
-> What could be done is to use `apache-site.tmpl`, and add to it variables
-> exposing and configuring stuff like htpasswd setup or whatever else
-> is needed (we have some collectd monitoring snippets in one of our
-> sites at branchable, for example). Then have
-> ikiwiki.setup hold the configuration for those variables.
-> --[[Joey]]
-
-create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:
-
-    <VirtualHost *:80>
-        ServerName <TMPL_VAR HOSTNAME>:80
-        ...
-        Include /etc/apache2/ikisite/<TMPL_VAR USER>.*.conf
-    </VirtualHost>
-
-    <VirtualHost *:80>
-        ServerName <TMPL_VAR HOSTNAME>:80
-        ...
-        Include /etc/apache2/ikisite/src.<TMPL_VAR USER>.*.conf
-    </VirtualHost>
-
-Then you can put whatever you want in those files. Note that Apache considers
-it to be a syntax error if an `Include` directory doesn't exist, but is
-perfectly happy if a glob fails to match any files.
-
-If the `HTML::Template` functionality is useful in practice (is it?),
-`ikisite` could perhaps automatically generate `foo.conf` from `foo.tmpl`.
-
-> I haven't done this on my branch so far. --[[smcv]]
-
-## `~/apache/`
-
-I don't know what you put in here in practice, so I don't know whether
-it can cause privilege escalation :-)
-
-> Currently, only htpasswd files. --[[Joey]]
-
 ## logs
 
 <http://httpd.apache.org/docs/2.2/misc/security_tips.html#serverroot> says:
@@ -200,3 +199,10 @@ would break:
 Probably not worth it...
 
 > I agree, this is not an approach I really want to pursue. --[[Joey]]
+
+## `~/apache/`
+
+I don't know what you put in here in practice, so I don't know whether
+it can cause privilege escalation :-)
+
+> Currently, only htpasswd files. Exploitability unlikely. --[[Joey]]

update
diff --git a/doc/design.mdwn b/doc/design.mdwn
index a39965d..86f3095 100644
--- a/doc/design.mdwn
+++ b/doc/design.mdwn
@@ -13,9 +13,13 @@ The primary url of a site uses either its hostname, or one of its aliases.
 Ikiwiki is configured to use this in its url and cgiurl.
 
 From the hostname, a unique [[username]] is derived. Ikiwiki runs as that user,
-and all data files associated with the site are stored in the user's home
+and data files associated with the site are stored in the user's home
 directory.
 
+Outside the home directory, runtime files for the site are managed in
+`/var/www/`, `/var/log/ikiwiki-hosting/`, and
+`/etc/apache2/sites-available/`.
+
 The home directory has these contents:
 
 * `public_html` - the site's html is here

ikisite upgrade
diff --git a/debian/changelog b/debian/changelog
index 40ef0e0..85a5fb6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -6,9 +6,8 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     and using suexec with cgi programs moved to /var/www.
     Thanks, Simon McVittie
   * Note that previously created sites will continue using
-    the old locations. Manually migrating to the new
-    layout is recommended. See 
-    /usr/share/doc/ikiwiki-hosting-common/migration.html for a checklist.
+    the old locations. Using "ikisite upgrade" to upgrade them to the new
+    locations is highly recommended.
 
  -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
 
diff --git a/doc/migration.html b/doc/migration.html
deleted file mode 100644
index ba5e1a0..0000000
--- a/doc/migration.html
+++ /dev/null
@@ -1,12 +0,0 @@
-The location of log files and cgi programs has changed to fix possible
-[[security/privilege_escalation]] problems.
-
-New sites will use the new location.
-
-Unless manually migrated, existing sites will continue to use the old
-locations. How well that works is unknown.
-
-This is a possibly incomplete checklist for how to migrate a site to
-use the new locations:
-
-
diff --git a/ikisite b/ikisite
index 1462482..fbc1e5d 100755
--- a/ikisite
+++ b/ikisite
@@ -2304,6 +2304,81 @@ sub checksite {
 	}
 }
 
+sub meta_upgrade {
+	required => [qw{hostname}],
+	options => [],
+	description => "upgrade a site to new layout",
+	section => "primary",
+}
+sub upgrade {
+	my $hostname=lc(shift);
+
+	assert_root();
+
+	my $home=homedir($hostname);
+
+	my @cleanup;
+		
+	my $user=username($hostname);
+	my $uid=int getpwnam($user);
+	my $gid=int getgrnam($user);
+
+	# logs moved
+	if (-d "$home/logs") {
+		my $newlogdir=logdir($hostname, 1);
+		if (! -d $newlogdir) {
+			mkdir($newlogdir) || error "mkdir $newlogdir: $!";
+			chmod(0750, "$newlogdir") || error "chmod $newlogdir: $!";
+		}
+		foreach my $file (<$home/logs/*>) {
+			my $basefile=IkiWiki::basename($file);
+			my $dest="$newlogdir/$basefile";
+			if (! -e $dest) {
+				shell("mv", "-f", $file, $dest);
+			}
+			else {
+				print STDERR "warning: $file not moved to $basefile, which already exists\n";
+			}
+		}
+		rmdir("$home/logs");
+
+		# Only ikisite log is writable by the site user's gid.
+		foreach my $file (".", "ikisite.log") {
+			chown(0, $gid, "$newlogdir/$file")
+				|| error "chown $newlogdir/$file: $!";
+		}
+	}
+
+	# cgi moved, and is no longer suid, as suidexec is used.
+	my $oldcgi=cgidir($hostname)."/ikiwiki.cgi";
+	if (-e $oldcgi) {
+		push @cleanup, $oldcgi;
+
+		my $cgidir=cgidir($hostname, 1);
+		mkdir($cgidir) || error "mkdir $cgidir: $!";
+		chown($uid, $gid, "$cgidir") || error "chown $cgidir: $!";
+		chmod(0755, "$cgidir") || error "chmod $cgidir: $!";
+
+		changesetup($hostname,
+			rebuild => 0,
+			commit => 1,
+			message => "ikisite upgrade",
+			set => [
+				"cgi_wrapper" ."=". $cgidir."/ikiwiki.cgi",
+				"cgi_wrappermode" ."=". "0755",
+			],
+		);
+	}
+
+	# Disable and re-enable to write new apache configs, etc.
+	disable($hostname, temporary => 1);
+	enable($hostname);
+
+	foreach my $file (@cleanup) {
+		unlink($file) || error "unlink $file: $!";
+	}
+}
+
 ############################################################################
 
 my %locks;

add doc
diff --git a/debian/changelog b/debian/changelog
index 511636c..40ef0e0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,7 +7,8 @@ ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
     Thanks, Simon McVittie
   * Note that previously created sites will continue using
     the old locations. Manually migrating to the new
-    layout is recommended.
+    layout is recommended. See 
+    /usr/share/doc/ikiwiki-hosting-common/migration.html for a checklist.
 
  -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
 
diff --git a/doc/migration.html b/doc/migration.html
new file mode 100644
index 0000000..ba5e1a0
--- /dev/null
+++ b/doc/migration.html
@@ -0,0 +1,12 @@
+The location of log files and cgi programs has changed to fix possible
+[[security/privilege_escalation]] problems.
+
+New sites will use the new location.
+
+Unless manually migrated, existing sites will continue to use the old
+locations. How well that works is unknown.
+
+This is a possibly incomplete checklist for how to migrate a site to
+use the new locations:
+
+

backup does not back up logs
It never has, apparently. And I don't really want it to.
It was probably possible to restore a backup that somehow did contain the
logs directory. Update docs, as that will not work anymore, due to the
log directory moving out of home.
diff --git a/doc/design/backupformat.mdwn b/doc/design/backupformat.mdwn
index c5130ea..f47ea23 100644
--- a/doc/design/backupformat.mdwn
+++ b/doc/design/backupformat.mdwn
@@ -7,7 +7,6 @@ contains eg, passwords.
 
 * `$vcs.dump` - some kind of serialization of the vcs repository
   (for git, `git.dump` is a git-bundle)
-* `logs/` - optionally, some or all of the wiki's logs
 * other files can be included in the tarball using the same
   filename as is used in the home directory. For example as
   `source/.ikiwiki/indexdb` and `source/.ikiwiki/userdb`.
diff --git a/ikisite b/ikisite
index 79c0793..dc9bb21 100755
--- a/ikisite
+++ b/ikisite
@@ -137,7 +137,7 @@ sub delete {
 
 sub meta_backup {
 	required => [qw{hostname}],
-	options => [qw{filename=s morgue stdout no-logs}],
+	options => [qw{filename=s morgue stdout}],
 	description => "back up a site to the specified output",
 	section => "primary",
 }
@@ -413,7 +413,7 @@ sub branch {
 	
 	eval q{use File::Temp};
 	my ($tempfh, $tempfile) = File::Temp::tempfile(UNLINK => 1);
-	backup($oldhostname, filename => $tempfile, logs => 0);
+	backup($oldhostname, filename => $tempfile);
 	restore($newhostname, filename => $tempfile, "no-setup" => 1,
 		# when admin is changed, do not copy ssh keys from
 		# oldhostname

merged smcv/escalation
diff --git a/debian/changelog b/debian/changelog
index 169bce9..511636c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+ikiwiki-hosting (0.20110425) UNRELEASED; urgency=low
+
+  * Improve security, blocking escalation from site users to
+    httpd user, by moving apache log directory out of users
+    home directory to /var/log/ikiwiki-hosting/,
+    and using suexec with cgi programs moved to /var/www.
+    Thanks, Simon McVittie
+  * Note that previously created sites will continue using
+    the old locations. Manually migrating to the new
+    layout is recommended.
+
+ -- Joey Hess <joeyh@debian.org>  Tue, 26 Apr 2011 12:26:32 -0400
+
 ikiwiki-hosting (0.20110424) unstable; urgency=low
 
   * Remove unused dependency on libdigest-sha1-perl. Closes: #623957
diff --git a/doc/design.mdwn b/doc/design.mdwn
index 9d26ec8..a39965d 100644
--- a/doc/design.mdwn
+++ b/doc/design.mdwn
@@ -19,13 +19,13 @@ directory.
 The home directory has these contents:
 
 * `public_html` - the site's html is here
+  (but its cgis are created in /var/www so suidexec can be used)
 * `source.git` - bare git repo (or similar for other VCS)
 * `source` - checkout of the wiki's source
 * `ikiwiki.setup` - config file for the site
 * `apache.conf.tmpl` - apache config fragment (see [[apacheinclude]])
 * `apache` - directory contains optional apache configs
    ssl certs, etc)
-* `logs` - holds web server and other logs
 * `tmp` - per-user temp directory
 
 The home directory *itself* is a checkout of a different branch of the
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index d42fa00..24cc4ee 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -31,6 +31,8 @@ suexec will only work if the CGI script is under /var/www, owned by
 those conditions; CGIs not meeting those conditions won't be executed at
 all.
 
+> Done in your branch, which I've merged. --[[Joey]] 
+
 ### Central setuid-root wrapper
 
 Have a central setuid-root wrapper `/usr/lib/ikiwiki-hosting/ikiwiki.cgi`
@@ -72,6 +74,8 @@ of the home directory can be private.
 > break, not sure). It'd be great if you could merge some or all of
 > this. --[[smcv]]
 
+>> And merged. --[[Joey]] 
+
 ## ikisite parsing `ikiwiki.setup`
 
 ikisite loads `ikiwiki.setup` in "safe mode", so hopefully there's no
@@ -178,6 +182,8 @@ the home directory contain a logs/ symlink for convenience?
 >> the hosting user can (potentially) read their own logs later.
 >> --[[smcv]]
 
+>>> And merged. --[[Joey]] 
+
 ## users not owning their own $HOME?
 
 One way to avoid various privilege escalations would be for the site
@@ -192,3 +198,5 @@ would break:
   a temporary file and renaming over the original
 
 Probably not worth it...
+
+> I agree, this is not an approach I really want to pursue. --[[Joey]]

ikisite checklock renamed to checksite, and can check that a requested nonce has been created, to notice if site creation crashed part way through.
diff --git a/IkiWiki/Plugin/makesite.pm b/IkiWiki/Plugin/makesite.pm
index 328c2ee..b31fe8e 100644
--- a/IkiWiki/Plugin/makesite.pm
+++ b/IkiWiki/Plugin/makesite.pm
@@ -173,17 +173,16 @@ sub makesite ($$;$) {
 		my $canwait=$acceptplan && $dns_ok && defined $email;
 
 		# Check if background site creation is done by checking if
-		# the site exists and is no longer locked. 
-		IkiWiki::Hosting::getshell("ikisite-wrapper", "checklock", $internal_hostname,
-			($canwait ? "--wait" : ()));
+		# the site exists, is no longer locked, and has the
+		# requested nonce created.
+		IkiWiki::Hosting::getshell("ikisite-wrapper", "checksite", $internal_hostname,
+			"--hasnonce", ($canwait ? "--wait" : ()));
 		if ($? == 0) {
 			$creating=0;
 			$ready=1;
 		}
 		elsif ($canwait) {
-			# Only way checklock --wait can fail is if the
-			# site doesn't exist.
-			error sprintf("failure creating %s",	
+			error sprintf("failure creating %s",
 				encode_entities($internal_hostname));
 		}
 	}
diff --git a/debian/changelog b/debian/changelog
index 5bab6e7..60aa433 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,6 +5,9 @@ ikiwiki-hosting (0.20110402) UNRELEASED; urgency=low
   * better handling of www special case when making a site
   * ikiwiki-hosting-web-backup: Fix removal of morgued sites from primary 
     backup.
+  * ikisite checklock renamed to checksite, and can check that a requested
+    nonce has been created, to notice if site creation crashed part way
+    through.
 
  -- Joey Hess <joeyh@debian.org>  Mon, 04 Apr 2011 15:55:00 -0400
 
diff --git a/doc/bugs/site_creation_failure_not_noticed.mdwn b/doc/bugs/site_creation_failure_not_noticed.mdwn
new file mode 100644
index 0000000..8c1675e
--- /dev/null
+++ b/doc/bugs/site_creation_failure_not_noticed.mdwn
@@ -0,0 +1,13 @@
+Since site creation over the web happens in the background,
+there's a problem in detecting when the site creation fails.
+
+Instead of a useful error message, the user will be dumped
+into a site that failed to be created, or branched, and is in
+some unknown broken state.
+
+The code currently just checks that the site exists, and is
+not locked, and assumed that means ikiwiki set it up correctly.
+There should at least be some positive sign checked that ikiwiki
+finished successfully.
+
+> [[done]]; nonce checked
diff --git a/ikisite b/ikisite
index 2b7a2de..359143e 100755
--- a/ikisite
+++ b/ikisite
@@ -2172,13 +2172,13 @@ sub deletenonce {
 	return 1;
 }
 
-sub meta_checklock {
+sub meta_checksite {
 	required => [qw{hostname}],
-	options => [qw{wait}],
-	description => "returns true if site is not currently locked",
+	options => [qw{wait hasnonse}],
+	description => "checks if site is done being created",
 	section => "query",
 }
-sub checklock {
+sub checksite {
 	my $hostname=lc(shift);
 	my %options=@_;
 	
@@ -2186,10 +2186,20 @@ sub checklock {
 	assert_siteexists($hostname, 1);
 	assert_wrapper_unsafe();
 
+	my $checknonce = sub {
+		if ($options{hasnonce}) {
+			my $noncefile=homedir($hostname)."/.ikisite-nonce";
+			if (! -e $noncefile) {
+				return IkiWiki::SuccessReason->new("$hostname lacks nonce");
+			}
+		}
+		return IkiWiki::SuccessReason->new("$hostname is ready");
+	};
+
 	if ($options{wait}) {
 		# blocking wait
 		locksite($hostname);
-		return IkiWiki::SuccessReason->new("$hostname is not locked");
+		return $checknonce->();
 	}
 	else {
 		# nonblocking lock test
@@ -2202,7 +2212,7 @@ sub checklock {
 		}
 		else {
 			close CHECKLOCK;
-			return IkiWiki::SuccessReason->new("$hostname is not locked");
+			return $checknonce->();
 		}
 	}
 }
diff --git a/ikisite-wrapper.c b/ikisite-wrapper.c
index e6a2705..f966515 100644
--- a/ikisite-wrapper.c
+++ b/ikisite-wrapper.c
@@ -6,7 +6,7 @@
  * this wrapper expects the environment variable IKISITE_NONCE to be
  * set to contain a previously created nonce for the site.
  *
- * An exception is the create, branch, list, checklock, sitelookup,
+ * An exception is the create, branch, list, checksite, sitelookup,
  * enabledns, and updatecustomersite subcommands, which do not need a
  * nonce to be set.
  * 
@@ -32,7 +32,7 @@ int main (int argc, char **argv) {
 		    strcmp(argv[1], "list") == 0 ||
 		    strcmp(argv[1], "sitelookup") == 0 ||
 		    strcmp(argv[1], "updatecustomersite") == 0 ||
-		    strcmp(argv[1], "checklock") == 0 ||
+		    strcmp(argv[1], "checksite") == 0 ||
 		    strcmp(argv[1], "enabledns") == 0) {
 			/* use a dummy value so ikisite still can tell
 			 * it is being run from the wrapper */

close
diff --git a/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn b/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
index 934ad63..6e9ffe4 100644
--- a/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
+++ b/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
@@ -14,3 +14,5 @@ Please contact me at timo.lindfors@iki.fi
 > with iceweasel 3.5.15. Instead, if you click on the line of a key, 
 > you can use left/right arrows to scroll just that line, with no visible
 > UI! (What a strange UI decision the mozilla people made!) --[[Joey]] 
+
+>> This seems to be fixed in current iceweasel. [[done]] --[[Joey]] 

releasing version 0.20110401
diff --git a/Makefile b/Makefile
index efa3404..08c4fff 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,8 @@ BINS=iki-git-shell iki-git-hook-update ikisite-wrapper
 SCRIPTS=ikisite ikidns ikiwiki-hosting-web-daily ikiwiki-hosting-web-backup \
 	ikisite-delete-unfinished-site 
 MANS=ikisite ikidns ikisite-wrapper ikiwiki-hosting-web-daily \
-     	ikiwiki-hosting-web-backup ikisite-delete-unfinished-site
+     	ikiwiki-hosting-web-backup ikisite-delete-unfinished-site \
+	iki-git-hook-update iki-git-shell
 
 IKIWIKI=ikiwiki --wikiname "ikiwiki hosting internals" \
 		--no-usedirs --underlaydir=/dev/null \
diff --git a/debian/changelog b/debian/changelog
index 73b3b19..e4b6ec0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,5 @@
-ikiwiki-hosting (0.01) UNRELEASED; urgency=low
+ikiwiki-hosting (0.20110401) unstable; urgency=low
 
-  * Initial version.
+  * Initial release to Debian.
 
- -- Joey Hess <joeyh@debian.org>  Sun, 14 Feb 2010 17:02:10 -0500
+ -- Joey Hess <joeyh@debian.org>  Fri, 01 Apr 2011 20:41:11 -0400
diff --git a/debian/compat b/debian/compat
index 7f8f011..45a4fb7 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-7
+8
diff --git a/debian/control b/debian/control
index 80bc319..89818bc 100644
--- a/debian/control
+++ b/debian/control
@@ -1,24 +1,45 @@
 Source: ikiwiki-hosting
 Section: admin
 Priority: optional
-Build-Depends: ikiwiki, debhelper (>= 7.0.50)
+Build-Depends: ikiwiki, debhelper (>= 8)
 Maintainer: Joey Hess <joeyh@debian.org>
-Standards-Version: 3.8.4
+Standards-Version: 3.9.1
+Vcs-Git: git://ikiwiki-hosting.branchable.com/
+Homepage: http://ikiwiki-hosting.branchable.com/
 
 Package: ikiwiki-hosting-common
 Architecture: all
 Depends: ${misc:Depends}, ${perl:Depends}
 Description: ikiwiki hosting: common files
- Common files for all ikiwiki hosting servers.
+ A hosting interface for ikiwiki. Facilitates management of many separate
+ ikiwiki sites, with capabilities including web-based signup to create new
+ sites, easy support for branching sites, deleting sites, and transferring
+ sites between servers. Ikiwiki-hosting was developed for Branchable.com.
+ .
+ This package contains common files for all ikiwiki hosting servers,
+ and documentation.
 
 Package: ikiwiki-hosting-web
 Architecture: any
 Depends: ${misc:Depends}, ${perl:Depends}, ikiwiki-hosting-common, ikiwiki (>= 3.20100723), gcc | c-compiler, libc6-dev | libc-dev, git (>= 1:1.7.0), libxml-simple-perl, libnet-openid-consumer-perl (>= 1.03), liblwpx-paranoidagent-perl, libtimedate-perl, libdatetime-perl, libcgi-formbuilder-perl (>= 3.05), libcgi-session-perl (>= 4.14-1), libmail-sendmail-perl, libauthen-passphrase-perl, librpc-xml-perl, libtext-wikiformat-perl, python-docutils, polygen, libhtml-tree-perl, libxml-feed-perl, libmailtools-perl, perlmagick, libfile-mimeinfo-perl, libcrypt-ssleay-perl, liblocale-gettext-perl (>= 1.05-1), libtext-typography-perl, libtext-csv-perl, libdigest-sha1-perl, libtext-wikicreole-perl, libtext-textile-perl, libhighlight-perl, apache2, dnsutils, libyaml-perl, libyaml-syck-perl, uuid, dnsutils, gitweb (>= 1:1.7.0), libtext-markdown-perl (>= 1.0.26-1~bpo50+1), moreutils (>= 0.43), libdata-compare-perl
-Description: ikiwiki hosting: web server scripts
- The ikisite script, and other stuff to install on each web server.
+Description: ikiwiki hosting: web server
+ A hosting interface for ikiwiki. Facilitates management of many separate
+ ikiwiki sites, with capabilities including web-based signup to create new
+ sites, easy support for branching sites, deleting sites, and transferring
+ sites between servers. Ikiwiki-hosting was developed for Branchable.com.
+ .
+ This package contains the ikisite program, and related things to install
+ on each web server.
 
 Package: ikiwiki-hosting-dns
 Architecture: all
 Depends: ${misc:Depends}, ${perl:Depends}, ikiwiki-hosting-common, bind9
-Description: ikiwiki hosting: dns server scripts
- The ikidns script, and other stuff to install on the master dns server.
+Description: ikiwiki hosting: dns server
+ A hosting interface for ikiwiki. Facilitates management of many separate
+ ikiwiki sites, with capabilities including web-based signup to create new
+ sites, easy support for branching sites, deleting sites, and transferring
+ sites between servers. Ikiwiki-hosting was developed for Branchable.com.
+ .
+ This package should be installed on the master DNS server, only if you
+ will be allowing ikiwiki-hosting to automatically manage DNS for 
+ sites. It contains the ikidns program.
diff --git a/debian/copyright b/debian/copyright
index 2286003..06a2b77 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,4 +1,5 @@
 Format: http://dep.debian.net/deps/dep5/
+Source: native package
 
 Files: *
 Copyright: © 2010-2011 Joey Hess <joey@kitenet.net>
diff --git a/debian/ikiwiki-hosting-web.manpages b/debian/ikiwiki-hosting-web.manpages
index 2f3aec9..0c13377 100644
--- a/debian/ikiwiki-hosting-web.manpages
+++ b/debian/ikiwiki-hosting-web.manpages
@@ -3,3 +3,5 @@ ikisite-wrapper.1
 ikisite-delete-unfinished-site.1
 ikiwiki-hosting-web-daily.1
 ikiwiki-hosting-web-backup.1
+iki-git-shell.1
+iki-git-hook-update.1
diff --git a/doc/iki-git-hook-update.mdwn b/doc/iki-git-hook-update.mdwn
new file mode 100644
index 0000000..f563467
--- /dev/null
+++ b/doc/iki-git-hook-update.mdwn
@@ -0,0 +1,24 @@
+# NAME
+
+iki-git-hook-update - ikiwiki-hosting git update hook
+
+# SYNOPSIS
+
+iki-git-hook-update
+
+# DESCRIPTION
+
+This program is installed by ikisite as the git update hook for ikiwiki
+git repositories. It allows trusted sources to commit any change,
+while limiting commits from untrusted sources to prevent them making arbitrary
+new branches, or making unsafe changes to the site's setup branch.
+
+# SEE ALSO
+
+* [[ikisite]](1)
+
+# AUTHOR
+
+Joey Hess <joey@ikiwiki.info>
+
+Warning: this page is automatically made into a man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD).  Edit with care
diff --git a/doc/iki-git-shell.mdwn b/doc/iki-git-shell.mdwn
new file mode 100644
index 0000000..196bf48
--- /dev/null
+++ b/doc/iki-git-shell.mdwn
@@ -0,0 +1,27 @@
+# NAME
+
+iki-git-shell - ikiwiki-hosting helper
+
+# SYNOPSIS
+
+iki-git-shell -c I<command> I<argument>
+
+# DESCRIPTION
+
+This is a wrapper for git-shell, and the parameters are passed
+on to that program. Used in a ssh authorized_keys file for
+an ikiwiki-hosting site user, it adds several safety features
+to incoming commits. These include the ability to park a
+repo, preventing changes, and limiting access to only a site's source.git
+repository and no other repositories.
+
+# SEE ALSO
+
+* [[ikisite]](1)
+* [[git-shell]](1)
+
+# AUTHOR
+
+Joey Hess <joey@ikiwiki.info>
+
+Warning: this page is automatically made into a man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD).  Edit with care
diff --git a/iki-git-hook-update.c b/iki-git-hook-update.c
index 68b53e8..f14eebb 100644
--- a/iki-git-hook-update.c
+++ b/iki-git-hook-update.c
@@ -1,6 +1,6 @@
 /*
  * git update hook that allows trusted sources to make any change,
- * while untrusted sources may only push changes to master.
+ * while untrusted sources may only push changes that seem safe.
  *
  * (iki-git-shell sets UNTRUSTED_COMMIT=1 for commits pushed from external
  * sources)

document problem
diff --git a/doc/security/push_setup_branch_deny_was_broken.mdwn b/doc/security/push_setup_branch_deny_was_broken.mdwn
new file mode 100644
index 0000000..513d750
--- /dev/null
+++ b/doc/security/push_setup_branch_deny_was_broken.mdwn
@@ -0,0 +1,9 @@
+Ikisite created a broken symlink for the git update hook, so pushes to the
+setup branch were not denied. This could possibly lead to unauthorized code
+execution, although it would have to be paired with a site branch or
+backup/restore.
+
+This is fixed, but any existing sites need to have their update hook manually
+fixed to link to /usr/bin/iki-git-hook-update
+
+[[done]] --[[Joey]] 

pull over updated design docs from internal
diff --git a/doc/design/customersite.mdwn b/doc/design/customersite.mdwn
index a92be9a..bf619e0 100644
--- a/doc/design/customersite.mdwn
+++ b/doc/design/customersite.mdwn
@@ -53,9 +53,24 @@ as a shared lock by things that do customer-level locking.
 * `openid_list` holds the openid(s) of the user
 * `startdate` when this customer's account was first created (represented
   as time from unix epoch)
-* `balance` amount of money owed (in cents)
+* `balance` amount of money owed (in cents) (a negative balance indicates
+  the customer has a credit)
+* `previousbalance` what the balance was before the last billing or payment
+   event (be sure to update this when changing the balance)
 * `lastbilldate` when user was last billed (represented as time
   from unix epoch)
+* `disable_billing` if set to a true value, bills will not be sent
+  (used for test accounts)
 * `lastreminderdate` when last billing reminder was sent
 * `bill_startdate` start of billing period for last bill
 * `bill_enddate` end of billing period for last bill
+* `lastinvoiceid` id of the last invoice sent
+* `lastplan` name of the price plan used in the last invoice sent
+
+## non-customer data
+
+In a charming example of scope creep, we're storing a bit of
+non-customer-specific data in the customersite already:
+
+* `invoice/last` - stores the last used invoice id.
+* `invoice/YYY-MM/` - stores copies of invoices sent to customers

new ipv6 regime
Removed the ipv6 prefix stuff; implementing a prefix everywhere
seems like too much bother.
Instead, added a config setting to allow disabling ipv6.
This way, ipv6 can be enabled by default, and then disabled on a per-site
basis. It might be nice to allow the converse, but that is actually harder.
As currently implemented, a site that is lacking a setup file yet is
assumed to have ipv6 enabled. Then when the setup file is put into place,
it can disable ipv6. If sites were assumed to have ipv6 disabled and the
setup file enabled it, the dns propigation delays that early dns setup
avoids would be more evident.
Anyway, let's be bold. ipv6 on by default is a fun default :)
diff --git a/IkiWiki/Plugin/ikiwikihosting.pm b/IkiWiki/Plugin/ikiwikihosting.pm
index b60dfac..ac9cb44 100644
--- a/IkiWiki/Plugin/ikiwikihosting.pm
+++ b/IkiWiki/Plugin/ikiwikihosting.pm
@@ -13,6 +13,7 @@ sub import {
 	hook(type => "sessioncgi", id => "ikiwikihosting",  call => \&sessioncgi);
 	hook(type => "formbuilder_setup", id => "ikiwikihosting",
 		call => \&formbuilder_setup, last => 1);
+	hook(type => "checkconfig", id => "ikiwikihosting",  call => \&checkconfig);
 	hook(type => "genwrapper", id => "ikiwikihosting", call => \&genwrapper);
 }
 
@@ -60,6 +61,13 @@ sub getsetup () {
 			safe => 1,
 			rebuild => 0,
 		},
+		ipv6_disabled => {
+			type => "boolean",
+			example => 1,
+			description => "disable IPv6?",
+			safe => 1,
+			rebuild => 0,
+		},
 }
 
 sub sessioncgi ($$) {
@@ -376,17 +384,25 @@ sub alias ($) {
 	return @alias;
 }
 
+my $old_ipv6_disabled;
+sub checkconfig {
+	if (! defined $config{ipv6_disabled}) {
+		$config{ipv6_disabled}=0;
+	}
+	# stash for comparison later
+	$old_ipv6_disabled=$config{ipv6_disabled};
+}
+
 sub genwrapper {
 	# This hook is called whenever wrappers are being built,
 	# and that happens when configuration has changed.
-	commitsetup();
+	handlechangedsetup();
 
 	# C code to inject into wrapper.
 	return "";
 }
 
-sub commitsetup {
-	# Commit any changes to the setup file into the setup branch.
+sub handlechangedsetup {
 	# Locking requires this be done in the background.
 	eval q{use IkiWiki::Hosting};
 	error $@ if $@;
@@ -397,8 +413,16 @@ sub commitsetup {
 	
 	# Drop lock; ikisite takes the lock itself.
 	IkiWiki::unlockwiki();
+
+	# If ipv6 was enabled or disabled, need to refresh dns.
+	if ($old_ipv6_disabled ne $config{ipv6_disabled}) {
+		IkiWiki::Hosting::getshell("ikisite", "enabledns", $config{hostname});
+	}
+
+	# Commit any changes to the setup file into the setup branch.
 	IkiWiki::Hosting::getshell("ikisite", "commitsetup", $config{hostname});
 	exit;
 }
 
+
 1
diff --git a/doc/ikisite-wrapper.mdwn b/doc/ikisite-wrapper.mdwn
index f87510f..45eb345 100644
--- a/doc/ikisite-wrapper.mdwn
+++ b/doc/ikisite-wrapper.mdwn
@@ -12,8 +12,9 @@ ikisite-wrapper is a wrapper around [[ikisite]]. It is designed to be safely
 made suid root, though it is not currently suid by default.
 
 A few ikisite subcommands can be run using the wrapper without any
-authorisation at all. These include: create, branch, list, sitelookup, and
-checklock. So making the wrapper suid allows any user to create a site.
+authorisation at all. These include: create, branch, list, sitelookup,
+checklock, updatecustomersite, and enabledns. So making the wrapper suid
+allows any user to create a site.
 
 Other ikisite subcommands can only be run using the wrapper by
 users who specify a nonce in the IKISITE_NONCE environment variable. These
diff --git a/ikisite b/ikisite
index e66a69c..5859ccd 100755
--- a/ikisite
+++ b/ikisite
@@ -1423,22 +1423,32 @@ sub enabledns {
 	my $hostname=lc(shift);
 	
 	assert_root();
+	# Enabling dns is a fairly safe operation, and sites need to be
+	# able to call it when ipv6_disabled is changed.
+	assert_wrapper_unsafe();
+
 	locksite($hostname);
-	assert_wrapper_denied();
 
-	if ($config{allow_ipv4} ||
-	    $config{allow_ipv6} || $config{allow_ipv6_prefix}) {
-		my ($ipv4, $ipv6)=site_addresses();
+	if ($config{allow_ipv4} || $config{allow_ipv6}) {
 		my @commands;
+		# A site's setup file can be used to disable ipv6.
+		# But, the setup file may not yet exist, if an early dns
+		# setup is being done. In that case, ipv6 is assumed not
+		# to be disabled, and enabledns is expected to be run
+		# a second time once the setup file is in place, and
+		# can disable it then.
+		my $ipv6_disabled = eval { getsetup($hostname, "ipv6_disabled") };
+
+		my ($ipv4, $ipv6)=site_addresses();
 		foreach my $h ($hostname, "source.$hostname") {
+			if ($ipv6_disabled || ! defined $ipv6 || ! $config{allow_ipv6}) {
+				push @commands, "update delete $h AAAA";
+			}
+			else {
+				push @commands, "update add $h $config{ttl} IN AAAA $ipv6";
+			}
 			push @commands, "update add $h $config{ttl} IN A $ipv4"
 				if defined $ipv4 && $config{allow_ipv4};
-			push @commands, "update add $h $config{ttl} IN AAAA $ipv6"
-				if defined $ipv6 && $config{allow_ipv6};
-			if (defined $ipv6 && $config{allow_ipv6_prefix}) {
-				push @commands, "update add ipv6.$h $config{ttl} IN AAAA $ipv6";
-				push @commands, "update add ipv6.$h $config{ttl} IN A $ipv4";
-			}
 		}
 		if (! @commands) {
 			error("failed to determine IP address");
@@ -1460,12 +1470,10 @@ sub disabledns {
 	locksite($hostname);
 	assert_wrapper_denied();
 
-	if ($config{allow_ipv4} ||
-	    $config{allow_ipv6} || $config{allow_ipv6_prefix}) {
+	if ($config{allow_ipv4} || $config{allow_ipv6}) {
 		nsupdate(
 			"update delete $hostname",
 			"update delete source.$hostname",
-			"update delete ipv6.$hostname",
 		);
 	}
 }
diff --git a/ikisite-wrapper.c b/ikisite-wrapper.c
index af2ff4c..e6a2705 100644
--- a/ikisite-wrapper.c
+++ b/ikisite-wrapper.c
@@ -7,7 +7,8 @@
  * set to contain a previously created nonce for the site.
  *
  * An exception is the create, branch, list, checklock, sitelookup,
- * and updatecustomersite subcommands, which do not need a nonce to be set.
+ * enabledns, and updatecustomersite subcommands, which do not need a
+ * nonce to be set.
  * 
  */
 
@@ -31,7 +32,8 @@ int main (int argc, char **argv) {
 		    strcmp(argv[1], "list") == 0 ||
 		    strcmp(argv[1], "sitelookup") == 0 ||
 		    strcmp(argv[1], "updatecustomersite") == 0 ||
-		    strcmp(argv[1], "checklock") == 0) {
+		    strcmp(argv[1], "checklock") == 0 ||
+		    strcmp(argv[1], "enabledns") == 0) {
 			/* use a dummy value so ikisite still can tell
 			 * it is being run from the wrapper */
 			nonce="dummy";
diff --git a/ikiwiki-hosting.conf b/ikiwiki-hosting.conf
index f39f2fd..c05d122 100644
--- a/ikiwiki-hosting.conf
+++ b/ikiwiki-hosting.conf
@@ -22,9 +22,6 @@ vcs=git
 allow_ipv4=0
 # Set to 1 to allow sites to be auto-assigned ipv6 addresses in the DNS.
 allow_ipv6=0
-# Set to 1 to allow sites to be auto-assigned ipv6 addresses in the form
-# ipv6.<site> in the DNS.
-allow_ipv6_prefix=0
 # (Disable all of the above to disable auto-assignment of DNS addresses.)
 
 # This is the DNS TTL to use when adding a hostname for a site.

split out a backup script from the daily script
diff --git a/Makefile b/Makefile
index 442c157..efa3404 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,10 @@ MODDIR=$(DESTDIR)/usr/share/perl5/
 
 CFLAGS=-O2 -Wall -g
 BINS=iki-git-shell iki-git-hook-update ikisite-wrapper
-SCRIPTS=ikisite ikidns ikiwiki-hosting-web-daily ikisite-delete-unfinished-site 
-MANS=ikisite ikidns ikisite-wrapper ikiwiki-hosting-web-daily ikisite-delete-unfinished-site
+SCRIPTS=ikisite ikidns ikiwiki-hosting-web-daily ikiwiki-hosting-web-backup \
+	ikisite-delete-unfinished-site 
+MANS=ikisite ikidns ikisite-wrapper ikiwiki-hosting-web-daily \
+     	ikiwiki-hosting-web-backup ikisite-delete-unfinished-site
 
 IKIWIKI=ikiwiki --wikiname "ikiwiki hosting internals" \
 		--no-usedirs --underlaydir=/dev/null \
diff --git a/debian/ikiwiki-hosting-web.cron.daily b/debian/ikiwiki-hosting-web.cron.daily
index a3dc7fc..c5c2357 100644
--- a/debian/ikiwiki-hosting-web.cron.daily
+++ b/debian/ikiwiki-hosting-web.cron.daily
@@ -1,8 +1,11 @@
 #!/bin/sh
-# Backup and compact all sites. This is a low-priority background job.
+# Compact and maintain all sites. This is a low-priority background job.
 # It can be a bit noisy, so chronic is used to only show output on error.
 nice -n 19 ionice -c 3 chronic ikiwiki-hosting-web-daily
 
+# Backup sites once a day.
+nice -n 19 ionice -c 3 chronic ikiwiki-hosting-web-backup
+
 # Clean up unfinished sites. This produces output you probably want to see.
 ikisite-delete-unfinished-site --all
 
diff --git a/doc/ikiwiki-hosting-web-backup.mdwn b/doc/ikiwiki-hosting-web-backup.mdwn
new file mode 100644
index 0000000..bc674ef
--- /dev/null
+++ b/doc/ikiwiki-hosting-web-backup.mdwn
@@ -0,0 +1,22 @@
+# NAME
+
+ikiwiki-hosting-web-daily - backup sites
+
+# SYNOPSIS
+
+ikiwiki-hosting-web-backup
+
+# DESCRIPTION
+
+This script is run periodically by cron, as a low-priority job.
+It handles backing up sites.
+
+# SEE ALSO
+
+* [[ikisite]](1)
+
+# AUTHOR
+
+Joey Hess <joey@ikiwiki.info>
+
+Warning: this page is automatically made into a man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD).  Edit with care
diff --git a/doc/ikiwiki-hosting-web-daily.mdwn b/doc/ikiwiki-hosting-web-daily.mdwn
index a200e94..1c5559d 100644
--- a/doc/ikiwiki-hosting-web-daily.mdwn
+++ b/doc/ikiwiki-hosting-web-daily.mdwn
@@ -1,6 +1,6 @@
 # NAME
 
-ikiwiki-hosting-web-daily - backup and compact all sites
+ikiwiki-hosting-web-daily - compact and maintain all sites
 
 # SYNOPSIS
 
@@ -9,8 +9,8 @@ ikiwiki-hosting-web-daily
 # DESCRIPTION
 
 This script is run daily by cron, as a low-priority job.
-It does various cleanup and bookkeeping tasks, including backing up
-all sites, rotating their logs, and updating their calendars.
+It does various cleanup and bookkeeping tasks, including 
+rotating sites logs, and updating their calendars.
 
 # SEE ALSO
 
diff --git a/doc/index.mdwn b/doc/index.mdwn
index cc05ef0..0b27aef 100644
--- a/doc/index.mdwn
+++ b/doc/index.mdwn
@@ -15,6 +15,7 @@ Commands:
 * [[ikidns]]
 * [[ikisite-wrapper]]
 * [[ikiwiki-hosting-web-daily]]
+* [[ikiwiki-hosting-web-backup]]
 * [[ikisite-delete-unfinished-site]]
 
 This wiki is built from the files in the doc directory of
diff --git a/ikiwiki-hosting-web-backup b/ikiwiki-hosting-web-backup
new file mode 100755
index 0000000..474a933
--- /dev/null
+++ b/ikiwiki-hosting-web-backup
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Backs up all sites.
+
+failed=""
+
+. /etc/ikiwiki-hosting/ikiwiki-hosting.conf
+
+LOCKFILE=/var/run/ikiwiki-hosting-web-backup-lockfile
+
+cleanup () {
+	rm -f $LOCKFILE || true
+}
+
+# Use lockfile to avoid multiple passport-syncs running.
+# (bash needed because exec 200>file is a bashism)
+exec 200>$LOCKFILE
+if ! flock --nonblock 200; then
+	echo "another ikiwiki-hosting-web-backup is already running" >&2
+	exit 1
+fi
+
+trap cleanup EXIT INT
+
+for site in $(ikisite list); do
+	if [ "$num_backups" -gt 0 ] || [ -n "$backup_rsync_urls" ]; then
+		bdir="/var/backups/ikiwiki-hosting-web/$site"
+		mkdir -p "$bdir"
+
+		# savelog has a minimim -c of 2
+		if [ -e "$bdir/backup" && "$num_backups" -gt 2 ]; then
+			savelog -c "$num_backups" "$bdir/backup"
+		fi
+
+		# this uses git, which is noisy to stderr, so shut it up
+		if ! ikisite backup "$site" --filename="$bdir"/backup; then
+			echo "ikisite backup $site failed!" >&2
+			failed=1
+		fi
+
+		# rsync backups to somewhere
+		if [ -n "$backup_rsync_urls" ]; then
+			for url in $backup_rsync_urls; do
+				rsync -az $backup_rsync_options "$bdir/backup" "$url/$site/backup"
+			done
+		fi
+
+		# maybe we don't want to keep backups locally..
+		if [ "$num_backups" = 0 ]; then
+			rm -f "$bdir/backup"
+		fi
+	fi
+done
+
+if [ -n "$morguedir" ] && [ -d "$morguedir" ] && [ -n "$backup_rsync_urls" ]; then
+	# backup the morgue to any configured rsync urls.
+	for url in $backup_rsync_urls; do
+		rsync -az $backup_rsync_options "$morguedir/" "$url/morgue/"
+	done
+	# For each site in the morgue, zero out any old backup
+	# of it that might exist on the remote. This is done to avoid
+	# deleted sites being restored if the backups should be used.
+	# (We can't properly delete them the way that we're using rsync.)
+	touch "$morguedir/empty"
+	for file in $(find "$morguedir" -type f); do
+		site="$(basename "$file")"
+		rsync -a $backup_rsync_options "$morguedir/empty" "$url/$site/backup"
+	done
+	rm -f "$morguedir/empty"
+fi
+
+if [ "$failed" ]; then
+	exit 1
+else
+	exit 0
+fi
diff --git a/ikiwiki-hosting-web-daily b/ikiwiki-hosting-web-daily
index 2009bc8..1e73d25 100755
--- a/ikiwiki-hosting-web-daily
+++ b/ikiwiki-hosting-web-daily
@@ -7,25 +7,14 @@ failed=""
 
 for site in $(ikisite list); do
 	# Rotate logs, gc git repos, etc.
-	ikisite compact "$site"
-
-	# Back up each site.
-	if [ "$num_backups" -gt 0 ]; then
-		bdir="/var/backups/ikiwiki-hosting-web/$site"
-		mkdir -p "$bdir"
-		# savelog has a minimim -c of 2
-		if [ -e "$bdir/backup" && "$num_backups" -gt 2 ]; then
-			savelog -c "$num_backups" "$bdir/backup"
-		fi
-		# this uses git, which is noisy to stderr, so shut it up
-		if ! ikisite backup "$site" --filename="$bdir"/backup; then
-			echo "ikisite backup $site failed!" >&2
-			failed=1

(Diff truncated)
note on rsyncability
diff --git a/doc/design/backupformat.mdwn b/doc/design/backupformat.mdwn
index 4d87f17..c5130ea 100644
--- a/doc/design/backupformat.mdwn
+++ b/doc/design/backupformat.mdwn
@@ -3,7 +3,7 @@ of the files in it are compressed. All files in the tar file need to be
 owned by root:root, and the backup file should be kept mode 400 as it
 contains eg, passwords.
 
-Tarball contents:
+## tarball contents
 
 * `$vcs.dump` - some kind of serialization of the vcs repository
   (for git, `git.dump` is a git-bundle)
@@ -15,3 +15,9 @@ Tarball contents:
 This format allows the backup to be created by serializing the vcs
 and then just tarring up selected files from the home directory of the
 site.
+
+## rsyncability
+
+git dumps are highly rsyncable, and since the tarball is uncompressed, as a
+whole it is quite rsyncable too. Real world numbers: For a 15 mb backup,
+rsync reported a speedup of 166, and needed to send only 68 kb.

added a per-user tmp directory in homedir
ikiwiki is configured to use this. This way, a site is self-contained and
only if the volume holding its temp dir fills up will it ENOSPACE.
diff --git a/autosetup/auto-blog.setup b/autosetup/auto-blog.setup
index 512138f..7c49e83 100644
--- a/autosetup/auto-blog.setup
+++ b/autosetup/auto-blog.setup
@@ -76,4 +76,6 @@ websetup_unsafe:
  - indexpages
  - repositories
 websetup_show_unsafe: 0
+ENV:
+ TMPDIR: $ENV{HOME}/tmp
 EOF
diff --git a/autosetup/auto.setup b/autosetup/auto.setup
index f8c1d9c..ec2b246 100644
--- a/autosetup/auto.setup
+++ b/autosetup/auto.setup
@@ -61,4 +61,6 @@ websetup_unsafe:
  - indexpages
  - repositories
 websetup_show_unsafe: 0
+ENV:
+ TMPDIR: $ENV{HOME}/tmp
 EOF
diff --git a/doc/design.mdwn b/doc/design.mdwn
index 837ec47..9d26ec8 100644
--- a/doc/design.mdwn
+++ b/doc/design.mdwn
@@ -26,6 +26,7 @@ The home directory has these contents:
 * `apache` - directory contains optional apache configs
    ssl certs, etc)
 * `logs` - holds web server and other logs
+* `tmp` - per-user temp directory
 
 The home directory *itself* is a checkout of a different branch of the
 VCS repository, the "setup" branch. Into that branch are checked the
diff --git a/ikisite b/ikisite
index fb072f0..ca2c7c6 100755
--- a/ikisite
+++ b/ikisite
@@ -464,6 +464,7 @@ sub branch {
 	push @settings, 'set-yaml' => [
 		"urlalias=".Dump([]),
 		($options{admin} ? "adminuser=".Dump($options{admin}) : ()),
+		"ENV=".Dump({TMPDIR => homedir($newhostname)."/tmp"}),
 	];
 	
 	changesetup($newhostname,
@@ -1185,12 +1186,14 @@ sub usercreate {
 	my $home=homedir($hostname);
 	mkdir("$home/logs") || error "mkdir $home/logs: $!";
 	mkdir("$home/.ssh") || error "mkdir $home/.ssh: $!";
+	mkdir("$home/tmp") || error "mkdir $home/tmp: $!";
 	writefile("logs/ikisite.log", $home, "");
-	foreach my $file ("logs", "logs/ikisite.log", ".ssh") {
+	foreach my $file ("logs", "logs/ikisite.log", ".ssh", "tmp") {
 		chown($uid, $gid, "$home/$file")
 			|| error "chown $home/$file: $!";
 	}
 	chmod(0700, "$home/logs") || error "chmod $home/logs: $!";
+	chmod(0700, "$home/tmp") || error "chmod $home/tmp: $!";
 
 	# configure default username and email for git commits
 	runas(username($hostname), sub {

update
diff --git a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
index c7ddf83..29252be 100644
--- a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
+++ b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
@@ -1,4 +1,34 @@
-Eventually, I want to support using monkeysphere for ssh key configuration.
+Branchable's ssh host keys are now published on Monkeysphere.
+<http://www.branchable.com/forum/verifying_ssh_host_keys/>
+
+However, there is
+a limitation. Monkeysphere will only see the key if the user connects to
+`branchable.com`, not to `sitename.branchable.com`.
+
+We'd really like to be able to tell monkeysphere that "*.branchable.com"
+can use any of our ssh host keys. But I don't think it supports
+wildcarding.
+
+An alternative would be to do `monkeysphere-host add-servicename` for each
+subdomain we set up. But when they're all on the same key like that 
+a) the key will tend to get *big* and b) the key will have a list of
+every one of our subdomains, which is not information we want to expose.
+
+The other approach would be to run `monkeysphere-host import-key` for each
+subdomain we set up, so each has a unique key. But that has problems also:
+a) we'd have to keep a gpg key on our server to sign those keys, and it
+would have to be put in the web of trust -- I don't like keeping gpg keys
+on network servers. b) It might *still* allow getting a list of all
+our subdomains, if you can get ahold of the entire worldwide gpg web of
+trust.
+
+The final option would be for us to recommend users use ssh with
+`branchable.com`, not a subdomain. And, behind the scenes, redirect it to
+the appropriate server for the user who is logging in.
+
+---
+
+Eventually, I want to support using monkeysphere for user's ssh key configuration.
 
 This would allow the site owner to enter an email address, and have ssh keys
 for that user's email automatically retrieved. To help the site owner make
@@ -6,4 +36,5 @@ sure the ssh key was signed by the right gpg key, it could display a partial
 web of trust. (Or, if we knew the user's own gpg key, we could do a better
 display).
 
-Revocations of configured keys could also be scanned for, and the keys disabled.
+Revocations of configured keys could also be scanned for, and the keys
+disabled. --[[Joey]] 

can scroll but no UI
diff --git a/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn b/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
index 1dd843a..934ad63 100644
--- a/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
+++ b/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
@@ -4,3 +4,13 @@ Please contact me at timo.lindfors@iki.fi
 
 > I have access to the same wiki, and do not see the problem Timo sees. I see 380 chars of the SSH keys, and do have a scrollbar.
 > Weird. --liw
+
+> The html used to display the keys is an unstyled `<pre>`. I'd expect
+> a browser to add a scrollbar to the whole page when part of it is too
+> wide. Or to put a scrollbar on the individual pre with the too-long line,
+> like chromium does. 
+> 
+> But I can reproduce the problem described
+> with iceweasel 3.5.15. Instead, if you click on the line of a key, 
+> you can use left/right arrows to scroll just that line, with no visible
+> UI! (What a strange UI decision the mozilla people made!) --[[Joey]] 

bug moved from ikiwiki
diff --git a/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn b/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
new file mode 100644
index 0000000..1dd843a
--- /dev/null
+++ b/doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn
@@ -0,0 +1,6 @@
+At least at http://free-thursday.pieni.net/ikiwiki.cgi the "SSH keys" page shows only the first 139 characters of each SSH key. I'm using iceweasel in 1024x768 resolution and there are not scrollbars visible.
+
+Please contact me at timo.lindfors@iki.fi
+
+> I have access to the same wiki, and do not see the problem Timo sees. I see 380 chars of the SSH keys, and do have a scrollbar.
+> Weird. --liw

branch redone, existing users should hopefully now be unaffected
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 2df76c2..d42fa00 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -21,12 +21,12 @@ Possible fixes:
 ### Use Apache's `suexec`
 
 Something like this:
-<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/shortlog/suexec>.
+<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/shortlog/escalation>.
 (If you don't want to put the Debian dependencies one per line, leave out
 that commit, but I find git diff isn't very useful for long dependency
 lists otherwise...)
 
-suexec will only work if the CGI script is under /var/www, owned b
+suexec will only work if the CGI script is under /var/www, owned by
 `b-example`, not writeable by anyone else, and in a directory also meeting
 those conditions; CGIs not meeting those conditions won't be executed at
 all.
@@ -66,6 +66,12 @@ suexec is that the user owns it.
 As noted on [[homedir perms]] this has the nice side-effect that more
 of the home directory can be private.
 
+> I've done this on my `escalation` branch, which is the earlier `suexec`
+> branch redone so that existing users will (mostly) keep working, with
+> their old log/CGI directory (if you disable/enable sites it might still
+> break, not sure). It'd be great if you could merge some or all of
+> this. --[[smcv]]
+
 ## ikisite parsing `ikiwiki.setup`
 
 ikisite loads `ikiwiki.setup` in "safe mode", so hopefully there's no
@@ -75,6 +81,8 @@ possibility of arbitrary code execution there.
 > Of course, if any value is used in an insecure way by ikisite, it loses.
 > --[[Joey]]
 
+>> I haven't audited this thoroughly yet, but nothing jumps out at me... --[[smcv]]
+
 ## apache.conf.tmpl
 
 `apache.conf.tmpl` is, if not root-equivalent, then at least `www-data`-equivalent,
@@ -89,6 +97,11 @@ an untrusted backup is currently dangerous.
 > code. All the dangerous stuff should be confined to the setup branch,
 > which is why pushing that branch is rejected. --[[Joey]]
 
+>> Right, but my goal with this stuff is more or less: if bob is a user
+>> with shell access and b-example is his website, giving bob permission
+>> to become `b-example` via sudo doesn't let him escalate privileges
+>> any further than that. --[[smcv]]
+
 Since only root can set this up anyway, I'd personally be inclined to treat
 it as server-wide configuration that should be backed up as part of `/etc`,
 
@@ -125,6 +138,8 @@ perfectly happy if a glob fails to match any files.
 If the `HTML::Template` functionality is useful in practice (is it?),
 `ikisite` could perhaps automatically generate `foo.conf` from `foo.tmpl`.
 
+> I haven't done this on my branch so far. --[[smcv]]
+
 ## `~/apache/`
 
 I don't know what you put in here in practice, so I don't know whether
@@ -158,7 +173,10 @@ the home directory contain a logs/ symlink for convenience?
 > something filling the logs doesn't necessarily full the home partition
 > too. --[[Joey]] 
 
->> I've added that to my branch. --[[smcv]]
+>> I've added that to my branch; I used
+>> `/var/log/ikiwiki-hosting/b-example` owned by `root:b-example` so
+>> the hosting user can (potentially) read their own logs later.
+>> --[[smcv]]
 
 ## users not owning their own $HOME?
 

todo
diff --git a/doc/bugs/ikisite_calendar_old_posts.mdwn b/doc/bugs/ikisite_calendar_old_posts.mdwn
new file mode 100644
index 0000000..5ab5276
--- /dev/null
+++ b/doc/bugs/ikisite_calendar_old_posts.mdwn
@@ -0,0 +1,3 @@
+ikisite calendar only adds calendar files for new years. However, a user
+might import data from years past. It should probably find the oldest year
+with content and add all years from it to the present. 

move ikisite-delete-unfinished-site to where its output can be seen
diff --git a/debian/ikiwiki-hosting-web.cron.daily b/debian/ikiwiki-hosting-web.cron.daily
index 6761e63..a3dc7fc 100644
--- a/debian/ikiwiki-hosting-web.cron.daily
+++ b/debian/ikiwiki-hosting-web.cron.daily
@@ -1,5 +1,8 @@
 #!/bin/sh
-# Just run the daily cron job for ikiwiki-hosting-web.
-# This is a low-priority background job.
+# Backup and compact all sites. This is a low-priority background job.
 # It can be a bit noisy, so chronic is used to only show output on error.
 nice -n 19 ionice -c 3 chronic ikiwiki-hosting-web-daily
+
+# Clean up unfinished sites. This produces output you probably want to see.
+ikisite-delete-unfinished-site --all
+
diff --git a/doc/ikisite-delete-unfinished-site.mdwn b/doc/ikisite-delete-unfinished-site.mdwn
index e6a896d..6461a2d 100644
--- a/doc/ikisite-delete-unfinished-site.mdwn
+++ b/doc/ikisite-delete-unfinished-site.mdwn
@@ -8,7 +8,7 @@ ikisite-delete-unfinished-site openid|--all [--dry-run]
 
 # DESCRIPTION
 
-This helper script is run by [[ikiwiki-hosting-web-daily]],
+This helper script is run by by cron daily,
 and deletes sites that someone started to create, but never finished
 setting up.
 
diff --git a/doc/ikiwiki-hosting-web-daily.mdwn b/doc/ikiwiki-hosting-web-daily.mdwn
index 22967e3..a200e94 100644
--- a/doc/ikiwiki-hosting-web-daily.mdwn
+++ b/doc/ikiwiki-hosting-web-daily.mdwn
@@ -1,6 +1,6 @@
 # NAME
 
-ikiwiki-hosting-web-daily - run by cron daily
+ikiwiki-hosting-web-daily - backup and compact all sites
 
 # SYNOPSIS
 
diff --git a/ikiwiki-hosting-web-daily b/ikiwiki-hosting-web-daily
index 9f975e5..b15382e 100755
--- a/ikiwiki-hosting-web-daily
+++ b/ikiwiki-hosting-web-daily
@@ -3,9 +3,6 @@
 
 failed=""
 
-# Clean up unfinished sites.
-ikisite-delete-unfinished-site --all
-
 for site in $(ikisite list); do
 	# Rotate logs, gc git repos, etc.
 	ikisite compact "$site"

use chronic to shut up daily cron job
diff --git a/Makefile b/Makefile
index 4104f70..442c157 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,8 @@ MODDIR=$(DESTDIR)/usr/share/perl5/
 
 CFLAGS=-O2 -Wall -g
 BINS=iki-git-shell iki-git-hook-update ikisite-wrapper
-SCRIPTS=ikisite ikidns ikisite-delete-unfinished-site
-MANS=ikisite ikidns ikisite-wrapper ikisite-delete-unfinished-site
+SCRIPTS=ikisite ikidns ikiwiki-hosting-web-daily ikisite-delete-unfinished-site 
+MANS=ikisite ikidns ikisite-wrapper ikiwiki-hosting-web-daily ikisite-delete-unfinished-site
 
 IKIWIKI=ikiwiki --wikiname "ikiwiki hosting internals" \
 		--no-usedirs --underlaydir=/dev/null \
diff --git a/debian/control b/debian/control
index d8186d2..3a77875 100644
--- a/debian/control
+++ b/debian/control
@@ -13,7 +13,7 @@ Description: ikiwiki hosting: common files
 
 Package: ikiwiki-hosting-web
 Architecture: any
-Depends: ${misc:Depends}, ${perl:Depends}, ikiwiki-hosting-common, ikiwiki (>= 3.20100723), gcc | c-compiler, libc6-dev | libc-dev, git (>= 1:1.7.0), libxml-simple-perl, libnet-openid-consumer-perl (>= 1.03), liblwpx-paranoidagent-perl, libtimedate-perl, libdatetime-perl, libcgi-formbuilder-perl (>= 3.05), libcgi-session-perl (>= 4.14-1), libmail-sendmail-perl, libauthen-passphrase-perl, librpc-xml-perl, libtext-wikiformat-perl, python-docutils, polygen, libhtml-tree-perl, libxml-feed-perl, libmailtools-perl, perlmagick, libfile-mimeinfo-perl, libcrypt-ssleay-perl, liblocale-gettext-perl (>= 1.05-1), libtext-typography-perl, libtext-csv-perl, libdigest-sha1-perl, libtext-wikicreole-perl, libtext-textile-perl, libhighlight-perl, apache2, dnsutils, libyaml-perl, libyaml-syck-perl, uuid, dnsutils, gitweb (>= 1:1.7.0), libtext-markdown-perl (>= 1.0.26-1~bpo50+1)
+Depends: ${misc:Depends}, ${perl:Depends}, ikiwiki-hosting-common, ikiwiki (>= 3.20100723), gcc | c-compiler, libc6-dev | libc-dev, git (>= 1:1.7.0), libxml-simple-perl, libnet-openid-consumer-perl (>= 1.03), liblwpx-paranoidagent-perl, libtimedate-perl, libdatetime-perl, libcgi-formbuilder-perl (>= 3.05), libcgi-session-perl (>= 4.14-1), libmail-sendmail-perl, libauthen-passphrase-perl, librpc-xml-perl, libtext-wikiformat-perl, python-docutils, polygen, libhtml-tree-perl, libxml-feed-perl, libmailtools-perl, perlmagick, libfile-mimeinfo-perl, libcrypt-ssleay-perl, liblocale-gettext-perl (>= 1.05-1), libtext-typography-perl, libtext-csv-perl, libdigest-sha1-perl, libtext-wikicreole-perl, libtext-textile-perl, libhighlight-perl, apache2, dnsutils, libyaml-perl, libyaml-syck-perl, uuid, dnsutils, gitweb (>= 1:1.7.0), libtext-markdown-perl (>= 1.0.26-1~bpo50+1), moreutils (>= 0.43)
 Description: ikiwiki hosting: web server scripts
  The ikisite script, and other stuff to install on each web server.
 
diff --git a/debian/ikiwiki-hosting-web.cron.daily b/debian/ikiwiki-hosting-web.cron.daily
index 89f1454..6761e63 100644
--- a/debian/ikiwiki-hosting-web.cron.daily
+++ b/debian/ikiwiki-hosting-web.cron.daily
@@ -1,40 +1,5 @@
 #!/bin/sh
-# Daily cron job for ikiwiki-hosting-web.
-
-if [ ! -x /usr/bin/ikisite ]; then
-	exit 0
-fi
-
-mynice () {
-	nice -n 19 ionice -c 3 "$@"
-}
-
-# Clean up unfinished sites.
-ikisite-delete-unfinished-site --all
-
-(
-
-for site in $(ikisite list); do
-	# Rotate logs, gc git repos, etc.
-	# Uses git, and can be noisy to stderr, so shut it up.
-	mynice ikisite compact "$site" 2>&1
-
-	# Back up each site.
-	bdir="/var/backups/ikiwiki-hosting-web/$site"
-	mkdir -p "$bdir"
-	if [ -e "$bdir/backup" ]; then
-		mynice savelog "$bdir/backup" # keeps a week's worth of backups
-	fi
-	# this uses git, which is noisy to stderr, so shut it up
-	if ! mynice ikisite backup "$site" --filename="$bdir"/backup 2>&1; then
-		echo "ikisite backup $site failed!" >&2
-	fi
-
-	# Update calendars for sites that have the calendar plugin enabled.
-	mynice ikisite calendar "$site"
-done
-
-# Reload apache so it will start logging to the new site log files.
-/etc/init.d/apache2 reload
-
-) >/dev/null
+# Just run the daily cron job for ikiwiki-hosting-web.
+# This is a low-priority background job.
+# It can be a bit noisy, so chronic is used to only show output on error.
+nice -n 19 ionice -c 3 chronic ikiwiki-hosting-web-daily
diff --git a/doc/ikisite-delete-unfinished-site.mdwn b/doc/ikisite-delete-unfinished-site.mdwn
index 4fb601c..e6a896d 100644
--- a/doc/ikisite-delete-unfinished-site.mdwn
+++ b/doc/ikisite-delete-unfinished-site.mdwn
@@ -8,13 +8,13 @@ ikisite-delete-unfinished-site openid|--all [--dry-run]
 
 # DESCRIPTION
 
-This helper script is run from cron, and deletes sites that someone
-started to create, but never finished setting up.
+This helper script is run by [[ikiwiki-hosting-web-daily]],
+and deletes sites that someone started to create, but never finished
+setting up.
 
 # SEE ALSO
 
-* [[ikidns]](1)
-* [[ikisite-wrapper]](1)
+* [[ikisite]](1)
 
 # AUTHOR
 
diff --git a/doc/ikiwiki-hosting-web-daily.mdwn b/doc/ikiwiki-hosting-web-daily.mdwn
new file mode 100644
index 0000000..22967e3
--- /dev/null
+++ b/doc/ikiwiki-hosting-web-daily.mdwn
@@ -0,0 +1,23 @@
+# NAME
+
+ikiwiki-hosting-web-daily - run by cron daily
+
+# SYNOPSIS
+
+ikiwiki-hosting-web-daily
+
+# DESCRIPTION
+
+This script is run daily by cron, as a low-priority job.
+It does various cleanup and bookkeeping tasks, including backing up
+all sites, rotating their logs, and updating their calendars.
+
+# SEE ALSO
+
+* [[ikisite]](1)
+
+# AUTHOR
+
+Joey Hess <joey@ikiwiki.info>
+
+Warning: this page is automatically made into a man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD).  Edit with care
diff --git a/doc/index.mdwn b/doc/index.mdwn
index b0a1a3a..cc05ef0 100644
--- a/doc/index.mdwn
+++ b/doc/index.mdwn
@@ -14,6 +14,7 @@ Commands:
 * [[ikisite]]
 * [[ikidns]]
 * [[ikisite-wrapper]]
+* [[ikiwiki-hosting-web-daily]]
 * [[ikisite-delete-unfinished-site]]
 
 This wiki is built from the files in the doc directory of
diff --git a/ikiwiki-hosting-web-daily b/ikiwiki-hosting-web-daily
new file mode 100755
index 0000000..9f975e5
--- /dev/null
+++ b/ikiwiki-hosting-web-daily
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Run by daily cron job.
+
+failed=""
+
+# Clean up unfinished sites.
+ikisite-delete-unfinished-site --all
+
+for site in $(ikisite list); do
+	# Rotate logs, gc git repos, etc.
+	ikisite compact "$site"
+
+	# Back up each site.
+	bdir="/var/backups/ikiwiki-hosting-web/$site"
+	mkdir -p "$bdir"
+	if [ -e "$bdir/backup" ]; then
+		savelog "$bdir/backup" # keeps a week's worth of backups
+	fi
+	# this uses git, which is noisy to stderr, so shut it up
+	if ! ikisite backup "$site" --filename="$bdir"/backup; then
+		echo "ikisite backup $site failed!" >&2
+		failed=1
+	fi
+
+	# Update calendars for sites that have the calendar plugin enabled.
+	ikisite calendar "$site"
+done
+
+# Reload apache so it will start logging to the new site log files.
+/etc/init.d/apache2 reload
+		
+if [ "$failed" ]; then
+	exit 1
+else
+	exit 0
+fi

logs moved
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index d1cd67c..2df76c2 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -26,7 +26,7 @@ Something like this:
 that commit, but I find git diff isn't very useful for long dependency
 lists otherwise...)
 
-suexec will only work if the CGI script is under /var/www, owned by
+suexec will only work if the CGI script is under /var/www, owned b
 `b-example`, not writeable by anyone else, and in a directory also meeting
 those conditions; CGIs not meeting those conditions won't be executed at
 all.
@@ -158,6 +158,8 @@ the home directory contain a logs/ symlink for convenience?
 > something filling the logs doesn't necessarily full the home partition
 > too. --[[Joey]] 
 
+>> I've added that to my branch. --[[smcv]]
+
 ## users not owning their own $HOME?
 
 One way to avoid various privilege escalations would be for the site

thought
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 760c343..d1cd67c 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -95,7 +95,14 @@ it as server-wide configuration that should be backed up as part of `/etc`,
 > There will be frontends to configure common stuff in it later, and
 > it is site-specific apache configuration, that needs to be transferred
 > along with the site if it is, say, bundled and transferred to a different
-> server. --[[Joey]]
+> server.
+> 
+> What could be done is to use `apache-site.tmpl`, and add to it variables
+> exposing and configuring stuff like htpasswd setup or whatever else
+> is needed (we have some collectd monitoring snippets in one of our
+> sites at branchable, for example). Then have
+> ikiwiki.setup hold the configuration for those variables.
+> --[[Joey]]
 
 create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:
 

notes
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 07c9816..760c343 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -71,6 +71,10 @@ of the home directory can be private.
 ikisite loads `ikiwiki.setup` in "safe mode", so hopefully there's no
 possibility of arbitrary code execution there.
 
+> Specifically, safe mode prevents ikiwiki.setup from being a perl script.
+> Of course, if any value is used in an insecure way by ikisite, it loses.
+> --[[Joey]]
+
 ## apache.conf.tmpl
 
 `apache.conf.tmpl` is, if not root-equivalent, then at least `www-data`-equivalent,
@@ -78,8 +82,21 @@ because it can set security-related Apache configuration. I've noticed that it's
 not backed up, but it *is* restored from backups and `chown`'d to root, so restoring
 an untrusted backup is currently dangerous.
 
+> `apache.conf.tmpl` *is* backed up; it's committed to the setup branch.
+> 
+> Restoring from an untrusted backup is dangerous anyway, because for
+> example `ikiwiki.setup` can be configured to make ikiwiki run arbitrary
+> code. All the dangerous stuff should be confined to the setup branch,
+> which is why pushing that branch is rejected. --[[Joey]]
+
 Since only root can set this up anyway, I'd personally be inclined to treat
 it as server-wide configuration that should be backed up as part of `/etc`,
+
+> There will be frontends to configure common stuff in it later, and
+> it is site-specific apache configuration, that needs to be transferred
+> along with the site if it is, say, bundled and transferred to a different
+> server. --[[Joey]]
+
 create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:
 
     <VirtualHost *:80>
@@ -106,6 +123,8 @@ If the `HTML::Template` functionality is useful in practice (is it?),
 I don't know what you put in here in practice, so I don't know whether
 it can cause privilege escalation :-)
 
+> Currently, only htpasswd files. --[[Joey]]
+
 ## logs
 
 <http://httpd.apache.org/docs/2.2/misc/security_tips.html#serverroot> says:
@@ -125,6 +144,13 @@ put the logs in `/var/log/apache2/b-example/` or
 `/var/log/apache2/example.branchable.com/` or whatever, and have
 the home directory contain a logs/ symlink for convenience?
 
+> I think it's reasonable to move the logs outside of home. Having a
+> symlink would only encourage something to write through the symlink,
+> breaking security again. The other issue with having them outside of home
+> is /var needs to have space for them -- but this also means that
+> something filling the logs doesn't necessarily full the home partition
+> too. --[[Joey]] 
+
 ## users not owning their own $HOME?
 
 One way to avoid various privilege escalations would be for the site

could solve some of this by the user not owning $HOME, but that might cause more problems
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index f37dbca..07c9816 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -20,8 +20,11 @@ Possible fixes:
 
 ### Use Apache's `suexec`
 
-Like this:
-<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/shortlog/suexec>
+Something like this:
+<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/shortlog/suexec>.
+(If you don't want to put the Debian dependencies one per line, leave out
+that commit, but I find git diff isn't very useful for long dependency
+lists otherwise...)
 
 suexec will only work if the CGI script is under /var/www, owned by
 `b-example`, not writeable by anyone else, and in a directory also meeting
@@ -102,3 +105,37 @@ If the `HTML::Template` functionality is useful in practice (is it?),
 
 I don't know what you put in here in practice, so I don't know whether
 it can cause privilege escalation :-)
+
+## logs
+
+<http://httpd.apache.org/docs/2.2/misc/security_tips.html#serverroot> says:
+
+> If the logs directory is writeable (by a non-root user), someone could
+> replace a log file with a symlink to some other system file, and then
+> root might overwrite that file with arbitrary data.
+
+I don't know how plausible that is in practice, but on shared
+hosting services I've used in the past, the base directory for my
+website has been owned by root, with docroot, cgi-bin etc. subdirectories
+owned and writeable by me, and a logs directory not owned by me.
+
+If you want users to own their own home directories (which ikisite
+does currently assume), an alternative way to do this would be to
+put the logs in `/var/log/apache2/b-example/` or
+`/var/log/apache2/example.branchable.com/` or whatever, and have
+the home directory contain a logs/ symlink for convenience?
+
+## users not owning their own $HOME?
+
+One way to avoid various privilege escalations would be for the site
+users' home directories to be owned by root and not writeable by the
+user, with particular subdirectories writeable. Things that that
+would break:
+
+* the code in ikisite that replaces ikiwiki.setup
+* ikiwiki.setup in general, possibly, depending how ikiwiki rewrites it
+  (an easy workaround would be to put it in a subdirectory)
+* any random program that assumes it can replace a dotfile by creating
+  a temporary file and renaming over the original
+
+Probably not worth it...

a commit exists, it even seems to work
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 6ce6233..270e032 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -43,7 +43,9 @@ Things that need to be readable by other than the site user:
 > access to gitweb config as a nice side-effect. `git-daemon` still
 > needs read access to each *branchable* site's `source.git` - perhaps
 > the branchable plugin could set/clear bits 005 as appropriate?
-> --[[smcv]]
+>
+> I've started to lock down permissions on the `smcv` branch in my
+> git repository. Not done yet: source.git, public_html. --[[smcv]]
 
 * `~/apache.conf` and `~/apache` (could be 640 user:www-data)
 

suexec is now more than one commit
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 76bfcdc..f37dbca 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -21,7 +21,7 @@ Possible fixes:
 ### Use Apache's `suexec`
 
 Like this:
-<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/commitdiff/suexec>
+<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/shortlog/suexec>
 
 suexec will only work if the CGI script is under /var/www, owned by
 `b-example`, not writeable by anyone else, and in a directory also meeting

apache.conf etc.
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
index 5006f56..76bfcdc 100644
--- a/doc/security/privilege_escalation.mdwn
+++ b/doc/security/privilege_escalation.mdwn
@@ -60,7 +60,45 @@ suexec is that the user owns it.
     #!/bin/sh
     exec /usr/lib/cgi-bin/gitweb.cgi "$@"
 
+As noted on [[homedir perms]] this has the nice side-effect that more
+of the home directory can be private.
+
 ## ikisite parsing `ikiwiki.setup`
 
 ikisite loads `ikiwiki.setup` in "safe mode", so hopefully there's no
 possibility of arbitrary code execution there.
+
+## apache.conf.tmpl
+
+`apache.conf.tmpl` is, if not root-equivalent, then at least `www-data`-equivalent,
+because it can set security-related Apache configuration. I've noticed that it's
+not backed up, but it *is* restored from backups and `chown`'d to root, so restoring
+an untrusted backup is currently dangerous.
+
+Since only root can set this up anyway, I'd personally be inclined to treat
+it as server-wide configuration that should be backed up as part of `/etc`,
+create `/etc/apache2/ikisite`, and put something like this in `apache-site.tmpl`:
+
+    <VirtualHost *:80>
+        ServerName <TMPL_VAR HOSTNAME>:80
+        ...
+        Include /etc/apache2/ikisite/<TMPL_VAR USER>.*.conf
+    </VirtualHost>
+
+    <VirtualHost *:80>
+        ServerName <TMPL_VAR HOSTNAME>:80
+        ...
+        Include /etc/apache2/ikisite/src.<TMPL_VAR USER>.*.conf
+    </VirtualHost>
+
+Then you can put whatever you want in those files. Note that Apache considers
+it to be a syntax error if an `Include` directory doesn't exist, but is
+perfectly happy if a glob fails to match any files.
+
+If the `HTML::Template` functionality is useful in practice (is it?),
+`ikisite` could perhaps automatically generate `foo.conf` from `foo.tmpl`.
+
+## `~/apache/`
+
+I don't know what you put in here in practice, so I don't know whether
+it can cause privilege escalation :-)

more thoughts about permissions
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 9e7d055..6ce6233 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -28,19 +28,29 @@ Things that are world-readable and need not be:
 Things that need to be readable by other than the site user:
 
 * `~/public_html`
-* `~/source.git`
-* `~/source/.ikiwiki/gitweb*`
-* `~/apache.conf` and `~/apache` (could be 640 user:www-data)
 
 > `public_html` only needs to be written by the site user and read by www-data,
-> strictly speaking.
->
-> `source.git` only needs to be readable if the site is branchable?
->
+> strictly speaking. It could be 750. --[[smcv]]
+
+* `~/source/.ikiwiki/gitweb*`
+* `~/source.git`
+
 > It seems odd that the gitweb stuff is in `.ikiwiki`: it'd
 > make more sense to put it at top level, or even in `source.git`?
+>
+> However, if you run each user's gitweb under `suexec` to avoid
+> [[privilege escalation]] to www-data, then only the site user needs
+> access to gitweb config as a nice side-effect. `git-daemon` still
+> needs read access to each *branchable* site's `source.git` - perhaps
+> the branchable plugin could set/clear bits 005 as appropriate?
 > --[[smcv]]
 
+* `~/apache.conf` and `~/apache` (could be 640 user:www-data)
+
+> apache.conf.tmpl is root-equivalent, so it needs to be root:root.
+> As noted on [[privilege escalation]] I'm not sure that having it
+> in the homedir is such a great idea... --[[smcv]]
+
 Things that are already appropriatly locked-down:
 
 * `~/logs`

initial thoughts about how privileges can be escalated
diff --git a/doc/security/privilege_escalation.mdwn b/doc/security/privilege_escalation.mdwn
new file mode 100644
index 0000000..5006f56
--- /dev/null
+++ b/doc/security/privilege_escalation.mdwn
@@ -0,0 +1,66 @@
+(I originally reported this by private email, but Joey is fairly sure it's not
+exploitable on branchable.com, so I'm summarizing discussion here. --[[smcv]])
+
+By design, the hosted users aren't meant to be able to execute arbitrary code.
+However, if they can (due to a bug), they can get arbitrary code executed as
+`www-data`, at which point they can interfere with other users, steal
+`httpauth` passwords (although those aren't supported on `branchable.com`),
+and so on.
+
+For this page I'll assume that the user trying to escalate privilege is
+`b-example`.
+
+## IkiWiki CGI
+
+If the user can remove the setuid/setgid bits from their ikiwiki.cgi wrapper
+(which they own), it'll execute as `www-data`. They could then get anything
+executed with `www-data` privileges.
+
+Possible fixes:
+
+### Use Apache's `suexec`
+
+Like this:
+<http://git.pseudorandom.co.uk/smcv/ikiwiki-hosting.git/commitdiff/suexec>
+
+suexec will only work if the CGI script is under /var/www, owned by
+`b-example`, not writeable by anyone else, and in a directory also meeting
+those conditions; CGIs not meeting those conditions won't be executed at
+all.
+
+### Central setuid-root wrapper
+
+Have a central setuid-root wrapper `/usr/lib/ikiwiki-hosting/ikiwiki.cgi`
+which is only executable by www-data, and when run with
+`IKISITE_USER=b-example` or something, switches user/group to `b-example`
+and execs `/home/b-example/public_html/ikiwiki.cgi`. This is basically
+reinventing suexec.
+
+Joey pointed out that because ikiwiki plugins are allowed to add C code to
+the `cgi_wrapper`, every site's C CGI wrapper can be different, so the
+central setuid-root wrapper would have to be a wrapper for a wrapper.
+
+## Gitweb CGI
+
+`gitweb` will run arbitrary Perl code from `.ikiwiki/gitweb.conf.real`.
+Possible fixes:
+
+### Configuration elsewhere
+
+Put the gitweb.conf somewhere else (`/var/lib/ikiwiki-hosting-web/gitweb`?)
+and have root own it, so `www-data` can't be subverted.
+
+### Use `suexec` again
+
+Install a wrapper in each user's `suexec` directory, owned by the user
+themselves, so that each user's gitweb runs with the privileges of that user,
+via suexec. The wrapper can be as simple as this: the important thing for
+suexec is that the user owns it.
+
+    #!/bin/sh
+    exec /usr/lib/cgi-bin/gitweb.cgi "$@"
+
+## ikisite parsing `ikiwiki.setup`
+
+ikisite loads `ikiwiki.setup` in "safe mode", so hopefully there's no
+possibility of arbitrary code execution there.

close
diff --git a/doc/bugs/domains_with_multiple_dots.mdwn b/doc/bugs/domains_with_multiple_dots.mdwn
index f42f0f8..a859272 100644
--- a/doc/bugs/domains_with_multiple_dots.mdwn
+++ b/doc/bugs/domains_with_multiple_dots.mdwn
@@ -25,6 +25,9 @@ create domains.
 >> for an existing and nonexistent `foo`, and I just get the error
 >> `unknown prefix for foo.wiki.pseudorandom.co.uk`. --[[smcv]]
 
+>>> Ah, good, so it does. Cherry-picked this (and most of your general
+>>> changesets). [[done]] --[[Joey]]
+
     From 75db93d2dca5c95f0244c073c764915ee92154e3 Mon Sep 17 00:00:00 2001
     From: Simon McVittie <smcv@debian.org>
     Date: Fri, 24 Sep 2010 21:39:56 +0100

doesn't seem to be a problem due to a later check
diff --git a/doc/bugs/domains_with_multiple_dots.mdwn b/doc/bugs/domains_with_multiple_dots.mdwn
index 8b60b09..f42f0f8 100644
--- a/doc/bugs/domains_with_multiple_dots.mdwn
+++ b/doc/bugs/domains_with_multiple_dots.mdwn
@@ -17,6 +17,14 @@ create domains.
 > `%config` and only allow one-level subdomains of domains configured
 > there. --[[Joey]]
 
+>> The next thing ikisite does is to split into hostname and domain parts,
+>> using `prefix_?` as you advised: the check I'm patching here seems to
+>> just be a quick way to refuse completely invalid hostnames? The user
+>> can only create `source.foo.branchable.com` if a `prefix` points to
+>> `foo.branchable.com` (i.e. admin error). I've tried out `source.foo`
+>> for an existing and nonexistent `foo`, and I just get the error
+>> `unknown prefix for foo.wiki.pseudorandom.co.uk`. --[[smcv]]
+
     From 75db93d2dca5c95f0244c073c764915ee92154e3 Mon Sep 17 00:00:00 2001
     From: Simon McVittie <smcv@debian.org>
     Date: Fri, 24 Sep 2010 21:39:56 +0100

world-readability
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 50e5dbb..9e7d055 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -32,6 +32,15 @@ Things that need to be readable by other than the site user:
 * `~/source/.ikiwiki/gitweb*`
 * `~/apache.conf` and `~/apache` (could be 640 user:www-data)
 
+> `public_html` only needs to be written by the site user and read by www-data,
+> strictly speaking.
+>
+> `source.git` only needs to be readable if the site is branchable?
+>
+> It seems odd that the gitweb stuff is in `.ikiwiki`: it'd
+> make more sense to put it at top level, or even in `source.git`?
+> --[[smcv]]
+
 Things that are already appropriatly locked-down:
 
 * `~/logs`

home dir content audit
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 2b09a9c..50e5dbb 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -13,3 +13,27 @@ down to 700?
 
 >> Would 0711 on the home dir work? Ah, but everyone will have
 >> files with well-known names. --[[liw]]
+
+---
+
+Things that are world-readable and need not be:
+
+* `~/source/.ikiwiki` (other than the gitweb config files randomly
+  located in here)
+* `~/source` as a whole
+* `~/.git`
+* `~/ikiwiki.setup`
+* `~/.gitconfig`, `~/.gitignore`
+
+Things that need to be readable by other than the site user:
+
+* `~/public_html`
+* `~/source.git`
+* `~/source/.ikiwiki/gitweb*`
+* `~/apache.conf` and `~/apache` (could be 640 user:www-data)
+
+Things that are already appropriatly locked-down:
+
+* `~/logs`
+* `~/.ssh/authorized_keys`
+* `~/.ikisite-nonce` (transient file)

patch insecure
diff --git a/doc/bugs/domains_with_multiple_dots.mdwn b/doc/bugs/domains_with_multiple_dots.mdwn
index f7b88e7..8b60b09 100644
--- a/doc/bugs/domains_with_multiple_dots.mdwn
+++ b/doc/bugs/domains_with_multiple_dots.mdwn
@@ -8,6 +8,15 @@ create domains.
 [[Patch]] (which can also be cherry-picked from
 `git://git.pseudorandom.co.uk/git/smcv/ikiwiki-hosting.git`):
 
+> This is not entirely safe to apply. The problem is that
+> `source.$foo.branchable.com` is a reserved domain name. If a user can 
+> create that site for someone else's $foo, they can at a mimimum make
+> apache unhappy with conflicting vhosts, and at the worse, engage in evil.
+> 
+> To do this securely, it needs to look at the `prefix_?` keys in
+> `%config` and only allow one-level subdomains of domains configured
+> there. --[[Joey]]
+
     From 75db93d2dca5c95f0244c073c764915ee92154e3 Mon Sep 17 00:00:00 2001
     From: Simon McVittie <smcv@debian.org>
     Date: Fri, 24 Sep 2010 21:39:56 +0100

move discussion from internal
diff --git a/doc/security/homedir_perms.mdwn b/doc/security/homedir_perms.mdwn
index 943239b..2b09a9c 100644
--- a/doc/security/homedir_perms.mdwn
+++ b/doc/security/homedir_perms.mdwn
@@ -1,2 +1,15 @@
 Home directory perms currently allow global reading of most files. Lock
 down to 700?
+
+> I think I agree with 0700. Let's do that and see what breaks. --liw
+
+> The first thing to break will be apache, so this will need to be done
+> with care.. Probably safest to only lock down `source`, `source.git`,
+> `~/.git`, `~/ikiwiki.setup`.
+>
+> Hmm, the git daemon and gitweb run unprivilidged and need access to
+> `source/.ikiwiki` (gitweb config files could move elsewhere) and
+> `source.git` .. --[[Joey]]
+
+>> Would 0711 on the home dir work? Ah, but everyone will have
+>> files with well-known names. --[[liw]]

not everyone has a second-level domain :-)
diff --git a/doc/bugs/domains_with_multiple_dots.mdwn b/doc/bugs/domains_with_multiple_dots.mdwn
new file mode 100644
index 0000000..f7b88e7
--- /dev/null
+++ b/doc/bugs/domains_with_multiple_dots.mdwn
@@ -0,0 +1,34 @@
+I'm trying out running a copy of ikiwiki-hosting myself, in a subdomain of
+`pseudorandom.co.uk` (non-commercially - I'm not trying to compete with
+Branchable!). However, ikisite refuses to create subdomains, because it
+assumes that entries in `domains` contain exactly one dot (so `example.com`
+would be fine, but `example.co.uk` wouldn't work). This patch lets it
+create domains.
+
+[[Patch]] (which can also be cherry-picked from
+`git://git.pseudorandom.co.uk/git/smcv/ikiwiki-hosting.git`):
+
+    From 75db93d2dca5c95f0244c073c764915ee92154e3 Mon Sep 17 00:00:00 2001
+    From: Simon McVittie <smcv@debian.org>
+    Date: Fri, 24 Sep 2010 21:39:56 +0100
+    Subject: [PATCH] ikisite: allow base hostnames with more than one dot (like example.co.uk)
+    
+    ---
+     ikisite |    2 +-
+     1 files changed, 1 insertions(+), 1 deletions(-)
+    
+    diff --git a/ikisite b/ikisite
+    index b1e9cb5..dcac43f 100755
+    --- a/ikisite
+    +++ b/ikisite
+    @@ -747,7 +747,7 @@ sub username {
+     	my $hostname=lc(shift);
+     	
+     	# paranoia: make sure the hostname looks like a FQDN
+    -	if ($hostname !~ /^([a-z0-9][-a-z0-9]*)\.\w+\.\w+$/) {
+    +	if ($hostname !~ /^([a-z0-9][-a-z0-9]*)\.\w+(\.\w+)+$/) {
+     		error "illegal hostname \"$hostname\"";
+     	}
+     	if (length $hostname > 252) { # why not 253? Trailing dot..
+    -- 
+    1.7.1

close
diff --git a/doc/todo/directory.mdwn b/doc/todo/directory.mdwn
index 25ea206..3515213 100644
--- a/doc/todo/directory.mdwn
+++ b/doc/todo/directory.mdwn
@@ -32,3 +32,5 @@ If we had a privacy flag, sites would need to be hidden if the flag
 was set, and unhidden if it was cleared. Deferred for later. We'd
 probably want to manually review sites in a public directory anyway,
 and tag ones we want to publish.
+
+[[done]]

add observation framework
diff --git a/IkiWiki/Hosting.pm b/IkiWiki/Hosting.pm
index f77c1ce..53bca7e 100644
--- a/IkiWiki/Hosting.pm
+++ b/IkiWiki/Hosting.pm
@@ -312,26 +312,6 @@ sub syslog {
 	syslog('debug', "$subcommand: $message");
 }
 
-# used only for recording a few specific actions:
-# site creation and deletion
-sub accounting_log ($$;$) {
-	my $action=shift; # "create" or "delete"
-	my $hostname=shift;
-	my $openid=shift; # only for create
-
-	open(ACCOUNTING_LOG, ">>", $config{accountinglog}) || error "$config{accountinglog}: $!";
-	if ($action eq "create") {
-		print ACCOUNTING_LOG gmtime(time)." create $hostname $openid\n";
-	}
-	elsif ($action eq "delete") {
-		print ACCOUNTING_LOG gmtime(time)." delete $hostname\n";
-	}
-	else {
-		error "accounting_log: unsupported action $action";
-	}
-	close ACCOUNTING_LOG;
-}
-
 sub dispatch {
 	my $logger=shift;
 	my $subcommand=shift;
diff --git a/doc/todo/directory.mdwn b/doc/todo/directory.mdwn
index cae6311..25ea206 100644
--- a/doc/todo/directory.mdwn
+++ b/doc/todo/directory.mdwn
@@ -16,7 +16,7 @@ be configured thus:
 	# These sites should each have a template named observesite.tmpl, which
 	# will be filled out to create pages under sites/existing/ and
 	# sites/removed/
-	observingsites="internal.branchable.com www.branchable.com"
+	observersites="internal.branchable.com www.branchable.com"
 
 `ikisite observe hostname` can be called with either an existing, or a
 non-existing hostname, and will update its pages for each of the observed
diff --git a/ikisite b/ikisite
index f719bd7..7bd1bed 100755
--- a/ikisite
+++ b/ikisite
@@ -89,7 +89,7 @@ sub create {
 
 	enable($hostname);
 
-	accounting_log("create", $hostname, $owner);
+	accountinglog("create", $hostname, $owner);
 
 	if ($options{createnonce}) {
 		# If IKISITE_NONCE was set to a non-dummy nonce
@@ -120,7 +120,7 @@ sub delete {
 	assert_siteexists($hostname, 1);
 	assert_wrapper_safe($hostname);
 	
-	accounting_log("delete", $hostname);
+	accountinglog("delete", $hostname);
 
 	disable($hostname);
 	ikiwikiclean($hostname);
@@ -339,7 +339,7 @@ sub restore {
 	if (! $options{"no-setup"}) {
 		ikiwikisetup($hostname);
 		enable($hostname);
-		accounting_log("create", $hostname, getsetup($hostname, "owner"));
+		accountinglog("create", $hostname, getsetup($hostname, "owner"));
 	}
 
 	runas($username, sub {
@@ -479,7 +479,7 @@ sub branch {
 
 	enable($newhostname);
 	
-	accounting_log("create", $newhostname,
+	accountinglog("create", $newhostname,
 	       defined $owner ? $owner : getsetup($newhostname, "owner"));
 	
 	if ($options{createnonce}) {
@@ -1601,6 +1601,28 @@ sub commitsetup {
 	});
 }
 
+sub meta_observe {
+	required => [qw{hostname}],
+	description => "informs observersites about site creation or removal",
+	section => "utility",
+}
+sub observe {
+	my $hostname=lc(shift);
+	my %options=@_;
+
+	assert_wrapper_denied();
+
+	readconfig();
+	return unless defined $config{observersites};
+	foreach my $observer (split(' ', $config{observersites})) {
+		next unless siteexists($observer);
+		
+		runas(username($observer), sub {
+				# TODO
+		});
+	}
+}
+
 sub meta_updatecustomersite {
 	required => [qw{hostname}],
 	options => [],
@@ -2107,6 +2129,42 @@ sub actionlog {
 	close LOG;
 }
 
+# used only for recording a few specific actions:
+# site creation and deletion
+sub accountinglog ($$;$) {
+	my $action=shift; # "create" or "delete"
+	my $hostname=shift;
+	my $openid=shift; # only for create
+
+	readconfig();
+	open(ACCOUNTING_LOG, ">>", $config{accountinglog}) || error "$config{accountinglog}: $!";
+	if ($action eq "create") {
+		print ACCOUNTING_LOG gmtime(time)." create $hostname $openid\n";
+	}
+	elsif ($action eq "delete") {
+		print ACCOUNTING_LOG gmtime(time)." delete $hostname\n";
+	}
+	else {
+		error "accountinglog: unsupported action $action";
+	}
+	close ACCOUNTING_LOG;
+	
+	# Inform observers as background job to avoid delaying eg, 
+	# site creation.
+	my $pid=IkiWiki::Hosting::daemonize();
+	if ($pid) {
+		return;
+	}
+	# Avoid keeping sites locked while daemonized.
+	foreach my $lock (keys %locks) {
+		close($lock);
+	}
+	# Wait a minute to let anything that is being done settle.
+	sleep(60);
+	observe($hostname);
+	exit;
+}
+
 sub nsupdate {
 	# chdir done here because nsupdate expects the other key in the pwd
 	chdir "$config{keydir}/dns" || error "chdir $config{keydir}/dns: $!";
diff --git a/ikiwiki-hosting.conf b/ikiwiki-hosting.conf
index c28172c..6fa5dfe 100644
--- a/ikiwiki-hosting.conf
+++ b/ikiwiki-hosting.conf
@@ -54,5 +54,11 @@ accountinglog=/var/log/ikiwiki-hosting/accounting.log
 # Hostname of site with controlpanel and makesite plugins enabled.
 #controlsite=www.example.com
 
+# List of sites that will be updated when sites are added/removed.
+# These sites should each have a template named observesite.tmpl, which
+# will be filled out to create pages under sites/existing/ and
+# sites/removed/
+#observersites="www.example.com"
+
 # Url to ikiwiki CGI for the control site.
 #controlsitecgiurl="http://www.example.com/ikiwiki.cgi"

site directory planning
diff --git a/doc/todo/directory.mdwn b/doc/todo/directory.mdwn
new file mode 100644
index 0000000..cae6311
--- /dev/null
+++ b/doc/todo/directory.mdwn
@@ -0,0 +1,34 @@
+Wanted: Directory of sites. Could be used for:
+
+* internal monitoring of what sites are being made and used
+* possibly, a public directory (modulo privacy concerns)
+
+Data structure could be a directory with pages, created by ikisite when it
+creates sites, by filling out a template. (And removed by ikisite when it
+deletes sites.) Then the pages could be used to build a rss feed of sites,
+or they could have aggregation directives, to make a planet of their
+recentchanges feeds.
+
+So, it needs to support multiple observing sites. At the simplest, it could
+be configured thus:
+
+	# List of sites that will be updated when sites are added/removed.
+	# These sites should each have a template named observesite.tmpl, which
+	# will be filled out to create pages under sites/existing/ and
+	# sites/removed/
+	observingsites="internal.branchable.com www.branchable.com"
+
+`ikisite observe hostname` can be called with either an existing, or a
+non-existing hostname, and will update its pages for each of the observed
+sites. It should only create the page for a hostname if it does not already
+exist (to allow us to annotate hostnames with our comments, etc). When
+removing a page, it should move it to removed/ (preserving its content).
+It should also move any subpages associated with the site. That way we 
+can add comments, screenshots, etc.
+
+----
+
+If we had a privacy flag, sites would need to be hidden if the flag
+was set, and unhidden if it was cleared. Deferred for later. We'd
+probably want to manually review sites in a public directory anyway,
+and tag ones we want to publish.

thoughts on using monkeysphere
diff --git a/doc/todo/monkeysphere_for_ssh_key_setup.mdwn b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
new file mode 100644
index 0000000..c7ddf83
--- /dev/null
+++ b/doc/todo/monkeysphere_for_ssh_key_setup.mdwn
@@ -0,0 +1,9 @@
+Eventually, I want to support using monkeysphere for ssh key configuration.
+
+This would allow the site owner to enter an email address, and have ssh keys
+for that user's email automatically retrieved. To help the site owner make
+sure the ssh key was signed by the right gpg key, it could display a partial
+web of trust. (Or, if we knew the user's own gpg key, we could do a better
+display).
+
+Revocations of configured keys could also be scanned for, and the keys disabled.
diff --git a/doc/todo/multiple_servers.mdwn b/doc/todo/multiple_servers.mdwn
index a9513dc..9d8c883 100644
--- a/doc/todo/multiple_servers.mdwn
+++ b/doc/todo/multiple_servers.mdwn
@@ -12,6 +12,8 @@ sites.
   (ssh's warning message about the IP changing is not scary)
   Alternate approach would be to proxy all ssh connections through a central
   server, which is IIRC what github does.
+  (Monkeysphere is a way to distribute ssh keys to users, but only if they
+  use it.)
 * DNS ttl issues when moving a site to a different host.
 * Hardcoded IPs in users' DNS prevent moving some sites around.
 * `ikisite list` only lists local sites, and is used by controlpanel etc.

start a howto
Conflicts:
doc/index.mdwn
diff --git a/doc/howto.mdwn b/doc/howto.mdwn
new file mode 100644
index 0000000..644cef9
--- /dev/null
+++ b/doc/howto.mdwn
@@ -0,0 +1,23 @@
+Shell recipes for various things.
+
+## Running a command on all sites
+
+Sometimes you have a ikisite command that needs to be run on every site.
+For example, adding a new setup option. No problem:
+
+	for s in $(ikisite list); do ikisite foo $s ; done
+
+## Parking a site
+
+A parked site has all remote access to its content disabled, and replaced
+with a vague message saying it is unavailable. This can be useful if there
+was a legal or payment problem.
+
+	sudo ikisite changesetup test.branchable.com --enable-plugin parked --rebuild
+
+Optionally, include `--set parked_message="reason why it was parked"`
+
+## Unparking a site
+
+	sudo ikisite changesetup test.branchable.com --disable-plugin parked --rebuild
+
diff --git a/doc/index.mdwn b/doc/index.mdwn
index 42b4e3d..b0a1a3a 100644
--- a/doc/index.mdwn
+++ b/doc/index.mdwn
@@ -7,6 +7,7 @@ Stuff here:
 * [[bugs]]
 * [[security]]
 * [[design]]
+* [[howto]]
 
 Commands:
 

split out commands
diff --git a/doc/index.mdwn b/doc/index.mdwn
index 7ff966a..42b4e3d 100644
--- a/doc/index.mdwn
+++ b/doc/index.mdwn
@@ -7,8 +7,13 @@ Stuff here:
 * [[bugs]]
 * [[security]]
 * [[design]]
+
+Commands:
+
 * [[ikisite]]
 * [[ikidns]]
+* [[ikisite-wrapper]]
+* [[ikisite-delete-unfinished-site]]
 
 This wiki is built from the files in the doc directory of
 the ikiwiki-hosting git repository. You can get the source code

add man page for new command and install it
diff --git a/Makefile b/Makefile
index 7674eaf..4104f70 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,8 @@ MODDIR=$(DESTDIR)/usr/share/perl5/
 
 CFLAGS=-O2 -Wall -g
 BINS=iki-git-shell iki-git-hook-update ikisite-wrapper
-SCRIPTS=ikisite ikidns
-MANS=ikisite ikidns ikisite-wrapper
+SCRIPTS=ikisite ikidns ikisite-delete-unfinished-site
+MANS=ikisite ikidns ikisite-wrapper ikisite-delete-unfinished-site
 
 IKIWIKI=ikiwiki --wikiname "ikiwiki hosting internals" \
 		--no-usedirs --underlaydir=/dev/null \
diff --git a/doc/ikisite-delete-unfinished-site.mdwn b/doc/ikisite-delete-unfinished-site.mdwn
new file mode 100644
index 0000000..4fb601c
--- /dev/null
+++ b/doc/ikisite-delete-unfinished-site.mdwn
@@ -0,0 +1,23 @@
+# NAME
+
+ikisite-delete-unfinished-site - ikiwiki-hosting helper
+
+# SYNOPSIS
+
+ikisite-delete-unfinished-site openid|--all [--dry-run]
+
+# DESCRIPTION
+
+This helper script is run from cron, and deletes sites that someone
+started to create, but never finished setting up.
+
+# SEE ALSO
+
+* [[ikidns]](1)
+* [[ikisite-wrapper]](1)
+
+# AUTHOR
+
+Joey Hess <joey@ikiwiki.info>
+
+Warning: this page is automatically made into a man page via [mdwn2man](http://git.ikiwiki.info/?p=ikiwiki;a=blob;f=mdwn2man;hb=HEAD).  Edit with care

add script to delete unfinished sites after 2 days
Conflicts:
doc/todo/cleanup_unowned_sites.mdwn
diff --git a/doc/todo/cleanup_unowned_sites.mdwn b/doc/todo/cleanup_unowned_sites.mdwn
new file mode 100644
index 0000000..8c71d08
--- /dev/null
+++ b/doc/todo/cleanup_unowned_sites.mdwn
@@ -0,0 +1,9 @@
+If a user starts to make a site, but never clicks the Finish button,
+the site will be made in the background, and linger around.
+
+Such sites can be detected because the admin is `http://none/`.
+
+Something should handle cleaning these up. Especially since
+the user may later try again with the same name.
+
+[[done]] -- ikisite-delete-unfinished-site written, can be used in cron job
diff --git a/ikisite-delete-unfinished-site b/ikisite-delete-unfinished-site
new file mode 100755
index 0000000..f3c6664
--- /dev/null
+++ b/ikisite-delete-unfinished-site
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+# Finds sites whose registration was not completed, and deletes
+# after a timeout period.
+
+my $timeout=2 * 24 * 60 * 60; # 2 days
+
+use warnings;
+use strict;
+use IkiWiki::Hosting;
+use Getopt::Long;
+
+sub usage {
+	die "usage: $0 openid|--all [--dry-run]\n";
+}
+
+my $all=0;
+my $dry_run=0;
+GetOptions(
+	"all" => \$all,
+	"dry-run" => \$dry_run,
+) || usage();
+
+IkiWiki::Hosting::readconfig();
+
+if ($> != getpwnam("root")) {
+	die "$0 must be run by root\n";
+}
+
+my @siteinfo;
+if ($all) {
+	usage() if @ARGV;
+	@siteinfo=(@{IkiWiki::Hosting::yamlgetshell(
+		"ikisite", "list", "--extended")});
+}
+else {
+	usage() unless @ARGV;
+	foreach my $openid (@ARGV) {
+		push @siteinfo, (@{IkiWiki::Hosting::yamlgetshell(
+			"ikisite", "list", "--extended",
+			"--owner=$openid")});
+	}
+}
+
+foreach my $site (@siteinfo) {
+	# Skip sites just created, to avoid deleting a site a user is still
+	# setting up.
+	next if $site->{site_create} + $timeout > time();
+
+	# An unfinished site will have a dummy adminuser openid,
+	# as set by the makesite plugin.
+	my @admins=@{IkiWiki::Hosting::yamlgetshell(
+		"ikisite", "getsetup", $site, "adminusers")};
+	next if grep { $_ ne "http://none/" } @admins;
+
+	print "deleting unfinished site ".$site->{site_hostname}."\n";
+	if (! $dry_run) {
+		IkiWiki::Hosting::shell("ikisite", "delete",
+			$site->{site_hostname})
+	}
+}

todo
diff --git a/doc/todo/resume_interrupted_site_creation.mdwn b/doc/todo/resume_interrupted_site_creation.mdwn
new file mode 100644
index 0000000..65f69a2
--- /dev/null
+++ b/doc/todo/resume_interrupted_site_creation.mdwn
@@ -0,0 +1,6 @@
+If a user goes to create a site, and at the confirmation screen, their
+browser crashes, or they get distracted, etc, the site is created, locked,
+and they cannot resume the creation. (After 2 days, a cron job will delete
+it.)
+
+It should be possible to resume somehow.

update
diff --git a/doc/howto.mdwn b/doc/howto.mdwn
index 644cef9..752242c 100644
--- a/doc/howto.mdwn
+++ b/doc/howto.mdwn
@@ -11,7 +11,7 @@ For example, adding a new setup option. No problem:
 
 A parked site has all remote access to its content disabled, and replaced
 with a vague message saying it is unavailable. This can be useful if there
-was a legal or payment problem.
+was a legal or payment problem, or to reserve a particular site name.
 
 	sudo ikisite changesetup test.branchable.com --enable-plugin parked --rebuild