4fd896e3cc22c8a0c861490f77cda5a99e0c92f1
[strongswan.git] / src / libcharon / sa / tasks / xauth.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
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 "xauth.h"
17
18 #include <daemon.h>
19 #include <hydra.h>
20 #include <encoding/payloads/cp_payload.h>
21
22 typedef struct private_xauth_t private_xauth_t;
23
24 /**
25 * Status types exchanged
26 */
27 typedef enum {
28 XAUTH_FAILED = 0,
29 XAUTH_OK = 1,
30 } xauth_status_t;
31
32 /**
33 * Private members of a xauth_t task.
34 */
35 struct private_xauth_t {
36
37 /**
38 * Public methods and task_t interface.
39 */
40 xauth_t public;
41
42 /**
43 * Assigned IKE_SA.
44 */
45 ike_sa_t *ike_sa;
46
47 /**
48 * Are we the XAUTH initiator?
49 */
50 bool initiator;
51
52 /**
53 * XAuth backend to use
54 */
55 xauth_method_t *xauth;
56
57 /**
58 * Generated configuration payload
59 */
60 cp_payload_t *cp;
61
62 /**
63 * status of Xauth exchange
64 */
65 xauth_status_t status;
66 };
67
68 /**
69 * Load XAuth backend
70 */
71 static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator)
72 {
73 identification_t *server, *peer;
74 enumerator_t *enumerator;
75 xauth_method_t *xauth;
76 xauth_role_t role;
77 peer_cfg_t *peer_cfg;
78 auth_cfg_t *auth;
79 char *name;
80
81 if (initiator)
82 {
83 server = ike_sa->get_my_id(ike_sa);
84 peer = ike_sa->get_other_id(ike_sa);
85 role = XAUTH_SERVER;
86 }
87 else
88 {
89 peer = ike_sa->get_my_id(ike_sa);
90 server = ike_sa->get_other_id(ike_sa);
91 role = XAUTH_PEER;
92 }
93 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
94 enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !initiator);
95 if (!enumerator->enumerate(enumerator, &auth) ||
96 !enumerator->enumerate(enumerator, &auth))
97 {
98 DBG1(DBG_CFG, "no second authentication round found for XAuth");
99 enumerator->destroy(enumerator);
100 return NULL;
101 }
102 name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
103 enumerator->destroy(enumerator);
104
105 xauth = charon->xauth->create_instance(charon->xauth, name, role,
106 server, peer);
107 if (!xauth)
108 {
109 if (name)
110 {
111 DBG1(DBG_CFG, "no XAuth method found named '%s'");
112 }
113 else
114 {
115 DBG1(DBG_CFG, "no XAuth method found");
116 }
117 }
118 return xauth;
119 }
120
121 /**
122 * Set IKE_SA to established state
123 */
124 static void establish(private_xauth_t *this)
125 {
126 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
127 this->ike_sa->get_name(this->ike_sa),
128 this->ike_sa->get_unique_id(this->ike_sa),
129 this->ike_sa->get_my_host(this->ike_sa),
130 this->ike_sa->get_my_id(this->ike_sa),
131 this->ike_sa->get_other_host(this->ike_sa),
132 this->ike_sa->get_other_id(this->ike_sa));
133
134 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
135 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
136 }
137
138 METHOD(task_t, build_i_status, status_t,
139 private_xauth_t *this, message_t *message)
140 {
141 cp_payload_t *cp;
142
143 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
144 cp->add_attribute(cp,
145 configuration_attribute_create_value(XAUTH_STATUS, this->status));
146
147 message->add_payload(message, (payload_t *)cp);
148
149 return NEED_MORE;
150 }
151
152 METHOD(task_t, build_i, status_t,
153 private_xauth_t *this, message_t *message)
154 {
155 if (!this->xauth)
156 {
157 cp_payload_t *cp;
158
159 this->xauth = load_method(this->ike_sa, this->initiator);
160 if (!this->xauth)
161 {
162 return FAILED;
163 }
164 if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
165 {
166 return FAILED;
167 }
168 message->add_payload(message, (payload_t *)cp);
169 return NEED_MORE;
170 }
171
172 if (this->cp)
173 { /* send previously generated payload */
174 message->add_payload(message, (payload_t *)this->cp);
175 this->cp = NULL;
176 return NEED_MORE;
177 }
178 return FAILED;
179 }
180
181 METHOD(task_t, build_r_ack, status_t,
182 private_xauth_t *this, message_t *message)
183 {
184 cp_payload_t *cp;
185
186 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
187 cp->add_attribute(cp,
188 configuration_attribute_create_chunk(
189 CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
190
191 message->add_payload(message, (payload_t *)cp);
192
193 if (this->status == XAUTH_OK)
194 {
195 establish(this);
196 return SUCCESS;
197 }
198 return FAILED;
199 }
200
201 METHOD(task_t, process_r, status_t,
202 private_xauth_t *this, message_t *message)
203 {
204 cp_payload_t *cp;
205
206 if (!this->xauth)
207 {
208 this->xauth = load_method(this->ike_sa, this->initiator);
209 if (!this->xauth)
210 { /* send empty reply */
211 return NEED_MORE;
212 }
213 }
214 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
215 if (!cp)
216 {
217 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
218 return FAILED;
219 }
220 if (cp->get_type(cp) == CFG_REQUEST)
221 {
222 switch (this->xauth->process(this->xauth, cp, &this->cp))
223 {
224 case NEED_MORE:
225 return NEED_MORE;
226 case SUCCESS:
227 DBG1(DBG_IKE, "XAuth authentication successful");
228 establish(this);
229 break;
230 case FAILED:
231 default:
232 DBG1(DBG_IKE, "XAuth authentication failed");
233 break;
234 }
235 this->cp = NULL;
236 return NEED_MORE;
237 }
238 if (cp->get_type(cp) == CFG_SET)
239 {
240 configuration_attribute_t *attribute;
241 enumerator_t *enumerator;
242
243 enumerator = cp->create_attribute_enumerator(cp);
244 while (enumerator->enumerate(enumerator, &attribute))
245 {
246 if (attribute->get_type(attribute) == XAUTH_STATUS)
247 {
248 this->status = attribute->get_value(attribute);
249 }
250 }
251 enumerator->destroy(enumerator);
252 }
253 this->public.task.build = _build_r_ack;
254 return NEED_MORE;
255 }
256
257 METHOD(task_t, build_r, status_t,
258 private_xauth_t *this, message_t *message)
259 {
260 if (!this->cp)
261 { /* send empty reply if building data failed */
262 this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
263 }
264 message->add_payload(message, (payload_t *)this->cp);
265 this->cp = NULL;
266 return NEED_MORE;
267 }
268
269 METHOD(task_t, process_i_status, status_t,
270 private_xauth_t *this, message_t *message)
271 {
272 cp_payload_t *cp;
273
274 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
275 if (!cp || cp->get_type(cp) != CFG_ACK)
276 {
277 DBG1(DBG_IKE, "received invalid XAUTH status response");
278 return FAILED;
279 }
280 if (this->status != XAUTH_OK)
281 {
282 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
283 return FAILED;
284 }
285 establish(this);
286 return SUCCESS;
287 }
288
289 METHOD(task_t, process_i, status_t,
290 private_xauth_t *this, message_t *message)
291 {
292 cp_payload_t *cp;
293
294 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
295 if (!cp)
296 {
297 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
298 return FAILED;
299 }
300 switch (this->xauth->process(this->xauth, cp, &this->cp))
301 {
302 case NEED_MORE:
303 return NEED_MORE;
304 case SUCCESS:
305 DBG1(DBG_IKE, "XAuth authentication successful");
306 this->status = XAUTH_OK;
307 break;
308 case FAILED:
309 DBG1(DBG_IKE, "XAuth authentication failed");
310 break;
311 default:
312 return FAILED;
313 }
314 this->public.task.build = _build_i_status;
315 this->public.task.process = _process_i_status;
316 return NEED_MORE;
317 }
318
319 METHOD(task_t, get_type, task_type_t,
320 private_xauth_t *this)
321 {
322 return TASK_XAUTH;
323 }
324
325 METHOD(task_t, migrate, void,
326 private_xauth_t *this, ike_sa_t *ike_sa)
327 {
328 this->ike_sa = ike_sa;
329 }
330
331 METHOD(task_t, destroy, void,
332 private_xauth_t *this)
333 {
334 DESTROY_IF(this->xauth);
335 DESTROY_IF(this->cp);
336 free(this);
337 }
338
339 /*
340 * Described in header.
341 */
342 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
343 {
344 private_xauth_t *this;
345
346 INIT(this,
347 .public = {
348 .task = {
349 .get_type = _get_type,
350 .migrate = _migrate,
351 .destroy = _destroy,
352 },
353 },
354 .initiator = initiator,
355 .ike_sa = ike_sa,
356 .status = XAUTH_FAILED,
357 );
358
359 if (initiator)
360 {
361 this->public.task.build = _build_i;
362 this->public.task.process = _process_i;
363 }
364 else
365 {
366 this->public.task.build = _build_r;
367 this->public.task.process = _process_r;
368 }
369 return &this->public;
370 }