Coverage Report

Created: 2025-12-31 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/protocols/radius/base.c
Line
Count
Source
1
/*
2
 *   This library is free software; you can redistribute it and/or
3
 *   modify it under the terms of the GNU Lesser General Public
4
 *   License as published by the Free Software Foundation; either
5
 *   version 2.1 of the License, or (at your option) any later version.
6
 *
7
 *   This library is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
 *   Lesser General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU Lesser General Public
13
 *   License along with this library; if not, write to the Free Software
14
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15
 */
16
17
/**
18
 * $Id: 3edd26c403df7dfcdeef17694de8b9392c7bdae2 $
19
 *
20
 * @file protocols/radius/base.c
21
 * @brief Functions to send/receive radius packets.
22
 *
23
 * @copyright 2000-2003,2006 The FreeRADIUS server project
24
 */
25
RCSID("$Id: 3edd26c403df7dfcdeef17694de8b9392c7bdae2 $")
26
27
#include <fcntl.h>
28
#include <ctype.h>
29
30
#include "attrs.h"
31
#include "radius.h"
32
33
#include <freeradius-devel/io/pair.h>
34
#include <freeradius-devel/util/md5.h>
35
#include <freeradius-devel/util/net.h>
36
#include <freeradius-devel/util/proto.h>
37
#include <freeradius-devel/util/table.h>
38
#include <freeradius-devel/util/udp.h>
39
#include <freeradius-devel/protocol/radius/freeradius.internal.h>
40
41
static uint32_t instance_count = 0;
42
static bool instantiated = false;
43
44
fr_dict_t const *dict_freeradius;
45
fr_dict_t const *dict_radius;
46
47
extern fr_dict_autoload_t libfreeradius_radius_dict[];
48
fr_dict_autoload_t libfreeradius_radius_dict[] = {
49
  { .out = &dict_freeradius, .proto = "freeradius" },
50
  { .out = &dict_radius, .proto = "radius" },
51
52
  DICT_AUTOLOAD_TERMINATOR  
53
};
54
55
fr_dict_attr_t const *attr_packet_type;
56
fr_dict_attr_t const *attr_packet_authentication_vector;
57
fr_dict_attr_t const *attr_chap_challenge;
58
fr_dict_attr_t const *attr_chargeable_user_identity;
59
fr_dict_attr_t const *attr_eap_message;
60
fr_dict_attr_t const *attr_message_authenticator;
61
fr_dict_attr_t const *attr_state;
62
fr_dict_attr_t const *attr_vendor_specific;
63
fr_dict_attr_t const *attr_nas_filter_rule;
64
65
extern fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[];
66
fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[] = {
67
  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
68
  { .out = &attr_packet_authentication_vector, .name = "Packet-Authentication-Vector", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
69
  { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
70
  { .out = &attr_chargeable_user_identity, .name = "Chargeable-User-Identity", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
71
72
  { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
73
  { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
74
  { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
75
  { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
76
  { .out = &attr_nas_filter_rule, .name = "NAS-Filter-Rule", .type = FR_TYPE_STRING, .dict = &dict_radius },
77
78
  DICT_AUTOLOAD_TERMINATOR
79
};
80
81
/*
82
 *  Some messages get printed out only in debugging mode.
83
 */
84
120
#define FR_DEBUG_STRERROR_PRINTF    if (fr_debug_lvl) fr_strerror_printf
85
0
#define FR_DEBUG_STRERROR_PRINTF_PUSH   if (fr_debug_lvl) fr_strerror_printf_push
86
87
fr_table_num_sorted_t const fr_radius_require_ma_table[] = {
88
  { L("auto"),    FR_RADIUS_REQUIRE_MA_AUTO   },
89
  { L("false"),   FR_RADIUS_REQUIRE_MA_NO     },
90
  { L("no"),    FR_RADIUS_REQUIRE_MA_NO     },
91
  { L("true"),    FR_RADIUS_REQUIRE_MA_YES    },
92
  { L("yes"),   FR_RADIUS_REQUIRE_MA_YES    },
93
};
94
size_t fr_radius_require_ma_table_len = NUM_ELEMENTS(fr_radius_require_ma_table);
95
96
fr_table_num_sorted_t const fr_radius_limit_proxy_state_table[] = {
97
  { L("auto"),    FR_RADIUS_LIMIT_PROXY_STATE_AUTO  },
98
  { L("false"),   FR_RADIUS_LIMIT_PROXY_STATE_NO    },
99
  { L("no"),    FR_RADIUS_LIMIT_PROXY_STATE_NO    },
100
  { L("true"),    FR_RADIUS_LIMIT_PROXY_STATE_YES   },
101
  { L("yes"),   FR_RADIUS_LIMIT_PROXY_STATE_YES   },
102
};
103
size_t fr_radius_limit_proxy_state_table_len = NUM_ELEMENTS(fr_radius_limit_proxy_state_table);
104
105
fr_table_num_sorted_t const fr_radius_request_name_table[] = {
106
  { L("acct"),    FR_RADIUS_CODE_ACCOUNTING_REQUEST },
107
  { L("auth"),    FR_RADIUS_CODE_ACCESS_REQUEST   },
108
  { L("auto"),    FR_RADIUS_CODE_UNDEFINED    },
109
  { L("challenge"), FR_RADIUS_CODE_ACCESS_CHALLENGE   },
110
  { L("coa"),   FR_RADIUS_CODE_COA_REQUEST    },
111
  { L("disconnect"),  FR_RADIUS_CODE_DISCONNECT_REQUEST },
112
  { L("status"),    FR_RADIUS_CODE_STATUS_SERVER    }
113
};
114
size_t fr_radius_request_name_table_len = NUM_ELEMENTS(fr_radius_request_name_table);
115
116
char const *fr_radius_packet_name[FR_RADIUS_CODE_MAX] = {
117
  "",         //!< 0
118
  "Access-Request",
119
  "Access-Accept",
120
  "Access-Reject",
121
  "Accounting-Request",
122
  "Accounting-Response",
123
  "Accounting-Status",
124
  "Password-Request",
125
  "Password-Accept",
126
  "Password-Reject",
127
  "Accounting-Message",     //!< 10
128
  "Access-Challenge",
129
  "Status-Server",
130
  "Status-Client",
131
  "14",
132
  "15",
133
  "16",
134
  "17",
135
  "18",
136
  "19",
137
  "20",         //!< 20
138
  "Resource-Free-Request",
139
  "Resource-Free-Response",
140
  "Resource-Query-Request",
141
  "Resource-Query-Response",
142
  "Alternate-Resource-Reclaim-Request",
143
  "NAS-Reboot-Request",
144
  "NAS-Reboot-Response",
145
  "28",
146
  "Next-Passcode",
147
  "New-Pin",        //!< 30
148
  "Terminate-Session",
149
  "Password-Expired",
150
  "Event-Request",
151
  "Event-Response",
152
  "35",
153
  "36",
154
  "37",
155
  "38",
156
  "39",
157
  "Disconnect-Request",     //!< 40
158
  "Disconnect-ACK",
159
  "Disconnect-NAK",
160
  "CoA-Request",
161
  "CoA-ACK",
162
  "CoA-NAK",
163
  "46",
164
  "47",
165
  "48",
166
  "49",
167
  "IP-Address-Allocate",      //!< 50
168
  "IP-Address-Release",
169
  "Protocol-Error",
170
};
171
172
173
/** If we get a reply, the request must come from one of a small
174
 * number of packet types.
175
 */
176
static const fr_radius_packet_code_t allowed_replies[FR_RADIUS_CODE_MAX] = {
177
  [FR_RADIUS_CODE_ACCESS_ACCEPT]    = FR_RADIUS_CODE_ACCESS_REQUEST,
178
  [FR_RADIUS_CODE_ACCESS_CHALLENGE] = FR_RADIUS_CODE_ACCESS_REQUEST,
179
  [FR_RADIUS_CODE_ACCESS_REJECT]    = FR_RADIUS_CODE_ACCESS_REQUEST,
180
181
  [FR_RADIUS_CODE_ACCOUNTING_RESPONSE]  = FR_RADIUS_CODE_ACCOUNTING_REQUEST,
182
183
  [FR_RADIUS_CODE_COA_ACK]    = FR_RADIUS_CODE_COA_REQUEST,
184
  [FR_RADIUS_CODE_COA_NAK]    = FR_RADIUS_CODE_COA_REQUEST,
185
186
  [FR_RADIUS_CODE_DISCONNECT_ACK]   = FR_RADIUS_CODE_DISCONNECT_REQUEST,
187
  [FR_RADIUS_CODE_DISCONNECT_NAK]   = FR_RADIUS_CODE_DISCONNECT_REQUEST,
188
189
  [FR_RADIUS_CODE_PROTOCOL_ERROR]   = FR_RADIUS_CODE_PROTOCOL_ERROR,  /* Any */
190
};
191
192
FR_DICT_ATTR_FLAG_FUNC(fr_radius_attr_flags_t, abinary)
193
FR_DICT_ATTR_FLAG_FUNC(fr_radius_attr_flags_t, concat)
194
195
static int dict_flag_encrypt(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
196
96
{
197
96
  static fr_table_num_sorted_t const encrypted[] = {
198
96
    { L("Ascend-Secret"),  RADIUS_FLAG_ENCRYPT_ASCEND_SECRET },
199
96
    { L("Tunnel-Password"),  RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD },
200
96
    { L("User-Password"),  RADIUS_FLAG_ENCRYPT_USER_PASSWORD}
201
96
  };
202
96
  static size_t encrypted_len = NUM_ELEMENTS(encrypted);
203
204
96
  fr_radius_attr_flags_encrypt_t encrypt;
205
96
  fr_radius_attr_flags_t *flags = fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
206
207
96
  encrypt = fr_table_value_by_str(encrypted, value, RADIUS_FLAG_ENCRYPT_INVALID);
208
96
  if (encrypt == RADIUS_FLAG_ENCRYPT_INVALID) {
209
0
    fr_strerror_printf("Unknown encryption type '%s'", value);
210
0
    return -1;
211
0
  }
212
213
96
  flags->encrypt = encrypt;
214
215
96
  return 0;
216
96
}
217
218
FR_DICT_ATTR_FLAG_FUNC(fr_radius_attr_flags_t, extended)
219
FR_DICT_ATTR_FLAG_FUNC(fr_radius_attr_flags_t, has_tag)
220
FR_DICT_ATTR_FLAG_FUNC(fr_radius_attr_flags_t, long_extended)
221
222
static fr_dict_flag_parser_t const radius_flags[] = {
223
  { L("abinary"),     { .func = dict_flag_abinary } },
224
  { L("concat"),      { .func = dict_flag_concat } },
225
  { L("encrypt"),     { .func = dict_flag_encrypt, .needs_value = true } },
226
  { L("extended"),    { .func = dict_flag_extended } },
227
  { L("has_tag"),     { .func = dict_flag_has_tag } },
228
  { L("long_extended"),   { .func = dict_flag_long_extended } }
229
};
230
231
int fr_radius_allow_reply(int code, bool allowed[static FR_RADIUS_CODE_MAX])
232
0
{
233
0
  int i;
234
235
0
  if ((code <= 0) || (code >= FR_RADIUS_CODE_MAX)) return -1;
236
237
0
  for (i = 1; i < FR_RADIUS_CODE_MAX; i++) {
238
0
    allowed[i] |= (allowed_replies[i] == (fr_radius_packet_code_t) code);
239
0
  }
240
241
0
  return 0;
242
0
}
243
244
/**  Do Ascend-Send / Recv-Secret calculation.
245
 *
246
 * The secret is hidden by xoring with a MD5 digest created from
247
 * the RADIUS shared secret and the authentication vector.
248
 * We put them into MD5 in the reverse order from that used when
249
 * encrypting passwords to RADIUS.
250
 */
251
ssize_t fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen,
252
        char const *secret, uint8_t const *vector)
253
298
{
254
298
  fr_md5_ctx_t    *md5_ctx;
255
298
  size_t      i;
256
298
  uint8_t     digest[MD5_DIGEST_LENGTH];
257
298
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
258
259
298
  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, sizeof(digest));
260
261
298
  md5_ctx = fr_md5_ctx_alloc_from_list();
262
298
  fr_md5_update(md5_ctx, vector, RADIUS_AUTH_VECTOR_LENGTH);
263
298
  fr_md5_update(md5_ctx, (uint8_t const *) secret, talloc_array_length(secret) - 1);
264
298
  fr_md5_final(digest, md5_ctx);
265
298
  fr_md5_ctx_free_from_list(&md5_ctx);
266
267
298
  if (inlen > sizeof(digest)) inlen = sizeof(digest);
268
2.78k
  for (i = 0; i < inlen; i++) digest[i] ^= in[i];
269
270
298
  fr_dbuff_in_memcpy(&work_dbuff, digest, sizeof(digest));
271
272
298
  return fr_dbuff_set(dbuff, &work_dbuff);
273
298
}
274
275
/** Basic validation of RADIUS packet header
276
 *
277
 * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
278
 *  consumed when discarding malformed packet.
279
 *
280
 * @param[in] sockfd we're reading from.
281
 * @param[out] src_ipaddr of the packet.
282
 * @param[out] src_port of the packet.
283
 * @param[out] code Pointer to where to write the packet code.
284
 * @return
285
 *  - -1 on failure.
286
 *  - 1 on decode error.
287
 *  - >= RADIUS_HEADER_LENGTH on success. This is the packet length as specified in the header.
288
 */
289
ssize_t fr_radius_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, unsigned int *code)
290
0
{
291
0
  ssize_t     data_len, packet_len;
292
0
  uint8_t     header[4];
293
294
0
  data_len = udp_recv_peek(sockfd, header, sizeof(header), UDP_FLAGS_PEEK, src_ipaddr, src_port);
295
0
  if (data_len < 0) {
296
0
    if ((errno == EAGAIN) || (errno == EINTR)) return 0;
297
0
    return -1;
298
0
  }
299
300
  /*
301
   *  Too little data is available, discard the packet.
302
   */
303
0
  if (data_len < 4) {
304
0
    char buffer[INET6_ADDRSTRLEN];
305
306
0
    FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zd bytes", data_len);
307
0
invalid:
308
0
    FR_DEBUG_STRERROR_PRINTF_PUSH("Invalid data from %s",
309
0
                inet_ntop(src_ipaddr->af, &src_ipaddr->addr, buffer, sizeof(buffer)));
310
0
    (void) udp_recv_discard(sockfd);
311
312
0
    return 0;
313
0
  }
314
315
  /*
316
   *  See how long the packet says it is.
317
   */
318
0
  packet_len = (header[2] * 256) + header[3];
319
320
  /*
321
   *  The length in the packet says it's less than
322
   *  a RADIUS header length: discard it.
323
   */
324
0
  if (packet_len < RADIUS_HEADER_LENGTH) {
325
0
    FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HEADER_LENGTH)  " bytes of packet "
326
0
           "data, got %zd bytes", packet_len);
327
0
    goto invalid;
328
0
  }
329
330
  /*
331
   *  Enforce RFC requirements, for sanity.
332
   *  Anything after 4k will be discarded.
333
   */
334
0
  if (packet_len > MAX_PACKET_LEN) {
335
0
    FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
336
0
           STRINGIFY(MAX_PACKET_LEN) " bytes, got %zd bytes", packet_len);
337
0
    goto invalid;
338
0
  }
339
340
0
  *code = header[0];
341
342
  /*
343
   *  The packet says it's this long, but the actual UDP
344
   *  size could still be smaller.
345
   */
346
0
  return packet_len;
347
0
}
348
349
/** Sign a previously encoded packet
350
 *
351
 * Calculates the request/response authenticator for packets which need it, and fills
352
 * in the message-authenticator value if the attribute is present in the encoded packet.
353
 *
354
 * @param[in,out] packet  (request or response).
355
 * @param[in] vector    original packet vector to use
356
 * @param[in] secret    to sign the packet with.
357
 * @param[in] secret_len  The length of the secret.
358
 * @return
359
 *  - <0 on error
360
 *  - 0 on success
361
 */
362
int fr_radius_sign(uint8_t *packet, uint8_t const *vector,
363
       uint8_t const *secret, size_t secret_len)
364
0
{
365
0
  uint8_t   *msg, *end;
366
0
  size_t    packet_len = fr_nbo_to_uint16(packet + 2);
367
368
  /*
369
   *  No real limit on secret length, this is just
370
   *  to catch uninitialised fields.
371
   */
372
0
  if (!fr_cond_assert(secret_len <= UINT16_MAX)) {
373
0
    fr_strerror_printf("Secret is too long.  Expected <= %u, got %zu",
374
0
           (unsigned int) UINT16_MAX, secret_len);
375
0
    return -1;
376
0
  }
377
378
0
  if (packet_len < RADIUS_HEADER_LENGTH) {
379
0
    fr_strerror_const("Packet must be encoded before calling fr_radius_sign()");
380
0
    return -1;
381
0
  }
382
383
  /*
384
   *  Find Message-Authenticator.  Its value has to be
385
   *  calculated before we calculate the Request
386
   *  Authenticator or the Response Authenticator.
387
   */
388
0
  msg = packet + RADIUS_HEADER_LENGTH;
389
0
  end = packet + packet_len;
390
391
0
  while (msg < end) {
392
0
    if ((end - msg) < 2) goto invalid_attribute;
393
394
0
    if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
395
0
      if (msg[1] < 2) goto invalid_attribute;
396
397
0
      if ((msg + msg[1]) > end) {
398
0
      invalid_attribute:
399
0
        fr_strerror_printf("Invalid attribute at offset %zd", msg - packet);
400
0
        return -1;
401
0
      }
402
0
      msg += msg[1];
403
0
      continue;
404
0
    }
405
406
0
    if (msg[1] < 18) {
407
0
      fr_strerror_const("Message-Authenticator is too small");
408
0
      return -1;
409
0
    }
410
411
0
    switch (packet[0]) {
412
0
    case FR_RADIUS_CODE_ACCOUNTING_REQUEST:
413
0
    case FR_RADIUS_CODE_DISCONNECT_REQUEST:
414
0
    case FR_RADIUS_CODE_COA_REQUEST:
415
0
      memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
416
0
      break;
417
418
0
    case FR_RADIUS_CODE_ACCESS_ACCEPT:
419
0
    case FR_RADIUS_CODE_ACCESS_REJECT:
420
0
    case FR_RADIUS_CODE_ACCESS_CHALLENGE:
421
0
    case FR_RADIUS_CODE_ACCOUNTING_RESPONSE:
422
0
    case FR_RADIUS_CODE_DISCONNECT_ACK:
423
0
    case FR_RADIUS_CODE_DISCONNECT_NAK:
424
0
    case FR_RADIUS_CODE_COA_ACK:
425
0
    case FR_RADIUS_CODE_COA_NAK:
426
0
    case FR_RADIUS_CODE_PROTOCOL_ERROR:
427
0
      if (!vector) goto need_original;
428
0
      memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
429
0
      break;
430
431
0
    case FR_RADIUS_CODE_ACCESS_REQUEST:
432
0
    case FR_RADIUS_CODE_STATUS_SERVER:
433
      /* packet + 4 MUST be the Request Authenticator filled with random data */
434
0
      break;
435
436
0
    default:
437
0
      goto bad_packet;
438
0
    }
439
440
    /*
441
     *  Force Message-Authenticator to be zero,
442
     *  calculate the HMAC, and put it into the
443
     *  Message-Authenticator attribute.
444
     */
445
0
    memset(msg + 2, 0, RADIUS_AUTH_VECTOR_LENGTH);
446
0
    fr_hmac_md5(msg + 2, packet, packet_len, secret, secret_len);
447
0
    break;
448
0
  }
449
450
  /*
451
   *  Initialize the request authenticator.
452
   */
453
0
  switch (packet[0]) {
454
0
  case FR_RADIUS_CODE_ACCOUNTING_REQUEST:
455
0
  case FR_RADIUS_CODE_DISCONNECT_REQUEST:
456
0
  case FR_RADIUS_CODE_COA_REQUEST:
457
0
    memset(packet + 4, 0, RADIUS_AUTH_VECTOR_LENGTH);
458
0
    break;
459
460
0
  case FR_RADIUS_CODE_ACCESS_ACCEPT:
461
0
  case FR_RADIUS_CODE_ACCESS_REJECT:
462
0
  case FR_RADIUS_CODE_ACCESS_CHALLENGE:
463
0
  case FR_RADIUS_CODE_ACCOUNTING_RESPONSE:
464
0
  case FR_RADIUS_CODE_DISCONNECT_ACK:
465
0
  case FR_RADIUS_CODE_DISCONNECT_NAK:
466
0
  case FR_RADIUS_CODE_COA_ACK:
467
0
  case FR_RADIUS_CODE_COA_NAK:
468
0
  case FR_RADIUS_CODE_PROTOCOL_ERROR:
469
0
    if (!vector) {
470
0
    need_original:
471
0
      fr_strerror_const("Cannot sign response packet without a request packet");
472
0
      return -1;
473
0
    }
474
0
    memcpy(packet + 4, vector, RADIUS_AUTH_VECTOR_LENGTH);
475
0
    break;
476
477
    /*
478
     *  The Request Authenticator is random numbers.
479
     *  We don't need to sign anything else, so
480
     *  return.
481
     */
482
0
  case FR_RADIUS_CODE_ACCESS_REQUEST:
483
0
  case FR_RADIUS_CODE_STATUS_SERVER:
484
0
    return 0;
485
486
0
  default:
487
0
  bad_packet:
488
0
    fr_strerror_printf("Cannot sign unknown packet code %u", packet[0]);
489
0
    return -1;
490
0
  }
491
492
  /*
493
   *  Request / Response Authenticator = MD5(packet + secret)
494
   */
495
0
  {
496
0
    fr_md5_ctx_t  *md5_ctx;
497
498
0
    md5_ctx = fr_md5_ctx_alloc_from_list();
499
0
    fr_md5_update(md5_ctx, packet, packet_len);
500
0
    fr_md5_update(md5_ctx, secret, secret_len);
501
0
    fr_md5_final(packet + 4, md5_ctx);
502
0
    fr_md5_ctx_free_from_list(&md5_ctx);
503
0
  }
504
505
0
  return 0;
506
0
}
507
508
509
/** See if the data pointed to by PTR is a valid RADIUS packet.
510
 *
511
 * @param[in] packet    to check.
512
 * @param[in,out] packet_len_p  The size of the packet data.
513
 * @param[in] max_attributes  to allow in the packet.
514
 * @param[in] require_message_authenticator whether we require Message-Authenticator.
515
 * @param[in] reason    if not NULL, will have the failure reason written to where it points.
516
 * @return
517
 *  - True on success.
518
 *  - False on failure.
519
 */
520
bool fr_radius_ok(uint8_t const *packet, size_t *packet_len_p,
521
      uint32_t max_attributes, bool require_message_authenticator, fr_radius_decode_fail_t *reason)
522
5.19k
{
523
5.19k
  uint8_t const   *attr, *end;
524
5.19k
  size_t      totallen;
525
5.19k
  bool      seen_ma = false;
526
5.19k
  uint32_t    num_attributes;
527
5.19k
  fr_radius_decode_fail_t failure = DECODE_FAIL_NONE;
528
5.19k
  size_t      packet_len = *packet_len_p;
529
530
  /*
531
   *  Check for packets smaller than the packet header.
532
   *
533
   *  RFC 2865, Section 3., subsection 'length' says:
534
   *
535
   *  "The minimum length is 20 ..."
536
   */
537
5.19k
  if (packet_len < RADIUS_HEADER_LENGTH) {
538
9
    FR_DEBUG_STRERROR_PRINTF("Packet is too short (received %zu < minimum 20)",
539
9
           packet_len);
540
9
    failure = DECODE_FAIL_MIN_LENGTH_PACKET;
541
9
    goto finish;
542
9
  }
543
544
545
  /*
546
   *  Check for packets with mismatched size.
547
   *  i.e. We've received 128 bytes, and the packet header
548
   *  says it's 256 bytes long.
549
   */
550
5.18k
  totallen = fr_nbo_to_uint16(packet + 2);
551
552
  /*
553
   *  Code of 0 is not understood.
554
   *  Code of 16 or greater is not understood.
555
   */
556
5.18k
  if ((packet[0] == 0) ||
557
5.18k
      (packet[0] >= FR_RADIUS_CODE_MAX)) {
558
9
    FR_DEBUG_STRERROR_PRINTF("Unknown packet code %d", packet[0]);
559
9
    failure = DECODE_FAIL_UNKNOWN_PACKET_CODE;
560
9
    goto finish;
561
9
  }
562
563
5.18k
  switch (packet[0]) {
564
    /*
565
     *  Message-Authenticator is required in Status-Server
566
     *  packets, otherwise they can be trivially forged.
567
     */
568
5
  case FR_RADIUS_CODE_STATUS_SERVER:
569
5
    require_message_authenticator = true;
570
5
    break;
571
572
    /*
573
     *  Message-Authenticator may or may not be
574
     *  required for Access-* packets.
575
     */
576
210
  case FR_RADIUS_CODE_ACCESS_REQUEST:
577
375
  case FR_RADIUS_CODE_ACCESS_ACCEPT:
578
476
  case FR_RADIUS_CODE_ACCESS_CHALLENGE:
579
561
  case FR_RADIUS_CODE_ACCESS_REJECT:
580
641
  case FR_RADIUS_CODE_PROTOCOL_ERROR:
581
641
    break;
582
583
    /*
584
     *  Message-Authenticator is not required for all other packets.
585
     */
586
4.53k
  default:
587
4.53k
    require_message_authenticator = false;
588
4.53k
    break;
589
5.18k
  }
590
591
  /*
592
   *  Repeat the length checks.  This time, instead of
593
   *  looking at the data we received, look at the value
594
   *  of the 'length' field inside of the packet.
595
   *
596
   *  Check for packets smaller than the packet header.
597
   *
598
   *  RFC 2865, Section 3., subsection 'length' says:
599
   *
600
   *  "The minimum length is 20 ..."
601
   */
602
5.18k
  if (totallen < RADIUS_HEADER_LENGTH) {
603
10
    FR_DEBUG_STRERROR_PRINTF("Length in header is too small (length %zu < minimum 20)",
604
10
           totallen);
605
10
    failure = DECODE_FAIL_MIN_LENGTH_FIELD;
606
10
    goto finish;
607
10
  }
608
609
  /*
610
   *  And again, for the value of the 'length' field.
611
   *
612
   *  RFC 2865, Section 3., subsection 'length' says:
613
   *
614
   *  " ... and maximum length is 4096."
615
   *
616
   *  HOWEVER.  This requirement is for the network layer.
617
   *  If the code gets here, we assume that a well-formed
618
   *  packet is an OK packet.
619
   *
620
   *  We allow both the UDP data length, and the RADIUS
621
   *  "length" field to contain up to 64K of data.
622
   */
623
624
  /*
625
   *  RFC 2865, Section 3., subsection 'length' says:
626
   *
627
   *  "If the packet is shorter than the Length field
628
   *  indicates, it MUST be silently discarded."
629
   *
630
   *  i.e. No response to the NAS.
631
   */
632
5.17k
  if (totallen > packet_len) {
633
18
    FR_DEBUG_STRERROR_PRINTF("Packet is truncated (received %zu <  packet header length of %zu)",
634
18
           packet_len, totallen);
635
18
    failure = DECODE_FAIL_MIN_LENGTH_MISMATCH;
636
18
    goto finish;
637
18
  }
638
639
  /*
640
   *  RFC 2865, Section 3., subsection 'length' says:
641
   *
642
   *  "Octets outside the range of the Length field MUST be
643
   *  treated as padding and ignored on reception."
644
   */
645
5.15k
  if (totallen < packet_len) {
646
126
    *packet_len_p = packet_len = totallen;
647
126
  }
648
649
  /*
650
   *  Walk through the packet's attributes, ensuring that
651
   *  they add up EXACTLY to the size of the packet.
652
   *
653
   *  If they don't, then the attributes either under-fill
654
   *  or over-fill the packet.  Any parsing of the packet
655
   *  is impossible, and will result in unknown side effects.
656
   *
657
   *  This would ONLY happen with buggy RADIUS implementations,
658
   *  or with an intentional attack.  Either way, we do NOT want
659
   *  to be vulnerable to this problem.
660
   */
661
5.15k
  attr = packet + RADIUS_HEADER_LENGTH;
662
5.15k
  end = packet + packet_len;
663
5.15k
  num_attributes = 0;
664
665
139k
  while (attr < end) {
666
    /*
667
     *  We need at least 2 bytes to check the
668
     *  attribute header.
669
     */
670
134k
    if ((end - attr) < 2) {
671
10
      FR_DEBUG_STRERROR_PRINTF("Attribute header overflows the packet");
672
10
      failure = DECODE_FAIL_HEADER_OVERFLOW;
673
10
      goto finish;
674
10
    }
675
676
    /*
677
     *  Attribute number zero is NOT defined.
678
     */
679
134k
    if (attr[0] == 0) {
680
15
      FR_DEBUG_STRERROR_PRINTF("Invalid attribute 0 at offset %zd", attr - packet);
681
15
      failure = DECODE_FAIL_INVALID_ATTRIBUTE;
682
15
      goto finish;
683
15
    }
684
685
    /*
686
     *  Attributes are at LEAST as long as the ID & length
687
     *  fields.  Anything shorter is an invalid attribute.
688
     */
689
134k
    if (attr[1] < 2) {
690
4
      FR_DEBUG_STRERROR_PRINTF("Attribute %u is too short at offset %zd",
691
4
             attr[0], attr - packet);
692
4
      failure = DECODE_FAIL_ATTRIBUTE_TOO_SHORT;
693
4
      goto finish;
694
4
    }
695
696
    /*
697
     *  If there are fewer bytes in the packet than in the
698
     *  attribute, it's a bad packet.
699
     */
700
134k
    if ((attr + attr[1]) > end) {
701
12
      FR_DEBUG_STRERROR_PRINTF("Attribute %u data overflows the packet starting at offset %zd",
702
12
             attr[0], attr - packet);
703
12
      failure = DECODE_FAIL_ATTRIBUTE_OVERFLOW;
704
12
      goto finish;
705
12
    }
706
707
    /*
708
     *  Sanity check the attributes for length.
709
     */
710
134k
    switch (attr[0]) {
711
134k
    default:  /* don't do anything by default */
712
134k
      break;
713
714
      /*
715
       *  If there's an EAP-Message, we require
716
       *  a Message-Authenticator.
717
       */
718
134k
    case FR_EAP_MESSAGE:
719
229
      require_message_authenticator = true;
720
229
      break;
721
722
211
    case FR_MESSAGE_AUTHENTICATOR:
723
211
      if (attr[1] != 2 + RADIUS_AUTH_VECTOR_LENGTH) {
724
12
        FR_DEBUG_STRERROR_PRINTF("Message-Authenticator has invalid length (%d != 18) at offset %zd",
725
12
             attr[1] - 2, attr - packet);
726
12
        failure = DECODE_FAIL_MA_INVALID_LENGTH;
727
12
        goto finish;
728
12
      }
729
199
      seen_ma = true;
730
199
      break;
731
134k
    }
732
733
134k
    attr += attr[1];
734
134k
    num_attributes++; /* seen one more attribute */
735
134k
  }
736
737
  /*
738
   *  If the attributes add up to a packet, it's allowed.
739
   *
740
   *  If not, we complain, and throw the packet away.
741
   */
742
5.09k
  if (attr != end) {
743
0
    FR_DEBUG_STRERROR_PRINTF("Attributes do NOT exactly fill the packet");
744
0
    failure = DECODE_FAIL_ATTRIBUTE_UNDERFLOW;
745
0
    goto finish;
746
0
  }
747
748
  /*
749
   *  If we're configured to look for a maximum number of
750
   *  attributes, and we've seen more than that maximum,
751
   *  then throw the packet away, as a possible DoS.
752
   */
753
5.09k
  if ((max_attributes > 0) &&
754
5.09k
      (num_attributes > max_attributes)) {
755
13
    FR_DEBUG_STRERROR_PRINTF("Possible DoS attack - too many attributes in request (received %u, max %u are allowed).",
756
13
           num_attributes, max_attributes);
757
13
    failure = DECODE_FAIL_TOO_MANY_ATTRIBUTES;
758
13
    goto finish;
759
13
  }
760
761
  /*
762
   *  http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
763
   *
764
   *  A packet with an EAP-Message attribute MUST also have
765
   *  a Message-Authenticator attribute.
766
   *
767
   *  A Message-Authenticator all by itself is OK, though.
768
   *
769
   *  Similarly, Status-Server packets MUST contain
770
   *  Message-Authenticator attributes.
771
   */
772
5.08k
  if (require_message_authenticator && !seen_ma) {
773
8
    FR_DEBUG_STRERROR_PRINTF("We require Message-Authenticator attribute, but it is not in the packet");
774
8
    failure = DECODE_FAIL_MA_MISSING;
775
8
    goto finish;
776
8
  }
777
778
5.19k
finish:
779
780
5.19k
  if (reason) {
781
5.19k
    *reason = failure;
782
5.19k
  }
783
5.19k
  return (failure == DECODE_FAIL_NONE);
784
5.08k
}
785
786
787
/** Verify a request / response packet
788
 *
789
 *  This function does its work by calling fr_radius_sign(), and then
790
 *  comparing the signature in the packet with the one we calculated.
791
 *  If they differ, there's a problem.
792
 *
793
 * @param[in] packet        the raw RADIUS packet (request or response)
794
 * @param[in] vector        the original packet vector
795
 * @param[in] secret        the shared secret
796
 * @param[in] secret_len      the length of the secret
797
 * @param[in] require_message_authenticator whether we require Message-Authenticator.
798
 * @param[in] limit_proxy_state     whether we allow Proxy-State without Message-Authenticator.
799
 * @return
800
 *  < <0 on error (negative fr_radius_decode_fail_t)
801
 *  - 0 on success.
802
 */
803
int fr_radius_verify(uint8_t *packet, uint8_t const *vector,
804
         uint8_t const *secret, size_t secret_len,
805
         bool require_message_authenticator, bool limit_proxy_state)
806
0
{
807
0
  bool    found_message_authenticator = false;
808
0
  bool    found_proxy_state = false;
809
0
  int   rcode;
810
0
  int   code;
811
0
  uint8_t   *msg, *end;
812
0
  size_t    packet_len = fr_nbo_to_uint16(packet + 2);
813
0
  uint8_t   request_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
814
0
  uint8_t   message_authenticator[RADIUS_AUTH_VECTOR_LENGTH];
815
816
0
  if (packet_len < RADIUS_HEADER_LENGTH) {
817
0
    fr_strerror_printf("invalid packet length %zu", packet_len);
818
0
    return -DECODE_FAIL_MIN_LENGTH_PACKET;
819
0
  }
820
821
0
  code = packet[0];
822
0
  if (!code || (code >= FR_RADIUS_CODE_MAX)) {
823
0
    fr_strerror_printf("Unknown reply code %d", code);
824
0
    return -DECODE_FAIL_UNKNOWN_PACKET_CODE;
825
0
  }
826
827
0
  memcpy(request_authenticator, packet + 4, sizeof(request_authenticator));
828
829
  /*
830
   *  Find Message-Authenticator.  Its value has to be
831
   *  calculated before we calculate the Request
832
   *  Authenticator or the Response Authenticator.
833
   */
834
0
  msg = packet + RADIUS_HEADER_LENGTH;
835
0
  end = packet + packet_len;
836
837
0
  while (msg < end) {
838
0
    if ((end - msg) < 2) goto invalid_attribute;
839
840
0
    if (msg[0] != FR_MESSAGE_AUTHENTICATOR) {
841
0
      if (msg[1] < 2) goto invalid_attribute;
842
843
      /*
844
       *  If we're not allowing Proxy-State without
845
       *  Message-authenticator, we need to record
846
       *  the fact we found Proxy-State.
847
       */
848
0
      if (limit_proxy_state && (msg[0] == FR_PROXY_STATE)) found_proxy_state = true;
849
850
0
      if ((msg + msg[1]) > end) {
851
0
      invalid_attribute:
852
0
        fr_strerror_printf("invalid attribute at offset %zd", msg - packet);
853
0
        return -DECODE_FAIL_INVALID_ATTRIBUTE;
854
0
      }
855
0
      msg += msg[1];
856
0
      continue;
857
0
    }
858
859
0
    if (msg[1] < 18) {
860
0
      fr_strerror_const("too small Message-Authenticator");
861
0
      return -DECODE_FAIL_MA_INVALID_LENGTH;
862
0
    }
863
864
    /*
865
     *  Found it, save a copy.
866
     */
867
0
    memcpy(message_authenticator, msg + 2, sizeof(message_authenticator));
868
0
    found_message_authenticator = true;
869
0
    break;
870
0
  }
871
872
0
  if (packet[0] == FR_RADIUS_CODE_ACCESS_REQUEST) {
873
0
    if (limit_proxy_state && found_proxy_state && !found_message_authenticator) {
874
0
      fr_strerror_const("Proxy-State is not allowed without Message-Authenticator");
875
0
      return -DECODE_FAIL_MA_MISSING;
876
0
    }
877
878
0
        if (require_message_authenticator && !found_message_authenticator) {
879
0
      fr_strerror_const("Access-Request is missing the required Message-Authenticator attribute");
880
0
      return -DECODE_FAIL_MA_MISSING;
881
0
    }
882
0
  }
883
884
  /*
885
   *  Overwrite the contents of Message-Authenticator
886
   *  with the one we calculate.
887
   */
888
0
  rcode = fr_radius_sign(packet, vector, secret, secret_len);
889
0
  if (rcode < 0) {
890
0
    fr_strerror_const_push("Failed calculating correct authenticator");
891
0
    return -DECODE_FAIL_VERIFY;
892
0
  }
893
894
  /*
895
   *  Check the Message-Authenticator first.
896
   *
897
   *  If it's invalid, restore the original
898
   *  Message-Authenticator and Request Authenticator
899
   *  fields.
900
   *
901
   *  If it's valid the original and calculated
902
   *  message authenticators are the same, so we don't
903
   *  need to do anything.
904
   */
905
0
  if ((msg < end) &&
906
0
      (fr_digest_cmp(message_authenticator, msg + 2, sizeof(message_authenticator)) != 0)) {
907
0
    memcpy(msg + 2, message_authenticator, sizeof(message_authenticator));
908
0
    memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
909
910
0
    fr_strerror_const("invalid Message-Authenticator (shared secret is incorrect)");
911
0
    return -DECODE_FAIL_MA_INVALID;
912
0
  }
913
914
  /*
915
   *  These are random numbers, so there's no point in
916
   *  comparing them.
917
   */
918
0
  if ((packet[0] == FR_RADIUS_CODE_ACCESS_REQUEST) || (packet[0] == FR_RADIUS_CODE_STATUS_SERVER)) {
919
0
    return 0;
920
0
  }
921
922
  /*
923
   *  Check the Request Authenticator.
924
   */
925
0
  if (fr_digest_cmp(request_authenticator, packet + 4, sizeof(request_authenticator)) != 0) {
926
0
    memcpy(packet + 4, request_authenticator, sizeof(request_authenticator));
927
0
    if (vector) {
928
0
      fr_strerror_const("invalid Response Authenticator (shared secret is incorrect)");
929
0
    } else {
930
0
      fr_strerror_const("invalid Request Authenticator (shared secret is incorrect)");
931
0
    }
932
0
    return -DECODE_FAIL_VERIFY;
933
0
  }
934
935
0
  return 0;
936
0
}
937
938
void *fr_radius_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx);
939
940
void *fr_radius_next_encodable(fr_dcursor_t *cursor, void *current, void *uctx)
941
0
{
942
0
  fr_pair_t *c = current;
943
0
  fr_dict_t *dict = talloc_get_type_abort(uctx, fr_dict_t);
944
945
0
  while ((c = fr_dlist_next(cursor->dlist, c))) {
946
0
    PAIR_VERIFY(c);
947
0
    if ((c->da->dict == dict) &&
948
0
        (!c->da->flags.internal || ((c->da->attr > FR_TAG_BASE) && (c->da->attr < (FR_TAG_BASE + 0x20))))) {
949
0
      break;
950
0
    }
951
0
  }
952
953
0
  return c;
954
0
}
955
956
957
static const bool disallow_tunnel_passwords[FR_RADIUS_CODE_MAX] = {
958
  [ FR_RADIUS_CODE_ACCESS_REQUEST ] = true,
959
  // can be in Access-Accept
960
  [ FR_RADIUS_CODE_ACCESS_REJECT ] = true,
961
  [ FR_RADIUS_CODE_ACCESS_CHALLENGE ] = true,
962
963
  [ FR_RADIUS_CODE_ACCOUNTING_REQUEST ] = true,
964
  [ FR_RADIUS_CODE_ACCOUNTING_RESPONSE ] = true,
965
966
  [ FR_RADIUS_CODE_STATUS_SERVER ] = true,
967
968
  [ FR_RADIUS_CODE_COA_ACK ] = true,
969
  [ FR_RADIUS_CODE_COA_NAK ] = true,
970
971
  [ FR_RADIUS_CODE_DISCONNECT_REQUEST ] = true,
972
  [ FR_RADIUS_CODE_DISCONNECT_ACK ] = true,
973
  [ FR_RADIUS_CODE_DISCONNECT_NAK ] = true,
974
975
  [ FR_RADIUS_CODE_PROTOCOL_ERROR ] = true,
976
};
977
978
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
979
0
{
980
0
  ssize_t     slen;
981
0
  fr_pair_t const   *vp;
982
0
  fr_dcursor_t    cursor;
983
0
  fr_dbuff_t    work_dbuff, length_dbuff;
984
985
0
  packet_ctx->disallow_tunnel_passwords = disallow_tunnel_passwords[packet_ctx->code];
986
987
  /*
988
   *  The RADIUS header can't do more than 64K of data.
989
   */
990
0
  work_dbuff = FR_DBUFF_MAX(dbuff, 65535);
991
992
0
  FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, packet_ctx->code, packet_ctx->id);
993
0
  length_dbuff = FR_DBUFF(&work_dbuff);
994
0
  FR_DBUFF_IN_RETURN(&work_dbuff, (uint16_t) RADIUS_HEADER_LENGTH);
995
996
0
  switch (packet_ctx->code) {
997
0
  case FR_RADIUS_CODE_ACCESS_REQUEST:
998
0
  case FR_RADIUS_CODE_STATUS_SERVER:
999
0
    packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
1000
1001
    /*
1002
     *  Allow over-rides of the authentication vector for testing.
1003
     */
1004
0
    vp = fr_pair_find_by_da(vps, NULL, attr_packet_authentication_vector);
1005
0
    if (vp && (vp->vp_length >= RADIUS_AUTH_VECTOR_LENGTH)) {
1006
0
      FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_octets, RADIUS_AUTH_VECTOR_LENGTH);
1007
0
    } else {
1008
0
      int i;
1009
1010
0
      for (i = 0; i < 4; i++) {
1011
0
        FR_DBUFF_IN_RETURN(&work_dbuff, (uint32_t) fr_rand());
1012
0
      }
1013
0
    }
1014
0
    break;
1015
1016
0
  case FR_RADIUS_CODE_ACCESS_ACCEPT:
1017
0
  case FR_RADIUS_CODE_ACCESS_REJECT:
1018
0
  case FR_RADIUS_CODE_ACCESS_CHALLENGE:
1019
0
  case FR_RADIUS_CODE_ACCOUNTING_RESPONSE:
1020
0
  case FR_RADIUS_CODE_DISCONNECT_ACK:
1021
0
  case FR_RADIUS_CODE_DISCONNECT_NAK:
1022
0
  case FR_RADIUS_CODE_COA_ACK:
1023
0
  case FR_RADIUS_CODE_COA_NAK:
1024
0
  case FR_RADIUS_CODE_PROTOCOL_ERROR:
1025
0
    if (!packet_ctx->request_authenticator) {
1026
0
      fr_strerror_const("Cannot encode response without request");
1027
0
      return -1;
1028
0
    }
1029
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, packet_ctx->request_authenticator, RADIUS_AUTH_VECTOR_LENGTH);
1030
0
    break;
1031
1032
0
  case FR_RADIUS_CODE_ACCOUNTING_REQUEST:
1033
0
  case FR_RADIUS_CODE_DISCONNECT_REQUEST:
1034
    /*
1035
     *  Tunnel-Password encoded attributes are allowed
1036
     *  in CoA-Request packets, by RFC 5176 Section
1037
     *  3.6.  HOWEVER, the tunnel passwords are
1038
     *  "encrypted" using the Request Authenticator,
1039
     *  which is all zeros!  That makes them much
1040
     *  easier to decrypt.  The only solution here is
1041
     *  to say "don't do that!"
1042
     */
1043
0
  case FR_RADIUS_CODE_COA_REQUEST:
1044
0
    packet_ctx->request_authenticator = fr_dbuff_current(&work_dbuff);
1045
1046
0
    FR_DBUFF_MEMSET_RETURN(&work_dbuff, 0, RADIUS_AUTH_VECTOR_LENGTH);
1047
0
    break;
1048
1049
0
  default:
1050
0
    fr_strerror_printf("Cannot encode unknown packet code %d", packet_ctx->code);
1051
0
    return -1;
1052
0
  }
1053
1054
  /*
1055
   *  Always add Message-Authenticator after the packet
1056
   *  header for insecure transport protocols.
1057
   */
1058
0
  if (!packet_ctx->common->secure_transport) switch (packet_ctx->code) {
1059
0
  case FR_RADIUS_CODE_ACCESS_REQUEST:
1060
0
  case FR_RADIUS_CODE_ACCESS_ACCEPT:
1061
0
  case FR_RADIUS_CODE_ACCESS_REJECT:
1062
0
  case FR_RADIUS_CODE_ACCESS_CHALLENGE:
1063
0
  case FR_RADIUS_CODE_STATUS_SERVER:
1064
0
  case FR_RADIUS_CODE_PROTOCOL_ERROR:
1065
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_MESSAGE_AUTHENTICATOR, 0x12,
1066
0
           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1067
0
           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
1068
0
    packet_ctx->seen_message_authenticator = true;
1069
0
    break;
1070
1071
0
  default:
1072
0
    break;
1073
0
  }
1074
1075
  /*
1076
   *  If we're sending Protocol-Error, add in
1077
   *  Original-Packet-Code manually.  If the user adds it
1078
   *  later themselves, well, too bad.
1079
   */
1080
0
  if (packet_ctx->code == FR_RADIUS_CODE_PROTOCOL_ERROR) {
1081
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_EXTENDED_ATTRIBUTE_1, 0x07, 0x04 /* Original-Packet-Code */,
1082
0
           0x00, 0x00, 0x00, packet_ctx->request_code);
1083
0
  }
1084
1085
  /*
1086
   *  Loop over the reply attributes for the packet.
1087
   */
1088
0
  fr_pair_dcursor_iter_init(&cursor, vps, fr_radius_next_encodable, dict_radius);
1089
0
  while ((vp = fr_dcursor_current(&cursor))) {
1090
0
    PAIR_VERIFY(vp);
1091
1092
    /*
1093
     *  Encode an individual VP
1094
     */
1095
0
    slen = fr_radius_encode_pair(&work_dbuff, &cursor, packet_ctx);
1096
0
    if (slen < 0) return slen;
1097
0
  } /* done looping over all attributes */
1098
1099
  /*
1100
   *  Add Proxy-State to the end of the packet if the caller requested it.
1101
   */
1102
0
  if (packet_ctx->add_proxy_state) {
1103
0
    FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, FR_PROXY_STATE, (uint8_t) (2 + sizeof(packet_ctx->common->proxy_state)));
1104
0
    FR_DBUFF_IN_RETURN(&work_dbuff, packet_ctx->common->proxy_state);
1105
0
  }
1106
1107
  /*
1108
   *  Fill in the length field we zeroed out earlier.
1109
   *
1110
   */
1111
0
  fr_dbuff_in(&length_dbuff, (uint16_t) (fr_dbuff_used(&work_dbuff)));
1112
1113
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "%s encoded packet", __FUNCTION__);
1114
1115
0
  return fr_dbuff_set(dbuff, &work_dbuff);
1116
0
}
1117
1118
ssize_t fr_radius_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
1119
       uint8_t *packet, size_t packet_len,
1120
       fr_radius_decode_ctx_t *decode_ctx)
1121
5.07k
{
1122
5.07k
  ssize_t     slen;
1123
5.07k
  uint8_t const   *attr, *end;
1124
5.07k
  static const uint8_t    zeros[RADIUS_AUTH_VECTOR_LENGTH] = {};
1125
1126
5.07k
  if (!decode_ctx->request_authenticator) {
1127
0
    switch (packet[0]) {
1128
0
    case FR_RADIUS_CODE_ACCESS_REQUEST:
1129
0
    case FR_RADIUS_CODE_STATUS_SERVER:
1130
0
      decode_ctx->request_authenticator = packet + 4;
1131
0
      break;
1132
1133
0
    case FR_RADIUS_CODE_ACCOUNTING_REQUEST:
1134
0
    case FR_RADIUS_CODE_COA_REQUEST:
1135
0
    case FR_RADIUS_CODE_DISCONNECT_REQUEST:
1136
0
      decode_ctx->request_authenticator = zeros;
1137
0
      break;
1138
1139
0
    default:
1140
0
      fr_strerror_const("No authentication vector passed for packet decode");
1141
0
      return -1;
1142
0
    }
1143
0
  }
1144
1145
5.07k
  if (decode_ctx->request_code) {
1146
0
    unsigned int code = packet[0];
1147
1148
0
    if (code >= FR_RADIUS_CODE_MAX) {
1149
0
      return -DECODE_FAIL_UNKNOWN_PACKET_CODE;
1150
0
    }
1151
0
    if (decode_ctx->request_code >= FR_RADIUS_CODE_MAX) {
1152
0
      return -DECODE_FAIL_UNKNOWN_PACKET_CODE;
1153
0
    }
1154
1155
0
    if (!allowed_replies[code]) {
1156
0
      fr_strerror_printf("%s packet received unknown reply code %s",
1157
0
             fr_radius_packet_name[decode_ctx->request_code], fr_radius_packet_name[code]);
1158
0
      return -DECODE_FAIL_UNKNOWN_PACKET_CODE;
1159
0
    }
1160
1161
    /*
1162
     *  Protocol error can reply to any packet.
1163
     *
1164
     *  Status-Server can get any reply.
1165
     *
1166
     *  Otherwise the reply code must be associated with the request code we sent.
1167
     */
1168
0
    if ((allowed_replies[code] != decode_ctx->request_code) &&
1169
0
        (code != FR_RADIUS_CODE_PROTOCOL_ERROR) &&
1170
0
        (decode_ctx->request_code != FR_RADIUS_CODE_STATUS_SERVER)) {
1171
0
      fr_strerror_printf("%s packet received invalid reply code %s",
1172
0
             fr_radius_packet_name[decode_ctx->request_code], fr_radius_packet_name[code]);
1173
0
      return -DECODE_FAIL_UNKNOWN_PACKET_CODE;
1174
0
    }
1175
0
  }
1176
1177
  /*
1178
   *  We can skip verification for dynamic client checks, and where packets are unsigned as with
1179
   *  RADIUS/1.1.
1180
   */
1181
5.07k
  if (decode_ctx->verify) {
1182
0
    if (!decode_ctx->request_authenticator) decode_ctx->request_authenticator = zeros;
1183
1184
0
    if (fr_radius_verify(packet, decode_ctx->request_authenticator,
1185
0
             (uint8_t const *) decode_ctx->common->secret, decode_ctx->common->secret_length,
1186
0
             decode_ctx->require_message_authenticator, decode_ctx->limit_proxy_state) < 0) {
1187
0
      return -1;
1188
0
    }
1189
0
  }
1190
1191
5.07k
  attr = packet + 20;
1192
5.07k
  end = packet + packet_len;
1193
1194
  /*
1195
   *  The caller MUST have called fr_radius_ok() first.  If
1196
   *  he doesn't, all hell breaks loose.
1197
   */
1198
68.3k
  while (attr < end) {
1199
63.4k
    slen = fr_radius_decode_pair(ctx, out, attr, (end - attr), decode_ctx);
1200
63.4k
    if (slen < 0) return slen;
1201
1202
    /*
1203
     *  If slen is larger than the room in the packet,
1204
     *  all kinds of bad things happen.
1205
     */
1206
63.3k
     if (!fr_cond_assert(slen <= (end - attr))) {
1207
0
       return -slen;
1208
0
     }
1209
1210
63.3k
    attr += slen;
1211
63.3k
    talloc_free_children(decode_ctx->tmp_ctx);
1212
63.3k
  }
1213
1214
  /*
1215
   *  We've parsed the whole packet, return that.
1216
   */
1217
4.98k
  return packet_len;
1218
5.07k
}
1219
1220
/** Simple wrapper for callers who just need a shared secret
1221
 *
1222
 */
1223
ssize_t fr_radius_decode_simple(TALLOC_CTX *ctx, fr_pair_list_t *out,
1224
        uint8_t *packet, size_t packet_len,
1225
        uint8_t const *vector, char const *secret)
1226
0
{
1227
0
  ssize_t rcode;
1228
0
  fr_radius_ctx_t   common_ctx = {};
1229
0
  fr_radius_decode_ctx_t  packet_ctx = {};
1230
1231
0
  common_ctx.secret = secret;
1232
0
  common_ctx.secret_length = strlen(secret);
1233
1234
0
  packet_ctx.common = &common_ctx;
1235
0
  packet_ctx.tmp_ctx = talloc(ctx, uint8_t);
1236
0
  packet_ctx.request_authenticator = vector;
1237
0
  packet_ctx.end = packet + packet_len;
1238
1239
0
  rcode = fr_radius_decode(ctx, out, packet, packet_len, &packet_ctx);
1240
0
  talloc_free(packet_ctx.tmp_ctx);
1241
1242
0
  return rcode;
1243
0
}
1244
1245
int fr_radius_global_init(void)
1246
4
{
1247
4
  if (instance_count > 0) {
1248
2
    instance_count++;
1249
2
    return 0;
1250
2
  }
1251
1252
2
  instance_count++;
1253
1254
2
  if (fr_dict_autoload(libfreeradius_radius_dict) < 0) {
1255
0
  fail:
1256
0
    instance_count--;
1257
0
    return -1;
1258
0
  }
1259
1260
2
  if (fr_dict_attr_autoload(libfreeradius_radius_dict_attr) < 0) {
1261
0
    fr_dict_autofree(libfreeradius_radius_dict);
1262
0
    goto fail;
1263
0
  }
1264
1265
2
  instantiated = true;
1266
2
  return 0;
1267
2
}
1268
1269
void fr_radius_global_free(void)
1270
4
{
1271
4
  if (!instantiated) return;
1272
1273
4
  if (--instance_count != 0) return;
1274
1275
2
  fr_dict_autofree(libfreeradius_radius_dict);
1276
2
}
1277
1278
static bool attr_valid(fr_dict_attr_t *da)
1279
17.0k
{
1280
17.0k
  fr_radius_attr_flags_t const *flags = fr_radius_attr_flags(da);
1281
1282
17.0k
  if (da->parent->type == FR_TYPE_STRUCT) {
1283
346
    if (flags->extended) {
1284
0
      fr_strerror_const("Attributes of type 'extended' cannot be used inside of a 'struct'");
1285
0
      return false;
1286
0
    }
1287
1288
346
    if (flags->long_extended) {
1289
0
      fr_strerror_const("Attributes of type 'long_extended' cannot be used inside of a 'struct'");
1290
0
      return false;
1291
0
    }
1292
1293
1294
346
    if (flags->concat) {
1295
0
      fr_strerror_const("Attributes of type 'concat' cannot be used inside of a 'struct'");
1296
0
      return false;
1297
0
    }
1298
1299
346
    if (flags->has_tag) {
1300
0
      fr_strerror_const("Attributes of type 'concat' cannot be used inside of a 'struct'");
1301
0
      return false;
1302
0
    }
1303
1304
346
    if (flags->abinary) {
1305
0
      fr_strerror_const("Attributes of type 'abinary' cannot be used inside of a 'struct'");
1306
0
      return false;
1307
0
    }
1308
1309
346
    if (flags->encrypt > 0) {
1310
0
      fr_strerror_const("Attributes of type 'encrypt' cannot be used inside of a 'struct'");
1311
0
      return false;
1312
0
    }
1313
1314
346
    return true;
1315
346
  }
1316
1317
16.6k
  if (da->flags.length > 253) {
1318
0
    fr_strerror_printf("Attributes cannot be more than 253 octets in length");
1319
0
    return false;
1320
0
  }
1321
  /*
1322
   *  Secret things are secret.
1323
   */
1324
16.6k
  if (flags->encrypt != 0) da->flags.secret = true;
1325
1326
16.6k
  if (flags->concat) {
1327
8
    if (!da->parent->flags.is_root) {
1328
0
      fr_strerror_const("Attributes with the 'concat' flag MUST be at the root of the dictionary");
1329
0
      return false;
1330
0
    }
1331
1332
8
    if (da->type != FR_TYPE_OCTETS) {
1333
0
      fr_strerror_const("Attributes with the 'concat' flag MUST be of data type 'octets'");
1334
0
      return false;
1335
0
    }
1336
1337
8
    return true; /* can't use any other flag */
1338
8
  }
1339
1340
  /*
1341
   *  Tagged attributes can only be of two data types.  They
1342
   *  can, however, be VSAs.
1343
   */
1344
16.6k
  if (flags->has_tag) {
1345
84
    if ((da->type != FR_TYPE_UINT32) && (da->type != FR_TYPE_STRING)) {
1346
0
      fr_strerror_printf("The 'has_tag' flag can only be used for attributes of type 'integer' "
1347
0
             "or 'string'");
1348
0
      return false;
1349
0
    }
1350
1351
84
    if (!(da->parent->flags.is_root ||
1352
64
          ((da->parent->type == FR_TYPE_VENDOR) &&
1353
64
           (da->parent->parent && da->parent->parent->type == FR_TYPE_VSA)))) {
1354
0
      fr_strerror_const("The 'has_tag' flag can only be used with RFC and VSA attributes");
1355
0
      return false;
1356
0
    }
1357
1358
84
    return true;
1359
84
  }
1360
1361
16.5k
  if (flags->extended) {
1362
8
    if (da->type != FR_TYPE_TLV) {
1363
0
      fr_strerror_const("The 'long' or 'extended' flag can only be used for attributes of type 'tlv'");
1364
0
      return false;
1365
0
    }
1366
1367
8
    if (!da->parent->flags.is_root) {
1368
0
      fr_strerror_const("The 'long' flag can only be used for top-level RFC attributes");
1369
0
      return false;
1370
0
    }
1371
1372
8
    return true;
1373
8
  }
1374
1375
  /*
1376
   *  Stupid hacks for MS-CHAP-MPPE-Keys.  The User-Password
1377
   *  encryption method has no provisions for encoding the
1378
   *  length of the data.  For User-Password, the data is
1379
   *  (presumably) all printable non-zero data.  For
1380
   *  MS-CHAP-MPPE-Keys, the data is binary crap.  So... we
1381
   *  MUST specify a length in the dictionary.
1382
   */
1383
16.5k
  if ((flags->encrypt == RADIUS_FLAG_ENCRYPT_USER_PASSWORD) && (da->type != FR_TYPE_STRING)) {
1384
2
    if (da->type != FR_TYPE_OCTETS) {
1385
0
      fr_strerror_printf("The 'encrypt=User-Password' flag can only be used with "
1386
0
             "attributes of type 'string'");
1387
0
      return false;
1388
0
    }
1389
1390
2
    if (da->flags.length == 0) {
1391
0
      fr_strerror_printf("The 'encrypt=User-Password' flag MUST be used with an explicit length for "
1392
0
             "'octets' data types");
1393
0
      return false;
1394
0
    }
1395
2
  }
1396
1397
16.5k
  switch (da->type) {
1398
5.88k
  case FR_TYPE_STRING:
1399
5.88k
    break;
1400
1401
146
  case FR_TYPE_TLV:
1402
794
  case FR_TYPE_IPV4_ADDR:
1403
6.82k
  case FR_TYPE_UINT32:
1404
7.51k
  case FR_TYPE_OCTETS:
1405
7.51k
    if (flags->encrypt != RADIUS_FLAG_ENCRYPT_ASCEND_SECRET) break;
1406
0
    FALL_THROUGH;
1407
1408
3.15k
  default:
1409
3.15k
    if (flags->encrypt) {
1410
0
      fr_strerror_printf("The 'encrypt' flag cannot be used with attributes of type '%s'",
1411
0
             fr_type_to_str(da->type));
1412
0
      return false;
1413
0
    }
1414
16.5k
  }
1415
1416
16.5k
  return true;
1417
16.5k
}
1418
1419
extern fr_dict_protocol_t libfreeradius_radius_dict_protocol;
1420
fr_dict_protocol_t libfreeradius_radius_dict_protocol = {
1421
  .name = "radius",
1422
  .default_type_size = 1,
1423
  .default_type_length = 1,
1424
  .attr = {
1425
    .flags = {
1426
      .table = radius_flags,
1427
      .table_len = NUM_ELEMENTS(radius_flags),
1428
      .len = sizeof(fr_radius_attr_flags_t),
1429
    },
1430
    .valid = attr_valid,
1431
  },
1432
1433
  .init = fr_radius_global_init,
1434
  .free = fr_radius_global_free,
1435
1436
  .decode = fr_radius_decode_foreign,
1437
  .encode = fr_radius_encode_foreign,
1438
};