5df8aadee71fd819bc9841f33e54ff41db1ff498
[strongswan.git] / src / libcharon / plugins / xauth_generic / xauth_generic.c
1 /*
2 * Copyright (C) 2011 Tobias Brunner
3 * 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 "xauth_generic.h"
17
18 #include <daemon.h>
19 #include <library.h>
20
21 typedef struct private_xauth_generic_t private_xauth_generic_t;
22
23 /**
24 * Private data of an xauth_generic_t object.
25 */
26 struct private_xauth_generic_t {
27
28 /**
29 * Public interface.
30 */
31 xauth_generic_t public;
32
33 /**
34 * ID of the server
35 */
36 identification_t *server;
37
38 /**
39 * ID of the peer
40 */
41 identification_t *peer;
42 };
43
44 METHOD(xauth_method_t, initiate_peer, status_t,
45 private_xauth_generic_t *this, cp_payload_t **out)
46 {
47 /* peer never initiates */
48 return FAILED;
49 }
50
51 METHOD(xauth_method_t, process_peer, status_t,
52 private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out)
53 {
54 configuration_attribute_t *attr;
55 enumerator_t *enumerator;
56 shared_key_t *shared;
57 cp_payload_t *cp;
58 chunk_t msg;
59
60 enumerator = in->create_attribute_enumerator(in);
61 while (enumerator->enumerate(enumerator, &attr))
62 {
63 if (attr->get_type(attr) == XAUTH_MESSAGE)
64 {
65 chunk_printable(attr->get_chunk(attr), &msg, '?');
66 DBG1(DBG_CFG, "XAuth message: %.*s", (int)msg.len, msg.ptr);
67 free(msg.ptr);
68 }
69 }
70 enumerator->destroy(enumerator);
71
72 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
73
74 enumerator = in->create_attribute_enumerator(in);
75 while (enumerator->enumerate(enumerator, &attr))
76 {
77 shared_key_type_t type = SHARED_EAP;
78
79 switch (attr->get_type(attr))
80 {
81 case XAUTH_USER_NAME:
82 cp->add_attribute(cp, configuration_attribute_create_chunk(
83 CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME,
84 this->peer->get_encoding(this->peer)));
85 break;
86 case XAUTH_NEXT_PIN:
87 type = SHARED_PIN;
88 /* FALL */
89 case XAUTH_USER_PASSWORD:
90 shared = lib->credmgr->get_shared(lib->credmgr, type,
91 this->peer, this->server);
92 if (!shared)
93 {
94 DBG1(DBG_IKE, "no XAuth %s found for '%Y' - '%Y'",
95 type == SHARED_EAP ? "password" : "PIN",
96 this->peer, this->server);
97 enumerator->destroy(enumerator);
98 cp->destroy(cp);
99 return FAILED;
100 }
101 cp->add_attribute(cp, configuration_attribute_create_chunk(
102 CONFIGURATION_ATTRIBUTE_V1, attr->get_type(attr),
103 shared->get_key(shared)));
104 shared->destroy(shared);
105 break;
106 default:
107 break;
108 }
109 }
110 enumerator->destroy(enumerator);
111
112 *out = cp;
113 return NEED_MORE;
114 }
115
116 METHOD(xauth_method_t, initiate_server, status_t,
117 private_xauth_generic_t *this, cp_payload_t **out)
118 {
119 cp_payload_t *cp;
120
121 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
122 cp->add_attribute(cp, configuration_attribute_create_chunk(
123 CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty));
124 cp->add_attribute(cp, configuration_attribute_create_chunk(
125 CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty));
126 *out = cp;
127 return NEED_MORE;
128 }
129
130 METHOD(xauth_method_t, process_server, status_t,
131 private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out)
132 {
133 configuration_attribute_t *attr;
134 enumerator_t *enumerator;
135 shared_key_t *shared;
136 identification_t *id;
137 chunk_t user = chunk_empty, pass = chunk_empty;
138 status_t status = FAILED;
139 int tried = 0;
140
141 enumerator = in->create_attribute_enumerator(in);
142 while (enumerator->enumerate(enumerator, &attr))
143 {
144 switch (attr->get_type(attr))
145 {
146 case XAUTH_USER_NAME:
147 user = attr->get_chunk(attr);
148 break;
149 case XAUTH_USER_PASSWORD:
150 pass = attr->get_chunk(attr);
151 break;
152 default:
153 break;
154 }
155 }
156 enumerator->destroy(enumerator);
157
158 if (!user.ptr || !pass.ptr)
159 {
160 DBG1(DBG_IKE, "peer did not respond to our XAuth request");
161 return FAILED;
162 }
163 if (user.len)
164 {
165 id = identification_create_from_data(user);
166 if (!id)
167 {
168 DBG1(DBG_IKE, "failed to parse provided XAuth username");
169 return FAILED;
170 }
171 this->peer->destroy(this->peer);
172 this->peer = id;
173 }
174 if (pass.len && pass.ptr[pass.len - 1] == 0)
175 { /* fix null-terminated passwords (Android etc.) */
176 pass.len -= 1;
177 }
178
179 enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
180 SHARED_EAP, this->server, this->peer);
181 while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
182 {
183 if (chunk_equals(shared->get_key(shared), pass))
184 {
185 status = SUCCESS;
186 break;
187 }
188 tried++;
189 }
190 enumerator->destroy(enumerator);
191 if (status != SUCCESS)
192 {
193 if (!tried)
194 {
195 DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'",
196 this->server, this->peer);
197 }
198 else
199 {
200 DBG1(DBG_IKE, "none of %d found XAuth secrets for '%Y' - '%Y' "
201 "matched", tried, this->server, this->peer);
202 }
203 }
204 return status;
205 }
206
207 METHOD(xauth_method_t, get_identity, identification_t*,
208 private_xauth_generic_t *this)
209 {
210 return this->peer;
211 }
212
213 METHOD(xauth_method_t, destroy, void,
214 private_xauth_generic_t *this)
215 {
216 this->server->destroy(this->server);
217 this->peer->destroy(this->peer);
218 free(this);
219 }
220
221 /*
222 * Described in header.
223 */
224 xauth_generic_t *xauth_generic_create_peer(identification_t *server,
225 identification_t *peer,
226 char *profile)
227 {
228 private_xauth_generic_t *this;
229
230 INIT(this,
231 .public = {
232 .xauth_method = {
233 .initiate = _initiate_peer,
234 .process = _process_peer,
235 .get_identity = _get_identity,
236 .destroy = _destroy,
237 },
238 },
239 .server = server->clone(server),
240 .peer = peer->clone(peer),
241 );
242
243 return &this->public;
244 }
245
246 /*
247 * Described in header.
248 */
249 xauth_generic_t *xauth_generic_create_server(identification_t *server,
250 identification_t *peer,
251 char *profile)
252 {
253 private_xauth_generic_t *this;
254
255 INIT(this,
256 .public = {
257 .xauth_method = {
258 .initiate = _initiate_server,
259 .process = _process_server,
260 .get_identity = _get_identity,
261 .destroy = _destroy,
262 },
263 },
264 .server = server->clone(server),
265 .peer = peer->clone(peer),
266 );
267
268 return &this->public;
269 }