~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/radius/radius.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2007-08-26 16:06:57 UTC
  • mto: This revision was merged to the branch mainline in revision 26.
  • Revision ID: james.westby@ubuntu.com-20070826160657-mxk5ivjjh65ptxlr
Tags: upstream-0.6.0+0.5.8
ImportĀ upstreamĀ versionĀ 0.6.0+0.5.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * hostapd / RADIUS message processing
3
 
 * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License version 2 as
7
 
 * published by the Free Software Foundation.
8
 
 *
9
 
 * Alternatively, this software may be distributed under the terms of BSD
10
 
 * license.
11
 
 *
12
 
 * See README and COPYING for more details.
13
 
 */
14
 
 
15
 
#include "includes.h"
16
 
 
17
 
#include "common.h"
18
 
#include "radius.h"
19
 
#include "md5.h"
20
 
#include "crypto.h"
21
 
 
22
 
 
23
 
static struct radius_attr_hdr *
24
 
radius_get_attr_hdr(struct radius_msg *msg, int idx)
25
 
{
26
 
        return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);
27
 
}
28
 
 
29
 
 
30
 
struct radius_msg *radius_msg_new(u8 code, u8 identifier)
31
 
{
32
 
        struct radius_msg *msg;
33
 
 
34
 
        msg = os_malloc(sizeof(*msg));
35
 
        if (msg == NULL)
36
 
                return NULL;
37
 
 
38
 
        if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
39
 
                os_free(msg);
40
 
                return NULL;
41
 
        }
42
 
 
43
 
        radius_msg_set_hdr(msg, code, identifier);
44
 
 
45
 
        return msg;
46
 
}
47
 
 
48
 
 
49
 
int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
50
 
{
51
 
        if (msg == NULL || init_len < sizeof(struct radius_hdr))
52
 
                return -1;
53
 
 
54
 
        os_memset(msg, 0, sizeof(*msg));
55
 
        msg->buf = os_zalloc(init_len);
56
 
        if (msg->buf == NULL)
57
 
                return -1;
58
 
 
59
 
        msg->buf_size = init_len;
60
 
        msg->hdr = (struct radius_hdr *) msg->buf;
61
 
        msg->buf_used = sizeof(*msg->hdr);
62
 
 
63
 
        msg->attr_pos =
64
 
                os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
65
 
        if (msg->attr_pos == NULL) {
66
 
                os_free(msg->buf);
67
 
                msg->buf = NULL;
68
 
                msg->hdr = NULL;
69
 
                return -1;
70
 
        }
71
 
 
72
 
        msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
73
 
        msg->attr_used = 0;
74
 
 
75
 
        return 0;
76
 
}
77
 
 
78
 
 
79
 
void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
80
 
{
81
 
        msg->hdr->code = code;
82
 
        msg->hdr->identifier = identifier;
83
 
}
84
 
 
85
 
 
86
 
void radius_msg_free(struct radius_msg *msg)
87
 
{
88
 
        os_free(msg->buf);
89
 
        msg->buf = NULL;
90
 
        msg->hdr = NULL;
91
 
        msg->buf_size = msg->buf_used = 0;
92
 
 
93
 
        os_free(msg->attr_pos);
94
 
        msg->attr_pos = NULL;
95
 
        msg->attr_size = msg->attr_used = 0;
96
 
}
97
 
 
98
 
 
99
 
static const char *radius_code_string(u8 code)
100
 
{
101
 
        switch (code) {
102
 
        case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
103
 
        case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
104
 
        case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
105
 
        case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
106
 
        case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
107
 
        case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
108
 
        case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
109
 
        case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
110
 
        case RADIUS_CODE_RESERVED: return "Reserved";
111
 
        default: return "?Unknown?";
112
 
        }
113
 
}
114
 
 
115
 
 
116
 
struct radius_attr_type {
117
 
        u8 type;
118
 
        char *name;
119
 
        enum {
120
 
                RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
121
 
                RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
122
 
        } data_type;
123
 
};
124
 
 
125
 
static struct radius_attr_type radius_attrs[] =
126
 
{
127
 
        { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
128
 
        { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
129
 
        { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
130
 
        { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
131
 
        { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
132
 
        { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
133
 
        { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
134
 
        { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
135
 
        { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
136
 
        { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
137
 
        { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
138
 
        { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
139
 
          RADIUS_ATTR_INT32 },
140
 
        { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
141
 
          RADIUS_ATTR_TEXT },
142
 
        { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
143
 
          RADIUS_ATTR_TEXT },
144
 
        { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
145
 
        { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
146
 
          RADIUS_ATTR_INT32 },
147
 
        { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
148
 
        { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
149
 
          RADIUS_ATTR_INT32 },
150
 
        { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
151
 
          RADIUS_ATTR_INT32 },
152
 
        { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
153
 
        { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
154
 
        { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
155
 
          RADIUS_ATTR_INT32 },
156
 
        { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
157
 
          RADIUS_ATTR_INT32 },
158
 
        { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
159
 
          RADIUS_ATTR_INT32 },
160
 
        { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
161
 
          RADIUS_ATTR_INT32 },
162
 
        { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
163
 
          RADIUS_ATTR_TEXT },
164
 
        { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
165
 
        { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 
166
 
          RADIUS_ATTR_INT32 },
167
 
        { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
168
 
          RADIUS_ATTR_INT32 },
169
 
        { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
170
 
          RADIUS_ATTR_INT32 },
171
 
        { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
172
 
        { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
173
 
        { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
174
 
          RADIUS_ATTR_HEXDUMP },
175
 
        { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
176
 
        { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
177
 
        { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
178
 
          RADIUS_ATTR_UNDIST },
179
 
        { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
180
 
          RADIUS_ATTR_HEXDUMP },
181
 
        { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
182
 
          RADIUS_ATTR_INT32 },
183
 
        { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
184
 
};
185
 
#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
186
 
 
187
 
 
188
 
static struct radius_attr_type *radius_get_attr_type(u8 type)
189
 
{
190
 
        size_t i;
191
 
 
192
 
        for (i = 0; i < RADIUS_ATTRS; i++) {
193
 
                if (type == radius_attrs[i].type)
194
 
                        return &radius_attrs[i];
195
 
        }
196
 
 
197
 
        return NULL;
198
 
}
199
 
 
200
 
 
201
 
static void print_char(char c)
202
 
{
203
 
        if (c >= 32 && c < 127)
204
 
                printf("%c", c);
205
 
        else
206
 
                printf("<%02x>", c);
207
 
}
208
 
 
209
 
 
210
 
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
211
 
{
212
 
        struct radius_attr_type *attr;
213
 
        int i, len;
214
 
        unsigned char *pos;
215
 
 
216
 
        attr = radius_get_attr_type(hdr->type);
217
 
 
218
 
        printf("   Attribute %d (%s) length=%d\n",
219
 
               hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
220
 
 
221
 
        if (attr == NULL)
222
 
                return;
223
 
 
224
 
        len = hdr->length - sizeof(struct radius_attr_hdr);
225
 
        pos = (unsigned char *) (hdr + 1);
226
 
 
227
 
        switch (attr->data_type) {
228
 
        case RADIUS_ATTR_TEXT:
229
 
                printf("      Value: '");
230
 
                for (i = 0; i < len; i++)
231
 
                        print_char(pos[i]);
232
 
                printf("'\n");
233
 
                break;
234
 
 
235
 
        case RADIUS_ATTR_IP:
236
 
                if (len == 4) {
237
 
                        struct in_addr *addr = (struct in_addr *) pos;
238
 
                        printf("      Value: %s\n", inet_ntoa(*addr));
239
 
                } else
240
 
                        printf("      Invalid IP address length %d\n", len);
241
 
                break;
242
 
 
243
 
#ifdef CONFIG_IPV6
244
 
        case RADIUS_ATTR_IPV6:
245
 
                if (len == 16) {
246
 
                        char buf[128];
247
 
                        const char *atxt;
248
 
                        struct in6_addr *addr = (struct in6_addr *) pos;
249
 
                        atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
250
 
                        printf("      Value: %s\n", atxt ? atxt : "?");
251
 
                } else
252
 
                        printf("      Invalid IPv6 address length %d\n", len);
253
 
                break;
254
 
#endif /* CONFIG_IPV6 */
255
 
 
256
 
        case RADIUS_ATTR_HEXDUMP:
257
 
        case RADIUS_ATTR_UNDIST:
258
 
                printf("      Value:");
259
 
                for (i = 0; i < len; i++)
260
 
                        printf(" %02x", pos[i]);
261
 
                printf("\n");
262
 
                break;
263
 
 
264
 
        case RADIUS_ATTR_INT32:
265
 
                if (len == 4)
266
 
                        printf("      Value: %u\n", WPA_GET_BE32(pos));
267
 
                else
268
 
                        printf("      Invalid INT32 length %d\n", len);
269
 
                break;
270
 
 
271
 
        default:
272
 
                break;
273
 
        }
274
 
}
275
 
 
276
 
 
277
 
void radius_msg_dump(struct radius_msg *msg)
278
 
{
279
 
        size_t i;
280
 
 
281
 
        printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
282
 
               msg->hdr->code, radius_code_string(msg->hdr->code),
283
 
               msg->hdr->identifier, ntohs(msg->hdr->length));
284
 
 
285
 
        for (i = 0; i < msg->attr_used; i++) {
286
 
                struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
287
 
                radius_msg_dump_attr(attr);
288
 
        }
289
 
}
290
 
 
291
 
 
292
 
int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len)
293
 
{
294
 
        if (secret) {
295
 
                u8 auth[MD5_MAC_LEN];
296
 
                struct radius_attr_hdr *attr;
297
 
 
298
 
                os_memset(auth, 0, MD5_MAC_LEN);
299
 
                attr = radius_msg_add_attr(msg,
300
 
                                           RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
301
 
                                           auth, MD5_MAC_LEN);
302
 
                if (attr == NULL) {
303
 
                        printf("WARNING: Could not add "
304
 
                               "Message-Authenticator\n");
305
 
                        return -1;
306
 
                }
307
 
                msg->hdr->length = htons(msg->buf_used);
308
 
                hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
309
 
                         (u8 *) (attr + 1));
310
 
        } else
311
 
                msg->hdr->length = htons(msg->buf_used);
312
 
 
313
 
        if (msg->buf_used > 0xffff) {
314
 
                printf("WARNING: too long RADIUS message (%lu)\n",
315
 
                       (unsigned long) msg->buf_used);
316
 
                return -1;
317
 
        }
318
 
        return 0;
319
 
}
320
 
 
321
 
 
322
 
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
323
 
                          size_t secret_len, const u8 *req_authenticator)
324
 
{
325
 
        u8 auth[MD5_MAC_LEN];
326
 
        struct radius_attr_hdr *attr;
327
 
        const u8 *addr[4];
328
 
        size_t len[4];
329
 
 
330
 
        os_memset(auth, 0, MD5_MAC_LEN);
331
 
        attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
332
 
                                   auth, MD5_MAC_LEN);
333
 
        if (attr == NULL) {
334
 
                printf("WARNING: Could not add Message-Authenticator\n");
335
 
                return -1;
336
 
        }
337
 
        msg->hdr->length = htons(msg->buf_used);
338
 
        os_memcpy(msg->hdr->authenticator, req_authenticator,
339
 
                  sizeof(msg->hdr->authenticator));
340
 
        hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
341
 
                 (u8 *) (attr + 1));
342
 
 
343
 
        /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
344
 
        addr[0] = (u8 *) msg->hdr;
345
 
        len[0] = 1 + 1 + 2;
346
 
        addr[1] = req_authenticator;
347
 
        len[1] = MD5_MAC_LEN;
348
 
        addr[2] = (u8 *) (msg->hdr + 1);
349
 
        len[2] = msg->buf_used - sizeof(*msg->hdr);
350
 
        addr[3] = secret;
351
 
        len[3] = secret_len;
352
 
        md5_vector(4, addr, len, msg->hdr->authenticator);
353
 
 
354
 
        if (msg->buf_used > 0xffff) {
355
 
                printf("WARNING: too long RADIUS message (%lu)\n",
356
 
                       (unsigned long) msg->buf_used);
357
 
                return -1;
358
 
        }
359
 
        return 0;
360
 
}
361
 
 
362
 
 
363
 
void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
364
 
                            size_t secret_len)
365
 
{
366
 
        const u8 *addr[2];
367
 
        size_t len[2];
368
 
 
369
 
        msg->hdr->length = htons(msg->buf_used);
370
 
        os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
371
 
        addr[0] = msg->buf;
372
 
        len[0] = msg->buf_used;
373
 
        addr[1] = secret;
374
 
        len[1] = secret_len;
375
 
        md5_vector(2, addr, len, msg->hdr->authenticator);
376
 
 
377
 
        if (msg->buf_used > 0xffff) {
378
 
                printf("WARNING: too long RADIUS messages (%lu)\n",
379
 
                       (unsigned long) msg->buf_used);
380
 
        }
381
 
}
382
 
 
383
 
 
384
 
static int radius_msg_add_attr_to_array(struct radius_msg *msg,
385
 
                                        struct radius_attr_hdr *attr)
386
 
{
387
 
        if (msg->attr_used >= msg->attr_size) {
388
 
                size_t *nattr_pos;
389
 
                int nlen = msg->attr_size * 2;
390
 
 
391
 
                nattr_pos = os_realloc(msg->attr_pos,
392
 
                                       nlen * sizeof(*msg->attr_pos));
393
 
                if (nattr_pos == NULL)
394
 
                        return -1;
395
 
 
396
 
                msg->attr_pos = nattr_pos;
397
 
                msg->attr_size = nlen;
398
 
        }
399
 
 
400
 
        msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf;
401
 
 
402
 
        return 0;
403
 
}
404
 
 
405
 
 
406
 
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
407
 
                                            const u8 *data, size_t data_len)
408
 
{
409
 
        size_t buf_needed;
410
 
        struct radius_attr_hdr *attr;
411
 
 
412
 
        if (data_len > RADIUS_MAX_ATTR_LEN) {
413
 
                printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
414
 
                       (unsigned long) data_len);
415
 
                return NULL;
416
 
        }
417
 
 
418
 
        buf_needed = msg->buf_used + sizeof(*attr) + data_len;
419
 
 
420
 
        if (msg->buf_size < buf_needed) {
421
 
                /* allocate more space for message buffer */
422
 
                unsigned char *nbuf;
423
 
                size_t nlen = msg->buf_size;
424
 
 
425
 
                while (nlen < buf_needed)
426
 
                        nlen *= 2;
427
 
                nbuf = os_realloc(msg->buf, nlen);
428
 
                if (nbuf == NULL)
429
 
                        return NULL;
430
 
                msg->buf = nbuf;
431
 
                msg->hdr = (struct radius_hdr *) msg->buf;
432
 
                os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
433
 
                msg->buf_size = nlen;
434
 
        }
435
 
 
436
 
        attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
437
 
        attr->type = type;
438
 
        attr->length = sizeof(*attr) + data_len;
439
 
        if (data_len > 0)
440
 
                os_memcpy(attr + 1, data, data_len);
441
 
 
442
 
        msg->buf_used += sizeof(*attr) + data_len;
443
 
 
444
 
        if (radius_msg_add_attr_to_array(msg, attr))
445
 
                return NULL;
446
 
 
447
 
        return attr;
448
 
}
449
 
 
450
 
 
451
 
struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
452
 
{
453
 
        struct radius_msg *msg;
454
 
        struct radius_hdr *hdr;
455
 
        struct radius_attr_hdr *attr;
456
 
        size_t msg_len;
457
 
        unsigned char *pos, *end;
458
 
 
459
 
        if (data == NULL || len < sizeof(*hdr))
460
 
                return NULL;
461
 
 
462
 
        hdr = (struct radius_hdr *) data;
463
 
 
464
 
        msg_len = ntohs(hdr->length);
465
 
        if (msg_len < sizeof(*hdr) || msg_len > len) {
466
 
                printf("Invalid RADIUS message length\n");
467
 
                return NULL;
468
 
        }
469
 
 
470
 
        if (msg_len < len) {
471
 
                printf("Ignored %lu extra bytes after RADIUS message\n",
472
 
                       (unsigned long) len - msg_len);
473
 
        }
474
 
 
475
 
        msg = os_malloc(sizeof(*msg));
476
 
        if (msg == NULL)
477
 
                return NULL;
478
 
 
479
 
        if (radius_msg_initialize(msg, msg_len)) {
480
 
                os_free(msg);
481
 
                return NULL;
482
 
        }
483
 
 
484
 
        os_memcpy(msg->buf, data, msg_len);
485
 
        msg->buf_size = msg->buf_used = msg_len;
486
 
 
487
 
        /* parse attributes */
488
 
        pos = (unsigned char *) (msg->hdr + 1);
489
 
        end = msg->buf + msg->buf_used;
490
 
        while (pos < end) {
491
 
                if ((size_t) (end - pos) < sizeof(*attr))
492
 
                        goto fail;
493
 
 
494
 
                attr = (struct radius_attr_hdr *) pos;
495
 
 
496
 
                if (pos + attr->length > end || attr->length < sizeof(*attr))
497
 
                        goto fail;
498
 
 
499
 
                /* TODO: check that attr->length is suitable for attr->type */
500
 
 
501
 
                if (radius_msg_add_attr_to_array(msg, attr))
502
 
                        goto fail;
503
 
 
504
 
                pos += attr->length;
505
 
        }
506
 
 
507
 
        return msg;
508
 
 
509
 
 fail:
510
 
        radius_msg_free(msg);
511
 
        os_free(msg);
512
 
        return NULL;
513
 
}
514
 
 
515
 
 
516
 
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
517
 
{
518
 
        const u8 *pos = data;
519
 
        size_t left = data_len;
520
 
 
521
 
        while (left > 0) {
522
 
                int len;
523
 
                if (left > RADIUS_MAX_ATTR_LEN)
524
 
                        len = RADIUS_MAX_ATTR_LEN;
525
 
                else
526
 
                        len = left;
527
 
 
528
 
                if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
529
 
                                         pos, len))
530
 
                        return 0;
531
 
 
532
 
                pos += len;
533
 
                left -= len;
534
 
        }
535
 
 
536
 
        return 1;
537
 
}
538
 
 
539
 
 
540
 
u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
541
 
{
542
 
        u8 *eap, *pos;
543
 
        size_t len, i;
544
 
        struct radius_attr_hdr *attr;
545
 
 
546
 
        if (msg == NULL)
547
 
                return NULL;
548
 
 
549
 
        len = 0;
550
 
        for (i = 0; i < msg->attr_used; i++) {
551
 
                attr = radius_get_attr_hdr(msg, i);
552
 
                if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
553
 
                        len += attr->length - sizeof(struct radius_attr_hdr);
554
 
        }
555
 
 
556
 
        if (len == 0)
557
 
                return NULL;
558
 
 
559
 
        eap = os_malloc(len);
560
 
        if (eap == NULL)
561
 
                return NULL;
562
 
 
563
 
        pos = eap;
564
 
        for (i = 0; i < msg->attr_used; i++) {
565
 
                attr = radius_get_attr_hdr(msg, i);
566
 
                if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
567
 
                        int flen = attr->length - sizeof(*attr);
568
 
                        os_memcpy(pos, attr + 1, flen);
569
 
                        pos += flen;
570
 
                }
571
 
        }
572
 
 
573
 
        if (eap_len)
574
 
                *eap_len = len;
575
 
 
576
 
        return eap;
577
 
}
578
 
 
579
 
 
580
 
int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
581
 
                               size_t secret_len, const u8 *req_auth)
582
 
{
583
 
        u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
584
 
        u8 orig_authenticator[16];
585
 
        struct radius_attr_hdr *attr = NULL, *tmp;
586
 
        size_t i;
587
 
 
588
 
        for (i = 0; i < msg->attr_used; i++) {
589
 
                tmp = radius_get_attr_hdr(msg, i);
590
 
                if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
591
 
                        if (attr != NULL) {
592
 
                                printf("Multiple Message-Authenticator "
593
 
                                       "attributes in RADIUS message\n");
594
 
                                return 1;
595
 
                        }
596
 
                        attr = tmp;
597
 
                }
598
 
        }
599
 
 
600
 
        if (attr == NULL) {
601
 
                printf("No Message-Authenticator attribute found\n");
602
 
                return 1;
603
 
        }
604
 
 
605
 
        os_memcpy(orig, attr + 1, MD5_MAC_LEN);
606
 
        os_memset(attr + 1, 0, MD5_MAC_LEN);
607
 
        if (req_auth) {
608
 
                os_memcpy(orig_authenticator, msg->hdr->authenticator,
609
 
                          sizeof(orig_authenticator));
610
 
                os_memcpy(msg->hdr->authenticator, req_auth,
611
 
                          sizeof(msg->hdr->authenticator));
612
 
        }
613
 
        hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
614
 
        os_memcpy(attr + 1, orig, MD5_MAC_LEN);
615
 
        if (req_auth) {
616
 
                os_memcpy(msg->hdr->authenticator, orig_authenticator,
617
 
                          sizeof(orig_authenticator));
618
 
        }
619
 
 
620
 
        if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
621
 
                printf("Invalid Message-Authenticator!\n");
622
 
                return 1;
623
 
        }
624
 
 
625
 
        return 0;
626
 
}
627
 
 
628
 
 
629
 
int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
630
 
                      size_t secret_len, struct radius_msg *sent_msg, int auth)
631
 
{
632
 
        const u8 *addr[4];
633
 
        size_t len[4];
634
 
        u8 hash[MD5_MAC_LEN];
635
 
 
636
 
        if (sent_msg == NULL) {
637
 
                printf("No matching Access-Request message found\n");
638
 
                return 1;
639
 
        }
640
 
 
641
 
        if (auth &&
642
 
            radius_msg_verify_msg_auth(msg, secret, secret_len,
643
 
                                       sent_msg->hdr->authenticator)) {
644
 
                return 1;
645
 
        }
646
 
 
647
 
        /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
648
 
        addr[0] = (u8 *) msg->hdr;
649
 
        len[0] = 1 + 1 + 2;
650
 
        addr[1] = sent_msg->hdr->authenticator;
651
 
        len[1] = MD5_MAC_LEN;
652
 
        addr[2] = (u8 *) (msg->hdr + 1);
653
 
        len[2] = msg->buf_used - sizeof(*msg->hdr);
654
 
        addr[3] = secret;
655
 
        len[3] = secret_len;
656
 
        md5_vector(4, addr, len, hash);
657
 
        if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
658
 
                printf("Response Authenticator invalid!\n");
659
 
                return 1;
660
 
        }
661
 
 
662
 
        return 0;
663
 
}
664
 
 
665
 
 
666
 
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
667
 
                         u8 type)
668
 
{
669
 
        struct radius_attr_hdr *attr = NULL, *tmp;
670
 
        size_t i;
671
 
 
672
 
        for (i = 0; i < src->attr_used; i++) {
673
 
                tmp = radius_get_attr_hdr(src, i);
674
 
                if (tmp->type == type) {
675
 
                        attr = tmp;
676
 
                        break;
677
 
                }
678
 
        }
679
 
 
680
 
        if (attr == NULL)
681
 
                return 0;
682
 
 
683
 
        if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
684
 
                                 attr->length - sizeof(*attr)))
685
 
                return -1;
686
 
 
687
 
        return 1;
688
 
}
689
 
 
690
 
 
691
 
/* Create Request Authenticator. The value should be unique over the lifetime
692
 
 * of the shared secret between authenticator and authentication server.
693
 
 * Use one-way MD5 hash calculated from current timestamp and some data given
694
 
 * by the caller. */
695
 
void radius_msg_make_authenticator(struct radius_msg *msg,
696
 
                                   const u8 *data, size_t len)
697
 
{
698
 
        struct os_time tv;
699
 
        long int l;
700
 
        const u8 *addr[3];
701
 
        size_t elen[3];
702
 
 
703
 
        os_get_time(&tv);
704
 
        l = os_random();
705
 
        addr[0] = (u8 *) &tv;
706
 
        elen[0] = sizeof(tv);
707
 
        addr[1] = data;
708
 
        elen[1] = len;
709
 
        addr[2] = (u8 *) &l;
710
 
        elen[2] = sizeof(l);
711
 
        md5_vector(3, addr, elen, msg->hdr->authenticator);
712
 
}
713
 
 
714
 
 
715
 
/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
716
 
 * Returns the Attribute payload and sets alen to indicate the length of the
717
 
 * payload if a vendor attribute with subtype is found, otherwise returns NULL.
718
 
 * The returned payload is allocated with os_malloc() and caller must free it
719
 
 * by calling os_free().
720
 
 */
721
 
static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
722
 
                                      u8 subtype, size_t *alen)
723
 
{
724
 
        u8 *data, *pos;
725
 
        size_t i, len;
726
 
 
727
 
        if (msg == NULL)
728
 
                return NULL;
729
 
 
730
 
        for (i = 0; i < msg->attr_used; i++) {
731
 
                struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
732
 
                size_t left;
733
 
                u32 vendor_id;
734
 
                struct radius_attr_vendor *vhdr;
735
 
 
736
 
                if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
737
 
                        continue;
738
 
 
739
 
                left = attr->length - sizeof(*attr);
740
 
                if (left < 4)
741
 
                        continue;
742
 
 
743
 
                pos = (u8 *) (attr + 1);
744
 
 
745
 
                os_memcpy(&vendor_id, pos, 4);
746
 
                pos += 4;
747
 
                left -= 4;
748
 
 
749
 
                if (ntohl(vendor_id) != vendor)
750
 
                        continue;
751
 
 
752
 
                while (left >= sizeof(*vhdr)) {
753
 
                        vhdr = (struct radius_attr_vendor *) pos;
754
 
                        if (vhdr->vendor_length > left ||
755
 
                            vhdr->vendor_length < sizeof(*vhdr)) {
756
 
                                left = 0;
757
 
                                break;
758
 
                        }
759
 
                        if (vhdr->vendor_type != subtype) {
760
 
                                pos += vhdr->vendor_length;
761
 
                                left -= vhdr->vendor_length;
762
 
                                continue;
763
 
                        }
764
 
 
765
 
                        len = vhdr->vendor_length - sizeof(*vhdr);
766
 
                        data = os_malloc(len);
767
 
                        if (data == NULL)
768
 
                                return NULL;
769
 
                        os_memcpy(data, pos + sizeof(*vhdr), len);
770
 
                        if (alen)
771
 
                                *alen = len;
772
 
                        return data;
773
 
                }
774
 
        }
775
 
 
776
 
        return NULL;
777
 
}
778
 
 
779
 
 
780
 
static u8 * decrypt_ms_key(const u8 *key, size_t len,
781
 
                           const u8 *req_authenticator,
782
 
                           const u8 *secret, size_t secret_len, size_t *reslen)
783
 
{
784
 
        u8 *plain, *ppos, *res;
785
 
        const u8 *pos;
786
 
        size_t left, plen;
787
 
        u8 hash[MD5_MAC_LEN];
788
 
        int i, first = 1;
789
 
        const u8 *addr[3];
790
 
        size_t elen[3];
791
 
 
792
 
        /* key: 16-bit salt followed by encrypted key info */
793
 
 
794
 
        if (len < 2 + 16)
795
 
                return NULL;
796
 
 
797
 
        pos = key + 2;
798
 
        left = len - 2;
799
 
        if (left % 16) {
800
 
                printf("Invalid ms key len %lu\n", (unsigned long) left);
801
 
                return NULL;
802
 
        }
803
 
 
804
 
        plen = left;
805
 
        ppos = plain = os_malloc(plen);
806
 
        if (plain == NULL)
807
 
                return NULL;
808
 
 
809
 
        while (left > 0) {
810
 
                /* b(1) = MD5(Secret + Request-Authenticator + Salt)
811
 
                 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
812
 
 
813
 
                addr[0] = secret;
814
 
                elen[0] = secret_len;
815
 
                if (first) {
816
 
                        addr[1] = req_authenticator;
817
 
                        elen[1] = MD5_MAC_LEN;
818
 
                        addr[2] = key;
819
 
                        elen[2] = 2; /* Salt */
820
 
                } else {
821
 
                        addr[1] = pos - MD5_MAC_LEN;
822
 
                        elen[1] = MD5_MAC_LEN;
823
 
                }
824
 
                md5_vector(first ? 3 : 2, addr, elen, hash);
825
 
                first = 0;
826
 
 
827
 
                for (i = 0; i < MD5_MAC_LEN; i++)
828
 
                        *ppos++ = *pos++ ^ hash[i];
829
 
                left -= MD5_MAC_LEN;
830
 
        }
831
 
 
832
 
        if (plain[0] > plen - 1) {
833
 
                printf("Failed to decrypt MPPE key\n");
834
 
                os_free(plain);
835
 
                return NULL;
836
 
        }
837
 
 
838
 
        res = os_malloc(plain[0]);
839
 
        if (res == NULL) {
840
 
                os_free(plain);
841
 
                return NULL;
842
 
        }
843
 
        os_memcpy(res, plain + 1, plain[0]);
844
 
        if (reslen)
845
 
                *reslen = plain[0];
846
 
        os_free(plain);
847
 
        return res;
848
 
}
849
 
 
850
 
 
851
 
static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
852
 
                           const u8 *req_authenticator,
853
 
                           const u8 *secret, size_t secret_len,
854
 
                           u8 *ebuf, size_t *elen)
855
 
{
856
 
        int i, len, first = 1;
857
 
        u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
858
 
        const u8 *addr[3];
859
 
        size_t _len[3];
860
 
 
861
 
        WPA_PUT_BE16(saltbuf, salt);
862
 
 
863
 
        len = 1 + key_len;
864
 
        if (len & 0x0f) {
865
 
                len = (len & 0xf0) + 16;
866
 
        }
867
 
        os_memset(ebuf, 0, len);
868
 
        ebuf[0] = key_len;
869
 
        os_memcpy(ebuf + 1, key, key_len);
870
 
 
871
 
        *elen = len;
872
 
 
873
 
        pos = ebuf;
874
 
        while (len > 0) {
875
 
                /* b(1) = MD5(Secret + Request-Authenticator + Salt)
876
 
                 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
877
 
                addr[0] = secret;
878
 
                _len[0] = secret_len;
879
 
                if (first) {
880
 
                        addr[1] = req_authenticator;
881
 
                        _len[1] = MD5_MAC_LEN;
882
 
                        addr[2] = saltbuf;
883
 
                        _len[2] = sizeof(saltbuf);
884
 
                } else {
885
 
                        addr[1] = pos - MD5_MAC_LEN;
886
 
                        _len[1] = MD5_MAC_LEN;
887
 
                }
888
 
                md5_vector(first ? 3 : 2, addr, _len, hash);
889
 
                first = 0;
890
 
 
891
 
                for (i = 0; i < MD5_MAC_LEN; i++)
892
 
                        *pos++ ^= hash[i];
893
 
 
894
 
                len -= MD5_MAC_LEN;
895
 
        }
896
 
}
897
 
 
898
 
 
899
 
struct radius_ms_mppe_keys *
900
 
radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
901
 
                       u8 *secret, size_t secret_len)
902
 
{
903
 
        u8 *key;
904
 
        size_t keylen;
905
 
        struct radius_ms_mppe_keys *keys;
906
 
 
907
 
        if (msg == NULL || sent_msg == NULL)
908
 
                return NULL;
909
 
 
910
 
        keys = os_zalloc(sizeof(*keys));
911
 
        if (keys == NULL)
912
 
                return NULL;
913
 
 
914
 
        key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
915
 
                                         RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
916
 
                                         &keylen);
917
 
        if (key) {
918
 
                keys->send = decrypt_ms_key(key, keylen,
919
 
                                            sent_msg->hdr->authenticator,
920
 
                                            secret, secret_len,
921
 
                                            &keys->send_len);
922
 
                os_free(key);
923
 
        }
924
 
 
925
 
        key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
926
 
                                         RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
927
 
                                         &keylen);
928
 
        if (key) {
929
 
                keys->recv = decrypt_ms_key(key, keylen,
930
 
                                            sent_msg->hdr->authenticator,
931
 
                                            secret, secret_len,
932
 
                                            &keys->recv_len);
933
 
                os_free(key);
934
 
        }
935
 
 
936
 
        return keys;
937
 
}
938
 
 
939
 
 
940
 
struct radius_ms_mppe_keys *
941
 
radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
942
 
                          u8 *secret, size_t secret_len)
943
 
{
944
 
        u8 *key;
945
 
        size_t keylen;
946
 
        struct radius_ms_mppe_keys *keys;
947
 
 
948
 
        if (msg == NULL || sent_msg == NULL)
949
 
                return NULL;
950
 
 
951
 
        keys = os_zalloc(sizeof(*keys));
952
 
        if (keys == NULL)
953
 
                return NULL;
954
 
 
955
 
        key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
956
 
                                         RADIUS_CISCO_AV_PAIR, &keylen);
957
 
        if (key && keylen == 51 &&
958
 
            os_memcmp(key, "leap:session-key=", 17) == 0) {
959
 
                keys->recv = decrypt_ms_key(key + 17, keylen - 17,
960
 
                                            sent_msg->hdr->authenticator,
961
 
                                            secret, secret_len,
962
 
                                            &keys->recv_len);
963
 
        }
964
 
        os_free(key);
965
 
 
966
 
        return keys;
967
 
}
968
 
 
969
 
 
970
 
int radius_msg_add_mppe_keys(struct radius_msg *msg,
971
 
                             const u8 *req_authenticator,
972
 
                             const u8 *secret, size_t secret_len,
973
 
                             const u8 *send_key, size_t send_key_len,
974
 
                             const u8 *recv_key, size_t recv_key_len)
975
 
{
976
 
        struct radius_attr_hdr *attr;
977
 
        u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
978
 
        u8 *buf;
979
 
        struct radius_attr_vendor *vhdr;
980
 
        u8 *pos;
981
 
        size_t elen;
982
 
        int hlen;
983
 
        u16 salt;
984
 
 
985
 
        hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
986
 
 
987
 
        /* MS-MPPE-Send-Key */
988
 
        buf = os_malloc(hlen + send_key_len + 16);
989
 
        if (buf == NULL) {
990
 
                return 0;
991
 
        }
992
 
        pos = buf;
993
 
        os_memcpy(pos, &vendor_id, sizeof(vendor_id));
994
 
        pos += sizeof(vendor_id);
995
 
        vhdr = (struct radius_attr_vendor *) pos;
996
 
        vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
997
 
        pos = (u8 *) (vhdr + 1);
998
 
        salt = os_random() | 0x8000;
999
 
        WPA_PUT_BE16(pos, salt);
1000
 
        pos += 2;
1001
 
        encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
1002
 
                       secret_len, pos, &elen);
1003
 
        vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1004
 
 
1005
 
        attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1006
 
                                   buf, hlen + elen);
1007
 
        os_free(buf);
1008
 
        if (attr == NULL) {
1009
 
                return 0;
1010
 
        }
1011
 
 
1012
 
        /* MS-MPPE-Recv-Key */
1013
 
        buf = os_malloc(hlen + send_key_len + 16);
1014
 
        if (buf == NULL) {
1015
 
                return 0;
1016
 
        }
1017
 
        pos = buf;
1018
 
        os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1019
 
        pos += sizeof(vendor_id);
1020
 
        vhdr = (struct radius_attr_vendor *) pos;
1021
 
        vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
1022
 
        pos = (u8 *) (vhdr + 1);
1023
 
        salt ^= 1;
1024
 
        WPA_PUT_BE16(pos, salt);
1025
 
        pos += 2;
1026
 
        encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
1027
 
                       secret_len, pos, &elen);
1028
 
        vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1029
 
 
1030
 
        attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1031
 
                                   buf, hlen + elen);
1032
 
        os_free(buf);
1033
 
        if (attr == NULL) {
1034
 
                return 0;
1035
 
        }
1036
 
 
1037
 
        return 1;
1038
 
}
1039
 
 
1040
 
 
1041
 
/* Add User-Password attribute to a RADIUS message and encrypt it as specified
1042
 
 * in RFC 2865, Chap. 5.2 */
1043
 
struct radius_attr_hdr *
1044
 
radius_msg_add_attr_user_password(struct radius_msg *msg,
1045
 
                                  u8 *data, size_t data_len,
1046
 
                                  u8 *secret, size_t secret_len)
1047
 
{
1048
 
        u8 buf[128];
1049
 
        int padlen, i;
1050
 
        size_t buf_len, pos;
1051
 
        const u8 *addr[2];
1052
 
        size_t len[2];
1053
 
        u8 hash[16];
1054
 
 
1055
 
        if (data_len > 128)
1056
 
                return NULL;
1057
 
 
1058
 
        os_memcpy(buf, data, data_len);
1059
 
        buf_len = data_len;
1060
 
 
1061
 
        padlen = data_len % 16;
1062
 
        if (padlen) {
1063
 
                padlen = 16 - padlen;
1064
 
                os_memset(buf + data_len, 0, padlen);
1065
 
                buf_len += padlen;
1066
 
        }
1067
 
 
1068
 
        addr[0] = secret;
1069
 
        len[0] = secret_len;
1070
 
        addr[1] = msg->hdr->authenticator;
1071
 
        len[1] = 16;
1072
 
        md5_vector(2, addr, len, hash);
1073
 
 
1074
 
        for (i = 0; i < 16; i++)
1075
 
                buf[i] ^= hash[i];
1076
 
        pos = 16;
1077
 
 
1078
 
        while (pos < buf_len) {
1079
 
                addr[0] = secret;
1080
 
                len[0] = secret_len;
1081
 
                addr[1] = &buf[pos - 16];
1082
 
                len[1] = 16;
1083
 
                md5_vector(2, addr, len, hash);
1084
 
 
1085
 
                for (i = 0; i < 16; i++)
1086
 
                        buf[pos + i] ^= hash[i];
1087
 
 
1088
 
                pos += 16;
1089
 
        }
1090
 
 
1091
 
        return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
1092
 
                                   buf, buf_len);
1093
 
}
1094
 
 
1095
 
 
1096
 
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
1097
 
{
1098
 
        struct radius_attr_hdr *attr = NULL, *tmp;
1099
 
        size_t i, dlen;
1100
 
 
1101
 
        for (i = 0; i < msg->attr_used; i++) {
1102
 
                tmp = radius_get_attr_hdr(msg, i);
1103
 
                if (tmp->type == type) {
1104
 
                        attr = tmp;
1105
 
                        break;
1106
 
                }
1107
 
        }
1108
 
 
1109
 
        if (!attr)
1110
 
                return -1;
1111
 
 
1112
 
        dlen = attr->length - sizeof(*attr);
1113
 
        if (buf)
1114
 
                os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
1115
 
        return dlen;
1116
 
}
1117
 
 
1118
 
 
1119
 
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
1120
 
                            size_t *len, const u8 *start)
1121
 
{
1122
 
        size_t i;
1123
 
        struct radius_attr_hdr *attr = NULL, *tmp;
1124
 
 
1125
 
        for (i = 0; i < msg->attr_used; i++) {
1126
 
                tmp = radius_get_attr_hdr(msg, i);
1127
 
                if (tmp->type == type &&
1128
 
                    (start == NULL || (u8 *) tmp > start)) {
1129
 
                        attr = tmp;
1130
 
                        break;
1131
 
                }
1132
 
        }
1133
 
 
1134
 
        if (!attr)
1135
 
                return -1;
1136
 
 
1137
 
        *buf = (u8 *) (attr + 1);
1138
 
        *len = attr->length - sizeof(*attr);
1139
 
        return 0;
1140
 
}
1141
 
 
1142
 
 
1143
 
int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
1144
 
{
1145
 
        size_t i;
1146
 
        int count;
1147
 
 
1148
 
        for (count = 0, i = 0; i < msg->attr_used; i++) {
1149
 
                struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
1150
 
                if (attr->type == type &&
1151
 
                    attr->length >= sizeof(struct radius_attr_hdr) + min_len)
1152
 
                        count++;
1153
 
        }
1154
 
 
1155
 
        return count;
1156
 
}
1157
 
 
1158
 
 
1159
 
struct radius_tunnel_attrs {
1160
 
        int tag_used;
1161
 
        int type; /* Tunnel-Type */
1162
 
        int medium_type; /* Tunnel-Medium-Type */
1163
 
        int vlanid;
1164
 
};
1165
 
 
1166
 
 
1167
 
/**
1168
 
 * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1169
 
 * @msg: RADIUS message
1170
 
 * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1171
 
 */
1172
 
int radius_msg_get_vlanid(struct radius_msg *msg)
1173
 
{
1174
 
        struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
1175
 
        size_t i;
1176
 
        struct radius_attr_hdr *attr = NULL;
1177
 
        const u8 *data;
1178
 
        char buf[10];
1179
 
        size_t dlen;
1180
 
 
1181
 
        os_memset(&tunnel, 0, sizeof(tunnel));
1182
 
 
1183
 
        for (i = 0; i < msg->attr_used; i++) {
1184
 
                attr = radius_get_attr_hdr(msg, i);
1185
 
                data = (const u8 *) (attr + 1);
1186
 
                dlen = attr->length - sizeof(*attr);
1187
 
                if (attr->length < 3)
1188
 
                        continue;
1189
 
                if (data[0] >= RADIUS_TUNNEL_TAGS)
1190
 
                        tun = &tunnel[0];
1191
 
                else
1192
 
                        tun = &tunnel[data[0]];
1193
 
 
1194
 
                switch (attr->type) {
1195
 
                case RADIUS_ATTR_TUNNEL_TYPE:
1196
 
                        if (attr->length != 6)
1197
 
                                break;
1198
 
                        tun->tag_used++;
1199
 
                        tun->type = WPA_GET_BE24(data + 1);
1200
 
                        break;
1201
 
                case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
1202
 
                        if (attr->length != 6)
1203
 
                                break;
1204
 
                        tun->tag_used++;
1205
 
                        tun->medium_type = WPA_GET_BE24(data + 1);
1206
 
                        break;
1207
 
                case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1208
 
                        if (data[0] < RADIUS_TUNNEL_TAGS) {
1209
 
                                data++;
1210
 
                                dlen--;
1211
 
                        }
1212
 
                        if (dlen >= sizeof(buf))
1213
 
                                break;
1214
 
                        os_memcpy(buf, data, dlen);
1215
 
                        buf[dlen] = '\0';
1216
 
                        tun->tag_used++;
1217
 
                        tun->vlanid = atoi(buf);
1218
 
                        break;
1219
 
                }
1220
 
        }
1221
 
 
1222
 
        for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
1223
 
                tun = &tunnel[i];
1224
 
                if (tun->tag_used &&
1225
 
                    tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
1226
 
                    tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
1227
 
                    tun->vlanid > 0)
1228
 
                        return tun->vlanid;
1229
 
        }
1230
 
 
1231
 
        return -1;
1232
 
}