10365d6b044245b9a5b57017683e4a03c442301e
[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 * Mutex locking the batch in construction
76 */
77 mutex_t *batch_mutex;
78
79 /**
80 * Action Recommendations and Evaluations Results provided by IMVs
81 */
82 linked_list_t *recommendations;
83
84 /**
85 * Mutex locking the recommendations list
86 */
87 mutex_t *recommendation_mutex;
88 };
89
90 METHOD(tnccs_t, send_message, void,
91 private_tnccs_20_t* this, TNC_BufferReference message,
92 TNC_UInt32 message_len,
93 TNC_MessageType message_type)
94 {
95 chunk_t msg = { message, message_len };
96
97 DBG1(DBG_TNC, "TNCCS 2.0 send message");
98 this->batch_mutex->lock(this->batch_mutex);
99 this->batch = chunk_cat("mc", this->batch, msg);
100 this->batch_mutex->unlock(this->batch_mutex);
101 }
102
103 METHOD(tnccs_t, provide_recommendation, void,
104 private_tnccs_20_t* this, TNC_IMVID id,
105 TNC_IMV_Action_Recommendation rec,
106 TNC_IMV_Evaluation_Result eval)
107 {
108 enumerator_t *enumerator;
109 recommendation_entry_t *entry;
110 bool found = FALSE;
111
112 DBG2(DBG_TNC, "IMV %u provides recommendation '%N' and evaluation '%N'",
113 id, action_recommendation_names, rec, evaluation_result_names, eval);
114
115 this->recommendation_mutex->lock(this->recommendation_mutex);
116 enumerator = this->recommendations->create_enumerator(this->recommendations);
117 while (enumerator->enumerate(enumerator, &entry))
118 {
119 if (entry->id == id)
120 {
121 found = TRUE;
122 break;
123 }
124 }
125 enumerator->destroy(enumerator);
126
127 if (!found)
128 {
129 entry = malloc_thing(recommendation_entry_t);
130 entry->id = id;
131 this->recommendations->insert_last(this->recommendations, entry);
132 }
133
134 /* Assign provided action recommendation and evaluation result */
135 entry->rec = rec;
136 entry->eval = eval;
137 this->recommendation_mutex->unlock(this->recommendation_mutex);
138 }
139
140 METHOD(tls_t, process, status_t,
141 private_tnccs_20_t *this, void *buf, size_t buflen)
142 {
143 char *pos;
144 size_t len;
145
146 if (this->is_server && !this->connection_id)
147 {
148 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
149 (tnccs_t*)this,
150 _send_message, _provide_recommendation);
151 charon->imvs->notify_connection_change(charon->imvs,
152 this->connection_id, TNC_CONNECTION_STATE_CREATE);
153 }
154 DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u",
155 buflen, this->connection_id);
156 DBG3(DBG_TNC, "%.*s", buflen, buf);
157 pos = strchr(buf, '|');
158 if (pos)
159 {
160 pos++;
161 len = buflen - (pos - (char*)buf);
162 }
163 else
164 {
165 pos = buf;
166 len = buflen;
167 }
168 DBG1(DBG_TNC, "received message '%.*s'", len, pos);
169 if (this->is_server)
170 {
171 charon->imvs->receive_message(charon->imvs, this->connection_id,
172 pos, len, 0x0080ab31);
173 charon->imvs->batch_ending(charon->imvs, this->connection_id);
174 }
175 else
176 {
177 charon->imcs->receive_message(charon->imcs, this->connection_id,
178 pos, len, 0x0080ab31);
179 charon->imcs->batch_ending(charon->imcs, this->connection_id);
180 }
181 return NEED_MORE;
182 }
183
184 METHOD(tls_t, build, status_t,
185 private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
186 {
187 char *msg = this->is_server ? "tncs->tncc 2.0|" : "tncc->tncs 2.0|";
188 size_t len;
189
190 this->batch_mutex->lock(this->batch_mutex);
191 this->batch = chunk_cat("cm", chunk_create(msg, strlen(msg)), this->batch);
192 this->batch_mutex->unlock(this->batch_mutex);
193
194 if (!this->is_server && !this->connection_id)
195 {
196 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
197 (tnccs_t*)this, _send_message, NULL);
198 charon->imcs->notify_connection_change(charon->imcs,
199 this->connection_id, TNC_CONNECTION_STATE_CREATE);
200 charon->imcs->notify_connection_change(charon->imcs,
201 this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE);
202 charon->imcs->begin_handshake(charon->imcs, this->connection_id);
203 }
204
205 this->batch_mutex->lock(this->batch_mutex);
206 len = this->batch.len;
207 *msglen = len;
208 *buflen = len;
209 memcpy(buf, this->batch.ptr, len);
210 chunk_free(&this->batch);
211 this->batch_mutex->unlock(this->batch_mutex);
212
213 DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u",
214 len, this->connection_id);
215 DBG3(DBG_TNC, "%.*s", len, buf);
216
217 return ALREADY_DONE;
218 }
219
220 METHOD(tls_t, is_server, bool,
221 private_tnccs_20_t *this)
222 {
223 return this->is_server;
224 }
225
226 METHOD(tls_t, get_purpose, tls_purpose_t,
227 private_tnccs_20_t *this)
228 {
229 return TLS_PURPOSE_EAP_TNC;
230 }
231
232 METHOD(tls_t, is_complete, bool,
233 private_tnccs_20_t *this)
234 {
235 return FALSE;
236 }
237
238 METHOD(tls_t, get_eap_msk, chunk_t,
239 private_tnccs_20_t *this)
240 {
241 return chunk_empty;
242 }
243
244 METHOD(tls_t, destroy, void,
245 private_tnccs_20_t *this)
246 {
247 charon->tnccs->remove_connection(charon->tnccs, this->connection_id);
248 this->recommendations->destroy_function(this->recommendations, free);
249 this->recommendation_mutex->destroy(this->recommendation_mutex);
250 this->batch_mutex->destroy(this->batch_mutex);
251 free(this->batch.ptr);
252 free(this);
253 }
254
255 /**
256 * See header
257 */
258 tls_t *tnccs_20_create(bool is_server)
259 {
260 private_tnccs_20_t *this;
261
262 INIT(this,
263 .public = {
264 .process = _process,
265 .build = _build,
266 .is_server = _is_server,
267 .get_purpose = _get_purpose,
268 .is_complete = _is_complete,
269 .get_eap_msk = _get_eap_msk,
270 .destroy = _destroy,
271 },
272 .is_server = is_server,
273 .recommendations = linked_list_create(),
274 .recommendation_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
275 .batch_mutex = mutex_create(MUTEX_TYPE_DEFAULT),
276 );
277
278 return &this->public;
279 }