diff options
-rw-r--r-- | IkiWiki/Plugin/git.pm | 2 | ||||
-rw-r--r-- | IkiWiki/Receive.pm | 29 | ||||
-rw-r--r-- | IkiWiki/Wrapper.pm | 4 | ||||
-rw-r--r-- | doc/git.mdwn | 7 | ||||
-rw-r--r-- | doc/tips/untrusted_git_push.mdwn | 119 | ||||
-rw-r--r-- | foo.mdwn | 1 |
6 files changed, 151 insertions, 11 deletions
diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index 84df56181..5bef92856 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -46,7 +46,7 @@ sub checkconfig () { #{{{ push @{$config{wrappers}}, { test_receive => 1, wrapper => $config{git_test_receive_wrapper}, - wrappermode => "0755", + wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"), }; } } #}}} diff --git a/IkiWiki/Receive.pm b/IkiWiki/Receive.pm index 9a672abc9..451a3fe8e 100644 --- a/IkiWiki/Receive.pm +++ b/IkiWiki/Receive.pm @@ -7,7 +7,8 @@ use strict; use IkiWiki; sub getuser () { #{{{ - my $user=(getpwuid($<))[0]; + # CALLER_UID is set by the suid wrapper, to the original uid + my $user=(getpwuid(exists $ENV{CALLER_UID} ? $ENV{CALLER_UID} : $<))[0]; if (! defined $user) { error("cannot determine username for $<"); } @@ -23,19 +24,31 @@ sub trusted () { #{{{ sub test () { #{{{ exit 0 if trusted(); + IkiWiki::lockwiki(); + IkiWiki::loadindex(); + # Dummy up a cgi environment to use when calling check_canedit # and friends. eval q{use CGI}; error($@) if $@; my $cgi=CGI->new; + $ENV{REMOTE_ADDR}='unknown' unless exists $ENV{REMOTE_ADDR}; + + # And dummy up a session object. require IkiWiki::CGI; my $session=IkiWiki::cgi_getsession($cgi); $session->param("name", getuser()); - $ENV{REMOTE_ADDR}='unknown' unless exists $ENV{REMOTE_ADDR}; - - IkiWiki::lockwiki(); - IkiWiki::loadindex(); - + # Make sure whatever user was authed is in the + # userinfo db. + require IkiWiki::UserInfo; + if (! IkiWiki::userinfo_get($session->param("name"), "regdate")) { + IkiWiki::userinfo_setall($session->param("name"), { + email => "", + password => "", + regdate => time, + }) || error("failed adding user"); + } + my %newfiles; foreach my $change (IkiWiki::rcs_receive()) { @@ -59,8 +72,8 @@ sub test () { #{{{ $change->{action} eq 'add') { if (defined $page) { if (IkiWiki->can("check_canedit")) { - IkiWiki::check_canedit($page, $cgi, $session); - next; + IkiWiki::check_canedit($page, $cgi, $session); + next; } } else { diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index 187314d16..0a2b8d4f8 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -55,7 +55,7 @@ EOF #include <string.h> extern char **environ; -char *newenviron[$#envsave+5]; +char *newenviron[$#envsave+6]; int i=0; addenv(char *var, char *val) { @@ -72,6 +72,8 @@ int main (int argc, char **argv) { $envsave newenviron[i++]="HOME=$ENV{HOME}"; newenviron[i++]="WRAPPED_OPTIONS=$configstring"; + asprintf(&s, "CALLER_UID=%i", getuid()); + newenviron[i++]=s; newenviron[i]=NULL; environ=newenviron; diff --git a/doc/git.mdwn b/doc/git.mdwn index e5fef6a5a..cdaf3d4e2 100644 --- a/doc/git.mdwn +++ b/doc/git.mdwn @@ -1,6 +1,13 @@ Ikiwiki is developed in a git repository and can be checked out like this: +[[!template id=note text=""" +You can push changes back to ikiwiki's git repository over the `git://` +transport, to update the wiki, if you'd like, instead of editing it on the +web. Changes that could not be made via the web will be automatically +rejected. +"""]] + git clone git://git.ikiwiki.info/ Or like this if your firewall only passes http traffic (slow): diff --git a/doc/tips/untrusted_git_push.mdwn b/doc/tips/untrusted_git_push.mdwn new file mode 100644 index 000000000..48024566b --- /dev/null +++ b/doc/tips/untrusted_git_push.mdwn @@ -0,0 +1,119 @@ +This tip will describe how to allow anyone on the planet to `git push` +changes into your wiki, without needing a special account. All a user needs +to know is: + + git clone git://your.wiki/path + # now modify any of the files the wiki would let you modify on the web + git push + +This is a wonderful thing to set up for users, because then they can work +on the wiki while offline, and they don't need to mess around with web +browsers. + +## security + +But, you might be wondering, how can this possibly be secure. Won't users +upload all sorts of garbage, change pages you don't want them to edit, and so +on. + +The key to making it secure is configuring ikiwiki to run as your git +repository's `pre-receive` hook. There it will examine every change that +untrusted users push into the wiki, and reject pushes that contain changes +that cannot be made using the web interface. + +So, unless you have the [[ikiwiki/plugin/attachment]] plugin turned on, +non-page files cannot be added. And if it's turned on, whatever +`allowed_attachments` checks you have configured will also check files +pushed into git. + +And, unless you have the [[ikiwiki/plugin/remove]] plugin turned on, no +files can be deleted. + +And if you have `locked_pages` configured, then it will also affect what's +pushed into git. + +Untrusted committers will also not be able to upload files with strange +modes, or push to any branch except for the configured `gitorigin_branch`, +or manipulate tags. + +One thing to keep an eye on is uploading large files. It may be easier to +do this via git push than using the web, and that could be abused. + +## user setup + +Add a dedicated user who will push in untrusted commits. This user should have +a locked password, and `git-shell` asĀ its shell. + + root@bluebird:/home/joey>adduser --shell=/usr/bin/git-shell--disabled-password anon + Adding user `anon' ... + +## ikiwiki setup + +You should set up ikiwiki before turning on anonymous push in git. + +Edit your wiki's setup file, and uncomment the lines for +`git_test_receive_wrapper` and `untrusted_committers`. + + # git pre-receive hook to generate + git_test_receive_wrapper => '/srv/git/ikiwiki.info/.git/hooks/pre-receive', + # unix users whose commits should be checked by the pre-receive hook + untrusted_committers => ['anon'], + +The `git_test_receive_wrapper` will become the git `pre-receive` hook. The +`untrusted_committers` list is the list of unix users who will be pushing in +untrusted changes. It should *not* include the user that ikiwiki normally runs +as. + +Once you're done modifying the setup file, don't forget to run +`ikiwiki -setup --refresh --wrappers` on it. + +## git setup + +You'll need to arrange the permissions on your bare git repository so that +user anon can write to it. One way to do it is to create a group, and put +both anon and your regular user in that group. Then make make the bare git +repository owned and writable by the group. See [[rcs/git]] for some more +tips on setting up a git repository with multiple committers. + +Note that anon should *not* be able to write to the `srcdir`, *only* to the bare git +repository for your wiki. + +If you want to allow git over `ssh`, generate a ssh key for anon, and +publish the *private* key for other people to use. This is optional; you +can use `git-daemon` instead and not worry about keys. + +Now set up `git-daemon`. It will need to run as user `anon`, and be +configured to export your wiki's bare git repository. I set it up as +follows in `/etc/inetd.conf`, and ran `/etc/init.d/openbsd-inetd restart`. + + git stream tcp nowait anon /usr/bin/git-daemon git-daemon --inetd --export-all --interpolated-path=/srv/git/%H%D /srv/git + +At this point you should be able to `git clone git://your.wiki/path` from +anywhere, and check out the source to your wiki. But you won't be able to +push to it yet, one more change is needed to turn that on. Edit the +`config` file of your bare git repository, and allow `git-daemon` to +receive pushes: + + [daemon] + receivepack = true + +Now pushes should be accepted, and your wiki immediatly be updated. If it +doesn't, check your git repo's permissions, and make sure that the +`post-update` and `pre-receive` hooks are suid so they run as the user who +owns the `srcdir`. + +## infelicities + +If a user tries to push a changeset that ikiwiki doesn't like, it will +abort the push before refs are updated. However, the changeset will still +be present in your repository, wasting space. Since nothing refers to it, +it will be expired eventually. You can speed up the expiry by running `git +prune`. + +When aborting a push, ikiwiki displays an error message about why it didn't +accept it. If using git over ssh, the user will see this error message, +which is probably useful to them. But `git-daemon` is buggy, and hides this +message from the user. This can make it hard for users to figure out why +their push was rejected. (If this happens to you, look at "'git log --stat +origin/master..`" and think about whether your changes would be accepted +over the web interface.) diff --git a/foo.mdwn b/foo.mdwn deleted file mode 100644 index 71badb62b..000000000 --- a/foo.mdwn +++ /dev/null @@ -1 +0,0 @@ -this should not be accepted |