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