~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to radius.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

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