* @copyright 2006-2008 * @license http://www.gnu.org/licenses/gpl.html GNU Public License * @url http://siege.org/projects/phpMyID * @version 0.9 */ require( 'template.php' ); /** * Set a constant to indicate that phpMyID is running */ define('PHPMYID_STARTED', true); /** * List the known types and modes * @name $known * @global array $GLOBALS['known'] */ $GLOBALS['known'] = array( 'assoc_types' => array('HMAC-SHA1'), 'openid_modes' => array('accept', 'associate', 'authorize', 'cancel', 'checkid_immediate', 'checkid_setup', 'check_authentication', 'error', 'id_res', 'login', 'logout', 'test'), 'session_types' => array('', 'DH-SHA1'), 'bigmath_types' => array('DH-SHA1'), ); /** * Defined by OpenID spec * @name $g * @global integer $GLOBALS['g'] */ $GLOBALS['g'] = 2; /** * Defined by OpenID spec * @name $p * @global integer $GLOBALS['p'] */ $GLOBALS['p'] = '155172898181473697471232257763715539915724801966915404479707' . '7953140576293785419175806512274236981889937278161526466314385615958256881888' . '8995127215884267541995034125870655654980358010487053768147672651325574704076' . '5857479291291572334510643245094715007229621094194349783925984760375594985848' . '253359305585439638443'; // Runmode functions /** * Allow the user to accept trust on a URL * @global array $profile */ function accept_mode () { global $profile; // this is a user session user_session(); // the user needs refresh urls in their session to access this mode if (! isset($_SESSION['post_accept_url']) || ! isset($_SESSION['cancel_accept_url']) || ! isset($_SESSION['unaccepted_url'])) error_500('You may not access this mode directly.'); // has the user accepted the trust_root? $accepted = @strlen($_REQUEST['accepted']) ? $_REQUEST['accepted'] : null; // if so, refresh back to post_accept_url if ($accepted === 'yes') { $_SESSION['accepted_url'] = $_SESSION['unaccepted_url']; wrap_redirect($_SESSION['post_accept_url']); // if they rejected it, return to the client } elseif ($accepted === 'no') { wrap_redirect($_SESSION['cancel_accept_url']); } // if neither, offer the trust request $q = strpos($profile['req_url'], '?') ? '&' : '?'; $yes = $profile['req_url'] . $q . 'accepted=yes'; $no = $profile['req_url'] . $q . 'accepted=no'; wrap_html('The client site you are attempting to log into has requested that you trust the following URL:
' . $_SESSION['unaccepted_url'] . '

Do you wish to continue?
Yes | No'); } /** * Perform an association with a consumer * @global array $known * @global array $profile * @global integer $g * @global integer $p */ function associate_mode () { global $g, $known, $p, $profile; // Validate the request if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'associate') error_400(); // Get the request options, using defaults as necessary $assoc_type = (@strlen($_REQUEST['openid_assoc_type']) && in_array($_REQUEST['openid_assoc_type'], $known['assoc_types'])) ? $_REQUEST['openid_assoc_type'] : 'HMAC-SHA1'; $session_type = (@strlen($_REQUEST['openid_session_type']) && in_array($_REQUEST['openid_session_type'], $known['session_types'])) ? $_REQUEST['openid_session_type'] : ''; $dh_modulus = (@strlen($_REQUEST['openid_dh_modulus'])) ? long(base64_decode($_REQUEST['openid_dh_modulus'])) : ($session_type == 'DH-SHA1' ? $p : null); $dh_gen = (@strlen($_REQUEST['openid_dh_gen'])) ? long(base64_decode($_REQUEST['openid_dh_gen'])) : ($session_type == 'DH-SHA1' ? $g : null); $dh_consumer_public = (@strlen($_REQUEST['openid_dh_consumer_public'])) ? $_REQUEST['openid_dh_consumer_public'] : ($session_type == 'DH-SHA1' ? error_post('dh_consumer_public was not specified') : null); $lifetime = time() + $profile['lifetime']; // Create standard keys $keys = array( 'assoc_type' => $assoc_type, 'expires_in' => $profile['lifetime'] ); // If I can't handle bigmath, default to plaintext sessions if (in_array($session_type, $known['bigmath_types']) && $profile['use_bigmath'] === false) $session_type = null; // Add response keys based on the session type switch ($session_type) { case 'DH-SHA1': // Create the associate id and shared secret now list ($assoc_handle, $shared_secret) = new_assoc($lifetime); // Compute the Diffie-Hellman stuff $private_key = random($dh_modulus); $public_key = bmpowmod($dh_gen, $private_key, $dh_modulus); $remote_key = long(base64_decode($dh_consumer_public)); $ss = bmpowmod($remote_key, $private_key, $dh_modulus); $keys['assoc_handle'] = $assoc_handle; $keys['session_type'] = $session_type; $keys['dh_server_public'] = base64_encode(bin($public_key)); $keys['enc_mac_key'] = base64_encode(x_or(sha1_20(bin($ss)), $shared_secret)); break; default: // Create the associate id and shared secret now list ($assoc_handle, $shared_secret) = new_assoc($lifetime); $keys['assoc_handle'] = $assoc_handle; $keys['mac_key'] = base64_encode($shared_secret); } // Return the keys wrap_kv($keys); } /** * Perform a user authorization * @global array $profile */ function authorize_mode () { global $profile; global $USERNAME; // this is a user session // the user needs refresh urls in their session to access this mode if (! isset($_SESSION['post_auth_url']) || ! isset($_SESSION['cancel_auth_url'])) error_500('You may not access this mode directly.'); if (isset($_SERVER['PHP_AUTH_USER']) && $profile['authorized'] === false && $_SERVER['PHP_AUTH_USER']==$USERNAME) { if (OC_USER::checkPassword($USERNAME, $_SERVER['PHP_AUTH_PW'])) {// successful login! // return to the refresh url if they get in $_SESSION['openid_auth']=true; $_SESSION['openid_user']=$USERNAME; wrap_redirect($_SESSION['post_auth_url']); // failed login } else { $_SESSION['failures']++; debug('Login failed'); debug('Fail count: ' . $_SESSION['failures']); } } // if we get this far the user is not authorized, so send the headers $uid = uniqid(mt_rand(1,9)); $_SESSION['uniqid'] = $uid; // debug('Prompting user to log in. Stale? ' . $stale); header('HTTP/1.0 401 Unauthorized'); // header(sprintf('WWW-Authenticate: Digest qop="auth-int, auth", realm="%s", domain="%s", nonce="%s", opaque="%s", stale="%s", algorithm="MD5"', $profile['auth_realm'], $profile['auth_domain'], $uid, md5($profile['auth_realm']), $stale ? 'true' : 'false')); header('WWW-Authenticate: Basic realm="ownCloud"'); $q = strpos($_SESSION['cancel_auth_url'], '?') ? '&' : '?'; wrap_refresh($_SESSION['cancel_auth_url'] . $q . 'openid.mode=cancel'); // die('401 Unauthorized'); } /** * Handle a consumer's request for cancellation. */ function cancel_mode () { wrap_html('Request cancelled.'); } /** * Handle a consumer's request to see if the user is authenticated */ function check_authentication_mode () { // Validate the request if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'check_authentication') error_400(); $assoc_handle = @strlen($_REQUEST['openid_assoc_handle']) ? $_REQUEST['openid_assoc_handle'] : error_post('Missing assoc_handle'); $sig = @strlen($_REQUEST['openid_sig']) ? $_REQUEST['openid_sig'] : error_post('Missing sig'); $signed = @strlen($_REQUEST['openid_signed']) ? $_REQUEST['openid_signed'] : error_post('Missing signed'); // Prepare the return keys $keys = array( 'openid.mode' => 'id_res' ); // Invalidate the assoc handle if we need to if (@strlen($_REQUEST['openid_invalidate_handle'])) { destroy_assoc_handle($_REQUEST['openid_invalidate_handle']); $keys['invalidate_handle'] = $_REQUEST['openid_invalidate_handle']; } // Validate the sig by recreating the kv pair and signing $_REQUEST['openid_mode'] = 'id_res'; $tokens = ''; foreach (explode(',', $signed) as $param) { $post = preg_replace('/\./', '_', $param); $tokens .= sprintf("%s:%s\n", $param, $_REQUEST['openid_' . $post]); } // Add the sreg stuff, if we've got it if (isset($sreg_required)) { foreach (explode(',', $sreg_required) as $key) { if (! isset($sreg[$key])) continue; $skey = 'sreg.' . $key; $tokens .= sprintf("%s:%s\n", $skey, $sreg[$key]); $keys[$skey] = $sreg[$key]; $fields[] = $skey; } } // Look up the consumer's shared_secret and timeout list ($shared_secret, $expires) = secret($assoc_handle); // if I can't verify the assoc_handle, or if it's expired if ($shared_secret == false || (is_numeric($expires) && $expires < time())) { $keys['is_valid'] = 'false'; } else { $ok = base64_encode(hmac($shared_secret, $tokens)); $keys['is_valid'] = ($sig == $ok) ? 'true' : 'false'; } // Return the keys wrap_kv($keys); } /** * Handle a consumer's request to see if the end user is logged in * @global array $known * @global array $profile * @global array $sreg */ function checkid ( $wait ) { global $known, $profile, $sreg; global $USERNAME; // This is a user session user_session(); // Get the options, use defaults as necessary $return_to = @strlen($_REQUEST['openid_return_to']) ? $_REQUEST['openid_return_to'] : error_400('Missing return1_to'); $identity = @strlen($_REQUEST['openid_identity']) ? $_REQUEST['openid_identity'] : error_get($return_to, 'Missing identity'); $assoc_handle = @strlen($_REQUEST['openid_assoc_handle']) ? $_REQUEST['openid_assoc.handle'] : null; $trust_root = @strlen($_REQUEST['openid_trust_root']) ? $_REQUEST['openid_trust_root'] : $return_to; $sreg_required = @strlen($_REQUEST['openid_sreg_required']) ? $_REQUEST['openid_sreg.required'] : ''; $sreg_optional = @strlen($_REQUEST['openid_sreg_optional']) ? $_REQUEST['openid_sreg.optional'] : ''; // determine the cancel url $q = strpos($return_to, '?') ? '&' : '?'; $cancel_url = $return_to . $q . 'openid.mode=cancel'; // required and optional make no difference to us $sreg_required .= ',' . $sreg_optional; // do the trust_root analysis if ($trust_root != $return_to) { // the urls are not the same, be sure return decends from trust if (! url_descends($return_to, $trust_root)) error_500('Invalid trust_root: "' . $trust_root . '"'); } // transfer the user to the url accept mode if they're paranoid if ($wait == 1 && isset($profile['paranoid']) && $profile['paranoid'] === true && (! session_is_registered('accepted_url') || $_SESSION['accepted_url'] != $trust_root)) { $_SESSION['cancel_accept_url'] = $cancel_url; $_SESSION['post_accept_url'] = $profile['req_url']; $_SESSION['unaccepted_url'] = $trust_root; debug('Transferring to acceptance mode.'); debug('Cancel URL: ' . $_SESSION['cancel_accept_url']); debug('Post URL: ' . $_SESSION['post_accept_url']); $q = strpos($profile['idp_url'], '?') ? '&' : '?'; wrap_redirect($profile['idp_url'] . $q . 'openid.mode=accept'); } // make sure i am this identifier if ($identity != $profile['idp_url']) { debug("Invalid identity: $identity"); debug("IdP URL: " . $profile['idp_url']); error_get($return_to, "Invalid identity: '$identity'"); } // begin setting up return keys $keys = array( 'mode' => 'id_res' ); // if the user is not logged in, transfer to the authorization mode if ($_SESSION['openid_auth'] === false || $USERNAME != $_SESSION['openid_user']) { // users can only be logged in to one url at a time $_SESSION['auth_username'] = null; $_SESSION['auth_url'] = null; if ($wait) { unset($_SESSION['uniqid']); $_SESSION['cancel_auth_url'] = $cancel_url; $_SESSION['post_auth_url'] = $profile['req_url']; debug('Transferring to authorization mode.'); debug('Cancel URL: ' . $_SESSION['cancel_auth_url']); debug('Post URL: ' . $_SESSION['post_auth_url']); $q = strpos($profile['idp_url'], '?') ? '&' : '?'; wrap_redirect($profile['idp_url'] . $q . 'openid.mode=authorize'); } else { $keys['user_setup_url'] = $profile['idp_url']; } // the user is logged in } else { // remove the refresh URLs if set unset($_SESSION['cancel_auth_url']); unset($_SESSION['post_auth_url']); // check the assoc handle list($shared_secret, $expires) = secret($assoc_handle); // if I can't verify the assoc_handle, or if it's expired if ($shared_secret == false || (is_numeric($expires) && $expires < time())) { debug("Session expired or missing key: $expires < " . time()); if ($assoc_handle != null) { $keys['invalidate_handle'] = $assoc_handle; destroy_assoc_handle($assoc_handle); } $lifetime = time() + $profile['lifetime']; list ($assoc_handle, $shared_secret) = new_assoc($lifetime); } $keys['identity'] = $profile['idp_url']; $keys['assoc_handle'] = $assoc_handle; $keys['return_to'] = $return_to; $fields = array_keys($keys); $tokens = ''; foreach ($fields as $key) $tokens .= sprintf("%s:%s\n", $key, $keys[$key]); // add sreg keys foreach (explode(',', $sreg_required) as $key) { if (! isset($sreg[$key])) continue; $skey = 'sreg.' . $key; $tokens .= sprintf("%s:%s\n", $skey, $sreg[$key]); $keys[$skey] = $sreg[$key]; $fields[] = $skey; } $keys['signed'] = implode(',', $fields); $keys['sig'] = base64_encode(hmac($shared_secret, $tokens)); } wrap_keyed_redirect($return_to, $keys); } /** * Handle a consumer's request to see if the user is already logged in */ function checkid_immediate_mode () { if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'checkid_immediate') error_500(); checkid(false); } /** * Handle a consumer's request to see if the user is logged in, but be willing * to wait for them to perform a login if they're not */ function checkid_setup_mode () { if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'checkid_setup') error_500(); checkid(true); } /** * Handle errors */ function error_mode () { isset($_REQUEST['openid_error']) ? wrap_html($_REQUEST['openid_error']) : error_500(); } /** * Show a user if they are logged in or not * @global array $profile */ function id_res_mode () { global $profile; user_session(); if ($profile['authorized']) wrap_html('You are logged in as ' . $_SESSION['auth_username']); wrap_html('You are not logged in'); } /** * Allow a user to perform a static login * @global array $profile */ function login_mode () { global $profile; user_session(); if ($profile['authorized']) id_res_mode(); $keys = array( 'mode' => 'checkid_setup', 'identity' => $profile['idp_url'], 'return_to' => $profile['idp_url'] ); wrap_keyed_redirect($profile['idp_url'], $keys); } /** * Allow a user to perform a static logout * @global array $profile */ function logout_mode () { global $profile; user_session(); if (! $profile['authorized']) wrap_html('You were not logged in'); $_SESSION = array(); session_destroy(); debug('User session destroyed.'); header('HTTP/1.0 401 Unauthorized'); wrap_redirect($profile['idp_url']); } /** * The default information screen * @global array $profile */ function no_mode () { global $USERNAME, $profile; $tmpl = new OC_TEMPLATE( 'user_openid', 'nomode', 'guest' ); $tmpl->addHeader('link',array('rel'=>'openid.server', 'href'=>$profile['req_url'])); $tmpl->addHeader('link',array('rel'=>'openid.delegate', 'href'=>$profile['idp_url'])); $tmpl->assign('user',$USERNAME); $tmpl->printPage(); } /** * Testing for setup * @global array $profile */ function test_mode () { global $profile, $p, $g; if ($profile['allow_test'] != true) error_403(); @ini_set('max_execution_time', 180); $test_expire = time() + 120; $test_ss_enc = 'W7hvmld2yEYdDb0fHfSkKhQX+PM='; $test_ss = base64_decode($test_ss_enc); $test_token = "alpha:bravo\ncharlie:delta\necho:foxtrot"; $test_server_private = '11263846781670293092494395517924811173145217135753406847875706165886322533899689335716152496005807017390233667003995430954419468996805220211293016296351031812246187748601293733816011832462964410766956326501185504714561648498549481477143603650090931135412673422192550825523386522507656442905243832471167330268'; $test_client_public = base64_decode('AL63zqI5a5p8HdXZF5hFu8p+P9GOb816HcHuvNOhqrgkKdA3fO4XEzmldlb37nv3+xqMBgWj6gxT7vfuFerEZLBvuWyVvR7IOGZmx0BAByoq3fxYd3Fpe2Coxngs015vK37otmH8e83YyyGo5Qua/NAf13yz1PVuJ5Ctk7E+YdVc'); $res = array(); // bcmath $res['bcmath'] = extension_loaded('bcmath') ? 'pass' : 'warn - not loaded'; // gmp if ($profile['allow_gmp']) { $res['gmp'] = extension_loaded('gmp') ? 'pass' : 'warn - not loaded'; } else { $res['gmp'] = 'pass - n/a'; } // sys_get_temp_dir $res['logfile'] = is_writable($profile['logfile']) ? 'pass' : "warn - log is not writable"; // session & new_assoc user_session(); list($test_assoc, $test_new_ss) = new_assoc($test_expire); $res['session'] = ($test_assoc != session_id()) ? 'pass' : 'fail'; // secret @session_unregister('shared_secret'); list($check, $check2) = secret($test_assoc); $res['secret'] = ($check == $test_new_ss) ? 'pass' : 'fail'; // expire $res['expire'] = ($check2 <= $test_expire) ? 'pass' : 'fail'; // base64 $res['base64'] = (base64_encode($test_ss) == $test_ss_enc) ? 'pass' : 'fail'; // hmac $test_sig = base64_decode('/VXgHvZAOdoz/OTa5+XJXzSGhjs='); $check = hmac($test_ss, $test_token); $res['hmac'] = ($check == $test_sig) ? 'pass' : sprintf("fail - '%s'", base64_encode($check)); if ($profile['use_bigmath']) { // bigmath powmod $test_server_public = '102773334773637418574009974502372885384288396853657336911033649141556441102566075470916498748591002884433213640712303846640842555822818660704173387461364443541327856226098159843042567251113889701110175072389560896826887426539315893475252988846151505416694218615764823146765717947374855806613410142231092856731'; $check = bmpowmod($g, $test_server_private, $p); $res['bmpowmod-1'] = ($check == $test_server_public) ? 'pass' : sprintf("fail - '%s'", $check); // long $test_client_long = '133926731803116519408547886573524294471756220428015419404483437186057383311250738749035616354107518232016420809434801736658109316293127101479053449990587221774635063166689561125137927607200322073086097478667514042144489248048756916881344442393090205172004842481037581607299263456852036730858519133859409417564'; $res['long'] = (long($test_client_public) == $test_client_long) ? 'pass' : 'fail'; // bigmath powmod 2 $test_client_share = '19333275433742428703546496981182797556056709274486796259858099992516081822015362253491867310832140733686713353304595602619444380387600756677924791671971324290032515367930532292542300647858206600215875069588627551090223949962823532134061941805446571307168890255137575975911397744471376862555181588554632928402'; $check = bmpowmod($test_client_long, $test_server_private, $p); $res['bmpowmod-2'] = ($check == $test_client_share) ? 'pass' : sprintf("fail - '%s'", $check); // bin $test_client_mac_s1 = base64_decode('G4gQQkYM6QmAzhKbVKSBahFesPL0nL3F2MREVwEtnVRRYI0ifl9zmPklwTcvURt3QTiGBd+9Dn3ESLk5qka6IO5xnILcIoBT8nnGVPiOZvTygfuzKp4tQ2mXuIATJoa7oXRGmBWtlSdFapH5Zt6NJj4B83XF/jzZiRwdYuK4HJI='); $check = bin($test_client_share); $res['bin'] = ($check == $test_client_mac_s1) ? 'pass' : sprintf("fail - '%s'", base64_encode($check)); } else { $res['bigmath'] = 'fail - big math functions are not available.'; } // sha1_20 $test_client_mac_s1 = base64_decode('G4gQQkYM6QmAzhKbVKSBahFesPL0nL3F2MREVwEtnVRRYI0ifl9zmPklwTcvURt3QTiGBd+9Dn3ESLk5qka6IO5xnILcIoBT8nnGVPiOZvTygfuzKp4tQ2mXuIATJoa7oXRGmBWtlSdFapH5Zt6NJj4B83XF/jzZiRwdYuK4HJI='); $test_client_mac_s2 = base64_decode('0Mb2t9d/HvAZyuhbARJPYdx3+v4='); $check = sha1_20($test_client_mac_s1); $res['sha1_20'] = ($check == $test_client_mac_s2) ? 'pass' : sprintf("fail - '%s'", base64_encode($check)); // x_or $test_client_mac_s3 = base64_decode('i36ZLYAJ1rYEx1VEHObrS8hgAg0='); $check = x_or($test_client_mac_s2, $test_ss); $res['x_or'] = ($check == $test_client_mac_s3) ? 'pass' : sprintf("fail - '%s'", base64_encode($check)); $out = "\n"; foreach ($res as $test => $stat) { $code = substr($stat, 0, 4); $color = ($code == 'pass') ? '#9f9' : (($code == 'warn') ? '#ff9' : '#f99'); $out .= sprintf("\n", $test, $color, $stat); } $out .= "
%s%s
"; wrap_html( $out ); } // Support functions /** * Prefix the keys of an array with 'openid.' * @param array $array * @return array */ function append_openid ($array) { $keys = array_keys($array); $vals = array_values($array); $r = array(); for ($i=0; $i $rl ) { $r = str_repeat("0", $ll-$rl) . $r; $o = $ll; } else { $o = $ll; } $v = ''; $carry = 0; for ($i = $o-1; $i >= 0; $i--) { $d = (int)$l[$i] + (int)$r[$i] + $carry; if ($d <= 9) { $carry = 0; } else { $carry = 1; $d -= 10; } $v = (string) $d . $v; } if ($carry > 0) $v = "1" . $v; return $v; } /** * Create a big math comparison function * @param string $l * @param string $r * @return string */ function bmcomp($l, $r) { if (function_exists('bccomp')) return bccomp($l, $r); global $profile; if ($profile['use_gmp']) return gmp_strval(gmp_cmp($l, $r)); $l = strval($l); $r = strval($r); $ll = strlen($l); $lr = strlen($r); if ($ll != $lr) return ($ll > $lr) ? 1 : -1; return strcmp($l, $r); } /** * Create a big math division function * @param string $l * @param string $r * @param int $z * @return string * @url http://www.icosaedro.it/bigint Inspired by */ function bmdiv($l, $r, $z = 0) { if (function_exists('bcdiv')) return ($z == 0) ? bcdiv($l, $r) : bcmod($l, $r); global $profile; if ($profile['use_gmp']) return gmp_strval(($z == 0) ? gmp_div_q($l, $r) : gmp_mod($l, $r)); $l = strval($l); $r = strval($r); $v = '0'; while (true) { if( bmcomp($l, $r) < 0 ) break; $delta = strlen($l) - strlen($r); if ($delta >= 1) { $zeroes = str_repeat("0", $delta); $r2 = $r . $zeroes; if (strcmp($l, $r2) >= 0) { $v = bmadd($v, "1" . $zeroes); $l = bmsub($l, $r2); } else { $zeroes = str_repeat("0", $delta - 1); $v = bmadd($v, "1" . $zeroes); $l = bmsub($l, $r . $zeroes); } } else { $l = bmsub($l, $r); $v = bmadd($v, "1"); } } return ($z == 0) ? $v : $l; } /** * Create a big math multiplication function * @param string $l * @param string $r * @return string * @url http://www.icosaedro.it/bigint Inspired by */ function bmmul($l, $r) { if (function_exists('bcmul')) return bcmul($l, $r); global $profile; if ($profile['use_gmp']) return gmp_strval(gmp_mul($l, $r)); $l = strval($l); $r = strval($r); $v = '0'; $z = ''; for( $i = strlen($r)-1; $i >= 0; $i-- ){ $bd = (int) $r[$i]; $carry = 0; $p = ""; for( $j = strlen($l)-1; $j >= 0; $j-- ){ $ad = (int) $l[$j]; $pd = $ad * $bd + $carry; if( $pd <= 9 ){ $carry = 0; } else { $carry = (int) ($pd / 10); $pd = $pd % 10; } $p = (string) $pd . $p; } if( $carry > 0 ) $p = (string) $carry . $p; $p = $p . $z; $z .= "0"; $v = bmadd($v, $p); } return $v; } /** * Create a big math modulus function * @param string $value * @param string $mod * @return string */ function bmmod( $value, $mod ) { if (function_exists('bcmod')) return bcmod($value, $mod); global $profile; if ($profile['use_gmp']) return gmp_strval(gmp_mod($value, $mod)); $r = bmdiv($value, $mod, 1); return $r; } /** * Create a big math power function * @param string $value * @param string $exponent * @return string */ function bmpow ($value, $exponent) { if (function_exists('bcpow')) return bcpow($value, $exponent); global $profile; if ($profile['use_gmp']) return gmp_strval(gmp_pow($value, $exponent)); $r = '1'; while ($exponent) { $r = bmmul($r, $value, 100); $exponent--; } return (string)rtrim($r, '0.'); } /** * Create a big math 'powmod' function * @param string $value * @param string $exponent * @param string $mod * @return string * @url http://php.net/manual/en/function.bcpowmod.php#72704 Borrowed from */ function bmpowmod ($value, $exponent, $mod) { if (function_exists('bcpowmod')) return bcpowmod($value, $exponent, $mod); global $profile; if ($profile['use_gmp']) return gmp_strval(gmp_powm($value, $exponent, $mod)); $r = ''; while ($exponent != '0') { $t = bmmod($exponent, '4096'); $r = substr("000000000000" . decbin(intval($t)), -12) . $r; $exponent = bmdiv($exponent, '4096'); } $r = preg_replace("!^0+!","",$r); if ($r == '') $r = '0'; $value = bmmod($value, $mod); $erb = strrev($r); $q = '1'; $a[0] = $value; for ($i = 1; $i < strlen($erb); $i++) { $a[$i] = bmmod( bmmul($a[$i-1], $a[$i-1]), $mod ); } for ($i = 0; $i < strlen($erb); $i++) { if ($erb[$i] == "1") { $q = bmmod( bmmul($q, $a[$i]), $mod ); } } return($q); } /** * Create a big math subtraction function * @param string $l * @param string $r * @return string * @url http://www.icosaedro.it/bigint Inspired by */ function bmsub($l, $r) { if (function_exists('bcsub')) return bcsub($l, $r); global $profile; if ($profile['use_gmp']) return gmp_strval(gmp_sub($l, $r)); $l = strval($l); $r = strval($r); $ll = strlen($l); $rl = strlen($r); if ($ll < $rl) { $l = str_repeat("0", $rl-$ll) . $l; $o = $rl; } elseif ( $ll > $rl ) { $r = str_repeat("0", $ll-$rl) . (string)$r; $o = $ll; } else { $o = $ll; } if (strcmp($l, $r) >= 0) { $sign = ''; } else { $x = $l; $l = $r; $r = $x; $sign = '-'; } $v = ''; $carry = 0; for ($i = $o-1; $i >= 0; $i--) { $d = ($l[$i] - $r[$i]) - $carry; if ($d < 0) { $carry = 1; $d += 10; } else { $carry = 0; } $v = (string) $d . $v; } return $sign . ltrim($v, '0'); } /** * Get a binary value * @param integer $n * @return string * @url http://openidenabled.com Borrowed from PHP-OpenID */ function bin ($n) { $bytes = array(); while (bmcomp($n, 0) > 0) { array_unshift($bytes, bmmod($n, 256)); $n = bmdiv($n, bmpow(2,8)); } if ($bytes && ($bytes[0] > 127)) array_unshift($bytes, 0); $b = ''; foreach ($bytes as $byte) $b .= pack('C', $byte); return $b; } /** * Debug logging * @param mixed $x * @param string $m */ function debug ($x, $m = null) { global $profile; if (! isset($profile['debug']) || $profile['debug'] === false) return true; if (! is_writable(dirname($profile['logfile'])) &! is_writable($profile['logfile'])) error_500('Cannot write to debug log: ' . $profile['logfile']); if (is_array($x)) { ob_start(); print_r($x); $x = $m . ($m != null ? "\n" : '') . ob_get_clean(); } else { $x .= "\n"; } error_log($x . "\n", 3, $profile['logfile']); } /** * Destroy a consumer's assoc handle * @param string $id */ function destroy_assoc_handle ( $id ) { debug("Destroying session: $id"); $sid = session_id(); session_write_close(); session_id($id); session_start(); session_destroy(); session_id($sid); session_start(); } /** * Return an error message to the user * @param string $message */ function error_400 ( $message = 'Bad Request' ) { header("HTTP/1.1 400 Bad Request"); wrap_html($message); } /** * Return an error message to the user * @param string $message */ function error_403 ( $message = 'Forbidden' ) { header("HTTP/1.1 403 Forbidden"); wrap_html($message); } /** * Return an error message to the user * @param string $message */ function error_500 ( $message = 'Internal Server Error' ) { header("HTTP/1.1 500 Internal Server Error"); wrap_html($message); } /** * Return an error message to the consumer * @param string $message */ function error_get ( $url, $message = 'Bad Request') { wrap_keyed_redirect($url, array('mode' => 'error', 'error' => $message)); } /** * Return an error message to the consumer * @param string $message */ function error_post ( $message = 'Bad Request' ) { header("HTTP/1.1 400 Bad Request"); echo ('error:' . $message); exit(0); } /** * Do an HMAC * @param string $key * @param string $data * @param string $hash * @return string * @url http://php.net/manual/en/function.sha1.php#39492 Borrowed from */ function hmac($key, $data, $hash = 'sha1_20') { $blocksize=64; if (strlen($key) > $blocksize) $key = $hash($key); $key = str_pad($key, $blocksize,chr(0x00)); $ipad = str_repeat(chr(0x36),$blocksize); $opad = str_repeat(chr(0x5c),$blocksize); $h1 = $hash(($key ^ $ipad) . $data); $hmac = $hash(($key ^ $opad) . $h1); return $hmac; } if (! function_exists('http_build_query')) { /** * Create function if missing * @param array $array * @return string */ function http_build_query ($array) { $r = array(); foreach ($array as $key => $val) $r[] = sprintf('%s=%s', urlencode($key), urlencode($val)); return implode('&', $r); }} /** * Turn a binary back into a long * @param string $b * @return integer * @url http://openidenabled.com Borrowed from PHP-OpenID */ function long($b) { $bytes = array_merge(unpack('C*', $b)); $n = 0; foreach ($bytes as $byte) { $n = bmmul($n, bmpow(2,8)); $n = bmadd($n, $byte); } return $n; } /** * Create a new consumer association * @param integer $expiration * @return array */ function new_assoc ( $expiration ) { if (isset($_SESSION) && is_array($_SESSION)) { $sid = session_id(); $dat = session_encode(); session_write_close(); } session_start(); session_regenerate_id('false'); $id = session_id(); $shared_secret = new_secret(); debug('Started new assoc session: ' . $id); $_SESSION = array(); $_SESSION['expiration'] = $expiration; $_SESSION['shared_secret'] = base64_encode($shared_secret); session_write_close(); if (isset($sid)) { session_id($sid); session_start(); $_SESSION = array(); session_decode($dat); } return array($id, $shared_secret); } /** * Create a new shared secret * @return string */ function new_secret () { $r = ''; for($i=0; $i<20; $i++) $r .= chr(mt_rand(0, 255)); debug("Generated new key: hash = '" . md5($r) . "', length = '" . strlen($r) . "'"); return $r; } /** * Random number generation * @param integer max * @return integer */ function random ( $max ) { if (strlen($max) < 4) return mt_rand(1, $max - 1); $r = ''; for($i=1; $i= 0 && ($pr_host[$break] != '*' || substr_count(substr($pr_host, 0, $break), '.') < 2)) return false; // now compare the paths $break = str_diff_at($parts['child']['path'], $parts['parent']['path']); if ($break >= 0 && ($break < strlen($parts['parent']['path']) && $parts['parent']['path'][$break] != '*') || ($break > strlen($parts['child']['path']))) return false; return true; } /** * Create a user session * @global array $profile * @global array $proto */ function user_session () { global $proto, $profile; session_name('phpMyID_Server'); @session_start(); $profile['authorized'] = (isset($_SESSION['auth_username']) && $_SESSION['auth_username'] == $profile['auth_username']) ? true : false; debug('Started user session: ' . session_id() . ' Auth? ' . $profile['authorized']); } /** * Return HTML * @global string $charset * @param string $message */ function wrap_html ( $message ) { global $charset, $profile; header('Content-Type: text/html; charset=' . $charset); $html= ' phpMyID ' . implode("\n", $profile['opt_headers']) . '

' . $message . '

'; error_log($html); echo $html; exit(0); } /** * Return a key-value pair in plain text * @global string $charset * @param array $keys */ function wrap_kv ( $keys ) { global $charset; debug($keys, 'Wrapped key/vals'); header('Content-Type: text/plain; charset=' . $charset); foreach ($keys as $key => $value) printf("%s:%s\n", $key, $value); exit(0); } /** * Redirect, with OpenID keys * @param string $url * @param array @keys */ function wrap_keyed_redirect ($url, $keys) { $keys = append_openid($keys); debug($keys, 'Location keys'); $q = strpos($url, '?') ? '&' : '?'; wrap_redirect($url . $q . http_build_query($keys)); } /** * Redirect the browser * @global string $charset * @param string $url */ function wrap_redirect ($url) { header('HTTP/1.1 302 Found'); header('Location: ' . $url); debug('Location: ' . $url); exit(0); } /** * Return an HTML refresh * @global string $charset * @param string $url */ function wrap_refresh ($url) { global $charset; header('Content-Type: text/html; charset=' . $charset); echo ' phpMyID

Redirecting to ' . $url . '

'; debug('Refresh: ' . $url); exit(0); } /** * Implement binary x_or * @param string $a * @param string $b * @return string */ function x_or ($a, $b) { $r = ""; for ($i = 0; $i < strlen($b); $i++) $r .= $a[$i] ^ $b[$i]; debug("Xor size: " . strlen($r)); return $r; } /* * App Initialization */ // Determine the charset to use $GLOBALS['charset'] = 'iso-8859-1'; // Set the internal encoding if (function_exists('mb_internal_encoding')) mb_internal_encoding($charset); // Avoid problems with non-default arg_separator.output settings // Credit for this goes to user 'prelog' on the forums ini_set('arg_separator.output', '&'); // Do a check to be sure everything is set up correctly self_check(); /** * Determine the HTTP request port * @name $port * @global integer $GLOBALS['port'] */ $GLOBALS['port'] = ((isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' && $_SERVER['SERVER_PORT'] == 443) || $_SERVER['SERVER_PORT'] == 80) ? '' : ':' . $_SERVER['SERVER_PORT']; error_log($_SERVER['HTTP_HOST']); /** * Determine the HTTP request protocol * @name $proto * @global string $GLOBALS['proto'] */ $GLOBALS['proto'] = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http'; // Set the authorization state - DO NOT OVERRIDE $profile['authorized'] = false; // Set a default IDP URL if (! array_key_exists('idp_url', $profile)) $profile['idp_url'] = sprintf("%s://%s%s%s", $proto, $_SERVER['SERVER_NAME'], $port, $_SERVER['PHP_SELF']); // Determine the requested URL - DO NOT OVERRIDE $profile['req_url'] = sprintf("%s://%s%s", $proto, $_SERVER['HTTP_HOST'], // $port,//host already includes the path $_SERVER["REQUEST_URI"]); error_log($profile['req_url']); // Set the default allowance for testing if (! array_key_exists('allow_test', $profile)) $profile['allow_test'] = false; // Set the default allowance for gmp if (! array_key_exists('allow_gmp', $profile)) $profile['allow_gmp'] = false; // Set the default force bigmath - BAD IDEA to override this if (! array_key_exists('force_bigmath', $profile)) $profile['force_bigmath'] = false; // Determine if GMP is usable $profile['use_gmp'] = (extension_loaded('gmp') && $profile['allow_gmp']) ? true : false; // Determine if I can perform big math functions $profile['use_bigmath'] = (extension_loaded('bcmath') || $profile['use_gmp'] || $profile['force_bigmath']) ? true : false; // Set a default authentication domain if (! array_key_exists('auth_domain', $profile)) $profile['auth_domain'] = $profile['req_url'] . ' ' . $profile['idp_url']; // Set a default authentication realm if (! array_key_exists('auth_realm', $profile)) $profile['auth_realm'] = 'ownCloud'; // Determine the realm for digest authentication - DO NOT OVERRIDE $profile['php_realm'] = $profile['auth_realm'] . (ini_get('safe_mode') ? '-' . getmyuid() : ''); // Set a default lifetime - the lesser of GC and cache time if (! array_key_exists('lifetime', $profile)) { $sce = session_cache_expire() * 60; $gcm = ini_get('session.gc_maxlifetime'); $profile['lifetime'] = $sce < $gcm ? $sce : $gcm; } // Set a default log file if (! array_key_exists('logfile', $profile)) $profile['logfile'] = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $profile['auth_realm'] . '.debug.log'; /* * Optional Initialization */ // Setup optional headers $profile['opt_headers'] = array(); // Determine if I should add microid stuff if (array_key_exists('microid', $profile)) { $hash = sha1($profile['idp_url']); $values = is_array($profile['microid']) ? $profile['microid'] : array($profile['microid']); foreach ($values as $microid) { preg_match('/^([a-z]+)/i', $microid, $mtx); $profile['opt_headers'][] = sprintf('', $mtx[1], $proto, sha1(sha1($microid) . $hash)); } } // Determine if I should add pavatar stuff if (array_key_exists('pavatar', $profile)) $profile['opt_headers'][] = sprintf('', $profile['pavatar']); /* * Do it */ // Decide which runmode, based on user request or default $run_mode = (isset($_REQUEST['openid_mode']) && in_array($_REQUEST['openid_mode'], $known['openid_modes'])) ? $_REQUEST['openid_mode'] : 'no'; // Run in the determined runmode debug("Run mode: $run_mode at: " . time()); debug($_REQUEST, 'Request params'); call_user_func($run_mode . '_mode'); ?>