IKEv1 XAuth: XAuthInitPreShared working for XAuth initiator (Main Mode responder...
[strongswan.git] / src / libcharon / sa / tasks / xauth_request.c
1
2 #include "xauth_request.h"
3
4 #include <daemon.h>
5 #include <hydra.h>
6 #include <encoding/payloads/cp_payload.h>
7
8 typedef struct private_xauth_request_t private_xauth_request_t;
9
10 enum {
11 XAUTH_STATUS_FAIL = 0,
12 XAUTH_STATUS_OK = 1,
13 };
14
15 /**
16 * Private members of a xauth_request_t task.
17 */
18 struct private_xauth_request_t {
19
20 /**
21 * Public methods and task_t interface.
22 */
23 xauth_request_t public;
24
25 /**
26 * Assigned IKE_SA.
27 */
28 ike_sa_t *ike_sa;
29
30 /**
31 * Are we the initiator?
32 */
33 bool initiator;
34
35 /**
36 * virtual ip
37 */
38 host_t *virtual_ip;
39
40 /**
41 * list of attributes requested and its handler, entry_t
42 */
43 linked_list_t *requested;
44
45 /**
46 * The user name
47 */
48 chunk_t user_name;
49
50 /**
51 * The user pass
52 */
53 chunk_t user_pass;
54
55 /**
56 * The current state of the task
57 */
58 enum {
59 TASK_XAUTH_INIT,
60 TASK_XAUTH_PASS_DONE,
61 } state;
62
63 /**
64 * The status of the XAuth request
65 */
66 status_t status;
67 };
68
69 /**
70 * Entry for a requested attribute and the requesting handler
71 */
72 typedef struct {
73 /** attribute requested */
74 configuration_attribute_type_t type;
75 /** handler requesting this attribute */
76 attribute_handler_t *handler;
77 } entry_t;
78
79 METHOD(task_t, build_i, status_t,
80 private_xauth_request_t *this, message_t *message)
81 {
82 cp_payload_t *cp;
83 chunk_t chunk = chunk_empty;
84
85 switch(this->state)
86 {
87 case TASK_XAUTH_INIT:
88 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST);
89 cp->add_attribute(cp, configuration_attribute_create_chunk(
90 CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk));
91 cp->add_attribute(cp, configuration_attribute_create_chunk(
92 CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk));
93 break;
94 case TASK_XAUTH_PASS_DONE:
95 cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
96 cp->add_attribute(cp, configuration_attribute_create_value(
97 XAUTH_STATUS,
98 (this->status == FAILED ? XAUTH_STATUS_FAIL : XAUTH_STATUS_OK)));
99 break;
100 default:
101 return FAILED;
102
103 }
104 /* Add the payloads into the message */
105 message->add_payload(message, (payload_t *)cp);
106
107
108 return NEED_MORE;
109 }
110
111 METHOD(task_t, process_r, status_t,
112 private_xauth_request_t *this, message_t *message)
113 {
114 return NEED_MORE;
115 }
116
117 METHOD(task_t, build_r, status_t,
118 private_xauth_request_t *this, message_t *message)
119 {
120 return NEED_MORE;
121 }
122
123 METHOD(task_t, process_i, status_t,
124 private_xauth_request_t *this, message_t *message)
125 {
126 cp_payload_t *cp_payload;
127 enumerator_t *enumerator;
128 configuration_attribute_t *ca;
129 chunk_t status_chunk = chunk_empty;
130
131 cp_payload = (cp_payload_t *)message->get_payload(message, CONFIGURATION_V1);
132 enumerator = cp_payload->create_attribute_enumerator(cp_payload);
133 while (enumerator->enumerate(enumerator, &ca))
134 {
135 switch(ca->get_type(ca))
136 {
137 case XAUTH_USER_NAME:
138 this->user_name = ca->get_chunk(ca);
139 break;
140 case XAUTH_USER_PASSWORD:
141 this->user_pass = ca->get_chunk(ca);
142 break;
143 case XAUTH_STATUS:
144 status_chunk = ca->get_chunk(ca);
145 break;
146 default:
147 DBG3(DBG_IKE, "Unknown config attribute type %d, ignored", ca->get_type(ca));
148 }
149 }
150 enumerator->destroy(enumerator);
151
152 switch(this->state)
153 {
154 case TASK_XAUTH_INIT:
155
156 if(cp_payload->get_type(cp_payload) != CFG_REPLY)
157 {
158 DBG1(DBG_IKE, "ERROR: ConfigMode payload is not a reply");
159 return FAILED;
160 }
161
162 this->state = TASK_XAUTH_PASS_DONE;
163 if((this->user_name.len == 0) || (this->user_pass.len == 0))
164 {
165 DBG1(DBG_IKE, "ERROR: Did not get user name or user pass, aborting");
166 this->status = FAILED;
167 /* We should close out the XAuth negotiation cleanly by sending a "failed" message */
168 return NEED_MORE;
169 }
170
171 /* TODO-IKEv1: Do actual user/pass verification */
172 // if(!chunk_compare(this->user_name, this->user_pass))
173 // {
174 // this->status = FAILED;
175 // DBG1(DBG_IKE, "ERROR: user/pass verification failure");
176 /* We should close out the XAuth negotiation cleanly by sending a "failed" message */
177 // return NEED_MORE;
178 // }
179
180 this->status = SUCCESS;
181 return NEED_MORE;
182 case TASK_XAUTH_PASS_DONE:
183 if(cp_payload->get_type(cp_payload) != CFG_ACK)
184 {
185 DBG1(DBG_IKE, "ERROR: ConfigMode payload is not a status ack");
186 return FAILED;
187 }
188 if(status_chunk.len != 0)
189 {
190 DBG1(DBG_IKE, "Status payload of an ack had data, hmm....");
191 }
192
193 DBG1(DBG_IKE, "Done with XAUTH!!!");
194 return this->status;
195 }
196 return FAILED;
197 }
198
199 METHOD(task_t, get_type, task_type_t,
200 private_xauth_request_t *this)
201 {
202 return TASK_XAUTH_REQUEST;
203 }
204
205 METHOD(task_t, migrate, void,
206 private_xauth_request_t *this, ike_sa_t *ike_sa)
207 {
208 DESTROY_IF(this->virtual_ip);
209
210 this->ike_sa = ike_sa;
211 this->virtual_ip = NULL;
212 this->requested->destroy_function(this->requested, free);
213 this->requested = linked_list_create();
214 }
215
216 METHOD(task_t, destroy, void,
217 private_xauth_request_t *this)
218 {
219 DESTROY_IF(this->virtual_ip);
220 this->requested->destroy_function(this->requested, free);
221 free(this);
222 }
223
224 /*
225 * Described in header.
226 */
227 xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator)
228 {
229 private_xauth_request_t *this;
230
231 INIT(this,
232 .public = {
233 .task = {
234 .get_type = _get_type,
235 .migrate = _migrate,
236 .destroy = _destroy,
237 },
238 },
239 .initiator = initiator,
240 .ike_sa = ike_sa,
241 .requested = linked_list_create(),
242 .user_name = chunk_empty,
243 .user_pass = chunk_empty,
244 .state = TASK_XAUTH_INIT,
245 );
246
247 if (initiator)
248 {
249 this->public.task.build = _build_i;
250 this->public.task.process = _process_i;
251 }
252 else
253 {
254 this->public.task.build = _build_r;
255 this->public.task.process = _process_r;
256 }
257
258 return &this->public;
259 }