comparison extensions/app_radgw/rgw_clients.c @ 516:1c2f5ee38039

Allow RADIUS Proxies with the app_radgw extension
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 27 Aug 2010 10:59:51 +0900
parents d4fc98a3b79c
children 3f43713be92d
comparison
equal deleted inserted replaced
515:b9167b4de7dc 516:1c2f5ee38039
37 37
38 /* Probably some changes are needed to support RADIUS Proxies */ 38 /* Probably some changes are needed to support RADIUS Proxies */
39 39
40 #include "rgw.h" 40 #include "rgw.h"
41 41
42 #define REVERSE_DNS_SIZE_MAX 512 /* length of our buffer for reverse DNS */
43
42 /* Ordered lists of clients. The order relationship is a memcmp on the address zone. 44 /* Ordered lists of clients. The order relationship is a memcmp on the address zone.
43 For same addresses, the port is compared. 45 For same addresses, the port is compared.
44 The same address cannot be added twice, once with a 0-port and once with another port value. 46 The same address cannot be added twice, once with a 0-port and once with another port value.
45 */ 47 */
46 static struct fd_list cli_ip = FD_LIST_INITIALIZER(cli_ip); 48 static struct fd_list cli_ip = FD_LIST_INITIALIZER(cli_ip);
64 struct sockaddr_in6 *sin6; 66 struct sockaddr_in6 *sin6;
65 }; 67 };
66 68
67 /* The FQDN, realm, and optional aliases */ 69 /* The FQDN, realm, and optional aliases */
68 int is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */ 70 int is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */
71 enum rgw_cli_type type; /* is it a proxy ? */
69 char *fqdn; 72 char *fqdn;
70 size_t fqdn_len; 73 size_t fqdn_len;
71 char *realm; 74 char *realm;
72 char **aliases; 75 char **aliases;
73 size_t aliases_nb; 76 size_t aliases_nb;
88 }; 91 };
89 92
90 93
91 94
92 /* create a new rgw_client. the arguments are moved into the structure (to limit malloc & free calls). */ 95 /* create a new rgw_client. the arguments are moved into the structure (to limit malloc & free calls). */
93 static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen ) 96 static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type )
94 { 97 {
95 struct rgw_client *tmp = NULL; 98 struct rgw_client *tmp = NULL;
96 char buf[255]; 99 char buf[255];
97 int ret; 100 int ret;
98 int loc = 0; 101 int loc = 0;
114 117
115 /* Create the new object */ 118 /* Create the new object */
116 CHECK_MALLOC( tmp = malloc(sizeof (struct rgw_client)) ); 119 CHECK_MALLOC( tmp = malloc(sizeof (struct rgw_client)) );
117 memset(tmp, 0, sizeof(struct rgw_client)); 120 memset(tmp, 0, sizeof(struct rgw_client));
118 fd_list_init(&tmp->chain, NULL); 121 fd_list_init(&tmp->chain, NULL);
122
123 tmp->type = type;
119 124
120 if (loc) { 125 if (loc) {
121 tmp->is_local = 1; 126 tmp->is_local = 1;
122 } else { 127 } else {
123 /* Copy the fqdn */ 128 /* Copy the fqdn */
228 *key = cli->key.data; 233 *key = cli->key.data;
229 *key_len = cli->key.len; 234 *key_len = cli->key.len;
230 return 0; 235 return 0;
231 } 236 }
232 237
238 int rgw_clients_gettype(struct rgw_client * cli, enum rgw_cli_type *type)
239 {
240 CHECK_PARAMS( cli && type );
241 *type = cli->type;
242 return 0;
243 }
244
245
233 int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref) 246 int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref)
234 { 247 {
235 int ret = 0; 248 int ret = 0;
236 249
237 TRACE_ENTRY("%p %p", ip_port, ref); 250 TRACE_ENTRY("%p %p", ip_port, ref);
301 return 0; 314 return 0;
302 } 315 }
303 316
304 /* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */ 317 /* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */
305 /* Also update the client list of aliases if needed */ 318 /* Also update the client list of aliases if needed */
306 /* NOTE: This function will require changes to allow RADIUS Proxy on the path... */ 319 /* NOTE: This function does nothing if the client is a RADIUS Proxy... */
307 int rgw_clients_check_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli) 320 /* Check if the message has a valid authenticator, and update the meta-data accordingly */
321 int rgw_clients_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth)
322 {
323 unsigned char * key;
324 size_t keylen;
325 int count;
326
327 TRACE_ENTRY("%p %p %p", msg, cli, req_auth);
328
329 CHECK_PARAMS(msg && cli);
330
331 CHECK_FCT(rgw_clients_getkey(cli, &key, &keylen));
332
333 count = radius_msg_count_attr(&msg->radius, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0);
334 if (count > 1) {
335 TRACE_DEBUG(INFO, "Too many Message-Authenticator attributes (%d), discarding message.", count);
336 return EINVAL;
337 }
338 if (count == 0) {
339 TRACE_DEBUG(FULL, "Message does not contain a Message-Authenticator attributes.");
340 msg->valid_mac = 0;
341 } else {
342 if (radius_msg_verify_msg_auth( &msg->radius, key, keylen, req_auth )) {
343 TRACE_DEBUG(INFO, "Invalid Message-Authenticator received, discarding message.");
344 return EINVAL;
345 }
346 msg->valid_mac = 1;
347 }
348
349 return 0;
350 }
351
352 static struct dict_object * cache_orig_host = NULL;
353 static struct dict_object * cache_orig_realm = NULL;
354 static struct dict_object * cache_route_record = NULL;
355
356 int rgw_clients_init(void)
357 {
358 TRACE_ENTRY();
359 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &cache_orig_host, ENOENT) );
360 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &cache_orig_realm, ENOENT) );
361 CHECK_FCT( fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &cache_route_record, ENOENT) );
362 return 0;
363 }
364
365
366 /* The following function checks if a RADIUS message contains a valid NAS identifier, and initializes an empty Diameter
367 message with the appropriate routing information */
368 int rgw_clients_create_origin(struct rgw_radius_msg_meta *msg, struct rgw_client * cli, struct msg ** diam)
308 { 369 {
309 int idx; 370 int idx;
371 int valid_nas_info = 0;
310 struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL; 372 struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL;
311 373 char * oh_str = NULL;
312 TRACE_ENTRY("%p %p", msg, cli); 374 char * or_str = NULL;
313 CHECK_PARAMS(msg && cli && !msg->valid_nas_info ); 375 char * rr_str = NULL;
314 376 char buf[REVERSE_DNS_SIZE_MAX]; /* to store DNS lookups results */
377
378 struct avp *avp = NULL;
379 union avp_value avp_val;
380
381 TRACE_ENTRY("%p %p %p", msg, cli, diam);
382 CHECK_PARAMS(msg && cli && diam && (*diam == NULL));
383
315 /* Find the relevant attributes, if any */ 384 /* Find the relevant attributes, if any */
316 for (idx = 0; idx < msg->radius.attr_used; idx++) { 385 for (idx = 0; idx < msg->radius.attr_used; idx++) {
317 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[idx]); 386 struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[idx]);
318 size_t attr_len = attr->length - sizeof(struct radius_attr_hdr); 387 size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
319 388
333 } 402 }
334 } 403 }
335 404
336 if (!nas_ip && !nas_ip6 && !nas_id) { 405 if (!nas_ip && !nas_ip6 && !nas_id) {
337 TRACE_DEBUG(FULL, "The message does not contain any NAS identification attribute."); 406 TRACE_DEBUG(FULL, "The message does not contain any NAS identification attribute.");
338 goto end; 407
408 /* Get information on this peer */
409 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
410
411 goto diameter;
339 } 412 }
340 413
341 /* Check if the message was received from the IP in NAS-IP-Address attribute */ 414 /* Check if the message was received from the IP in NAS-IP-Address attribute */
342 if (nas_ip && (cli->sa->sa_family == AF_INET) && !memcmp(nas_ip+1, &cli->sin->sin_addr, sizeof(struct in_addr))) { 415 if (nas_ip && (cli->sa->sa_family == AF_INET) && !memcmp(nas_ip+1, &cli->sin->sin_addr, sizeof(struct in_addr))) {
343 TRACE_DEBUG(FULL, "NAS-IP-Address contains the same address as the message was received from."); 416 TRACE_DEBUG(FULL, "NAS-IP-Address contains the same address as the message was received from.");
344 msg->valid_nas_info |= 1; 417 valid_nas_info |= 1;
345 } 418 }
346 if (nas_ip6 && (cli->sa->sa_family == AF_INET6) && !memcmp(nas_ip6+1, &cli->sin6->sin6_addr, sizeof(struct in6_addr))) { 419 if (nas_ip6 && (cli->sa->sa_family == AF_INET6) && !memcmp(nas_ip6+1, &cli->sin6->sin6_addr, sizeof(struct in6_addr))) {
347 TRACE_DEBUG(FULL, "NAS-IPv6-Address contains the same address as the message was received from."); 420 TRACE_DEBUG(FULL, "NAS-IPv6-Address contains the same address as the message was received from.");
348 msg->valid_nas_info |= 1; 421 valid_nas_info |= 2;
349 } 422 }
350 423
351 /* If these conditions are not met, the message is probably forged (well, this might be false...) */ 424
352 if ((! msg->valid_nas_info) && (nas_ip || nas_ip6)) { 425 /*
353 /* 426 In RADIUS it would be possible for a rogue NAS to forge the NAS-IP-
354 In RADIUS it would be possible for a rogue NAS to forge the NAS-IP- 427 Address attribute value. Diameter/RADIUS translation agents MUST
355 Address attribute value. Diameter/RADIUS translation agents MUST 428 check a received NAS-IP-Address or NAS-IPv6-Address attribute against
356 check a received NAS-IP-Address or NAS-IPv6-Address attribute against 429 the source address of the RADIUS packet. If they do not match and
357 the source address of the RADIUS packet. If they do not match and 430 the Diameter/RADIUS translation agent does not know whether the
358 the Diameter/RADIUS translation agent does not know whether the 431 packet was sent by a RADIUS proxy or NAS (e.g., no Proxy-State
359 packet was sent by a RADIUS proxy or NAS (e.g., no Proxy-State 432 attribute), then by default it is assumed that the source address
360 attribute), then by default it is assumed that the source address 433 corresponds to a RADIUS proxy, and that the NAS Address is behind
361 corresponds to a RADIUS proxy, and that the NAS Address is behind 434 that proxy, potentially with some additional RADIUS proxies in
362 that proxy, potentially with some additional RADIUS proxies in 435 between. The Diameter/RADIUS translation agent MUST insert entries
363 between. The Diameter/RADIUS translation agent MUST insert entries 436 in the Route-Record AVP corresponding to the apparent route. This
364 in the Route-Record AVP corresponding to the apparent route. This 437 implies doing a reverse lookup on the source address and NAS-IP-
365 implies doing a reverse lookup on the source address and NAS-IP- 438 Address or NAS-IPv6-Address attributes to determine the corresponding
366 Address or NAS-IPv6-Address attributes to determine the corresponding 439 FQDNs.
367 FQDNs. 440
368 441 If the source address and the NAS-IP-Address or NAS-IPv6-Address do
369 If the source address and the NAS-IP-Address or NAS-IPv6-Address do 442 not match, and the Diameter/RADIUS translation agent knows that it is
370 not match, and the Diameter/RADIUS translation agent knows that it is 443 talking directly to the NAS (e.g., there are no RADIUS proxies
371 talking directly to the NAS (e.g., there are no RADIUS proxies 444 between it and the NAS), then the error should be logged, and the
372 between it and the NAS), then the error should be logged, and the 445 packet MUST be discarded.
373 packet MUST be discarded. 446
374 447 Diameter agents and servers MUST check whether the NAS-IP-Address AVP
375 Diameter agents and servers MUST check whether the NAS-IP-Address AVP 448 corresponds to an entry in the Route-Record AVP. This is done by
376 corresponds to an entry in the Route-Record AVP. This is done by 449 doing a reverse lookup (PTR RR) for the NAS-IP-Address to retrieve
377 doing a reverse lookup (PTR RR) for the NAS-IP-Address to retrieve 450 the corresponding FQDN, and by checking for a match with the Route-
378 the corresponding FQDN, and by checking for a match with the Route- 451 Record AVP. If no match is found, then an error is logged, but no
379 Record AVP. If no match is found, then an error is logged, but no 452 other action is taken.
380 other action is taken. 453 */
381 */ 454 if (nas_ip || nas_ip6) {
382 TRACE_DEBUG(INFO, "Message received with a NAS-IP-Address or NAS-IPv6-Address different from the sender's. Discarding..."); 455 if (!valid_nas_info) {
383 return ENOTSUP; 456 if (cli->type == RGW_CLI_NAS) {
384 } 457 TRACE_DEBUG(INFO, "Message received with a NAS-IP-Address or NAS-IPv6-Address different \nfrom the sender's. Please configure as Proxy if this is expected.\n Message discarded.");
385 458 return EINVAL;
386 /* Now check the nas_id, but only for non-local hosts */ 459 } else {
387 if (nas_id && (! cli->is_local) ) { 460 /* the peer is configured as a proxy, so accept the message */
388 char * str; 461 sSS ss;
462
463 /* In that case, the cli will be stored as Route-Record and the NAS-IP-Address as origin */
464 if (!cli->is_local) {
465 rr_str = cli->fqdn;
466 }
467
468 /* We must DNS-reverse the NAS-IP*-Address */
469 memset(&ss, 0 , sizeof(sSS));
470 if (nas_ip) {
471 sSA4 * sin = (sSA4 *)&ss;
472 sin->sin_family = AF_INET;
473 memcpy(&sin->sin_addr, nas_ip + 1, sizeof(struct in_addr));
474 } else {
475 sSA6 * sin6 = (sSA6 *)&ss;
476 sin6->sin6_family = AF_INET6;
477 memcpy(&sin6->sin6_addr, nas_ip6 + 1, sizeof(struct in6_addr));
478 }
479 CHECK_SYS_DO( getnameinfo( (sSA *)&ss, sSAlen(&ss), &buf[0], sizeof(buf), NULL, 0, NI_NAMEREQD),
480 {
481 TRACE_DEBUG(INFO, "The NAS-IP*-Address cannot be DNS reversed in order to create the Origin-Host AVP; rejecting the message (translation is impossible).");
482 return EINVAL;
483 } );
484
485 oh_str = &buf[0];
486 or_str = strchr(oh_str, '.');
487 if (or_str) {
488 or_str ++; /* move after the first dot */
489 if (*or_str == '\0')
490 or_str = NULL; /* Discard this realm, we will use the local realm later */
491 }
492 }
493 } else {
494 /* The attribute matches the source address, just use this in origin-host */
495 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
496 }
497
498 goto diameter; /* we ignore the nas_id in that case */
499 }
500
501 /* We don't have a NAS-IP*-Address attribute if we are here */
502 if (cli->is_local) {
503 /* Simple: we use our own configuration */
504 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
505 goto diameter;
506 }
507
508 /* At this point, we only have nas_id, and the client is not local */
509 ASSERT(nas_id);
510
511 {
389 int found, ret; 512 int found, ret;
390 struct addrinfo hint, *res, *ptr; 513 struct addrinfo hint, *res, *ptr;
391 514
392 /* 515 /*
393 In RADIUS it would be possible for a rogue NAS to forge the NAS- 516 In RADIUS it would be possible for a rogue NAS to forge the NAS-
407 */ 530 */
408 531
409 /* first, check if the nas_id is the fqdn of the peer or a known alias */ 532 /* first, check if the nas_id is the fqdn of the peer or a known alias */
410 if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr))) 533 if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr)))
411 && (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) { 534 && (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) {
412 TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the NAS"); 535 TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the client");
413 found = 1; 536 found = 1;
414 } else { 537 } else {
415 for (idx = 0; idx < cli->aliases_nb; idx++) { 538 for (idx = 0; idx < cli->aliases_nb; idx++) {
416 if (((nas_id->length - sizeof(struct radius_attr_hdr)) == strlen(cli->aliases[idx])) 539 if (((nas_id->length - sizeof(struct radius_attr_hdr)) == strlen(cli->aliases[idx]))
417 && (!strncasecmp((char *)(nas_id + 1), cli->aliases[idx], nas_id->length - sizeof(struct radius_attr_hdr)))) { 540 && (!strncasecmp((char *)(nas_id + 1), cli->aliases[idx], nas_id->length - sizeof(struct radius_attr_hdr)))) {
421 } 544 }
422 } 545 }
423 } 546 }
424 547
425 if (found) { 548 if (found) {
426 msg->valid_nas_info |= 2; 549 /* The NAS-Identifier matches the source IP */
427 goto end; 550 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
428 } 551
429 552 goto diameter;
430 /* copy the identifier, we try to DNS resolve it */ 553 }
431 CHECK_MALLOC( str = malloc(nas_id->length - sizeof(struct radius_attr_hdr) + 1) ); 554
432 memcpy(str, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr)); 555 /* Attempt DNS resolution of the identifier */
433 str[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0'; 556 ASSERT( nas_id->length - sizeof(struct radius_attr_hdr) < sizeof(buf) );
557 memcpy(buf, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
558 buf[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0';
434 559
435 /* Now check if this alias is valid for this peer */ 560 /* Now check if this alias is valid for this peer */
436 memset(&hint, 0, sizeof(hint)); 561 memset(&hint, 0, sizeof(hint));
437 hint.ai_family = cli->sa->sa_family;
438 hint.ai_flags = AI_CANONNAME; 562 hint.ai_flags = AI_CANONNAME;
439 ret = getaddrinfo(str, NULL, &hint, &res); 563 ret = getaddrinfo(buf, NULL, &hint, &res);
440 if (ret == 0) { 564 if (ret == 0) {
441 /* The name was resolved correctly, it must match the IP of the client: */ 565 strncpy(buf, res->ai_canonname, sizeof(buf));
566 /* The name was resolved correctly, does it match the IP of the client? */
442 for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { 567 for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
443 if (cli->sa->sa_family != ptr->ai_family) 568 if (cli->sa->sa_family != ptr->ai_family)
444 continue; 569 continue;
445 if (memcmp(cli->sa, ptr->ai_addr, sSAlen(cli->sa))) 570 if (memcmp(cli->sa, ptr->ai_addr, sSAlen(cli->sa)))
446 continue; 571 continue;
447 572
448 /* It matches: the alias is valid */
449 found = 1; 573 found = 1;
450 break; 574 break;
451 } 575 }
452 freeaddrinfo(res); 576 freeaddrinfo(res);
453 577
454 if (!found) { 578 if (!found) {
455 TRACE_DEBUG(INFO, "The NAS-Identifier value '%s' resolves to a different IP from the NAS's, discarding the message.", str); 579 if (cli->type == RGW_CLI_NAS) {
456 free(str); 580 TRACE_DEBUG(INFO, "The NAS-Identifier value '%.*s' resolves to a different IP than the client's, discarding the message. \nConfigure this client as a Proxy if this message should be valid.",
457 return EINVAL; 581 nas_id->length - sizeof(struct radius_attr_hdr), nas_id + 1);
582 return EINVAL;
583 } else {
584 /* This identifier matches a different IP, assume it is a proxied message */
585 if (!cli->is_local) {
586 rr_str = cli->fqdn;
587 }
588 oh_str = &buf[0]; /* The canonname resolved */
589 or_str = strchr(oh_str, '.');
590 if (or_str) {
591 or_str ++; /* move after the first dot */
592 if (*or_str == '\0')
593 or_str = NULL; /* Discard this realm, we will use the local realm later */
594 }
595 }
596 } else {
597 /* It is a valid alias, save it */
598 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) );
599 CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1] = malloc( 1 + nas_id->length - sizeof(struct radius_attr_hdr) ));
600 memcpy( cli->aliases[cli->aliases_nb + 1], nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
601 *(cli->aliases[cli->aliases_nb + 1] + nas_id->length - sizeof(struct radius_attr_hdr)) = '\0';
602 cli->aliases_nb ++;
603 TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", cli->aliases[cli->aliases_nb + 1], cli->fqdn);
604 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
458 } 605 }
459 } else { 606 } else {
460 /* Error resolving the name */ 607 /* Error resolving the name */
461 TRACE_DEBUG(INFO, "Error while resolving NAS-Identifier value '%s': %s. Ignoring...", str, gai_strerror(ret)); 608 TRACE_DEBUG(INFO, "NAS-Identifier '%s' cannot be resolved: %s. Ignoring...", buf, gai_strerror(ret));
462 } 609 /* Assume this is a valid identifier for the client */
463 610 CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
464 /* It is a valid alias, save it */ 611 }
465 CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) ); 612 }
466 cli->aliases[cli->aliases_nb + 1] = str; 613
467 cli->aliases_nb ++; 614 /* Now, let's create the empty Diameter message with Origin-Host, -Realm, and Route-Record if needed. */
468 TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", str, cli->fqdn); 615 diameter:
469 msg->valid_nas_info |= 2; 616 ASSERT(oh_str); /* If it is not defined here, there is a bug... */
470 } 617 if (!or_str)
471 end: 618 or_str = fd_g_config->cnf_diamrlm; /* Use local realm in that case */
619
620 /* Create an empty Diameter message so that extensions can store their AVPs */
621 CHECK_FCT( fd_msg_new ( NULL, MSGFL_ALLOC_ETEID, diam ) );
622
623 /* Add the Origin-Host as next AVP */
624 CHECK_FCT( fd_msg_avp_new ( cache_orig_host, 0, &avp ) );
625 memset(&avp_val, 0, sizeof(avp_val));
626 avp_val.os.data = (unsigned char *)oh_str;
627 avp_val.os.len = strlen(oh_str);
628 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
629 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
630
631 /* Add the Origin-Realm as next AVP */
632 CHECK_FCT( fd_msg_avp_new ( cache_orig_realm, 0, &avp ) );
633 memset(&avp_val, 0, sizeof(avp_val));
634 avp_val.os.data = (unsigned char *)or_str;
635 avp_val.os.len = strlen(or_str);
636 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
637 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
638
639 if (rr_str) {
640 CHECK_FCT( fd_msg_avp_new ( cache_route_record, 0, &avp ) );
641 memset(&avp_val, 0, sizeof(avp_val));
642 avp_val.os.data = (unsigned char *)rr_str;
643 avp_val.os.len = strlen(rr_str);
644 CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
645 CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
646 }
647
648 /* Done! */
472 return 0; 649 return 0;
473 } 650 }
474 651
475 int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm) 652 int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm)
476 { 653 {
505 client_unlink(*ref); 682 client_unlink(*ref);
506 *ref = NULL; 683 *ref = NULL;
507 CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), ); 684 CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), );
508 } 685 }
509 686
510 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen ) 687 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen, enum rgw_cli_type type )
511 { 688 {
512 struct rgw_client * prev = NULL, *new = NULL; 689 struct rgw_client * prev = NULL, *new = NULL;
513 int ret; 690 int ret;
514 691
515 TRACE_ENTRY("%p %p %lu", ip_port, key, keylen); 692 TRACE_ENTRY("%p %p %lu", ip_port, key, keylen);
516 693
517 CHECK_PARAMS( ip_port && key && *key && keylen ); 694 CHECK_PARAMS( ip_port && key && *key && keylen );
518 CHECK_PARAMS( (ip_port->sa_family == AF_INET) || (ip_port->sa_family == AF_INET6) ); 695 CHECK_PARAMS( (ip_port->sa_family == AF_INET) || (ip_port->sa_family == AF_INET6) );
696 CHECK_PARAMS( (type == RGW_CLI_NAS) || (type == RGW_CLI_PXY) );
519 697
520 /* Dump the entry in debug mode */ 698 /* Dump the entry in debug mode */
521 if (TRACE_BOOL(FULL + 1 )) { 699 if (TRACE_BOOL(FULL + 1 )) {
522 TRACE_DEBUG(FULL, "Adding client:"); 700 TRACE_DEBUG(FULL, "Adding %s:", (type == RGW_CLI_NAS) ? "NAS" : "PROXY" );
523 TRACE_DEBUG_sSA(FULL, "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 701 TRACE_DEBUG_sSA(FULL, "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" );
524 TRACE_DEBUG_BUFFER(FULL, "\tKey: [", *key, keylen, "]" ); 702 TRACE_DEBUG_BUFFER(FULL, "\tKey: [", *key, keylen, "]" );
525 } 703 }
526 704
527 /* Lock the lists */ 705 /* Lock the lists */
529 707
530 /* Check if the same entry does not already exist */ 708 /* Check if the same entry does not already exist */
531 ret = client_search(&prev, ip_port ); 709 ret = client_search(&prev, ip_port );
532 if (ret == ENOENT) { 710 if (ret == ENOENT) {
533 /* No duplicate found, Ok to add */ 711 /* No duplicate found, Ok to add */
534 CHECK_FCT_DO( ret = client_create( &new, &ip_port, key, keylen ), goto end ); 712 CHECK_FCT_DO( ret = client_create( &new, &ip_port, key, keylen, type ), goto end );
535 fd_list_insert_after(&prev->chain, &new->chain); 713 fd_list_insert_after(&prev->chain, &new->chain);
536 new->refcount++; 714 new->refcount++;
537 ret = 0; 715 ret = 0;
538 goto end; 716 goto end;
539 } 717 }
540 718
541 if (ret == EEXIST) { 719 if (ret == EEXIST) {
542 /* Check if the key is the same, then skip or return an error */ 720 /* Check if the key is the same, then skip or return an error */
543 if ((keylen == prev->key.len ) && ( ! memcmp(*key, prev->key.data, keylen) )) { 721 if ((keylen == prev->key.len ) && ( ! memcmp(*key, prev->key.data, keylen) ) && (type == prev->type)) {
544 TRACE_DEBUG(INFO, "Skipping duplicate client description"); 722 TRACE_DEBUG(INFO, "Skipping duplicate client description");
545 ret = 0; 723 ret = 0;
546 goto end; 724 goto end;
547 } 725 }
548 726
549 fd_log_debug("ERROR: Conflicting RADIUS clients descriptions!\n"); 727 fd_log_debug("ERROR: Conflicting RADIUS clients descriptions!\n");
550 TRACE_DEBUG(NONE, "Previous entry:"); 728 TRACE_DEBUG(NONE, "Previous entry: %s", (prev->type == RGW_CLI_NAS) ? "NAS" : "PROXY");
551 TRACE_DEBUG_sSA(NONE, "\tIP : ", prev->sa, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 729 TRACE_DEBUG_sSA(NONE, "\tIP : ", prev->sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
552 TRACE_DEBUG_BUFFER(NONE, "\tKey: [", prev->key.data, prev->key.len, "]" ); 730 TRACE_DEBUG_BUFFER(NONE, "\tKey: [", prev->key.data, prev->key.len, "]" );
553 TRACE_DEBUG(NONE, "Conflicting entry:"); 731 TRACE_DEBUG(NONE, "Conflicting entry: %s", (type == RGW_CLI_NAS) ? "NAS" : "PROXY");
554 TRACE_DEBUG_sSA(NONE, "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" ); 732 TRACE_DEBUG_sSA(NONE, "\tIP : ", ip_port, NI_NUMERICHOST | NI_NUMERICSERV, "" );
555 TRACE_DEBUG_BUFFER(NONE, "\tKey: [", *key, keylen, "]" ); 733 TRACE_DEBUG_BUFFER(NONE, "\tKey: [", *key, keylen, "]" );
556 } 734 }
557 end: 735 end:
558 /* release the lists */ 736 /* release the lists */
"Welcome to our mercurial repository"