Revivify unixauth and rsync plugins (and hook needed by rsync) lost in
[ikiwiki] / IkiWiki / Plugin / unixauth.pm
1 #!/usr/bin/perl
2 # Ikiwiki unixauth authentication.
3 package IkiWiki::Plugin::unixauth;
4
5 use warnings;
6 use strict;
7 use IkiWiki 2.00;
8
9 sub import {
10         hook(type => "getsetup", id => "unixauth", call => \&getsetup);
11                 hook(type => "formbuilder_setup", id => "unixauth",
12                         call => \&formbuilder_setup);
13                 hook(type => "formbuilder", id => "unixauth",
14                         call => \&formbuilder);
15         hook(type => "sessioncgi", id => "unixauth", call => \&sessioncgi);
16 }
17
18 sub getsetup () {
19         return
20         unixauth_type => {
21                         type => "string",
22                         example => "checkpassword",
23                         description => "type of authenticator; can be 'checkpassword' or 'pwauth'",
24                         safe => 0,
25                         rebuild => 1,
26         },
27         unixauth_command => {
28                         type => "string",
29                         example => "/path/to/checkpassword",
30                         description => "full path and any arguments",
31                         safe => 0,
32                         rebuild => 1,
33         },
34         unixauth_requiressl => {
35                         type => "boolean",
36                         example => "1",
37                         description => "require SSL? strongly recommended",
38                         safe => 0,
39                         rebuild => 1,
40         },
41         plugin => {
42                         description => "Unix user authentication",
43                         safe => 0,
44                         rebuild => 1,
45         },
46 }
47
48 # Checks if a string matches a user's password, and returns true or false.
49 sub checkpassword ($$;$) {
50         my $user=shift;
51         my $password=shift;
52         my $field=shift || "password";
53
54         # It's very important that the user not be allowed to log in with
55         # an empty password!
56         if (! length $password) {
57                         return 0;
58         }
59
60         my $ret=0;
61         if (! exists $config{unixauth_type}) {
62                         # admin needs to carefully think over his configuration
63                         return 0;
64         }
65         elsif ($config{unixauth_type} eq "checkpassword") {
66                         open UNIXAUTH, "|$config{unixauth_command} true 3<&0" or die("Could not run $config{unixauth_type}");
67                         print UNIXAUTH "$user\0$password\0Y123456\0";
68                         close UNIXAUTH;
69                         $ret=!($?>>8);
70         }
71         elsif ($config{unixauth_type} eq "pwauth") {
72                         open UNIXAUTH, "|$config{unixauth_command}" or die("Could not run $config{unixauth_type}");
73                         print UNIXAUTH "$user\n$password\n";
74                         close UNIXAUTH;
75                         $ret=!($?>>8);
76         }
77         else {
78                         # no such authentication type
79                         return 0;
80         }
81
82         if ($ret) {
83                 my $userinfo=IkiWiki::userinfo_retrieve();
84                 if (! length $user || ! defined $userinfo ||
85                         ! exists $userinfo->{$user} || ! ref $userinfo->{$user}) {
86                                 IkiWiki::userinfo_setall($user, {
87                                         'email' => '',
88                                         'regdate' => time,
89                                 });
90                 }
91         }
92
93         return $ret;
94 }
95
96 sub formbuilder_setup (@) {
97         my %params=@_;
98
99         my $form=$params{form};
100         my $session=$params{session};
101         my $cgi=$params{cgi};
102
103         # if not under SSL, die before even showing a login form,
104         # unless the admin explicitly says it's fine
105         if (! exists $config{unixauth_requiressl}) {
106                         $config{unixauth_requiressl} = 1;
107         }
108         if ($config{unixauth_requiressl}) {
109                 if ((! $config{sslcookie}) || (! exists $ENV{'HTTPS'})) {
110                         die("SSL required to login. Contact your administrator.<br>");
111                 }
112         }
113
114         if ($form->title eq "signin") {
115                         $form->field(name => "name", required => 0);
116                         $form->field(name => "password", type => "password", required => 0);
117
118                         if ($form->submitted) {
119                                         my $submittype=$form->submitted;
120                                         # Set required fields based on how form was submitted.
121                                         my %required=(
122                                                         "Login" => [qw(name password)],
123                                         );
124                                         foreach my $opt (@{$required{$submittype}}) {
125                                                         $form->field(name => $opt, required => 1);
126                                         }
127
128                                         # Validate password against name for Login.
129                                         if ($submittype eq "Login") {
130                                                         $form->field(
131                                                                         name => "password",
132                                                                         validate => sub {
133                                                                                         checkpassword($form->field("name"), shift);
134                                                                         },
135                                                         );
136                                         }
137
138                                         # XXX is this reachable? looks like no
139                                         elsif ($submittype eq "Login") {
140                                                         $form->field(
141                                                                         name => "name",
142                                                                         validate => sub {
143                                                                                         my $name=shift;
144                                                                                         length $name &&
145                                                                                         IkiWiki::userinfo_get($name, "regdate");
146                                                                         },
147                                                         );
148                                         }
149                         }
150                         else {
151                                         # First time settings.
152                                         $form->field(name => "name");
153                                         if ($session->param("name")) {
154                                                         $form->field(name => "name", value => $session->param("name"));
155                                         }
156                         }
157         }
158         elsif ($form->title eq "preferences") {
159                 $form->field(name => "name", disabled => 1,
160                                 value => $session->param("name"), force => 1,
161                                 fieldset => "login");
162                 $form->field(name => "password", disabled => 1, type => "password",
163                                 fieldset => "login"),
164         }
165 }
166
167 sub formbuilder (@) {
168         my %params=@_;
169
170         my $form=$params{form};
171         my $session=$params{session};
172         my $cgi=$params{cgi};
173         my $buttons=$params{buttons};
174
175         if ($form->title eq "signin") {
176                 if ($form->submitted && $form->validate) {
177                         if ($form->submitted eq 'Login') {
178                                 $session->param("name", $form->field("name"));
179                                 IkiWiki::cgi_postsignin($cgi, $session);
180                         }
181                 }
182         }
183         elsif ($form->title eq "preferences") {
184                 if ($form->submitted eq "Save Preferences" && $form->validate) {
185                         my $user_name=$form->field('name');
186                 }
187         }
188 }
189
190 sub sessioncgi ($$) {
191         my $q=shift;
192         my $session=shift;
193 }
194
195 1