58e127aa949b4422887f1f8a9dd3a6d89dcde61b
[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 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
97 {
98 if (!enumerator->enumerate(enumerator, &auth) ||
99 (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH)
100 {
101 DBG1(DBG_CFG, "no XAuth authentication round found");
102 enumerator->destroy(enumerator);
103 return NULL;
104 }
105 }
106 name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND);
107 enumerator->destroy(enumerator);
108
109 xauth = charon->xauth->create_instance(charon->xauth, name, role,
110 server, peer);
111 if (!xauth)
112 {
113 if (name)
114 {
115 DBG1(DBG_CFG, "no XAuth method found named '%s'");
116 }
117 else
118 {
119 DBG1(DBG_CFG, "no XAuth method found");
120 }
121 }
122 return xauth;
123 }
124
125 /**
126 * Set IKE_SA to established state
127 */
128 static void establish(private_xauth_t *this)
129 {
130 DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
131 this->ike_sa->get_name(this->ike_sa),
132 this->ike_sa->get_unique_id(this->ike_sa),
133 this->ike_sa->get_my_host(this->ike_sa),
134 this->ike_sa->get_my_id(this->ike_sa),
135 this->ike_sa->get_other_host(this->ike_sa),
136 this->ike_sa->get_other_id(this->ike_sa));
137
138 this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
139 charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
140 }
141
142 METHOD(task_t, build_i_status, status_t,
143 private_xauth_t *this, message_t *message)
144 {
145 cp_payload_t *cp;
146
147 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
148 cp->add_attribute(cp,
149 configuration_attribute_create_value(XAUTH_STATUS, this->status));
150
151 message->add_payload(message, (payload_t *)cp);
152
153 return NEED_MORE;
154 }
155
156 METHOD(task_t, build_i, status_t,
157 private_xauth_t *this, message_t *message)
158 {
159 if (!this->xauth)
160 {
161 cp_payload_t *cp;
162
163 this->xauth = load_method(this->ike_sa, this->initiator);
164 if (!this->xauth)
165 {
166 return FAILED;
167 }
168 if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE)
169 {
170 return FAILED;
171 }
172 message->add_payload(message, (payload_t *)cp);
173 return NEED_MORE;
174 }
175
176 if (this->cp)
177 { /* send previously generated payload */
178 message->add_payload(message, (payload_t *)this->cp);
179 this->cp = NULL;
180 return NEED_MORE;
181 }
182 return FAILED;
183 }
184
185 METHOD(task_t, build_r_ack, status_t,
186 private_xauth_t *this, message_t *message)
187 {
188 cp_payload_t *cp;
189
190 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
191 cp->add_attribute(cp,
192 configuration_attribute_create_chunk(
193 CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty));
194
195 message->add_payload(message, (payload_t *)cp);
196
197 if (this->status == XAUTH_OK)
198 {
199 establish(this);
200 return SUCCESS;
201 }
202 return FAILED;
203 }
204
205 METHOD(task_t, process_r, status_t,
206 private_xauth_t *this, message_t *message)
207 {
208 cp_payload_t *cp;
209
210 if (!this->xauth)
211 {
212 this->xauth = load_method(this->ike_sa, this->initiator);
213 if (!this->xauth)
214 { /* send empty reply */
215 return NEED_MORE;
216 }
217 }
218 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
219 if (!cp)
220 {
221 DBG1(DBG_IKE, "configuration payload missing in XAuth request");
222 return FAILED;
223 }
224 if (cp->get_type(cp) == CFG_REQUEST)
225 {
226 switch (this->xauth->process(this->xauth, cp, &this->cp))
227 {
228 case NEED_MORE:
229 return NEED_MORE;
230 case SUCCESS:
231 DBG1(DBG_IKE, "XAuth authentication successful");
232 establish(this);
233 break;
234 case FAILED:
235 default:
236 DBG1(DBG_IKE, "XAuth authentication failed");
237 break;
238 }
239 this->cp = NULL;
240 return NEED_MORE;
241 }
242 if (cp->get_type(cp) == CFG_SET)
243 {
244 configuration_attribute_t *attribute;
245 enumerator_t *enumerator;
246
247 enumerator = cp->create_attribute_enumerator(cp);
248 while (enumerator->enumerate(enumerator, &attribute))
249 {
250 if (attribute->get_type(attribute) == XAUTH_STATUS)
251 {
252 this->status = attribute->get_value(attribute);
253 }
254 }
255 enumerator->destroy(enumerator);
256 }
257 this->public.task.build = _build_r_ack;
258 return NEED_MORE;
259 }
260
261 METHOD(task_t, build_r, status_t,
262 private_xauth_t *this, message_t *message)
263 {
264 if (!this->cp)
265 { /* send empty reply if building data failed */
266 this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
267 }
268 message->add_payload(message, (payload_t *)this->cp);
269 this->cp = NULL;
270 return NEED_MORE;
271 }
272
273 METHOD(task_t, process_i_status, status_t,
274 private_xauth_t *this, message_t *message)
275 {
276 cp_payload_t *cp;
277
278 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
279 if (!cp || cp->get_type(cp) != CFG_ACK)
280 {
281 DBG1(DBG_IKE, "received invalid XAUTH status response");
282 return FAILED;
283 }
284 if (this->status != XAUTH_OK)
285 {
286 DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication");
287 return FAILED;
288 }
289 establish(this);
290 return SUCCESS;
291 }
292
293 METHOD(task_t, process_i, status_t,
294 private_xauth_t *this, message_t *message)
295 {
296 cp_payload_t *cp;
297
298 cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1);
299 if (!cp)
300 {
301 DBG1(DBG_IKE, "configuration payload missing in XAuth response");
302 return FAILED;
303 }
304 switch (this->xauth->process(this->xauth, cp, &this->cp))
305 {
306 case NEED_MORE:
307 return NEED_MORE;
308 case SUCCESS:
309 DBG1(DBG_IKE, "XAuth authentication successful");
310 this->status = XAUTH_OK;
311 break;
312 case FAILED:
313 DBG1(DBG_IKE, "XAuth authentication failed");
314 break;
315 default:
316 return FAILED;
317 }
318 this->public.task.build = _build_i_status;
319 this->public.task.process = _process_i_status;
320 return NEED_MORE;
321 }
322
323 METHOD(task_t, get_type, task_type_t,
324 private_xauth_t *this)
325 {
326 return TASK_XAUTH;
327 }
328
329 METHOD(task_t, migrate, void,
330 private_xauth_t *this, ike_sa_t *ike_sa)
331 {
332 this->ike_sa = ike_sa;
333 }
334
335 METHOD(task_t, destroy, void,
336 private_xauth_t *this)
337 {
338 DESTROY_IF(this->xauth);
339 DESTROY_IF(this->cp);
340 free(this);
341 }
342
343 /*
344 * Described in header.
345 */
346 xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator)
347 {
348 private_xauth_t *this;
349
350 INIT(this,
351 .public = {
352 .task = {
353 .get_type = _get_type,
354 .migrate = _migrate,
355 .destroy = _destroy,
356 },
357 },
358 .initiator = initiator,
359 .ike_sa = ike_sa,
360 .status = XAUTH_FAILED,
361 );
362
363 if (initiator)
364 {
365 this->public.task.build = _build_i;
366 this->public.task.process = _process_i;
367 }
368 else
369 {
370 this->public.task.build = _build_r;
371 this->public.task.process = _process_r;
372 }
373 return &this->public;
374 }