updated XML interface to new schema
[strongswan.git] / src / charon / control / interfaces / xml_interface.c
index 9923774..389aeed 100644 (file)
@@ -39,8 +39,6 @@
 #include <daemon.h>
 #include <processing/jobs/callback_job.h>
 
-static struct sockaddr_un socket_addr = { AF_UNIX, "/var/run/charon.xml"};
-
 
 typedef struct private_xml_interface_t private_xml_interface_t;
 
@@ -65,27 +63,231 @@ struct private_xml_interface_t {
        callback_job_t *job;
 };
 
+ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING,
+       "created",
+       "connecting",
+       "established",
+       "rekeying",
+       "deleting",
+);
+
+/**
+ * write a bool into element
+ */
+static void write_bool(xmlTextWriterPtr writer, char *element, bool val)
+{
+       xmlTextWriterWriteElement(writer, element, val ? "true" : "false");
+}
+
+/**
+ * write a identification_t into element
+ */
+static void write_id(xmlTextWriterPtr writer, char *element, identification_t *id)
+{
+       xmlTextWriterStartElement(writer, element);
+       switch (id->get_type(id))
+       {
+               {
+                       char *type = "";
+                       while (TRUE)
+                       {
+                               case ID_IPV4_ADDR:
+                                       type = "ipv4";
+                                       break;
+                               case ID_IPV6_ADDR:
+                                       type = "ipv6";
+                                       break;
+                               case ID_FQDN:
+                                       type = "fqdn";
+                                       break;
+                               case ID_RFC822_ADDR:
+                                       type = "email";
+                                       break;
+                               case ID_DER_ASN1_DN:
+                                       type = "asn1dn";
+                                       break;
+                               case ID_DER_ASN1_GN:
+                                       type = "asn1gn";
+                                       break;
+                       }
+                       xmlTextWriterWriteAttribute(writer, "type", type);
+                       xmlTextWriterWriteFormatString(writer, "%D", id);
+                       break;
+               }
+               case ID_ANY:
+                       xmlTextWriterWriteAttribute(writer, "type", "any");
+                       break;
+               default:
+                       /* TODO: base64 keyid */
+                       xmlTextWriterWriteAttribute(writer, "type", "keyid");
+                       break;
+       }
+       xmlTextWriterEndElement(writer);
+}
+
+/**
+ * write a host_t address into an element
+ */
+static void write_address(xmlTextWriterPtr writer, char *element, host_t *host)
+{
+       xmlTextWriterStartElement(writer, element);
+       xmlTextWriterWriteAttribute(writer, "type",
+                                               host->get_family(host) == AF_INET ? "ipv4" : "ipv6");
+       if (host->is_anyaddr(host))
+       {       /* do not use %any for XML */
+               xmlTextWriterWriteFormatString(writer, "%s",
+                                               host->get_family(host) == AF_INET ? "0.0.0.0" : "::");
+       }
+       else
+       {
+               xmlTextWriterWriteFormatString(writer, "%H", host);
+       }
+       xmlTextWriterEndElement(writer);
+}
+
+/**
+ * process a ikesalist query request message
+ */
+static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
+{
+       iterator_t *iterator;
+       ike_sa_t *ike_sa;
+
+       /* <ikesalist> */
+       xmlTextWriterStartElement(writer, "ikesalist");
+       
+       iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+       while (iterator->iterate(iterator, (void**)&ike_sa))
+       {
+               ike_sa_id_t *id;
+               host_t *local, *remote;
+               iterator_t *children;
+               child_sa_t *child_sa;
+               
+               id = ike_sa->get_id(ike_sa);
+               
+               xmlTextWriterStartElement(writer, "ikesa");
+               xmlTextWriterWriteFormatElement(writer, "id", "%d",
+                                                       ike_sa->get_unique_id(ike_sa));
+               xmlTextWriterWriteFormatElement(writer, "status", "%N", 
+                                                       ike_sa_state_lower_names, ike_sa->get_state(ike_sa));
+               xmlTextWriterWriteElement(writer, "role",
+                                                       id->is_initiator(id) ? "initiator" : "responder");
+               xmlTextWriterWriteElement(writer, "peerconfig", ike_sa->get_name(ike_sa));
+               
+               /* <local> */
+               local = ike_sa->get_my_host(ike_sa);
+               xmlTextWriterStartElement(writer, "local");
+               xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
+                                                       id->is_initiator(id) ? id->get_initiator_spi(id)
+                                                                                                : id->get_responder_spi(id));
+               write_id(writer, "identification", ike_sa->get_my_id(ike_sa));
+               write_address(writer, "address", local);
+               xmlTextWriterWriteFormatElement(writer, "port", "%d",
+                                                       local->get_port(local));
+               if (ike_sa->supports_extension(ike_sa, EXT_NATT))
+               {
+                       write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_HERE));
+               }
+               /* </local> */
+               
+               /* <remote> */
+               remote = ike_sa->get_other_host(ike_sa);
+               xmlTextWriterStartElement(writer, "remote");
+               xmlTextWriterWriteFormatElement(writer, "spi", "%.16llx",
+                                                       id->is_initiator(id) ? id->get_responder_spi(id)
+                                                                                                : id->get_initiator_spi(id));
+               write_id(writer, "identification", ike_sa->get_other_id(ike_sa));
+               write_address(writer, "address", remote);
+               xmlTextWriterWriteFormatElement(writer, "port", "%d",
+                                                       remote->get_port(remote));
+               if (ike_sa->supports_extension(ike_sa, EXT_NATT))
+               {
+                       write_bool(writer, "nat", ike_sa->has_condition(ike_sa, COND_NAT_THERE));
+               }
+               /* </remote> */         
+               
+               /* <childsalist> */
+               xmlTextWriterStartElement(writer, "childsalist");
+               children = ike_sa->create_child_sa_iterator(ike_sa);
+               while (children->iterate(children, (void**)&child_sa))
+               {
+                       /* TODO: Children */
+               }
+               children->destroy(children);
+               /* </childsalist> */
+               xmlTextWriterEndElement(writer);                
+               
+               /* </ikesa> */
+               xmlTextWriterEndElement(writer);
+       }
+       iterator->destroy(iterator);
+       
+       /* </ikesalist> */
+       xmlTextWriterEndElement(writer);
+}
+
+/**
+ * process a query request
+ */
+static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
+{
+       /* <query> */
+       xmlTextWriterStartElement(writer, "query");
+    while (xmlTextReaderRead(reader))
+    {
+               if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
+               {
+                       if (streq(xmlTextReaderConstName(reader), "ikesalist"))
+                       {
+                               request_query_ikesa(reader, writer);
+                               break;
+                       }
+               }
+       }
+       /* </query> */
+       xmlTextWriterEndElement(writer);
+}
+
 /**
- * process a getRequest message
+ * process a request message
  */
-static void process_get(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
+static void request(xmlTextReaderPtr reader, char *id, int fd)
 {
-       if (/* <GetResponse> */
-               xmlTextWriterStartElement(writer, "GetResponse") < 0 ||
-               /*   <Status Code="200"><Message/></Status> */
-               xmlTextWriterStartElement(writer, "Status") < 0 ||
-               xmlTextWriterWriteAttribute(writer, "Code", "200") < 0  ||
-               xmlTextWriterStartElement(writer, "Message") < 0 ||
-               xmlTextWriterEndElement(writer) < 0 ||
-               xmlTextWriterEndElement(writer) < 0 ||
-               /*   <ConnectionList/> */
-               xmlTextWriterStartElement(writer, "ConnectionList") < 0 ||
-               xmlTextWriterEndElement(writer) < 0 ||
-               /* </GetResponse> */
-               xmlTextWriterEndElement(writer) < 0)
+       xmlTextWriterPtr writer;
+       
+       writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
+       if (writer == NULL)
        {
-               DBG1(DBG_CFG, "error writing XML document (GetResponse)");
+               DBG1(DBG_CFG, "opening SMP XML writer failed");
+               return;
        }
+
+       xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
+       /* <message xmlns="http://www.strongswan.org/smp/1.0"
+               id="id" type="response"> */
+       xmlTextWriterStartElement(writer, "message");
+       xmlTextWriterWriteAttribute(writer, "xmlns",
+                                                               "http://www.strongswan.org/smp/1.0");
+       xmlTextWriterWriteAttribute(writer, "id", id);
+       xmlTextWriterWriteAttribute(writer, "type", "response");
+
+       while (xmlTextReaderRead(reader))
+       {
+               if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
+               {
+                       if (streq(xmlTextReaderConstName(reader), "query"))
+                       {
+                               request_query(reader, writer);
+                               break;
+                       }
+               }
+       }
+       /*   </message> and close document */
+       xmlTextWriterEndDocument(writer);
+       xmlFreeTextWriter(writer);
+       /* write a newline to indicate end of xml */
+       write(fd, "\n", 1);
 }
 
 /**
@@ -97,11 +299,13 @@ static job_requeue_t process(int *fdp)
        char buffer[4096];
        size_t len;
        xmlTextReaderPtr reader;
-       xmlTextWriterPtr writer;
+       char *id = NULL, *type = NULL;
        
+       pthread_cleanup_push((void*)close, (void*)fd);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
        len = read(fd, buffer, sizeof(buffer));
        pthread_setcancelstate(oldstate, NULL);
+       pthread_cleanup_pop(0);
        if (len <= 0)
        {
                close(fd);
@@ -116,65 +320,32 @@ static job_requeue_t process(int *fdp)
                return JOB_REQUEUE_FAIR;;
        }
        
-       writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
-       if (writer == NULL)
-       {
-               xmlFreeTextReader(reader);
-               DBG1(DBG_CFG, "opening SMP XML writer failed");
-               return JOB_REQUEUE_FAIR;;
-       }
-       
-       /* create the standard message parts */
-       if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) < 0 ||
-               /* <SMPMessage xmlns="http://www.strongswan.org/smp/1.0"> */
-               xmlTextWriterStartElement(writer, "SMPMessage") < 0 ||
-               xmlTextWriterWriteAttribute(writer, "xmlns",
-                                               "http://www.strongswan.org/smp/1.0") < 0 ||
-               /* <Body> */
-               xmlTextWriterStartElement(writer, "Body") < 0)
-       {
-               xmlFreeTextReader(reader);
-               xmlFreeTextWriter(writer);
-               DBG1(DBG_CFG, "creating SMP XML message failed");
-               return JOB_REQUEUE_FAIR;;
-       }
-       
-    while (TRUE)
+       /* read message type and id */
+    while (xmlTextReaderRead(reader))
     {
-       switch (xmlTextReaderRead(reader))
-       {
-               case 1:
-               {
-                               if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
-                               {
-                                       if (streq(xmlTextReaderConstName(reader), "GetRequest"))
-                                       {
-                                               process_get(reader, writer);
-                                               break;
-                                       }
-                               }
-                               continue;
-                       }
-                       case 0:
-                           /* end of XML */
-                           break;
-                       default:
-                           DBG1(DBG_CFG, "parsing SMP XML message failed");
-                           break;
+               if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT &&
+                       streq(xmlTextReaderConstName(reader), "message"))
+               {
+                       id = xmlTextReaderGetAttribute(reader, "id");
+                       type = xmlTextReaderGetAttribute(reader, "type");
+                       break;
                }
-        xmlFreeTextReader(reader);
-        break;
-    }
-    /* write </Body></SMPMessage> and close document */
-    if (xmlTextWriterEndDocument(writer) < 0)
-    {
-               DBG1(DBG_CFG, "completing SMP XML message failed");
     }
-    xmlFreeTextWriter(writer);
     
-    /* write a newline to indicate end of xml */
-    write(fd, "\n", 1);
-    return JOB_REQUEUE_FAIR;;
+    /* process message */
+    if (id && type)
+       {
+           if (streq(type, "request"))
+           {
+               request(reader, id, fd);
+           }
+           else
+           {
+               /* response(reader, id) */
+           }
+    }
+       xmlFreeTextReader(reader);
+       return JOB_REQUEUE_FAIR;;
 }
 
 /**
@@ -206,13 +377,16 @@ static job_requeue_t dispatch(private_xml_interface_t *this)
        return JOB_REQUEUE_DIRECT;
 }
 
+struct sockaddr_un unix_addr = { AF_UNIX, "/var/run/charon.xml"};
+
 /**
  * Implementation of itnerface_t.destroy.
  */
 static void destroy(private_xml_interface_t *this)
 {
        this->job->cancel(this->job);
-       unlink(socket_addr.sun_path);
+       close(this->socket);
+       //unlink(unix_addr.sun_path);
        free(this);
 }
 
@@ -222,12 +396,13 @@ static void destroy(private_xml_interface_t *this)
 interface_t *interface_create()
 {
        private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
-       mode_t old;
+       //mode_t old;
+       struct sockaddr_in tcp_addr;
 
        this->public.interface.destroy = (void (*)(interface_t*))destroy;
        
        /* set up unix socket */
-       this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       this->socket = socket(AF_INET, SOCK_STREAM, 0);//socket(AF_UNIX, SOCK_STREAM, 0);
        if (this->socket == -1)
        {
                DBG1(DBG_CFG, "could not create XML socket");
@@ -235,6 +410,19 @@ interface_t *interface_create()
                return NULL;
        }
        
+       memset(&tcp_addr, 0, sizeof(tcp_addr));
+       tcp_addr.sin_family = AF_INET;
+       tcp_addr.sin_addr.s_addr = INADDR_ANY;
+       tcp_addr.sin_port = htons(4502);
+       if (bind(this->socket, (struct sockaddr*)&tcp_addr, sizeof(tcp_addr)) < 0)
+       {
+               DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
+               close(this->socket);
+               free(this);
+               return NULL;
+       }
+       
+       /*
        old = umask(~S_IRWXU);
        if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
        {
@@ -243,9 +431,9 @@ interface_t *interface_create()
                free(this);
                return NULL;
        }
-       umask(old);
+       umask(old);*/
        
-       if (listen(this->socket, 0) < 0)
+       if (listen(this->socket, 5) < 0)
        {
                DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
                close(this->socket);