diff --git a/bin/v-check-api-key b/bin/v-check-api-key new file mode 100755 index 00000000..8d0d409e --- /dev/null +++ b/bin/v-check-api-key @@ -0,0 +1,40 @@ +#!/bin/bash +# info: check api key +# options: KEY +# +# The function checks a key file in /usr/local/vesta/data/keys/ + + +#----------------------------------------------------------# +# Variable&Function # +#----------------------------------------------------------# + +if [ -z "$1" ]; then + echo "Error: key missmatch" + exit 9 +fi +key=$(basename $1) +ip=${2-127.0.0.1} +time_n_date=$(date +'%T %F') +time=$(echo "$time_n_date" |cut -f 1 -d \ ) +date=$(echo "$time_n_date" |cut -f 2 -d \ ) + + +#----------------------------------------------------------# +# Action # +#----------------------------------------------------------# + +if [ ! -e $VESTA/data/keys/$key ]; then + echo "Error: key missmatch" + echo "$date $time api $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + + +#----------------------------------------------------------# +# Vesta # +#----------------------------------------------------------# + +echo "$date $time api $ip successfully launched" >> $VESTA/log/auth.log + +exit diff --git a/bin/v-check-user-hash b/bin/v-check-user-hash new file mode 100755 index 00000000..7fd55789 --- /dev/null +++ b/bin/v-check-user-hash @@ -0,0 +1,100 @@ +#!/bin/bash +# info: check user hash +# options: USER HASH [IP] +# +# The function verifies user hash + + +#----------------------------------------------------------# +# Variable&Function # +#----------------------------------------------------------# + +# Argument definition +user=$1 +hash=$2; HIDE=2 +ip=${3-127.0.0.1} + +# Includes +source $VESTA/func/main.sh +source $VESTA/conf/vesta.conf + +time_n_date=$(date +'%T %F') +time=$(echo "$time_n_date" |cut -f 1 -d \ ) +date=$(echo "$time_n_date" |cut -f 2 -d \ ) + + +#----------------------------------------------------------# +# Verifications # +#----------------------------------------------------------# + + +check_args '2' "$#" 'USER HASH' +is_format_valid 'user' + +# Checking user +if [ ! -d "$VESTA/data/users/$user" ] && [ "$user" != 'root' ]; then + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + +# Checking user hash +is_hash_valid + +# Checking empty hash +if [[ -z "$hash" ]]; then + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + + +#----------------------------------------------------------# +# Action # +#----------------------------------------------------------# + + +# Parsing user's salt +shadow=$(grep "^$user:" /etc/shadow | cut -f 2 -d :) + +if echo "$shadow" | grep -qE '^\$[0-9a-z]+\$[^\$]+\$' +then + salt=$(echo "$shadow" |cut -f 3 -d \$) + method=$(echo "$shadow" |cut -f 2 -d \$) + if [ "$method" -eq '1' ]; then + method='md5' + elif [ "$method" -eq '6' ]; then + method='sha-512' + else + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 + fi +else + salt=${shadow:0:2} + method='des' +fi + +if [ -z "$salt" ]; then + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + +# Checking hash +result=$(grep "^$user:$hash:" /etc/shadow 2>/dev/null) +if [[ -z "$result" ]]; then + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + + +#----------------------------------------------------------# +# Vesta # +#----------------------------------------------------------# + +# Logging +echo "$date $time $user $ip successfully logged in" >> $VESTA/log/auth.log + +exit diff --git a/bin/v-get-user-salt b/bin/v-get-user-salt new file mode 100755 index 00000000..08ee5a9c --- /dev/null +++ b/bin/v-get-user-salt @@ -0,0 +1,118 @@ +#!/bin/bash +# info: get user salt +# options: USER [IP] [FORMAT] +# +# The function provides users salt + + +#----------------------------------------------------------# +# Variable&Function # +#----------------------------------------------------------# + +# Argument definition +user=$1 +ip=${2-127.0.0.1} +format=${3-shell} + +# Includes +source $VESTA/func/main.sh +source $VESTA/conf/vesta.conf + +time_n_date=$(date +'%T %F') +time=$(echo "$time_n_date" |cut -f 1 -d \ ) +date=$(echo "$time_n_date" |cut -f 2 -d \ ) + +# JSON list function +json_list() { + echo '{' + echo ' "'$user'": { + "METHOD": "'$method'", + "SALT": "'$salt'", + "TIME": "'$time'", + "DATE": "'$date'" + }' + echo '}' +} + +# SHELL list function +shell_list() { + echo "METHOD: $method" + echo "SALT: $salt" +} + +# PLAIN list function +plain_list() { + echo -e "$method\t$salt" +} + +# CSV list function +csv_list() { + echo "METHOD,SALT" + echo "$method, $salt" +} + + +#----------------------------------------------------------# +# Verifications # +#----------------------------------------------------------# + + +check_args '1' "$#" 'USER [IP] [SALT]' +is_format_valid 'user' + +# Checking user +if [ ! -d "$VESTA/data/users/$user" ] && [ "$user" != 'root' ]; then + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + + +#----------------------------------------------------------# +# Action # +#----------------------------------------------------------# + +# Parsing user's salt +shadow=$(grep "^$user:" /etc/shadow | cut -f 2 -d :) + +if echo "$shadow" | grep -qE '^\$[0-9a-z]+\$[^\$]+\$' +then + salt=$(echo "$shadow" |cut -f 3 -d \$) + method=$(echo "$shadow" |cut -f 2 -d \$) + if [ "$method" -eq '1' ]; then + method='md5' + elif [ "$method" -eq '6' ]; then + method='sha-512' + else + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 + fi +else + salt=${shadow:0:2} + method='des' +fi + +if [ -z "$salt" ]; then + echo "Error: password missmatch" + echo "$date $time $user $ip failed to login" >> $VESTA/log/auth.log + exit 9 +fi + + +# Listing data +case $format in + json) json_list ;; + plain) plain_list ;; + csv) csv_list ;; + shell) shell_list ;; +esac + + +#----------------------------------------------------------# +# Vesta # +#----------------------------------------------------------# + +# Logging + +exit diff --git a/func/main.sh b/func/main.sh index 3b04d250..a79cb2a0 100644 --- a/func/main.sh +++ b/func/main.sh @@ -278,6 +278,15 @@ is_password_valid() { fi } +# Check if hash is transmitted via file +is_hash_valid() { + if [[ "$hash" =~ ^/tmp/ ]]; then + if [ -f "$hash" ]; then + hash="$(head -n1 $hash)" + fi + fi +} + # Get object value get_object_value() { object=$(grep "$2='$3'" $USER_DATA/$1.conf) diff --git a/web/api/index.php b/web/api/index.php index 1ad9d595..3cf0ec2d 100644 --- a/web/api/index.php +++ b/web/api/index.php @@ -4,32 +4,64 @@ define('VESTA_CMD', '/usr/bin/sudo /usr/local/vesta/bin/'); if (isset($_POST['user']) || isset($_POST['hash'])) { // Authentication - $auth_code = 1; if (empty($_POST['hash'])) { - // Check user permission to use API if ($_POST['user'] != 'admin') { - echo 'Error: only admin is allowed to use API'; + echo 'Error: authentication failed'; exit; } - $v_user = escapeshellarg($_POST['user']); - $v_password = tempnam("/tmp","vst"); - $fp = fopen($v_password, "w"); - fwrite($fp, $_POST['password']."\n"); + $password = $_POST['password']; + $v_ip = escapeshellarg($_SERVER['REMOTE_ADDR']); + $output = ''; + exec (VESTA_CMD."v-get-user-salt admin ".$v_ip." json" , $output, $return_var); + $pam = json_decode(implode('', $output), true); + $salt = $pam['admin']['SALT']; + $method = $pam['admin']['METHOD']; + + if ($method == 'md5' ) { + $hash = crypt($password, '$1$'.$salt.'$'); + } + if ($method == 'sha-512' ) { + $hash = crypt($password, '$6$rounds=5000$'.$salt.'$'); + $hash = str_replace('$rounds=5000','',$hash); + } + if ($method == 'des' ) { + $hash = crypt($password, $salt); + } + + // Send hash via tmp file + $v_hash = exec('mktemp -p /tmp'); + $fp = fopen($v_hash, "w"); + fwrite($fp, $hash."\n"); fclose($fp); - $v_ip_addr = escapeshellarg($_SERVER["REMOTE_ADDR"]); - exec(VESTA_CMD ."v-check-user-password ".$v_user." ".escapeshellarg($v_password)." '".$v_ip_addr."'", $output, $auth_code); - unlink($v_password); - /* No hash auth for security reason + + // Check user hash + exec(VESTA_CMD ."v-check-user-hash admin ".$v_hash." ".$v_ip, $output, $return_var); + unset($output); + + // Remove tmp file + unlink($v_hash); + + // Check API answer + if ( $return_var > 0 ) { + echo 'Error: authentication failed'; + exit; + } } else { $key = '/usr/local/vesta/data/keys/' . basename($_POST['hash']); if (file_exists($key) && is_file($key)) { - $auth_code = '0'; + exec(VESTA_CMD ."v-check-api-key ".escapeshellarg($key)." ".$v_ip, $output, $return_var); + unset($output); + + // Check API answer + if ( $return_var > 0 ) { + echo 'Error: authentication failed'; + exit; + } } - */ } - if ($auth_code != 0 ) { + if ( $return_var > 0 ) { echo 'Error: authentication failed'; exit; } diff --git a/web/login/index.php b/web/login/index.php index 6e3d5def..08074b3e 100644 --- a/web/login/index.php +++ b/web/login/index.php @@ -14,9 +14,6 @@ if (isset($_GET['logout'])) { session_destroy(); } - - - // Login as someone else if (isset($_SESSION['user'])) { if ($_SESSION['user'] == 'admin' && !empty($_GET['loginas'])) { @@ -36,62 +33,85 @@ if (isset($_SESSION['user'])) { if (isset($_POST['user']) && isset($_POST['password'])) { if(isset($_SESSION['token']) && isset($_POST['token']) && $_POST['token'] == $_SESSION['token']) { $v_user = escapeshellarg($_POST['user']); + $v_ip = escapeshellarg($_SERVER['REMOTE_ADDR']); - // Send password via tmp file - $v_password = exec('mktemp -p /tmp'); - $fp = fopen($v_password, "w"); - fwrite($fp, $_POST['password']."\n"); - fclose($fp); - - // Check user & password - exec(VESTA_CMD ."v-check-user-password ".$v_user." ".escapeshellarg($v_password)." ".escapeshellarg($_SERVER['REMOTE_ADDR']), $output, $return_var); - unset($output); - - // Remove tmp file - unlink($v_password); - - // Check API answer + // Get user's salt + $output = ''; + exec (VESTA_CMD."v-get-user-salt ".$v_user." ".$v_ip." json" , $output, $return_var); + $pam = json_decode(implode('', $output), true); if ( $return_var > 0 ) { $ERROR = "".__('Invalid username or password').""; - } else { + $user = $_POST['user']; + $password = $_POST['password']; + $salt = $pam[$user]['SALT']; + $method = $pam[$user]['METHOD']; - // Make root admin user - if ($_POST['user'] == 'root') $v_user = 'admin'; - - // Get user speciefic parameters - exec (VESTA_CMD . "v-list-user ".$v_user." json", $output, $return_var); - $data = json_decode(implode('', $output), true); - - // Define session user - $_SESSION['user'] = key($data); - $v_user = $_SESSION['user']; - - // Get user favorites - get_favourites(); - - // Define language - $output = ''; - exec (VESTA_CMD."v-list-sys-languages json", $output, $return_var); - $languages = json_decode(implode('', $output), true); - if(in_array($data[$v_user]['LANGUAGE'], $languages)){ - $_SESSION['language'] = $data[$v_user]['LANGUAGE']; + if ($method == 'md5' ) { + $hash = crypt($password, '$1$'.$salt.'$'); } - else { - $_SESSION['language'] = 'en'; + if ($method == 'sha-512' ) { + $hash = crypt($password, '$6$rounds=5000$'.$salt.'$'); + $hash = str_replace('$rounds=5000','',$hash); + } + if ($method == 'des' ) { + $hash = crypt($password, $salt); } - - // Regenerate session id to prevent session fixation - session_regenerate_id(); - // Redirect request to control panel interface - if (!empty($_SESSION['request_uri'])) { - header("Location: ".$_SESSION['request_uri']); - unset($_SESSION['request_uri']); - exit; + // Send hash via tmp file + $v_hash = exec('mktemp -p /tmp'); + $fp = fopen($v_hash, "w"); + fwrite($fp, $hash."\n"); + fclose($fp); + + // Check user hash + exec(VESTA_CMD ."v-check-user-hash ".$v_user." ".$v_hash." ".$v_ip, $output, $return_var); + unset($output); + + // Remove tmp file + unlink($v_hash); + + // Check API answer + if ( $return_var > 0 ) { + $ERROR = "".__('Invalid username or password').""; } else { - header("Location: /"); - exit; + + // Make root admin user + if ($_POST['user'] == 'root') $v_user = 'admin'; + + // Get user speciefic parameters + exec (VESTA_CMD . "v-list-user ".$v_user." json", $output, $return_var); + $data = json_decode(implode('', $output), true); + + // Define session user + $_SESSION['user'] = key($data); + $v_user = $_SESSION['user']; + + // Get user favorites + get_favourites(); + + // Define language + $output = ''; + exec (VESTA_CMD."v-list-sys-languages json", $output, $return_var); + $languages = json_decode(implode('', $output), true); + if (in_array($data[$v_user]['LANGUAGE'], $languages)){ + $_SESSION['language'] = $data[$v_user]['LANGUAGE']; + } else { + $_SESSION['language'] = 'en'; + } + + // Regenerate session id to prevent session fixation + session_regenerate_id(); + + // Redirect request to control panel interface + if (!empty($_SESSION['request_uri'])) { + header("Location: ".$_SESSION['request_uri']); + unset($_SESSION['request_uri']); + exit; + } else { + header("Location: /"); + exit; + } } } } else {