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