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