Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_radius/eap_radius_xauth.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013 Martin Willi
3: * Copyright (C) 2013 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 "eap_radius_xauth.h"
17: #include "eap_radius_plugin.h"
18: #include "eap_radius.h"
19: #include "eap_radius_forward.h"
20:
21: #include <daemon.h>
22: #include <radius_client.h>
23: #include <collections/array.h>
24:
25:
26: typedef struct private_eap_radius_xauth_t private_eap_radius_xauth_t;
27: typedef struct xauth_round_t xauth_round_t;
28:
29: /**
30: * Configuration for an XAuth authentication exchange
31: */
32: struct xauth_round_t {
33: /** XAuth message type to send */
34: configuration_attribute_type_t type;
35: /** Message to present to user */
36: char *message;
37: };
38:
39: /**
40: * Private data of an eap_radius_xauth_t object.
41: */
42: struct private_eap_radius_xauth_t {
43:
44: /**
45: * Public interface.
46: */
47: eap_radius_xauth_t public;
48:
49: /**
50: * ID of the server
51: */
52: identification_t *server;
53:
54: /**
55: * ID of the peer
56: */
57: identification_t *peer;
58:
59: /**
60: * RADIUS connection
61: */
62: radius_client_t *client;
63:
64: /**
65: * XAuth authentication rounds, as xauth_round_t
66: */
67: array_t *rounds;
68:
69: /**
70: * XAuth round currently in progress
71: */
72: xauth_round_t round;
73:
74: /**
75: * Concatenated password of all rounds
76: */
77: chunk_t pass;
78: };
79:
80: /**
81: * Fetch next XAuth round, add attributes to CP payload
82: */
83: static bool build_round(private_eap_radius_xauth_t *this, cp_payload_t *cp)
84: {
85: if (!array_remove(this->rounds, ARRAY_HEAD, &this->round))
86: {
87: return FALSE;
88: }
89: cp->add_attribute(cp, configuration_attribute_create_chunk(
90: PLV1_CONFIGURATION_ATTRIBUTE, this->round.type, chunk_empty));
91:
92: if (this->round.message && strlen(this->round.message))
93: {
94: cp->add_attribute(cp, configuration_attribute_create_chunk(
95: PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_MESSAGE,
96: chunk_from_str(this->round.message)));
97: }
98: return TRUE;
99: }
100:
101: METHOD(xauth_method_t, initiate, status_t,
102: private_eap_radius_xauth_t *this, cp_payload_t **out)
103: {
104: cp_payload_t *cp;
105:
106: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST);
107: /* first message always comes with username */
108: cp->add_attribute(cp, configuration_attribute_create_chunk(
109: PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, chunk_empty));
110:
111: if (build_round(this, cp))
112: {
113: *out = cp;
114: return NEED_MORE;
115: }
116: cp->destroy(cp);
117: return FAILED;
118: }
119:
120: /**
121: * Verify a password using RADIUS User-Name/User-Password attributes
122: */
123: static status_t verify_radius(private_eap_radius_xauth_t *this)
124: {
125: radius_message_t *request, *response;
126: status_t status = FAILED;
127:
128: request = radius_message_create(RMC_ACCESS_REQUEST);
129: request->add(request, RAT_USER_NAME, this->peer->get_encoding(this->peer));
130: request->add(request, RAT_USER_PASSWORD, this->pass);
131:
132: eap_radius_build_attributes(request);
133: eap_radius_forward_from_ike(request);
134:
135: response = this->client->request(this->client, request);
136: if (response)
137: {
138: eap_radius_forward_to_ike(response);
139: switch (response->get_code(response))
140: {
141: case RMC_ACCESS_ACCEPT:
142: eap_radius_process_attributes(response);
143: status = SUCCESS;
144: break;
145: case RMC_ACCESS_CHALLENGE:
146: DBG1(DBG_IKE, "RADIUS Access-Challenge not supported");
147: /* FALL */
148: case RMC_ACCESS_REJECT:
149: default:
150: DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
151: this->peer);
152: break;
153: }
154: response->destroy(response);
155: }
156: else
157: {
158: eap_radius_handle_timeout(NULL);
159: }
160: request->destroy(request);
161: return status;
162: }
163:
164: METHOD(xauth_method_t, process, status_t,
165: private_eap_radius_xauth_t *this, cp_payload_t *in, cp_payload_t **out)
166: {
167: configuration_attribute_t *attr;
168: enumerator_t *enumerator;
169: identification_t *id;
170: cp_payload_t *cp;
171: chunk_t user = chunk_empty, pass = chunk_empty;
172:
173: enumerator = in->create_attribute_enumerator(in);
174: while (enumerator->enumerate(enumerator, &attr))
175: {
176: if (attr->get_type(attr) == XAUTH_USER_NAME)
177: {
178: user = attr->get_chunk(attr);
179: }
180: else if (attr->get_type(attr) == this->round.type)
181: {
182: pass = attr->get_chunk(attr);
183: /* trim password to any null termination. As User-Password
184: * uses null padding, we can't have any null in it, and some
185: * clients actually send null terminated strings (Android). */
186: pass.len = strnlen(pass.ptr, pass.len);
187: }
188: }
189: enumerator->destroy(enumerator);
190:
191: if (!pass.ptr)
192: {
193: DBG1(DBG_IKE, "peer did not respond to our XAuth %N request",
194: configuration_attribute_type_names, this->round.type);
195: return FAILED;
196: }
197: this->pass = chunk_cat("mc", this->pass, pass);
198: if (user.len)
199: {
200: id = identification_create_from_data(user);
201: if (!id)
202: {
203: DBG1(DBG_IKE, "failed to parse provided XAuth username");
204: return FAILED;
205: }
206: this->peer->destroy(this->peer);
207: this->peer = id;
208: }
209:
210: if (array_count(this->rounds) == 0)
211: {
212: return verify_radius(this);
213: }
214: cp = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REQUEST);
215: if (build_round(this, cp))
216: {
217: *out = cp;
218: return NEED_MORE;
219: }
220: cp->destroy(cp);
221: return FAILED;
222: }
223:
224: METHOD(xauth_method_t, get_identity, identification_t*,
225: private_eap_radius_xauth_t *this)
226: {
227: return this->peer;
228: }
229:
230: /**
231: * Parse XAuth round configuration
232: */
233: static bool parse_rounds(private_eap_radius_xauth_t *this, char *profile)
234: {
235: struct {
236: char *str;
237: configuration_attribute_type_t type;
238: } map[] = {
239: { "password", XAUTH_USER_PASSWORD, },
240: { "passcode", XAUTH_PASSCODE, },
241: { "nextpin", XAUTH_NEXT_PIN, },
242: { "answer", XAUTH_ANSWER, },
243: };
244: enumerator_t *enumerator;
245: char *type, *message;
246: xauth_round_t round;
247: int i;
248:
249: if (!profile || strlen(profile) == 0)
250: {
251: /* no config, fallback to password */
252: round.type = XAUTH_USER_PASSWORD;
253: round.message = NULL;
254: array_insert(this->rounds, ARRAY_TAIL, &round);
255: return TRUE;
256: }
257:
258: enumerator = lib->settings->create_key_value_enumerator(lib->settings,
259: "%s.plugins.eap-radius.xauth.%s", lib->ns, profile);
260: while (enumerator->enumerate(enumerator, &type, &message))
261: {
262: bool invalid = TRUE;
263:
264: for (i = 0; i < countof(map); i++)
265: {
266: if (strcaseeq(map[i].str, type))
267: {
268: round.type = map[i].type;
269: round.message = message;
270: array_insert(this->rounds, ARRAY_TAIL, &round);
271: invalid = FALSE;
272: break;
273: }
274: }
275: if (invalid)
276: {
277: DBG1(DBG_CFG, "invalid XAuth round type: '%s'", type);
278: enumerator->destroy(enumerator);
279: return FALSE;
280: }
281: }
282: enumerator->destroy(enumerator);
283:
284: if (array_count(this->rounds) == 0)
285: {
286: DBG1(DBG_CFG, "XAuth configuration profile '%s' invalid", profile);
287: return FALSE;
288: }
289: return TRUE;
290: }
291:
292: METHOD(xauth_method_t, destroy, void,
293: private_eap_radius_xauth_t *this)
294: {
295: DESTROY_IF(this->client);
296: chunk_clear(&this->pass);
297: array_destroy(this->rounds);
298: this->server->destroy(this->server);
299: this->peer->destroy(this->peer);
300: free(this);
301: }
302:
303: /*
304: * Described in header.
305: */
306: eap_radius_xauth_t *eap_radius_xauth_create_server(identification_t *server,
307: identification_t *peer,
308: char *profile)
309: {
310: private_eap_radius_xauth_t *this;
311:
312: INIT(this,
313: .public = {
314: .xauth_method = {
315: .initiate = _initiate,
316: .process = _process,
317: .get_identity = _get_identity,
318: .destroy = _destroy,
319: },
320: },
321: .server = server->clone(server),
322: .peer = peer->clone(peer),
323: .client = eap_radius_create_client(),
324: .rounds = array_create(sizeof(xauth_round_t), 0),
325: );
326:
327: if (!parse_rounds(this, profile))
328: {
329: destroy(this);
330: return NULL;
331: }
332: if (!this->client)
333: {
334: destroy(this);
335: return NULL;
336: }
337: return &this->public;
338: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>