*basic admin stuff is there
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 15 Jul 2007 16:59:17 +0000 (16:59 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sun, 15 Jul 2007 16:59:17 +0000 (16:59 +0000)
*started machine interface
*session part of DB scheme is there

git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@13 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

15 files changed:
doc/index.html
doc/prog_protocol.html [new file with mode: 0644]
src/mainwindow.cpp [new file with mode: 0644]
src/mainwindow.h
src/smoke.pro
www/admin.php
www/config.php.template
www/inc/db.php
www/inc/db_mysql.php
www/inc/db_scheme.php
www/inc/session.php [new file with mode: 0644]
www/index.php
www/loader.php
www/loader_nonadmin.php [moved from www/loader2.php with 100% similarity]
www/machine.php [new file with mode: 0644]

index 06a6529..d3b0f1e 100644 (file)
@@ -27,6 +27,10 @@ to be written:
 
 to be written
 
+<ul>
+<li><a href="prog_protocol.html">Protocol Documentation</a></li>
+</ul>
+
 
 </body>
 </html>
\ No newline at end of file
diff --git a/doc/prog_protocol.html b/doc/prog_protocol.html
new file mode 100644 (file)
index 0000000..857a368
--- /dev/null
@@ -0,0 +1,111 @@
+<html>
+<title>Magic Smoke Protocol Documentation</title>
+<body>
+<h1>Magic Smoke Protocol Documentation</h1>
+
+The Magic Smoke Protocol is used between the Magic Smoke Server and Client. It is based on HTTP and XML. Only POST requests are allowed.<p>
+
+Each request must have a "x-magicsmoke-request=..." header. The actual request data is sent as POST-data. Except for the <tt>serverinfo</tt> and <tt>startsession</tt> requests all requests must also carry a "x-magicsmoke-session" header.
+
+<h2>HTTP Headers</h2>
+
+Part of the data is transmitted in headers. This section lists all possible headers used by Magic Smoke.
+
+<h3>Client Request Headers</h3>
+
+<table frame="1" border="1">
+<tr><td>x-magicsmoke-request</td><td>The request that is to be executed by the server. This header is mandatory for all requests.</td></tr>
+<tr><td>x-magicsmoke-session</td><td>The session ID of this connection. This header is mandatory for all requests except <tt>serverinfo</tt> and <tt>startsession</tt>.</td></tr>
+</table>
+
+<h3>Server Response Headers</h3>
+
+<table frame="1" border="1">
+<tr><td>x-magicsmoke-status</td><td>The status of the request execution. See table below for details</td></tr>
+</table><p>
+
+Possible status codes are:
+<table frame="1" border="1">
+<tr><td><i>(missing)</i></td><td>If the whole header is missing or contains an unknown value, this should be treated as if it contained "Error" (see below).</td></tr>
+<tr><td>Ok</td><td>The request went ok and the actual data comes as response body.</td></tr>
+<tr><td>Error</td><td>Some unspecified error occured. The response body might contain some detailed human readable information.</td></tr>
+<tr><td>NonPost</td><td>The HTTP method was not POST. The body is a simple HTML page explaining to the user that browsers are not meant to use this page.</td></tr>
+<tr><td>Unauthenticated</td><td>The session ID does not exist, authentication failed or the session expired.</td></tr>
+<tr><td>InvalidRequest</td><td>The request was not understood. There was probably a mismatch in client and server version.</td></tr>
+<tr><td>SyntaxError</td><td>There was a syntactical error in the request data. Some details might follow in the response body.</td></tr>
+</table>
+
+<h2>Server Info</h2>
+
+A <tt>serverinfo</tt>-request can be sent by any client in order to get basic information
+about the server.<p>
+
+The server replies with an XML document that contains the most important information:
+<pre>
+&lt;Info>
+ &lt;ServerVersion proto="protocol-version">server-version-number&lt;/ServerVersion>
+ &lt;AuthAlgorithm>hash-algo&lt;/AuthAlgorithm>
+&lt;/Info>
+</pre>
+
+The <tt>proto</tt> argument of the ServerVersion tag returns the protocol version, which is used by the client to check whether it is compatible with the server. It consists of two blocks of four hex-digits each, separated by a space. The first block is the lowest protocol version understood by the server, while the second block contains the current protocol version implemented by the server.<p>
+
+The server version number in the ServerVersion tags text is a the software version itself. The hash-algorithm values are described below in the authentication protocol section.<p>
+
+The protocol version described in this document is <tt>0000</tt>.
+
+<h2>Authentication protocol</h2>
+
+First the client requests the hash-algorithm from the server. Possible
+algorithms are:
+
+<table frame="1" border="1">
+<tr><td>md5, sha1, sha256</td><td>use the hash algorithm directly, the returned value is calculated by first concatenating challenge and password/hostkey and then hashing it</td></tr>
+<tr><td>hmac-*</td><td>use the same algorithm in HMAC mode with the challenge as data and the password/hostkey as key</td></tr>
+</table>
+
+<h3>Step 1: Start a Session</h3>
+
+The authentication handshake is started with the client asking for a new session using a <tt>startsession</tt>-request. The post data of this request should consist of at least 128 random bits (base64 or another ASCII encoding) which are used by the server to calculate a session ID.
+
+The server responds with a session object:
+<pre>
+&lt;SessionStart>
+ &lt;ID>session-id-string&lt;/ID>
+ &lt;HostChallenge>host-challenge-string&lt;/HostChallenge>
+ &lt;UserChallenge>user-challenge-string&lt;/UserChallenge>
+ &lt;Timeout>seconds-till-session-timeout&lt;/Timeout>
+&lt;/SessionStart>
+</pre>
+
+The challenge strings are derived from some internal function and the clock. By no means they are meant to be secure against all kinds of attack. The challenge-response-protocol is only supposed to avoid sending the passwords in plain text over the wire.<p>
+
+The timeout of the temporary session is usually 5 minutes (300s).
+
+<h3>Step 2: Authenticating the Session</h3>
+
+This is done using a <tt>sessionauth</tt> request. The session ID header must be set.<p>
+
+The client sends its authentication data as XML:
+<pre>
+&lt;SessionAuth>
+ &lt;HostName>host-name&lt;/HostName>
+ &lt;HostAuth>host-authentication-data&lt;/HostAuth>
+ &lt;UserName>user-name&lt;/UserName>
+ &lt;UserAuth>user-authentication-data&lt;/UserAuth>
+&lt;/SessionAuth>
+</pre>
+
+The authentication data is calculated using the hash-function mandated by the server. The HostAuth item is calculated using the HostChallenge and the hosts key. The UserAuth item is calculated using the UserChallenge and the users password. Both *Auth values are hexadecimal-encoded.<p>
+
+The result one single numeric item in the body that states the new session timeout in seconds (0 if the request failed). The status is "Ok" or "Unauthenticated" - in the latter case the session ID is deleted and the client needs to start with a <tt>startsession</tt> request again if it wants to retry.<p>
+
+A result of "Unauthenticated" can have multiple reasons: the timeout of the temporary session expired before the request was received, the authentication of the user failed, the user is not allowed to connect from this or an anonymous host, or the authentication of the host failed and the user is not allowed to connect from an anonymous host.
+
+<h3>Step n: Closing the Session</h3>
+
+This is done with a <tt>sessionclose</tt> request. Neither request nor response contain a body.<p>
+
+This request always yields an "Ok" status response regardless of whether the session ID was still valid or not.
+
+<h2>Basic Requests</h2>
\ No newline at end of file
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
new file mode 100644 (file)
index 0000000..427db33
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// C++ Implementation: mainwindow
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "mainwindow.h"
+
+#include <QHttp>
+#include <QFile>
+#include <QByteArray>
+#include <QMenuBar>
+#include <QMenu>
+
+MMainWindow::MMainWindow()
+{
+       QMenuBar*mb=menuBar();
+       QMenu*m=mb->addMenu("&File");
+       m->addAction("&Test",this,SLOT(testrequest()));
+       m->addSeparator();
+       m->addAction("&Close Session",this,SLOT(close()));
+}
+
+void MMainWindow::testrequest()
+{
+       req=new QHttp("localhost");
+       connect(req,SIGNAL(requestFinished(int,bool)),this,SLOT(trfin(int,bool)));
+       QHttpRequestHeader hrh("POST","/~konrad/smoke/machine.php");
+       hrh.setValue("Host","localhost");
+       hrh.setValue("X-MagicSmoke-Request","testdueluEhue");
+       QByteArray tdata("blah\nschwafel\r\nseier");
+       hrh.setContentLength(tdata.size());
+       hrh.setContentType("text/x-magicsmoke");
+       qDebug("Requesting data with:\n%s",hrh.toString().toAscii().data());
+       req->request(hrh,tdata);
+}
+
+void MMainWindow::trfin(int id,bool err)
+{
+       qDebug("Received Request finish for ID=%i Status=%s",id,err?"Error":"Ok");
+       if(err){
+               qDebug("HTTP Error: %s",req->errorString().toAscii().data());
+       }else{
+               QHttpResponseHeader hrh=req->lastResponse();
+               QByteArray data=req->readAll();
+               qDebug("HTTP Response Headers:\n%s",hrh.toString().toAscii().data());
+               QFile fd("rsp"+QString::number(id)+".html");
+               fd.open(QIODevice::WriteOnly);
+               fd.write(data);
+               fd.close();
+       }
+}
index b453951..8f187f4 100644 (file)
 
 #include <QMainWindow>
 
+class QHttp;
+
 class MMainWindow:public QMainWindow
 {
+       Q_OBJECT
+       public:
+               MMainWindow();
+       public slots:
+               void testrequest();
+               void trfin(int,bool);
+       private:
+               QHttp*req;
 };
 
 #endif
index ca731a1..037800c 100644 (file)
@@ -16,7 +16,8 @@ MSVERSION = "0.1 alpha"
 
 SOURCES = \
        main.cpp \
-       keygen.cpp
+       keygen.cpp \
+       mainwindow.cpp
 HEADERS = \
        keygen.h \
        mainwindow.h
index b0904ee..9964913 100644 (file)
@@ -13,4 +13,78 @@ if(!$db->checkAdmin()){
 ?>
 <h1>Magic Smoke Admin Utility</h1>
 
-<h2>Checking DB</h2>
\ No newline at end of file
+
+
+<h2>Checking DB</h2>
+
+<?
+if(isset($_GET["CreateDB"])){
+       print("Creating Database...<p>");
+       $db->createDb();
+}
+?>
+
+<?
+if($db->canUseDb()){
+?>
+Database exists and is usable.
+<?
+}else{
+?>
+Database is not usable. Create?<br>
+<form action="admin.php" method="GET">
+<input type="submit" value="Yes, Create DB now." name="CreateDB"/>
+</form>
+<?
+       exit();
+}
+?>
+
+
+<h2>Checking for Admin Users</h2>
+
+<?
+do{
+if(isset($_POST["adminuser"])&&isset($_POST["adminpwd1"])&&isset($_POST["adminpwd2"])){
+       //do passwords match?
+       if($_POST["adminpwd1"]==""){
+               print("Error: Cannot create user with empty password!<p>");
+               break;
+       }
+       if($_POST["adminpwd1"]!=$_POST["adminpwd2"]){
+               print("Error: Passwords do not match.<p>");
+               break;
+       }
+       //does user exist?
+       $un=$_POST["adminuser"];
+       $usr=$db->select("users","uname","uname='".addslashes($un)."'");
+       if(count($usr)>0){
+               print("Error: User already exists.<p>");
+               break;
+       }
+       //create
+       $db->insert("users",array("uname"=>$un,"passwd"=>$_POST["adminpwd1"]));
+       $db->insert("userrole",array("uname"=>$un,"role"=>"_admin"));
+}
+}while(0);
+?>
+
+List of Admins:
+<ul>
+<?
+$admlst=$db->select("userrole","uname","role='_admin'");
+for($i=0;$i<count($admlst);$i++){
+       print("<li>".$admlst[$i][0]."</li>");
+}
+?>
+</ul><p>
+
+<b>Create new Admin User:</b><br>
+<form action="admin.php" method="POST">
+<table>
+<tr><td>Username:</td><td><input type="text" name="adminuser"></td></tr>
+<tr><td>Password:</td><td><input type="password" name="adminpwd1"></td></tr>
+<tr><td>Repeat Password:</td><td><input type="password" name="adminpwd2"></td></tr>
+</table>
+<input type="submit" value="Create">
+</form>
\ No newline at end of file
index e653217..add9314 100644 (file)
@@ -1,5 +1,48 @@
 <?
+///////////////////////////////////////////////////
+// MAGIC-SMOKE CONFIGURATION FILE
+//
+// see the documentation on how to make settings
+
 //Template directory
 $template="./template/de/";
-//TODO: storage config
+
+
+///////////
+//Chose a DB engine
+
+////
+//MySQL
+
+// create engine: server, user, password
+$db = new MysqlEngine("localhost","smoke","");
+// set database name
+$db->setDbName("smoke");
+// set table-prefix (optional)
+$db->setPrefix("smoke_");
+
+
+//use this for DB creation and upgrading, comment it out otherwise
+//change the passcode before using this on a production system!!!
+$db->setAdminPassCode("Admin","SmokeInMyEye");
+//set this to one of the supported MySQL storage engines for DB creation
+$db->setStorageEngine("InnoDB");
+
+
+////////////
+//Dedicated Client Configuration
+
+//Authentication algorithm
+// possible: md5, sha1, sha256, hmac-md5, hmac-sha1, hmac-sha256
+$ClientAuthAlgo="hmac-sha1";
+//hash algorithm library -- the PHP extension/module used for calculation
+// possible: string (md5, sha1 only), hash, mhash
+$HashLib="hash";
+
+//Initial timeout from start of session request to session authentication
+// usually 300s (5min) is a good value
+$ClientAuthTimeout=300;
+//Authenticated session timeout - how long an authenticated session lasts
+// this should usually be a few hours (3600s per hour)
+$ClientSessionTimeout=2*3600;
 ?>
\ No newline at end of file
index b4bf6e0..adad151 100644 (file)
@@ -39,31 +39,41 @@ abstract class DbEngine
        public function needVersion(){return "00.01";}
        
        /**returns whether the table exists; must be implemented by driver*/
-       protected abstract function haveTable($tablename);
+       public abstract function haveTable($tablename);
        
        /**begins a transaction; must be implemented by driver*/
-       protected abstract function beginTransaction();
+       public abstract function beginTransaction();
        
        /**ends a transaction successfully; must be implemented by driver; returns true on success*/
-       protected abstract function commitTransaction();
+       public abstract function commitTransaction();
        
        /**ends a transaction with a rollback; must be implemented by driver; returns true on success*/
-       protected abstract function rollbackTransaction();
+       public abstract function rollbackTransaction();
        
        /**gets some data from the database; $table is the name of the table, $cols is the list of columns to return or "*" for all, $where is the where clause of the SQL-statement; returns array of rows, which are in *_fetch_array format; returns false on error*/
-       protected abstract function select($table,$cols,$where);
+       public abstract function select($table,$cols,$where);
        
-       /**creates a table; the argument is an array of the form "col-name" => array("col-type", "flags"...); use sqlCreate() etc. to create the actual statement*/
+       /**insert values into a table*/
+       public abstract function insert($table,array $values);
+       
+       /**creates a table; the argument is an array of the form "col-name" => array("col-type", "flags"...); use sqlCreateTable() etc. to create the actual statement*/
        protected abstract function createTable($tablename,$table);
        
+       /**transform an internally used table name to the actual table name in the DB; the default implementation returns exactly what it gets*/
+       protected function tableName($tname){return $tname;}
+       
        /**returns the correct type name for the required abstract data type;
        types that must be understood are: int32 (INTEGER), int64 (LONG INTEGER), autoint32 (auto-incrementing int), autoint64, string:$length (text up to 255 chars, length is optional, default is 255; VARCHAR($length)), text (unlimited text)*/
        protected function dataType($type)
        {
                if($type=="int32")return "INTEGER";
                if($type=="int64")return "LONG INTEGER";
-               if(strncmp(7,$type,"string:")){
-                       return "VARCHAR("."??".")";
+               $tpa=explode(":",$type);
+               if($tpa[0]=="string"){
+                       if(isset($tpa[1]))
+                               return "VARCHAR(".$tpa[1].")";
+                       else
+                               return "VARCHAR(255)";
                }
                return false;
        }
@@ -74,13 +84,82 @@ abstract class DbEngine
        {
                if($flag=="primarykey")return "PRIMARY KEY";
                if($flag=="notnull")return "NOT NULL";
-               if($flag=="unique")return "NOT NULL,UNIQUE";
+               if($flag=="unique")return "NOT NULL UNIQUE";
                if($flag=="index")return "INDEX";
+               $tpa=explode(":",$flag);
+               if($tpa[0]=="foreignkey"){
+                       if(count($tpa)<3)
+                               return false;
+                       return "REFERENCES $tpa[1]($tpa[2])";
+               }
+               if($tpa[0]=="defaultint"){
+                       if(count($tpa)<2)
+                               return "DEFAULT NULL";
+                       return "DEFAULT $tpa[1]";
+               }
+               if($tpa[0]=="defaultstr"){
+                       if(count($tpa)<2)
+                               return "DEFAULT NULL";
+                       return "DEFAULT '".addslashes($tpa[1])."'";
+               }
        }
        
        /**creates a SQL92 statement for creating a table*/
        protected function sqlCreateTable($tablename,$table)
        {
+               $ret="CREATE TABLE ".$this->tableName($tablename)." (";
+               $cm="";
+               reset($table);
+               while(list($col,$def)=each($table)){
+                       $ret.=$cm;$cm=",";
+                       //column name
+                       $ret.=$col." ";
+                       //get type
+                       $ret.=$this->dataType($def[0])." ";
+                       //get flags
+                       for($i=0;$i<count($def);$i++)
+                               $ret.=$this->columnFlag($def[$i])." ";
+               }
+               $ret.=")";
+               return $ret;
+       }
+       
+       /**creates a SQL92 statement for inserts*/
+       protected function sqlInsert($table,array $values)
+       {
+               global $dbScheme;
+               $ret="INSERT INTO ".$this->tableName($table)." (";
+               reset($values);
+               $cm="";
+               $val=") VALUES (";
+               while(list($k,$v)=each($values)){
+                       $ret.=$cm;$val.=$cm;$cm=",";
+                       //append column name
+                       $ret.=$k;
+                       //append value
+                       if($dbScheme->isIntColumn($table,$k))
+                               $val.=$this->escapeInt($v);
+                       else
+                       if($dbScheme->isStringColumn($table,$k))
+                               $val.=$this->escapeString($v);
+                       else
+                               //don't know how to escape it...
+                               $val.="NULL";
+               }
+               $ret.=$val.")";
+               return $ret;
+       }
+       
+       /**escapes integers; the default implementation just makes sure it is an int*/
+       protected function escapeInt($i)
+       {
+               return $i + 0;
+       }
+       
+       /**escapes strings; the default uses addslashes and encloses the value in ''*/
+       protected function escapeString($s)
+       {
+               return "'".addslashes($s)."'";
        }
        
        /**returns a configuration setting*/
@@ -88,6 +167,7 @@ abstract class DbEngine
        {
                $mar=$this->select("config","cval","ckey='".addslashes($key)."'");
                if(count($mar)>0)return $mar[0][0];
+               return false;
        }
        
        /**tries to find out whether the connected DB version is usable*/
@@ -95,8 +175,34 @@ abstract class DbEngine
        {
                if(!$this->haveTable("config"))
                        return false;
-               return getConfig("MagicSmokeVersion")==$this->needVersion();
+               return $this->getConfig("MagicSmokeVersion")==$this->needVersion();
        }
+       
+       /**creates the database, used by admin.php only!!*/
+       public function createDb()
+       {
+               global $dbScheme;
+               $this->beginTransaction();
+               //iterate DB schema and create tables
+               $tabs=$dbScheme->tableNames();
+               for($i=0;$i<count($tabs);$i++){
+                       if(!$this->createTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))){
+                               print("DB Error: ".$this->lastError());
+                               $this->rollbackTransaction();
+                               die("Unable to create database.");
+                       }
+               }
+               //insert some defaults
+               $this->insert("config",array("ckey"=>"MagicSmokeVersion","cval"=>$this->needVersion()));
+               $this->insert("host",array("hostname"=>"_any"));
+               $this->insert("host",array("hostname"=>"_anon"));
+               $this->insert("host",array("hostname"=>"_online"));
+               //close transaction
+               $this->commitTransaction();
+       }
+       
+       /**returns the error string of the last operation*/
+       public abstract function lastError();
 };
 
 ?>
\ No newline at end of file
index 7452bf2..0032133 100644 (file)
@@ -46,40 +46,82 @@ class MysqlEngine extends DbEngine
                        die("Unable to select database \"$this->dbname\". Giving up.");
        }
        
-       protected function haveTable($tnm)
+       public function haveTable($tnm)
        {
-               $res=mysql_query("select * from ".$this->prefix.$tnm." where 1=2",$this->dbhdl);
+               $res=mysql_query("select * from ".$this->tableName($tnm)." where 1=2",$this->dbhdl);
                if($res===false)return false;
                mysql_free_result($res);
                return true;
        }
-       protected function beginTransaction()
+       public function beginTransaction()
        {
-               mysql_query("begin transaction");
+               return mysql_query("BEGIN");
        }
        
-       protected function commitTransaction()
+       public function commitTransaction()
        {
-               return mysql_query("commit transaction");
+               return mysql_query("COMMIT");
        }
        
-       protected function rollbackTransaction()
+       public function rollbackTransaction()
        {
-               return mysql_query("rollback transaction");
+               return mysql_query("ROLLBACK");
        }
        
-       protected function select($table,$cols,$where)
+       public function select($table,$cols,$where)
        {
-               $res=mysql_query("select $cols from ".$this->prefix.$table." where ".$where);
+               $res=mysql_query("SELECT $cols FROM ".$this->tableName($table)." WHERE ".$where);
                if($res===false)return false;
                $nr=mysql_num_rows($res);
                $ret=array();
-               for($i=0;$i<$max;$i++){
+               for($i=0;$i<$nr;$i++){
                        $ret[]=mysql_fetch_array($res,MYSQL_BOTH);
                }
                mysql_free_result($res);
                return $ret;
        }
        
-       protected function createTable($tn,$t){}
+       protected function createTable($tn,$t)
+       {
+               return mysql_query($this->sqlCreateTable($tn,$t)." engine=".$this->engine);
+       }
+       
+       protected function tableName($tn)
+       {
+               return $this->prefix.$tn;
+       }
+       
+       protected function dataType($type)
+       {
+               if($type=="int32")return "INT";
+               if($type=="int64")return "BIGINT";
+               if($type=="autoint32")return "INT AUTO_INCREMENT";
+               if($type=="autoint64")return "BIGINT AUTO_INCREMENT";
+               if($type=="text")return "TEXT";
+               $tpa=explode(":",$type);
+               if($tpa[0]=="string"){
+                       if(isset($tpa[1]))
+                               return "VARCHAR(".$tpa[1].")";
+                       else
+                               return "VARCHAR(255)";
+               }
+               //fallback to SQL standard
+               return parent::dataType($type);
+       }
+       
+       protected function columnFlag($flag)
+       {
+               //FIXME: currently MySQL does not mark columns for indexing, since the syntax is somewhat different --> this needs to be fixed!
+               if($flag=="index")return "";
+       }
+       
+       public function insert($table,array $values)
+       {
+               return mysql_query($this->sqlInsert($table,$values));
+       }
+       
+       public function lastError()
+       {
+               return mysql_error();
+       }
 };
\ No newline at end of file
index e782422..41d0621 100644 (file)
@@ -3,6 +3,18 @@ class DbScheme {
        private static $scheme;
        function __construct()
        {
+               //configuration
+               $this->scheme["config"]=array(
+                       "ckey"=>array("string:32","primarykey"),
+                       "cval"=>array("string:32")
+               );
+               //clients
+               $this->scheme["host"]=array(
+                       "hostname"=>array("string:64","primarykey"),
+                       //if hostkey is NULL it is a special host (_any, _anon, _online)
+                       "hostkey"=>array("string")
+               );
+               //users
                $this->scheme["users"]=array(
                        "uname" => array("string:64","primarykey"),
                        "passwd" => array("string","notnull")
@@ -11,6 +23,90 @@ class DbScheme {
                        "uname" =>array("string:64","notnull","foreignkey:users:uname","index"),
                        "role" =>array("string:32","notnull")
                );
+               $this->scheme["userhosts"]=array(
+                       "uname" => array("string:64","notnull","foreignkey:users:uname","index"),
+                       "host" => array("string:64","notnull","foreignkey:host:hostname")
+               );
+               //sessions
+               $this->scheme["session"]=array(
+                       "sessionid" => array("string:64","primarykey"),
+                       //if empty: not authenticated
+                       "user"=>array("string:64"),
+                       //emptied after authentication:
+                       "hchallenge"=>array("string:64"),
+                       "uchallenge"=>array("string:64"),
+                       //unix timestamp at which to delete this session
+                       // this needs to change to 64-bit int in 2038
+                       "timeout"=>array("int32","notnull")
+               );
+       }
+       
+       /**return the tables to be created in order*/
+       public function tableNames()
+       {
+               return array_keys($this->scheme);
+       }
+       
+       /**return the full definition of a table, or false if it does not exist*/
+       public function tableDefinition($tab)
+       {
+               if(!isset($this->scheme[$tab]))
+                       return false;
+               return $this->scheme[$tab];
+       }
+       
+       /**return the names of all columns of a table, or false if the table does not exist*/
+       public function tableColumns($tab)
+       {
+               if(!isset($this->scheme[$tab]))
+                       return false;
+               return array_keys($this->scheme[$tab]);
+       }
+       
+       /**return the type of a column, or false if it does not exist*/
+       public function columnType($tab,$col)
+       {
+               if(!isset($this->scheme[$tab][$col]))
+                       return false;
+               return $this->scheme[$tab][$col][0];
+       }
+       
+       /**return the flags of a column, empty array if no flags are set, or false if the column does not exist*/
+       public function columnFlags($tab,$col)
+       {
+               if(!isset($this->scheme[$tab][$col]))
+                       return false;
+               $tmp=$this->scheme[$tab][$col];
+               unset($tmp[0]);
+               return array_values($tmp);
+       }
+       
+       /**returns true if the given column is of an integer type*/
+       public function isIntColumn($tab,$col)
+       {
+               if(!isset($this->scheme[$tab][$col]))
+                       return false;
+               $tpa=explode(":",$this->scheme[$tab][$col][0]);
+               switch($tpa[0]){
+                       case "int32":case "autoint32":case "int64":case "autoint64":
+                               return true;
+                       default:
+                               return false;
+               }
+       }
+       
+       /**returns true if the given column is of a string type*/
+       public function isStringColumn($tab,$col)
+       {
+               if(!isset($this->scheme[$tab][$col]))
+                       return false;
+               $tpa=explode(":",$this->scheme[$tab][$col][0]);
+               switch($tpa[0]){
+                       case "string":case "text":
+                               return true;
+                       default:
+                               return false;
+               }
        }
 };
 $dbScheme=new DbScheme;
diff --git a/www/inc/session.php b/www/inc/session.php
new file mode 100644 (file)
index 0000000..6297a28
--- /dev/null
@@ -0,0 +1,13 @@
+<?
+//
+// PHP Implementation: session
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+?>
\ No newline at end of file
index ba57067..7c0a0d9 100644 (file)
@@ -1,7 +1,7 @@
 <? 
 //basics
 include('loader.php');
-include('loader2.php');
+include('loader_nonadmin.php');
 //include display scripts
 include('inc/listing.php');
 include('inc/parser.php');
index 76df225..26c9f65 100644 (file)
@@ -1,4 +1,6 @@
 <?
+//internal info: server version
+$MAGICSMOKEVERSION="0.1 alpha";
 //load DB drivers
 include('inc/db.php');
 include('inc/db_mysql.php');
@@ -6,5 +8,5 @@ include('config.php');
 include('inc/db_scheme.php');
 //try to connect
 $db->tryConnect();
-//move on in loader2.php (or admin.php)
+//move on in loader_nonadmin.php (or admin.php)
 ?>
\ No newline at end of file
similarity index 100%
rename from www/loader2.php
rename to www/loader_nonadmin.php
diff --git a/www/machine.php b/www/machine.php
new file mode 100644 (file)
index 0000000..f94ba95
--- /dev/null
@@ -0,0 +1,61 @@
+<?
+//check the HTTP-request type
+if($_SERVER["REQUEST_METHOD"] != "POST" || !isset($_SERVER["HTTP_X_MAGICSMOKE_REQUEST"])){
+       header("X-MagicSmoke-Status","NonPost");
+       print("<html><title>Error</title><body>This is the machine interface of Magic Smoke. Other clients and browsers are not allowed.</html>");
+       exit();
+}
+
+//check whether the request is known
+// all valid requests must be listed here (in lower case)
+$ALLOWEDREQUESTS=array(
+       "serverinfo", //info request
+       "startsession","sessionauth","closesession", //session requests
+       "blah" //...
+);
+$SMOKEREQUEST=strtolower($_SERVER["HTTP_X_MAGICSMOKE_REQUEST"]);
+if(!in_array($SMOKEREQUEST,$ALLOWEDREQUESTS)){
+       header("X-MagicSmoke-Status","InvalidRequest");
+       exit();
+}
+$REQUESTDATA="";
+if(isset($HTTP_RAW_POST_DATA)){
+       $REQUESTDATA=$HTTP_RAW_POST_DATA;
+}
+
+//initialize basics
+include("loader.php");
+
+// server info can be answered without performing any more initialization
+if($SMOKEREQUEST=="serverinfo"){
+       header("X-MagicSmoke-Status","Ok");
+       print("<Info>\n <ServerVersion proto=\"0000 0000\">$MAGICSMOKEVERSION</ServerVersion\n <AuthAlgorithm>$ClientAuthAlgo</AuthAlgorithm>\n</Info>");
+       exit();
+}
+
+//initialize DB
+include("loader_nonadmin.php");
+
+//load machine interface
+include("inc/session.php");
+
+// request to start a session
+if($SMOKEREQUEST=="startsession"){
+       //TODO: start session
+       exit();
+}
+//request to close a session
+if($SMOKEREQUEST=="closesession"){
+       //TODO: close session
+       header("X-MagicSmoke-Status","Ok");
+       exit();
+}
+
+//all others need a valid session, check it
+//TODO: check session
+
+//request session authentication
+
+
+
+?>
\ No newline at end of file