Mercurial > hg > freeDiameter
diff libfdproto/ostr.c @ 707:e387d5c6b6f5
Added support for Internationalized Domain Names (IDNA) using GNU libidn
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Wed, 09 Feb 2011 18:08:54 +0900 |
parents | 4ffbc9f1e922 |
children | 571b3abaa5df |
line wrap: on
line diff
--- a/libfdproto/ostr.c Wed Feb 09 15:26:58 2011 +0900 +++ b/libfdproto/ostr.c Wed Feb 09 18:08:54 2011 +0900 @@ -35,6 +35,11 @@ #include "fdproto-internal.h" +#if (!defined(DIAMID_IDNA_IGNORE) && !defined(DIAMID_IDNA_REJECT)) +/* Process IDNA with stringprep -- See RFC5890 -- and libidn documentation... */ +#include <idna.h> /* idna_to_ascii_8z() */ +#endif /* !defined(DIAMID_IDNA_IGNORE) && !defined(DIAMID_IDNA_REJECT) */ + /* Similar to strdup with (must be verified) os0_t */ os0_t os0dup_int(os0_t s, size_t l) { os0_t r; @@ -88,9 +93,15 @@ /* Check if the string contains only ASCII */ int fd_os_is_valid_DiameterIdentity(uint8_t * os, size_t ossz) { +#ifdef DIAMID_IDNA_IGNORE + + /* Allow anything */ + +#else /* DIAMID_IDNA_IGNORE */ + int i; - /* Allow letters, digits, hyphen, dot */ + /* Allow only letters, digits, hyphen, dot */ for (i=0; i < ossz; i++) { if (os[i] > 'z') break; @@ -105,9 +116,53 @@ break; } if (i < ossz) { - TRACE_DEBUG(INFO, "Invalid character '%c' in DiameterIdentity '%.*s'", os[i], ossz, os); + int nb = 1; + /* To get a better display, check if the invalid char is UTF-8 */ + if ((os[i] & 0xE0) == 0xC0 /* 110xxxxx */) { + if ((i < ossz - 1) && ((os[i + 1] & 0xC0) == 0x80 /* 10xxxxxx */)) + nb = 2; + goto disp; + } + if ((os[i] & 0xF0) == 0xE0 /* 1110xxxx */) { + if ((i < ossz - 2) && ((os[i + 1] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 2] & 0xC0) == 0x80 /* 10xxxxxx */)) + nb = 3; + goto disp; + } + if ((os[i] & 0xF8) == 0xF0 /* 11110xxx */) { + if ((i < ossz - 3) && ((os[i + 1] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 2] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 3] & 0xC0) == 0x80 /* 10xxxxxx */)) + nb = 4; + goto disp; + } + if ((os[i] & 0xFC) == 0xF8 /* 111110xx */) { + if ((i < ossz - 4) && ((os[i + 1] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 2] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 3] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 4] & 0xC0) == 0x80 /* 10xxxxxx */)) + nb = 5; + goto disp; + } + if ((os[i] & 0xFE) == 0xFC /* 1111110x */) { + if ((i < ossz - 5) && ((os[i + 1] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 2] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 3] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 4] & 0xC0) == 0x80 /* 10xxxxxx */) + && ((os[i + 5] & 0xC0) == 0x80 /* 10xxxxxx */)) + nb = 6; + goto disp; + } + /* otherwise, we just display the hex code */ + TRACE_DEBUG(INFO, "Invalid character (0xhhX) at offset %d in DiameterIdentity '%.*s'", os[i], i+1, ossz, os); + return 0; +disp: + TRACE_DEBUG(INFO, "Invalid character '%.*s' at offset %d in DiameterIdentity '%.*s'", nb, os + i, i+1, ossz, os); return 0; } + +#endif /* DIAMID_IDNA_IGNORE */ + return 1; } @@ -118,16 +173,38 @@ *outsz = strlen(*id); +#ifndef DIAMID_IDNA_IGNORE + if (!fd_os_is_valid_DiameterIdentity((os0_t)*id, *outsz)) { - char buf[HOST_NAME_MAX]; + +#ifdef DIAMID_IDNA_REJECT + + TRACE_DEBUG(INFO, "The string '%s' is not a valid DiameterIdentity!", *id); + TRACE_DEBUG(INFO, "Returning EINVAL since fD is compiled with option DIAMID_IDNA_REJECT."); + return EINVAL; + +#else /* DIAMID_IDNA_REJECT */ + + char *processed; + int ret; - TODO("Stringprep in into buf"); - TRACE_DEBUG(INFO, "The string '%s' is not a valid DiameterIdentity, it was changed to '%s'", *id, buf); - TODO("Realloc *id if !memory"); - /* copy buf */ - /* update the size */ - return ENOTSUP; - } else { + ret = idna_to_ascii_8z ( *id, &processed, IDNA_USE_STD3_ASCII_RULES ); + if (ret == IDNA_SUCCESS) { + TRACE_DEBUG(INFO, "The string '%s' is not a valid DiameterIdentity, it was changed to '%s'", *id, processed); + if (memory == 0) + free(*id); + *id = processed; + *outsz = strlen(processed); + /* Done! */ + } else { + TRACE_DEBUG(INFO, "The string '%s' is not a valid DiameterIdentity and cannot be sanitanized: %s", *id, idna_strerror (ret)); + return EINVAL; + } + +#endif /* DIAMID_IDNA_REJECT */ + } else +#endif /* ! DIAMID_IDNA_IGNORE */ + { if (memory == 1) { CHECK_MALLOC( *id = os0dup(*id, *outsz) ); } @@ -137,8 +214,6 @@ - - /********************************************************************************************************/ /* Hash function -- credits to Austin Appleby, thank you ^^ */ /* See http://murmurhash.googlepages.com for more information on this function */