Clone from GitHub, continuing devel here...

master
Pentium44 2020-11-03 19:40:44 -08:00
commit a5440b04e5
9 changed files with 662 additions and 0 deletions

29
README.md Executable file
View File

@ -0,0 +1,29 @@
SVMM - Simple Virtual Machine Manager
----
A simple VM manager with bash backend that runs on flatfile databases. It requires
no setup (except setting properties in the config.php script). SVMM is released
under the CC-BY-NC-SA v3.0 unported.
SVMM was written by Chris Dorman, 2020 <https://cddo.cf>
Requirements
----
* PHP5+
* Qemu-KVM installed and configured for KVM
* Super user privleges
Setup
----
* Modify config.php to your needs
* Visit page to generate svmm_db for flat file user database
* Execute SVMM backend as SU: sudo ./start-svmm start
* Copy a fresh OS install of your choice in a qcow2 (or other format) image to svmm_db/disks/clean.img (THIS MUST BE DONE FOR THE SCRIPT TO COPY AND START A FRESH VM)
ChangeLog
----
9/24/2020 - v1.0
* Working PHP front end with user registeration and login
* Working bash back end for server management
* Allows each user to create 1 VM
* Allows user ability to start / stop VM
* PHP email validation via filter_var

15
config.php Normal file
View File

@ -0,0 +1,15 @@
<?php
///////
// SVMM - Simple VM Manager - For Qemu KVM
// (C) Chris Dorman, GPL v3 (2013-2020)
// https://github.com/Pentium44/SVMM
// Version: 1.0
///////
$svmmtitle = "FreeBox"; // SM title
$desc = "Simple, ad-free, yet flexible VPS hosting platform to the user; for the user! " . $svmmtitle . " is powered by SVMM.<br /><br />With a fresh account, you'll be able to create your own free VPS, and 1 is available per user."; // platform description
$domain = "vps.cddo.cf"; // where is SSB operating?
$version = "1.0"; // version
$maxvm = "100"; // max vm count
?>

78
functions.php Normal file
View File

@ -0,0 +1,78 @@
<?php
// SVMM - Simple VM Manager - for Qemu KVM
// (C) Chris Dorman, 2020
// License: CC-BY-NC-SA version 3.0
// http://github.com/Pentium44/SVMM
function loginForm() {
?>
<br />
<div class="login">
<a class="button" href="<?php echo $_SERVER['PHP_SELF']; ?>?forms=register">Register</a>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>?do=login" method="post">
<table><tr><td>
Username:</td><td> <input class="text" type="text" name="username"></td></tr><tr><td>
Password:</td><td> <input class="text" type="password" name="password"></td></tr></table>
<input style="padding: 2px;" class="text" type="submit" name="submitBtn" value="Login">
</form>
</div>
<?php
}
function changePassForm() {
?>
<br />
<div class="chgpass">
<form action="<?php echo $_SERVER['PHP_SELF']; ?>?do=changepass" method="post">
<table><tr><td>
Old password:</td><td> <input class="text" type="password" name="oldpass"></td></tr><tr><td>
Password:</td><td> <input class="text" type="password" name="password"></td></tr><tr><td>
Password Again:</td><td> <input class="text" type="password" name="password_again"></td></tr>
</table>
<input class="text" type="submit" name="submitBtn" value="Change">
</form>
</div>
<?php
}
/*function uploadForm() {
print <<<EOD
Upload
<table style="margin:auto;">
<form action="upload.php" method="post" enctype="multipart/form-data">
<tr>
<td>
<input type="file" name="file[]" id="file" multiple><br>
</td>
<td>
<input type="submit" name="submit" value="Upload">
</td>
</tr>
</form>
</table>
EOD;
}*/
function registerForm() {
?>
<br />
<div class="login">
<form action="<?php echo $_SERVER['PHP_SELF']; ?>?do=register" method="post">
<table><tr><td>
Username:</td><td> <input class="text" type="text" name="username"></td></tr><tr><td>
Full name:</td><td> <input class="text" type="text" name="fullname"></td></tr><tr><td>
Email:</td><td><input class="text" type="text" name="email"></td></tr><tr><td>
Password:</td><td> <input class="text" type="password" name="password"></td></tr><tr><td>
Password Again:</td><td> <input class="text" type="password" name="password-again"></td></tr><tr><td>
<input class="text" type="submit" name="submitBtn" value="Register">
</td></tr></table>
</form>
</div>
<?php
}
?>

319
index.php Normal file
View File

@ -0,0 +1,319 @@
<?php
// SVMM - Simple VM Manager - For Qemu KVM
// (C) Chris Dorman, 2020
// License: CC-BY-NC-SA version 3.0
// http://github.com/Pentium44/SVMM
session_start();
include "config.php";
include "functions.php";
// check if flatfile database location is populated
if(!file_exists("svmm_db"))
{
mkdir("svmm_db", 0777);
}
if(!file_exists("svmm_db/events"))
{
mkdir("svmm_db/events", 0777);
}
if(!file_exists("svmm_db/disks"))
{
mkdir("svmm_db/disks", 0777);
}
if(!file_exists("svmm_db/pids"))
{
mkdir("svmm_db/pids", 0777);
}
if(!file_exists("svmm_db/users"))
{
mkdir("svmm_db/users", 0777);
}
if(!file_exists("svmm_db/users/usercount"))
{
file_put_contents("svmm_db/users/usercount", "9");
}
$username = $_SESSION['svmm-user'];
?>
<!DOCTYPE html>
<html lang="en-us">
<head>
<title><?php echo $svmmtitle; ?></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=.55, shrink-to-fit=yes"><meta name="description" content="<?php echo htmlentities($svmmtitle) . " - " . $desc; ?>">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="maincontain">
<div id="navcontainer">
<div id="navbar"><!--
<?php if(isset($_SESSION['svmm-user']) && isset($_SESSION['svmm-pass'])) { ?>
--><a href="index.php">Create</a><!--
--><a href="?do=manage">Manage</a><!--
--><a href="?do=about">About</a><!--
--><a href="?do=logout">Logout</a><!--
<?php } else {?>
--><a href="?forms=login">Login</a><!--
--><a href="?do=about">About</a><!--
<?php } ?>
--></div>
</div>
<div class='contain'>
<div class='title'><?php echo $svmmtitle; ?></div>
<?php
if(isset($_GET['forms']))
{
$forms = $_GET['forms'];
$id = $_GET['pid'];
if($forms=="register") {
registerForm();
}
else if($forms=="login") {
loginForm();
}
else if($forms=="friendreq") {
friendReqForm();
}
else if($forms=="changepass") {
changePassForm();
}
else { echo "ERROR: Unknown form-name<br>"; }
}
else if(isset($_GET['notify']))
{
$notify = $_GET['notify'];
if($notify=="1") { echo "Error: User not found"; }
else if($notify=="2") { echo "Error: Incorrect password provided"; }
else if($notify=="3") { echo "Error: Please fill out all the text boxes"; }
else if($notify=="4") { echo "Error: The provided passwords did not match"; }
else if($notify=="5") { echo "Error: Special characters cannot be used in your username"; }
else if($notify=="6") { echo "Error: This username is already in use"; }
else { echo "Error: unknown error... this is quite unusual..."; }
}
else if(isset($_GET['do']))
{
$do = $_GET['do'];
// Server admin can just delete ssb_db
/*if($do=="clean")
{
if($_POST['password']!="" && $_POST['password']==$pw)
{
$db_content = glob("ssb_db/" . '*', GLOB_MARK);
foreach($db_content as $file)
{
unlink($file);
}
rmdir("ssb_db");
echo "Database Cleaned<br>";
}
else
{
echo "ERROR: Wrong Password<br>";
}
}*/
// grab session values and send friend request functions.
if($do=="create") {
if (!isset($_SESSION['svmm-user']) || !isset($_SESSION['svmm-pass'])) { loginForm(); } else {
include("svmm_db/users/$username.php");
if(!file_exists("svmm_db/disks/$userid.img")) {
if(!copy("svmm_db/disks/clean.img", "svmm_db/disks/$userid.img"))
{
echo "Error copying new disk image to user location... Please contact the system administrator!";
}
else
{
// Trigger event to start VM!
file_put_contents("svmm_db/events/$userid", "./machine start $userid");
echo "VM created! Refer to the user management panel for start / up info.";
}
} else {
echo "Error: VM exists, please click &quot;Manage&quot; to start / stop your VM or to download a disk backup.";
}
}
}
if($do=="start") {
if (!isset($_SESSION['svmm-user']) || !isset($_SESSION['svmm-pass'])) { loginForm(); } else {
include("svmm_db/users/$username.php");
if(file_exists("svmm_db/disks/$userid.img")) {
if(!file_exists("svmm_db/users/$userid.pid.statuscode")) {
echo "Pending: VM is pending creation, this process shouldn't take longer than 30 seconds...";
} else {
$vmstatus = file_get_contents("svmm_db/users/$userid.pid.statuscode");
if($vmstatus == "false") {
file_put_contents("svmm_db/events/$userid", "./machine start $userid");
header("Location: index.php?do=manage");
} else {
echo "VM already running...";
}
}
} else {
echo "ERROR: VM not found!";
}
}
}
if($do=="stop") {
if (!isset($_SESSION['svmm-user']) || !isset($_SESSION['svmm-pass'])) { loginForm(); } else {
include("svmm_db/users/$username.php");
if(file_exists("svmm_db/disks/$userid.img")) {
if(!file_exists("svmm_db/users/$userid.pid.statuscode")) {
echo "Pending: VM is pending creation, this process shouldn't take longer than 30 seconds...";
} else {
$vmstatus = file_get_contents("svmm_db/users/$userid.pid.statuscode");
if($vmstatus == "true") {
file_put_contents("svmm_db/events/$userid", "./machine stop $userid");
header("Location: index.php?do=manage");
} else {
echo "VM already stopped...";
}
}
} else {
echo "ERROR: VM not found!";
}
}
}
if($do=="manage") {
if (!isset($_SESSION['svmm-user']) || !isset($_SESSION['svmm-pass'])) { loginForm(); } else {
include("svmm_db/users/$username.php");
if(file_exists("svmm_db/disks/$userid.img")) {
if(!file_exists("svmm_db/users/$userid.pid.status")) {
echo "Pending: VM is pending creation, this process shouldn't take longer than 30 seconds...";
} else {
echo $username . "'s VM<br /> VM status: ";
$vmstatus = file_get_contents("svmm_db/users/$userid.pid.status");
echo $vmstatus;
echo "<br /><a href='index.php?do=start' class='button'>Start</a>&nbsp;<a href='index.php?do=stop' class='button'>Stop</a>";
echo "<br /><br />";
echo "<b>Connection information (Via SSH):</b><br />";
echo "<table><tr><td>IP/Port:</td><td> cddo.cf/" . $userid . "22</td></tr>";
echo "<tr><td style='padding-right: 30px;'>Default root password: </td><td>root</td></tr></table><br />";
echo "<b>Available ports for use:</b>";
echo "<table><tr><td style='padding-right:30px;'>Server side port</td><td>External port (viewable)</td></tr>";
echo "<tr><td>21</td><td>" . $userid . "21</td></tr>";
echo "<tr><td>22</td><td>" . $userid . "22</td></tr>";
echo "<tr><td>25565</td><td>" . $userid . "65</td></tr>";
echo "<tr><td>6666</td><td>" . $userid . "66</td></tr>";
echo "<tr><td>6667</td><td>" . $userid . "67</td></tr>";
echo "<tr><td>80</td><td>" . $userid . "80</td></tr>";
echo "</table>";
}
} else {
echo "ERROR: VM not found!";
}
}
}
if($do=="about")
{
echo "<h2>About</h2>";
echo $desc;
}
if($do=="login")
{
$username = $_POST['username'];
if(file_exists("svmm_db/users/$username.php")) {
include_once("svmm_db/users/$username.php");
if($user_password==sha1(md5($_POST['password']))) {
$pass = $user_password;
$user = $username;
$color = $user_color;
$_SESSION['svmm-user'] = $user;
$_SESSION['svmm-pass'] = $pass;
header("Location: index.php");
} else {
echo "Wrong password!";
}
} else {
echo "User $username not found!";
}
}
if($do=="logout")
{
$_SESSION['svmm-user'] = null;
$_SESSION['svmm-pass'] = null;
header("Location: index.php?forms=login");
}
if($do=="register")
{
if($_POST['username']!="" && $_POST['password']!="" && $_POST['password-again']!="" && $_POST['fullname']!="" && isset($_POST['email']) && $_POST['email']!="") {
if($_POST['password']==$_POST['password-again']) {
if(!preg_match('/[^a-z0-9]/i', $_POST['username'])) {
if(!file_exists("svmm_db/users/" . $_POST['username'] . ".php")) {
$vpscount = file_get_contents("svmm_db/users/usercount");
if($vpscount < $maxvm)
{
if(filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$vpscount = $vpscount + 1;
file_put_contents("svmm_db/users/usercount", $vpscount);
file_put_contents("svmm_db/users/" . stripslashes(htmlentities($_POST['username'])) . ".php", "<?php\n\$user_handle = \"" . stripslashes(htmlentities($_POST['username'])) . "\";\n\$user_password = \"" . sha1(md5($_POST['password'])) . "\";\n \$user_email = \"" . stripslashes(htmlentities($_POST['email'])) . "\"; \$user_fullname = \"" . stripslashes(htmlentities($_POST['fullname'])) . "\"; \$userid = \"" . $vpscount . "\";\n?>");
header("Location: index.php");
}
else
{
echo "ERROR: Email is invalid!";
}
}
else
{
echo "ERROR: VPS cap reached!";
}
} else {
header("Location: index.php?notify=6");
}
} else {
header("Location: index.php?notify=5");
}
} else {
header("Location: index.php?notify=4");
}
} else {
header("Location: index.php?notify=3");
}
}
}
else if (!isset($_SESSION['svmm-user']) || !isset($_SESSION['svmm-pass']))
{
loginForm();
}
else
{
include("svmm_db/users/$username.php");
if(!file_exists("svmm_db/disks/$userid.img"))
{
echo "<h3>Free VPS creation</h3>";
echo "<p>Each user will have the ability to create a VM, and will have a consistent uptime unless FreeBox ends up being disabled due to malicious users improperly using the virtual machines</p>";
echo "<ul><li>CPU: 10% of 1x Xeon E5649 core</li><li>RAM: 128MB dedicated</li><li>Disk: 10GB dedicated space</li><li>OS: Alpine GNU/Linux</li><li>Network: 50mbps down + 2mbps upload</li><li>Select available ports for server operation</li></ul>";
echo "<a href='index.php?do=create' class='button'>Create a VPS</a>";
}
else
{
echo "You've been assigned a VPS, click &quot;Manage&quot; for more information on your server.";
}
}
?>
<br /><br />
<center style="background-color: #555555; padding 3px;">Powered By SVMM <?php echo $version; ?></center>
</div>
</div> <!-- main contain -->
</body>
</html>

47
machine Executable file
View File

@ -0,0 +1,47 @@
#!/bin/bash
MAXLOAD=25
CMD="qemu-system-x86_64"
MEMS=138
case $1 in
status )
case $2 in
html )
if ps -p $(cat svmm_db/pids/$3.pid) > /dev/null
then
echo "<div style='display:inline;color:#00ff00;'>Running</div>"
else
echo "<div style='display:inline;color:#ff0000;'>Stopped</div>"
fi
;;
return )
if ps -p $(cat svmm_db/pids/$3.pid) > /dev/null
then
echo "1"
else
echo "0"
fi
;;
esac
;;
start )
$CMD -enable-kvm -daemonize -display none -hda svmm_db/disks/$2.img -m ${MEMS}M -net nic,model=e1000,vlan=0,vlan=1 -net user,vlan=0,vlan=1,hostfwd=tcp::${2}80-:80,hostfwd=tcp::${2}22-:22,hostfwd=tcp::${2}66-:6666,hostfwd=tcp::${2}65-:25665,hostfwd=tcp::${2}21-:21,hostfwd=tcp::${2}67-:6667 -pidfile svmm_db/pids/$2.pid
./setcpulimit $(cat svmm_db/pids/$2.pid) $MAXLOAD > /dev/null &
#./setkilltimer $(cat svmm_db/pids/$2.pid) $2 > /dev/null &
;;
stopall )
killall $CMD
;;
stop )
echo "Stopping VM $2"
kill -TERM $(cat svmm_db/pids/$2.pid)
echo "Stopped!";;
* )
echo "Usage: machine {start|status|stop|stopall} {_|html|return} [vm id]";;
esac

6
setcpulimit Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
BOOTSLEEPTIME=120
sleep $BOOTSLEEPTIME
cpulimit --pid $1 --limit $2 > /dev/null &

7
start-svmm Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
case $1 in
start ) ./svmm > /dev/null &;;
stop ) killall svmm;;
* ) echo "Usage: ./start-svmm [start|stop]";;
esac

118
style.css Normal file
View File

@ -0,0 +1,118 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto&family=Ubuntu&display=swap');
html, body {
background-color: #626262;
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
color: #e3e3e3;
margin: 0 auto;
font-size: 18px;
font-family: "Ubuntu", "Roboto", sans-serif;
}
.title {
font-size: 46px;
text-align: center;
padding: 8px;
}
#navbar {
margin: 0 auto;
/*width: 100%;*/
/*background-color: #ffffff;*/
top: 1px;
left: 1px;
padding-bottom: 0px;
}
#navcontainer {
width: 702px;
max-width: 702px;
min-width: 702px;
margin: 0 auto;
background-color: #ffffff;
}
#navbar a {
text-decoration: none;
font-family: "Ubuntu", "Roboto", sans-serif;
font-size: 28px;
text-align: center;
padding-top: 4px;
padding-bottom: 5px;
background-color: #ffffff;
color: #5577ff;
width: 125px;
display: inline-block;
}
#navbar a:hover {
background-color: #999999;
color: #323232;
}
.notifications {
background-color: #171717;
border-radius: 4px;
border: solid 1px #222222;
padding: 4px;
}
table { padding: 1px; }
tr, td { padding: 2px; }
textarea {
background-color: #222222;
border-radius: 10px;
border: 1px solid #323232;
font-family: "Roboto Sans", Ubuntu, sans-serif;
outline: none;
resize: none;
color: #d7d7d7;
width: 98%;
padding: 4px;
}
input, button, select, label {
background-color: #222222;
border: solid 1px #323232;
outline: none;
border-radius: 6px;
color: #d7d7d7;
padding: 4px;
font-size: 18px;
}
.button {
background-color: #222222;
border: solid 1px #323232;
outline: none;
font-size: 18px;
border-radius: 6px;
color: #d7d7d7;
margin: auto;
padding: 4px;
display: inline-flex;
}
a {
color: #5577ff;
text-decoration: none;
}
a:hover {
color: #aabbff;
text-decoration: none;
}
.contain {
background-color: #121212;
border: solid 1px #565656;
width: 690px;
max-width: 690px;
min-width: 690px;
margin: 0 auto;
padding: 5px;
}
.maincontain {
margin: 0 auto;
width: 702px;
}

43
svmm Executable file
View File

@ -0,0 +1,43 @@
#!/bin/sh
# SVMM event manager
# Chris Dorman (C) 2020
wrkdir=`pwd`
events="svmm_db/events"
pids="svmm_db/pids"
while true
do
cd $wrkdir/$events
for x in *
do
if [ -f "$x" ]; then
execcmd=`cat $x`
rm $x
cd $wrkdir
`$execcmd`
cd $events
fi
done
cd $wrkdir/$pids
for y in *
do
if [ -f "$y" ]; then
if ps -p $(cat $y) > /dev/null
then
cd $wrkdir/svmm_db/users
echo "<div style='display:inline;color:#00ff00;'>Running</div>" > $y.status
echo -n "true" > $y.statuscode
else
cd $wrkdir/svmm_db/users
echo "<div style='display:inline;color:#ff0000;'>Stopped</div>" > $y.status
echo -n "false" > $y.statuscode
fi
cd $wrkdir/$pids
fi
done
sleep 5
done