Index: extensions/app_radgw/rgw_clients.c
===================================================================
--- extensions/app_radgw/rgw_clients.c	(revision 554)
+++ extensions/app_radgw/rgw_clients.c	(revision 706)
@@ -86,8 +86,12 @@
 	int			 is_local; /* true if the RADIUS client runs on the same host -- we use Diameter Identity in that case */
 	enum rgw_cli_type 	 type; /* is it a proxy ? */
-	char 			*fqdn;
+	DiamId_t		 fqdn; /* malloc'd here */
 	size_t			 fqdn_len;
-	char			*realm;
-	char			**aliases;
+	DiamId_t		 realm; /* references another string, do not free */
+	size_t			 realm_len;
+	struct {
+		os0_t		 name;
+		size_t		 len;
+	}			*aliases; /* Received aliases */
 	size_t			 aliases_nb;
 	
@@ -210,5 +214,6 @@
 {
 	struct rgw_client *tmp = NULL;
-	char buf[255];
+	DiamId_t fqdn;
+	size_t fqdn_len;
 	int ret, i;
 	int loc = 0;
@@ -220,4 +225,5 @@
 		loc = 1;
 	} else {
+		char buf[255];
 	
 		/* Search FQDN for the client */
@@ -227,4 +233,10 @@
 			return EINVAL;
 		}
+		fqdn = &buf[0];
+		CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&fqdn, &fqdn_len, 1),
+			{
+				TRACE_DEBUG(INFO, "Unable to use resolved peer name '%s' as DiameterIdentity: %s", buf, strerror(ret));
+				return ret;
+			} );
 	}
 	
@@ -246,12 +258,17 @@
 	} else {
 		/* Copy the fqdn */
-		CHECK_MALLOC( tmp->fqdn = strdup(buf) );
-		tmp->fqdn_len = strlen(tmp->fqdn);
+		tmp->fqdn = fqdn;
+		tmp->fqdn_len = fqdn_len;
+
 		/* Find an appropriate realm */
-		tmp->realm = strchr(tmp->fqdn, '.');
-		if (tmp->realm)
+		tmp->realm = strchr(fqdn, '.');
+		if (tmp->realm) {
 			tmp->realm += 1;
-		if ((!tmp->realm) || (*tmp->realm == '\0')) /* in case the fqdn was "localhost." for example, if it is possible... */
+			tmp->realm_len = tmp->fqdn_len - (tmp->realm - fqdn);
+		}
+		if ((!tmp->realm) || (*tmp->realm == '\0')) { /* in case the fqdn was "localhost." for example, if it is possible... */
 			tmp->realm = fd_g_config->cnf_diamrlm;
+			tmp->realm_len = fd_g_config->cnf_diamrlm_len;
+		}
 	}
 	
@@ -282,5 +299,5 @@
 		/* Free the data */
 		for (idx = 0; idx < client->aliases_nb; idx++)
-			free(client->aliases[idx]);
+			free(client->aliases[idx].name);
 		free(client->aliases);
 		free(client->fqdn);
@@ -532,7 +549,8 @@
 	int valid_nas_info = 0;
 	struct radius_attr_hdr *nas_ip = NULL, *nas_ip6 = NULL, *nas_id = NULL;
-	char * oh_str = NULL;
-	char * or_str = NULL;
-	char * rr_str = NULL;
+	size_t nas_id_len;
+	char * oh_str = NULL; size_t oh_strlen; int oh_free = 0;
+	char * or_str = NULL; size_t or_strlen;
+	char * rr_str = NULL; size_t rr_strlen;
 	char buf[REVERSE_DNS_SIZE_MAX]; /* to store DNS lookups results */
 	
@@ -555,4 +573,5 @@
 		if ((attr->type == RADIUS_ATTR_NAS_IDENTIFIER) && (attr_len > 0)) {
 			nas_id = attr;
+			nas_id_len = attr_len;
 			continue;
 		}
@@ -568,5 +587,5 @@
 		
 		/* Get information on this peer */
-		CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+		CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 		
 		goto diameter;
@@ -619,10 +638,12 @@
 				return EINVAL;
 			} else {
+				int ret;
+				sSS ss;
 				/* the peer is configured as a proxy, or running on localhost, so accept the message */
-				sSS ss;
 				
 				/* In that case, the cli will be stored as Route-Record and the NAS-IP-Address as origin */
 				if (!cli->is_local) {
 					rr_str = cli->fqdn;
+					rr_strlen = cli->fqdn_len;
 				}
 				
@@ -641,5 +662,5 @@
 					{
 						if (cli->is_local) {
-							CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+							CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 							goto diameter;
 						}
@@ -648,6 +669,18 @@
 						return EINVAL;
 					} );
+					
+				oh_str = &buf[0];
+				CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1),
+					{
+						if (cli->is_local) {
+							CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
+							goto diameter;
+						}
+						
+						TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret));
+						return ret;
+					} );
+				oh_free = 1;
 				
-				oh_str = &buf[0];
 				or_str = strchr(oh_str, '.');
 				if (or_str) {
@@ -655,9 +688,11 @@
 					if (*or_str == '\0')
 						or_str = NULL; /* Discard this realm, we will use the local realm later */
+					else
+						or_strlen = oh_strlen - (or_str - oh_str);
 				}
 			}
 		} else {
 			/* The attribute matches the source address, just use this in origin-host */
-			CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+			CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 		}
 		
@@ -668,5 +703,5 @@
 	if (cli->is_local) {
 		/* Simple: we use our own configuration */
-		CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+		CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 		goto diameter;
 	}
@@ -697,12 +732,12 @@
 		
 		/* first, check if the nas_id is the fqdn of the peer or a known alias */
-		if ((cli->fqdn_len == (nas_id->length - sizeof(struct radius_attr_hdr))) 
-		&& (!strncasecmp((char *)(nas_id + 1), cli->fqdn, nas_id->length - sizeof(struct radius_attr_hdr)))) {
+		if (!fd_os_almostcasecmp(nas_id + 1, nas_id_len, 
+						cli->fqdn, cli->fqdn_len)) {
 			TRACE_DEBUG(FULL, "NAS-Identifier contains the fqdn of the client");
 			found = 1;
 		} else {
 			for (idx = 0; idx < cli->aliases_nb; idx++) {
-				if (((nas_id->length - sizeof(struct radius_attr_hdr)) == strlen(cli->aliases[idx])) 
-				&& (!strncasecmp((char *)(nas_id + 1), cli->aliases[idx], nas_id->length - sizeof(struct radius_attr_hdr)))) {
+				if (!fd_os_cmp(nas_id + 1, nas_id_len, 
+						cli->aliases[idx].name, cli->aliases[idx].len)) {
 					TRACE_DEBUG(FULL, "NAS-Identifier valid value found in the cache");
 					found = 1;
@@ -714,5 +749,5 @@
 		if (found) {
 			/* The NAS-Identifier matches the source IP */
-			CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+			CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 
 			goto diameter;
@@ -720,6 +755,6 @@
 		
 		/* Attempt DNS resolution of the identifier */
-		ASSERT( nas_id->length - sizeof(struct radius_attr_hdr) < sizeof(buf) );
-		memcpy(buf, nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
+		ASSERT( nas_id_len < sizeof(buf) );
+		memcpy(buf, nas_id + 1, nas_id_len);
 		buf[nas_id->length - sizeof(struct radius_attr_hdr)] = '\0';
 		
@@ -745,5 +780,5 @@
 				if (cli->type == RGW_CLI_NAS) {
 					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.", 
-						nas_id->length - sizeof(struct radius_attr_hdr), nas_id + 1);
+						nas_id_len, nas_id + 1);
 					return EINVAL;
 				} else {
@@ -751,6 +786,13 @@
 					if (!cli->is_local) {
 						rr_str = cli->fqdn;
+						rr_strlen = cli->fqdn_len;
 					}
 					oh_str = &buf[0]; /* The canonname resolved */
+					CHECK_FCT_DO( ret = fd_os_validate_DiameterIdentity(&oh_str, &oh_strlen, 1),
+						{
+							TRACE_DEBUG(INFO, "Unable to use resolved client name '%s' as DiameterIdentity: %s", buf, strerror(ret));
+							return ret;
+						} );
+					oh_free = 1;
 					or_str = strchr(oh_str, '.');
 					if (or_str) {
@@ -758,15 +800,18 @@
 						if (*or_str == '\0')
 							or_str = NULL; /* Discard this realm, we will use the local realm later */
+						else
+							or_strlen = oh_strlen - (or_str - oh_str);
 					}
 				}
 			} else {
 				/* It is a valid alias, save it */
-				CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(char *)) );
-				CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1] = malloc( 1 + nas_id->length - sizeof(struct radius_attr_hdr) ));
-				memcpy( cli->aliases[cli->aliases_nb + 1], nas_id + 1, nas_id->length - sizeof(struct radius_attr_hdr));
-				*(cli->aliases[cli->aliases_nb + 1] + nas_id->length - sizeof(struct radius_attr_hdr)) = '\0';
+				CHECK_MALLOC( cli->aliases = realloc(cli->aliases, (cli->aliases_nb + 1) * sizeof(cli->aliases[0])) );
+				
+				CHECK_MALLOC( cli->aliases[cli->aliases_nb + 1].name = os0dup(nas_id + 1, nas_id_len ) );
+				cli->aliases[cli->aliases_nb + 1].len = nas_id_len;
+
 				cli->aliases_nb ++;
-				TRACE_DEBUG(FULL, "Saved valid alias for client: '%s' -> '%s'", cli->aliases[cli->aliases_nb + 1], cli->fqdn);
-				CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+				TRACE_DEBUG(FULL, "Saved valid alias for client: '%.*s' -> '%s'", nas_id_len, nas_id + 1, cli->fqdn);
+				CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 			}
 		} else {
@@ -774,5 +819,5 @@
 			TRACE_DEBUG(INFO, "NAS-Identifier '%s' cannot be resolved: %s. Ignoring...", buf, gai_strerror(ret));
 			/* Assume this is a valid identifier for the client */
-			CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &or_str) );
+			CHECK_FCT( rgw_clients_get_origin(cli, &oh_str, &oh_strlen, &or_str, &or_strlen) );
 		}
 	}
@@ -781,6 +826,8 @@
 diameter:
 	ASSERT(oh_str); /* If it is not defined here, there is a bug... */
-	if (!or_str)
+	if (!or_str) {
 		or_str = fd_g_config->cnf_diamrlm; /* Use local realm in that case */
+		or_strlen = fd_g_config->cnf_diamrlm_len;
+	}
 	
 	/* Create an empty Diameter message so that extensions can store their AVPs */
@@ -791,5 +838,5 @@
 	memset(&avp_val, 0, sizeof(avp_val));
 	avp_val.os.data = (unsigned char *)oh_str;
-	avp_val.os.len = strlen(oh_str);
+	avp_val.os.len = oh_strlen;
 	CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
 	CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
@@ -799,5 +846,5 @@
 	memset(&avp_val, 0, sizeof(avp_val));
 	avp_val.os.data = (unsigned char *)or_str;
-	avp_val.os.len = strlen(or_str);
+	avp_val.os.len = or_strlen;
 	CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
 	CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
@@ -807,26 +854,35 @@
 		memset(&avp_val, 0, sizeof(avp_val));
 		avp_val.os.data = (unsigned char *)rr_str;
-		avp_val.os.len = strlen(rr_str);
+		avp_val.os.len = rr_strlen;
 		CHECK_FCT( fd_msg_avp_setvalue ( avp, &avp_val ) );
 		CHECK_FCT( fd_msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
 	}
 	
+	if (oh_free)
+		free(oh_str);
+	
 	/* Done! */
 	return 0;
 }
 
-int rgw_clients_get_origin(struct rgw_client *cli, char **fqdn, char **realm)
-{
-	TRACE_ENTRY("%p %p %p", cli, fqdn, realm);
-	CHECK_PARAMS(cli && fqdn);
+int rgw_clients_get_origin(struct rgw_client *cli, DiamId_t *fqdn, size_t *fqdnlen, DiamId_t *realm, size_t *realmlen)
+{
+	TRACE_ENTRY("%p %p %p %p %p", cli, fqdn, fqdnlen, realm, realmlen);
+	CHECK_PARAMS(cli && fqdn && fqdnlen);
 	
 	if (cli->is_local) {
 		*fqdn = fd_g_config->cnf_diamid;
+		*fqdnlen = fd_g_config->cnf_diamid_len;
 		if (realm)
 			*realm= fd_g_config->cnf_diamrlm;
+		if (realmlen)
+			*realmlen= fd_g_config->cnf_diamrlm_len;
 	} else {
 		*fqdn = cli->fqdn;
+		*fqdnlen = cli->fqdn_len;
 		if (realm)
 			*realm= cli->realm;
+		if (realmlen)
+			*realmlen= cli->realm_len;
 	}
 		
