diff -r d109af008343 -r 6212d849ab08 yubikey/usercp.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yubikey/usercp.php Fri Jun 30 17:49:12 2017 -0400 @@ -0,0 +1,385 @@ +attachHook("userprefs_jbox", "yubikey_ucp_setup();"); +$plugins->attachHook("userprefs_body", "return yubikey_user_cp(\$section);"); +$plugins->attachHook("login_form_html", "yubikey_inject_html_login();"); +$plugins->attachHook("ucp_register_form", "yubikey_inject_registration_form();"); +$plugins->attachHook("ucp_register_validate", "yubikey_register_validate(\$error);"); +$plugins->attachHook("user_registered", "yubikey_register_insert_key(\$user_id);"); + +function yubikey_ucp_setup() +{ + userprefs_menu_add('usercp_sec_profile', 'yubiucp_panel_title', makeUrlNS('Special', 'Preferences/Yubikey') . '" onclick="ajaxLoginNavTo(\'Special\', \'Preferences/Yubikey\', '.USER_LEVEL_CHPREF.'); return false;'); +} + +function yubikey_user_cp($section) +{ + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if ( $section !== 'Yubikey' ) + return false; + + if ( $session->auth_level < USER_LEVEL_CHPREF ) + { + redirect(makeUrlNS('Special', 'Login/' . $paths->fullpage, 'level=' . USER_LEVEL_CHPREF, true), 'Authentication required', 'You need to re-authenticate to access this page.', 0); + } + + $count_enabled = intval(getConfig('yubikey_enroll_limit', '3')); + + if ( isset($_POST['submit']) ) + { + csrf_request_confirm(); + + $keys = array(); + if ( isset($_POST['yubikey_enable']) ) + { + for ( $i = 0; $i < $count_enabled; $i++ ) + { + if ( !empty($_POST["yubikey_otp_$i"]) ) + { + $ckey =& $_POST["yubikey_otp_$i"]; + if ( preg_match('/^[cbdefghijklnrtuv]{12,44}$/', $ckey) ) + { + $ckey = substr($ckey, 0, 12); + $keys[] = $ckey; + } + unset($ckey); + } + } + } + // Check for double enrollment + $keys_check = "yubi_uid = '" . implode("' OR yubi_uid = '", $keys) . "'"; + $q = $db->sql_query('SELECT yubi_uid FROM ' . table_prefix . "yubikey WHERE ( $keys_check ) AND user_id != {$session->user_id};"); + if ( !$q ) + $db->_die(); + + if ( $db->numrows() > 0 ) + { + echo '
' . $lang->get('yubiucp_err_double_enrollment') . '
'; + while ( $row = $db->fetchrow() ) + { + foreach ( $keys as $i => $key ) + { + if ( $key == $row['yubi_uid'] ) + { + unset($keys[$i]); + } + } + } + $keys = array_values($keys); + } + $db->free_result(); + + // Remove all currently registered keys + $q = $db->sql_query('DELETE FROM ' . table_prefix . "yubikey WHERE user_id = {$session->user_id};"); + if ( !$q ) + $db->_die(); + + // Enroll any new keys + if ( !empty($keys) ) + { + $query = 'INSERT INTO ' . table_prefix . "yubikey(user_id, yubi_uid) VALUES\n " . + "( $session->user_id, '" . implode("' ),\n ( $session->user_id, '", $keys) . "' );"; + if ( !$db->sql_query($query) ) + $db->_die(); + } + + // Calculate flags + $yubi_flags = 0; + $yubi_flags |= intval($_POST['login_normal_flags']); + $yubi_flags |= intval($_POST['login_elev_flags']); + $yubi_flags |= ( isset($_POST['allow_no_yubikey']) ) ? YK_SEC_ALLOW_NO_OTP : 0; + + // update flags + $q = $db->sql_query('UPDATE ' . table_prefix . "users SET user_yubikey_flags = $yubi_flags WHERE user_id = {$session->user_id};"); + if ( !$q ) + $db->_die(); + + // regenerate session + $q = $db->sql_query('SELECT password FROM ' . table_prefix . "users WHERE user_id = {$session->user_id};"); + if ( !$q ) + $db->_die(); + list($password_hmac) = $db->fetchrow_num(); + + @$session->register_session($session->user_id, $session->username, $password_hmac, USER_LEVEL_MEMBER, false); + $session->logout(USER_LEVEL_CHPREF); + + // redirect back to normal CP + // if OB-ing isn't enabled, require a JS redirect (hey, not many other options...) + if ( @ob_get_contents() ) + { + @ob_end_clean(); + redirect(makeUrlNS('Special', 'Preferences'), $lang->get('yubiucp_msg_save_title'), $lang->get('yubiucp_msg_save_body'), 3); + } + else + { + echo '

' . $lang->get('yubiucp_msg_save_title') . '

'; + echo '

' . $lang->get('yubiucp_msg_save_body') . '

'; + // not much choice here, i'm resorting to javascript because the user CP always + // sends headers :-/ + echo ''; + return true; + } + } + else + { + // Fetch flags + $q = $db->sql_query('SELECT user_yubikey_flags FROM ' . table_prefix . "users WHERE user_id = {$session->user_id};"); + if ( !$q ) + $db->_die(); + + list($yubi_flags) = $db->fetchrow_num(); + $yubi_flags = intval($yubi_flags); + // Fetch user's authorized keys from the DB + $q = $db->sql_query('SELECT yubi_uid FROM ' . table_prefix . "yubikey WHERE user_id = {$session->user_id};"); + if ( !$q ) + $db->_die(); + + $keys = array(); + while ( $row = $db->fetchrow() ) + { + $keys[] = $row['yubi_uid']; + } + $db->free_result(); + } + + while ( count($keys) < $count_enabled ) + { + $keys[] = false; + } + + $enable_checked = ( $keys[0] === false && !isset($_POST['yubikey_enable']) ) ? '' : 'checked="checked"'; + $displaytable = ( $keys[0] === false && !isset($_POST['yubikey_enable']) ) ? 'none' : 'block'; + + $check_normal_keyonly = ( !($yubi_flags & YK_SEC_NORMAL_USERNAME) && !($yubi_flags & YK_SEC_NORMAL_PASSWORD) ) ? 'checked="checked" ' : ''; + $check_normal_username = ( ($yubi_flags & YK_SEC_NORMAL_USERNAME) && !($yubi_flags & YK_SEC_NORMAL_PASSWORD) ) ? 'checked="checked" ' : ''; + $check_normal_userandpw = ( ($yubi_flags & YK_SEC_NORMAL_USERNAME) && ($yubi_flags & YK_SEC_NORMAL_PASSWORD) ) ? 'checked="checked" ' : ''; + + $check_elev_keyonly = ( !($yubi_flags & YK_SEC_ELEV_USERNAME) && !($yubi_flags & YK_SEC_ELEV_PASSWORD) ) ? 'checked="checked" ' : ''; + $check_elev_username = ( ($yubi_flags & YK_SEC_ELEV_USERNAME) && !($yubi_flags & YK_SEC_ELEV_PASSWORD) ) ? 'checked="checked" ' : ''; + $check_elev_userandpw = ( ($yubi_flags & YK_SEC_ELEV_USERNAME) && ($yubi_flags & YK_SEC_ELEV_PASSWORD) ) ? 'checked="checked" ' : ''; + + ?> +

get('yubiucp_panel_title'); ?>

+ +
+ +
+ + + + + +
+ get('yubiucp_field_enable_title'); ?>
+ get('yubiucp_field_enable_hint'); ?> +
+ +
+ + + + + + + + + + + + + + + + + +
+ get('yubiucp_field_keys_title'); ?>
+ get('yubiucp_field_keys_hint'); + if ( $count_enabled > 1 ) + { + echo ' '; + echo $lang->get('yubiucp_field_keys_maximum', array('max' => $count_enabled)); + } + ?> +
+ ' . generate_yubikey_field('yubikey_otp_' . $i, $keys[$i]) . '

'; + } + ?> +
+ get('yubiucp_field_normal_flags'); ?> + + + +
+ + + +
+ + +
+ get('yubiucp_field_elev_flags'); ?> + + + +
+ + + +
+ + +
+ + +
+ + get('yubiucp_field_allow_plain_login_hint'); ?> + +
+ + + + +
+ +
+
+ + + +
+ + + + get('yubiauth_lbl_otp_field'); ?> + + + + + + + + + get('yubiucp_reg_field_otp'); ?>
+ get('yubiucp_reg_field_otp_hint_required'); + else + echo $lang->get('yubiucp_reg_field_otp_hint_optional'); + ?> + + + + + + + + get('yubiucp_reg_err_otp_required'); + return false; + } + if ( $have_otp ) + { + $result = yubikey_validate_otp($_POST['yubikey_otp']); + if ( !$result['success'] ) + { + $error = '' . $lang->get('yubiucp_reg_err_otp_invalid') . '
' . $lang->get("yubiauth_err_{$result['error']}"); + return false; + } + // check for double enrollment + $yubi_uid = substr($_POST['yubikey_otp'], 0, 12); + // Note on SQL injection: yubikey_validate_otp() has already ensured that this is safe + $q = $db->sql_query('SELECT 1 FROM ' . table_prefix . "yubikey WHERE yubi_uid = '$yubi_uid';"); + if ( !$q ) + $db->_die(); + if ( $db->numrows() > 0 ) + { + $error = '' . $lang->get('yubiucp_reg_err_otp_invalid') . '
' . $lang->get('yubiucp_err_double_enrollment_single'); + return false; + } + $db->free_result(); + } +} + +function yubikey_register_insert_key($user_id) +{ + global $db, $session, $paths, $template, $plugins; // Common objects + if ( !empty($_POST['yubikey_otp']) ) + { + $yubi_uid = $db->escape(substr($_POST['yubikey_otp'], 0, 12)); + $q = $db->sql_query('INSERT INTO ' . table_prefix . "yubikey ( user_id, yubi_uid ) VALUES ( $user_id, '$yubi_uid' );"); + if ( !$q ) + $db->_die(); + } +}