Coverage Report

Created: 2026-05-16 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libcharon/plugins/eap_radius/eap_radius.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2012-2018 Tobias Brunner
3
 * Copyright (C) 2009 Martin Willi
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include "eap_radius.h"
19
#include "eap_radius_plugin.h"
20
#include "eap_radius_forward.h"
21
#include "eap_radius_provider.h"
22
#include "eap_radius_accounting.h"
23
24
#include <radius_message.h>
25
#include <radius_client.h>
26
#include <bio/bio_writer.h>
27
28
#include <daemon.h>
29
30
typedef struct private_eap_radius_t private_eap_radius_t;
31
32
/**
33
 * Private data of an eap_radius_t object.
34
 */
35
struct private_eap_radius_t {
36
37
  /**
38
   * Public authenticator_t interface.
39
   */
40
  eap_radius_t public;
41
42
  /**
43
   * ID of the server
44
   */
45
  identification_t *server;
46
47
  /**
48
   * ID of the peer
49
   */
50
  identification_t *peer;
51
52
  /**
53
   * EAP method type we are proxying
54
   */
55
  eap_type_t type;
56
57
  /**
58
   * EAP vendor, if any
59
   */
60
  pen_t vendor;
61
62
  /**
63
   * EAP message identifier
64
   */
65
  uint8_t identifier;
66
67
  /**
68
   * RADIUS client instance
69
   */
70
  radius_client_t *client;
71
72
  /**
73
   * TRUE to use EAP-Start, FALSE to send EAP-Identity Response directly
74
   */
75
  bool eap_start;
76
77
  /**
78
   * Prefix to prepend to EAP identity
79
   */
80
  char *id_prefix;
81
};
82
83
/**
84
 * Add EAP-Identity to RADIUS message
85
 */
86
static void add_eap_identity(private_eap_radius_t *this,
87
               radius_message_t *request)
88
0
{
89
0
  struct {
90
    /** EAP code (REQUEST/RESPONSE) */
91
0
    uint8_t code;
92
    /** unique message identifier */
93
0
    uint8_t identifier;
94
    /** length of whole message */
95
0
    uint16_t length;
96
    /** EAP type */
97
0
    uint8_t type;
98
    /** identity data */
99
0
    uint8_t data[];
100
0
  } __attribute__((__packed__)) *hdr;
101
0
  chunk_t id, prefix;
102
0
  size_t len;
103
104
0
  id = this->peer->get_encoding(this->peer);
105
0
  prefix = chunk_create(this->id_prefix, strlen(this->id_prefix));
106
0
  len = sizeof(*hdr) + prefix.len + id.len;
107
108
0
  hdr = alloca(len);
109
0
  hdr->code = EAP_RESPONSE;
110
0
  hdr->identifier = this->identifier;
111
0
  hdr->length = htons(len);
112
0
  hdr->type = EAP_IDENTITY;
113
0
  memcpy(hdr->data, prefix.ptr, prefix.len);
114
0
  memcpy(hdr->data + prefix.len, id.ptr, id.len);
115
116
0
  request->add(request, RAT_EAP_MESSAGE, chunk_create((u_char*)hdr, len));
117
0
}
118
119
/**
120
 * Copy EAP-Message attribute from RADIUS message to an new EAP payload
121
 */
122
static bool radius2ike(private_eap_radius_t *this,
123
             radius_message_t *msg, eap_payload_t **out)
124
0
{
125
0
  enumerator_t *enumerator;
126
0
  eap_payload_t *payload;
127
0
  chunk_t data, message = chunk_empty;
128
0
  int type;
129
130
0
  enumerator = msg->create_enumerator(msg);
131
0
  while (enumerator->enumerate(enumerator, &type, &data))
132
0
  {
133
0
    if (type == RAT_EAP_MESSAGE && data.len)
134
0
    {
135
0
      message = chunk_cat("mc", message, data);
136
0
    }
137
0
  }
138
0
  enumerator->destroy(enumerator);
139
0
  if (message.len)
140
0
  {
141
0
    *out = payload = eap_payload_create_data(message);
142
143
    /* apply EAP method selected by RADIUS server */
144
0
    this->type = payload->get_type(payload, &this->vendor);
145
146
0
    DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &message);
147
0
    free(message.ptr);
148
0
    return TRUE;
149
0
  }
150
0
  return FALSE;
151
0
}
152
153
/**
154
 * See header.
155
 */
156
void eap_radius_build_attributes(radius_message_t *request)
157
0
{
158
0
  ike_sa_t *ike_sa;
159
0
  host_t *host;
160
0
  char buf[40], *station_id_fmt, *session_id;
161
0
  uint32_t value;
162
0
  chunk_t chunk;
163
164
  /* virtual NAS-Port-Type */
165
0
  value = htonl(5);
166
0
  request->add(request, RAT_NAS_PORT_TYPE, chunk_from_thing(value));
167
  /* framed ServiceType */
168
0
  value = htonl(2);
169
0
  request->add(request, RAT_SERVICE_TYPE, chunk_from_thing(value));
170
171
0
  ike_sa = charon->bus->get_sa(charon->bus);
172
0
  if (ike_sa)
173
0
  {
174
0
    value = htonl(ike_sa->get_unique_id(ike_sa));
175
0
    request->add(request, RAT_NAS_PORT, chunk_from_thing(value));
176
0
    request->add(request, RAT_NAS_PORT_ID,
177
0
           chunk_from_str(ike_sa->get_name(ike_sa)));
178
179
0
    host = ike_sa->get_my_host(ike_sa);
180
0
    chunk = host->get_address(host);
181
0
    switch (host->get_family(host))
182
0
    {
183
0
      case AF_INET:
184
0
        request->add(request, RAT_NAS_IP_ADDRESS, chunk);
185
0
        break;
186
0
      case AF_INET6:
187
0
        request->add(request, RAT_NAS_IPV6_ADDRESS, chunk);
188
0
      default:
189
0
        break;
190
0
    }
191
0
    if (lib->settings->get_bool(lib->settings,
192
0
                  "%s.plugins.eap-radius.station_id_with_port",
193
0
                  TRUE, lib->ns))
194
0
    {
195
0
      station_id_fmt = "%#H";
196
0
    }
197
0
    else
198
0
    {
199
0
      station_id_fmt = "%H";
200
0
    }
201
0
    snprintf(buf, sizeof(buf), station_id_fmt, host);
202
0
    request->add(request, RAT_CALLED_STATION_ID, chunk_from_str(buf));
203
0
    host = ike_sa->get_other_host(ike_sa);
204
0
    snprintf(buf, sizeof(buf), station_id_fmt, host);
205
0
    request->add(request, RAT_CALLING_STATION_ID, chunk_from_str(buf));
206
207
0
    session_id = eap_radius_accounting_session_id(ike_sa);
208
0
    if (session_id)
209
0
    {
210
0
      request->add(request, RAT_ACCT_SESSION_ID,
211
0
             chunk_from_str(session_id));
212
0
      free(session_id);
213
0
    }
214
0
  }
215
0
}
216
217
/**
218
 * Add a set of RADIUS attributes to a request message
219
 */
220
static void add_radius_request_attrs(private_eap_radius_t *this,
221
                   radius_message_t *request)
222
0
{
223
0
  chunk_t chunk;
224
225
0
  chunk = chunk_from_str(this->id_prefix);
226
0
  chunk = chunk_cata("cc", chunk, this->peer->get_encoding(this->peer));
227
0
  request->add(request, RAT_USER_NAME, chunk);
228
229
0
  eap_radius_build_attributes(request);
230
0
  eap_radius_forward_from_ike(request);
231
0
}
232
233
METHOD(eap_method_t, initiate, status_t,
234
  private_eap_radius_t *this, eap_payload_t **out)
235
0
{
236
0
  radius_message_t *request, *response;
237
0
  status_t status = FAILED;
238
239
0
  request = radius_message_create(RMC_ACCESS_REQUEST);
240
0
  add_radius_request_attrs(this, request);
241
242
0
  if (this->eap_start)
243
0
  {
244
0
    request->add(request, RAT_EAP_MESSAGE, chunk_empty);
245
0
  }
246
0
  else
247
0
  {
248
0
    add_eap_identity(this, request);
249
0
  }
250
251
0
  response = this->client->request(this->client, request);
252
0
  if (response)
253
0
  {
254
0
    eap_radius_forward_to_ike(response);
255
0
    switch (response->get_code(response))
256
0
    {
257
0
      case RMC_ACCESS_CHALLENGE:
258
0
        if (radius2ike(this, response, out))
259
0
        {
260
0
          status = NEED_MORE;
261
0
        }
262
0
        break;
263
0
      case RMC_ACCESS_ACCEPT:
264
        /* Microsoft RADIUS servers can run in a mode where they respond
265
         * like this on the first request (i.e. without authentication),
266
         * we treat this as Access-Reject */
267
0
      case RMC_ACCESS_REJECT:
268
0
      default:
269
0
        DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
270
0
           this->peer);
271
0
        break;
272
0
    }
273
0
    response->destroy(response);
274
0
  }
275
0
  else
276
0
  {
277
0
    eap_radius_handle_timeout(NULL);
278
0
  }
279
0
  request->destroy(request);
280
0
  return status;
281
0
}
282
283
/**
284
 * Handle the Class attribute
285
 */
286
static void process_class(radius_message_t *msg)
287
0
{
288
0
  enumerator_t *enumerator;
289
0
  ike_sa_t *ike_sa;
290
0
  identification_t *id;
291
0
  auth_cfg_t *auth;
292
0
  chunk_t data;
293
0
  bool class_group, class_send;
294
0
  int type;
295
296
0
  class_group = lib->settings->get_bool(lib->settings,
297
0
        "%s.plugins.eap-radius.class_group", FALSE, lib->ns);
298
0
  class_send = lib->settings->get_bool(lib->settings,
299
0
        "%s.plugins.eap-radius.accounting_send_class", FALSE, lib->ns);
300
0
  ike_sa = charon->bus->get_sa(charon->bus);
301
302
0
  if ((!class_group && !class_send) || !ike_sa)
303
0
  {
304
0
    return;
305
0
  }
306
307
0
  enumerator = msg->create_enumerator(msg);
308
0
  while (enumerator->enumerate(enumerator, &type, &data))
309
0
  {
310
0
    if (type == RAT_CLASS)
311
0
    {
312
0
      if (class_group && data.len < 44)
313
0
      { /* quirk: ignore long class attributes, these are used for
314
         * other purposes by some RADIUS servers (such as NPS). */
315
0
        auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
316
0
        id = identification_create_from_data(data);
317
0
        DBG1(DBG_CFG, "received group membership '%Y' from RADIUS",
318
0
           id);
319
0
        auth->add(auth, AUTH_RULE_GROUP, id);
320
0
      }
321
0
      if (class_send)
322
0
      {
323
0
        eap_radius_accounting_add_class(ike_sa, data);
324
0
      }
325
0
    }
326
0
  }
327
0
  enumerator->destroy(enumerator);
328
0
}
329
330
/**
331
 * Handle the Filter-Id attribute as IPsec CHILD_SA name
332
 */
333
static void process_filter_id(radius_message_t *msg)
334
0
{
335
0
  enumerator_t *enumerator;
336
0
  int type;
337
0
  uint8_t tunnel_tag DBG_UNUSED;
338
0
  uint32_t tunnel_type;
339
0
  chunk_t filter_id = chunk_empty, data;
340
0
  bool is_esp_tunnel = FALSE;
341
342
0
  enumerator = msg->create_enumerator(msg);
343
0
  while (enumerator->enumerate(enumerator, &type, &data))
344
0
  {
345
0
    switch (type)
346
0
    {
347
0
      case RAT_TUNNEL_TYPE:
348
0
        if (data.len != 4)
349
0
        {
350
0
          continue;
351
0
        }
352
0
        tunnel_tag = *data.ptr;
353
0
        *data.ptr = 0x00;
354
0
        tunnel_type = untoh32(data.ptr);
355
0
        DBG1(DBG_IKE, "received RADIUS attribute Tunnel-Type: "
356
0
                "tag = %u, value = %u", tunnel_tag, tunnel_type);
357
0
        is_esp_tunnel = (tunnel_type == RADIUS_TUNNEL_TYPE_ESP);
358
0
        break;
359
0
      case RAT_FILTER_ID:
360
0
        filter_id = data;
361
0
        DBG1(DBG_IKE, "received RADIUS attribute Filter-Id: "
362
0
                "'%.*s'", (int)filter_id.len, filter_id.ptr);
363
0
        break;
364
0
      default:
365
0
        break;
366
0
    }
367
0
  }
368
0
  enumerator->destroy(enumerator);
369
370
0
  if (is_esp_tunnel && filter_id.len)
371
0
  {
372
0
    identification_t *id;
373
0
    ike_sa_t *ike_sa;
374
0
    auth_cfg_t *auth;
375
376
0
    ike_sa = charon->bus->get_sa(charon->bus);
377
0
    if (ike_sa)
378
0
    {
379
0
      auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
380
0
      id = identification_create_from_data(filter_id);
381
0
      auth->add(auth, AUTH_RULE_GROUP, id);
382
0
    }
383
0
  }
384
0
}
385
386
/**
387
 * Handle Session-Timeout attribute and Interim updates
388
 */
389
static void process_timeout(radius_message_t *msg)
390
0
{
391
0
  enumerator_t *enumerator;
392
0
  ike_sa_t *ike_sa;
393
0
  chunk_t data;
394
0
  int type;
395
396
0
  ike_sa = charon->bus->get_sa(charon->bus);
397
0
  if (ike_sa)
398
0
  {
399
0
    enumerator = msg->create_enumerator(msg);
400
0
    while (enumerator->enumerate(enumerator, &type, &data))
401
0
    {
402
0
      if (type == RAT_SESSION_TIMEOUT && data.len == 4)
403
0
      {
404
0
        ike_sa->set_auth_lifetime(ike_sa, untoh32(data.ptr));
405
0
      }
406
0
      else if (type == RAT_ACCT_INTERIM_INTERVAL && data.len == 4)
407
0
      {
408
0
        eap_radius_accounting_start_interim(ike_sa, untoh32(data.ptr));
409
0
      }
410
0
    }
411
0
    enumerator->destroy(enumerator);
412
0
  }
413
0
}
414
415
/**
416
 * Add a Cisco Unity configuration attribute
417
 */
418
static void add_unity_attribute(eap_radius_provider_t *provider, uint32_t id,
419
                int type, chunk_t data)
420
0
{
421
0
  switch (type)
422
0
  {
423
0
    case 15: /* CVPN3000-IPSec-Banner1 */
424
0
    case 36: /* CVPN3000-IPSec-Banner2 */
425
0
      provider->add_attribute(provider, id, UNITY_BANNER, data);
426
0
      break;
427
0
    case 28: /* CVPN3000-IPSec-Default-Domain */
428
0
      provider->add_attribute(provider, id, UNITY_DEF_DOMAIN, data);
429
0
      break;
430
0
    case 29: /* CVPN3000-IPSec-Split-DNS-Names */
431
0
      provider->add_attribute(provider, id, UNITY_SPLITDNS_NAME, data);
432
0
      break;
433
0
  }
434
0
}
435
436
/**
437
 * Add a DNS/NBNS configuration attribute
438
 */
439
static void add_nameserver_attribute(eap_radius_provider_t *provider,
440
                   uint32_t id, int type, chunk_t data)
441
0
{
442
  /* these are from different vendors, but there is currently no conflict */
443
0
  switch (type)
444
0
  {
445
0
    case  5: /* CVPN3000-Primary-DNS */
446
0
    case  6: /* CVPN3000-Secondary-DNS */
447
0
    case 28: /* MS-Primary-DNS-Server */
448
0
    case 29: /* MS-Secondary-DNS-Server */
449
0
      provider->add_attribute(provider, id, INTERNAL_IP4_DNS, data);
450
0
      break;
451
0
    case  7: /* CVPN3000-Primary-WINS */
452
0
    case  8: /* CVPN3000-Secondary-WINS */
453
0
    case 30: /* MS-Primary-NBNS-Server */
454
0
    case 31: /* MS-Secondary-NBNS-Server */
455
0
      provider->add_attribute(provider, id, INTERNAL_IP4_NBNS, data);
456
0
      break;
457
0
    case RAT_FRAMED_IPV6_DNS_SERVER:
458
0
      provider->add_attribute(provider, id, INTERNAL_IP6_DNS, data);
459
0
      break;
460
0
  }
461
0
}
462
463
/**
464
 * Add a UNITY_LOCAL_LAN or UNITY_SPLIT_INCLUDE attribute
465
 */
466
static void add_unity_split_attribute(eap_radius_provider_t *provider,
467
              uint32_t id, configuration_attribute_type_t type,
468
              chunk_t data)
469
0
{
470
0
  enumerator_t *enumerator;
471
0
  bio_writer_t *writer;
472
0
  char buffer[256], *token, *slash;
473
474
0
  if (snprintf(buffer, sizeof(buffer), "%.*s", (int)data.len,
475
0
         data.ptr) >= sizeof(buffer))
476
0
  {
477
0
    return;
478
0
  }
479
0
  writer = bio_writer_create(16); /* two IPv4 addresses and 6 bytes padding */
480
0
  enumerator = enumerator_create_token(buffer, ",", " ");
481
0
  while (enumerator->enumerate(enumerator, &token))
482
0
  {
483
0
    host_t *net, *mask = NULL;
484
0
    chunk_t padding;
485
486
0
    slash = strchr(token, '/');
487
0
    if (slash)
488
0
    {
489
0
      *slash++ = '\0';
490
0
      mask = host_create_from_string(slash, 0);
491
0
    }
492
0
    if (!mask)
493
0
    { /* default to /32 */
494
0
      mask = host_create_from_string("255.255.255.255", 0);
495
0
    }
496
0
    net = host_create_from_string(token, 0);
497
0
    if (!net || net->get_family(net) != AF_INET ||
498
0
       mask->get_family(mask) != AF_INET)
499
0
    {
500
0
      mask->destroy(mask);
501
0
      DESTROY_IF(net);
502
0
      continue;
503
0
    }
504
0
    writer->write_data(writer, net->get_address(net));
505
0
    writer->write_data(writer, mask->get_address(mask));
506
0
    padding = writer->skip(writer, 6); /* 6 bytes padding */
507
0
    memset(padding.ptr, 0, padding.len);
508
0
    mask->destroy(mask);
509
0
    net->destroy(net);
510
0
  }
511
0
  enumerator->destroy(enumerator);
512
513
0
  data = writer->get_buf(writer);
514
0
  if (data.len)
515
0
  {
516
0
    provider->add_attribute(provider, id, type, data);
517
0
  }
518
0
  writer->destroy(writer);
519
0
}
520
521
/**
522
 * Handle Framed-IP-Address and other IKE configuration attributes
523
 */
524
static void process_cfg_attributes(radius_message_t *msg)
525
0
{
526
0
  eap_radius_provider_t *provider;
527
0
  enumerator_t *enumerator;
528
0
  ike_sa_t *ike_sa;
529
0
  host_t *host;
530
0
  chunk_t data;
531
0
  configuration_attribute_type_t split_type = 0;
532
0
  int type, vendor;
533
534
0
  ike_sa = charon->bus->get_sa(charon->bus);
535
0
  provider = eap_radius_provider_get();
536
0
  if (provider && ike_sa)
537
0
  {
538
0
    enumerator = msg->create_enumerator(msg);
539
0
    while (enumerator->enumerate(enumerator, &type, &data))
540
0
    {
541
0
      if ((type == RAT_FRAMED_IP_ADDRESS && data.len == 4) ||
542
0
        (type == RAT_FRAMED_IPV6_ADDRESS && data.len == 16))
543
0
      {
544
0
        host = host_create_from_chunk(AF_UNSPEC, data, 0);
545
0
        if (host)
546
0
        {
547
0
          provider->add_framed_ip(provider,
548
0
                  ike_sa->get_unique_id(ike_sa), host);
549
0
        }
550
0
      }
551
0
      else if (type == RAT_FRAMED_IP_NETMASK && data.len == 4)
552
0
      {
553
0
        provider->add_attribute(provider, ike_sa->get_unique_id(ike_sa),
554
0
                    INTERNAL_IP4_NETMASK, data);
555
0
      }
556
0
      else if (type == RAT_FRAMED_IPV6_DNS_SERVER && data.len == 16)
557
0
      {
558
0
        add_nameserver_attribute(provider,
559
0
                  ike_sa->get_unique_id(ike_sa), type, data);
560
0
      }
561
0
    }
562
0
    enumerator->destroy(enumerator);
563
564
0
    enumerator = msg->create_vendor_enumerator(msg);
565
0
    while (enumerator->enumerate(enumerator, &vendor, &type, &data))
566
0
    {
567
0
      if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */)
568
0
      {
569
0
        switch (type)
570
0
        {
571
0
          case  5: /* CVPN3000-Primary-DNS */
572
0
          case  6: /* CVPN3000-Secondary-DNS */
573
0
          case  7: /* CVPN3000-Primary-WINS */
574
0
          case  8: /* CVPN3000-Secondary-WINS */
575
0
            if (data.len == 4)
576
0
            {
577
0
              add_nameserver_attribute(provider,
578
0
                  ike_sa->get_unique_id(ike_sa), type, data);
579
0
            }
580
0
            break;
581
0
          case 15: /* CVPN3000-IPSec-Banner1 */
582
0
          case 28: /* CVPN3000-IPSec-Default-Domain */
583
0
          case 29: /* CVPN3000-IPSec-Split-DNS-Names */
584
0
          case 36: /* CVPN3000-IPSec-Banner2 */
585
0
            if (ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
586
0
            {
587
0
              add_unity_attribute(provider,
588
0
                  ike_sa->get_unique_id(ike_sa), type, data);
589
0
            }
590
0
            break;
591
0
          case 55: /* CVPN3000-IPSec-Split-Tunneling-Policy */
592
0
            if (data.len)
593
0
            {
594
0
              switch (data.ptr[data.len - 1])
595
0
              {
596
0
                case 0: /* tunnelall */
597
0
                default:
598
0
                  break;
599
0
                case 1: /* tunnelspecified */
600
0
                  split_type = UNITY_SPLIT_INCLUDE;
601
0
                  break;
602
0
                case 2: /* excludespecified */
603
0
                  split_type = UNITY_LOCAL_LAN;
604
0
                  break;
605
0
              }
606
0
            }
607
0
            break;
608
0
          default:
609
0
            break;
610
0
        }
611
0
      }
612
0
      if (vendor == PEN_MICROSOFT)
613
0
      {
614
0
        switch (type)
615
0
        {
616
0
          case 28: /* MS-Primary-DNS-Server */
617
0
          case 29: /* MS-Secondary-DNS-Server */
618
0
          case 30: /* MS-Primary-NBNS-Server */
619
0
          case 31: /* MS-Secondary-NBNS-Server */
620
0
            if (data.len == 4)
621
0
            {
622
0
              add_nameserver_attribute(provider,
623
0
                  ike_sa->get_unique_id(ike_sa), type, data);
624
0
            }
625
0
            break;
626
0
        }
627
0
      }
628
0
    }
629
0
    enumerator->destroy(enumerator);
630
631
0
    if (split_type != 0 &&
632
0
      ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
633
0
    {
634
0
      enumerator = msg->create_vendor_enumerator(msg);
635
0
      while (enumerator->enumerate(enumerator, &vendor, &type, &data))
636
0
      {
637
0
        if (vendor == PEN_ALTIGA /* aka Cisco VPN3000 */ &&
638
0
          type == 27 /* CVPN3000-IPSec-Split-Tunnel-List */)
639
0
        {
640
0
          add_unity_split_attribute(provider,
641
0
              ike_sa->get_unique_id(ike_sa), split_type, data);
642
0
        }
643
0
      }
644
0
      enumerator->destroy(enumerator);
645
0
    }
646
0
  }
647
0
}
648
649
/**
650
 * See header.
651
 */
652
void eap_radius_process_attributes(radius_message_t *message)
653
0
{
654
0
  process_class(message);
655
0
  if (lib->settings->get_bool(lib->settings,
656
0
            "%s.plugins.eap-radius.filter_id", FALSE, lib->ns))
657
0
  {
658
0
    process_filter_id(message);
659
0
  }
660
0
  process_timeout(message);
661
0
  process_cfg_attributes(message);
662
0
}
663
664
METHOD(eap_method_t, process, status_t,
665
  private_eap_radius_t *this, eap_payload_t *in, eap_payload_t **out)
666
0
{
667
0
  radius_message_t *request, *response;
668
0
  status_t status = FAILED;
669
0
  chunk_t data;
670
671
0
  request = radius_message_create(RMC_ACCESS_REQUEST);
672
0
  add_radius_request_attrs(this, request);
673
674
0
  data = in->get_data(in);
675
0
  DBG3(DBG_IKE, "%N payload %B", eap_type_names, this->type, &data);
676
677
  /* fragment data suitable for RADIUS */
678
0
  while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE)
679
0
  {
680
0
    request->add(request, RAT_EAP_MESSAGE,
681
0
           chunk_create(data.ptr,MAX_RADIUS_ATTRIBUTE_SIZE));
682
0
    data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE);
683
0
  }
684
0
  request->add(request, RAT_EAP_MESSAGE, data);
685
686
0
  response = this->client->request(this->client, request);
687
0
  if (response)
688
0
  {
689
0
    eap_radius_forward_to_ike(response);
690
0
    switch (response->get_code(response))
691
0
    {
692
0
      case RMC_ACCESS_CHALLENGE:
693
0
        if (radius2ike(this, response, out))
694
0
        {
695
0
          status = NEED_MORE;
696
0
          break;
697
0
        }
698
0
        status = FAILED;
699
0
        break;
700
0
      case RMC_ACCESS_ACCEPT:
701
0
        eap_radius_process_attributes(response);
702
0
        DBG1(DBG_IKE, "RADIUS authentication of '%Y' successful",
703
0
           this->peer);
704
0
        status = SUCCESS;
705
0
        break;
706
0
      case RMC_ACCESS_REJECT:
707
0
      default:
708
0
        DBG1(DBG_IKE, "RADIUS authentication of '%Y' failed",
709
0
           this->peer);
710
0
        status = FAILED;
711
0
        break;
712
0
    }
713
0
    response->destroy(response);
714
0
  }
715
0
  request->destroy(request);
716
0
  return status;
717
0
}
718
719
METHOD(eap_method_t, get_type, eap_type_t,
720
  private_eap_radius_t *this, pen_t *vendor)
721
0
{
722
0
  *vendor = this->vendor;
723
0
  return this->type;
724
0
}
725
726
METHOD(eap_method_t, get_msk, status_t,
727
  private_eap_radius_t *this, chunk_t *out)
728
0
{
729
0
  chunk_t msk;
730
731
0
  msk = this->client->get_msk(this->client);
732
0
  if (msk.len)
733
0
  {
734
0
    *out = msk;
735
0
    return SUCCESS;
736
0
  }
737
  /* we assume the selected method did not establish an MSK, if it failed
738
   * to establish one, process() would have failed */
739
0
  return NOT_SUPPORTED;
740
0
}
741
742
METHOD(eap_method_t, get_identifier, uint8_t,
743
  private_eap_radius_t *this)
744
0
{
745
0
  return this->identifier;
746
0
}
747
748
METHOD(eap_method_t, set_identifier, void,
749
  private_eap_radius_t *this, uint8_t identifier)
750
0
{
751
0
  this->identifier = identifier;
752
0
}
753
754
METHOD(eap_method_t, is_mutual, bool,
755
  private_eap_radius_t *this)
756
0
{
757
0
  switch (this->type)
758
0
  {
759
0
    case EAP_AKA:
760
0
    case EAP_SIM:
761
0
      return TRUE;
762
0
    default:
763
0
      return FALSE;
764
0
  }
765
0
}
766
767
METHOD(eap_method_t, destroy, void,
768
  private_eap_radius_t *this)
769
0
{
770
0
  this->peer->destroy(this->peer);
771
0
  this->server->destroy(this->server);
772
0
  this->client->destroy(this->client);
773
0
  free(this);
774
0
}
775
776
/**
777
 * Generic constructor
778
 */
779
eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer)
780
0
{
781
0
  private_eap_radius_t *this;
782
783
0
  INIT(this,
784
0
    .public = {
785
0
      .eap_method = {
786
0
        .initiate = _initiate,
787
0
        .process = _process,
788
0
        .get_type = _get_type,
789
0
        .is_mutual = _is_mutual,
790
0
        .get_msk = _get_msk,
791
0
        .get_identifier = _get_identifier,
792
0
        .set_identifier = _set_identifier,
793
0
        .destroy = _destroy,
794
0
      },
795
0
    },
796
    /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
797
0
    .type = EAP_RADIUS,
798
0
    .eap_start = lib->settings->get_bool(lib->settings,
799
0
                  "%s.plugins.eap-radius.eap_start", FALSE,
800
0
                  lib->ns),
801
0
    .id_prefix = lib->settings->get_str(lib->settings,
802
0
                  "%s.plugins.eap-radius.id_prefix", "",
803
0
                  lib->ns),
804
0
  );
805
0
  this->client = eap_radius_create_client();
806
0
  if (!this->client)
807
0
  {
808
0
    free(this);
809
0
    return NULL;
810
0
  }
811
0
  this->peer = peer->clone(peer);
812
0
  this->server = server->clone(server);
813
0
  return &this->public;
814
0
}