OSDN Git Service

* BugTrack2/246: Should use array_key_exists($maybe, $null) here (patched by sonots).
[pukiwiki/pukiwiki.git] / lib / auth.php
1 <?php
2 // PukiWiki - Yet another WikiWikiWeb clone
3 // $Id: auth.php,v 1.22 2011/01/25 15:01:01 henoheno Exp $
4 // Copyright (C) 2003-2005, 2007 PukiWiki Developers Team
5 // License: GPL v2 or (at your option) any later version
6 //
7 // Authentication related functions
8
9 define('PKWK_PASSPHRASE_LIMIT_LENGTH', 512);
10
11 // Passwd-auth related ----
12
13 function pkwk_login($pass = '')
14 {
15         global $adminpass;
16
17         if (! PKWK_READONLY && isset($adminpass) &&
18                 pkwk_hash_compute($pass, $adminpass) === $adminpass) {
19                 return TRUE;
20         } else {
21                 sleep(2);       // Blocking brute force attack
22                 return FALSE;
23         }
24 }
25
26 // Compute RFC2307 'userPassword' value, like slappasswd (OpenLDAP)
27 // $phrase : Pass-phrase
28 // $scheme : Specify '{scheme}' or '{scheme}salt'
29 // $prefix : Output with a scheme-prefix or not
30 // $canonical : Correct or Preserve $scheme prefix
31 function pkwk_hash_compute($phrase = '', $scheme = '{x-php-md5}', $prefix = TRUE, $canonical = FALSE)
32 {
33         if (! is_string($phrase) || ! is_string($scheme)) return FALSE;
34
35         if (strlen($phrase) > PKWK_PASSPHRASE_LIMIT_LENGTH)
36                 die('pkwk_hash_compute(): malicious message length');
37
38         // With a {scheme}salt or not
39         $matches = array();
40         if (preg_match('/^(\{.+\})(.*)$/', $scheme, $matches)) {
41                 $scheme = & $matches[1];
42                 $salt   = & $matches[2];
43         } else if ($scheme != '') {
44                 $scheme  = ''; // Cleartext
45                 $salt    = '';
46         }
47
48         // Compute and add a scheme-prefix
49         switch (strtolower($scheme)) {
50
51         // PHP crypt()
52         case '{x-php-crypt}' :
53                 $hash = ($prefix ? ($canonical ? '{x-php-crypt}' : $scheme) : '') .
54                         ($salt != '' ? crypt($phrase, $salt) : crypt($phrase));
55                 break;
56
57         // PHP md5()
58         case '{x-php-md5}'   :
59                 $hash = ($prefix ? ($canonical ? '{x-php-md5}' : $scheme) : '') .
60                         md5($phrase);
61                 break;
62
63         // PHP sha1()
64         case '{x-php-sha1}'  :
65                 $hash = ($prefix ? ($canonical ? '{x-php-sha1}' : $scheme) : '') .
66                         sha1($phrase);
67                 break;
68
69         // LDAP CRYPT
70         case '{crypt}'       :
71                 $hash = ($prefix ? ($canonical ? '{CRYPT}' : $scheme) : '') .
72                         ($salt != '' ? crypt($phrase, $salt) : crypt($phrase));
73                 break;
74
75         // LDAP MD5
76         case '{md5}'         :
77                 $hash = ($prefix ? ($canonical ? '{MD5}' : $scheme) : '') .
78                         base64_encode(pkwk_hex2bin(md5($phrase)));
79                 break;
80
81         // LDAP SMD5
82         case '{smd5}'        :
83                 // MD5 Key length = 128bits = 16bytes
84                 $salt = ($salt != '' ? substr(base64_decode($salt), 16) : substr(crypt(''), -8));
85                 $hash = ($prefix ? ($canonical ? '{SMD5}' : $scheme) : '') .
86                         base64_encode(pkwk_hex2bin(md5($phrase . $salt)) . $salt);
87                 break;
88
89         // LDAP SHA
90         case '{sha}'         :
91                 $hash = ($prefix ? ($canonical ? '{SHA}' : $scheme) : '') .
92                         base64_encode(pkwk_hex2bin(sha1($phrase)));
93                 break;
94
95         // LDAP SSHA
96         case '{ssha}'        :
97                 // SHA-1 Key length = 160bits = 20bytes
98                 $salt = ($salt != '' ? substr(base64_decode($salt), 20) : substr(crypt(''), -8));
99                 $hash = ($prefix ? ($canonical ? '{SSHA}' : $scheme) : '') .
100                         base64_encode(pkwk_hex2bin(sha1($phrase . $salt)) . $salt);
101                 break;
102
103         // LDAP CLEARTEXT and just cleartext
104         case '{cleartext}'   : /* FALLTHROUGH */
105         case ''              :
106                 $hash = ($prefix ? ($canonical ? '{CLEARTEXT}' : $scheme) : '') .
107                         $phrase;
108                 break;
109
110         // Invalid scheme
111         default:
112                 $hash = FALSE;
113                 break;
114         }
115
116         return $hash;
117 }
118
119
120 // Basic-auth related ----
121
122 // Check edit-permission
123 function check_editable($page, $auth_flag = TRUE, $exit_flag = TRUE)
124 {
125         global $script, $_title_cannotedit, $_msg_unfreeze;
126
127         if (edit_auth($page, $auth_flag, $exit_flag) && is_editable($page)) {
128                 // Editable
129                 return TRUE;
130         } else {
131                 // Not editable
132                 if ($exit_flag === FALSE) {
133                         return FALSE; // Without exit
134                 } else {
135                         // With exit
136                         $body = $title = str_replace('$1',
137                                 htmlsc(strip_bracket($page)), $_title_cannotedit);
138                         if (is_freeze($page))
139                                 $body .= '(<a href="' . $script . '?cmd=unfreeze&amp;page=' .
140                                         rawurlencode($page) . '">' . $_msg_unfreeze . '</a>)';
141                         $page = str_replace('$1', make_search($page), $_title_cannotedit);
142                         catbody($title, $page, $body);
143                         exit;
144                 }
145         }
146 }
147
148 // Check read-permission
149 function check_readable($page, $auth_flag = TRUE, $exit_flag = TRUE)
150 {
151         return read_auth($page, $auth_flag, $exit_flag);
152 }
153
154 function edit_auth($page, $auth_flag = TRUE, $exit_flag = TRUE)
155 {
156         global $edit_auth, $edit_auth_pages, $_title_cannotedit;
157         return $edit_auth ?  basic_auth($page, $auth_flag, $exit_flag,
158                 $edit_auth_pages, $_title_cannotedit) : TRUE;
159 }
160
161 function read_auth($page, $auth_flag = TRUE, $exit_flag = TRUE)
162 {
163         global $read_auth, $read_auth_pages, $_title_cannotread;
164         return $read_auth ?  basic_auth($page, $auth_flag, $exit_flag,
165                 $read_auth_pages, $_title_cannotread) : TRUE;
166 }
167
168 // Basic authentication
169 function basic_auth($page, $auth_flag, $exit_flag, $auth_pages, $title_cannot)
170 {
171         global $auth_method_type, $auth_users, $_msg_auth;
172
173         // Checked by:
174         $target_str = '';
175         if ($auth_method_type == 'pagename') {
176                 $target_str = $page; // Page name
177         } else if ($auth_method_type == 'contents') {
178                 $target_str = join('', get_source($page)); // Its contents
179         }
180
181         $user_list = array();
182         foreach($auth_pages as $key=>$val)
183                 if (preg_match($key, $target_str))
184                         $user_list = array_merge($user_list, explode(',', $val));
185
186         if (empty($user_list)) return TRUE; // No limit
187
188         $matches = array();
189         if (! isset($_SERVER['PHP_AUTH_USER']) &&
190                 ! isset($_SERVER ['PHP_AUTH_PW']) &&
191                 isset($_SERVER['HTTP_AUTHORIZATION']) &&
192                 preg_match('/^Basic (.*)$/', $_SERVER['HTTP_AUTHORIZATION'], $matches))
193         {
194
195                 // Basic-auth with $_SERVER['HTTP_AUTHORIZATION']
196                 list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
197                         explode(':', base64_decode($matches[1]));
198         }
199
200         if (PKWK_READONLY ||
201                 ! isset($_SERVER['PHP_AUTH_USER']) ||
202                 ! in_array($_SERVER['PHP_AUTH_USER'], $user_list) ||
203                 ! isset($auth_users[$_SERVER['PHP_AUTH_USER']]) ||
204                 pkwk_hash_compute(
205                         $_SERVER['PHP_AUTH_PW'],
206                         $auth_users[$_SERVER['PHP_AUTH_USER']]
207                         ) !== $auth_users[$_SERVER['PHP_AUTH_USER']])
208         {
209                 // Auth failed
210                 pkwk_common_headers();
211                 if ($auth_flag) {
212                         header('WWW-Authenticate: Basic realm="' . $_msg_auth . '"');
213                         header('HTTP/1.0 401 Unauthorized');
214                 }
215                 if ($exit_flag) {
216                         $body = $title = str_replace('$1',
217                                 htmlsc(strip_bracket($page)), $title_cannot);
218                         $page = str_replace('$1', make_search($page), $title_cannot);
219                         catbody($title, $page, $body);
220                         exit;
221                 }
222                 return FALSE;
223         } else {
224                 return TRUE;
225         }
226 }
227 ?>