Merge remote-tracking branch 'origin/master' into drizzle
[phpmyadmin/crack.git] / libraries / auth / swekey / swekey.php
blob869d3d5c97cb3f7c4663151fce3366d6a436bdea
1 <?php
2 /**
3 * Library that provides common functions that are used to help integrating Swekey Authentication in a PHP web site
4 * Version 1.0
6 * History:
7 * 1.2 Use curl (widely installed) to query the server
8 * Fixed a possible tempfile race attack
9 * Random token cache can now be disabled
10 * 1.1 Added Swekey_HttpGet function that support faulty servers
11 * Support for custom servers
12 * 1.0 First release
14 * @package Swekey
18 /**
19 * Errors codes
21 define ("SWEKEY_ERR_INVALID_DEV_STATUS",901); // The satus of the device is not SWEKEY_STATUS_OK
22 define ("SWEKEY_ERR_INTERNAL",902); // Should never occurd
23 define ("SWEKEY_ERR_OUTDATED_RND_TOKEN",910); // You random token is too old
24 define ("SWEKEY_ERR_INVALID_OTP",911); // The otp was not correct
26 /**
27 * Those errors are considered as an attack and your site will be blacklisted during one minute
28 * if you receive one of those errors
30 define ("SWEKEY_ERR_BADLY_ENCODED_REQUEST",920);
31 define ("SWEKEY_ERR_INVALID_RND_TOKEN",921);
32 define ("SWEKEY_ERR_DEV_NOT_FOUND",922);
34 /**
35 * Default values for configuration.
37 define ('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net');
38 define ('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net');
39 define ('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net');
41 /**
42 * The last error of an operation is alway put in this global var
45 global $gSwekeyLastError;
46 $gSwekeyLastError = 0;
48 global $gSwekeyLastResult;
49 $gSwekeyLastResult = "<not set>";
51 /**
52 * Servers addresses
53 * Use the Swekey_SetXxxServer($server) functions to set them
56 global $gSwekeyCheckServer;
57 if (! isset($gSwekeyCheckServer))
58 $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
60 global $gSwekeyRndTokenServer;
61 if (! isset($gSwekeyRndTokenServer))
62 $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
64 global $gSwekeyStatusServer;
65 if (! isset($gSwekeyStatusServer))
66 $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
68 global $gSwekeyCA;
70 global $gSwekeyTokenCacheEnabled;
71 if (! isset($gSwekeyTokenCacheEnabled))
72 $gSwekeyTokenCacheEnabled = true;
74 /**
75 * Change the address of the Check server.
76 * If $server is empty the default value 'http://auth-check.musbe.net' will be used
78 * @param server The protocol and hostname to use
79 * @access public
81 function Swekey_SetCheckServer($server)
83 global $gSwekeyCheckServer;
84 if (empty($server))
85 $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
86 else
87 $gSwekeyCheckServer = $server;
90 /**
91 * Change the address of the Random Token Generator server.
92 * If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used
94 * @param server The protocol and hostname to use
95 * @access public
97 function Swekey_SetRndTokenServer($server)
99 global $gSwekeyRndTokenServer;
100 if (empty($server))
101 $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
102 else
103 $gSwekeyRndTokenServer = $server;
107 * Change the address of the Satus server.
108 * If $server is empty the default value 'http://auth-status.musbe.net' will be used
110 * @param server The protocol and hostname to use
111 * @access public
113 function Swekey_SetStatusServer($server)
115 global $gSwekeyStatusServer;
116 if (empty($server))
117 $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
118 else
119 $gSwekeyStatusServer = $server;
123 * Change the certificat file in case of the the severs use https instead of http
125 * @param cafile The path of the crt file to use
126 * @access public
128 function Swekey_SetCAFile($cafile)
130 global $gSwekeyCA;
131 $gSwekeyCA = $cafile;
135 * Enable or disable the random token caching
136 * Because everybody has full access to the cache file, it can be a DOS vulnerability
137 * So disable it if you are running in a non secure enviromnement
139 * @param $enable
140 * @access public
142 function Swekey_EnableTokenCache($enable)
144 global $gSwekeyTokenCacheEnabled;
145 $gSwekeyTokenCacheEnabled = ! empty($enable);
150 * Return the last error.
152 * @return The Last Error
153 * @access public
155 function Swekey_GetLastError()
157 global $gSwekeyLastError;
158 return $gSwekeyLastError;
162 * Return the last result.
164 * @return The Last Error
165 * @access public
167 function Swekey_GetLastResult()
169 global $gSwekeyLastResult;
170 return $gSwekeyLastResult;
174 * Send a synchronous request to the server.
175 * This function manages timeout then will not block if one of the server is down
177 * @param url The url to get
178 * @param response_code The response code
179 * @return The body of the response or "" in case of error
180 * @access private
182 function Swekey_HttpGet($url, &$response_code)
184 global $gSwekeyLastError;
185 $gSwekeyLastError = 0;
186 global $gSwekeyLastResult;
187 $gSwekeyLastResult = "<not set>";
189 // use curl if available
190 if (function_exists('curl_init'))
192 $sess = curl_init($url);
193 if (substr($url, 0, 8) == "https://")
195 global $gSwekeyCA;
197 if (! empty($gSwekeyCA))
199 if (file_exists($gSwekeyCA))
201 if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA))
202 error_log("SWEKEY_ERROR:Could not set CA file : ".curl_error($sess));
203 else
204 $caFileOk = true;
206 else
207 error_log("SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url");
210 curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2');
211 curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '2');
212 curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20');
213 curl_setopt($sess, CURLOPT_TIMEOUT, '20');
215 else
217 curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3');
218 curl_setopt($sess, CURLOPT_TIMEOUT, '5');
221 curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1');
222 $res=curl_exec($sess);
223 $response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE);
224 $curlerr = curl_error($sess);
225 curl_close($sess);
227 if ($response_code == 200)
229 $gSwekeyLastResult = $res;
230 return $res;
233 if (! empty($response_code))
235 $gSwekeyLastError = $response_code;
236 error_log("SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url");
237 return "";
240 $response_code = 408; // Request Timeout
241 $gSwekeyLastError = $response_code;
242 error_log("SWEKEY_ERROR:Error $curlerr getting $url");
243 return "";
246 // use pecl_http if available
247 if (class_exists('HttpRequest'))
249 // retry if one of the server is down
250 for ($num=1; $num <= 3; $num++ )
252 $r = new HttpRequest($url);
253 $options = array('timeout' => '3');
255 if (substr($url,0, 6) == "https:")
257 $sslOptions = array();
258 $sslOptions['verifypeer'] = true;
259 $sslOptions['verifyhost'] = true;
261 $capath = __FILE__;
262 $name = strrchr($capath, '/');
263 if (empty($name)) // windows
264 $name = strrchr($capath, '\\');
265 $capath = substr($capath, 0, strlen($capath) - strlen($name) + 1).'musbe-ca.crt';
267 if (! empty($gSwekeyCA))
268 $sslOptions['cainfo'] = $gSwekeyCA;
270 $options['ssl'] = $sslOptions;
273 $r->setOptions($options);
275 // try
277 $reply = $r->send();
278 $res = $reply->getBody();
279 $info = $r->getResponseInfo();
280 $response_code = $info['response_code'];
281 if ($response_code != 200)
283 $gSwekeyLastError = $response_code;
284 error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
285 return "";
289 $gSwekeyLastResult = $res;
290 return $res;
292 // catch (HttpException $e)
293 // {
294 // error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url);
295 // }
298 $response_code = 408; // Request Timeout
299 $gSwekeyLastError = $response_code;
300 error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
301 return "";
304 global $http_response_header;
305 $res = @file_get_contents($url);
306 $response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0
307 if ($response_code == 200)
309 $gSwekeyLastResult = $res;
310 return $res;
313 $gSwekeyLastError = $response_code;
314 error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url);
315 return "";
319 * Get a Random Token from a Token Server
320 * The RT is a 64 vhars hexadecimal value
321 * You should better use Swekey_GetFastRndToken() for performance
322 * @access public
324 function Swekey_GetRndToken()
326 global $gSwekeyRndTokenServer;
327 return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code);
331 * Get a Half Random Token from a Token Server
332 * The RT is a 64 vhars hexadecimal value
333 * Use this value if you want to make your own Swekey_GetFastRndToken()
334 * @access public
336 function Swekey_GetHalfRndToken()
338 global $gSwekeyRndTokenServer;
339 return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code);
343 * Get a Half Random Token
344 * The RT is a 64 vhars hexadecimal value
345 * This function get a new random token and reuse it.
346 * Token are refetched from the server only once every 30 seconds.
347 * You should always use this function to get half random token.
348 * @access public
350 function Swekey_GetFastHalfRndToken()
352 global $gSwekeyTokenCacheEnabled;
354 $res = "";
355 $cachefile = "";
357 // We check if we have a valid RT is the session
358 if (isset($_SESSION['rnd-token-date']))
359 if (time() - $_SESSION['rnd-token-date'] < 30)
360 $res = $_SESSION['rnd-token'];
362 // If not we try to get it from a temp file (PHP >= 5.2.1 only)
363 if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled)
365 if (function_exists('sys_get_temp_dir'))
367 $tempdir = sys_get_temp_dir();
368 $cachefile = $tempdir."/swekey-rnd-token-".get_current_user();
369 $modif = filemtime($cachefile);
370 if ($modif != false)
371 if (time() - $modif < 30)
373 $res = @file_get_contents($cachefile);
374 if (strlen($res) != 32)
375 $res = "";
376 else
378 $_SESSION['rnd-token'] = $res;
379 $_SESSION['rnd-token-date'] = $modif;
385 // If we don't have a valid RT here we have to get it from the server
386 if (strlen($res) != 32)
388 $res = substr(Swekey_GetHalfRndToken(), 0, 32);
389 $_SESSION['rnd-token'] = $res;
390 $_SESSION['rnd-token-date'] = time();
391 if (! empty($cachefile))
393 // we unlink the file so no possible tempfile race attack
394 unlink($cachefile);
395 $file = fopen($cachefile , "x");
396 if ($file != false)
398 @fwrite($file, $res);
399 @fclose($file);
404 return $res."00000000000000000000000000000000";
408 * Get a Random Token
409 * The RT is a 64 vhars hexadecimal value
410 * This function generates a unique random token for each call but call the
411 * server only once every 30 seconds.
412 * You should always use this function to get random token.
413 * @access public
415 function Swekey_GetFastRndToken()
417 $res = Swekey_GetFastHalfRndToken();
418 if (strlen($res) == 64)
419 return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" + mt_rand() + date(DATE_ATOM)));
421 return "";
426 * Checks that an OTP generated by a Swekey is valid
428 * @param id The id of the swekey
429 * @param rt The random token used to generate the otp
430 * @param otp The otp generated by the swekey
431 * @return true or false
432 * @access public
434 function Swekey_CheckOtp($id, $rt, $otp)
436 global $gSwekeyCheckServer;
437 $res = Swekey_HttpGet($gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp, $response_code);
438 return $response_code == 200 && $res == "OK";
442 * Values that are associated with a key.
443 * The following values can be returned by the Swekey_GetStatus() function
445 define ("SWEKEY_STATUS_OK",0);
446 define ("SWEKEY_STATUS_NOT_FOUND",1); // The key does not exist in the db
447 define ("SWEKEY_STATUS_INACTIVE",2); // The key has never been activated
448 define ("SWEKEY_STATUS_LOST",3); // The user has lost his key
449 define ("SWEKEY_STATUS_STOLEN",4); // The key was stolen
450 define ("SWEKEY_STATUS_FEE_DUE",5); // The annual fee was not paid
451 define ("SWEKEY_STATUS_OBSOLETE",6); // The hardware is no longer supported
452 define ("SWEKEY_STATUS_UNKOWN",201); // We could not connect to the authentication server
455 * Values that are associated with a key.
456 * The Javascript Api can also return the following values
458 define ("SWEKEY_STATUS_REPLACED",100); // This key has been replaced by a backup key
459 define ("SWEKEY_STATUS_BACKUP_KEY",101); // This key is a backup key that is not activated yet
460 define ("SWEKEY_STATUS_NOTPLUGGED",200); // This key is not plugged in the computer
464 * Return the text corresponding to the integer status of a key
466 * @param status The status
467 * @return The text corresponding to the status
468 * @access public
470 function Swekey_GetStatusStr($status)
472 switch($status)
474 case SWEKEY_STATUS_OK : return 'OK';
475 case SWEKEY_STATUS_NOT_FOUND : return 'Key does not exist in the db';
476 case SWEKEY_STATUS_INACTIVE : return 'Key not activated';
477 case SWEKEY_STATUS_LOST : return 'Key was lost';
478 case SWEKEY_STATUS_STOLEN : return 'Key was stolen';
479 case SWEKEY_STATUS_FEE_DUE : return 'The annual fee was not paid';
480 case SWEKEY_STATUS_OBSOLETE : return 'Key no longer supported';
481 case SWEKEY_STATUS_REPLACED : return 'This key has been replaced by a backup key';
482 case SWEKEY_STATUS_BACKUP_KEY : return 'This key is a backup key that is not activated yet';
483 case SWEKEY_STATUS_NOTPLUGGED : return 'This key is not plugged in the computer';
484 case SWEKEY_STATUS_UNKOWN : return 'Unknow Status, could not connect to the authentication server';
486 return 'unknown status '.$status;
490 * If your web site requires a key to login you should check that the key
491 * is still valid (has not been lost or stolen) before requiring it.
492 * A key can be authenticated only if its status is SWEKEY_STATUS_OK
493 * @param id The id of the swekey
494 * @return The status of the swekey
495 * @access public
497 function Swekey_GetStatus($id)
499 global $gSwekeyStatusServer;
500 $res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code);
501 if ($response_code == 200)
502 return intval($res);
504 return SWEKEY_STATUS_UNKOWN;