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(¬_before); - time(¬_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(¬_before, ¬_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(¬_before); + time(¬_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(¬_before, ¬_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.