From 51121bd09bc238de23f042eb88466520e95c5033 Mon Sep 17 00:00:00 2001
From: BlackLight <blacklight@autistici.org>
Date: Sat, 25 Dec 2010 13:27:38 +0100
Subject: [PATCH] Multiuser support, useradd command

---
 blash.css                       |  10 ++
 blash.js                        | 149 ++++++++++++++++-------
 blash.json                      |   2 +
 commands/clear.json             |  25 +---
 commands/echo.json              |  15 +++
 commands/useradd.json           | 113 +++++++++++++++++
 index.html                      |   1 +
 md5.js                          | 209 ++++++++++++++++++++++++++++++++
 modules/users/.userlist.php.swp | Bin 0 -> 12288 bytes
 modules/users/.users.php.swp    | Bin 0 -> 12288 bytes
 modules/users/userlist.php      |  10 ++
 modules/users/users.php         |  68 +++++++++++
 12 files changed, 537 insertions(+), 65 deletions(-)
 create mode 100644 commands/echo.json
 create mode 100644 commands/useradd.json
 create mode 100644 md5.js
 create mode 100644 modules/users/.userlist.php.swp
 create mode 100644 modules/users/.users.php.swp
 create mode 100644 modules/users/userlist.php
 create mode 100644 modules/users/users.php

diff --git a/blash.css b/blash.css
index da09cb0..da4f52e 100644
--- a/blash.css
+++ b/blash.css
@@ -17,6 +17,16 @@ input.promptInput
 	width : 500px;
 }
 
+input.password
+{
+	background-color : black;
+	border : 0;
+	color : #888;
+	font-family : Terminus, courier, monospace, fixed;
+	font-size : 13px;
+	width : 500px;
+}
+
 div#blashWindow
 {
 	width : 800px;
diff --git a/blash.js b/blash.js
index b2d1cce..bc46107 100644
--- a/blash.js
+++ b/blash.js
@@ -48,6 +48,12 @@ function blash ()
 
 	/** Check if this is the first command given in this session (for fixing <br/> stuff) */
 	this.__first_cmd = true;
+
+	/** Variable set if the prompt is re-generated automatically after a command was given */
+	this.auto_prompt_refresh = true;
+
+	/** Variable set if the focus should be automatically set to the prompt line after a command */
+	this.auto_prompt_focus = true;
 	/**************************************/
 
 	this.loadCommand = function ( cmd )
@@ -139,48 +145,55 @@ function blash ()
 				}
 			}
 
-			var value = this.prompt.value;
-			var out = this.cmdOut.innerHTML;
-
-			var text = ( shell.json.promptText ) ? shell.json.promptText : "[%n@%m %W] $ ";
-			text = shell.unescapePrompt ( text, shell.json.promptSequences );
-
-			this.window.removeChild ( this.prompt );
-			this.window.removeChild ( this.cmdOut );
-
-			if ( this.__first_cmd && this.prompt.value.length > 0 )
+			if ( this.auto_prompt_refresh )
 			{
-				this.window.innerHTML += value + '<br/>' + out + text;
-				this.__first_cmd = false;
-			} else {
-				if ( out )
+				var value = this.prompt.value;
+				var out = this.cmdOut.innerHTML;
+
+				var text = ( shell.json.promptText ) ? shell.json.promptText : "[%n@%m %W] $ ";
+				text = shell.unescapePrompt ( text, shell.json.promptSequences );
+
+				this.window.removeChild ( this.prompt );
+				this.window.removeChild ( this.cmdOut );
+
+				if ( this.__first_cmd && this.prompt.value.length > 0 )
 				{
-					if ( out.match ( /^\s*<br.?>\s*/ ))
+					this.window.innerHTML += value + '<br/>' + out + text;
+					this.__first_cmd = false;
+				} else {
+					if ( out )
 					{
-						out = '';
+						if ( out.match ( /^\s*<br.?>\s*/ ))
+						{
+							out = '';
+						}
 					}
+
+					this.window.innerHTML += value + '<br/>' + out + text;
 				}
 
-				this.window.innerHTML += value + '<br/>' + out + text;
+				this.prompt = document.createElement ( 'input' );
+				this.prompt.setAttribute ( 'name', 'blashPrompt' );
+				this.prompt.setAttribute ( 'type', 'text' );
+				this.prompt.setAttribute ( 'class', 'promptInput' );
+				this.prompt.setAttribute ( 'autocomplete', 'off' );
+				this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' );
+				this.prompt.setAttribute ( 'onkeyup', 'this.focus()' );
+				this.prompt.setAttribute ( 'onblur', 'return false' );
+
+				this.cmdOut = document.createElement ( 'div' );
+				this.cmdOut.setAttribute ( 'id', 'blashCmdOut' );
+				this.cmdOut.setAttribute ( 'class', 'blashCmdOut' );
+				this.cmdOut.innerHTML = '<br/>';
+
+				this.window.appendChild ( this.prompt );
+				this.window.appendChild ( this.cmdOut );
+
+				if ( this.auto_prompt_focus )
+				{
+					this.prompt.focus();
+				}
 			}
-
-			this.prompt = document.createElement ( 'input' );
-			this.prompt.setAttribute ( 'name', 'blashPrompt' );
-			this.prompt.setAttribute ( 'type', 'text' );
-			this.prompt.setAttribute ( 'class', 'promptInput' );
-			this.prompt.setAttribute ( 'autocomplete', 'off' );
-			this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' );
-			this.prompt.setAttribute ( 'onkeyup', 'this.focus()' );
-			this.prompt.setAttribute ( 'onblur', 'return false' );
-
-			this.cmdOut = document.createElement ( 'div' );
-			this.cmdOut.setAttribute ( 'id', 'blashCmdOut' );
-			this.cmdOut.setAttribute ( 'class', 'blashCmdOut' );
-			this.cmdOut.innerHTML = '<br/>';
-
-			this.window.appendChild ( this.prompt );
-			this.window.appendChild ( this.cmdOut );
-			this.prompt.focus();
 		} else if ( key == 38 || key == 40 ) {
 			if ( key == 38 )
 			{
@@ -332,18 +345,24 @@ function blash ()
 				}
 			}
 
-			this.prompt.focus();
-			setTimeout ( function()  { shell.prompt.focus(); }, 1 );
-			
-			if ( this.prompt.setSelectionRange )
+			if ( this.auto_prompt_focus )
 			{
-				this.prompt.setSelectionRange ( this.prompt.value.length, this.prompt.value.length );
+				this.prompt.focus();
+				setTimeout ( function()  { shell.prompt.focus(); }, 1 );
+			
+				if ( this.prompt.setSelectionRange )
+				{
+					this.prompt.setSelectionRange ( this.prompt.value.length, this.prompt.value.length );
+				}
 			}
 
 			return false;
 		}
 
-		this.prompt.focus();
+		if ( this.auto_prompt_focus )
+		{
+			this.prompt.focus();
+		}
 	}
 
 	this.unescapePrompt = function ( prompt, sequences )
@@ -374,6 +393,54 @@ function blash ()
 		return prompt;
 	}
 
+	/**
+	 * \brief Refresh the shell prompt
+	 * \param clearTerm Set this variable as true if you want also to clear the terminal screen
+	 * \param clearOut Set this variable as true if you want to clear the latest output command
+	 */
+	this.refreshPrompt = function ( clearTerm, clearOut )
+	{
+		var value = this.prompt.value;
+		var out = this.cmdOut.innerHTML;
+		var text = ( this.json.promptText ) ? this.json.promptText : "[%n@%m %W] $ ";
+		text = this.unescapePrompt ( text, this.json.promptSequences );
+
+		this.window.removeChild ( this.prompt );
+		this.window.removeChild ( this.cmdOut );
+
+		if ( clearTerm )
+		{
+			this.window.innerHTML = '';
+		}
+		
+		if ( !clearOut )
+		{
+			if ( out.length > 0 )
+			{
+				var outDiv = document.createElement ( 'span' );
+				outDiv.innerHTML = '<br/>' + out + '<br/>' + text;
+				this.window.appendChild ( outDiv );
+			}
+		}
+
+		this.prompt = document.createElement ( 'input' );
+		this.prompt.setAttribute ( 'name', 'blashPrompt' );
+		this.prompt.setAttribute ( 'type', 'text' );
+		this.prompt.setAttribute ( 'class', 'promptInput' );
+		this.prompt.setAttribute ( 'autocomplete', 'off' );
+		this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' );
+		this.prompt.setAttribute ( 'onkeyup', 'this.focus()' );
+		this.prompt.setAttribute ( 'onblur', 'return false' );
+
+		this.cmdOut = document.createElement ( 'div' );
+		this.cmdOut.setAttribute ( 'id', 'blashCmdOut' );
+		this.cmdOut.setAttribute ( 'class', 'blashCmdOut' );
+
+		this.window.appendChild ( this.prompt );
+		this.window.appendChild ( this.cmdOut );
+		this.prompt.focus();
+	}
+
 	this.unescapePromptSequence = function ( prompt, sequence, text, default_text )
 	{
 		var re = new RegExp ( "([^\]?)" + sequence, "g" );
diff --git a/blash.json b/blash.json
index 327eb11..974ff6c 100644
--- a/blash.json
+++ b/blash.json
@@ -189,11 +189,13 @@
 		"cat",
 		"cd",
 		"clear",
+		"echo",
 		"eval",
 		"find",
 		"ls",
 		"man",
 		"pwd",
+		"useradd",
 		"whoami",
 	],
 }
diff --git a/commands/clear.json b/commands/clear.json
index c049011..5e9fff6 100644
--- a/commands/clear.json
+++ b/commands/clear.json
@@ -9,30 +9,7 @@
 	"action" : function ( arg )
 	{
 		var out = '';
-		var text = ( shell.json.promptText ) ? shell.json.promptText : "[%n@%m %W] $ ";
-		text = shell.unescapePrompt ( text, shell.json.promptSequences );
-
-		shell.window.removeChild ( shell.prompt );
-		shell.window.removeChild ( shell.cmdOut );
-		shell.window.innerHTML = '';
-
-		shell.prompt = document.createElement ( 'input' );
-		shell.prompt.setAttribute ( 'name', 'blashPrompt' );
-		shell.prompt.setAttribute ( 'type', 'text' );
-		shell.prompt.setAttribute ( 'class', 'promptInput' );
-		shell.prompt.setAttribute ( 'autocomplete', 'off' );
-		shell.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' );
-		shell.prompt.setAttribute ( 'onkeyup', 'this.focus()' );
-		shell.prompt.setAttribute ( 'onblur', 'return false' );
-
-		shell.cmdOut = document.createElement ( 'div' );
-		shell.cmdOut.setAttribute ( 'id', 'blashCmdOut' );
-		shell.cmdOut.setAttribute ( 'class', 'blashCmdOut' );
-
-		shell.window.appendChild ( shell.prompt );
-		shell.window.appendChild ( shell.cmdOut );
-		shell.prompt.focus();
-
+		shell.refreshPrompt ( true );
 		return out;
 	},
 }
diff --git a/commands/echo.json b/commands/echo.json
new file mode 100644
index 0000000..2acfa33
--- /dev/null
+++ b/commands/echo.json
@@ -0,0 +1,15 @@
+{
+	"name" : "echo",
+
+	"info" : {
+		"syntax" : "echo [text]",
+		"brief" : "Display a line of text",
+	},
+
+	"action" : function ( arg )
+	{
+		var out = arg + "<br/>\n";
+		return out;
+	},
+}
+
diff --git a/commands/useradd.json b/commands/useradd.json
new file mode 100644
index 0000000..c1dc323
--- /dev/null
+++ b/commands/useradd.json
@@ -0,0 +1,113 @@
+{
+	"name" : "useradd",
+
+	"info" : {
+		"syntax" : "useradd &lt;username&gt;",
+		"brief" : "Create a new user on the system",
+	},
+
+	"password" : '',
+	"repeatPassword" : '',
+
+	"keyPassword" : function ( e )
+	{
+		var evt = ( window.event ) ? window.event : e;
+		var key = ( evt.charCode ) ? evt.charCode : evt.keyCode;
+		var password = document.getElementsByName ( "password" )[0];
+		var repeatPassword = document.getElementsByName ( "repeatPassword" )[0];
+		var repeatPasswordText = document.getElementById ( "repeatPasswordText" );
+
+		if ( key == 13 && password.value.length > 0 )
+		{
+			repeatPassword.style.visibility = 'visible';
+			repeatPasswordText.style.visibility = 'visible';
+			repeatPassword.focus();
+		}
+	},
+
+	"keyRepeatPassword" : function ( e )
+	{
+		var evt = ( window.event ) ? window.event : e;
+		var key = ( evt.charCode ) ? evt.charCode : evt.keyCode;
+		var password = document.getElementsByName ( "password" )[0];
+		var repeatPassword = document.getElementsByName ( "repeatPassword" )[0];
+		var repeatPasswordText = document.getElementById ( "repeatPasswordText" );
+
+		if ( key == 13 && password.value.length > 0 )
+		{
+			if ( password.value != repeatPassword.value )
+			{
+				shell.cmdOut.innerHTML = 'The passwords do not match';
+			} else {
+				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 );
+
+				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 {
+							shell.cmdOut.innerHTML = '';
+						}
+
+						shell.refreshPrompt ( false, false );
+					}
+				}
+
+				http.send ( params );
+				shell.cmdOut.innerHTML = '';
+			}
+
+			shell.auto_prompt_focus = true;
+			shell.auto_prompt_refresh = true;
+			shell.refreshPrompt ( false, false );
+		}
+	},
+
+	"action" : function ( arg )
+	{
+		var out = '';
+
+		if ( !arg || arg.length == 0 )
+		{
+			return "Usage: " + this.name + " &lt;username&gt;<br/>\n";
+		}
+
+		shell.keyPassword = this.keyPassword;
+		shell.keyRepeatPassword = this.keyRepeatPassword;
+		shell.newuser = arg;
+
+		if ( shell.__first_cmd )
+		{
+			shell.cmdOut.innerHTML = '<br/>';
+			shell.__first_cmd = false;
+		}
+
+		shell.cmdOut.innerHTML += 'Password: <input type="password" ' +
+			'name="password" class="password" ' +
+			'onkeyup="shell.keyPassword ( event )">' +
+			'<br/><span id="repeatPasswordText" style="visibility: hidden">' +
+			'Repeat password: </span>' +
+			'<input type="password" name="repeatPassword" class="password" ' +
+			'style="visibility: hidden" onkeyup="shell.keyRepeatPassword ( event )"><br/>';
+
+		shell.auto_prompt_focus = false;
+		shell.auto_prompt_refresh = false;
+
+		this.password = document.getElementsByName ( "password" )[0];
+		this.password.focus();
+
+		return out;
+	},
+}
+
diff --git a/index.html b/index.html
index aad07ae..5c6f0b4 100644
--- a/index.html
+++ b/index.html
@@ -2,6 +2,7 @@
 	<head>
 		<title>Blash - An AJAX interactive shell emulator for web browsing</title>
 		<script type="text/javascript" language="javascript" src="blash.js"></script>
+		<script type="text/javascript" language="javascript" src="md5.js"></script>
 		<link rel="stylesheet" href="blash.css" type="text/css">
 	</head>
 
diff --git a/md5.js b/md5.js
new file mode 100644
index 0000000..e09c081
--- /dev/null
+++ b/md5.js
@@ -0,0 +1,209 @@
+/**
+*
+*  MD5 (Message-Digest Algorithm)
+*  http://www.webtoolkit.info/
+*
+**/
+ 
+function md5 (string)
+{
+ 
+	function RotateLeft(lValue, iShiftBits) {
+		return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
+	}
+ 
+	function AddUnsigned(lX,lY) {
+		var lX4,lY4,lX8,lY8,lResult;
+		lX8 = (lX & 0x80000000);
+		lY8 = (lY & 0x80000000);
+		lX4 = (lX & 0x40000000);
+		lY4 = (lY & 0x40000000);
+		lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
+		if (lX4 & lY4) {
+			return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
+		}
+		if (lX4 | lY4) {
+			if (lResult & 0x40000000) {
+				return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
+			} else {
+				return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
+			}
+		} else {
+			return (lResult ^ lX8 ^ lY8);
+		}
+ 	}
+ 
+ 	function F(x,y,z) { return (x & y) | ((~x) & z); }
+ 	function G(x,y,z) { return (x & z) | (y & (~z)); }
+ 	function H(x,y,z) { return (x ^ y ^ z); }
+	function I(x,y,z) { return (y ^ (x | (~z))); }
+ 
+	function FF(a,b,c,d,x,s,ac) {
+		a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
+		return AddUnsigned(RotateLeft(a, s), b);
+	};
+ 
+	function GG(a,b,c,d,x,s,ac) {
+		a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
+		return AddUnsigned(RotateLeft(a, s), b);
+	};
+ 
+	function HH(a,b,c,d,x,s,ac) {
+		a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
+		return AddUnsigned(RotateLeft(a, s), b);
+	};
+ 
+	function II(a,b,c,d,x,s,ac) {
+		a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
+		return AddUnsigned(RotateLeft(a, s), b);
+	};
+ 
+	function ConvertToWordArray(string) {
+		var lWordCount;
+		var lMessageLength = string.length;
+		var lNumberOfWords_temp1=lMessageLength + 8;
+		var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
+		var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
+		var lWordArray=Array(lNumberOfWords-1);
+		var lBytePosition = 0;
+		var lByteCount = 0;
+		while ( lByteCount < lMessageLength ) {
+			lWordCount = (lByteCount-(lByteCount % 4))/4;
+			lBytePosition = (lByteCount % 4)*8;
+			lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition));
+			lByteCount++;
+		}
+		lWordCount = (lByteCount-(lByteCount % 4))/4;
+		lBytePosition = (lByteCount % 4)*8;
+		lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
+		lWordArray[lNumberOfWords-2] = lMessageLength<<3;
+		lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
+		return lWordArray;
+	};
+ 
+	function WordToHex(lValue) {
+		var WordToHexValue="",WordToHexValue_temp="",lByte,lCount;
+		for (lCount = 0;lCount<=3;lCount++) {
+			lByte = (lValue>>>(lCount*8)) & 255;
+			WordToHexValue_temp = "0" + lByte.toString(16);
+			WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2);
+		}
+		return WordToHexValue;
+	};
+ 
+	function Utf8Encode(string) {
+		string = string.replace(/\r\n/g,"\n");
+		var utftext = "";
+ 
+		for (var n = 0; n < string.length; n++) {
+ 
+			var c = string.charCodeAt(n);
+ 
+			if (c < 128) {
+				utftext += String.fromCharCode(c);
+			}
+			else if((c > 127) && (c < 2048)) {
+				utftext += String.fromCharCode((c >> 6) | 192);
+				utftext += String.fromCharCode((c & 63) | 128);
+			}
+			else {
+				utftext += String.fromCharCode((c >> 12) | 224);
+				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+				utftext += String.fromCharCode((c & 63) | 128);
+			}
+ 
+		}
+ 
+		return utftext;
+	};
+ 
+	var x=Array();
+	var k,AA,BB,CC,DD,a,b,c,d;
+	var S11=7, S12=12, S13=17, S14=22;
+	var S21=5, S22=9 , S23=14, S24=20;
+	var S31=4, S32=11, S33=16, S34=23;
+	var S41=6, S42=10, S43=15, S44=21;
+ 
+	string = Utf8Encode(string);
+ 
+	x = ConvertToWordArray(string);
+ 
+	a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
+ 
+	for (k=0;k<x.length;k+=16) {
+		AA=a; BB=b; CC=c; DD=d;
+		a=FF(a,b,c,d,x[k+0], S11,0xD76AA478);
+		d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
+		c=FF(c,d,a,b,x[k+2], S13,0x242070DB);
+		b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
+		a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
+		d=FF(d,a,b,c,x[k+5], S12,0x4787C62A);
+		c=FF(c,d,a,b,x[k+6], S13,0xA8304613);
+		b=FF(b,c,d,a,x[k+7], S14,0xFD469501);
+		a=FF(a,b,c,d,x[k+8], S11,0x698098D8);
+		d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
+		c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
+		b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
+		a=FF(a,b,c,d,x[k+12],S11,0x6B901122);
+		d=FF(d,a,b,c,x[k+13],S12,0xFD987193);
+		c=FF(c,d,a,b,x[k+14],S13,0xA679438E);
+		b=FF(b,c,d,a,x[k+15],S14,0x49B40821);
+		a=GG(a,b,c,d,x[k+1], S21,0xF61E2562);
+		d=GG(d,a,b,c,x[k+6], S22,0xC040B340);
+		c=GG(c,d,a,b,x[k+11],S23,0x265E5A51);
+		b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
+		a=GG(a,b,c,d,x[k+5], S21,0xD62F105D);
+		d=GG(d,a,b,c,x[k+10],S22,0x2441453);
+		c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
+		b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
+		a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
+		d=GG(d,a,b,c,x[k+14],S22,0xC33707D6);
+		c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
+		b=GG(b,c,d,a,x[k+8], S24,0x455A14ED);
+		a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
+		d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
+		c=GG(c,d,a,b,x[k+7], S23,0x676F02D9);
+		b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
+		a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
+		d=HH(d,a,b,c,x[k+8], S32,0x8771F681);
+		c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
+		b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
+		a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
+		d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
+		c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
+		b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
+		a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
+		d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
+		c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
+		b=HH(b,c,d,a,x[k+6], S34,0x4881D05);
+		a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
+		d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
+		c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
+		b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
+		a=II(a,b,c,d,x[k+0], S41,0xF4292244);
+		d=II(d,a,b,c,x[k+7], S42,0x432AFF97);
+		c=II(c,d,a,b,x[k+14],S43,0xAB9423A7);
+		b=II(b,c,d,a,x[k+5], S44,0xFC93A039);
+		a=II(a,b,c,d,x[k+12],S41,0x655B59C3);
+		d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
+		c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
+		b=II(b,c,d,a,x[k+1], S44,0x85845DD1);
+		a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
+		d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
+		c=II(c,d,a,b,x[k+6], S43,0xA3014314);
+		b=II(b,c,d,a,x[k+13],S44,0x4E0811A1);
+		a=II(a,b,c,d,x[k+4], S41,0xF7537E82);
+		d=II(d,a,b,c,x[k+11],S42,0xBD3AF235);
+		c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
+		b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
+		a=AddUnsigned(a,AA);
+		b=AddUnsigned(b,BB);
+		c=AddUnsigned(c,CC);
+		d=AddUnsigned(d,DD);
+	}
+ 
+	var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d);
+ 
+	return temp.toLowerCase();
+}
+
diff --git a/modules/users/.userlist.php.swp b/modules/users/.userlist.php.swp
new file mode 100644
index 0000000000000000000000000000000000000000..225fe82e97e1262078188cb7964271ddf855b2d2
GIT binary patch
literal 12288
zcmYc?2=nw+FxN9?U|?VnU|@LsNYuCg0~5oYECz<8oW$hpoXqr$5|AWrT%MU%l3J8o
zT9S%e4M?UAVW56SNl8J9env@3esZyXQchxVhJJ2-N@-4Nv3_ZBY7vCY$t*6>E66AS
zX&%L+Aut*O<cC0MNt&(&FN3j>p@FiJqJpqcDEVfM>KqM$(GVC7fzc2c4S~@R7!85Z
z5Eu=C(GVDtAy87l$nc+mfq{vEfq{#Gfq@Z<hooml9X%QXqaiRF0;3@?8UmvsFd71*
zAut*OqaiRF0;3@?8UmvsfHedXQy3UR`571{@<ZnTL1O^F_!$^}@-r|z;b&l2!_UC5
zgr9+7Ha`QyEPe)tsr(EKQ=sa9@nJP`RB$u|MnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU
z1V%$(Gz11y2-w>(FhuzJSTiu#fR>yq<R#{&+A1X$rzj~DBo-IjDw$gtnwnXfr6wn(
z875nrrJ7k-nk1Q<Tbh`fr5GC<q$(+7<b$;6gD8EFMtwVEqjK_dNH+?}RgjhNb`a+k
z+cDVKSLEg>l%*CGXXfYGDjDh-C@G}oCFiGP=B3*zg@(B4S|}+Lmn7z;B<AGjrP?Z0
mrWPyN+cBtA<mM#j=ar=9l_=OM*x1-a`1&v~*w}+s)&l@NeS$Oq

literal 0
HcmV?d00001

diff --git a/modules/users/.users.php.swp b/modules/users/.users.php.swp
new file mode 100644
index 0000000000000000000000000000000000000000..21565a08a031df67544dafea0e404665a73514e1
GIT binary patch
literal 12288
zcmYc?2=nw+FxN9?U|?VnU|`tvNYr;K4-><kECz<8oW$hpoXqr$5|AWrT%MU%l3J8o
zT9S%e4M?UAVW56SNl8J9env@3esZyXQchxVhJJ2-N@-4Nv3_ZBY7vywE66AS=^VwQ
zAut*O6oo)(Nt&(&FN3j>p@FiJqJpqcC`HDNY90-N(GVC7fzc2c4S~@R7!85Z5Eu=C
z(GVDVAy87l$nc+mfq{vEfx(4=fq@Z<hn`PHT|62BqaiRF0;3@?8UmvsFd71*Aut*O
zqaiRF0;3@?8UmvsfGY$NQy3T|IT;vixghiZpfP}7{0s~~`571<@-r|T;%8tu$j`vA
zil2dD1wRABTz&?I+58L)v-lYp+W8q6TKO3mD)<=~!uc5(%=j4?O!*lY82K3({_-&}
zeBfhXc*DoQ@S2Z-VLKlK!)87PhB!V3hCn_B246k~1|L2KhF`o44BvPe7&h@TFf8R|
zU|7h@z_5UqfgyvJfgy#Lfx(2AfkB;@fkBy<fkBCvf#CxW1H&6028NA13=C^{7#ON~
z7#MPS7#K2m7#LD`7#Nay7#OU17#O&D7#MDIGcYXRW?-1l&A^b)&A^b&&A_0`&A_0*
z&A=eT&A=ed&A@Poi-BPS7X!n3E(Qi)E(Qh{E(QiCE(QiiE(QiWE=ag&gTe+^0FH`}
zhQMeDjE2By2#kinXb6mk!0-zJdpib(S_TGt1_*<bGpQ&wF&pep6cK9%PR@d&%)Al>
z_0ZzfA_XONJr&Se&b-9jR6TWt;?m^g)Z*f_(wv-1g~XJU)D#_sjQreGg_O*q)Z~)<
zqDqD0)Dne~d<7+akhngwcBL4lm^>wG1_n;fwB(%p;#36<1(mb{1x=8pY2`(kB~TF^
z1tlB%f{cQgyqLTgm5SV)<ovvn)VvY}TLl{%n+RW@m^>u~Jq3`Au3chrgs+c=rh=Y=
zQcPZiua7lIm%SZGi6+>tS_V!|&Z5+k(xN;CLy%Qa4=RP`B_`#hf*hNelA=(Ok*ZK!
zkeZyCmYJHO0P?erLTO%hUVeF=LTXV_ei7L1oSfARoSd0y3K|NE5ZBu(q~#Z+<|$|>
zsDm`+WEPizR=ld~D5#gKD`;wJg8ZwJms$>z)wN4ZNpUPGDauSL1^ZSV6iOhq(BJ}j
z3#1Sf-jIO7t+gPrxL93BK?OvY=NF|AQV%i{q#nEZ3bwESO-XUi$jnKB`A8jPE(0eg
zI2^$QYG}fOGXx_56%uobQWH}u6;dlQi%W{30SFF3Xb={c6eTAXrzYnXfYL%mZjP=U
z$aT>wnX%F8VE4xAD8Lh-f~F<|Bm&a%i$EGO6>Jp@tQAx;6>Joe^GoweK!R{n6f{9n
z+S&@>C;+=0e=-2aBPbn!+)%6#;p?N2mYI_ZbvH`HSLEg>*ec|umMa8j<`(3nM)>-;
z=A`C=5~&6_9AQZongDRx4hpq`qWrSVl++XjcucCpBUN1?vsfW7zeFKXp)4^cGesdI
zu{Z<WMFmBv>G8RVCCM3}NYjswOVq7$)QvLGwT#sV#W>ttO@*2oh2oN;9B_h#TcV(;
zplGXLY(yZWKyC#E4Jcw1k`wb3^7C>k6+k{s%*<0r&PXguOfE?+DpttM17|0Y2&gzv
zkA}M^K31K0$Hzll54RGMm%u@pl9{TYp`-*ZI#418u2|7lA+IziM?p;uDTlxWAtoXG
zZ>yjZALJSs>KYsptquw;^;l3zfk=5M3P5&%6@b#Nf_h>~in<j;HA8WECL{(_5|c|Z
z^YcKVS<AqQaB4LJxZr?E+d^Ha$-n>?LUsql6p%%kdC57YDXC~Bj5PxTxR_)B0HSvR
AK>z>%

literal 0
HcmV?d00001

diff --git a/modules/users/userlist.php b/modules/users/userlist.php
new file mode 100644
index 0000000..29108df
--- /dev/null
+++ b/modules/users/userlist.php
@@ -0,0 +1,10 @@
+<?php
+
+$xmlcontent = <<<XML
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<users>
+</users>
+
+XML;
+
+?>
diff --git a/modules/users/users.php b/modules/users/users.php
new file mode 100644
index 0000000..e381134
--- /dev/null
+++ b/modules/users/users.php
@@ -0,0 +1,68 @@
+<?php
+
+include 'userlist.php';
+$action = $_REQUEST['action'];
+
+if ( $action == null )
+{
+	die ("");
+}
+
+switch ( $action )
+{
+	case 'add':
+		$username = $_REQUEST['user'];
+		$password = $_REQUEST['pass'];
+
+		if ( !( $username != null && $password != null ))
+		{
+			die ("");
+		}
+
+		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;
+		}
+
+		if ( preg_match ( '/[^a-zA-Z0-9]/', $password ) || strlen ( $password ) != 32 )
+		{
+			print "The provided password '$password' is not a valid hash\n";
+			return 1;
+		}
+
+		if ( !( $xml = new SimpleXMLElement ( $xmlcontent )))
+		{
+			print "Unable to open the users XML file\n";
+			return 1;
+		}
+
+		for ( $i = 0; $i < count ( $xml->user ); $i++ )
+		{
+			if ( !strcasecmp ( $xml->user[$i]['name'], $username ))
+			{
+				print "The specified user already exists\n";
+				return 1;
+			}
+		}
+
+		$newuser = $xml->addChild ( 'user' );
+		$newuser->addAttribute ( 'name', $username );
+		$newuser->addAttribute ( 'pass', $password );
+		$newuser->addAttribute ( 'home', '/home/' . $username );
+
+		if ( !( $fp = fopen ( 'userlist.php', 'w' )))
+		{
+			print "Unable to add the specified user, unknown error\n";
+			return 1;
+		}
+
+		fwrite ( $fp, "<?php\n\n\$xmlcontent = <<<XML\n" . $xml->asXML() . "\nXML;\n\n?>\n" );
+		fclose ( $fp );
+
+		print 'User "'.$username.' successfully added, home directory set to "/home/'.$username."\"\n";
+		break;
+}
+
+?>
+