2 // PukiWiki - Yet another WikiWikiWeb clone
3 // $Id: auth.php,v 1.13 2005/04/29 09:10:11 henoheno Exp $
4 // Copywrite (C) 2003-2005 PukiWiki Developers Team
5 // License: GPL v2 or (at your option) any later version
7 // Authentication related functions
9 define('PKWK_PASSPHRASE_LIMIT_LENGTH', 512);
11 // Passwd-auth related ----
13 function pkwk_login($pass = '')
17 if (! PKWK_READONLY && isset($adminpass) &&
18 pkwk_hash_compute($adminpass, $pass) === $adminpass) {
21 sleep(2); // Blocking brute force attack
26 // Compute RFC2307 'userPassword' value, like slappasswd (OpenLDAP)
27 // $scheme : Specify '{scheme}' or '{scheme}salt'
28 // $phrase : Pass-phrase
29 // $prefix : Output with a scheme-prefix or not
30 // $canonical : Correct or Preserve $scheme prefix
31 function pkwk_hash_compute($scheme = '{php_md5}', $phrase = '', $prefix = TRUE, $canonical = FALSE)
33 if (strlen($phrase) > PKWK_PASSPHRASE_LIMIT_LENGTH)
34 die('pkwk_hash_compute(): malicious message length');
38 if (preg_match('/^(\{.+\})(.*)$/', $scheme, $matches)) {
39 $scheme = $matches[1];
41 } else if ($scheme != '') {
42 $scheme = '{CLEARTEXT}';
45 // Compute and add a scheme-prefix
46 switch (strtolower($scheme)) {
47 case '{x-php-crypt}' : /* FALLTHROUGH */
49 $hash = ($prefix ? ($canonical ? '{x-php-crypt}' : $scheme) : '') .
50 ($salt != '' ? crypt($phrase, $salt) : crypt($phrase));
52 case '{x-php-md5}' : /* FALLTHROUGH */
54 $hash = ($prefix ? ($canonical ? '{x-php-md5}' : $scheme) : '') .
57 case '{x-php-sha1}' : /* FALLTHROUGH */
59 $hash = ($prefix ? ($canonical ? '{x-php-sha1}' : $scheme) : '') .
63 case '{crypt}' : /* FALLTHROUGH */
65 $hash = ($prefix ? ($canonical ? '{CRYPT}' : $scheme) : '') .
66 ($salt != '' ? crypt($phrase, $salt) : crypt($phrase));
69 case '{md5}' : /* FALLTHROUGH */
71 $hash = ($prefix ? ($canonical ? '{MD5}' : $scheme) : '') .
72 base64_encode(hex2bin(md5($phrase)));
74 case '{smd5}' : /* FALLTHROUGH */
76 // MD5 Key length = 128bits = 16bytes
77 $salt = ($salt != '' ? substr(base64_decode($salt), 16) : substr(crypt(''), -8));
78 $hash = ($prefix ? ($canonical ? '{SMD5}' : $scheme) : '') .
79 base64_encode(hex2bin(md5($phrase . $salt)) . $salt);
82 case '{sha}' : /* FALLTHROUGH */
84 $hash = ($prefix ? ($canonical ? '{SHA}' : $scheme) : '') .
85 base64_encode(hex2bin(sha1($phrase)));
87 case '{ssha}' : /* FALLTHROUGH */
89 // SHA-1 Key length = 160bits = 20bytes
90 $salt = ($salt != '' ? substr(base64_decode($salt), 20) : substr(crypt(''), -8));
91 $hash = ($prefix ? ($canonical ? '{SSHA}' : $scheme) : '') .
92 base64_encode(hex2bin(sha1($phrase . $salt)) . $salt);
95 case '{cleartext}' : /* FALLTHROUGH */
96 case '{clear}' : /* FALLTHROUGH */
98 $hash = & $phrase; break; // Creartext, keep NO prefix
101 $hash = FALSE; break; // Invalid scheme
108 // Basic-auth related ----
110 // Check edit-permission
111 function check_editable($page, $auth_flag = TRUE, $exit_flag = TRUE)
113 global $script, $_title_cannotedit, $_msg_unfreeze;
115 if (edit_auth($page, $auth_flag, $exit_flag) && is_editable($page)) {
120 if ($exit_flag === FALSE) {
121 return FALSE; // Without exit
124 $body = $title = str_replace('$1',
125 htmlspecialchars(strip_bracket($page)), $_title_cannotedit);
126 if (is_freeze($page))
127 $body .= '(<a href="' . $script . '?cmd=unfreeze&page=' .
128 rawurlencode($page) . '">' . $_msg_unfreeze . '</a>)';
129 $page = str_replace('$1', make_search($page), $_title_cannotedit);
130 catbody($title, $page, $body);
136 // Check read-permission
137 function check_readable($page, $auth_flag = TRUE, $exit_flag = TRUE)
139 return read_auth($page, $auth_flag, $exit_flag);
142 function edit_auth($page, $auth_flag = TRUE, $exit_flag = TRUE)
144 global $edit_auth, $edit_auth_pages, $_title_cannotedit;
145 return $edit_auth ? basic_auth($page, $auth_flag, $exit_flag,
146 $edit_auth_pages, $_title_cannotedit) : TRUE;
149 function read_auth($page, $auth_flag = TRUE, $exit_flag = TRUE)
151 global $read_auth, $read_auth_pages, $_title_cannotread;
152 return $read_auth ? basic_auth($page, $auth_flag, $exit_flag,
153 $read_auth_pages, $_title_cannotread) : TRUE;
156 // Basic authentication
157 function basic_auth($page, $auth_flag, $exit_flag, $auth_pages, $title_cannot)
159 global $auth_method_type, $auth_users, $_msg_auth;
163 if ($auth_method_type == 'pagename') {
164 $target_str = $page; // Page name
165 } else if ($auth_method_type == 'contents') {
166 $target_str = join('', get_source($page)); // Its contents
169 $user_list = array();
170 foreach($auth_pages as $key=>$val)
171 if (preg_match($key, $target_str))
172 $user_list = array_merge($user_list, explode(',', $val));
174 if (empty($user_list)) return TRUE; // No limit
177 if (! isset($_SERVER['PHP_AUTH_USER']) &&
178 ! isset($_SERVER ['PHP_AUTH_PW']) &&
179 isset($_SERVER['HTTP_AUTHORIZATION']) &&
180 preg_match('/^Basic (.*)$/', $_SERVER['HTTP_AUTHORIZATION'], $matches))
183 // Basic-auth with $_SERVER['HTTP_AUTHORIZATION']
184 list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) =
185 explode(':', base64_decode($matches[1]));
189 ! isset($_SERVER['PHP_AUTH_USER']) ||
190 ! in_array($_SERVER['PHP_AUTH_USER'], $user_list) ||
191 ! isset($auth_users[$_SERVER['PHP_AUTH_USER']]) ||
192 pkwk_hash_compute($auth_users[$_SERVER['PHP_AUTH_USER']],
193 $_SERVER['PHP_AUTH_PW']) !== $auth_users[$_SERVER['PHP_AUTH_USER']])
196 pkwk_common_headers();
198 header('WWW-Authenticate: Basic realm="' . $_msg_auth . '"');
199 header('HTTP/1.0 401 Unauthorized');
202 $body = $title = str_replace('$1',
203 htmlspecialchars(strip_bracket($page)), $title_cannot);
204 $page = str_replace('$1', make_search($page), $title_cannot);
205 catbody($title, $page, $body);