Mercurial > hg > freeDiameter
comparison extensions/app_radgw/radius.c @ 550:4c935aecee6c
Hide and automate the Proxy-State attributes management in RADIUS gateway
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Wed, 15 Sep 2010 14:24:45 +0900 |
parents | 23736ebcbfbb |
children | d2be88628747 |
comparison
equal
deleted
inserted
replaced
549:1b8809c7d7cc | 550:4c935aecee6c |
---|---|
1 /*********************************************************************************/ | 1 /********************************************************************************************************* |
2 * Software License Agreement (BSD License) * | |
3 * Author: Sebastien Decugis <sdecugis@nict.go.jp> * | |
4 * * | |
5 * Copyright (c) 2010, WIDE Project and NICT * | |
6 * All rights reserved. * | |
7 * * | |
8 * Redistribution and use of this software in source and binary forms, with or without modification, are * | |
9 * permitted provided that the following conditions are met: * | |
10 * * | |
11 * * Redistributions of source code must retain the above * | |
12 * copyright notice, this list of conditions and the * | |
13 * following disclaimer. * | |
14 * * | |
15 * * Redistributions in binary form must reproduce the above * | |
16 * copyright notice, this list of conditions and the * | |
17 * following disclaimer in the documentation and/or other * | |
18 * materials provided with the distribution. * | |
19 * * | |
20 * * Neither the name of the WIDE Project or NICT nor the * | |
21 * names of its contributors may be used to endorse or * | |
22 * promote products derived from this software without * | |
23 * specific prior written permission of WIDE Project and * | |
24 * NICT. * | |
25 * * | |
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * | |
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * | |
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * | |
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * | |
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * | |
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * | |
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * | |
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * | |
34 *********************************************************************************************************/ | |
35 | |
2 /* freeDiameter author note: | 36 /* freeDiameter author note: |
3 * The content from this file comes directly from the hostap project. | 37 * The content from this file comes for the main part from the hostap project. |
4 * It is redistributed under the terms of the BSD license, as allowed | 38 * It is redistributed under the terms of the BSD license, as allowed |
5 * by the original copyright reproduced bellow. | 39 * by the original copyright reproduced bellow. |
6 * In addition to this notice, the following changes have been done: | 40 * The modifications to this file are placed under the copyright of the freeDiameter project. |
7 * - created the radius_msg_dump_attr_val function | |
8 */ | 41 */ |
9 #include "rgw_common.h" | |
10 | |
11 /* Overwrite printf */ | |
12 #define printf(args...) fd_log_debug(args) | |
13 | |
14 /*********************************************************************************/ | |
15 | |
16 | 42 |
17 /* | 43 /* |
18 * hostapd / RADIUS message processing | 44 * hostapd / RADIUS message processing |
19 * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> | 45 * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> |
20 * | 46 * |
26 * license. | 52 * license. |
27 * | 53 * |
28 * See README and COPYING for more details. | 54 * See README and COPYING for more details. |
29 */ | 55 */ |
30 | 56 |
57 /*********************************************************************************/ | |
58 #include "rgw.h" | |
59 | |
60 /* Overwrite printf */ | |
61 #define printf(args...) fd_log_debug(args) | |
62 | |
63 | |
31 static struct radius_attr_hdr * | 64 static struct radius_attr_hdr * |
32 radius_get_attr_hdr(struct radius_msg *msg, int idx) | 65 radius_get_attr_hdr(struct radius_msg *msg, int idx) |
33 { | 66 { |
34 return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]); | 67 return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]); |
35 } | 68 } |
101 os_free(msg->attr_pos); | 134 os_free(msg->attr_pos); |
102 msg->attr_pos = NULL; | 135 msg->attr_pos = NULL; |
103 msg->attr_size = msg->attr_used = 0; | 136 msg->attr_size = msg->attr_used = 0; |
104 } | 137 } |
105 | 138 |
106 | 139 /* Destroy a message */ |
107 static const char *radius_code_string(u8 code) | 140 void rgw_msg_free(struct rgw_radius_msg_meta ** msg) |
108 { | 141 { |
109 switch (code) { | 142 if (!msg || !*msg) |
110 case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; | 143 return; |
111 case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; | 144 |
112 case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; | 145 radius_msg_free(&(*msg)->radius); |
113 case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; | 146 free(*msg); |
114 case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; | 147 *msg = NULL; |
115 case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; | 148 } |
116 case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; | 149 |
117 case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; | |
118 case RADIUS_CODE_RESERVED: return "Reserved"; | |
119 default: return "?Unknown?"; | |
120 } | |
121 } | |
122 | 150 |
123 | 151 |
124 struct radius_attr_type { | 152 struct radius_attr_type { |
125 u8 type; | 153 u8 type; |
126 char *name; | 154 char *name; |
216 else | 244 else |
217 printf("<%02x>", c); | 245 printf("<%02x>", c); |
218 } | 246 } |
219 | 247 |
220 | 248 |
221 void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr) | 249 static void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr) |
222 { | 250 { |
223 struct radius_attr_type *attr; | 251 struct radius_attr_type *attr; |
224 int i, len; | 252 int i, len; |
225 unsigned char *pos; | 253 unsigned char *pos; |
226 u8 attrtype; | 254 u8 attrtype; |
279 printf("\n"); | 307 printf("\n"); |
280 break; | 308 break; |
281 } | 309 } |
282 } | 310 } |
283 | 311 |
284 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) | 312 /* Dump a message -- can be used safely with a struct radius_msg as parameter (we don't dump the metadata) */ |
285 { | 313 void rgw_msg_dump(struct rgw_radius_msg_meta * msg) |
286 struct radius_attr_type *attr; | 314 { |
287 | 315 unsigned char *auth; |
288 attr = radius_get_attr_type(hdr->type); | |
289 | |
290 printf(" Attribute %d (%s) length=%d\n", | |
291 hdr->type, attr ? attr->name : "?Unknown?", hdr->length); | |
292 | |
293 radius_msg_dump_attr_val(hdr); | |
294 } | |
295 | |
296 | |
297 void radius_msg_dump(struct radius_msg *msg) | |
298 { | |
299 size_t i; | 316 size_t i; |
300 | 317 if (! TRACE_BOOL(FULL) ) |
301 printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", | 318 return; |
302 msg->hdr->code, radius_code_string(msg->hdr->code), | 319 |
303 msg->hdr->identifier, ntohs(msg->hdr->length)); | 320 auth = &(msg->radius.hdr->authenticator[0]); |
304 | 321 |
305 for (i = 0; i < msg->attr_used; i++) { | 322 fd_log_debug("------ RADIUS msg dump -------\n"); |
306 struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); | 323 fd_log_debug(" id : 0x%02hhx, code : %hhd (%s), length : %d\n", msg->radius.hdr->identifier, msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code), ntohs(msg->radius.hdr->length)); |
307 radius_msg_dump_attr(attr); | 324 fd_log_debug(" auth: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", |
308 } | 325 auth[0], auth[1], auth[2], auth[3], auth[4], auth[5], auth[6], auth[7]); |
326 fd_log_debug(" %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", | |
327 auth[8], auth[9], auth[10], auth[11], auth[12], auth[13], auth[14], auth[15]); | |
328 for (i = 0; i < msg->radius.attr_used; i++) { | |
329 struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[i]); | |
330 fd_log_debug(" - Type: 0x%02hhx (%s)\n Len: %-3hhu", attr->type, rgw_msg_attrtype_str(attr->type), attr->length); | |
331 radius_msg_dump_attr_val(attr); | |
332 } | |
333 if (msg->ps_nb) { | |
334 fd_log_debug("---- hidden attributes:\n"); | |
335 for (i = msg->ps_first; i < msg->ps_first + msg->ps_nb; i++) { | |
336 struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[i]); | |
337 fd_log_debug(" - Type: 0x%02hhx (%s)\n Len: %-3hhu", attr->type, rgw_msg_attrtype_str(attr->type), attr->length); | |
338 radius_msg_dump_attr_val(attr); | |
339 } | |
340 } | |
341 fd_log_debug("-----------------------------\n"); | |
309 } | 342 } |
310 | 343 |
311 | 344 |
312 int radius_msg_finish(struct radius_msg *msg, const u8 *secret, | 345 int radius_msg_finish(struct radius_msg *msg, const u8 *secret, |
313 size_t secret_len) | 346 size_t secret_len) |
404 (unsigned long) msg->buf_used); | 437 (unsigned long) msg->buf_used); |
405 } | 438 } |
406 } | 439 } |
407 | 440 |
408 | 441 |
409 static int radius_msg_add_attr_to_array(struct radius_msg *msg, | 442 int radius_msg_add_attr_to_array(struct radius_msg *msg, |
410 struct radius_attr_hdr *attr) | 443 struct radius_attr_hdr *attr) |
411 { | 444 { |
412 if (msg->attr_used >= msg->attr_size) { | 445 if (msg->attr_used >= msg->attr_size) { |
413 size_t *nattr_pos; | 446 size_t *nattr_pos; |
414 int nlen = msg->attr_size * 2; | 447 int nlen = msg->attr_size * 2; |
471 | 504 |
472 return attr; | 505 return attr; |
473 } | 506 } |
474 | 507 |
475 | 508 |
476 struct radius_msg *radius_msg_parse(const u8 *data, size_t len) | 509 /* Modified version of radius_msg_parse */ |
477 { | 510 int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg) |
478 struct radius_msg *msg; | 511 { |
512 struct rgw_radius_msg_meta * temp_msg = NULL; | |
479 struct radius_hdr *hdr; | 513 struct radius_hdr *hdr; |
480 struct radius_attr_hdr *attr; | 514 struct radius_attr_hdr *attr; |
481 size_t msg_len; | 515 size_t msg_len; |
482 unsigned char *pos, *end; | 516 unsigned char *pos, *end; |
483 | 517 int ret = 0; |
484 if (data == NULL || len < sizeof(*hdr)) | 518 |
485 return NULL; | 519 TRACE_ENTRY("%p %g %p", buf, len, msg); |
486 | 520 |
487 hdr = (struct radius_hdr *) data; | 521 CHECK_PARAMS( buf && len >= sizeof(*hdr) && msg ); |
488 | 522 |
523 *msg = NULL; | |
524 | |
525 /* Parse the RADIUS message */ | |
526 hdr = (struct radius_hdr *) buf; | |
489 msg_len = ntohs(hdr->length); | 527 msg_len = ntohs(hdr->length); |
490 if (msg_len < sizeof(*hdr) || msg_len > len) { | 528 if (msg_len < sizeof(*hdr) || msg_len > len) { |
491 printf("Invalid RADIUS message length\n"); | 529 TRACE_DEBUG(INFO, "Invalid RADIUS message length\n"); |
492 return NULL; | 530 return EINVAL; |
493 } | 531 } |
494 | 532 |
495 if (msg_len < len) { | 533 if (msg_len < len) { |
496 printf("Ignored %lu extra bytes after RADIUS message\n", | 534 TRACE_DEBUG(INFO, "Ignored %lu extra bytes after RADIUS message\n", |
497 (unsigned long) len - msg_len); | 535 (unsigned long) len - msg_len); |
498 } | 536 } |
499 | 537 |
500 msg = os_malloc(sizeof(*msg)); | 538 CHECK_MALLOC( temp_msg = malloc(sizeof(struct rgw_radius_msg_meta)) ); |
501 if (msg == NULL) | 539 memset(temp_msg, 0, sizeof(struct rgw_radius_msg_meta)); |
502 return NULL; | 540 |
503 | 541 if (radius_msg_initialize(&temp_msg->radius, msg_len)) { |
504 if (radius_msg_initialize(msg, msg_len)) { | 542 TRACE_DEBUG(INFO, "Error in radius_msg_initialize, returning ENOMEM."); |
505 os_free(msg); | 543 free(temp_msg); |
506 return NULL; | 544 return ENOMEM; |
507 } | 545 } |
508 | 546 |
509 os_memcpy(msg->buf, data, msg_len); | 547 /* Store the received data in the alloc'd buffer */ |
510 msg->buf_size = msg->buf_used = msg_len; | 548 memcpy(temp_msg->radius.buf, buf, msg_len); |
511 | 549 temp_msg->radius.buf_size = temp_msg->radius.buf_used = msg_len; |
550 | |
512 /* parse attributes */ | 551 /* parse attributes */ |
513 pos = (unsigned char *) (msg->hdr + 1); | 552 pos = (unsigned char *) (temp_msg->radius.hdr + 1); |
514 end = msg->buf + msg->buf_used; | 553 end = temp_msg->radius.buf + temp_msg->radius.buf_used; |
554 | |
515 while (pos < end) { | 555 while (pos < end) { |
516 if ((size_t) (end - pos) < sizeof(*attr)) | 556 if ((size_t) (end - pos) < sizeof(*attr)) { |
517 goto fail; | 557 TRACE_DEBUG(INFO, "Trucated attribute found in RADIUS buffer, EINVAL."); |
518 | 558 ret = EINVAL; |
559 break; | |
560 } | |
561 | |
519 attr = (struct radius_attr_hdr *) pos; | 562 attr = (struct radius_attr_hdr *) pos; |
520 | 563 |
521 if (pos + attr->length > end || attr->length < sizeof(*attr)) | 564 if (pos + attr->length > end || attr->length < sizeof(*attr)) { |
522 goto fail; | 565 TRACE_DEBUG(INFO, "Trucated attribute found in RADIUS buffer, EINVAL."); |
523 | 566 ret = EINVAL; |
524 /* TODO: check that attr->length is suitable for attr->type */ | 567 break; |
525 | 568 } |
526 if (radius_msg_add_attr_to_array(msg, attr)) | 569 |
527 goto fail; | 570 if (radius_msg_add_attr_to_array(&temp_msg->radius, attr)) { |
571 TRACE_DEBUG(INFO, "Error in radius_msg_add_attr_to_array, ENOMEM"); | |
572 ret = ENOMEM; | |
573 break; | |
574 } | |
575 | |
576 if (attr->type == RADIUS_ATTR_PROXY_STATE) | |
577 temp_msg->ps_nb += 1; | |
528 | 578 |
529 pos += attr->length; | 579 pos += attr->length; |
530 } | 580 } |
531 | 581 |
532 return msg; | 582 if (ret != 0) { |
533 | 583 radius_msg_free(&temp_msg->radius); |
534 fail: | 584 free(temp_msg); |
535 radius_msg_free(msg); | 585 return ret; |
536 os_free(msg); | 586 } |
537 return NULL; | 587 |
538 } | 588 /* Now move all the proxy-state attributes at the end of the attr_pos array */ |
589 if (temp_msg->ps_nb) { | |
590 size_t *temp_ps = NULL; | |
591 int n, new_n = 0, p = 0; | |
592 | |
593 CHECK_MALLOC( temp_ps = calloc(temp_msg->ps_nb, sizeof(size_t *)) ); | |
594 | |
595 /* Move all the Proxy-State attributes into the temp_ps array */ | |
596 for (n=0; n < temp_msg->radius.attr_used; n++) { | |
597 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(temp_msg->radius.buf + temp_msg->radius.attr_pos[n]); | |
598 | |
599 if (attr->type == RADIUS_ATTR_PROXY_STATE) { | |
600 temp_ps[p++] = temp_msg->radius.attr_pos[n]; | |
601 } else { | |
602 temp_msg->radius.attr_pos[new_n++] = temp_msg->radius.attr_pos[n]; | |
603 } | |
604 } | |
605 temp_msg->radius.attr_used = new_n; /* hide the proxy-state to other modules */ | |
606 temp_msg->ps_first = new_n; | |
607 | |
608 /* And back into the array */ | |
609 memcpy(temp_msg->radius.attr_pos + new_n, temp_ps, p * sizeof(size_t *)); | |
610 free(temp_ps); | |
611 } | |
612 | |
613 *msg = temp_msg; | |
614 return 0; | |
615 } | |
616 | |
539 | 617 |
540 | 618 |
541 int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) | 619 int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) |
542 { | 620 { |
543 const u8 *pos = data; | 621 const u8 *pos = data; |