[pisa-src] r1152 - in trunk/community-operator: Makefile.am co_client.c co_client.cfg co_common_packets.h co_server.c hipl.c hipl.h

  • From: Jan Marten <jan.marten@xxxxxxxxxxxxxx>
  • To: pisa-src@xxxxxxxxxxxxx
  • Date: Wed, 14 Oct 2009 17:22:24 +0200

Author: marten
Date: Wed Oct 14 17:22:24 2009
New Revision: 1152

Log:
Added Community-Operator changes:
 - A protocol is introduced
 - Client checks periodically for new certificate
 - A request can be denied
 - changes which require the certificate changes in the HIPL code are added in 
ifdef blocks

Added:
   trunk/community-operator/co_common_packets.h
Modified:
   trunk/community-operator/Makefile.am
   trunk/community-operator/co_client.c
   trunk/community-operator/co_client.cfg
   trunk/community-operator/co_server.c
   trunk/community-operator/hipl.c
   trunk/community-operator/hipl.h

Modified: trunk/community-operator/Makefile.am
==============================================================================
--- trunk/community-operator/Makefile.am        Wed Oct 14 17:12:26 2009        
(r1151)
+++ trunk/community-operator/Makefile.am        Wed Oct 14 17:22:24 2009        
(r1152)
@@ -26,8 +26,9 @@
 INCLUDES = -I@PISA_HIPL_SRCDIR@/libinet6/include
 INCLUDES += -I@PISA_HIPL_SRCDIR@/libinet6
 INCLUDES += -I@PISA_HIPL_SRCDIR@/libhiptool
-INCLUDES += -I@PISA_HIPL_SRCDIR@/libdht
+INCLUDES += -I@PISA_HIPL_SRCDIR@/opendht
 INCLUDES += -I@PISA_HIPL_SRCDIR@/hipd
+INCLUDES += -I@PISA_HIPL_SRCDIR@/firewall
 INCLUDES += -I@PISA_HIPL_SRCDIR@/i3/i3_client
 INCLUDES += -I@PISA_HIPL_SRCDIR@/pjproject/pjnath/include
 INCLUDES += -I@PISA_HIPL_SRCDIR@/pjproject/pjlib/include
@@ -42,6 +43,11 @@
 co_server_SOURCES = co_server.c hipl.c
 
 co_client_LDADD  = $(LDADD) -lm -lcrypto
+if PISA_WITH_HIPL
+# TODO correct linking
+# pisa_split_cert function is needed in co_client.c
+       co_client_LDADD += @PISA_HIPL_SRCDIR@/firewall/pisa_cert.o
+endif
 co_client_SOURCES = co_client.c
 
 include_HEADERS = hipl.h

Modified: trunk/community-operator/co_client.c
==============================================================================
--- trunk/community-operator/co_client.c        Wed Oct 14 17:12:26 2009        
(r1151)
+++ trunk/community-operator/co_client.c        Wed Oct 14 17:22:24 2009        
(r1152)
@@ -3,17 +3,61 @@
  * All rights reserved.
  */
 
-#include <errno.h>
-#include <stdio.h>
-
-#include "config.h"
-
+#include <sys/types.h>
 #include <sys/socket.h>
-#include <arpa/inet.h>
 #include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
+#include <signal.h>
 #include <unistd.h>
+#include <dirent.h>
+
+#include "global.h"
+
+#define __USE_XOPEN
+#include <time.h>
+
+#include "co_common_packets.h"
+#include "config.h"
+#include "debug.h"
+//#include "util.h"
+
+#ifdef CONFIG_PISA_WITH_HIPL
+# include "pisa_cert.h"        /* in firewall under the hipl source tree */
+#endif /* CONFIG_PISA_WITH_HIPL */
+
+#define CERT_FILENAME_FORMAT "%Y%m%d%H%M%S"
+
+#define PATH_BUFFER 1000 /** @todo */
+
+static int check_certs_dir(void);
+static void co_client_check_certs(int signal);
+static void co_client_init(void);
+static void co_client_main(void);
+static void co_client_quit(int signal);
+static int copy_cert(const char * source,char * destination);
+static int create_client_socket(struct sockaddr_in6 *srv_addr);
+static int is_valid_cert(const char *filename);
+static void print_deny_reason(int reason);
+static int receive_certificate(char **cert);
+static int retrieve_new_cert(void);
+static int request_cert(void);
+static int write_cert_file(char *cert,const char *filename);
+
+typedef struct co_client_conf
+{
+    int retries;
+    char srv_hit[INET6_ADDRSTRLEN];
+    int port;
+    char cert_filename[PATH_BUFFER];
+    int check_interval;
+    char certs_dir[PATH_BUFFER];
+    int save_certs;
+}
+co_client_conf_t;
+
+co_client_conf_t co_client_conf;
+static int running;
+static int sock;
+char last_used_cert[PATH_BUFFER];
 
 /**
  * Write a certificate to a file.
@@ -38,6 +82,27 @@
 }
 
 /**
+ * Prints the corresponding deny reason to the given reason number.
+ * @param reason Reason number
+ */
+static void print_deny_reason(int reason)
+{
+    PISA_ERROR("Certificate request denied:\n");
+    switch(reason)
+    {
+    case DENY_HIT_EXPIRED:
+        PISA_ERROR("The HIT has expired.\n");
+        break;
+    case DENY_HIT_NOT_ALLOWED:
+        PISA_ERROR("The HIT is not allowed to request certificates.\n");
+        break;
+    case DENY_UNKNOWN_ERROR:
+        PISA_ERROR("An unknown error occurred.\n");
+        break;
+    }
+}
+
+/**
  * Create a UDP socket connected to the server with a receive timeout.
  *
  * @param srv_addr HIT of the server
@@ -51,38 +116,57 @@
        to.tv_sec = 5;
        to.tv_usec = 0;
 
-       if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) == 0) {
-               printf("socket() failed.\n");
-               exit(-1);
-       }
-
-       if (connect(s, (struct sockaddr *)srv_addr,
-                   sizeof(struct sockaddr_in6)) == -1) {
-               printf("connect to srv_addr failed.\n");
-               exit(-1);
-       }
+    if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) == 0)
+    {
+        PISA_ERROR("socket() failed.\n");
+        exit(-1);
+    }
+
+    if (connect(s, (struct sockaddr *)srv_addr,
+                sizeof(struct sockaddr_in6)) == -1)
+    {
+        PISA_ERROR("connect to srv_addr failed.\n");
+        exit(-1);
+    }
 
-       if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)))
-               printf("Could not set a receive timeout.\n");
+    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)))
+        PISA_ERROR("Could not set a receive timeout.\n");
 
-       return s;
+    return s;
 }
 
-static int sock;
-
 /**
  * Request a certificate from the server using the previously opened socket.
  * @todo define protocol
  *
- * @return 0 on success, -1 otherwise
+ * @return 1 on success, 0 otherwise
  */
-static int sendRequest(void)
+static int request_cert(void)
 {
-       if (send(sock, "blah", 4, 0) != 4) {
-               printf("failed to request the certificate\n");
-               return -1;
-       }
-       return 0;
+    int sent;
+    co_packet *packet;
+    packet = malloc(sizeof(co_packet));
+
+    packet->message_type = MESSAGE_CERTIFICATE_REQUEST;
+
+    sent = send(sock,packet,sizeof(co_packet),0);
+    free(packet);
+    if(sent == -1)
+    {
+        PISA_ERROR("send failed.\n");
+
+        return 0;
+    }
+
+    if (sent!=sizeof(co_packet))
+    {
+        PISA_ERROR("sent bytes (%i) do not match expected value (%i).\n",
+               sent, sizeof(co_packet));
+
+        return 0;
+    }
+
+    return 1;
 }
 
 /**
@@ -92,69 +176,390 @@
  * @param cert place to store the newly malloced certificate
  * @return 0 for success, -1 for permanent failure, -2 for retry
  */
-static int receiveCertificate(char **cert)
+static int receive_certificate(char **cert)
 {
-       char buffer[10240] = "";
-       ssize_t count;
+    co_packet *packet;
+    ssize_t count;
 
-       *cert = NULL;
+    int result;
 
-       if ((count = recv(sock, buffer, sizeof(buffer) -1, 0)) == -1) {
-               printf("Receive failed (errno %i): %s\n", errno,
-                      strerror(errno));
-               if (errno == EAGAIN)
-                       return -2;
-               return -1;
-       }
+    *cert = NULL;
 
-       buffer[count] = 0;
-       if (!strcmp(buffer, "denied")) {
-               printf("Community operator server denied the certificate.\n");
-               return -1;
-       }
+    packet = malloc(sizeof(co_packet));
 
-       *cert = strdup(buffer);
-       return 0;
+    if ((count = recv(sock, packet, sizeof(co_packet) , 0)) == -1)
+    {
+        PISA_ERROR("Receive failed (errno %i): %s\n", errno,
+               strerror(errno));
+        if (errno == EAGAIN)
+            result = -2;
+        result = -1;
+    }
+
+    switch(packet->message_type)
+    {
+    case MESSAGE_CERTIFICATE_DENY:
+        print_deny_reason(packet->message.deny.reason);
+        result = -1;
+        break;
+    case MESSAGE_CERTIFICATE_ACCEPT:
+        PISA_INFO("Certificate request approved!\n");
+        *cert = strdup(packet->message.cert.cert);
+        result = 0;
+        break;
+    case MESSAGE_ERROR:
+        PISA_ERROR("Error(%i): 
%s\n",packet->message.error.error_type,packet->message.error.error_message);
+        result = -1;
+        break;
+    default:
+        PISA_ERROR("Unknown error occurred.\n");
+        result = -2;
+        break;
+    }
+
+    free(packet);
+    return result;
+}
+
+
+/**
+ * Terminate community-operator client by receiving signal
+ * @param signal signal quit code
+ */
+static void co_client_quit(int signal)
+{
+    running = 0;
+    PISA_INFO("Shutting down Community-Operator client...\n");
+    pisa_cfg_cleanup();
+}
+
+/**
+ * Main loop
+ */
+static void co_client_main(void)
+{
+    while(running)
+    { }
+}
+
+/**
+ * Copies cert file to destination.
+ * @param source Source filename
+ * @param destination Destination filename
+ * @return 1 -> success
+ * @return 0 -> error
+ */
+static int copy_cert(const char * source,char * destination)
+{
+    FILE *from,*to;
+    char ch;
+
+    if((from = fopen(source,"r")) == NULL)
+    {
+        perror("open");
+        return 0;
+    }
+
+    if((to = fopen(destination, "w")) == NULL)
+    {
+        perror("open");
+        return 0;
+    }
+
+    while(!feof(from))
+    {
+        ch = fgetc(from);
+        if(ferror(from))
+        {
+            PISA_ERROR("Error reading source file.\n");
+            return 0;
+        }
+        if(!feof(from))
+            fputc(ch, to);
+        if(ferror(to))
+        {
+            PISA_ERROR("Error writing destination file.\n");
+            return 0;
+        }
+    }
+
+    if(fclose(from)==EOF)
+    {
+        PISA_ERROR("Error closing source file.\n");
+        return 0;
+    }
+
+    if(fclose(to)==EOF)
+    {
+        PISA_ERROR("Error closing destination file.\n");
+        return 0;
+    }
+    return 1;
+}
+
+/**
+ * Reads the settings from the config file.
+ */
+static void co_client_init(void)
+{
+    pisa_cfg_get_string_value("hit", co_client_conf.srv_hit, INET6_ADDRSTRLEN);
+    pisa_cfg_get_int_value("port", &co_client_conf.port);
+    pisa_cfg_get_int_value("retry", &co_client_conf.retries);
+    
pisa_cfg_get_string_value("filename",co_client_conf.cert_filename,PATH_BUFFER);
+    pisa_cfg_get_int_value("check_interval",&co_client_conf.check_interval);
+    
pisa_cfg_get_string_value("certs_dir",co_client_conf.certs_dir,PATH_BUFFER);
+    pisa_cfg_get_bool_value("save_certs",&co_client_conf.save_certs);
+
+    /* sanity check configuration values */
+    if (co_client_conf.retries < 1)
+        co_client_conf.retries = 1;
+    if (co_client_conf.retries > 100) /* @todo find reasonable maximum */
+        co_client_conf.retries = 100;
+
+    if(co_client_conf.check_interval<=0)
+        co_client_conf.check_interval = 60;
+}
+
+/**
+ * Retrieves new certificates from community-operator server
+ * @return 1 -> success
+ * @return 0 -> error
+ */
+static int retrieve_new_cert(void)
+{
+    struct sockaddr_in6 srv_addr = { 0 };
+    char *cert = NULL;
+    int count;
+
+    srv_addr.sin6_family = AF_INET6;
+    inet_pton(PF_INET6, co_client_conf.srv_hit, &(srv_addr.sin6_addr));
+    srv_addr.sin6_port = htons(co_client_conf.port);
+    sock = create_client_socket(&srv_addr);
+
+    for (count = 0; count < co_client_conf.retries; count++)
+    {
+        if (request_cert() == 0)
+            break;
+        if (receive_certificate(&cert) != -2)
+            break;
+    }
+
+    close(sock);
+
+    // Successfully received certificate
+    if (cert)
+    {
+        PISA_INFO("Certificate was successfully retrieved.\n");
+#ifdef CONFIG_PISA_WITH_HIPL
+        if(co_client_conf.save_certs)
+        {
+            struct pisa_cert pc;
+            struct tm *ts;
+            char buf_before[15];
+            char buf_after[15];
+            char path[100];
+            time_t now;
+            char *cert_start;
+
+            // Workaround:
+            // Because pisa_cert.c seems to be made for a different cert file 
format
+            cert_start = strstr(cert,"(cert");
+            // Create pisa_struct from cert file
+            pisa_split_cert(cert_start, &pc);
+
+            // Convert dates to format yyyymmddhhmmss
+            PISA_DEBUG(PL_GENERIC,"Certificate is valid from: 
%s",ctime(&pc.not_before));
+            ts = localtime(&pc.not_before);
+            strftime(buf_before, sizeof(buf_before), CERT_FILENAME_FORMAT, ts);
+            ts = localtime(&pc.not_after);
+            PISA_DEBUG(PL_GENERIC,"Certificate expires at: 
%s",ctime(&pc.not_after));
+            strftime(buf_after, sizeof(buf_after), CERT_FILENAME_FORMAT, ts);
+
+            // Create filename notbefore-notaftercert 
(yyyymmddhhmmss-yyyymmddhhmmsscert)
+            // in co_client_conf.certs_dir
+            snprintf((char 
*)path,sizeof(path),"%s/%s-%scert",co_client_conf.certs_dir 
,buf_before,buf_after);
+            write_cert_file(cert,  path);
+            time(&now);
+
+            // Certificate is already valid
+            if(difftime(now,pc.not_before)>=0)
+            {
+                PISA_DEBUG(PL_GENERIC,"Copying to cert location...\n");
+                strncpy(last_used_cert,path,PATH_BUFFER);
+                write_cert_file(cert,co_client_conf.cert_filename);
+            }
+            else
+            {
+                PISA_DEBUG(PL_GENERIC,"Certificate not yet valid.\n");
+            }
+            free(cert);
+            return 1;
+        }
+#else
+        write_cert_file(cert,co_client_conf.cert_filename);
+#endif
+
+    }
+    else
+    {
+        PISA_ERROR("Certificate could not be obtained.\n");
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * Checks expiration dates of a cert filename 
+ * @param filename filename to check
+ * @return 1  -> cert is valid
+ * @return 0  -> cert not yet valid
+ * @return -1 -> cert expired
+ */
+static int is_valid_cert(const char *filename)
+{
+    struct tm ts_before,ts_after;
+    char buf_before[15];
+    char buf_after[15];
+    time_t now,not_before,not_after;
+
+    // Read not-before date
+    strncpy(buf_before,filename,14);
+    strptime(buf_before,CERT_FILENAME_FORMAT,&ts_before);
+
+    // Read not-after date
+    strncpy(buf_after,filename+15,14);
+    strptime(buf_after,CERT_FILENAME_FORMAT,&ts_after);
+
+    time(&now);
+    not_before = mktime(&ts_before);
+    not_after = mktime(&ts_after);
+
+    // Expired
+    if(difftime(now,not_after)>0)
+    {
+        PISA_DEBUG(PL_GENERIC,"Cert: %s expired.\n",filename);
+        return -1;
+    }
+
+    // Not yet valid
+    if(difftime(now,not_before)<0)
+    {
+        PISA_DEBUG(PL_GENERIC,"Cert: %s is not yet valid.\n",filename);
+        return 0;
+    }
+
+    PISA_DEBUG(PL_GENERIC,"Cert: %s is valid.\n",filename);
+    return 1;
+}
+
+/**
+ * Checks if there is a valid cert in co_client_conf.certs_dir 
+ * and copies the cert to co_client_conf.filename
+ * @return 1 -> a valid cert file existent
+ * @return 0 -> no valid cert file found
+ */
+static int check_certs_dir(void)
+{
+    struct dirent **namelist;
+    int n,i,found,result;
+    char path[PATH_BUFFER];
+
+    found = 0;
+    n = scandir(co_client_conf.certs_dir, &namelist, 0, alphasort);
+    if (n < 0)
+        perror("scandir");
+    else
+    {
+        for(i = 0; i<n && !found; i++)
+        {
+            // Skip . and ..
+            if(strcmp(namelist[i]->d_name,".")!=0 && 
strcmp(namelist[i]->d_name,"..")!=0)
+            {
+                result = is_valid_cert(namelist[i]->d_name);
+                snprintf((char 
*)path,sizeof(path),"%s/%s",co_client_conf.certs_dir ,namelist[i]->d_name);
+                // Cert expired
+                if(result == -1)
+                {
+                    PISA_DEBUG(PL_GENERIC,"Removing cert...\n");
+                    if(remove(path)!=0)
+                    {
+                        perror("Removing cert failed");
+                    }
+                }
+                else if(result)
+                {
+                    found = 1;
+                    if(strcmp(path,last_used_cert)!=0)
+                    {
+                        strncpy(last_used_cert,path,PATH_BUFFER);
+                        PISA_DEBUG(PL_GENERIC,"Found valid cert.\n");
+                        PISA_DEBUG(PL_GENERIC,"Copying to cert location...\n");
+                        copy_cert(path,co_client_conf.cert_filename);
+                    }
+                }
+            }
+            free(namelist[i]);
+        }
+        free(namelist);
+    }
+    return found;
+}
+
+/**
+ * Function is called periodically to retrieve new certs if old certs in 
co_client_conf.certs_dir expired.
+ * @param signal signal code
+ */
+static void co_client_check_certs(int signal)
+{
+    if(co_client_conf.save_certs)
+    {
+        PISA_INFO("Checking existing certificates...\n");
+        if(!check_certs_dir())
+        {
+            PISA_INFO("Did not find a valid cert\n");
+            PISA_INFO("Requesting new cert...\n");
+            retrieve_new_cert();
+        }
+        alarm(co_client_conf.check_interval);
+    }
+    else
+    {
+        retrieve_new_cert();
+    }
 }
 
 int main(int argc, char **argv)
 {
-       struct sockaddr_in6 srv_addr = { 0 };
-       char *cert = NULL;
-       char srv_hit[1000]; /* @todo */
-       int count, port, retries = 3;
+
+    signal(SIGTERM, co_client_quit);
+    signal(SIGINT, co_client_quit);
+    signal(SIGQUIT, co_client_quit);
+    signal(SIGILL, co_client_quit);
+    signal(SIGHUP, co_client_quit);
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGBUS, co_client_quit);
+    signal(SIGSEGV, co_client_quit);
+    signal(SIGALRM, co_client_check_certs);
 
        pisa_cfg_setup_file("co_client.cfg");
-       pisa_cfg_get_string_value("hit", srv_hit, 1000);
-       pisa_cfg_get_int_value("port", &port);
-       pisa_cfg_get_int_value("retry", &retries);
-
-       /* sanity check configuration values */
-       if (retries < 1)
-               retries = 1;
-       if (retries > 100) /* @todo find reasonable maximum */
-               retries = 100;
-
-       srv_addr.sin6_family = AF_INET6;
-       inet_pton(PF_INET6, srv_hit, &(srv_addr.sin6_addr));
-       srv_addr.sin6_port = htons(port);
-       sock = createClientSocket(&srv_addr);
-
-       for (count = 0; count < retries; count++) {
-               if (sendRequest() < 0)
-                       break;
-               if (receiveCertificate(&cert) != -2)
-                       break;
-       }
-
-       if (cert) {
-               writeCertFile(cert, "test-cert");
-               free(cert);
-               printf("Certificate was successfully retrieved.\n");
-       } else
-               printf("Certificate could not be obtained.\n");
 
-       pisa_cfg_cleanup();
-       close(sock);
-       return 0;
+    co_client_init();
+
+    running = 1;
+
+    co_client_check_certs(SIGALRM);
+
+    // Only enter infinite loop if we periodically check for valid certs
+    if(co_client_conf.save_certs)
+    {
+        co_client_main();
+    }
+
+    co_client_quit(0);
+
+    exit(EXIT_SUCCESS);
+
+    return 0;
+
 }

Modified: trunk/community-operator/co_client.cfg
==============================================================================
--- trunk/community-operator/co_client.cfg      Wed Oct 14 17:12:26 2009        
(r1151)
+++ trunk/community-operator/co_client.cfg      Wed Oct 14 17:22:24 2009        
(r1152)
@@ -5,5 +5,15 @@
 # How often should we retry if we don't receive an answer before the timeout
 retry=3;
 
+# Saves valid certs to certs_dir and only retrieves new certs if no valid cert 
is found. 
+# Otherwise, the cert is received directly from server and is written to 
"filename"
+save_certs=false;
+
+# Directory to save received certificates
+certs_dir="certs";
+
+# Interval (in seconds) to check certs_dir for expired certificates
+check_interval=60;
+
 # should be /etc/hip/cert for deployment
-filename="test.file";
+filename="/etc/hip/cert";

Added: trunk/community-operator/co_common_packets.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/community-operator/co_common_packets.h        Wed Oct 14 17:22:24 
2009        (r1152)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009, Distributed Systems Group, RWTH Aachen
+ * All rights reserved.
+ */
+
+#ifndef CO_COMMON_PACKETS_H
+#define CO_COMMON_PACKETS_H
+
+#include <netinet/in.h>
+
+#include "global.h"
+
+#define LENGTH_ERROR_MESSAGE 128
+
+// Message types
+#define MESSAGE_CERTIFICATE_REQUEST 0
+#define MESSAGE_CERTIFICATE_DENY 1
+#define MESSAGE_CERTIFICATE_ACCEPT 2
+#define MESSAGE_ERROR 3
+
+// Deny reasons
+#define DENY_HIT_NOT_ALLOWED 0
+#define DENY_HIT_EXPIRED 1
+#define DENY_UNKNOWN_ERROR 2
+
+typedef struct co_certificate_request
+{
+
+} __attribute__ ((packed)) co_certificate_request;
+
+typedef struct co_certificate_deny
+{
+    uint8_t reason;
+} __attribute__ ((packed)) co_certificate_deny;
+
+typedef struct co_certificate
+{
+    char cert[PISA_CERT_LENGTH];
+} __attribute__ ((packed)) co_certificate;
+
+typedef struct co_error
+{
+    uint8_t error_type;
+    uint8_t error_message[LENGTH_ERROR_MESSAGE];
+} __attribute__ ((packed)) co_error;
+
+/* General Community-Operator packet */
+typedef struct co_packet
+{
+    uint8_t    message_type;
+
+    union message {
+        co_certificate_request request;
+        co_certificate_deny deny;
+        co_certificate cert;
+        co_error error;
+    } message;
+
+} __attribute__ ((packed)) co_packet;
+
+#endif

Modified: trunk/community-operator/co_server.c
==============================================================================
--- trunk/community-operator/co_server.c        Wed Oct 14 17:12:26 2009        
(r1151)
+++ trunk/community-operator/co_server.c        Wed Oct 14 17:22:24 2009        
(r1152)
@@ -7,19 +7,35 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/socket.h>
+#include <sys/select.h>
+#include <signal.h>
 
 #include "ac_config.h"
 #include "global.h"
 #include "debug.h"
+#include "co_common_packets.h"
 #include "config.h"
 #include "hitlist.h"
 #include "hipl.h"
 
-#define BUFSIZE 10240
+//#define BUFSIZE 10240
 #define CERT_BUF_SIZE 10240
+#define DEFAULT_NUMBER_OF_PARALLEL_USERS 3
 
+
+static int running;
 static struct in6_addr issuer_hit;
 static pisa_hitlist *allowed = NULL;
+static int sock;
+
+
+static int create_server_socket(void);
+static int answer_certificate_query(struct sockaddr_in6 *cl_addr);
+static int handle_certificate_request(struct sockaddr_in6 
*socket_addr,co_certificate_request *request);
+static void co_quit(int quitcode);
+static char *get_certificate_for_hit(struct in6_addr *hit,int *reason);
+static int handle_packet(struct sockaddr_in6 *socket_addr, co_packet 
*co_packet);
+static int get_number_of_parallel_users(pisa_hitlist_entry *entry);
 
 /**
  * Create a socket and port specified in the config file.
@@ -50,12 +66,34 @@
                exit(-1);
        }
 
-       printf("socket created and bound to port %i\n", port);
+    PISA_INFO("socket created and bound to port %i\n", port);
 
        return s;
 }
 
 /**
+ * Terminate community-operator server by receiving signal
+ * @param signal signal quit code
+ */
+static void co_quit(int quitcode)
+{
+    switch (quitcode)
+    {
+    case SIGTERM:
+    case SIGINT:
+    case SIGQUIT:
+    case SIGBUS:
+        PISA_INFO("Shutting down Community-Operator Server...\n");
+        running = 0;
+        break;
+
+    case SIGILL:
+    case SIGPIPE:
+        break;
+    }
+}
+
+/**
  * Request a certificate for a specified hit, if all requirements are met:
  * - HIT must be whitelisted in the allowed HIT list.
  * - expiration date for that HIT must not be in the past.
@@ -64,124 +102,252 @@
  * date is within that week.
  *
  * @param hit HIT of the requesting host
+ * @param reason Pointer to an int which holds the reason for the deny
  * @return pointer to certificate on success, NULL otherwise
  */
-static char *getCertificateForHit(struct in6_addr *hit)
+static char *get_certificate_for_hit(struct in6_addr *hit,int *reason)
 {
-       char *cert;
-       time_t not_before, not_after;
-       pisa_hitlist_entry *conn;
-
-       time(&not_before);
-       time(&not_after);
-
-       /* certificate for one week */
-       not_after += 7 * 24 * 60 * 60;
-
-       if (!(conn = pisa_hitlist_find(allowed, hit)))
-               return NULL;
-       if (conn->expiration < not_before)
-               return NULL;
-       if (conn->expiration < not_after)
-               not_after = conn->expiration;
-       cert = malloc(CERT_BUF_SIZE);
-       if (createCertificate(&not_before, &not_after, hit, &issuer_hit, cert,
-                             CERT_BUF_SIZE) != 0) {
-               free(cert);
-               return NULL;
+
+    char *cert;
+    time_t not_before, not_after;
+    pisa_hitlist_entry*conn;
+    int parallel_users;
+
+    time(&not_before);
+    time(&not_after);
+
+    /* certificate for one week */
+    not_after += 7 * 24 * 60 * 60;
+
+    if (!(conn = pisa_hitlist_find(allowed, hit)))
+    {
+        *reason = DENY_HIT_NOT_ALLOWED;
+        return NULL;
+    }
+    if (conn->expiration < not_before)
+    {
+        *reason = DENY_HIT_EXPIRED;
+        return NULL;
+    }
+    if (conn->expiration < not_after)
+    {
+        not_after = conn->expiration;
+    }
+
+    parallel_users = get_number_of_parallel_users(conn);
+
+    cert = malloc(CERT_BUF_SIZE);
+    if (createCertificate(&not_before, &not_after, hit, &issuer_hit, 
parallel_users, cert,
+                          CERT_BUF_SIZE) != 0)
+    {
+        free(cert);
+        *reason = DENY_UNKNOWN_ERROR;
+        return NULL;
+    }
+
+    return cert;
+}
+
+static int get_number_of_parallel_users(pisa_hitlist_entry *entry)
+{
+       config_setting_t *users;
+       users =config_setting_get_member(entry->group,"parallel_users");
+       if(users!=NULL)
+       {
+               return config_setting_get_int(users);
+       }else
+       {
+               return DEFAULT_NUMBER_OF_PARALLEL_USERS;
        }
-       return cert;
 }
 
-static int sock;
 
 /**
  * Process a request from a specified client and send back the result
- * @todo specify protocol
  *
  * @param cl_addr client that requested the certificate
+ * @param number_of_access_points Number of Access-Points the client provides
+ * @return 1 -> success; 0 -> error;
  */
 static void answerCertificateQuery(struct sockaddr_in6 *cl_addr)
 {
-       char *cert;
-       int bytes, sent;
-
-       if (!(cert = getCertificateForHit(&cl_addr->sin6_addr))) {
-               cert = strdup("denied");
-       }
-       bytes = strlen(cert);
-
-       if ((sent = sendto(sock, cert, bytes, 0, (struct sockaddr *) cl_addr,
-                          sizeof(struct sockaddr_in6))) == -1) {
-               printf("sendto failed.\n");
-               free(cert);
-               return;
-       }
+    char *cert;
+    int sent,reason;
+    co_packet *packet;
+
+    packet = malloc(sizeof(co_packet));
+
+    if (!(cert = get_certificate_for_hit(&cl_addr->sin6_addr,&reason)))
+    {
+        // Deny request
+        packet->message_type = MESSAGE_CERTIFICATE_DENY;
+        packet->message.deny.reason = reason;
+    }
+    else
+    {
+        // Accept request
+        packet->message_type = MESSAGE_CERTIFICATE_ACCEPT;
+        strncpy(packet->message.cert.cert,cert,strlen(cert));
+    }
+
+    sent = sendto(sock,packet,sizeof(co_packet),0,(struct sockaddr *) cl_addr,
+                  sizeof(struct sockaddr_in6));
+    if(sent == -1)
+    {
+        PISA_ERROR("sendto failed.\n");
+        free(cert);
+        return 0;
+    }
+
+    if (sent!=sizeof(co_packet))
+    {
+        PISA_ERROR("sent bytes (%i) do not match expected value (%i).\n",
+               sent, sizeof(co_packet));
+        return 0;
+    }
+    else
+    {
+        PISA_INFO("the request has been answered.\n");
+        return 1;
+    }
 
-       if (bytes != sent)
-               printf("sent bytes (%i) do not match expected value (%i).\n",
-                      sent, bytes);
-       else
-               printf("the request has been answered.\n");
-
-       free(cert);
+    free(cert);
+    free(packet);
 }
 
 int main(int argc, char **argv)
 {
-       int received;
-       size_t addrlen;
-       struct sockaddr_in6 cl_addr = { 0 };
-       char *buf, *addr_string;
-
-       if (getuid() != 0) {
-               printf("You're not root. HIPD won't sign certificates.\n");
-               return -1;
-       }
-
-       buf = malloc(BUFSIZE);
-       addr_string = malloc(INET6_ADDRSTRLEN);
 
-       pisa_cfg_setup_file("co_server.cfg");
-       allowed = pisa_hitlist_build("allowed_hosts");
+    signal(SIGTERM, co_quit);
+    signal(SIGINT, co_quit);
+    signal(SIGQUIT, co_quit);
+    signal(SIGILL, co_quit);
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGBUS, co_quit);
+
+    int received;
+    size_t addrlen;
+    char *addr_string;
+    co_packet *packet;
+    struct sockaddr_in6 cl_addr = { 0 };
+
+
+    if (getuid() != 0)
+    {
+        PISA_ERROR("You're not root. HIPD won't sign certificates.\n");
+        return -1;
+    }
+
+    running = 1;
+
+    packet = malloc(sizeof(co_packet));
+    addr_string = malloc(INET6_ADDRSTRLEN);
+
+    pisa_cfg_authorized_hosts_setup_file("co_server.cfg");
+    pisa_cfg_setup_file("co_server.cfg");
+    allowed = pisa_hitlist_build("allowed_hosts");
 
 #ifdef CONFIG_PISA_WITH_HIPL
        hip_set_logdebug(1); /* disable the debug output from HIPL code */
 #endif /* CONFIG_PISA_WITH_HIPL */
-       sock = createServerSocket();
-       getDefaultHIT(&issuer_hit);
 
-       printf("community operator server ready\n");
+    sock = create_server_socket();
 
-       while (1) {
-               printf("\nwaiting for incoming packet...\n");
-               addrlen = sizeof(cl_addr);
-               received = recvfrom(sock, buf, BUFSIZE, 0,
-                                   (struct sockaddr *)&cl_addr, &addrlen);
-
-               if (received < 0) {
-                       perror("error in recvfrom:");
-                       continue;
-               } else if (received == 0)
-                       continue;
-
-               inet_ntop(AF_INET6, &cl_addr.sin6_addr, addr_string,
-                         INET6_ADDRSTRLEN);
-               printf("received %i bytes from %s\n", received, addr_string);
-
-               if (pisa_ipv6_addr_is_hit(&cl_addr.sin6_addr)) {
-                       printf("sender was a HIT, processing request.\n");
-                       answerCertificateQuery(&cl_addr);
-               } else {
-                       printf("sender was not a HIT, ignoring request.\n");
-               }
-       }
+    getDefaultHIT(&issuer_hit);
+
+    PISA_INFO("community operator server ready\n");
+    PISA_INFO("\nwaiting for incoming packet...\n");
+    while (running)
+    {
+        fd_set readfds;
+        struct timeval select_to;
+
+        FD_ZERO(&readfds);
+
+        select_to.tv_sec = 1;
+        select_to.tv_usec = 0;
+
+        FD_SET(sock,&readfds);
+
+        if (select(sock + 1, &readfds, NULL, NULL, &select_to) > 0)
+        {
+            // Receive request
+            if(FD_ISSET(sock,&readfds))
+            {
+                addrlen = sizeof(cl_addr);
+                received = recvfrom(sock,packet,sizeof(co_packet),0, (struct 
sockaddr *)&cl_addr, &addrlen);
+
+                if (received < 0)
+                {
+                    perror("error in recvfrom:");
+                    continue;
+                }
+                else if (received == 0)
+                    continue;
+
+                inet_ntop(AF_INET6, &cl_addr.sin6_addr, addr_string,
+                          INET6_ADDRSTRLEN);
+                PISA_DEBUG(PL_GENERIC,"received %i bytes from %s\n", received, 
addr_string);
+
+                if (pisa_ipv6_addr_is_hit(&cl_addr.sin6_addr))
+                {
+                    PISA_DEBUG(PL_GENERIC,"sender was a HIT, processing 
request.\n");
+                    handle_packet(&cl_addr,packet);
+                }
+                else
+                {
+                    PISA_DEBUG(PL_GENERIC,"sender was not a HIT, ignoring 
request.\n");
+                }
+
+                PISA_INFO("\nwaiting for incoming packet...\n");
+            }
+        }
+    }
+
+    pisa_hitlist_destroy(allowed);
+    pisa_cfg_cleanup();
+    pisa_cfg_authorized_hosts_cleanup();
+    free(packet);
+    free(addr_string);
+    close(sock);
+
+    return 0;
+}
+
+/**
+ * This function handles any packet received.
+ *
+ * @param socket_addr IP address where the packet was received
+ * @param co_packet A pointer to a co_packet_t structure
+ *
+ * @return 1 if successfully handled; 0 if packet unrecognized
+ */
+static int handle_packet(struct sockaddr_in6 *socket_addr, co_packet *packet)
+{
+    int result;
+
+    assert(socket_addr != NULL);
+    assert(packet != NULL);
 
-       pisa_hitlist_destroy(allowed);
-       configCleanup();
-       close(sock);
-       free(buf);
-       free(addr_string);
+    switch (packet->message_type)
+    {
+    case MESSAGE_CERTIFICATE_REQUEST:
+        result = 
handle_certificate_request(socket_addr,&(packet->message.request));
+        break;
+    case MESSAGE_ERROR:
+        PISA_ERROR("Error: %i\n",packet->message.error.error_type);
+        result = 0;
+        break;
+    default:
+        result = 0;
+        break;
+    }
 
-       return 0;
+    return result;
 }
+
+static int handle_certificate_request(struct sockaddr_in6 
*socket_addr,co_certificate_request *request)
+{
+    return answer_certificate_query(socket_addr);
+}
+

Modified: trunk/community-operator/hipl.c
==============================================================================
--- trunk/community-operator/hipl.c     Wed Oct 14 17:12:26 2009        (r1151)
+++ trunk/community-operator/hipl.c     Wed Oct 14 17:22:24 2009        (r1152)
@@ -14,9 +14,15 @@
 #include <string.h>
 #include <netinet/in.h>
 
+#ifdef HIPL_CERTIFICATE_CHANGES
+int createCertificate(time_t *not_before, time_t *not_after,
+                     struct in6_addr *hit, struct in6_addr *issuer_hit,
+                     int parallel_users, char *certificate, size_t size)
+#else
 int createCertificate(time_t *not_before, time_t *not_after,
                      struct in6_addr *hit, struct in6_addr *issuer_hit,
                      char *certificate, size_t size)
+#endif
 {
 #ifdef CONFIG_PISA_WITH_HIPL
        struct hip_cert_spki_info cert = { 0 };
@@ -26,8 +32,13 @@
                return -1;
        }
 
+#ifdef HIPL_CERTIFICATE_CHANGES
        hip_cert_spki_create_cert(&cert, "hit", issuer_hit, "hit", hit,
                                  not_before, not_after);
+#else
+       hip_cert_spki_create_cert(&cert, "hit", issuer_hit, "hit", hit,
+                                 not_before, not_after, parallel_users);
+#endif
 
        snprintf(certificate, size, "(sequence %s%s%s)", cert.public_key,
                 cert.cert, cert.signature);

Modified: trunk/community-operator/hipl.h
==============================================================================
--- trunk/community-operator/hipl.h     Wed Oct 14 17:12:26 2009        (r1151)
+++ trunk/community-operator/hipl.h     Wed Oct 14 17:22:24 2009        (r1152)
@@ -7,9 +7,27 @@
 #define PISA_HIPL_H
 
 #include <time.h>
-#include <string.h>
 #include <netinet/in.h>
 
+#ifdef HIPL_CERTIFICATE_CHANGES
+/**
+ * Create the certificate with the given parameters. This is a wrapper
+ * function for hip_cert_spki_create_cert. It requires a running hipd on
+ * the same machine and superuser privileges.
+ *
+ * @param not_before start of certificate lifetime
+ * @param not_after end of certificate lifetime
+ * @param hit HIT of subject (the home router HIT)
+ * @param issuer_hit HIT of issuer (the community operator HIT)
+ * @param certificate buffer to store the resulting certificate in
+ * @param size size of the certificate buffer
+ * @param parallel_users The number of allowed parallel users
+ * @return 0 on success
+ */
+int createCertificate(time_t *not_before, time_t *not_after,
+                     struct in6_addr *hit, struct in6_addr *issuer_hit,
+                     int parallel_users, char *certificate, size_t size);
+#else
 /**
  * Create the certificate with the given parameters. This is a wrapper
  * function for hip_cert_spki_create_cert. It requires a running hipd on
@@ -26,7 +44,7 @@
 int createCertificate(time_t *not_before, time_t *not_after,
                      struct in6_addr *hit, struct in6_addr *issuer_hit,
                      char *certificate, size_t size);
-
+#endif
 /**
  * Get the default hit of the local HIPD. Requires a running hipd on the same
  * machine. Sends a query to hipd and expects the default HIT to be returned.

Other related posts: