added IMC and IMV IDs as arguments to send_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 private_tnccs_20_t private_tnccs_20_t;
26
27 /**
28 * Private data of a tnccs_20_t object.
29 */
30 struct private_tnccs_20_t {
31
32 /**
33 * Public tls_t interface.
34 */
35 tls_t public;
36
37 /**
38 * TNCC if TRUE, TNCS if FALSE
39 */
40 bool is_server;
41
42 /**
43 * Connection ID assigned to this TNCCS connection
44 */
45 TNC_ConnectionID connection_id;
46
47 /**
48 * Batch being constructed
49 */
50 chunk_t batch;
51
52 /**
53 * Mutex locking the batch in construction
54 */
55 mutex_t *mutex;
56
57 /**
58 * Set of IMV recommendations (TNC Server only)
59 */
60 recommendations_t *recs;
61 };
62
63 METHOD(tnccs_t, send_message, void,
64 private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
65 TNC_BufferReference message,
66 TNC_UInt32 message_len,
67 TNC_MessageType message_type)
68 {
69 chunk_t msg = { message, message_len };
70
71 DBG1(DBG_TNC, "TNCCS 2.0 send message");
72 this->mutex->lock(this->mutex);
73 this->batch = chunk_cat("mc", this->batch, msg);
74 this->mutex->unlock(this->mutex);
75 }
76
77 METHOD(tls_t, process, status_t,
78 private_tnccs_20_t *this, void *buf, size_t buflen)
79 {
80 char *pos;
81 size_t len;
82
83 if (this->is_server && !this->connection_id)
84 {
85 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
86 (tnccs_t*)this, _send_message, &this->recs);
87 if (!this->connection_id)
88 {
89 return FAILED;
90 }
91 charon->imvs->notify_connection_change(charon->imvs,
92 this->connection_id, TNC_CONNECTION_STATE_CREATE);
93 }
94 DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u",
95 buflen, this->connection_id);
96 DBG3(DBG_TNC, "%.*s", buflen, buf);
97 pos = strchr(buf, '|');
98 if (pos)
99 {
100 pos++;
101 len = buflen - (pos - (char*)buf);
102 }
103 else
104 {
105 pos = buf;
106 len = buflen;
107 }
108 DBG1(DBG_TNC, "received message '%.*s'", len, pos);
109 if (this->is_server)
110 {
111 charon->imvs->receive_message(charon->imvs, this->connection_id,
112 pos, len, 0x0080ab31);
113 charon->imvs->batch_ending(charon->imvs, this->connection_id);
114 }
115 else
116 {
117 charon->imcs->receive_message(charon->imcs, this->connection_id,
118 pos, len, 0x0080ab31);
119 charon->imcs->batch_ending(charon->imcs, this->connection_id);
120 }
121 return NEED_MORE;
122 }
123
124 METHOD(tls_t, build, status_t,
125 private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
126 {
127 char *msg = this->is_server ? "tncs->tncc 2.0|" : "tncc->tncs 2.0|";
128 size_t len;
129
130 this->mutex->lock(this->mutex);
131 this->batch = chunk_cat("cm", chunk_create(msg, strlen(msg)), this->batch);
132 this->mutex->unlock(this->mutex);
133
134 if (!this->is_server && !this->connection_id)
135 {
136 this->connection_id = charon->tnccs->create_connection(charon->tnccs,
137 (tnccs_t*)this, _send_message, NULL);
138 if (!this->connection_id)
139 {
140 return FAILED;
141 }
142 charon->imcs->notify_connection_change(charon->imcs,
143 this->connection_id, TNC_CONNECTION_STATE_CREATE);
144 charon->imcs->notify_connection_change(charon->imcs,
145 this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE);
146 charon->imcs->begin_handshake(charon->imcs, this->connection_id);
147 }
148
149 this->mutex->lock(this->mutex);
150 len = this->batch.len;
151 *msglen = len;
152 *buflen = len;
153 memcpy(buf, this->batch.ptr, len);
154 chunk_free(&this->batch);
155 this->mutex->unlock(this->mutex);
156
157 DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u",
158 len, this->connection_id);
159 DBG3(DBG_TNC, "%.*s", len, buf);
160
161 return ALREADY_DONE;
162 }
163
164 METHOD(tls_t, is_server, bool,
165 private_tnccs_20_t *this)
166 {
167 return this->is_server;
168 }
169
170 METHOD(tls_t, get_purpose, tls_purpose_t,
171 private_tnccs_20_t *this)
172 {
173 return TLS_PURPOSE_EAP_TNC;
174 }
175
176 METHOD(tls_t, is_complete, bool,
177 private_tnccs_20_t *this)
178 {
179 TNC_IMV_Action_Recommendation rec;
180 TNC_IMV_Evaluation_Result eval;
181
182 if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval))
183 {
184 DBG2(DBG_TNC, "Final recommendation '%N' and evaluation '%N'",
185 action_recommendation_names, rec, evaluation_result_names, eval);
186
187 return charon->imvs->enforce_recommendation(charon->imvs, rec);
188 }
189 else
190 {
191 return FALSE;
192 }
193 }
194
195 METHOD(tls_t, get_eap_msk, chunk_t,
196 private_tnccs_20_t *this)
197 {
198 return chunk_empty;
199 }
200
201 METHOD(tls_t, destroy, void,
202 private_tnccs_20_t *this)
203 {
204 charon->tnccs->remove_connection(charon->tnccs, this->connection_id);
205 this->mutex->destroy(this->mutex);
206 free(this->batch.ptr);
207 free(this);
208 }
209
210 /**
211 * See header
212 */
213 tls_t *tnccs_20_create(bool is_server)
214 {
215 private_tnccs_20_t *this;
216
217 INIT(this,
218 .public = {
219 .process = _process,
220 .build = _build,
221 .is_server = _is_server,
222 .get_purpose = _get_purpose,
223 .is_complete = _is_complete,
224 .get_eap_msk = _get_eap_msk,
225 .destroy = _destroy,
226 },
227 .is_server = is_server,
228 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
229 );
230
231 return &this->public;
232 }