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;
"Welcome to our mercurial repository"