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