d44645d7016e8e2426ab9b6f0f820d0dd8006a77
[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 #include "messages/tnccs_error_msg.h"
18
19 #include <debug.h>
20 #include <utils/linked_list.h>
21 #include <tnc/tnccs/tnccs.h>
22
23 #include <libxml/parser.h>
24
25 typedef struct private_tnccs_batch_t private_tnccs_batch_t;
26
27 /**
28 * Private data of a tnccs_batch_t object.
29 *
30 */
31 struct private_tnccs_batch_t {
32 /**
33 * Public tnccs_batch_t interface.
34 */
35 tnccs_batch_t public;
36
37 /**
38 * Batch ID
39 */
40 int batch_id;
41
42 /**
43 * TNCC if TRUE, TNCS if FALSE
44 */
45 bool is_server;
46
47 /**
48 * linked list of TNCCS messages
49 */
50 linked_list_t *messages;
51
52 /**
53 * linked list of TNCCS error messages
54 */
55 linked_list_t *errors;
56
57 /**
58 * XML document
59 */
60 xmlDocPtr doc;
61
62 /**
63 * Encoded message
64 */
65 chunk_t encoding;
66 };
67
68 METHOD(tnccs_batch_t, get_encoding, chunk_t,
69 private_tnccs_batch_t *this)
70 {
71 return this->encoding;
72 }
73
74 METHOD(tnccs_batch_t, add_msg, void,
75 private_tnccs_batch_t *this, tnccs_msg_t* msg)
76 {
77 xmlNodePtr root;
78
79 DBG2(DBG_TNC, "adding %N message", tnccs_msg_type_names,
80 msg->get_type(msg));
81 this->messages->insert_last(this->messages, msg);
82 root = xmlDocGetRootElement(this->doc);
83 xmlAddChild(root, msg->get_node(msg));
84 }
85
86 METHOD(tnccs_batch_t, build, void,
87 private_tnccs_batch_t *this)
88 {
89 xmlChar *xmlbuf;
90 int buf_size;
91
92 xmlDocDumpFormatMemory(this->doc, &xmlbuf, &buf_size, 1);
93 this->encoding = chunk_create((u_char*)xmlbuf, buf_size);
94 this->encoding = chunk_clone(this->encoding);
95 xmlFree(xmlbuf);
96 }
97
98 METHOD(tnccs_batch_t, process, status_t,
99 private_tnccs_batch_t *this)
100 {
101 tnccs_msg_t *tnccs_msg, *msg;
102 tnccs_error_type_t error_type = TNCCS_ERROR_OTHER;
103 char *error_msg, buf[BUF_LEN];
104 xmlNodePtr cur;
105 xmlNsPtr ns;
106 xmlChar *batchid, *recipient;
107 int batch_id;
108
109 status_t status;
110
111 this->doc = xmlParseMemory(this->encoding.ptr, this->encoding.len);
112 if (!this->doc)
113 {
114 error_type = TNCCS_ERROR_MALFORMED_BATCH;
115 error_msg = "failed to parse XML message";
116 goto fatal;
117 }
118
119 /* check out the XML document */
120 cur = xmlDocGetRootElement(this->doc);
121 if (!cur)
122 {
123 error_type = TNCCS_ERROR_MALFORMED_BATCH;
124 error_msg = "empty XML document";
125 goto fatal;
126 }
127
128 /* check TNCCS namespace */
129 ns = xmlSearchNsByHref(this->doc, cur, (const xmlChar*)
130 "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#");
131 if (!ns)
132 {
133 error_type = TNCCS_ERROR_MALFORMED_BATCH;
134 error_msg = "TNCCS namespace not found";
135 goto fatal;
136 }
137
138 /* check XML document type */
139 if (xmlStrcmp(cur->name, (const xmlChar*)"TNCCS-Batch"))
140 {
141 error_type = TNCCS_ERROR_MALFORMED_BATCH;
142 error_msg = buf;
143 snprintf(buf, BUF_LEN, "wrong XML document type '%s', expected TNCCS-Batch",
144 cur->name);
145 goto fatal;
146 }
147
148 /* check presence of BatchID property */
149 batchid = xmlGetProp(cur, (const xmlChar*)"BatchId");
150 if (!batchid)
151 {
152 error_type = TNCCS_ERROR_INVALID_BATCH_ID;
153 error_msg = "BatchId is missing";
154 goto fatal;
155 }
156
157 /* check BatchID */
158 batch_id = atoi((char*)batchid);
159 xmlFree(batchid);
160 if (batch_id != this->batch_id)
161 {
162 error_type = TNCCS_ERROR_INVALID_BATCH_ID;
163 error_msg = buf;
164 snprintf(buf, BUF_LEN, "BatchId %d expected, got %d", this->batch_id,
165 batch_id);
166 goto fatal;
167 }
168
169 /* check presence of Recipient property */
170 recipient = xmlGetProp(cur, (const xmlChar*)"Recipient");
171 if (!recipient)
172 {
173 error_type = TNCCS_ERROR_INVALID_RECIPIENT_TYPE;
174 error_msg = "Recipient is missing";
175 goto fatal;
176 }
177
178 /* check recipient */
179 if (!streq((char*)recipient, this->is_server ? "TNCS" : "TNCC"))
180 {
181 error_type = TNCCS_ERROR_INVALID_RECIPIENT_TYPE;
182 error_msg = buf;
183 snprintf(buf, BUF_LEN, "message recipient expected '%s', got '%s'",
184 this->is_server ? "TNCS" : "TNCC", (char*)recipient);
185 xmlFree(recipient);
186 goto fatal;
187 }
188 xmlFree(recipient);
189
190 DBG2(DBG_TNC, "processing TNCCS Batch #%d", batch_id);
191
192 /* Now walk the tree, handling message nodes as we go */
193 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next)
194 {
195 /* ignore empty or blank nodes */
196 if (xmlIsBlankNode(cur))
197 {
198 continue;
199 }
200
201 /* ignore nodes with wrong namespace */
202 if (cur->ns != ns)
203 {
204 DBG1(DBG_TNC, "ignoring message node '%s' having wrong namespace",
205 (char*)cur->name);
206 continue;
207 }
208
209 tnccs_msg = tnccs_msg_create_from_node(cur);
210 if (!tnccs_msg)
211 {
212 continue;
213 }
214
215 DBG2(DBG_TNC, "processing %N message", tnccs_msg_type_names,
216 tnccs_msg->get_type(tnccs_msg));
217 status = tnccs_msg->process(tnccs_msg);
218 if (status == FAILED)
219 {
220 tnccs_msg->destroy(tnccs_msg);
221 return FAILED;
222 }
223 this->messages->insert_last(this->messages, tnccs_msg);
224 }
225 return SUCCESS;
226
227 fatal:
228 DBG1(DBG_TNC, "%s", error_msg);
229 msg = tnccs_error_msg_create(error_type, error_msg);
230 this->errors->insert_last(this->errors, msg);
231 return FAILED;
232
233 }
234
235 METHOD(tnccs_batch_t, create_msg_enumerator, enumerator_t*,
236 private_tnccs_batch_t *this)
237 {
238 return this->messages->create_enumerator(this->messages);
239 }
240
241 METHOD(tnccs_batch_t, destroy, void,
242 private_tnccs_batch_t *this)
243 {
244 this->messages->destroy_offset(this->messages,
245 offsetof(tnccs_msg_t, destroy));
246 this->errors->destroy_offset(this->errors,
247 offsetof(tnccs_msg_t, destroy));
248 xmlFreeDoc(this->doc);
249 free(this->encoding.ptr);
250 free(this);
251 }
252
253 /**
254 * See header
255 */
256 tnccs_batch_t* tnccs_batch_create(bool is_server, int batch_id)
257 {
258 private_tnccs_batch_t *this;
259 xmlNodePtr n;
260 char buf[12];
261 const char *recipient;
262
263 INIT(this,
264 .public = {
265 .get_encoding = _get_encoding,
266 .add_msg = _add_msg,
267 .build = _build,
268 .process = _process,
269 .create_msg_enumerator = _create_msg_enumerator,
270 .destroy = _destroy,
271 },
272 .is_server = is_server,
273 .messages = linked_list_create(),
274 .errors = linked_list_create(),
275 .batch_id = batch_id,
276 .doc = xmlNewDoc(BAD_CAST "1.0"),
277 );
278
279 DBG2(DBG_TNC, "creating TNCCS Batch #%d", this->batch_id);
280 n = xmlNewNode(NULL, BAD_CAST "TNCCS-Batch");
281 snprintf(buf, sizeof(buf), "%d", batch_id);
282 recipient = this->is_server ? "TNCC" : "TNCS";
283 xmlNewProp(n, BAD_CAST "BatchId", BAD_CAST buf);
284 xmlNewProp(n, BAD_CAST "Recipient", BAD_CAST recipient);
285 xmlNewProp(n, BAD_CAST "xmlns", BAD_CAST "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#");
286 xmlNewProp(n, BAD_CAST "xmlns:xsi", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
287 xmlNewProp(n, BAD_CAST "xsi:schemaLocation", BAD_CAST "http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS# "
288 "https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd");
289 xmlDocSetRootElement(this->doc, n);
290
291 return &this->public;
292 }
293
294 /**
295 * See header
296 */
297 tnccs_batch_t* tnccs_batch_create_from_data(bool is_server, int batch_id, chunk_t data)
298 {
299 private_tnccs_batch_t *this;
300
301 INIT(this,
302 .public = {
303 .get_encoding = _get_encoding,
304 .add_msg = _add_msg,
305 .build = _build,
306 .process = _process,
307 .create_msg_enumerator = _create_msg_enumerator,
308 .destroy = _destroy,
309 },
310 .is_server = is_server,
311 .batch_id = batch_id,
312 .messages = linked_list_create(),
313 .errors = linked_list_create(),
314 .encoding = chunk_clone(data),
315 );
316
317 return &this->public;
318 }
319