]>
Commit | Line | Data |
---|---|---|
4333c48a AS |
1 | /* |
2 | * Copyright (C) 2010 Sansar Choinyanbuu | |
80322d2c | 3 | * Copyright (C) 2010-2015 Andreas Steffen |
4333c48a AS |
4 | * HSR Hochschule fuer Technik Rapperswil |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | */ | |
16 | ||
4333c48a | 17 | #include "pb_tnc_batch.h" |
ddfc5896 | 18 | #include "messages/ietf/pb_error_msg.h" |
4dda2984 | 19 | #include "messages/ietf/pb_pa_msg.h" |
5988fc0d | 20 | #include "state_machine/pb_tnc_state_machine.h" |
4333c48a | 21 | |
f0a8bf47 AS |
22 | #include <tnc/tnccs/tnccs.h> |
23 | ||
12642a68 | 24 | #include <collections/linked_list.h> |
7e432eff AS |
25 | #include <bio/bio_writer.h> |
26 | #include <bio/bio_reader.h> | |
7c4d4d20 | 27 | #include <pen/pen.h> |
f05b4272 | 28 | #include <utils/debug.h> |
4333c48a | 29 | |
4333c48a AS |
30 | ENUM(pb_tnc_batch_type_names, PB_BATCH_CDATA, PB_BATCH_CLOSE, |
31 | "CDATA", | |
32 | "SDATA", | |
33 | "RESULT", | |
34 | "CRETRY", | |
35 | "SRETRY", | |
36 | "CLOSE" | |
37 | ); | |
38 | ||
39 | typedef struct private_pb_tnc_batch_t private_pb_tnc_batch_t; | |
40 | ||
41 | /** | |
42 | * PB-Batch Header (see section 4.1 of RFC 5793) | |
43 | * | |
44 | * 0 1 2 3 | |
45 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
46 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
47 | * | Version |D| Reserved | B-Type| | |
48 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
49 | * | Batch Length | | |
50 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
51 | */ | |
52 | ||
53 | #define PB_TNC_BATCH_FLAG_NONE 0x00 | |
54 | #define PB_TNC_BATCH_FLAG_D (1<<7) | |
4333c48a AS |
55 | |
56 | /** | |
57 | * PB-TNC Message (see section 4.2 of RFC 5793) | |
58 | * | |
59 | * 0 1 2 3 | |
60 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
61 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
62 | * | Flags | PB-TNC Vendor ID | | |
63 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
64 | * | PB-TNC Message Type | | |
65 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
66 | * | PB-TNC Message Length | | |
67 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
68 | * | PB-TNC Message Value (Variable Length) | | |
69 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
70 | */ | |
71 | ||
72 | #define PB_TNC_FLAG_NONE 0x00 | |
73 | #define PB_TNC_FLAG_NOSKIP (1<<7) | |
4333c48a AS |
74 | |
75 | #define PB_TNC_RESERVED_MSG_TYPE 0xffffffff | |
76 | ||
77 | /** | |
78 | * Private data of a pb_tnc_batch_t object. | |
79 | * | |
80 | */ | |
81 | struct private_pb_tnc_batch_t { | |
82 | /** | |
54eb669d | 83 | * Public pb_pa_msg_t interface. |
4333c48a AS |
84 | */ |
85 | pb_tnc_batch_t public; | |
86 | ||
87 | /** | |
80322d2c | 88 | * from TNC server if TRUE, from TNC client if FALSE |
4333c48a AS |
89 | */ |
90 | bool is_server; | |
91 | ||
92 | /** | |
93 | * PB-TNC Batch type | |
94 | */ | |
95 | pb_tnc_batch_type_t type; | |
96 | ||
a5c79d01 AS |
97 | /** |
98 | * Current PB-TNC Batch size | |
99 | */ | |
100 | size_t batch_len; | |
101 | ||
102 | /** | |
103 | * Maximum PB-TNC Batch size | |
104 | */ | |
105 | size_t max_batch_len; | |
106 | ||
4333c48a AS |
107 | /** |
108 | * linked list of PB-TNC messages | |
109 | */ | |
110 | linked_list_t *messages; | |
111 | ||
112 | /** | |
113 | * linked list of PB-TNC error messages | |
114 | */ | |
115 | linked_list_t *errors; | |
116 | ||
117 | /** | |
118 | * Encoded message | |
119 | */ | |
120 | chunk_t encoding; | |
121 | ||
122 | /** | |
123 | * Offset into encoding (used for error reporting) | |
124 | */ | |
54eb669d | 125 | u_int32_t offset; |
4333c48a AS |
126 | }; |
127 | ||
128 | METHOD(pb_tnc_batch_t, get_type, pb_tnc_batch_type_t, | |
129 | private_pb_tnc_batch_t *this) | |
130 | { | |
131 | return this->type; | |
132 | } | |
133 | ||
134 | METHOD(pb_tnc_batch_t, get_encoding, chunk_t, | |
135 | private_pb_tnc_batch_t *this) | |
136 | { | |
137 | return this->encoding; | |
138 | } | |
139 | ||
a5c79d01 | 140 | METHOD(pb_tnc_batch_t, add_msg, bool, |
54eb669d | 141 | private_pb_tnc_batch_t *this, pb_tnc_msg_t* msg) |
4333c48a | 142 | { |
ddfc5896 | 143 | enum_name_t *msg_type_names; |
a5c79d01 | 144 | chunk_t msg_value; |
ddfc5896 | 145 | pen_type_t msg_type; |
a5c79d01 AS |
146 | size_t msg_len; |
147 | ||
148 | msg->build(msg); | |
149 | msg_value = msg->get_encoding(msg); | |
4dda2984 | 150 | msg_len = PB_TNC_MSG_HEADER_SIZE + msg_value.len; |
a5c79d01 AS |
151 | |
152 | if (this->batch_len + msg_len > this->max_batch_len) | |
153 | { | |
154 | /* message just does not fit into this batch */ | |
155 | return FALSE; | |
156 | } | |
157 | this->batch_len += msg_len; | |
158 | ||
ddfc5896 AS |
159 | msg_type = msg->get_type(msg); |
160 | switch (msg_type.vendor_id) | |
161 | { | |
162 | default: | |
163 | case PEN_IETF: | |
164 | msg_type_names = pb_tnc_msg_type_names; | |
165 | break; | |
166 | case PEN_TCG: | |
167 | msg_type_names = pb_tnc_tcg_msg_type_names; | |
168 | break; | |
c6aed8aa AS |
169 | case PEN_ITA: |
170 | msg_type_names = pb_tnc_ita_msg_type_names; | |
171 | break; | |
ddfc5896 AS |
172 | } |
173 | DBG2(DBG_TNC, "adding %N/%N message", pen_names, msg_type.vendor_id, | |
174 | msg_type_names, msg_type.type); | |
4333c48a | 175 | this->messages->insert_last(this->messages, msg); |
a5c79d01 | 176 | return TRUE; |
4333c48a AS |
177 | } |
178 | ||
179 | METHOD(pb_tnc_batch_t, build, void, | |
180 | private_pb_tnc_batch_t *this) | |
181 | { | |
883c11ca | 182 | u_int8_t version; |
a5c79d01 | 183 | u_int32_t msg_len; |
4333c48a AS |
184 | chunk_t msg_value; |
185 | enumerator_t *enumerator; | |
ddfc5896 | 186 | pen_type_t msg_type; |
54eb669d | 187 | pb_tnc_msg_t *msg; |
ddfc5896 | 188 | pb_tnc_msg_info_t *msg_infos; |
7e432eff | 189 | bio_writer_t *writer; |
4333c48a | 190 | |
883c11ca AS |
191 | /* Set wrong PB-TNC version for testing purposes to force a PB-TNC error */ |
192 | version = lib->settings->get_int(lib->settings, | |
193 | "%s.plugins.tnccs-20.tests.pb_tnc_version", | |
194 | PB_TNC_VERSION, lib->ns); | |
195 | ||
4333c48a | 196 | /* build PB-TNC batch header */ |
12642a68 | 197 | writer = bio_writer_create(this->batch_len); |
883c11ca | 198 | writer->write_uint8 (writer, version); |
4333c48a AS |
199 | writer->write_uint8 (writer, this->is_server ? |
200 | PB_TNC_BATCH_FLAG_D : PB_TNC_BATCH_FLAG_NONE); | |
201 | writer->write_uint16(writer, this->type); | |
12642a68 | 202 | writer->write_uint32(writer, this->batch_len); |
4333c48a AS |
203 | |
204 | /* build PB-TNC messages */ | |
205 | enumerator = this->messages->create_enumerator(this->messages); | |
206 | while (enumerator->enumerate(enumerator, &msg)) | |
207 | { | |
54eb669d AS |
208 | u_int8_t flags = PB_TNC_FLAG_NONE; |
209 | ||
4333c48a AS |
210 | /* build PB-TNC message */ |
211 | msg_value = msg->get_encoding(msg); | |
4dda2984 | 212 | msg_len = PB_TNC_MSG_HEADER_SIZE + msg_value.len; |
4333c48a | 213 | msg_type = msg->get_type(msg); |
ddfc5896 AS |
214 | switch (msg_type.vendor_id) |
215 | { | |
216 | default: | |
217 | case PEN_IETF: | |
218 | msg_infos = pb_tnc_msg_infos; | |
219 | break; | |
220 | case PEN_TCG: | |
221 | msg_infos = pb_tnc_tcg_msg_infos; | |
222 | break; | |
c6aed8aa AS |
223 | case PEN_ITA: |
224 | msg_infos = pb_tnc_ita_msg_infos; | |
225 | break; | |
ddfc5896 AS |
226 | } |
227 | if (msg_infos[msg_type.type].has_noskip_flag) | |
4333c48a | 228 | { |
54eb669d AS |
229 | flags |= PB_TNC_FLAG_NOSKIP; |
230 | } | |
4333c48a | 231 | writer->write_uint8 (writer, flags); |
ddfc5896 AS |
232 | writer->write_uint24(writer, msg_type.vendor_id); |
233 | writer->write_uint32(writer, msg_type.type); | |
4333c48a AS |
234 | writer->write_uint32(writer, msg_len); |
235 | writer->write_data (writer, msg_value); | |
236 | } | |
237 | enumerator->destroy(enumerator); | |
238 | ||
1a9dee5d | 239 | this->encoding = writer->extract_buf(writer); |
4333c48a AS |
240 | writer->destroy(writer); |
241 | } | |
242 | ||
80322d2c AS |
243 | METHOD(pb_tnc_batch_t, process_header, status_t, |
244 | private_pb_tnc_batch_t *this, bool directionality, bool is_server, | |
245 | bool *from_server) | |
4333c48a | 246 | { |
7e432eff | 247 | bio_reader_t *reader; |
54eb669d AS |
248 | pb_tnc_msg_t *msg; |
249 | pb_error_msg_t *err_msg; | |
4333c48a AS |
250 | u_int8_t version, flags, reserved, type; |
251 | u_int32_t batch_len; | |
4333c48a AS |
252 | |
253 | if (this->encoding.len < PB_TNC_BATCH_HEADER_SIZE) | |
254 | { | |
255 | DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC batch header", | |
256 | this->encoding.len); | |
425a3a26 | 257 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 258 | PB_ERROR_INVALID_PARAMETER, 0); |
4333c48a AS |
259 | goto fatal; |
260 | } | |
261 | ||
7e432eff | 262 | reader = bio_reader_create(this->encoding); |
4333c48a AS |
263 | reader->read_uint8 (reader, &version); |
264 | reader->read_uint8 (reader, &flags); | |
265 | reader->read_uint8 (reader, &reserved); | |
266 | reader->read_uint8 (reader, &type); | |
267 | reader->read_uint32(reader, &batch_len); | |
268 | reader->destroy(reader); | |
269 | ||
270 | /* Version */ | |
271 | if (version != PB_TNC_VERSION) | |
272 | { | |
c56667f1 | 273 | DBG1(DBG_TNC, "unsupported TNCCS batch version 0x%02x", version); |
425a3a26 | 274 | msg = pb_error_msg_create(TRUE, PEN_IETF, |
54eb669d AS |
275 | PB_ERROR_VERSION_NOT_SUPPORTED); |
276 | err_msg = (pb_error_msg_t*)msg; | |
4333c48a AS |
277 | err_msg->set_bad_version(err_msg, version); |
278 | goto fatal; | |
279 | } | |
280 | ||
281 | /* Directionality */ | |
80322d2c AS |
282 | *from_server = (flags & PB_TNC_BATCH_FLAG_D) != PB_TNC_BATCH_FLAG_NONE; |
283 | ||
284 | if (directionality & (*from_server == is_server)) | |
4333c48a | 285 | { |
c1c65063 | 286 | DBG1(DBG_TNC, "wrong Directionality: batch is from a PB-TNC %s", |
80322d2c | 287 | is_server ? "server" : "client"); |
425a3a26 | 288 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
80322d2c | 289 | PB_ERROR_INVALID_PARAMETER, 1); |
4333c48a AS |
290 | goto fatal; |
291 | } | |
292 | ||
293 | /* Batch Type */ | |
294 | this->type = type & 0x0F; | |
295 | if (this->type > PB_BATCH_ROOF) | |
296 | { | |
41216e65 | 297 | DBG1(DBG_TNC, "unknown PB-TNC batch type: %d", this->type); |
425a3a26 | 298 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 299 | PB_ERROR_INVALID_PARAMETER, 3); |
4333c48a AS |
300 | goto fatal; |
301 | } | |
68fada37 | 302 | |
4333c48a AS |
303 | /* Batch Length */ |
304 | if (this->encoding.len != batch_len) | |
305 | { | |
306 | DBG1(DBG_TNC, "%u bytes of data is not equal to batch length of %u bytes", | |
307 | this->encoding.len, batch_len); | |
425a3a26 | 308 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 309 | PB_ERROR_INVALID_PARAMETER, 4); |
4333c48a AS |
310 | goto fatal; |
311 | } | |
312 | ||
313 | this->offset = PB_TNC_BATCH_HEADER_SIZE; | |
b8b678a5 | 314 | |
4333c48a AS |
315 | return SUCCESS; |
316 | ||
317 | fatal: | |
318 | this->errors->insert_last(this->errors, msg); | |
883c11ca | 319 | return FAILED; |
4333c48a AS |
320 | } |
321 | ||
54eb669d | 322 | static status_t process_tnc_msg(private_pb_tnc_batch_t *this) |
4333c48a | 323 | { |
7e432eff | 324 | bio_reader_t *reader; |
54eb669d | 325 | pb_tnc_msg_t *pb_tnc_msg, *msg; |
ddfc5896 | 326 | pb_tnc_msg_info_t *msg_infos; |
4333c48a | 327 | u_int8_t flags; |
54eb669d | 328 | u_int32_t vendor_id, msg_type, msg_len, offset; |
4333c48a | 329 | chunk_t data, msg_value; |
54eb669d | 330 | bool noskip_flag; |
ddfc5896 AS |
331 | enum_name_t *msg_type_names; |
332 | pen_type_t msg_pen_type; | |
4333c48a AS |
333 | status_t status; |
334 | ||
335 | data = chunk_skip(this->encoding, this->offset); | |
336 | ||
4dda2984 | 337 | if (data.len < PB_TNC_MSG_HEADER_SIZE) |
4333c48a AS |
338 | { |
339 | DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC message header", | |
340 | data.len); | |
425a3a26 | 341 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 342 | PB_ERROR_INVALID_PARAMETER, this->offset); |
4333c48a AS |
343 | goto fatal; |
344 | } | |
345 | ||
7e432eff | 346 | reader = bio_reader_create(data); |
4333c48a AS |
347 | reader->read_uint8 (reader, &flags); |
348 | reader->read_uint24(reader, &vendor_id); | |
349 | reader->read_uint32(reader, &msg_type); | |
350 | reader->read_uint32(reader, &msg_len); | |
351 | reader->destroy(reader); | |
352 | ||
54eb669d | 353 | noskip_flag = (flags & PB_TNC_FLAG_NOSKIP) != PB_TNC_FLAG_NONE; |
12642a68 | 354 | |
4333c48a AS |
355 | if (msg_len > data.len) |
356 | { | |
357 | DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC message", data.len); | |
425a3a26 | 358 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 359 | PB_ERROR_INVALID_PARAMETER, this->offset + 8); |
4333c48a AS |
360 | goto fatal; |
361 | } | |
362 | ||
425a3a26 | 363 | if (vendor_id == PEN_RESERVED) |
4333c48a | 364 | { |
425a3a26 AS |
365 | DBG1(DBG_TNC, "Vendor ID 0x%06x is reserved", PEN_RESERVED); |
366 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, | |
54eb669d | 367 | PB_ERROR_INVALID_PARAMETER, this->offset + 1); |
4333c48a AS |
368 | goto fatal; |
369 | ||
370 | } | |
371 | ||
372 | if (msg_type == PB_TNC_RESERVED_MSG_TYPE) | |
373 | { | |
41216e65 | 374 | DBG1(DBG_TNC, "PB-TNC message Type 0x%08x is reserved", |
4333c48a | 375 | PB_TNC_RESERVED_MSG_TYPE); |
425a3a26 | 376 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 377 | PB_ERROR_INVALID_PARAMETER, this->offset + 4); |
4333c48a AS |
378 | goto fatal; |
379 | } | |
380 | ||
ddfc5896 AS |
381 | if (vendor_id == PEN_IETF && msg_type <= PB_MSG_ROOF) |
382 | { | |
383 | if (msg_type == PB_MSG_EXPERIMENTAL && noskip_flag) | |
384 | { | |
385 | DBG1(DBG_TNC, "reject IETF/PB-Experimental message with " | |
386 | "NOSKIP flag set"); | |
387 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, | |
388 | PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset); | |
389 | goto fatal; | |
390 | } | |
391 | msg_type_names = pb_tnc_msg_type_names; | |
392 | msg_infos = pb_tnc_msg_infos; | |
393 | } | |
883c11ca AS |
394 | else if (vendor_id == PEN_TCG && msg_type <= PB_TCG_MSG_ROOF && |
395 | msg_type > PB_TCG_MSG_RESERVED) | |
ddfc5896 AS |
396 | { |
397 | msg_type_names = pb_tnc_tcg_msg_type_names; | |
398 | msg_infos = pb_tnc_tcg_msg_infos; | |
399 | } | |
883c11ca AS |
400 | else if (vendor_id == PEN_ITA && msg_type <= PB_ITA_MSG_ROOF && |
401 | msg_type > PB_ITA_MSG_NOSKIP_TEST) | |
c6aed8aa AS |
402 | { |
403 | msg_type_names = pb_tnc_ita_msg_type_names; | |
404 | msg_infos = pb_tnc_ita_msg_infos; | |
405 | } | |
ddfc5896 | 406 | else |
4333c48a | 407 | { |
4dda2984 | 408 | if (msg_len < PB_TNC_MSG_HEADER_SIZE) |
54eb669d AS |
409 | { |
410 | DBG1(DBG_TNC, "%u bytes too small for PB-TNC message length", | |
411 | msg_len); | |
425a3a26 | 412 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d AS |
413 | PB_ERROR_INVALID_PARAMETER, this->offset + 8); |
414 | goto fatal; | |
415 | } | |
416 | ||
417 | if (noskip_flag) | |
4333c48a | 418 | { |
883c11ca | 419 | DBG1(DBG_TNC, "reject PB-TNC message (0x%06x/0x%08x)", |
2c4d772a | 420 | vendor_id, msg_type); |
425a3a26 | 421 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 422 | PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset); |
4333c48a AS |
423 | goto fatal; |
424 | } | |
425 | else | |
426 | { | |
883c11ca | 427 | DBG1(DBG_TNC, "ignore PB-TNC message (0x%06x/0x%08x)", |
2c4d772a | 428 | vendor_id, msg_type); |
4333c48a | 429 | this->offset += msg_len; |
af1e3ff5 | 430 | return SUCCESS; |
4333c48a AS |
431 | } |
432 | } | |
ddfc5896 AS |
433 | |
434 | if (msg_infos[msg_type].has_noskip_flag != TRUE_OR_FALSE && | |
435 | msg_infos[msg_type].has_noskip_flag != noskip_flag) | |
54eb669d | 436 | { |
ddfc5896 AS |
437 | DBG1(DBG_TNC, "%N/%N message must%s have NOSKIP flag set", |
438 | pen_names, vendor_id, msg_type_names, msg_type, | |
439 | msg_infos[msg_type].has_noskip_flag ? "" : " not"); | |
440 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, | |
441 | PB_ERROR_INVALID_PARAMETER, this->offset); | |
442 | goto fatal; | |
443 | } | |
4333c48a | 444 | |
ddfc5896 AS |
445 | if (msg_len < msg_infos[msg_type].min_size || |
446 | (msg_infos[msg_type].exact_size && | |
447 | msg_len != msg_infos[msg_type].min_size)) | |
448 | { | |
449 | DBG1(DBG_TNC, "%N/%N message length must be %s %u bytes but is %u bytes", | |
450 | pen_names, vendor_id, msg_type_names, msg_type, | |
451 | msg_infos[msg_type].exact_size ? "exactly" : "at least", | |
452 | msg_infos[msg_type].min_size, msg_len); | |
453 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, | |
454 | PB_ERROR_INVALID_PARAMETER, this->offset); | |
455 | goto fatal; | |
54eb669d AS |
456 | } |
457 | ||
ddfc5896 | 458 | if (msg_infos[msg_type].in_result_batch && this->type != PB_BATCH_RESULT) |
7e7efa64 | 459 | { |
af1e3ff5 AS |
460 | if (this->is_server) |
461 | { | |
ddfc5896 AS |
462 | DBG1(DBG_TNC,"reject %N/%N message received from a PB-TNC client", |
463 | pen_names, vendor_id, msg_type_names, msg_type); | |
425a3a26 | 464 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 465 | PB_ERROR_INVALID_PARAMETER, this->offset); |
af1e3ff5 AS |
466 | goto fatal; |
467 | } | |
468 | else | |
469 | { | |
ddfc5896 AS |
470 | DBG1(DBG_TNC,"ignore %N/%N message not received within RESULT batch", |
471 | pen_names, vendor_id, msg_type_names, msg_type); | |
af1e3ff5 AS |
472 | this->offset += msg_len; |
473 | return SUCCESS; | |
474 | } | |
7e7efa64 AS |
475 | } |
476 | ||
ddfc5896 AS |
477 | DBG2(DBG_TNC, "processing %N/%N message (%u bytes)", pen_names, vendor_id, |
478 | msg_type_names, msg_type, msg_len); | |
4333c48a | 479 | data.len = msg_len; |
4dda2984 | 480 | msg_value = chunk_skip(data, PB_TNC_MSG_HEADER_SIZE); |
ddfc5896 AS |
481 | msg_pen_type = pen_type_create(vendor_id, msg_type); |
482 | pb_tnc_msg = pb_tnc_msg_create_from_data(msg_pen_type, msg_value); | |
4333c48a | 483 | |
54eb669d AS |
484 | status = pb_tnc_msg->process(pb_tnc_msg, &offset); |
485 | if (status == FAILED || status == VERIFY_ERROR) | |
486 | { | |
425a3a26 | 487 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
a96d9abf | 488 | PB_ERROR_INVALID_PARAMETER, this->offset + offset); |
54eb669d AS |
489 | this->errors->insert_last(this->errors, msg); |
490 | } | |
4333c48a AS |
491 | if (status == FAILED) |
492 | { | |
493 | pb_tnc_msg->destroy(pb_tnc_msg); | |
494 | return FAILED; | |
495 | } | |
496 | this->messages->insert_last(this->messages, pb_tnc_msg); | |
497 | this->offset += msg_len; | |
54eb669d | 498 | return status; |
4333c48a AS |
499 | |
500 | fatal: | |
501 | this->errors->insert_last(this->errors, msg); | |
12642a68 | 502 | return FAILED; |
4333c48a AS |
503 | } |
504 | ||
505 | METHOD(pb_tnc_batch_t, process, status_t, | |
5988fc0d | 506 | private_pb_tnc_batch_t *this, pb_tnc_state_machine_t *state_machine) |
4333c48a | 507 | { |
80322d2c AS |
508 | pb_tnc_msg_t *msg; |
509 | status_t status = SUCCESS; | |
4333c48a | 510 | |
80322d2c | 511 | if (!state_machine->receive_batch(state_machine, this->type)) |
4333c48a | 512 | { |
80322d2c AS |
513 | DBG1(DBG_TNC, "unexpected PB-TNC batch type: %N", |
514 | pb_tnc_batch_type_names, this->type); | |
515 | msg = pb_error_msg_create(TRUE, PEN_IETF, | |
516 | PB_ERROR_UNEXPECTED_BATCH_TYPE); | |
517 | this->errors->insert_last(this->errors, msg); | |
4333c48a AS |
518 | return FAILED; |
519 | } | |
b8b678a5 | 520 | |
80322d2c AS |
521 | /* Register an empty CDATA batch with the state machine */ |
522 | if (this->type == PB_BATCH_CDATA) | |
523 | { | |
524 | state_machine->set_empty_cdata(state_machine, | |
525 | this->offset == this->encoding.len); | |
526 | } | |
527 | ||
4333c48a AS |
528 | while (this->offset < this->encoding.len) |
529 | { | |
54eb669d | 530 | switch (process_tnc_msg(this)) |
4333c48a | 531 | { |
af1e3ff5 AS |
532 | case FAILED: |
533 | return FAILED; | |
534 | case VERIFY_ERROR: | |
535 | status = VERIFY_ERROR; | |
536 | break; | |
537 | case SUCCESS: | |
538 | default: | |
539 | break; | |
4333c48a AS |
540 | } |
541 | } | |
af1e3ff5 | 542 | return status; |
4333c48a AS |
543 | } |
544 | ||
545 | METHOD(pb_tnc_batch_t, create_msg_enumerator, enumerator_t*, | |
546 | private_pb_tnc_batch_t *this) | |
547 | { | |
548 | return this->messages->create_enumerator(this->messages); | |
549 | } | |
550 | ||
551 | METHOD(pb_tnc_batch_t, create_error_enumerator, enumerator_t*, | |
552 | private_pb_tnc_batch_t *this) | |
553 | { | |
554 | return this->errors->create_enumerator(this->errors); | |
555 | } | |
556 | ||
557 | METHOD(pb_tnc_batch_t, destroy, void, | |
558 | private_pb_tnc_batch_t *this) | |
559 | { | |
560 | this->messages->destroy_offset(this->messages, | |
54eb669d | 561 | offsetof(pb_tnc_msg_t, destroy)); |
4333c48a | 562 | this->errors->destroy_offset(this->errors, |
54eb669d | 563 | offsetof(pb_tnc_msg_t, destroy)); |
4333c48a AS |
564 | free(this->encoding.ptr); |
565 | free(this); | |
566 | } | |
567 | ||
568 | /** | |
569 | * See header | |
570 | */ | |
a5c79d01 AS |
571 | pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, |
572 | size_t max_batch_len) | |
4333c48a AS |
573 | { |
574 | private_pb_tnc_batch_t *this; | |
575 | ||
576 | INIT(this, | |
577 | .public = { | |
578 | .get_type = _get_type, | |
579 | .get_encoding = _get_encoding, | |
54eb669d | 580 | .add_msg = _add_msg, |
4333c48a AS |
581 | .build = _build, |
582 | .process = _process, | |
583 | .create_msg_enumerator = _create_msg_enumerator, | |
584 | .create_error_enumerator = _create_error_enumerator, | |
585 | .destroy = _destroy, | |
586 | }, | |
587 | .is_server = is_server, | |
588 | .type = type, | |
a5c79d01 AS |
589 | .max_batch_len = max_batch_len, |
590 | .batch_len = PB_TNC_BATCH_HEADER_SIZE, | |
4333c48a AS |
591 | .messages = linked_list_create(), |
592 | .errors = linked_list_create(), | |
593 | ); | |
594 | ||
41216e65 | 595 | DBG2(DBG_TNC, "creating PB-TNC %N batch", pb_tnc_batch_type_names, type); |
4333c48a AS |
596 | |
597 | return &this->public; | |
598 | } | |
599 | ||
600 | /** | |
601 | * See header | |
602 | */ | |
80322d2c | 603 | pb_tnc_batch_t* pb_tnc_batch_create_from_data(chunk_t data) |
4333c48a AS |
604 | { |
605 | private_pb_tnc_batch_t *this; | |
606 | ||
607 | INIT(this, | |
608 | .public = { | |
609 | .get_type = _get_type, | |
610 | .get_encoding = _get_encoding, | |
54eb669d | 611 | .add_msg = _add_msg, |
4333c48a | 612 | .build = _build, |
80322d2c | 613 | .process_header = _process_header, |
4333c48a AS |
614 | .process = _process, |
615 | .create_msg_enumerator = _create_msg_enumerator, | |
616 | .create_error_enumerator = _create_error_enumerator, | |
617 | .destroy = _destroy, | |
618 | }, | |
4333c48a AS |
619 | .messages = linked_list_create(), |
620 | .errors = linked_list_create(), | |
621 | .encoding = chunk_clone(data), | |
622 | ); | |
623 | ||
624 | return &this->public; | |
625 | } | |
626 |