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