implemented TNCCS 1.1 without libtnc
[strongswan.git] / src / libcharon / plugins / tnccs_11 / batch / tnccs_batch.c
1 /*
2 * Copyright (C) 2006 Mike McCauley (mikem@open.com.au)
3 * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tnccs_batch.h"
17
18 #include <debug.h>
19 #include <utils/linked_list.h>
20 #include <tnc/tnccs/tnccs.h>
21
22 #include <libxml/parser.h>
23
24 typedef struct private_tnccs_batch_t private_tnccs_batch_t;
25
26 /**
27 * Private data of a tnccs_batch_t object.
28 *
29 */
30 struct private_tnccs_batch_t {
31 /**
32 * Public tnccs_batch_t interface.
33 */
34 tnccs_batch_t public;
35
36 /**
37 * Batch ID
38 */
39 int batch_id;
40
41 /**
42 * TNCC if TRUE, TNCS if FALSE
43 */
44 bool is_server;
45
46 /**
47 * linked list of TNCCS messages
48 */
49 linked_list_t *messages;
50
51 /**
52 * XML document
53 */
54 xmlDocPtr doc;
55
56 /**
57 * Encoded message
58 */
59 chunk_t encoding;
60 };
61
62 METHOD(tnccs_batch_t, get_encoding, chunk_t,
63 private_tnccs_batch_t *this)
64 {
65 return this->encoding;
66 }
67
68 METHOD(tnccs_batch_t, add_msg, void,
69 private_tnccs_batch_t *this, tnccs_msg_t* msg)
70 {
71 xmlNodePtr root;
72
73 DBG2(DBG_TNC, "adding %N message", tnccs_msg_type_names,
74 msg->get_type(msg));
75 this->messages->insert_last(this->messages, msg);
76 root = xmlDocGetRootElement(this->doc);
77 xmlAddChild(root, msg->get_node(msg));
78 }
79
80 METHOD(tnccs_batch_t, build, void,
81 private_tnccs_batch_t *this)
82 {
83 xmlChar *xmlbuf;
84 int buf_size;
85
86 xmlDocDumpFormatMemory(this->doc, &xmlbuf, &buf_size, 1);
87 this->encoding = chunk_create((u_char*)xmlbuf, buf_size);
88 this->encoding = chunk_clone(this->encoding);
89 xmlFree(xmlbuf);
90 }
91
92 METHOD(tnccs_batch_t, process, status_t,
93 private_tnccs_batch_t *this)
94 {
95 tnccs_msg_t *tnccs_msg;
96 xmlNodePtr cur;
97 xmlNsPtr ns;
98 xmlChar *batchid, *recipient;
99 int batch_id;
100
101 status_t status;
102
103 this->doc = xmlParseMemory(this->encoding.ptr, this->encoding.len);
104 if (!this->doc)
105 {
106 DBG1(DBG_TNC, "failed to parse XML message");
107 return FAILED;
108 }
109
110 /* check out the XML document */
111 cur = xmlDocGetRootElement(this->doc);
112 if (!cur)
113 {
114 DBG1(DBG_TNC, "empty XML document");
115 return FAILED;
116 }
117
118 /* check TNCCS namespace */
119 ns = xmlSearchNsByHref(this->doc, cur, (const xmlChar*)
120 "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#");
121 if (!ns)
122 {
123 DBG1(DBG_TNC, "TNCCS namespace not found");
124 return FAILED;
125 }
126
127 /* check XML document type */
128 if (xmlStrcmp(cur->name, (const xmlChar*)"TNCCS-Batch"))
129 {
130 DBG1(DBG_TNC, "wrong XML document type '%s', expected TNCCS-Batch",
131 cur->name);
132 return FAILED;
133 }
134
135 /* check presence of BatchID property */
136 batchid = xmlGetProp(cur, (const xmlChar*)"BatchId");
137 if (!batchid)
138 {
139 DBG1(DBG_TNC, "BatchId is missing");
140 return FAILED;
141 }
142
143 /* check BatchID */
144 batch_id = atoi((char*)batchid);
145 xmlFree(batchid);
146 if (batch_id != this->batch_id)
147 {
148 DBG1(DBG_TNC, "BatchID %d expected, got %d", this->batch_id, batch_id);
149 return FAILED;
150 }
151
152 /* check presence of Recipient property */
153 recipient = xmlGetProp(cur, (const xmlChar*)"Recipient");
154 if (!recipient)
155 {
156 DBG1(DBG_TNC, "Recipient is missing");
157 return FAILED;
158 }
159
160 /* check recipient */
161 if (!streq((char*)recipient, this->is_server ? "TNCS" : "TNCC"))
162 {
163 DBG1(DBG_TNC, "message recipient expected '%s', got '%s'",
164 this->is_server ? "TNCS" : "TNCC", (char*)recipient);
165 xmlFree(recipient);
166 return FAILED;
167 }
168 xmlFree(recipient);
169
170 /* Now walk the tree, handling message nodes as we go */
171 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
172 {
173 /* ignore empty or blank nodes */
174 if (xmlIsBlankNode(cur))
175 {
176 continue;
177 }
178
179 /* ignore nodes with wrong namespace */
180 if (cur->ns != ns)
181 {
182 DBG1(DBG_TNC, "ignoring message node '%s' having wrong namespace",
183 (char*)cur->name);
184 continue;
185 }
186
187 tnccs_msg = tnccs_msg_create_from_node(cur);
188 if (!tnccs_msg)
189 {
190 continue;
191 }
192
193 status = tnccs_msg->process(tnccs_msg);
194 if (status == FAILED)
195 {
196 tnccs_msg->destroy(tnccs_msg);
197 return FAILED;
198 }
199 this->messages->insert_last(this->messages, tnccs_msg);
200 }
201 return SUCCESS;
202 }
203
204 METHOD(tnccs_batch_t, create_msg_enumerator, enumerator_t*,
205 private_tnccs_batch_t *this)
206 {
207 return this->messages->create_enumerator(this->messages);
208 }
209
210 METHOD(tnccs_batch_t, destroy, void,
211 private_tnccs_batch_t *this)
212 {
213 this->messages->destroy_offset(this->messages,
214 offsetof(tnccs_msg_t, destroy));
215 xmlFreeDoc(this->doc);
216 free(this->encoding.ptr);
217 free(this);
218 }
219
220 /**
221 * See header
222 */
223 tnccs_batch_t* tnccs_batch_create(bool is_server, int batch_id)
224 {
225 private_tnccs_batch_t *this;
226 xmlNodePtr n;
227 char buf[12];
228 const char *recipient;
229
230 INIT(this,
231 .public = {
232 .get_encoding = _get_encoding,
233 .add_msg = _add_msg,
234 .build = _build,
235 .process = _process,
236 .create_msg_enumerator = _create_msg_enumerator,
237 .destroy = _destroy,
238 },
239 .is_server = is_server,
240 .messages = linked_list_create(),
241 .batch_id = batch_id,
242 .doc = xmlNewDoc(BAD_CAST "1.0"),
243 );
244
245 DBG2(DBG_TNC, "creating TNCCS Batch #%d", this->batch_id);
246 n = xmlNewNode(NULL, BAD_CAST "TNCCS-Batch");
247 snprintf(buf, sizeof(buf), "%d", batch_id);
248 recipient = this->is_server ? "TNCC" : "TNCS";
249 xmlNewProp(n, BAD_CAST "BatchId", BAD_CAST buf);
250 xmlNewProp(n, BAD_CAST "Recipient", BAD_CAST recipient);
251 xmlNewProp(n, BAD_CAST "xmlns", BAD_CAST "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#");
252 xmlNewProp(n, BAD_CAST "xmlns:xsi", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
253 xmlNewProp(n, BAD_CAST "xsi:schemaLocation", BAD_CAST "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS# "
254 "https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd");
255 xmlDocSetRootElement(this->doc, n);
256
257 return &this->public;
258 }
259
260 /**
261 * See header
262 */
263 tnccs_batch_t* tnccs_batch_create_from_data(bool is_server, int batch_id, chunk_t data)
264 {
265 private_tnccs_batch_t *this;
266
267 INIT(this,
268 .public = {
269 .get_encoding = _get_encoding,
270 .add_msg = _add_msg,
271 .build = _build,
272 .process = _process,
273 .create_msg_enumerator = _create_msg_enumerator,
274 .destroy = _destroy,
275 },
276 .is_server = is_server,
277 .batch_id = batch_id,
278 .messages = linked_list_create(),
279 .encoding = chunk_clone(data),
280 );
281
282 return &this->public;
283 }
284