communicate DELETE state to IMCs and IMVs
[strongswan.git] / src / libcharon / plugins / tnccs_11 / messages / imc_imv_msg.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 "imc_imv_msg.h"
17
18 #include <tnc/tnccs/tnccs.h>
19 #include <debug.h>
20 #include <utils/lexparser.h>
21
22 typedef struct private_imc_imv_msg_t private_imc_imv_msg_t;
23
24 #define BYTES_PER_LINE 57
25
26 /**
27 * Private data of a imc_imv_msg_t object.
28 *
29 */
30 struct private_imc_imv_msg_t {
31 /**
32 * Public imc_imv_msg_t interface.
33 */
34 imc_imv_msg_t public;
35
36 /**
37 * TNCCS message type
38 */
39 tnccs_msg_type_t type;
40
41 /**
42 * XML-encoded message node
43 */
44 xmlNodePtr node;
45
46 /**
47 * IMC-IMV message type
48 */
49 TNC_MessageType msg_type;
50
51 /**
52 * IMC-IMV message body
53 */
54 chunk_t msg_body;
55
56 };
57
58 /**
59 * Encodes message data into multiple base64-encoded lines
60 */
61 static chunk_t encode_base64(chunk_t data)
62 {
63 chunk_t encoding;
64 u_char *pos;
65 size_t b64_chars, b64_lines;
66
67 /* compute and allocate maximum size of base64 object */
68 b64_chars = 4 * ((data.len + 2) / 3);
69 b64_lines = (data.len + BYTES_PER_LINE - 1) / BYTES_PER_LINE;
70 encoding = chunk_alloc(b64_chars + b64_lines);
71 pos = encoding.ptr;
72
73 /* encode lines */
74 while (b64_lines--)
75 {
76 chunk_t data_line, b64_line;
77
78 data_line = chunk_create(data.ptr, min(data.len, BYTES_PER_LINE));
79 data.ptr += data_line.len;
80 data.len -= data_line.len;
81 b64_line = chunk_to_base64(data_line, pos);
82 pos += b64_line.len;
83 *pos = '\n';
84 pos++;
85 }
86 /* terminate last line with NULL character instead of newline */
87 *(pos-1) = '\0';
88
89 return encoding;
90 }
91
92 /**
93 * Decodes message data from multiple base64-encoded lines
94 */
95 static chunk_t decode_base64(chunk_t data)
96 {
97 chunk_t decoding, data_line, b64_line;
98 u_char *pos;
99
100 /* compute and allocate maximum size of decoded message data */
101 decoding = chunk_alloc(3 * ((data.len + 3) / 4));
102 pos = decoding.ptr;
103 decoding.len = 0;
104
105 while (fetchline(&data, &b64_line))
106 {
107 data_line = chunk_from_base64(b64_line, pos);
108 pos += data_line.len;
109 decoding.len += data_line.len;
110 }
111
112 return decoding;
113 }
114
115 METHOD(tnccs_msg_t, get_type, tnccs_msg_type_t,
116 private_imc_imv_msg_t *this)
117 {
118 return this->type;
119 }
120
121 METHOD(tnccs_msg_t, get_node, xmlNodePtr,
122 private_imc_imv_msg_t *this)
123 {
124 return this->node;
125 }
126
127 METHOD(tnccs_msg_t, destroy, void,
128 private_imc_imv_msg_t *this)
129 {
130 free(this->msg_body.ptr);
131 free(this);
132 }
133
134 METHOD(imc_imv_msg_t, get_msg_type, TNC_MessageType,
135 private_imc_imv_msg_t *this)
136 {
137 return this->msg_type;
138 }
139
140 METHOD(imc_imv_msg_t, get_msg_body, chunk_t,
141 private_imc_imv_msg_t *this)
142 {
143 return this->msg_body;
144 }
145
146 /**
147 * See header
148 */
149 tnccs_msg_t *imc_imv_msg_create_from_node(xmlNodePtr node, linked_list_t *errors)
150 {
151 private_imc_imv_msg_t *this;
152 xmlNsPtr ns;
153 xmlNodePtr cur;
154 xmlChar *content;
155 chunk_t b64_body;
156
157 INIT(this,
158 .public = {
159 .tnccs_msg_interface = {
160 .get_type = _get_type,
161 .get_node = _get_node,
162 .destroy = _destroy,
163 },
164 .get_msg_type = _get_msg_type,
165 .get_msg_body = _get_msg_body,
166 },
167 .type = IMC_IMV_MSG,
168 .node = node,
169 );
170
171 ns = node->ns;
172 cur = node->xmlChildrenNode;
173 while (cur)
174 {
175 if (streq((char*)cur->name, "Type") && cur->ns == ns)
176 {
177 content = xmlNodeGetContent(cur);
178 this->msg_type = strtoul((char*)content, NULL, 16);
179 xmlFree(content);
180 }
181 else if (streq((char*)cur->name, "Base64") && cur->ns == ns)
182 {
183 content = xmlNodeGetContent(cur);
184 b64_body = chunk_create((char*)content, strlen((char*)content));
185 this->msg_body = decode_base64(b64_body);
186 xmlFree(content);
187 }
188 cur = cur->next;
189 }
190
191 return &this->public.tnccs_msg_interface;
192 }
193
194 /**
195 * See header
196 */
197 tnccs_msg_t *imc_imv_msg_create(TNC_MessageType msg_type, chunk_t msg_body)
198 {
199 private_imc_imv_msg_t *this;
200 chunk_t b64_body;
201 char buf[10]; /* big enough for hex-encoded message type */
202 xmlNodePtr n;
203
204 INIT(this,
205 .public = {
206 .tnccs_msg_interface = {
207 .get_type = _get_type,
208 .get_node = _get_node,
209 .destroy = _destroy,
210 },
211 .get_msg_type = _get_msg_type,
212 .get_msg_body = _get_msg_body,
213 },
214 .type = IMC_IMV_MSG,
215 .node = xmlNewNode(NULL, BAD_CAST "IMC-IMV-Message"),
216 .msg_type = msg_type,
217 .msg_body = chunk_clone(msg_body),
218 );
219
220 /* add the message type number in hex */
221 n = xmlNewNode(NULL, BAD_CAST "Type");
222 snprintf(buf, 10, "%08x", this->msg_type);
223 xmlNodeSetContent(n, BAD_CAST buf);
224 xmlAddChild(this->node, n);
225
226 /* encode the message as a Base64 node */
227 n = xmlNewNode(NULL, BAD_CAST "Base64");
228 b64_body = encode_base64(this->msg_body);
229 xmlNodeSetContent(n, BAD_CAST b64_body.ptr);
230 xmlAddChild(this->node, n);
231 free(b64_body.ptr);
232
233 return &this->public.tnccs_msg_interface;
234 }