add host management
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 1 Mar 2008 14:45:07 +0000 (14:45 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 1 Mar 2008 14:45:07 +0000 (14:45 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@98 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

14 files changed:
doc/prog_protocol.html
src/host.cpp [new file with mode: 0644]
src/host.h [new file with mode: 0644]
src/keygen.cpp
src/keygen.h
src/mainwindow.cpp
src/mainwindow.h
src/overview.cpp
src/overview.h
src/smoke.pro
src/webrequest.cpp
src/webrequest.h
www/inc/machine/host.php [new file with mode: 0644]
www/machine.php

index e296e47..1b7ca1a 100644 (file)
@@ -313,3 +313,27 @@ All setable hosts must be listed, so that the client can use these for displayin
 The <tt>setuserhosts</tt> transaction can be used to update a users allowed client hosts. The request is identical to the response of <tt>getuserhosts</tt>, while the response is an empty document on success - only the status "OK" counts.<p>
 
 Any host listed in the request is changed accordingly, non-existant hosts are ignored, hosts not listed are left unchanged.<p>
+
+<h3>Creating and Changing Hosts</h3>
+
+The <tt>addhost</tt> transaction creates new hosts. The <tt>sethost</tt> transaction changes the key of existing hosts. For both the request looks like:<p>
+
+<pre>
+&lt;Hosts>
+  &lt;Host name="hostname">hostkey&lt;/Host>
+  ...
+&lt;/Hosts>
+</pre>
+
+FIXME: currently these transactions do not return any feedback about success. The <tt>sethost</tt> transaction silently ignores hosts that do not exist.
+
+<h3>Getting All Hosts</h3>
+
+The <tt>gethosts</tt> transaction returns the name and key of all hosts. There is no request body. The response looks like the request above.
+
+<h3>Deleting Hosts</h3>
+
+The <tt>deletehost</tt> transaction deletes one single host. The request contains only the name of the host as ASCII text.<p>
+
+FIXME: special hosts (beginning with "_") return errors. Non-existing hosts are silently ignored.
+
diff --git a/src/host.cpp b/src/host.cpp
new file mode 100644 (file)
index 0000000..f934b07
--- /dev/null
@@ -0,0 +1,120 @@
+//
+// C++ Implementation: host
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "host.h"
+#include "webrequest.h"
+#include "keygen.h"
+
+#include <QRegExp>
+#include <QDomElement>
+#include <QCoreApplication>
+
+MHost::MHost(MWebRequest*r,QDomElement&e)
+{
+       req=r;
+       m_hostid=e.attribute("name").trimmed();
+       m_key=e.text().trimmed();
+}
+
+MHost::MHost(MWebRequest*r,QString n,QString k)
+{
+       req=r;
+       m_hostid=n;
+       m_key=k;
+}
+
+MHost::MHost()
+{
+       req=0;
+}
+
+MHost::MHost(const MHost&u)
+{
+       req=u.req;
+       m_hostid=u.m_hostid;
+       m_key=u.m_key;
+}
+
+QString MHost::hostId()
+{
+       return m_hostid;
+}
+
+QString MHost::hostKey()
+{
+       return m_key;
+}
+
+bool MHost::isValid()
+{
+       return QRegExp("[A-Za-z0-9_]+").exactMatch(m_hostid);
+}
+
+int MHost::newKey()
+{
+       int r=getEntropy();
+       m_key=getRandom(40).toHex();
+       if(r<(40*8))return r;
+       else return 40*8;
+}
+
+bool MHost::create()
+{
+       //do not attempt to save invalid or incomplete data
+       if(!isValid())return false;
+       //create XML
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Hosts");
+       QDomElement el=doc.createElement("Host");
+       el.setAttribute("name",m_hostid);
+       el.appendChild(doc.createTextNode(m_key));
+       root.appendChild(el);
+       doc.appendChild(root);
+       //call
+       req->request("addhost",doc.toByteArray());
+       //check success
+       if(req->responseStatus()==MWebRequest::Ok){
+               //TODO: check response content for myself, return false if not found
+               return true;
+       }else{
+               return false;
+       }
+}
+
+bool MHost::save()
+{
+       //do not attempt to save invalid or incomplete data
+       if(!isValid())return false;
+       //create XML
+       QDomDocument doc;
+       QDomElement root=doc.createElement("Hosts");
+       QDomElement el=doc.createElement("Host");
+       el.setAttribute("name",m_hostid);
+       el.appendChild(doc.createTextNode(m_key));
+       root.appendChild(el);
+       doc.appendChild(root);
+       //call
+       req->request("sethost",doc.toByteArray());
+       //check success
+       if(req->responseStatus()==MWebRequest::Ok){
+               //TODO: check response content for myself, return false if not found
+               return true;
+       }else{
+               return false;
+       }
+}
+
+void MHost::deleteHost()
+{
+       if(!isValid())return;
+       req->request("deletehost",m_hostid.toUtf8());
+}
diff --git a/src/host.h b/src/host.h
new file mode 100644 (file)
index 0000000..065acff
--- /dev/null
@@ -0,0 +1,59 @@
+//
+// C++ Interface: host
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2007
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_HOST_H
+#define MAGICSMOKE_HOST_H
+
+#include <QString>
+
+class MWebRequest;
+class QDomElement;
+
+class MHost
+{
+       public:
+               /**create invalid host*/
+               MHost();
+               /**create host by name*/
+               MHost(MWebRequest*,QString,QString k=QString());
+               /**create host from XML element*/
+               MHost(MWebRequest*,QDomElement&);
+               /**copy host*/
+               MHost(const MHost&);
+               
+               /**returns host name*/
+               QString hostId();
+               
+               /**returns host key (fetches it from DB if not known yet)*/
+               QString hostKey();
+               
+               /**checks host name*/
+               bool isValid();
+               
+               /**creates new host key for this host; returns number of entropy bits*/
+               int newKey();
+               
+               /**creates host in database; returns true on success*/
+               bool create();
+               
+               /**updates host key in database; returns true on success*/
+               bool save();
+               
+               /**deletes host from database*/
+               void deleteHost();
+               
+       private:
+               MWebRequest*req;
+               QString m_hostid,m_key;
+};
+
+#endif
index dd8910d..a7fa561 100644 (file)
@@ -224,3 +224,9 @@ QByteArray getRandom(int num)
        if(efilter.isNull())return QByteArray();
        return efilter->getRandom(num);
 }
+
+int getEntropy()
+{
+       if(efilter.isNull())return 0;
+       return efilter->entropy();
+}
index 1efc408..ea24539 100644 (file)
@@ -61,5 +61,6 @@ class EFilter:public QObject
 
 //shortcut:
 QByteArray getRandom(int);
+int getEntropy();
 
 #endif
index 33455d4..444477d 100644 (file)
@@ -35,6 +35,7 @@
 #include <QMessageBox>
 #include <QFileDialog>
 #include <QCryptographicHash>
+#include <QInputDialog>
 
 MMainWindow::MMainWindow()
 {
@@ -226,18 +227,30 @@ void MMainWindow::changeLang()
 
 void MMainWindow::exportKey()
 {
-       QString key=QSettings().value("hostkey").toString().trimmed();
-       saveKey(key);
+       QSettings st;
+       QString host=st.value("hostname").toString().trimmed();
+       QString key=st.value("hostkey").toString().trimmed();
+       saveKey(host,key);
 }
 
 void MMainWindow::generateKey()
 {
+       QString name;
+       do{
+               bool ok;
+               name=QInputDialog::getText(this,tr("New Host Name"),tr("Please enter a name for the new host:"),QLineEdit::Normal,name,&ok);
+               if(!ok)return;
+               if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(name)){
+                       QMessageBox::warning(this,tr("Warning"),tr("The host name must only consist of letters, digits and underscore. It must start with a letter."));
+                       continue;
+               }
+       }while(false);
        MKeyGen mkg;
        if(mkg.exec()==QDialog::Accepted)
-               saveKey(mkg.getKey());
+               saveKey(name,mkg.getKey());
 }
 
-void MMainWindow::saveKey(QString key)
+void MMainWindow::saveKey(QString host,QString key)
 {
        QStringList fn;
        QFileDialog fdlg(this,tr("Export Key to File"),QString(),"Magic Smoke Host Key (*.mshk)");
@@ -253,7 +266,7 @@ void MMainWindow::saveKey(QString key)
                return;
        }
        QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
-       QString out="MagicSmokeHostKey\n"+key+"\n"+chk;
+       QString out="MagicSmokeHostKey\n"+host+"\n"+key+"\n"+chk;
        fd.write(out.toAscii());
        fd.close();
 }
@@ -287,16 +300,22 @@ void MMainWindow::importKey()
                QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
                return;
        }
-       QString key=fc[1].trimmed();
+       QString hname=fc[1].trimmed();
+       if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname)){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid host name."));
+               return;
+       }
+       QString key=fc[2].trimmed();
        if(!QRegExp("[0-9a-fA-F]+").exactMatch(key) || key.size()<40){
                QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid key."));
                return;
        }
        QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
-       if(chk!=fc[2].trimmed()){
+       if(chk!=fc[3].trimmed()){
                QMessageBox::warning(this,tr("Warning"),tr("The key check sum did not match. Please get a clean copy of the host key file."));
                return;
        }
        //save
        QSettings().setValue("hostkey",key);
+       QSettings().setValue("hostname",hname);
 }
index 2d5b675..619fcc4 100644 (file)
@@ -39,7 +39,7 @@ class MMainWindow:public QMainWindow
                QComboBox*profiles;
                
                //helper for exportKey and generateKey
-               void saveKey(QString);
+               void saveKey(QString hostname,QString hostkey);
                
        private slots:
                //handling of login/profile screen
index 86f3018..1884745 100644 (file)
 #include <QLabel>
 #include <QTextEdit>
 #include <QFrame>
+#include <QInputDialog>
+#include <QFileDialog>
+#include <QFile>
+#include <QCryptographicHash>
 
 MOverview::MOverview(MWebRequest*mw,QString pk)
 {
@@ -147,6 +151,33 @@ MOverview::MOverview(MWebRequest*mw,QString pk)
        
        //host tab
        tab->addTab(hosttab=new QWidget,tr("Hosts"));
+       hosttab->setLayout(hl=new QHBoxLayout);
+       hl->addWidget(hosttable=new QTableView,10);
+       hosttable->setModel(hostmodel=new QStandardItemModel(this));
+       hosttable->setSelectionMode(QAbstractItemView::SingleSelection);
+       hosttable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+       hl->addSpacing(5);
+       hl->addLayout(vl=new QVBoxLayout,0);
+       vl->addWidget(p=new QPushButton(tr("New Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(newHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(thishostbutton=p=new QPushButton(tr("Add This Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(addThisHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Delete Host...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteHost()));
+       p->setEnabled(req->hasRole("deletehost"));
+       vl->addSpacing(20);
+       vl->addWidget(p=new QPushButton(tr("Generate New Key...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(changeHostKey()));
+       p->setEnabled(req->hasRole("sethostkey"));
+       vl->addWidget(p=new QPushButton(tr("Import...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(importHost()));
+       p->setEnabled(req->hasRole("addhost"));
+       vl->addWidget(p=new QPushButton(tr("Export...")),0);
+       connect(p,SIGNAL(clicked()),this,SLOT(exportHost()));
+       p->setEnabled(req->hasRole("gethostkey"));
+       vl->addStretch(10);
        
        //status bar
        statusBar()->setSizeGripEnabled(true);
@@ -327,4 +358,166 @@ void MOverview::editUserHosts()
 }
 
 
-void MOverview::updateHosts(){}
+void MOverview::updateHosts()
+{
+       bool foundThis=false;
+       QString thisHost=req->hostName();
+       QList<MHost>hsl=req->getAllHosts();
+       hostmodel->clear();
+       hostmodel->insertColumns(0,2);
+       hostmodel->insertRows(0,hsl.size());
+       hostmodel->setHorizontalHeaderLabels(QStringList()<<tr("Host Name")<<tr("Host Key"));
+       for(int i=0;i<hsl.size();i++){
+               hostmodel->setData(hostmodel->index(i,0),hsl[i].hostId());
+               hostmodel->setData(hostmodel->index(i,1),hsl[i].hostKey());
+               if(thisHost==hsl[i].hostId())
+                       foundThis=true;
+       }
+       hosttable->resizeColumnToContents(0);
+       hosttable->resizeColumnToContents(1);
+       thishostbutton->setEnabled(!foundThis && req->hasRole("addhost"));
+}
+
+void MOverview::newHost()
+{
+       //get Host Name
+       QString hname;
+       do{
+               bool ok;
+               hname=QInputDialog::getText(this,tr("Create New Host"),tr("Please enter a host name:"),QLineEdit::Normal,hname,&ok);
+               if(!ok)return;
+               if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname))continue;
+       }while(false);
+       //create it
+       MHost hst(req,hname);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The key of this new host could only be generated with %1 bits entropy. Store anyway?").arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.create();
+       //update
+       updateHosts();
+}
+
+void MOverview::addThisHost()
+{
+       MHost hst(req,req->hostName(),QSettings().value("hostkey").toString());
+       hst.create();
+       updateHosts();
+}
+
+void MOverview::deleteHost()
+{
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Delete this Host?"),tr("Really delete host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //delete it
+       MHost(req,name).deleteHost();
+       updateHosts();
+}
+
+void MOverview::changeHostKey()
+{
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       //ask
+       if(QMessageBox::question(this,tr("Change Host Key?"),tr("Really change the key of host '%1'?").arg(name),QMessageBox::Yes|QMessageBox::No)!=QMessageBox::Yes)return;
+       //change it
+       MHost hst(req,name);
+       int e=hst.newKey();
+       if(e<128){
+               if(QMessageBox::warning(this,tr("Warning"),tr("The new key of this host could only be generated with %1 bits entropy. Store anyway?").arg(e),QMessageBox::Yes|QMessageBox::No,QMessageBox::No)!=QMessageBox::Yes)
+                       return;
+       }
+       hst.save();
+       //update
+       updateHosts();
+}
+
+void MOverview::importHost()
+{
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Import Key from File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptOpen);
+       fdlg.setFileMode(QFileDialog::ExistingFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::ReadOnly)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for reading: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       //read content (max: 10k to limit potential damage)
+       QStringList fc=QString::fromAscii(fd.read(10240)).split("\n",QString::SkipEmptyParts);
+       fd.close();
+       //check content
+       if(fc.size()<3){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       if(fc[0].trimmed()!="MagicSmokeHostKey"){
+               QMessageBox::warning(this,tr("Warning"),tr("This is not a host key file."));
+               return;
+       }
+       QString hname=fc[1].trimmed();
+       if(!QRegExp("[A-Za-z][A-Za-z0-9_]*").exactMatch(hname)){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid host name."));
+               return;
+       }
+       QString key=fc[2].trimmed();
+       if(!QRegExp("[0-9a-fA-F]+").exactMatch(key) || key.size()<40){
+               QMessageBox::warning(this,tr("Warning"),tr("This host key file does not contain a valid key."));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       if(chk!=fc[3].trimmed()){
+               QMessageBox::warning(this,tr("Warning"),tr("The key check sum did not match. Please get a clean copy of the host key file."));
+               return;
+       }
+       //save
+       MHost hst(req,hname,key);
+       hst.create();
+       updateHosts();
+}
+
+void MOverview::exportHost()
+{
+       //get selection
+       QModelIndex sel=hosttable->currentIndex();
+       if(!sel.isValid())return;
+       //get hname
+       QString name=hostmodel->data(hostmodel->index(sel.row(),0)).toString();
+       QString key=hostmodel->data(hostmodel->index(sel.row(),1)).toString();
+       if(name[0]=='_' || key==""){
+               QMessageBox::warning(this,tr("Warning"),tr("This host cannot be exported."));
+               return;
+       }
+       //save
+       QStringList fn;
+       QFileDialog fdlg(this,tr("Export Key to File"),QString(),"Magic Smoke Host Key (*.mshk)");
+       fdlg.setDefaultSuffix("mshk");
+       fdlg.setAcceptMode(QFileDialog::AcceptSave);
+       fdlg.setFileMode(QFileDialog::AnyFile);
+       if(!fdlg.exec())return;
+       fn=fdlg.selectedFiles();
+       if(fn.size()!=1)return;
+       QFile fd(fn[0]);
+       if(!fd.open(QIODevice::WriteOnly|QIODevice::Truncate)){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to open file %1 for writing: %2").arg(fn[0]).arg(fd.errorString()));
+               return;
+       }
+       QString chk=QCryptographicHash::hash(key.toAscii(),QCryptographicHash::Md5).toHex();
+       QString out="MagicSmokeHostKey\n"+name+"\n"+key+"\n"+chk;
+       fd.write(out.toAscii());
+       fd.close();
+}
index dbd0f46..5f99fbc 100644 (file)
@@ -20,6 +20,7 @@ class MWebRequest;
 class QTabWidget;
 class QTableView;
 class QStandardItemModel;
+class QPushButton;
 
 /**Main Overview Window*/
 class MOverview:public QMainWindow
@@ -58,6 +59,19 @@ class MOverview:public QMainWindow
                
                /**update list of hosts*/
                void updateHosts();
+               /**create new host*/
+               void newHost();
+               /**create a database entry for this host*/
+               void addThisHost();
+               /**delete a host*/
+               void deleteHost();
+               /**generate a new key*/
+               void changeHostKey();
+               /**import host from file*/
+               void importHost();
+               /**export host to file*/
+               void exportHost();
+               
        private:
                //my session object
                QPointer<MWebRequest>req;
@@ -68,6 +82,7 @@ class MOverview:public QMainWindow
                QWidget*eventtab,*carttab,*usertab,*hosttab;
                QTableView*eventtable,*usertable,*hosttable;
                QStandardItemModel*eventmodel,*usermodel,*hostmodel;
+               QPushButton*thishostbutton;
 };
 
 #endif
index 0203a0f..c52c87b 100644 (file)
@@ -33,6 +33,7 @@ SOURCES = \
        event.cpp \
        room.cpp \
        user.cpp \
+       host.cpp \
        checkdlg.cpp
 HEADERS = \
        keygen.h \
@@ -44,6 +45,7 @@ HEADERS = \
        event.h \
        room.h \
        user.h \
+       host.h \
        checkdlg.h \
        ../www/machine.php \
        ../www/inc/machine/session.php
index d9be3f4..b2e8b21 100644 (file)
@@ -329,7 +329,7 @@ QList<MRoom> MWebRequest::getAllRooms()
        QDomDocument doc;
        QString msg;int ln,cl;
        if(!doc.setContent(rspdata,&msg,&ln,&cl)){
-               errstr=tr("Error parsing EventList XML data (line %1 column %2): %3").arg(ln).arg(cl).arg(msg);
+               errstr=tr("Error parsing RoomList XML data (line %1 column %2): %3").arg(ln).arg(cl).arg(msg);
                return QList<MRoom>();
        }
        QDomElement root=doc.documentElement();
@@ -352,7 +352,7 @@ QList<MUser> MWebRequest::getAllUsers()
        QDomDocument doc;
        QString msg;int ln,cl;
        if(!doc.setContent(rspdata,&msg,&ln,&cl)){
-               errstr=tr("Error parsing EventList XML data (line %1 column %2): %3").arg(ln).arg(cl).arg(msg);
+               errstr=tr("Error parsing UserList XML data (line %1 column %2): %3").arg(ln).arg(cl).arg(msg);
                return QList<MUser>();
        }
        QDomElement root=doc.documentElement();
@@ -367,6 +367,29 @@ QList<MUser> MWebRequest::getAllUsers()
        return ret;
 }
 
+QList<MHost> MWebRequest::getAllHosts()
+{
+       errstr="";
+       if(!request("gethosts",""))return QList<MHost>();
+       //parse return document
+       QDomDocument doc;
+       QString msg;int ln,cl;
+       if(!doc.setContent(rspdata,&msg,&ln,&cl)){
+               errstr=tr("Error parsing HostList XML data (line %1 column %2): %3").arg(ln).arg(cl).arg(msg);
+               return QList<MHost>();
+       }
+       QDomElement root=doc.documentElement();
+       QDomNodeList nl=root.elementsByTagName("Host");
+       QList<MHost>ret;
+       for(int i=0;i<nl.size();i++){
+               QDomElement el=nl.at(i).toElement();
+               if(el.isNull())continue;
+               MHost hs(this,el);
+               if(hs.isValid())ret.append(hs);
+       }
+       return ret;
+}
+
 QByteArray MWebRequest::responseBody()
 {
        return rspdata;
@@ -397,3 +420,8 @@ void MWebRequest::reloginCheck()
        if(sessiontimeout<=QDateTime::currentDateTime().toTime_t())
                relogin();
 }
+
+QString MWebRequest::hostName()
+{
+       return hostname;
+}
index 2d0c405..5d9a237 100644 (file)
@@ -25,6 +25,7 @@
 #include "room.h"
 #include "event.h"
 #include "user.h"
+#include "host.h"
 
 /**abstraction of requests to the web server, handles sessions and all data transfer*/
 class MWebRequest:public QObject
@@ -76,6 +77,12 @@ class MWebRequest:public QObject
                /**returns a list of all users**/
                QList<MUser>getAllUsers();
                
+               /**returns a list of all hosts**/
+               QList<MHost>getAllHosts();
+               
+               /**return current host name of this session*/
+               QString hostName();
+               
        public slots:
                /**set how long to wait for a web request*/
                void setTimeout(int);
diff --git a/www/inc/machine/host.php b/www/inc/machine/host.php
new file mode 100644 (file)
index 0000000..dd1bde3
--- /dev/null
@@ -0,0 +1,100 @@
+<?
+//
+// PHP Implementation: host
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2008
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+//return names&keys of all hosts
+function getAllHostsXml()
+{
+       global $db;
+       header("X-MagicSmoke-Status: Ok");
+       $res=$db->select("host","hostname,hostkey","");
+       $dom=new DomDocument;
+       $root=$dom->createElement("Hosts");
+       for($i=0;$i<count($res);$i++){
+               $hst=$dom->createElement("Host",$res[$i]["hostkey"]);
+               $hst->setAttributeNode(new DOMAttr("name",$res[$i]["hostname"]));
+               $root->appendChild($hst);
+       }
+       $dom->appendChild($root);
+       print($dom->saveXML());
+}
+
+//create a new host
+function addHostXml($txt)
+{
+       global $db;
+       $hlist=parseHostXml($txt);
+       foreach($hlist as $host){
+               //check name
+               if(ereg("^[A-Za-z][A-Za-z0-9_]*$",$host["name"])===false)continue;
+               //create
+               $db->insert("host",array("hostname"=>$host["name"],"hostkey"=>$host["key"]));
+       }
+       header("X-MagicSmoke-Status: Ok");
+       //FIXME: return a useful answer
+}
+
+//change a host
+function setHostXml($txt)
+{
+       global $db;
+       $hlist=parseHostXml($txt);
+       foreach($hlist as $host){
+               //check name
+               if(ereg("^[A-Za-z][A-Za-z0-9_]*$",$host["name"])===false)continue;
+               //update
+               $db->update("host",array("hostkey"=>$host["key"]),"hostname=".$db->escapeString($host["name"]));
+       }
+       header("X-MagicSmoke-Status: Ok");
+       //FIXME: return a useful answer
+}
+
+//helper: parse host data
+function parseHostXml($txt)
+{
+       $xml=new DOMDocument;
+       if(!$xml->loadXML($txt)){
+               header("X-MagicSmoke-Status: SyntaxError");
+               die("unable to parse XML data");
+       }
+       $ret=array();
+       foreach($xml->getElementsByTagName("Host") as $el){
+               $usr["name"]=$el->getAttribute("name");
+               $usr["key"]="";
+               foreach($el->childNodes as $cn)
+                       if($cn->nodeType==XML_TEXT_NODE)
+                               $usr["key"]=$cn->wholeText;
+               $ret[]=$usr;
+       }
+       return $ret;
+}
+
+//delete a host
+function deleteHostXml($txt)
+{
+       global $db;
+       $hst=trim($txt);
+       //check syntax
+       if(substr($hst,0,1)=="_"){
+               header("X-MagicSmoke-Status: Error");
+               die("Cannot delete special hosts.");
+       }
+       //delete Host from users
+       $db->deleteRows("userhosts","host=".$db->escapeString($hst));
+       //delete Host
+       $db->deleteRows("host","hostname=".$db->escapeString($hst));
+       //say OK anyway; FIXME: check for success above
+       header("X-MagicSmoke-Status: Ok");
+}
+
+
+?>
\ No newline at end of file
index 9f92709..835e419 100644 (file)
@@ -51,6 +51,7 @@ include("inc/loader_nonadmin.php");
 
 //load machine interface
 include("inc/machine/session.php");
+include("inc/machine/host.php");
 
 // request to start a session
 if($SMOKEREQUEST=="startsession"){
@@ -157,33 +158,52 @@ if($SMOKEREQUEST=="getuseracl"){
        getUserAclXml($REQUESTDATA);
        exit();
 }
-
+//set the ACL of a specific user
 if($SMOKEREQUEST=="setuseracl"){
        setUserAclXml($REQUESTDATA);
        exit();
 }
+//get the allowed client hosts of a specific user
 if($SMOKEREQUEST=="getuserhosts"){
        getUserHostsXml($REQUESTDATA);
        exit();
 }
+//set the allowed client hosts of a specific user
 if($SMOKEREQUEST=="setuserhosts"){
        setUserHostsXml($REQUESTDATA);
        exit();
 }
-
+//create a new user
 if($SMOKEREQUEST=="adduser"){
        addUserXml($REQUESTDATA);
        exit();
 }
-
+//delete an user
 if($SMOKEREQUEST=="deleteuser"){
        deleteUserXml($REQUESTDATA);
        exit();
 }
-if($SMOKEREQUEST=="gethosts"){}
-if($SMOKEREQUEST=="sethost"){}
-if($SMOKEREQUEST=="addhost"){}
-if($SMOKEREQUEST=="deletehost"){}
+
+//return a list of all hosts with their keys
+// there is currently no transaction to get names only, since this is
+// implied in getuserhosts
+if($SMOKEREQUEST=="gethosts"){
+       getAllHostsXml();
+       exit();
+}
+//change the key of a host
+if($SMOKEREQUEST=="sethost"){
+       setHostXml($REQUESTDATA);
+}
+//create a new host entry
+if($SMOKEREQUEST=="addhost"){
+       addHostXml($REQUESTDATA);
+       exit();
+}
+if($SMOKEREQUEST=="deletehost"){
+       deleteHostXml($REQUESTDATA);
+       exit();
+}
 
 
 //EOF