]>
Commit | Line | Data |
---|---|---|
d1e348cf A |
1 | /* $NetBSD: isakmp_xauth.c,v 1.11.6.1 2007/08/07 04:49:24 manu Exp $ */ |
2 | ||
3 | /* Id: isakmp_xauth.c,v 1.38 2006/08/22 18:17:17 manubsd Exp */ | |
52b7d2ce A |
4 | |
5 | /* | |
6 | * Copyright (C) 2004-2005 Emmanuel Dreyfus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * 3. Neither the name of the project nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include "config.h" | |
35 | ||
36 | #include <sys/types.h> | |
37 | #include <sys/param.h> | |
38 | #include <sys/socket.h> | |
39 | #include <sys/queue.h> | |
40 | ||
41 | #include <netinet/in.h> | |
42 | ||
43 | #include <stdlib.h> | |
44 | #include <stdio.h> | |
45 | #include <string.h> | |
46 | #include <errno.h> | |
47 | #include <pwd.h> | |
d1e348cf | 48 | #include <grp.h> |
52b7d2ce A |
49 | #if TIME_WITH_SYS_TIME |
50 | # include <sys/time.h> | |
51 | # include <time.h> | |
52 | #else | |
53 | # if HAVE_SYS_TIME_H | |
54 | # include <sys/time.h> | |
55 | # else | |
56 | # include <time.h> | |
57 | # endif | |
58 | #endif | |
59 | #include <netdb.h> | |
60 | #ifdef HAVE_UNISTD_H | |
61 | #include <unistd.h> | |
62 | #endif | |
63 | #include <ctype.h> | |
d1e348cf A |
64 | #include <resolv.h> |
65 | ||
66 | #ifdef HAVE_SHADOW_H | |
67 | #include <shadow.h> | |
68 | #endif | |
52b7d2ce A |
69 | |
70 | #include "var.h" | |
71 | #include "misc.h" | |
72 | #include "vmbuf.h" | |
73 | #include "plog.h" | |
74 | #include "sockmisc.h" | |
75 | #include "schedule.h" | |
76 | #include "debug.h" | |
65c25746 | 77 | #include "fsm.h" |
52b7d2ce A |
78 | |
79 | #include "crypto_openssl.h" | |
80 | #include "isakmp_var.h" | |
81 | #include "isakmp.h" | |
52b7d2ce A |
82 | #include "handler.h" |
83 | #include "throttle.h" | |
84 | #include "remoteconf.h" | |
85 | #include "isakmp_inf.h" | |
86 | #include "isakmp_xauth.h" | |
87 | #include "isakmp_unity.h" | |
88 | #include "isakmp_cfg.h" | |
89 | #include "strnames.h" | |
90 | #include "ipsec_doi.h" | |
91 | #include "remoteconf.h" | |
92 | #include "localconf.h" | |
d1e348cf A |
93 | #include "vpn_control.h" |
94 | #include "vpn_control_var.h" | |
95 | #include "ipsecSessionTracer.h" | |
96 | #include "ipsecMessageTracer.h" | |
52b7d2ce | 97 | |
52b7d2ce A |
98 | |
99 | void | |
100 | xauth_sendreq(iph1) | |
65c25746 | 101 | phase1_handle_t *iph1; |
52b7d2ce A |
102 | { |
103 | vchar_t *buffer; | |
104 | struct isakmp_pl_attr *attr; | |
105 | struct isakmp_data *typeattr; | |
106 | struct isakmp_data *usrattr; | |
107 | struct isakmp_data *pwdattr; | |
108 | struct xauth_state *xst = &iph1->mode_cfg->xauth; | |
109 | size_t tlen; | |
110 | ||
111 | /* Status checks */ | |
65c25746 A |
112 | if (!FSM_STATE_IS_ESTABLISHED(iph1->status)) { |
113 | plog(ASL_LEVEL_ERR, | |
52b7d2ce A |
114 | "Xauth request while phase 1 is not completed\n"); |
115 | return; | |
116 | } | |
117 | ||
118 | if (xst->status != XAUTHST_NOTYET) { | |
65c25746 | 119 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
120 | "Xauth request whith Xauth state %d\n", xst->status); |
121 | return; | |
122 | } | |
123 | ||
65c25746 | 124 | plog(ASL_LEVEL_INFO, "Sending Xauth request\n"); |
52b7d2ce A |
125 | |
126 | tlen = sizeof(*attr) + | |
127 | + sizeof(*typeattr) + | |
128 | + sizeof(*usrattr) + | |
129 | + sizeof(*pwdattr); | |
130 | ||
131 | if ((buffer = vmalloc(tlen)) == NULL) { | |
65c25746 | 132 | plog(ASL_LEVEL_ERR, "Cannot allocate buffer\n"); |
52b7d2ce A |
133 | return; |
134 | } | |
135 | ||
136 | attr = (struct isakmp_pl_attr *)buffer->v; | |
137 | memset(attr, 0, tlen); | |
138 | ||
139 | attr->h.len = htons(tlen); | |
140 | attr->type = ISAKMP_CFG_REQUEST; | |
141 | attr->id = htons(eay_random()); | |
142 | ||
143 | typeattr = (struct isakmp_data *)(attr + 1); | |
144 | typeattr->type = htons(XAUTH_TYPE | ISAKMP_GEN_TV); | |
145 | typeattr->lorv = htons(XAUTH_TYPE_GENERIC); | |
146 | ||
147 | usrattr = (struct isakmp_data *)(typeattr + 1); | |
148 | usrattr->type = htons(XAUTH_USER_NAME | ISAKMP_GEN_TLV); | |
149 | usrattr->lorv = htons(0); | |
150 | ||
151 | pwdattr = (struct isakmp_data *)(usrattr + 1); | |
152 | pwdattr->type = htons(XAUTH_USER_PASSWORD | ISAKMP_GEN_TLV); | |
153 | pwdattr->lorv = htons(0); | |
154 | ||
155 | isakmp_cfg_send(iph1, buffer, | |
d1e348cf | 156 | ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1, 0, NULL); |
52b7d2ce A |
157 | |
158 | vfree(buffer); | |
159 | ||
160 | xst->status = XAUTHST_REQSENT; | |
161 | ||
162 | return; | |
163 | } | |
164 | ||
d1e348cf | 165 | int |
52b7d2ce | 166 | xauth_attr_reply(iph1, attr, id) |
65c25746 | 167 | phase1_handle_t *iph1; |
52b7d2ce A |
168 | struct isakmp_data *attr; |
169 | int id; | |
170 | { | |
171 | char **outlet = NULL; | |
172 | size_t alen = 0; | |
173 | int type; | |
174 | struct xauth_state *xst = &iph1->mode_cfg->xauth; | |
175 | ||
176 | if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { | |
65c25746 | 177 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
178 | "Xauth reply but peer did not declare " |
179 | "itself as Xauth capable\n"); | |
d1e348cf | 180 | return -1; |
52b7d2ce A |
181 | } |
182 | ||
183 | if (xst->status != XAUTHST_REQSENT) { | |
65c25746 | 184 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 185 | "Xauth reply while Xauth state is %d\n", xst->status); |
d1e348cf | 186 | return -1; |
52b7d2ce A |
187 | } |
188 | ||
189 | type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; | |
190 | switch (type) { | |
191 | case XAUTH_TYPE: | |
192 | switch (ntohs(attr->lorv)) { | |
193 | case XAUTH_TYPE_GENERIC: | |
194 | xst->authtype = XAUTH_TYPE_GENERIC; | |
195 | break; | |
196 | default: | |
65c25746 | 197 | plog(ASL_LEVEL_WARNING, |
52b7d2ce A |
198 | "Unexpected authentication type %d\n", |
199 | ntohs(type)); | |
d1e348cf | 200 | return -1; |
52b7d2ce A |
201 | } |
202 | break; | |
203 | ||
204 | case XAUTH_USER_NAME: | |
205 | outlet = &xst->authdata.generic.usr; | |
206 | break; | |
207 | ||
208 | case XAUTH_USER_PASSWORD: | |
209 | outlet = &xst->authdata.generic.pwd; | |
210 | break; | |
211 | ||
212 | default: | |
65c25746 | 213 | plog(ASL_LEVEL_WARNING, |
52b7d2ce A |
214 | "ignored Xauth attribute %d\n", type); |
215 | break; | |
216 | } | |
217 | ||
218 | if (outlet != NULL) { | |
219 | alen = ntohs(attr->lorv); | |
220 | ||
d1e348cf | 221 | if ((*outlet = racoon_realloc(*outlet, alen + 1)) == NULL) { |
65c25746 | 222 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 223 | "Cannot allocate memory for Xauth Data\n"); |
d1e348cf | 224 | return -1; |
52b7d2ce A |
225 | } |
226 | ||
227 | memcpy(*outlet, attr + 1, alen); | |
228 | (*outlet)[alen] = '\0'; | |
229 | outlet = NULL; | |
230 | } | |
231 | ||
232 | ||
233 | if ((xst->authdata.generic.usr != NULL) && | |
234 | (xst->authdata.generic.pwd != NULL)) { | |
235 | int port; | |
236 | int res; | |
237 | char *usr = xst->authdata.generic.usr; | |
238 | char *pwd = xst->authdata.generic.pwd; | |
239 | time_t throttle_delay = 0; | |
240 | ||
241 | #if 0 /* Real debug, don't do that at home */ | |
65c25746 | 242 | plog(ASL_LEVEL_DEBUG, |
52b7d2ce A |
243 | "Got username \"%s\", password \"%s\"\n", usr, pwd); |
244 | #endif | |
d1e348cf | 245 | strlcpy(iph1->mode_cfg->login, usr, sizeof(iph1->mode_cfg->login)); |
52b7d2ce A |
246 | |
247 | res = -1; | |
248 | if ((port = isakmp_cfg_getport(iph1)) == -1) { | |
65c25746 | 249 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
250 | "Port pool depleted\n"); |
251 | goto skip_auth; | |
252 | } | |
253 | ||
254 | switch (isakmp_cfg_config.authsource) { | |
255 | case ISAKMP_CFG_AUTH_SYSTEM: | |
e8d9021d | 256 | res = xauth_login_system(usr, pwd); |
52b7d2ce | 257 | break; |
65c25746 | 258 | |
52b7d2ce | 259 | default: |
65c25746 | 260 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
261 | "Unexpected authentication source\n"); |
262 | res = -1; | |
263 | break; | |
264 | } | |
265 | ||
d1e348cf A |
266 | /* |
267 | * Optional group authentication | |
268 | */ | |
269 | if (!res && (isakmp_cfg_config.groupcount)) | |
270 | res = group_check(iph1, | |
271 | isakmp_cfg_config.grouplist, | |
272 | isakmp_cfg_config.groupcount); | |
273 | ||
52b7d2ce A |
274 | /* |
275 | * On failure, throttle the connexion for the remote host | |
276 | * in order to make password attacks more difficult. | |
277 | */ | |
278 | throttle_delay = throttle_host(iph1->remote, res) - time(NULL); | |
279 | if (throttle_delay > 0) { | |
280 | char *str; | |
281 | ||
85f41bec | 282 | str = saddrwop2str((struct sockaddr *)iph1->remote); |
52b7d2ce | 283 | |
65c25746 | 284 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
285 | "Throttling in action for %s: delay %lds\n", |
286 | str, (unsigned long)throttle_delay); | |
287 | res = -1; | |
288 | } else { | |
289 | throttle_delay = 0; | |
290 | } | |
291 | ||
292 | skip_auth: | |
293 | if (throttle_delay != 0) { | |
294 | struct xauth_reply_arg *xra; | |
295 | ||
296 | if ((xra = racoon_malloc(sizeof(*xra))) == NULL) { | |
65c25746 | 297 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 298 | "malloc failed, bypass throttling\n"); |
d1e348cf | 299 | return xauth_reply(iph1, port, id, res); |
52b7d2ce A |
300 | } |
301 | ||
302 | /* | |
303 | * We need to store the ph1, but it might have | |
304 | * disapeared when xauth_reply is called, so | |
305 | * store the index instead. | |
306 | */ | |
307 | xra->index = iph1->index; | |
308 | xra->port = port; | |
309 | xra->id = id; | |
310 | xra->res = res; | |
311 | sched_new(throttle_delay, xauth_reply_stub, xra); | |
312 | } else { | |
d1e348cf | 313 | return xauth_reply(iph1, port, id, res); |
52b7d2ce A |
314 | } |
315 | } | |
316 | ||
d1e348cf | 317 | return 0; |
52b7d2ce A |
318 | } |
319 | ||
320 | void | |
321 | xauth_reply_stub(args) | |
322 | void *args; | |
323 | { | |
324 | struct xauth_reply_arg *xra = (struct xauth_reply_arg *)args; | |
65c25746 | 325 | phase1_handle_t *iph1; |
52b7d2ce | 326 | |
65c25746 | 327 | if ((iph1 = ike_session_getph1byindex(NULL, &xra->index)) != NULL) |
d1e348cf | 328 | (void)xauth_reply(iph1, xra->port, xra->id, xra->res); |
52b7d2ce | 329 | else |
65c25746 | 330 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
331 | "Delayed Xauth reply: phase 1 no longer exists.\n"); |
332 | ||
333 | racoon_free(xra); | |
334 | return; | |
335 | } | |
336 | ||
d1e348cf | 337 | int |
52b7d2ce | 338 | xauth_reply(iph1, port, id, res) |
65c25746 | 339 | phase1_handle_t *iph1; |
52b7d2ce A |
340 | int port; |
341 | int id; | |
342 | { | |
343 | struct xauth_state *xst = &iph1->mode_cfg->xauth; | |
344 | char *usr = xst->authdata.generic.usr; | |
345 | ||
e8d9021d | 346 | if (iph1->is_dying) { |
65c25746 | 347 | plog(ASL_LEVEL_INFO, |
e8d9021d A |
348 | "dropped login for user \"%s\"\n", usr); |
349 | return -1; | |
350 | } | |
351 | ||
52b7d2ce A |
352 | if (res != 0) { |
353 | if (port != -1) | |
354 | isakmp_cfg_putport(iph1, port); | |
355 | ||
65c25746 | 356 | plog(ASL_LEVEL_INFO, |
52b7d2ce A |
357 | "login failed for user \"%s\"\n", usr); |
358 | ||
359 | xauth_sendstatus(iph1, XAUTH_STATUS_FAIL, id); | |
360 | xst->status = XAUTHST_NOTYET; | |
361 | ||
362 | /* Delete Phase 1 SA */ | |
65c25746 | 363 | if (FSM_STATE_IS_ESTABLISHED(iph1->status)) |
52b7d2ce | 364 | isakmp_info_send_d1(iph1); |
47612122 | 365 | isakmp_ph1expire(iph1); |
52b7d2ce | 366 | |
d1e348cf | 367 | return -1; |
52b7d2ce A |
368 | } |
369 | ||
370 | xst->status = XAUTHST_OK; | |
65c25746 | 371 | plog(ASL_LEVEL_INFO, |
52b7d2ce A |
372 | "login succeeded for user \"%s\"\n", usr); |
373 | ||
374 | xauth_sendstatus(iph1, XAUTH_STATUS_OK, id); | |
375 | ||
d1e348cf | 376 | return 0; |
52b7d2ce A |
377 | } |
378 | ||
379 | void | |
380 | xauth_sendstatus(iph1, status, id) | |
65c25746 | 381 | phase1_handle_t *iph1; |
52b7d2ce A |
382 | int status; |
383 | int id; | |
384 | { | |
385 | vchar_t *buffer; | |
386 | struct isakmp_pl_attr *attr; | |
387 | struct isakmp_data *stattr; | |
388 | size_t tlen; | |
389 | ||
390 | tlen = sizeof(*attr) + | |
391 | + sizeof(*stattr); | |
392 | ||
393 | if ((buffer = vmalloc(tlen)) == NULL) { | |
65c25746 | 394 | plog(ASL_LEVEL_ERR, "Cannot allocate buffer\n"); |
52b7d2ce A |
395 | return; |
396 | } | |
397 | ||
398 | attr = (struct isakmp_pl_attr *)buffer->v; | |
399 | memset(attr, 0, tlen); | |
400 | ||
401 | attr->h.len = htons(tlen); | |
402 | attr->type = ISAKMP_CFG_SET; | |
403 | attr->id = htons(id); | |
404 | ||
405 | stattr = (struct isakmp_data *)(attr + 1); | |
406 | stattr->type = htons(XAUTH_STATUS | ISAKMP_GEN_TV); | |
407 | stattr->lorv = htons(status); | |
408 | ||
409 | isakmp_cfg_send(iph1, buffer, | |
d1e348cf | 410 | ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 1, 0, NULL); |
52b7d2ce A |
411 | |
412 | vfree(buffer); | |
413 | ||
414 | return; | |
415 | } | |
416 | ||
d1e348cf | 417 | |
52b7d2ce A |
418 | int |
419 | xauth_login_system(usr, pwd) | |
420 | char *usr; | |
421 | char *pwd; | |
422 | { | |
423 | struct passwd *pw; | |
424 | char *cryptpwd; | |
425 | char *syscryptpwd; | |
426 | #ifdef HAVE_SHADOW_H | |
427 | struct spwd *spw; | |
428 | ||
429 | if ((spw = getspnam(usr)) == NULL) | |
430 | return -1; | |
431 | ||
432 | syscryptpwd = spw->sp_pwdp; | |
433 | #endif | |
434 | ||
435 | if ((pw = getpwnam(usr)) == NULL) | |
436 | return -1; | |
437 | ||
438 | #ifndef HAVE_SHADOW_H | |
439 | syscryptpwd = pw->pw_passwd; | |
440 | #endif | |
441 | ||
442 | /* No root login. Ever. */ | |
443 | if (pw->pw_uid == 0) | |
444 | return -1; | |
445 | ||
446 | if ((cryptpwd = crypt(pwd, syscryptpwd)) == NULL) | |
447 | return -1; | |
448 | ||
449 | if (strcmp(cryptpwd, syscryptpwd) == 0) | |
450 | return 0; | |
451 | ||
452 | return -1; | |
453 | } | |
454 | ||
d1e348cf A |
455 | int |
456 | xauth_group_system(usr, grp) | |
457 | char * usr; | |
458 | char * grp; | |
459 | { | |
460 | struct group * gr; | |
461 | char * member; | |
462 | int index = 0; | |
463 | ||
464 | gr = getgrnam(grp); | |
465 | if (gr == NULL) { | |
65c25746 | 466 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
467 | "the system group name \'%s\' is unknown\n", |
468 | grp); | |
469 | return -1; | |
470 | } | |
471 | ||
472 | while ((member = gr->gr_mem[index++])!=NULL) { | |
473 | if (!strcmp(member,usr)) { | |
65c25746 | 474 | plog(ASL_LEVEL_INFO, |
d1e348cf A |
475 | "membership validated\n"); |
476 | return 0; | |
477 | } | |
478 | } | |
479 | ||
480 | return -1; | |
481 | } | |
482 | ||
52b7d2ce A |
483 | int |
484 | xauth_check(iph1) | |
65c25746 | 485 | phase1_handle_t *iph1; |
52b7d2ce A |
486 | { |
487 | struct xauth_state *xst = &iph1->mode_cfg->xauth; | |
488 | ||
d1e348cf A |
489 | /* |
490 | * Only the server side (edge device) really check for Xauth | |
491 | * status. It does it if the chose authmethod is using Xauth. | |
492 | * On the client side (roadwarrior), we don't check anything. | |
493 | */ | |
494 | switch (AUTHMETHOD(iph1)) { | |
495 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: | |
496 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: | |
497 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: | |
52b7d2ce | 498 | /* The following are not yet implemented */ |
d1e348cf A |
499 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: |
500 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: | |
52b7d2ce | 501 | if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { |
65c25746 | 502 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
503 | "Hybrid auth negotiated but peer did not " |
504 | "announced as Xauth capable\n"); | |
505 | return -1; | |
506 | } | |
507 | ||
508 | if (xst->status != XAUTHST_OK) { | |
65c25746 | 509 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
510 | "Hybrid auth negotiated but peer did not " |
511 | "succeed Xauth exchange\n"); | |
512 | return -1; | |
513 | } | |
514 | ||
515 | return 0; | |
516 | break; | |
517 | default: | |
518 | return 0; | |
519 | break; | |
520 | } | |
521 | ||
522 | return 0; | |
523 | } | |
524 | ||
d1e348cf A |
525 | int |
526 | group_check(iph1, grp_list, grp_count) | |
65c25746 | 527 | phase1_handle_t *iph1; |
d1e348cf A |
528 | char **grp_list; |
529 | int grp_count; | |
530 | { | |
531 | int res = -1; | |
532 | int grp_index = 0; | |
533 | char * usr = NULL; | |
534 | ||
535 | /* check for presence of modecfg data */ | |
536 | ||
537 | if(iph1->mode_cfg == NULL) { | |
65c25746 | 538 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
539 | "xauth group specified but modecfg not found\n"); |
540 | return res; | |
541 | } | |
542 | ||
543 | /* loop through our group list */ | |
544 | ||
545 | for(; grp_index < grp_count; grp_index++) { | |
546 | ||
547 | /* check for presence of xauth data */ | |
548 | ||
549 | usr = iph1->mode_cfg->xauth.authdata.generic.usr; | |
550 | ||
551 | if(usr == NULL) { | |
65c25746 | 552 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
553 | "xauth group specified but xauth not found\n"); |
554 | return res; | |
555 | } | |
556 | ||
557 | /* call appropriate group validation funtion */ | |
558 | ||
559 | switch (isakmp_cfg_config.groupsource) { | |
560 | ||
561 | case ISAKMP_CFG_GROUP_SYSTEM: | |
562 | res = xauth_group_system( | |
563 | usr, | |
564 | grp_list[grp_index]); | |
565 | break; | |
566 | ||
d1e348cf A |
567 | default: |
568 | /* we should never get here */ | |
65c25746 | 569 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
570 | "Unknown group auth source\n"); |
571 | break; | |
572 | } | |
573 | ||
574 | if( !res ) { | |
65c25746 | 575 | plog(ASL_LEVEL_INFO, |
d1e348cf A |
576 | "user \"%s\" is a member of group \"%s\"\n", |
577 | usr, | |
578 | grp_list[grp_index]); | |
579 | break; | |
580 | } else { | |
65c25746 | 581 | plog(ASL_LEVEL_INFO, |
d1e348cf A |
582 | "user \"%s\" is not a member of group \"%s\"\n", |
583 | usr, | |
584 | grp_list[grp_index]); | |
585 | } | |
586 | } | |
587 | ||
588 | return res; | |
589 | } | |
590 | ||
52b7d2ce A |
591 | vchar_t * |
592 | isakmp_xauth_req(iph1, attr) | |
65c25746 | 593 | phase1_handle_t *iph1; |
52b7d2ce A |
594 | struct isakmp_data *attr; |
595 | { | |
596 | int type; | |
597 | size_t dlen = 0; | |
598 | int ashort = 0; | |
599 | int value = 0; | |
600 | vchar_t *buffer = NULL; | |
d1e348cf A |
601 | char* mraw = NULL; |
602 | vchar_t *mdata = NULL; | |
52b7d2ce A |
603 | char *data; |
604 | vchar_t *usr = NULL; | |
605 | vchar_t *pwd = NULL; | |
606 | size_t skip = 0; | |
607 | int freepwd = 0; | |
608 | ||
609 | if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { | |
65c25746 | 610 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
611 | "Xauth mode config request but peer " |
612 | "did not declare itself as Xauth capable\n"); | |
613 | return NULL; | |
614 | } | |
615 | ||
616 | type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; | |
617 | ||
618 | /* Sanity checks */ | |
619 | switch(type) { | |
620 | case XAUTH_TYPE: | |
621 | if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) { | |
65c25746 | 622 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
623 | "Unexpected long XAUTH_TYPE attribute\n"); |
624 | return NULL; | |
625 | } | |
626 | if (ntohs(attr->lorv) != XAUTH_TYPE_GENERIC) { | |
65c25746 | 627 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
628 | "Unsupported Xauth authentication %d\n", |
629 | ntohs(attr->lorv)); | |
630 | return NULL; | |
631 | } | |
632 | ashort = 1; | |
633 | dlen = 0; | |
634 | value = XAUTH_TYPE_GENERIC; | |
635 | break; | |
636 | ||
637 | case XAUTH_USER_NAME: | |
d1e348cf | 638 | if (!iph1->rmconf->xauth || !iph1->rmconf->xauth->login) { |
65c25746 | 639 | plog(ASL_LEVEL_ERR, "Xauth performed " |
52b7d2ce A |
640 | "with no login supplied\n"); |
641 | return NULL; | |
642 | } | |
643 | ||
d1e348cf A |
644 | dlen = iph1->rmconf->xauth->login->l - 1; |
645 | iph1->rmconf->xauth->state |= XAUTH_SENT_USERNAME; | |
52b7d2ce A |
646 | break; |
647 | ||
648 | case XAUTH_USER_PASSWORD: | |
d1e348cf A |
649 | case XAUTH_PASSCODE: |
650 | if (!iph1->rmconf->xauth || !iph1->rmconf->xauth->login) | |
52b7d2ce A |
651 | return NULL; |
652 | ||
653 | skip = sizeof(struct ipsecdoi_id_b); | |
d1e348cf A |
654 | usr = vmalloc(iph1->rmconf->xauth->login->l - 1 + skip); |
655 | if (usr == NULL) { | |
65c25746 | 656 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
657 | "Cannot allocate memory\n"); |
658 | return NULL; | |
659 | } | |
52b7d2ce A |
660 | memset(usr->v, 0, skip); |
661 | memcpy(usr->v + skip, | |
d1e348cf A |
662 | iph1->rmconf->xauth->login->v, |
663 | iph1->rmconf->xauth->login->l - 1); | |
52b7d2ce | 664 | |
d1e348cf | 665 | if (iph1->rmconf->xauth->pass) { |
52b7d2ce | 666 | /* A key given through racoonctl */ |
d1e348cf | 667 | pwd = iph1->rmconf->xauth->pass; |
52b7d2ce A |
668 | } else { |
669 | if ((pwd = getpskbyname(usr)) == NULL) { | |
65c25746 | 670 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 671 | "No password was found for login %s\n", |
d1e348cf | 672 | iph1->rmconf->xauth->login->v); |
52b7d2ce A |
673 | vfree(usr); |
674 | return NULL; | |
675 | } | |
676 | /* We have to free it before returning */ | |
677 | freepwd = 1; | |
678 | } | |
679 | vfree(usr); | |
680 | ||
d1e348cf A |
681 | iph1->rmconf->xauth->state |= XAUTH_SENT_PASSWORD; |
682 | dlen = pwd->l - 1; | |
52b7d2ce A |
683 | |
684 | break; | |
d1e348cf A |
685 | |
686 | case XAUTH_MESSAGE: | |
687 | if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) { | |
688 | dlen = ntohs(attr->lorv); | |
689 | if (dlen > 0) { | |
690 | mraw = (char*)(attr + 1); | |
691 | if ((mdata = vmalloc(dlen)) == NULL) { | |
65c25746 | 692 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
693 | "Cannot allocate memory\n"); |
694 | return NULL; | |
695 | } | |
696 | memcpy(mdata->v, mraw, mdata->l); | |
65c25746 | 697 | plog(ASL_LEVEL_NOTICE, "XAUTH Message: '%s'.\n", |
d1e348cf A |
698 | binsanitize(mdata->v, mdata->l)); |
699 | vfree(mdata); | |
700 | } | |
701 | } | |
702 | return NULL; | |
52b7d2ce | 703 | default: |
65c25746 | 704 | plog(ASL_LEVEL_WARNING, |
d1e348cf | 705 | "Ignored attribute %s\n", s_isakmp_cfg_type(type)); |
52b7d2ce A |
706 | return NULL; |
707 | break; | |
708 | } | |
709 | ||
710 | if ((buffer = vmalloc(sizeof(*attr) + dlen)) == NULL) { | |
65c25746 | 711 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
712 | "Cannot allocate memory\n"); |
713 | goto out; | |
714 | } | |
715 | ||
716 | attr = (struct isakmp_data *)buffer->v; | |
717 | if (ashort) { | |
718 | attr->type = htons(type | ISAKMP_GEN_TV); | |
719 | attr->lorv = htons(value); | |
720 | goto out; | |
721 | } | |
722 | ||
723 | attr->type = htons(type | ISAKMP_GEN_TLV); | |
724 | attr->lorv = htons(dlen); | |
725 | data = (char *)(attr + 1); | |
726 | ||
727 | switch(type) { | |
728 | case XAUTH_USER_NAME: | |
d1e348cf A |
729 | /* |
730 | * iph1->rmconf->xauth->login->v is valid, | |
731 | * we just checked it in the previous switch case | |
732 | */ | |
733 | memcpy(data, iph1->rmconf->xauth->login->v, dlen); | |
52b7d2ce A |
734 | break; |
735 | case XAUTH_USER_PASSWORD: | |
d1e348cf | 736 | case XAUTH_PASSCODE: |
52b7d2ce A |
737 | memcpy(data, pwd->v, dlen); |
738 | break; | |
739 | default: | |
740 | break; | |
741 | } | |
742 | ||
743 | out: | |
744 | if (freepwd) | |
745 | vfree(pwd); | |
746 | ||
747 | return buffer; | |
748 | } | |
749 | ||
750 | vchar_t * | |
751 | isakmp_xauth_set(iph1, attr) | |
65c25746 | 752 | phase1_handle_t *iph1; |
52b7d2ce A |
753 | struct isakmp_data *attr; |
754 | { | |
755 | int type; | |
756 | vchar_t *buffer = NULL; | |
d1e348cf A |
757 | struct xauth_state *xst; |
758 | size_t dlen = 0; | |
759 | char* mraw = NULL; | |
760 | vchar_t *mdata = NULL; | |
52b7d2ce A |
761 | |
762 | if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { | |
d1e348cf A |
763 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
764 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_DROP, | |
765 | CONSTSTR("XAUTH is not supported by peer"), | |
766 | CONSTSTR("XAUTH dropped (not supported by peer)")); | |
65c25746 | 767 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
768 | "Xauth mode config set but peer " |
769 | "did not declare itself as Xauth capable\n"); | |
770 | return NULL; | |
771 | } | |
772 | ||
773 | type = ntohs(attr->type) & ~ISAKMP_GEN_MASK; | |
774 | ||
775 | switch(type) { | |
776 | case XAUTH_STATUS: | |
d1e348cf A |
777 | /* |
778 | * We should only receive ISAKMP mode_cfg SET XAUTH_STATUS | |
779 | * when running as a client (initiator). | |
780 | */ | |
781 | xst = &iph1->mode_cfg->xauth; | |
782 | switch(AUTHMETHOD(iph1)) { | |
783 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: | |
784 | if (!iph1->is_rekey) { | |
785 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
786 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_DROP, | |
787 | CONSTSTR("Unexpected XAUTH Status"), | |
65c25746 A |
788 | CONSTSTR("Xauth dropped (unexpected Xauth status)... not a Phase 1 rekey")); |
789 | plog(ASL_LEVEL_ERR, | |
790 | "Unexpected XAUTH_STATUS_OK... not a Phase 1 rekey\n"); | |
d1e348cf A |
791 | return NULL; |
792 | } | |
793 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: | |
794 | case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: | |
795 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: | |
796 | /* Not implemented ... */ | |
d1e348cf A |
797 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: |
798 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: | |
799 | break; | |
800 | default: | |
801 | IPSECSESSIONTRACEREVENT(iph1->parent_session, | |
802 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_DROP, | |
803 | CONSTSTR("Unexpected XAUTH Status"), | |
804 | CONSTSTR("Xauth dropped (unexpected Xauth status)")); | |
65c25746 | 805 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
806 | "Unexpected XAUTH_STATUS_OK\n"); |
807 | return NULL; | |
808 | break; | |
809 | } | |
810 | ||
52b7d2ce A |
811 | /* If we got a failure, delete iph1 */ |
812 | if (ntohs(attr->lorv) != XAUTH_STATUS_OK) { | |
d1e348cf A |
813 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
814 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_FAIL, | |
815 | CONSTSTR("XAUTH Status is not OK"), | |
816 | CONSTSTR("Xauth Failed (status not ok)")); | |
65c25746 | 817 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 818 | "Xauth authentication failed\n"); |
d1e348cf A |
819 | |
820 | vpncontrol_notify_ike_failed(VPNCTL_NTYPE_AUTHENTICATION_FAILED, FROM_LOCAL, | |
821 | ((struct sockaddr_in*)iph1->remote)->sin_addr.s_addr, 0, NULL); | |
52b7d2ce A |
822 | |
823 | iph1->mode_cfg->flags |= ISAKMP_CFG_DELETE_PH1; | |
e8d9021d A |
824 | |
825 | IPSECLOGASLMSG("IPSec Extended Authentication Failed.\n"); | |
52b7d2ce | 826 | } else { |
d1e348cf A |
827 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
828 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_SUCC, | |
829 | CONSTSTR("XAUTH Status is OK"), | |
830 | CONSTSTR(NULL)); | |
d1e348cf A |
831 | if (iph1->is_rekey) { |
832 | xst->status = XAUTHST_OK; | |
833 | } | |
e8d9021d A |
834 | |
835 | IPSECLOGASLMSG("IPSec Extended Authentication Passed.\n"); | |
52b7d2ce A |
836 | } |
837 | ||
838 | ||
839 | /* We acknowledge it */ | |
840 | break; | |
d1e348cf A |
841 | case XAUTH_MESSAGE: |
842 | if ((ntohs(attr->type) & ISAKMP_GEN_TV) == 0) { | |
843 | dlen = ntohs(attr->lorv); | |
844 | if (dlen > 0) { | |
845 | mraw = (char*)(attr + 1); | |
846 | if ((mdata = vmalloc(dlen)) == NULL) { | |
65c25746 | 847 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
848 | "Cannot allocate memory\n"); |
849 | return NULL; | |
850 | } | |
851 | memcpy(mdata->v, mraw, mdata->l); | |
65c25746 | 852 | plog(ASL_LEVEL_NOTICE, "XAUTH Message: '%s'.\n", |
d1e348cf A |
853 | binsanitize(mdata->v, mdata->l)); |
854 | vfree(mdata); | |
855 | } | |
856 | } | |
857 | ||
52b7d2ce | 858 | default: |
d1e348cf A |
859 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
860 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_DROP, | |
861 | CONSTSTR("ignored attribute"), | |
862 | CONSTSTR("Xauth dropped (ignored attribute)")); | |
65c25746 | 863 | plog(ASL_LEVEL_WARNING, |
d1e348cf | 864 | "Ignored attribute %s\n", s_isakmp_cfg_type(type)); |
52b7d2ce A |
865 | return NULL; |
866 | break; | |
867 | } | |
868 | ||
869 | if ((buffer = vmalloc(sizeof(*attr))) == NULL) { | |
d1e348cf A |
870 | IPSECSESSIONTRACEREVENT(iph1->parent_session, |
871 | IPSECSESSIONEVENTCODE_IKEV1_XAUTH_DROP, | |
872 | CONSTSTR("Failed to allocate attribute"), | |
873 | CONSTSTR("Xauth dropped (failed to allocate attribute)")); | |
65c25746 | 874 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
875 | "Cannot allocate memory\n"); |
876 | return NULL; | |
877 | } | |
878 | ||
879 | attr = (struct isakmp_data *)buffer->v; | |
880 | attr->type = htons(type | ISAKMP_GEN_TV); | |
881 | attr->lorv = htons(0); | |
882 | ||
883 | return buffer; | |
884 | } | |
885 | ||
886 | ||
887 | void | |
888 | xauth_rmstate(xst) | |
889 | struct xauth_state *xst; | |
890 | { | |
891 | switch (xst->authtype) { | |
892 | case XAUTH_TYPE_GENERIC: | |
893 | if (xst->authdata.generic.usr) | |
894 | racoon_free(xst->authdata.generic.usr); | |
895 | ||
896 | if (xst->authdata.generic.pwd) | |
897 | racoon_free(xst->authdata.generic.pwd); | |
898 | ||
899 | break; | |
900 | ||
901 | case XAUTH_TYPE_CHAP: | |
902 | case XAUTH_TYPE_OTP: | |
903 | case XAUTH_TYPE_SKEY: | |
65c25746 | 904 | plog(ASL_LEVEL_WARNING, |
52b7d2ce A |
905 | "Unsupported authtype %d\n", xst->authtype); |
906 | break; | |
907 | ||
908 | default: | |
65c25746 | 909 | plog(ASL_LEVEL_WARNING, |
52b7d2ce A |
910 | "Unexpected authtype %d\n", xst->authtype); |
911 | break; | |
912 | } | |
913 | ||
914 | return; | |
915 | } | |
916 | ||
d1e348cf A |
917 | int |
918 | xauth_rmconf_used(xauth_rmconf) | |
919 | struct xauth_rmconf **xauth_rmconf; | |
920 | { | |
921 | if (*xauth_rmconf == NULL) { | |
922 | *xauth_rmconf = racoon_malloc(sizeof(**xauth_rmconf)); | |
923 | if (*xauth_rmconf == NULL) { | |
65c25746 | 924 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
925 | "xauth_rmconf_used: malloc failed\n"); |
926 | return -1; | |
927 | } | |
928 | ||
929 | (*xauth_rmconf)->login = NULL; | |
930 | (*xauth_rmconf)->pass = NULL; | |
931 | (*xauth_rmconf)->state = 0; | |
932 | } else { | |
933 | if ((*xauth_rmconf)->login) { | |
934 | vfree((*xauth_rmconf)->login); | |
935 | (*xauth_rmconf)->login = NULL; | |
936 | } | |
937 | if ((*xauth_rmconf)->pass != NULL) { | |
938 | vfree((*xauth_rmconf)->pass); | |
939 | (*xauth_rmconf)->pass = NULL; | |
940 | } | |
941 | (*xauth_rmconf)->state = 0; | |
942 | } | |
943 | ||
944 | return 0; | |
945 | } | |
946 | ||
947 | void | |
948 | xauth_rmconf_delete(xauth_rmconf) | |
949 | struct xauth_rmconf **xauth_rmconf; | |
950 | { | |
951 | if (*xauth_rmconf != NULL) { | |
952 | if ((*xauth_rmconf)->login != NULL) | |
953 | vfree((*xauth_rmconf)->login); | |
954 | if ((*xauth_rmconf)->pass != NULL) | |
955 | vfree((*xauth_rmconf)->pass); | |
956 | ||
957 | racoon_free(*xauth_rmconf); | |
958 | *xauth_rmconf = NULL; | |
959 | } | |
960 | ||
961 | return; | |
962 | } |