fixed received test message
[strongswan.git] / src / libcharon / plugins / tnccs_20 / tnccs_20.c
1 /*
2 * Copyright (C) 2010 Sansar Choinyanbuu
3 * 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_20.h"
17
18 #include <debug.h>
19 #include <daemon.h>
20 #include <threading/mutex.h>
21 #include <tnc/tncif.h>
22 #include <tnc/tncifimv_names.h>
23 #include <tnc/tnccs/tnccs.h>
24
25 typedef struct recommendation_entry_t recommendation_entry_t;
26 typedef struct private_tnccs_20_t private_tnccs_20_t;
27
28 /**
29 * Recommendation entry
30 */
31 struct recommendation_entry_t {
32
33 /**
34 * IMV ID
35 */
36 TNC_IMVID id;
37
38 /**
39 * Action Recommendation provided by IMV instance
40 */
41 TNC_IMV_Action_Recommendation rec;
42
43 /**
44 * Evaluation Result provided by IMV instance
45 */
46 TNC_IMV_Evaluation_Result eval;
47 };
48
49 /**
50 * Private data of a tnccs_20_t object.
51 */
52 struct private_tnccs_20_t {
53
54 /**
55 * Public tls_t interface.
56 */
57 tls_t public;
58
59 /**
60 * TNCC if TRUE, TNCS if FALSE
61 */
62 bool is_server;
63
64 /**
65 * Connection ID assigned to this TNCCS connection
66 */
67 TNC_ConnectionID connection_id;
68
69 /**
70 * Batch being constructed
71 */
72 chunk_t batch;
73
74 /**
75 * Action Recommendations and Evaluations Results provided by IMVs
76 */
77 linked_list_t *recommendations;
78
79 /**
80 * Mutex locking the recommendations list
81 */
82 mutex_t *recommendation_mutex;
83 };
84
85 METHOD(tnccs_t, send_message, void,
86 private_tnccs_20_t* this, TNC_BufferReference message,
87 TNC_UInt32 message_len,
88 TNC_MessageType message_type)
89 {
90 chunk_t msg = { message, message_len },
91 batch = this->batch;
92
93 DBG1(DBG_TNC, "TNCCS 2.0 send message");
94 this->batch = chunk_cat("mc", batch, msg);
95 }
96
97 METHOD(tnccs_t, provide_recommendation, void,
98 private_tnccs_20_t* this, TNC_IMVID id,
99 TNC_IMV_Action_Recommendation rec,
100 TNC_IMV_Evaluation_Result eval)
101 {
102 enumerator_t *enumerator;
103 recommendation_entry_t *entry;
104 bool found = FALSE;
105
106 DBG2(DBG_TNC, "IMV %u provides recommendation '%N' and evaluation '%N'",
107 id, action_recommendation_names, rec, evaluation_result_names, eval);
108
109 this->recommendation_mutex->lock(this->recommendation_mutex);
110 enumerator = this->recommendations->create_enumerator(this->recommendations);
111 while (enumerator->enumerate(enumerator, &entry))
112 {
113 if (entry->id == id)
114 {
115 found = TRUE;
116 break;
117 }
118 }
119 enumerator->destroy(enumerator);
120
121 if (!found)
122 {
123 entry = malloc_thing(recommendation_entry_t);
124 entry->id = id;
125 this->recommendations->insert_last(this->recommendations, entry);
126 }
127
128 /* Assign provided action recommendation and evaluation result */
129 entry->rec = rec;
130 entry->eval = eval;
131 this->recommendation_mutex->unlock(this->recommendation_mutex);
132 }
133
134 METHOD(tls_t, process, status_t,
135 private_tnccs_20_t *this, void *buf, size_t buflen)
136 {
137 char *pos;
138 size_t len;
139
140 if (this->is_server && !this->connection_id)
141 {
142 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
143 (tnccs_t*)this,
144 _send_message, _provide_recommendation);
145 charon->imvs->notify_connection_change(charon->imvs,
146 this->connection_id, TNC_CONNECTION_STATE_CREATE);
147 }
148 DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u",
149 buflen, this->connection_id);
150 DBG3(DBG_TNC, "%.*s", buflen, buf);
151 pos = strchr(buf, '|');
152 if (pos)
153 {
154 pos++;
155 len = buflen - (pos - (char*)buf);
156 }
157 else
158 {
159 pos = buf;
160 len = buflen;
161 }
162 DBG1(DBG_TNC, "received message '%.*s'", len, pos);
163 if (this->is_server)
164 {
165 charon->imvs->receive_message(charon->imvs, this->connection_id,
166 pos, len, 0x0080ab31);
167 charon->imvs->batch_ending(charon->imvs, this->connection_id);
168 }
169 else
170 {
171 charon->imcs->receive_message(charon->imcs, this->connection_id,
172 pos, len, 0x0080ab31);
173 charon->imcs->batch_ending(charon->imcs, this->connection_id);
174 }
175 return NEED_MORE;
176 }
177
178 METHOD(tls_t, build, status_t,
179 private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
180 {
181 char *msg = this->is_server ? "tncs->tncc 2.0|" : "tncc->tncs 2.0|";
182 size_t len;
183
184 this->batch = chunk_cat("cm", chunk_create(msg, strlen(msg)), this->batch);
185
186 if (!this->is_server && !this->connection_id)
187 {
188 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
189 (tnccs_t*)this, _send_message, NULL);
190 charon->imcs->notify_connection_change(charon->imcs,
191 this->connection_id, TNC_CONNECTION_STATE_CREATE);
192 charon->imcs->notify_connection_change(charon->imcs,
193 this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE);
194 charon->imcs->begin_handshake(charon->imcs, this->connection_id);
195 }
196
197 len = this->batch.len;
198 *msglen = len;
199 *buflen = len;
200 memcpy(buf, this->batch.ptr, len);
201
202 DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u",
203 len, this->connection_id);
204 DBG3(DBG_TNC, "%.*s", len, buf);
205 chunk_free(&this->batch);
206
207 return ALREADY_DONE;
208 }
209
210 METHOD(tls_t, is_server, bool,
211 private_tnccs_20_t *this)
212 {
213 return this->is_server;
214 }
215
216 METHOD(tls_t, get_purpose, tls_purpose_t,
217 private_tnccs_20_t *this)
218 {
219 return TLS_PURPOSE_EAP_TNC;
220 }
221
222 METHOD(tls_t, is_complete, bool,
223 private_tnccs_20_t *this)
224 {
225 return FALSE;
226 }
227
228 METHOD(tls_t, get_eap_msk, chunk_t,
229 private_tnccs_20_t *this)
230 {
231 return chunk_empty;
232 }
233
234 METHOD(tls_t, destroy, void,
235 private_tnccs_20_t *this)
236 {
237 charon->tnccs->remove_connection(charon->tnccs, this->connection_id);
238 this->recommendations->destroy_function(this->recommendations, free);
239 this->recommendation_mutex->destroy(this->recommendation_mutex);
240 free(this->batch.ptr);
241 free(this);
242 }
243
244 /**
245 * See header
246 */
247 tls_t *tnccs_20_create(bool is_server)
248 {
249 private_tnccs_20_t *this;
250
251 INIT(this,
252 .public = {
253 .process = _process,
254 .build = _build,
255 .is_server = _is_server,
256 .get_purpose = _get_purpose,
257 .is_complete = _is_complete,
258 .get_eap_msk = _get_eap_msk,
259 .destroy = _destroy,
260 },
261 .is_server = is_server,
262 .recommendations = linked_list_create(),
263 .recommendation_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
264 );
265
266 return &this->public;
267 }