diff --git a/blash.css b/blash.css index 024fbfa..11bb6dd 100644 --- a/blash.css +++ b/blash.css @@ -29,11 +29,11 @@ input.password div#blashWindow { - width : 800px; - height : 400px; + /* width : 800px; */ + /* height : 400px; */ margin : auto; - padding : 10px; - border : 1px solid #888; + /* padding : 10px; */ + /* border : 1px solid #888; */ overflow : auto; tabindex : -1; } diff --git a/commands/mkdir.json b/commands/mkdir.json new file mode 100644 index 0000000..938038e --- /dev/null +++ b/commands/mkdir.json @@ -0,0 +1,89 @@ +{ + "name" : "mkdir", + + "info" : { + "syntax" : "mkdir <directory name>", + "brief" : "Create a new directory", + }, + + "action" : function ( arg ) + { + if ( !arg || arg.length == 0 ) + { + return "mkdir: Parameter expected
\n"; + } + + shell.auto_prompt_focus = false; + shell.auto_prompt_refresh = false; + arg = shell.expandPath ( arg ); + + var users_php = window.location.href; + users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' ); + params = 'action=mkdir&dir=' + escape ( arg ); + + var http = new XMLHttpRequest(); + http.open ( "POST", users_php, true ); + http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + http.setRequestHeader("Content-length", params.length); + http.setRequestHeader("Connection", "close"); + + http.onreadystatechange = function () + { + if ( http.readyState == 4 && http.status == 200 ) + { + if ( http.responseText.length > 0 ) + { + shell.cmdOut.innerHTML = http.responseText; + } else { + var files_config = window.location.href; + files_config = files_config.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/files.php' ); + + var http2 = new XMLHttpRequest(); + http2.open ( "GET", files_config, true ); + + http2.onreadystatechange = function () + { + if ( http2.readyState == 4 && http2.status == 200 ) + { + shell.files = eval ( '(' + http2.responseText + ')' ); + + // Remove duplicates + var tmp = new Array(); + + for ( var i in shell.files ) + { + var contains = false; + + for ( var j=0; j < tmp.length && !contains; j++ ) + { + if ( shell.files[i].path == tmp[j].path ) + { + contains = true; + } + } + + if ( !contains ) + { + tmp.push ( shell.files[i] ); + } + } + + shell.files = tmp; + } + } + + http2.send ( null ); + shell.cmdOut.innerHTML = ''; + } + + shell.refreshPrompt ( false, false ); + shell.auto_prompt_focus = true; + shell.auto_prompt_refresh = true; + } + } + + http.send ( params ); + shell.cmdOut.innerHTML = ''; + } +} + diff --git a/commands/rmdir.json b/commands/rmdir.json new file mode 100644 index 0000000..861bee7 --- /dev/null +++ b/commands/rmdir.json @@ -0,0 +1,89 @@ +{ + "name" : "rmdir", + + "info" : { + "syntax" : "rmdir <directory name>", + "brief" : "Remove a directory (recursively if the directory is not empty)", + }, + + "action" : function ( arg ) + { + if ( !arg || arg.length == 0 ) + { + return "mkdir: Parameter expected
\n"; + } + + shell.auto_prompt_focus = false; + shell.auto_prompt_refresh = false; + arg = shell.expandPath ( arg ); + + var users_php = window.location.href; + users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' ); + params = 'action=rmdir&dir=' + escape ( arg ); + + var http = new XMLHttpRequest(); + http.open ( "POST", users_php, true ); + http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + http.setRequestHeader("Content-length", params.length); + http.setRequestHeader("Connection", "close"); + + http.onreadystatechange = function () + { + if ( http.readyState == 4 && http.status == 200 ) + { + if ( http.responseText.length > 0 ) + { + shell.cmdOut.innerHTML = http.responseText; + } else { + var files_config = window.location.href; + files_config = files_config.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/files.php' ); + + var http2 = new XMLHttpRequest(); + http2.open ( "GET", files_config, true ); + + http2.onreadystatechange = function () + { + if ( http2.readyState == 4 && http2.status == 200 ) + { + shell.files = eval ( '(' + http2.responseText + ')' ); + + // Remove duplicates + var tmp = new Array(); + + for ( var i in shell.files ) + { + var contains = false; + + for ( var j=0; j < tmp.length && !contains; j++ ) + { + if ( shell.files[i].path == tmp[j].path ) + { + contains = true; + } + } + + if ( !contains ) + { + tmp.push ( shell.files[i] ); + } + } + + shell.files = tmp; + } + } + + http2.send ( null ); + shell.cmdOut.innerHTML = ''; + } + + shell.refreshPrompt ( false, false ); + shell.auto_prompt_focus = true; + shell.auto_prompt_refresh = true; + } + } + + http.send ( params ); + shell.cmdOut.innerHTML = ''; + } +} + diff --git a/commands/su.json b/commands/su.json index b1fc6f9..f5916ea 100644 --- a/commands/su.json +++ b/commands/su.json @@ -22,18 +22,22 @@ if ( shell.__first_cmd ) { - shell.cmdOut.innerHTML = '
'; + shell.cmdOut.innerHTML = '
Password: ' + + '
'; + shell.__first_cmd = false; + } else { + shell.cmdOut.innerHTML = 'Password: ' + + '
'; } shell.getPassword = this.getPassword; shell.newuser = arg; - shell.cmdOut.innerHTML += 'Password: ' + - '
'; - shell.auto_prompt_focus = false; shell.auto_prompt_refresh = false; diff --git a/commands/useradd.json b/commands/useradd.json index b218b2f..15c9e76 100644 --- a/commands/useradd.json +++ b/commands/useradd.json @@ -39,6 +39,12 @@ { shell.cmdOut.innerHTML = 'The passwords do not match'; } else { + if ( shell.newuser.match ( /[^0-9a-zA-Z_]/ )) + { + shell.cmdOut.innerHTML = 'The username contains invalid characters, out of the charset [0-9a-zA-Z_]'; + return false; + } + var users_php = window.location.href; users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' ); params = 'action=add&user=' + escape ( shell.newuser ) + '&pass=' + md5 ( password.value ); @@ -60,6 +66,8 @@ shell.cmdOut.innerHTML = ''; } + shell.auto_prompt_focus = true; + shell.auto_prompt_refresh = true; shell.refreshPrompt ( false, false ); } } @@ -67,10 +75,6 @@ http.send ( params ); shell.cmdOut.innerHTML = ''; } - - shell.auto_prompt_focus = true; - shell.auto_prompt_refresh = true; - shell.refreshPrompt ( false, false ); } }, @@ -89,23 +93,35 @@ return "Usage: " + this.name + " <username>
\n"; } + if ( arg.match ( /[^0-9a-zA-Z_]/ )) + { + return "Invalid character(s) in the username, range [0-9a-zA-Z_] allowed
\n"; + } + shell.keyPassword = this.keyPassword; shell.keyRepeatPassword = this.keyRepeatPassword; shell.newuser = arg; if ( shell.__first_cmd ) { - shell.cmdOut.innerHTML = '
'; - shell.__first_cmd = false; - } + shell.cmdOut.innerHTML = '
Password: ' + + '
' + + '
'; - shell.cmdOut.innerHTML += 'Password: ' + - '
' + - '
'; + shell.__first_cmd = false; + } else { + shell.cmdOut.innerHTML = 'Password: ' + + '
' + + '
'; + } shell.auto_prompt_focus = false; shell.auto_prompt_refresh = false; diff --git a/modules/users/user_utils.php b/modules/users/user_utils.php index b73bda1..95cb9a9 100644 --- a/modules/users/user_utils.php +++ b/modules/users/user_utils.php @@ -1,5 +1,7 @@ $value ) { + $items[] = __json_encode("$key") . ': ' . __json_encode($value); + } + + $json = '{' . implode(', ', $items) . '}'."\n"; + } + } elseif ( is_string ( $data )) { + # Escape non-printable or Non-ASCII characters. + # I also put the \\ character first, as suggested in comments on the 'addclashes' page. + #$string = '"' . addcslashes($data, "\\\"\n\r\t/" . chr(8) . chr(12)) . '"'; + $string = '"' . $data . '"'; + $json = ''; + $len = strlen ($string); + + # Convert UTF-8 to Hexadecimal Codepoints. + for ( $i = 0; $i < $len; $i++ ) { + $char = $string[$i]; + $c1 = ord($char); + + # Single byte; + if( $c1 <128 ) { + $json .= ($c1 > 31) ? $char : sprintf("\\u%04x", $c1); + continue; + } + + # Double byte + $c2 = ord($string[++$i]); + if ( ($c1 & 32) === 0 ) { + $json .= sprintf("\\u%04x", ($c1 - 192) * 64 + $c2 - 128); + continue; + } + + # Triple + $c3 = ord($string[++$i]); + if( ($c1 & 16) === 0 ) { + $json .= sprintf("\\u%04x", (($c1 - 224) <<12) + (($c2 - 128) << 6) + ($c3 - 128)); + continue; + } + + # Quadruple + $c4 = ord($string[++$i]); + if( ($c1 & 8 ) === 0 ) { + $u = (($c1 & 15) << 2) + (($c2>>4) & 3) - 1; + + $w1 = (54<<10) + ($u<<6) + (($c2 & 15) << 2) + (($c3>>4) & 3); + $w2 = (55<<10) + (($c3 & 15)<<6) + ($c4-128); + $json .= sprintf("\\u%04x\\u%04x", $w1, $w2); + } + } + } else { + # int, floats, bools, null + $json = strtolower(var_export( $data, true )); + } + + return $json; +} + +function __mkdir ( $dir, $own_perms ) +{ + include "../../system/files_json.php"; + + if ( !$files_json || strlen ( $files_json ) == 0 ) + { + return 'mkdir: Error: Empty JSON file container'; + } + + if ( preg_match ( "@[^0-9a-zA-Z_\./\ ]@", $dir )) + { + return "mkdir: Invalid character(s) for a directory name out of range '[0-9a-zA-Z_./ ]'\n"; + } + + $has_perms = false; + + if ( $own_perms ) + { + if ( is_array ( $own_perms )) + { + $has_perms = true; + } + } + + $user = getUser(); + $json = json_decode ( $files_json, true ); + $parent_dir = preg_replace ( '@/[^/]+$@', '', $dir ); + $parent_dir_found = false; + + if ( preg_match ( "/^\s*$/", $parent_dir )) + { + $parent_dir = '/'; + } + + for ( $i=0; $i < count ( $json ); $i++ ) + { + $path = $json[$i]['path']; + + if ( !$path || strlen ( $path ) == 0 ) + { + continue; + } + + if ( $path == $parent_dir ) + { + $parent_dir_found = true; + $perms = getPerms ( $parent_dir ); + $perms = json_decode ( $perms, true ); + + if ( $perms['write'] == false ) + { + $dir = str_replace ( '<', '<', $dir ); + $dir = str_replace ( '>', '>', $dir ); + return "mkdir: Could not create directory $dir: Permission denied\n"; + } + } + + if ( $path == $dir ) + { + $dir = str_replace ( '<', '<', $dir ); + $dir = str_replace ( '>', '>', $dir ); + return "mkdir: Could not create directory $dir: The file already exists\n"; + } + } + + if ( !$parent_dir_found ) + { + $dir = str_replace ( '<', '<', $dir ); + $dir = str_replace ( '>', '>', $dir ); + return "mkdir: Could not create directory $dir: Parent directory not found\n"; + } + + $newdir = array(); + $newdir['path'] = "$dir"; + $newdir['type'] = 'directory'; + $newdir['owner'] = ($has_perms) ? $own_perms['owner'] : "$user"; + $newdir['can_read'] = ($has_perms) ? $own_perms['can_read'] : '@all'; + $newdir['can_write'] = ($has_perms) ? $own_perms['can_write'] : "$user"; + + array_push ( $json, $newdir ); + + if ( !( $fp = fopen ( "../../system/files_json.php", "w" ))) + { + return "mkdir: Unable to write on directories file\n"; + } + + fwrite ( $fp, ""); + fclose ( $fp ); + return ""; +} + +function __rmdir ( $dir ) +{ + include "../../system/files_json.php"; + + if ( !$files_json || strlen ( $files_json ) == 0 ) + { + return 'mkdir: Error: Empty JSON file container'; + } + + $user = getUser(); + $json = json_decode ( $files_json, true ); + $dir_found = false; + + for ( $i=0; $i < count ( $json ) && !$dir_found; $i++ ) + { + $path = $json[$i]['path']; + + if ( !$path || strlen ( $path ) == 0 ) + { + continue; + } + + if ( $path == $dir ) + { + $dir_found = true; + $perms = getPerms ( $dir ); + $perms = json_decode ( $perms, true ); + + if ( $perms['write'] == false ) + { + $dir = str_replace ( '<', '<', $dir ); + $dir = str_replace ( '>', '>', $dir ); + return "rmdir: Could not remove directory $dir: Permission denied\n"; + } else { + array_splice ( $json, $i, 1 ); + } + } + } + + if ( !$dir_found ) + { + $dir = str_replace ( '<', '<', $dir ); + $dir = str_replace ( '>', '>', $dir ); + return "mkdir: Could not remove directory $dir: File not found\n"; + } + + if ( !( $fp = fopen ( "../../system/files_json.php", "w" ))) + { + return "mkdir: Unable to write on directories file\n"; + } + + fwrite ( $fp, ""); + fclose ( $fp ); + return ""; +} + ?> diff --git a/modules/users/users.php b/modules/users/users.php index e31b4a3..0edf75f 100644 --- a/modules/users/users.php +++ b/modules/users/users.php @@ -3,6 +3,8 @@ include 'userlist.php'; include 'user_utils.php'; +global $sudo_cmd; + $action = $_REQUEST['action']; if ( $action == null ) @@ -24,19 +26,19 @@ switch ( $action ) if ( preg_match ( '/[^a-zA-Z0-9_]/', $username )) { print "The username can only contain characters in the charset '[a-zA-Z0-9_]'\n"; - return 1; + return ''; } - if ( preg_match ( '/[^a-zA-Z0-9]/', $password ) || strlen ( $password ) != 32 ) + if ( preg_match ( '/[^a-fA-F0-9]/', $password ) || strlen ( $password ) != 32 ) { print "The provided password is not a valid hash\n"; - return 1; + return ''; } if ( !( $xml = new SimpleXMLElement ( $xmlcontent ))) { print "Unable to open the users XML file\n"; - return 1; + return ''; } for ( $i = 0; $i < count ( $xml->user ); $i++ ) @@ -44,7 +46,7 @@ switch ( $action ) if ( !strcasecmp ( $xml->user[$i]['name'], $username )) { print "The specified user already exists\n"; - return 1; + return ''; } } @@ -56,13 +58,22 @@ switch ( $action ) if ( !( $fp = fopen ( 'userlist.php', 'w' ))) { print "Unable to add the specified user, unknown error\n"; - return 1; + return ''; } fwrite ( $fp, 'asXML() . "\nXML;\n\n?>\n" ); fclose ( $fp ); - print 'User "'.$username.' successfully added, home directory set to "/home/'.$username."\"\n"; + $perms = array(); + $perms['owner'] = $username; + $perms['can_read'] = $username; + $perms['can_write'] = $username; + + $GLOBALS['sudo_cmd'] = true; + print __mkdir ( '/home/'.$username, $perms )."
\n"; + $GLOBALS['sudo_cmd'] = false; + + print 'User "'.$username.'" successfully added, home directory set to "/home/'.$username."\"\n"; break; case 'login': @@ -77,13 +88,13 @@ switch ( $action ) if ( preg_match ( '/[^a-zA-Z0-9_]/', $username )) { print "The username can only contain characters in the charset '[a-zA-Z0-9_]'\n"; - return 1; + return ''; } if ( !( $xml = new SimpleXMLElement ( $xmlcontent ))) { print "Unable to open the users XML file\n"; - return 1; + return ''; } for ( $i = 0; $i < count ( $xml->user ) && !$found; $i++ ) @@ -93,7 +104,7 @@ switch ( $action ) if ( strcasecmp ( $xml->user[$i]['pass'], $password )) { print "Wrong password provided for user '$username'\n"; - return 1; + return ''; } else { $auth = md5 ( $xml->user[$i]['name'] . $xml->user[$i]['pass'] ); setcookie ( 'username', $xml->user[$i]['name'], 0, "/" ); @@ -106,7 +117,7 @@ switch ( $action ) } print "Username not found: '$username'\n"; - return 1; + return ''; break; case 'getuser': @@ -129,13 +140,13 @@ switch ( $action ) if ( $cur_user != 'root' && $cur_user != $user ) { print "You cannot change the password for the user '$user'\n"; - return 1; + return ''; } if ( !( $xml = new SimpleXMLElement ( $xmlcontent ))) { print "Unable to open the users XML file\n"; - return 1; + return ''; } for ( $i = 0; $i < count ( $xml->user ); $i++ ) @@ -151,7 +162,7 @@ switch ( $action ) if ( $xml->user[$i]['pass'] != $old_pass ) { print "The provided current password is wrong\n"; - return 1; + return ''; } } @@ -160,7 +171,7 @@ switch ( $action ) if ( !( $fp = fopen ( 'userlist.php', 'w' ))) { print "Unable to change the password for the specified user, unknown error\n"; - return 1; + return ''; } fwrite ( $fp, "asXML() . "\nXML;\n\n?>\n" ); @@ -183,7 +194,28 @@ switch ( $action ) print getPerms ( $res ); break; + + case 'mkdir': + $dir = $_REQUEST['dir']; + + if ( !$dir ) + { + return false; + } + + print __mkdir ( $dir, null ); + break; + + case 'rmdir': + $dir = $_REQUEST['dir']; + + if ( !$dir ) + { + return false; + } + + print __rmdir ( $dir ); + break; } ?> - diff --git a/system/blash.json b/system/blash.json index b247238..3883f99 100644 --- a/system/blash.json +++ b/system/blash.json @@ -63,8 +63,10 @@ "logout", "ls", "man", + "mkdir", "passwd", "pwd", + "rmdir", "su", "useradd", "whoami" diff --git a/system/files_json.php b/system/files_json.php index c0c879e..b7b4026 100644 --- a/system/files_json.php +++ b/system/files_json.php @@ -2,157 +2,38 @@ $files_json = << +?> \ No newline at end of file