--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : gcm_input.cpp
+** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION : Application to store client messages into the database
+** The client message contains a log file from one of the
+** system logs. Gcm_input parses the log file and enters
+** the raw data into the 'log' table of the gnucomo database.
+**
+** The system log may arrive in one of several forms:
+** 1. Log file (archived or not) from a client machine.
+** 2. Log file from a client system, arriving in a clear Email.
+** 3. Log file from a client machine, arriving in an
+** encrypted Email.
+**
+** additional information we need that may not be availble in
+** the content of the log is:
+** - FQDN of the client.
+** - Time of arrival of the log
+** - Service that created the log.
+**
+** If the log arrives in an Email, these items probably are
+** available in the mail header. Otherwise, they have to be
+** provided as command line arguments.
+**
+** Command line arguments:
+** -c <name> Configuration name (default = gnucomo).
+** -d <date> Date and time of log arrival.
+** -h <hostname> FQDN of the client.
+** -s <service> Service that created the log.
+** -T Test mode. Do not alter the database.
+** -v Verbose (debug) output.
+** -V Print version and exit.
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Aug 29, 2002
+** LAST UPDATE : Sep 30, 2002
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: gcm_input.cpp,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+static const char *RCSID = "$Id: gcm_input.cpp,v 1.1 2002-10-05 10:25:49 arjen Exp $";
+
+#include <getopt.h>
+
+#include "message.h"
+
+bool verbose = false;
+bool testmode = false;
+
+static char *Version = "gcm_input version 0.0.3 - Sep 30, 2002";
+
+
+/*=========================================================================
+** NAME : main
+** SYNOPSIS : int main(int argc, char *argv[])
+** PARAMETERS :
+** RETURN VALUE :
+**
+** DESCRIPTION : Parse command line arguments and establish a connection
+** to the database.
+** When we have a database connection, parse the log file
+** from stdin.
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED : Sep 30, 2002
+**=========================================================================
+*/
+
+int main(int argc, char *argv[])
+{
+ const char *usage = "Usage: gcm_input [-c configname] [-h hostname] [-d date]"
+ " [-s service] [-T] [-v] [-V]\n";
+
+ gnucomo_config cfg;
+ char *config_name = "gnucomo";
+
+ /* Parse command line arguments */
+
+ UTC arrival = Now();
+ String hostname(""), service("");
+ int option;
+
+
+ while ((option = getopt(argc, argv, "c:h:d:s:TvV")) != -1)
+ {
+ switch (option)
+ {
+ case 'c':
+ config_name = optarg;
+ break;
+
+ case 'h':
+ hostname = optarg;
+ break;
+
+ case 'd':
+ arrival = String(optarg);
+ if (!arrival.proper())
+ {
+ cerr << "gcm_input: Invalid date string: " << optarg << ".\n";
+ exit(1);
+ }
+ break;
+
+ case 's':
+ service = optarg;
+ break;
+
+ case 'T':
+ testmode = true;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ case 'V':
+ cout << Version << "\n";
+ exit(0);
+
+ case '?':
+ case ':':
+ cerr << usage;
+ exit(1);
+ }
+ }
+
+ if (verbose)
+ {
+ cout << "Hostname = " << hostname;
+ cout << " Arrival = " << arrival;
+ cout << " Service = " << service << "\n";
+ }
+
+ /* Get the configuration file */
+
+ if (!cfg.read(config_name))
+ {
+ cerr << "Can not read Gnucomo configuration file for " << config_name << ".\n";
+ exit(1);
+ }
+
+ if (verbose)
+ {
+ cout << "Config OK.\n";
+ }
+
+ /* Try to connect to the database */
+
+ gnucomo_database db(&cfg);
+
+ client_message msg(&cin, db);
+
+ if (msg.classify(hostname, arrival, service) > 0.9)
+ {
+ msg.enter();
+ }
+
+ return 0;
+}
+
--- /dev/null
+CXXFLAGS = -I/usr/include/gnome-xml -g
+
+GCMINPUT_O = gcm_input.o gnucomo_config.o database.o message.o
+
+gcm_input : $(GCMINPUT_O)
+ $(CXX) -o gcm_input $(GCMINPUT_O) -lAXE -lxml -lpq++
+
+gcm_input.o : message.h database.h
+database.o : database.h
+message.o : message.h
+
+clean:
+ rm -f gcm_input $(GCMINPUT_O)
--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : message.cpp
+** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION : Implementation of the message handling classes
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Sep 16, 2002
+** LAST UPDATE : Oct 05, 2002
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: message.cpp,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+static const char *RCSID = "$Id: message.cpp,v 1.1 2002-10-05 10:25:49 arjen Exp $";
+
+#include "message.h"
+
+extern bool verbose; /* Defined in the main application */
+extern bool testmode;
+
+/* Utility functions */
+
+String SQL_Escape(String s);
+
+/*=========================================================================
+** NAME : operator >>
+** SYNOPSIS : bool operator >> (message_buffer &, String &)
+** PARAMETERS :
+** RETURN VALUE : True if input was available.
+**
+** DESCRIPTION : Input operator. Read the next line from the message.
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED : Sep 30, 2002
+**=========================================================================
+*/
+
+bool operator >> (message_buffer &b, String &s)
+{
+ bool input_ok = false;
+
+ if (b.next_line == b.buffer.end())
+ {
+ String l;
+
+ //cout << " buffer is depleted.\n";
+ if (*(b.input) >> l)
+ {
+ b.buffer.push_back(l);
+
+ // next_line keeps pointing to the end.
+
+ s = l;
+ input_ok = true;
+ //cout << " new line from input.\n";
+ }
+ }
+ else
+ {
+ //cout << " reading from cache.\n";
+ s = *(b.next_line);
+ b.next_line++;
+ input_ok = true;
+ }
+ return input_ok;
+}
+
+client_message::client_message(istream *in, gnucomo_database db)
+{
+ input.from(in);
+ database = db;
+
+ hostname = "";
+ mail_header = false;
+ gpg_encrypted = false;
+ classification = UNKNOWN;
+ certainty = 0.0;
+}
+
+static const String syslog_date_re("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}");
+static const String mail_date_re("[[:alpha:]]{3}, [ 123]?[0-9] [[:alpha:]]{3} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} [+-][0-9]{4}");
+static const String unix_date_re("[[:alpha:]]{3} [[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}");
+
+static const regex re_syslog(syslog_date_re + " [a-z]+ [[:alpha:]]+.*:.+");
+static const regex re_PGP("-----BEGIN PGP MESSAGE-----");
+static const regex re_dump("^ *DUMP: Date of this level");
+static const regex re_accesslog("(GET|POST) .+ HTTP");
+static const regex re_errorlog("^\\[" + unix_date_re + "\\] \\[(error|notice)\\] .+");
+
+static const regex re_syslog_date("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}");
+static const regex re_uxmail_from("^From - " + unix_date_re);
+static const regex re_mail_From("^From:[[:blank:]]+");
+static const regex re_mail_Date("^Date:[[:blank:]]+" + mail_date_re);
+static const regex re_email_address("[[:alnum:]_.-]+@[[:alnum:]_.-]+");
+static const regex re_email_user("[[:alnum:]_.-]+@");
+
+/*=========================================================================
+** NAME : classify
+** SYNOPSIS : double classify(String host, date arriv_d, hour arriv_t, String serv)
+** PARAMETERS :
+** RETURN VALUE : The certainty with which the message is classified.
+**
+** DESCRIPTION :
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED : Oct 05, 2002
+**=========================================================================
+*/
+
+double client_message::classify(String host, UTC arriv, String serv)
+{
+ String line;
+
+ hostname = host;
+ arrival = arriv;
+ service = serv;
+
+ /* First, check if the message has a mail header. */
+
+ if (input >> line && line == re_uxmail_from)
+ {
+ String from_address;
+
+ mail_header = true;
+
+ /* Scan ahead for the hostname and date of arrival. */
+
+ while (input >> line && line != "")
+ {
+ if (line == re_mail_From)
+ {
+ from_address = line(re_email_address);
+ from_address(re_email_user) = ""; // Remove the user part;
+ hostname = from_address;
+ }
+ if (line == re_mail_Date)
+ {
+ arrival = UTC(line(regex(mail_date_re)));
+ }
+ }
+ }
+ else
+ {
+ // Push the first line back, we need to read it again.
+ --input;
+ }
+
+ /*
+ * Now that we have the mail header out of the way, try to figure
+ * out what the content of the message is.
+ */
+
+
+ while (input >> line && certainty < 0.9)
+ {
+ cout << " testing: " << line << "\n";
+ if (line == re_syslog)
+ {
+ certainty = 1.0;
+ classification = SYSLOG;
+ if (verbose)
+ {
+ cout << "Syslog detected.\n";
+ }
+ }
+ else if (line == re_PGP)
+ {
+ certainty = 1.0;
+ gpg_encrypted = true;
+ cerr << "The message is PGP/GnuPG encrypted.\n";
+ }
+ else if (line == re_dump)
+ {
+ certainty = 1.0;
+ if (verbose)
+ {
+ cout << "DUMP output detected.\n";
+ }
+ }
+ else if (line == re_accesslog)
+ {
+ certainty = 1.0;
+ classification = ACCESSLOG;
+ service = "httpd";
+ if (verbose)
+ {
+ cout << "HTTP access log detected.\n";
+ }
+ }
+ else if (line == re_errorlog)
+ {
+ certainty = 1.0;
+ classification = ERRORLOG;
+ service = "httpd";
+ if (verbose)
+ {
+ cout << "HTTP error log detected.\n";
+ }
+ }
+ }
+ input.rewind();
+
+ if (hostname == "")
+ {
+ cerr << "Can not determine the hostname where the message came from.\n";
+ certainty = 0.0;
+ }
+ else if (!arrival.proper())
+ {
+ cerr << "Arrival time is not knwon.\n";
+ certainty = 0.0;
+ }
+ else
+ {
+ certainty = 1.0;
+ }
+
+ return certainty;
+}
+
+/*=========================================================================
+** NAME : enter
+** SYNOPSIS : int enter()
+** PARAMETERS :
+** RETURN VALUE : The number of lines successfully parsed from the input
+**
+** DESCRIPTION :
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED : Oct 05, 2002
+**=========================================================================
+*/
+
+int client_message::enter()
+{
+ long nr_lines = 0;
+ String line;
+
+ /* Double-check the classification of the message */
+
+ if (classification == UNKNOWN || certainty < 0.9 || gpg_encrypted)
+ {
+ return 0;
+ }
+
+ if (mail_header)
+ {
+ // Skip the mail header.
+
+ while (input >> line && line != "");
+ }
+
+ /* Try to find the host in the database */
+
+ String objectid;
+
+ objectid = database.find_host(hostname);
+ if (objectid == "")
+ {
+ cerr << "Please define the host " << hostname << " in the database.\n";
+ return 0;
+ }
+ if (verbose)
+ {
+ cout << "Object id for " << hostname << " is " << objectid << "\n";
+ }
+
+ /* Scan the input line by line, entring records into the database */
+
+ String rest; // Rest of the line to be parsed
+
+ while (input >> line)
+ {
+ if (verbose)
+ {
+ cout << line << "\n";
+ }
+
+
+ /* Check each line if it contains valid information */
+
+ const regex *check;
+
+ switch (classification)
+ {
+ case SYSLOG:
+ check = &re_syslog;
+ break;
+ case ACCESSLOG:
+ check = &re_accesslog;
+ break;
+ case ERRORLOG:
+ check = &re_errorlog;
+ break;
+ }
+
+ if (line == *check)
+ {
+ date log_date;
+ hour log_time;
+ int i;
+
+ String insertion("insert into log (objectid, servicecode,"
+ " object_timestamp, timestamp, rawdata) values (");
+ String datestring;
+
+ switch (classification)
+ {
+ case SYSLOG:
+ log_date = line;
+ log_time = line;
+ if (log_date.Year() < 0 || log_date.Year() > 2500)
+ {
+ // The year is not in the log file. Assume the year of arrival
+
+ log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year());
+ }
+
+ if (verbose)
+ {
+ cout << " Log timestamp = " << log_date << " " << log_time << "\n";
+ }
+ rest = line << 16;
+ i = rest.index(' ');
+ if (rest(0,i) == hostname(0,i))
+ {
+ rest <<= i + 1;
+ if (verbose)
+ {
+ cout << " Hostname matches.\n";
+ cout << " rest = " << rest << "\n";
+ }
+ for (i = 0; isalpha(rest[i]) && i < ~rest; i++);
+ if (verbose)
+ {
+ cout << " Service name = " << rest(0,i) << "\n";
+ }
+
+ /* Insert a new record into the log table */
+
+ insertion += "'" + objectid + "',";
+ insertion += "'" + rest(0,i) + "',";
+ insertion += "'" + log_date.format() + " " + log_time.format() + "',";
+ insertion += "'" + arrival.format() + "',";
+ insertion += "'" + SQL_Escape(line) + "'";
+ insertion += ")";
+
+ if (testmode)
+ {
+ cout << insertion << "\n";
+ }
+ else
+ {
+ database.Query(insertion);
+ }
+
+ if (verbose)
+ {
+ cout << "\n\n";
+ }
+
+ nr_lines++;
+ }
+ else
+ {
+ cerr << " Hostname " << rest(0,i) << " does not match.\n";
+ }
+ break;
+
+ case ACCESSLOG:
+ datestring = line(regex("\\[.+\\]"));
+ datestring <<= 1;
+ datestring >>= 1;
+ datestring[datestring.index(':')] = ' ';
+ log_date = datestring;
+ log_time = datestring;
+ if (verbose)
+ {
+ cout << " Log timestamp = " << log_date << " " << log_time << "\n";
+ }
+ insertion += "'" + objectid + "',";
+ insertion += "'" + service + "',";
+ insertion += "'" + log_date.format() + " " + log_time.format() + "',";
+ insertion += "'" + arrival.format() + "',";
+ insertion += "'" + SQL_Escape(line) + "'";
+ insertion += ")";
+
+ if (testmode)
+ {
+ cout << insertion << "\n";
+ }
+ else
+ {
+ database.Query(insertion);
+ }
+
+ if (verbose)
+ {
+ cout << "\n\n";
+ }
+
+ nr_lines++;
+ break;
+
+ case ERRORLOG:
+ datestring = line(regex("\\[.+\\]"));
+ datestring <<= 1;
+ datestring >>= 1;
+ log_date = datestring;
+ log_time = datestring;
+ if (verbose)
+ {
+ cout << " Log timestamp = " << log_date << " " << log_time << "\n";
+ }
+ insertion += "'" + objectid + "',";
+ insertion += "'" + service + "',";
+ insertion += "'" + log_date.format() + " " + log_time.format() + "',";
+ insertion += "'" + arrival.format() + "',";
+ insertion += "'" + SQL_Escape(line) + "'";
+ insertion += ")";
+
+ if (testmode)
+ {
+ cout << insertion << "\n";
+ }
+ else
+ {
+ database.Query(insertion);
+ }
+
+ if (verbose)
+ {
+ cout << "\n\n";
+ }
+
+ nr_lines++;
+ break;
+ }
+ }
+ else
+ {
+ cerr << "gcm_input WARNING: Not a valid line: " << line << "\n";
+ }
+ }
+
+ if (verbose)
+ {
+ cout << nr_lines << " lines parsed from the log file.\n";
+ }
+ return nr_lines;
+}
+
+/*=========================================================================
+** NAME : SQL_Escape
+** SYNOPSIS : String SQL_Escape(String)
+** PARAMETERS :
+** RETURN VALUE :
+**
+** DESCRIPTION : Insert backslashes before single quotes.
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED :
+**=========================================================================
+*/
+
+String SQL_Escape(String s)
+{
+ int i;
+
+ for (i = 0; i < ~s; i++)
+ {
+ if (s[i] == '\'')
+ {
+ s(i,0) = "\\";
+ i++;
+ }
+ }
+
+ return s;
+}
--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : message.h
+** SYSTEM NAME :
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION : Classes to for handling client messages
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Sep 16, 2002
+** LAST UPDATE : Oct 05, 2002
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: message.h,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+/* static const char *RCSID = "$Id: message.h,v 1.1 2002-10-05 10:25:49 arjen Exp $"; */
+
+#include <iostream>
+#include <list>
+#include <AXE/String.h>
+#include <AXE/date.h>
+
+#include "database.h"
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : message_buffer
+// BASECLASS :
+// MEMBERS :
+// OPERATORS :
+// METHODS : rewind()
+//
+// DESCRIPTION :
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED : Sep 30, 2002
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class message_buffer
+{
+ istream *input;
+ list<String> buffer;
+
+ list<String>::iterator next_line;
+
+public:
+
+ message_buffer()
+ {
+ input = 0;
+ next_line = buffer.begin();
+ }
+
+ message_buffer(istream *in)
+ {
+ input = in;
+ next_line = buffer.begin();
+ }
+
+ void from(istream *in)
+ {
+ input = in;
+ }
+
+ friend bool operator >> (message_buffer &, String &);
+
+ void rewind()
+ {
+ next_line = buffer.begin();
+ }
+
+ void operator ++()
+ {
+ if (next_line != buffer.end())
+ {
+ next_line++;
+ }
+ }
+
+ void operator --()
+ {
+ if (next_line != buffer.begin())
+ {
+ next_line--;
+ }
+ }
+};
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : client_message
+// BASECLASS :
+// MEMBERS :
+// OPERATORS :
+// METHODS : classify()
+// enter()
+//
+// DESCRIPTION :
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED : Oct 05, 2002
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class client_message
+{
+ String hostname; // Where the message came from (FQDN)
+ UTC arrival; // When we got the message.
+ String service; // Service that created the message
+
+ bool mail_header; // Does the message contain a mail header ?
+ bool gpg_encrypted; // Is the message encrypted ?
+
+ double certainty; // How certain are we about the message
+ enum
+ {
+ UNKNOWN, SYSLOG, ACCESSLOG, ERRORLOG
+ } classification;
+
+
+ message_buffer input;
+ gnucomo_database database;
+
+public:
+
+ client_message(istream *in, gnucomo_database db);
+
+ double classify(String host, UTC arrival = Now(), String serv = "");
+ int enter();
+};
+
--- /dev/null
+<?xml version='1.0'?>
+<gnucomo version='0.0.0'>
+ <database>
+ <type>PostgreSQL</type>
+ <name>gnucomo</name>
+ <user>arjen</user>
+ <password>guess again :-)</password>
+ <host>localhost</host>
+ <port>5432</port>
+ </database>
+</gnucomo>
+
--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : database.h
+** SYSTEM NAME :
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION : Classes to provide an abstract layer on the Gnucomo
+** database.
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Sep 10, 2002
+** LAST UPDATE :
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: database.h,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+/* static const char *RCSID = "$Id: database.h,v 1.1 2002-10-05 10:25:49 arjen Exp $"; */
+
+#include <libpq++/pgdatabase.h>
+#include "gnucomo_config.h"
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : gnucomo_database
+// BASECLASS : configuration
+// MEMBERS :
+// OPERATORS :
+// METHODS : Database - Obtain the database access string
+//
+// DESCRIPTION :
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED : Sep 16, 2002
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class gnucomo_database
+{
+ gnucomo_config *cfg;
+ PgDatabase *db;
+
+public:
+
+ gnucomo_database()
+ {
+ cfg = 0;
+ db = 0;
+ }
+
+ gnucomo_database(gnucomo_config *c); // Use the configuration to connect to the database
+
+ // Low-level database access functions
+
+ int Query(String qry)
+ {
+ ExecStatusType result;
+
+ result = db->Exec(qry);
+ if (result == PGRES_TUPLES_OK || result == PGRES_COMMAND_OK)
+ {
+ return db->Tuples();
+ }
+ else
+ {
+ cerr << "Database query error: " << db->ErrorMessage() << "\n";
+ return -1;
+ }
+ }
+
+ // Return the objectid of the host given its name.
+
+ String find_host(const String hostname);
+};
+
--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : gnucomo.h
+** SYSTEM NAME :
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION :
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Jul 24, 2002
+** LAST UPDATE :
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: gnucomo_config.h,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+/* static const char *RCSID = "$Id: gnucomo_config.h,v 1.1 2002-10-05 10:25:49 arjen Exp $"; */
+
+#include <AXE/configuration.h>
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : gnucomo_config
+// BASECLASS : configuration
+// MEMBERS :
+// OPERATORS :
+// METHODS : Database - Obtain the database access string
+//
+// DESCRIPTION :
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED :
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class gnucomo_config : public configuration
+{
+
+public:
+
+ String Database(); // Return the database access string.
+};
+
--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : database.cpp
+** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION : Implementation of the gnucomo database classes
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Sep 10, 2002
+** LAST UPDATE : Sep 26, 2002
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: database.cpp,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+static const char *RCSID = "$Id: database.cpp,v 1.1 2002-10-05 10:25:49 arjen Exp $";
+
+#include "database.h"
+
+extern bool verbose; /* Defined in the main application */
+
+/*=========================================================================
+** NAME : gnucomo_database
+** SYNOPSIS : gnucomo_database(gnucomo_config &c);
+** PARAMETERS :
+** RETURN VALUE : Database constructor. Establishes a connection with
+** the database server.
+**
+** DESCRIPTION :
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED : Sep 26, 2002
+**=========================================================================
+*/
+
+gnucomo_database::gnucomo_database(gnucomo_config *c)
+{
+ cfg = c;
+
+ if (verbose)
+ {
+ cout << "Database connection string = " << cfg->Database() << "\n";
+ }
+
+ db = new PgDatabase(cfg->Database());
+
+ if (db->ConnectionBad())
+ {
+ cerr << "Can not connect to database: " << db->ErrorMessage();
+ }
+}
+
+/*=========================================================================
+** NAME : find_host
+** SYNOPSIS : String gnucomo_database::find_host(String hostname);
+** PARAMETERS :
+** RETURN VALUE : Find a hostname in the 'object' table of the gnucomo database
+** and return its object id.
+** Return an empty string as objectid if the hostname is
+** not found.
+**
+** DESCRIPTION :
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED : Sep 16, 2002
+**=========================================================================
+*/
+
+String gnucomo_database::find_host(const String hostname)
+{
+ String objectid("");
+ String check_host("select objectid from object where ");
+
+ check_host += "objectname = '";
+ check_host += hostname;
+ check_host += "'";
+
+ if (Query(check_host) > 0)
+ {
+ objectid = String(db->GetValue(0, "objectid"));
+ }
+
+ return objectid;
+}
--- /dev/null
+
+/**************************************************************************
+** (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+** FILE NAME : gnucomo_config.cpp
+** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
+** VERSION NUMBER : $Revision: 1.1 $
+**
+** DESCRIPTION : Implementation of the gnucomo_config class.
+**
+** EXPORTED OBJECTS :
+** LOCAL OBJECTS :
+** MODULES USED :
+***************************************************************************
+** ADMINISTRATIVE INFORMATION *
+********************************
+** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+** CREATION DATE : Jul 24, 2002
+** LAST UPDATE : Jul 24, 2002
+** MODIFICATIONS :
+**************************************************************************/
+
+/*****************************
+ $Log: gnucomo_config.cpp,v $
+ Revision 1.1 2002-10-05 10:25:49 arjen
+ Creation of gcm_input and a first approach to a web interface
+
+*****************************/
+
+static const char *RCSID = "$Id: gnucomo_config.cpp,v 1.1 2002-10-05 10:25:49 arjen Exp $";
+
+#include "gnucomo_config.h"
+
+
+
+/*=========================================================================
+** NAME : Database
+** SYNOPSIS : String gnucomo_config::Database()
+** PARAMETERS :
+** RETURN VALUE : The database access string
+**
+** DESCRIPTION :
+**
+** VARS USED :
+** VARS CHANGED :
+** FUNCTIONS USED :
+** SEE ALSO :
+** LAST MODIFIED :
+**=========================================================================
+*/
+
+String gnucomo_config::Database()
+{
+ String param;
+ String access_string("");
+
+ param = find_parameter("database", "name");
+ if (param != "")
+ {
+ access_string += "dbname=" + param;
+ }
+
+ param = find_parameter("database", "user");
+ if (param != "")
+ {
+ access_string += " user=" + param;
+ }
+ param = find_parameter("database", "password");
+ if (param != "")
+ {
+ access_string += " password=" + param;
+ }
+
+ /* FIXME: This needs a fix in the AXE library first */
+
+ /*
+ param = find_parameter("database", "host");
+ if (param != "")
+ {
+ access_string += " host=" + param;
+ }
+ param = find_parameter("database", "port");
+ if (param != "")
+ {
+ access_string += " port=" + param;
+ }
+*/
+ return access_string;
+}
--- /dev/null
+<?php
+
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : configuration
+// BASECLASS :
+// MEMBERS :
+// OPERATORS :
+// METHODS : read
+//
+// DESCRIPTION : Handle configurational parameters for the application.
+// Many applications need some permanently stored configurational
+// data. The information is usually stored in two places: A system-
+// wide configuration file and a configuration file per user.
+// The content of the configuration file is in XML format.
+// The configuration base class takes care of finding the configuration
+// files, e.g. in /etc/app.conf or in /usr/loca/etc/app.conf
+// The config files are parsed with the gnome XML parser and a
+// framework is provided to find configurational items.
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED : Jul 29, 2002
+///////////////////////////////////////////////////////////////////////////
+*/
+
+
+class configuration
+{
+ var $system, $user;
+
+ function configuration()
+ {
+ $system = false;
+ $user = false;
+ }
+
+ function xmlFindTag($node, $tag)
+ {
+ $element = false;
+ $i = 0;
+
+ while (!$element && $i < sizeof($node))
+ {
+ if ($node[$i]->type == XML_ELEMENT_NODE && $node[$i]->tagname == $tag)
+ {
+ $element = $node[$i];
+ }
+ $i++;
+ }
+
+ return $element;
+ }
+
+ function read($app_name)
+ {
+ $filename = "/etc/" . $app_name . ".conf";
+ $this->system = xmldocfile($filename);
+
+ if (!$this->system)
+ {
+ $filename = "/usr/local/etc/" . $app_name . ".conf";
+ $this->system = xmldocfile($filename);
+ }
+
+ if ($this->system)
+ {
+ $root = $this->system->root();
+
+ if ($root->tagname != $app_name)
+ {
+ print("Configuration error: Wrong configuration file.<br>");
+ $this->system = false;
+ }
+ }
+ else
+ {
+ print("Configuration error: Configuration file for $app_name not found.<br>");
+ }
+ }
+
+ function find_parameter($section, $parameter)
+ {
+ $param_value = "";
+
+ if ($this->system)
+ {
+ $root_node = $this->system->root();
+ $section_node = $this->xmlFindTag($root_node->children(), $section);
+ if ($section_node)
+ {
+ $param_node = $this->xmlFindTag($section_node->children(), $parameter);
+ if ($param_node)
+ {
+ $param_node = $param_node->children();
+ }
+ if ($param_node && $param_node[0]->type == XML_TEXT_NODE)
+ {
+ $param_value = $param_node[0]->content;
+ }
+ }
+ }
+
+ return $param_value;
+ }
+}
+
+?>
--- /dev/null
+<?php
+
+require_once('configuration.class.php');
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : gnucomo_config
+// BASECLASS : configuration
+// MEMBERS :
+// OPERATORS :
+// METHODS : Database - Obtain the database access string
+//
+// DESCRIPTION :
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED :
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class gnucomo_config extends configuration
+{
+
+ // Return the database access string.
+
+ function Database()
+ {
+ $access_string = "";
+
+ $param = $this->find_parameter("database", "name");
+ if ($param != "")
+ {
+ $access_string .= "dbname=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "user");
+ if ($param != "")
+ {
+ $access_string .= " user=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "password");
+ if ($param != "")
+ {
+ $access_string .= " password=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "host");
+ if ($param != "")
+ {
+ $access_string .= " host=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "port");
+ if ($param != "")
+ {
+ $access_string .= " port=" . $param;
+ }
+ return $access_string;
+ }
+};
+?>
--- /dev/null
+<?php
+
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : configuration
+// BASECLASS :
+// MEMBERS :
+// OPERATORS :
+// METHODS : read
+//
+// DESCRIPTION : Handle configurational parameters for the application.
+// Many applications need some permanently stored configurational
+// data. The information is usually stored in two places: A system-
+// wide configuration file and a configuration file per user.
+// The content of the configuration file is in XML format.
+// The configuration base class takes care of finding the configuration
+// files, e.g. in /etc/app.conf or in /usr/loca/etc/app.conf
+// The config files are parsed with the gnome XML parser and a
+// framework is provided to find configurational items.
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED : Jul 29, 2002
+///////////////////////////////////////////////////////////////////////////
+*/
+
+
+class configuration
+{
+ var $system, $user;
+
+ function configuration()
+ {
+ $system = false;
+ $user = false;
+ }
+
+ function xmlFindTag($node, $tag)
+ {
+ $element = false;
+ $i = 0;
+
+ while (!$element && $i < sizeof($node))
+ {
+ if ($node[$i]->type == XML_ELEMENT_NODE && $node[$i]->tagname == $tag)
+ {
+ $element = $node[$i];
+ }
+ $i++;
+ }
+
+ return $element;
+ }
+
+ function read($app_name)
+ {
+ $filename = "/etc/" . $app_name . ".conf";
+ $this->system = xmldocfile($filename);
+
+ if (!$this->system)
+ {
+ $filename = "/usr/local/etc/" . $app_name . ".conf";
+ $this->system = xmldocfile($filename);
+ }
+
+ if ($this->system)
+ {
+ $root = $this->system->root();
+
+ if ($root->tagname != $app_name)
+ {
+ print("Configuration error: Wrong configuration file.<br>");
+ $this->system = false;
+ }
+ }
+ else
+ {
+ print("Configuration error: Configuration file for $app_name not found.<br>");
+ }
+ }
+
+ function find_parameter($section, $parameter)
+ {
+ $param_value = "";
+
+ if ($this->system)
+ {
+ $root_node = $this->system->root();
+ $section_node = $this->xmlFindTag($root_node->children(), $section);
+ if ($section_node)
+ {
+ $param_node = $this->xmlFindTag($section_node->children(), $parameter);
+ if ($param_node)
+ {
+ $param_node = $param_node->children();
+ }
+ if ($param_node && $param_node[0]->type == XML_TEXT_NODE)
+ {
+ $param_value = $param_node[0]->content;
+ }
+ }
+ }
+
+ return $param_value;
+ }
+}
+
+?>
--- /dev/null
+<?php
+
+require_once('configuration.class.php');
+
+/*
+///////////////////////////////////////////////////////////////////////////
+// NAME : gnucomo_config
+// BASECLASS : configuration
+// MEMBERS :
+// OPERATORS :
+// METHODS : Database - Obtain the database access string
+//
+// DESCRIPTION :
+//
+// RELATIONS :
+// SEE ALSO :
+// LAST MODIFIED :
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class gnucomo_config extends configuration
+{
+
+ // Return the database access string.
+
+ function Database()
+ {
+ $access_string = "";
+
+ $param = $this->find_parameter("database", "name");
+ if ($param != "")
+ {
+ $access_string .= "dbname=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "user");
+ if ($param != "")
+ {
+ $access_string .= " user=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "password");
+ if ($param != "")
+ {
+ $access_string .= " password=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "host");
+ if ($param != "")
+ {
+ $access_string .= " host=" . $param;
+ }
+
+ $param = $this->find_parameter("database", "port");
+ if ($param != "")
+ {
+ $access_string .= " port=" . $param;
+ }
+ return $access_string;
+ }
+};
+?>
--- /dev/null
+<?
+/******************************************************************************************/
+/* global parameters */
+/******************************************************************************************/
+ //$pgsqlhost = "10.10.10.145"; // PostgreSQL server
+ //$pgsqlport = "5432"; // PostgreSQL port
+ //$dbname = "gnucomo"; // PostgreSQL database name
+
+/******************************************************************************************/
+/* string function login_form( void ) */
+/* */
+/* returns the login form */
+/******************************************************************************************/
+function login_form() {
+
+ $login = "<div class='login'>";
+ $login .= "<h1 align=\"center\">GNU Computer Monitoring</h1>";
+ $login .= "<center><table>";
+ $login .= "<tr>";
+ $login .= "<td width='50%'><img src='../doc/logo.png' alt='GnuCoMo logo'></td>";
+ $login .= "<td><form name=\"login\" method=\"POST\" action=\"login.php\">";
+ $login .= " <table>";
+ $login .= " <tr>";
+ $login .= " <td>Username</td>";
+ $login .= " <td><input type=\"text\" name=\"username\"></td>";
+ $login .= " </tr>";
+ $login .= " <tr>";
+ $login .= " <td>Password</td>";
+ $login .= " <td><input type=\"password\" name=\"password\"></td>";
+ $login .= " </tr>";
+ $login .= " <tr>";
+ $login .= " <td> </td>";
+ $login .= " <td align=\"right\"><input type=\"submit\" value=\"signin\"></td>";
+ $login .= " </tr>";
+ $login .= " </table>";
+ $login .= " </form>";
+ $login .= "</td>";
+ $login .= "</tr>";
+ $login .= "</table></center>";
+ $login .= "</div>";
+
+ return $login;
+}
+
+/******************************************************************************************/
+/* array function query( resource connection, string sqlquery ) */
+/* */
+/* gives an array return. */
+/* arr[0] = boolean if action completed whitout error, return true otherwise false */
+/* arr[1] = result sql query result */
+/* arr[2] = int number of rows */
+/* arr[3] = string error information */
+/******************************************************************************************/
+function query( $conn, $sql ) {
+
+ $query_result = pg_exec( $conn, $sql );
+
+ if( $query_result != FALSE ) {
+ $query_nRows = pg_NumRows($query_result);
+ $query_error = pg_errormessage( $conn );
+ return array( TRUE, $query_result, $query_nRows, "" );
+ } else {
+ $query_error = @pg_errormessage( $conn );
+ return array( FALSE, $query_result, 0, $query_error );
+ }
+}
+
+/******************************************************************************************/
+/* void function pgsql_error( string error ) */
+/* */
+/* prints an error message */
+/******************************************************************************************/
+function pgsql_error( $err ) {
+ echo "An error occured. Please contact your systemadministrator.<br>";
+ echo "Error: $err";
+}
+?>
--- /dev/null
+
+body
+{
+ background-color : rgb(80, 120, 100);
+}
+
+h1
+{
+ font-family : sans-serif ;
+ text-align : center ;
+}
+
+h2
+{
+ font-family : sans-serif ;
+}
+
+div.login
+{
+ background : rgb(80, 120, 150) ;
+ border: solid;
+ border-width: thick;
+ border-color : cyan ;
+ padding : 1em;
+ margin : 10% ;
+ width: 80%;
+ text-align : center ;
+}
+table
+{
+ width : 80% ;
+ border-width : medium ;
+ border-style : none ;
+ border-collapse : collapse;
+ padding : 1px ;
+}
+
+td
+{
+ font-family : sans-serif ;
+}
+
+th
+{
+ border-width : thin ;
+ border-style : solid ;
+}
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel='stylesheet' href='gnucomo.css' type='text/css'>
+<title>GnuCoMo Web Interface</title>
+</head>
+ <frameset rows="80,*" border='0'>
+ <frame name="menubar" frameborder='0' src="menu.html" scrolling="no" noresize>
+ <frame name="main" frameborder='0' src="login.php">
+ </frameset>
+</html>
--- /dev/null
+<?php
+session_start();
+require_once('gnucomo_config.php');
+include "functions.php";
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel='stylesheet' href='gnucomo.css' type='text/css'>
+<title>GNUCoMo login</title>
+</head>
+<body>
+<?php
+if( isset($_POST["username"]) and isset($_POST["password"]) and isset($_SESSION['login']) ) {
+ $name = $_POST["username"]; // PostgreSQL username
+ $passw = $_POST["password"]; // PostgreSQL user password
+
+ $config = new gnucomo_config;
+
+ $config->read("gnucomo");
+ //echo "Database Access string = " . $config->Database();
+
+ $conn = pg_connect($config->Database());
+
+ // connect to the database
+ //$conn = pg_Connect( "host=$pgsqlhost port=$pgsqlport dbname=$dbname user=$name password=$passw" );
+ if( !$conn ) {
+ echo "Error connecting, try again.";
+ echo login_form();
+ $_SESSION["login"] = true;
+ } else {
+ $sql = "SELECT * FROM user_gnucomo WHERE username='$name' and password='$passw'";
+ $res = query( $conn, $sql );
+
+ if( $res[0] ) {
+ if ($res[2] == 1)
+ {
+ $arr = pg_fetch_array( $res[1], 0 );
+ $_SESSION["login.ini"] = $arr;
+ }
+ else
+ {
+ echo "Login incorrect.<br>";
+ }
+
+ // user is authorised, step to next page.
+ echo "Ok!";
+ } else {
+ pgsql_error( "SQL: error.<br>" . $res[3] );
+ }
+ }
+} else {
+ echo login_form();
+ $_SESSION["login"] = true;
+}
+?>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel='stylesheet' href='gnucomo.css' type='text/css'>
+<title>GnuCoMo Web Interface</title>
+</head>
+<body>
+ <img src='server.png' alt='Objects'>
+ <img src='user.png' alt='Users'>
+ <img src='closed_package.png' alt='Packages'>
+ <img src='password.png' alt='Change Password'>
+ <img src='exit.png' alt='Logout'>
+ <hr>
+
+</body>
+</html>