X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcstrutil.c;h=c387ffc4fe012b4a0136455f115f4731890a420d;hb=c257b555225193e54d85daf541d29578b3c93882;hp=f15d07863d4fdc641a151520e6b2d59c85372d09;hpb=0b55012d620ee13dce587df51b11139dca26ec09;p=silc.git diff --git a/lib/silcutil/silcstrutil.c b/lib/silcutil/silcstrutil.c index f15d0786..c387ffc4 100644 --- a/lib/silcutil/silcstrutil.c +++ b/lib/silcutil/silcstrutil.c @@ -1,10 +1,10 @@ /* - silcstrutil.c + silcstrutil.c Author: Pekka Riikonen - Copyright (C) 2002 Pekka Riikonen + Copyright (C) 2002 - 2005 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,8 +25,7 @@ static unsigned char pem_enc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded - data string. Note: This is originally public domain code and is - still PD. */ + data string. */ char *silc_pem_encode(unsigned char *data, SilcUInt32 len) { @@ -102,8 +101,7 @@ char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len) return pem2; } -/* Decodes PEM into data. Returns the decoded data. Note: This is - originally public domain code and is still PD. */ +/* Decodes PEM into data. Returns the decoded data. */ unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len, SilcUInt32 *ret_len) @@ -172,243 +170,6 @@ unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len, return data; } -/* Encodes the string `bin' of which encoding is `bin_encoding' to the - UTF-8 encoding into the buffer `utf8' which is of size of `utf8_size'. - Returns the length of the UTF-8 encoded string, or zero (0) on error. - By default `bin_encoding' is ASCII, and the caller needs to know the - encoding of the input string if it is anything else. */ - -SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len, - SilcStringEncoding bin_encoding, - unsigned char *utf8, SilcUInt32 utf8_size) -{ - SilcUInt32 enclen = 0, i, charval = 0; - - if (!bin || !bin_len) - return 0; - - for (i = 0; i < bin_len; i++) { - switch (bin_encoding) { - case SILC_STRING_ASCII: - charval = bin[i]; - break; - case SILC_STRING_ASCII_ESC: - break; - case SILC_STRING_BMP: - break; - case SILC_STRING_UNIVERSAL: - break; - } - - if (charval < 0x80) { - if (utf8) { - if (enclen > utf8_size) - return 0; - - utf8[enclen] = (unsigned char)charval; - } - enclen++; - } else if (charval < 0x800) { - if (utf8) { - if (enclen + 2 > utf8_size) - return 0; - - utf8[enclen ] = (unsigned char )(((charval >> 6) & 0x1f) | 0xc0); - utf8[enclen + 1] = (unsigned char )((charval & 0x3f) | 0x80); - } - enclen += 2; - } else if (charval < 0x10000) { - if (utf8) { - if (enclen + 3 > utf8_size) - return 0; - - utf8[enclen ] = (unsigned char )(((charval >> 12) & 0xf) | 0xe0); - utf8[enclen + 1] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80); - utf8[enclen + 2] = (unsigned char )((charval & 0x3f) | 0x80); - } - enclen += 3; - } else if (charval < 0x200000) { - if (utf8) { - if (enclen + 4 > utf8_size) - return 0; - - utf8[enclen ] = (unsigned char )(((charval >> 18) & 0x7) | 0xf0); - utf8[enclen + 1] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80); - utf8[enclen + 2] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80); - utf8[enclen + 3] = (unsigned char )((charval & 0x3f) | 0x80); - } - enclen += 4; - } else if (charval < 0x4000000) { - if (utf8) { - if (enclen + 5 > utf8_size) - return 0; - - utf8[enclen ] = (unsigned char )(((charval >> 24) & 0x3) | 0xf8); - utf8[enclen + 1] = (unsigned char )(((charval >> 18) & 0x3f) | 0x80); - utf8[enclen + 2] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80); - utf8[enclen + 3] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80); - utf8[enclen + 4] = (unsigned char )((charval & 0x3f) | 0x80); - } - enclen += 5; - } else { - if (utf8) { - if (enclen + 6 > utf8_size) - return 0; - - utf8[enclen ] = (unsigned char )(((charval >> 30) & 0x1) | 0xfc); - utf8[enclen + 1] = (unsigned char )(((charval >> 24) & 0x3f) | 0x80); - utf8[enclen + 2] = (unsigned char )(((charval >> 18) & 0x3f) | 0x80); - utf8[enclen + 3] = (unsigned char )(((charval >> 12) & 0x3f) | 0x80); - utf8[enclen + 4] = (unsigned char )(((charval >> 6) & 0x3f) | 0x80); - utf8[enclen + 5] = (unsigned char )((charval & 0x3f) | 0x80); - } - enclen += 6; - } - } - - return enclen; -} - -/* Decodes UTF-8 encoded string `utf8' to string of which encoding is - to be `bin_encoding', into the `bin' buffer of size of `bin_size'. - Returns the length of the decoded buffer, or zero (0) on error. - By default `bin_encoding' is ASCII, and the caller needs to know to - which encoding the output string is to be encoded if ASCII is not - desired. */ - -SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, - SilcStringEncoding bin_encoding, - unsigned char *bin, SilcUInt32 bin_size) -{ - SilcUInt32 enclen = 0, i, charval; - - if (!utf8 || !utf8_len) - return 0; - - for (i = 0; i < utf8_len; i++) { - if ((utf8[i] & 0x80) == 0x00) { - charval = utf8[i] & 0x7f; - } else if ((utf8[i] & 0xe0) == 0xc0) { - if (utf8_len < 2) - return 0; - - if ((utf8[i + 1] & 0xc0) != 0x80) - return 0; - - charval = (utf8[i++] & 0x1f) << 6; - charval |= utf8[i] & 0x3f; - if (charval < 0x80) - return 0; - } else if ((utf8[i] & 0xf0) == 0xe0) { - if (utf8_len < 3) - return 0; - - if (((utf8[i + 1] & 0xc0) != 0x80) || - ((utf8[i + 2] & 0xc0) != 0x80)) - return 0; - - charval = (utf8[i++] & 0xf) << 12; - charval |= (utf8[i++] & 0x3f) << 6; - charval |= utf8[i] & 0x3f; - if (charval < 0x800) - return 0; - } else if ((utf8[i] & 0xf8) == 0xf0) { - if (utf8_len < 4) - return 0; - - if (((utf8[i + 1] & 0xc0) != 0x80) || - ((utf8[i + 2] & 0xc0) != 0x80) || - ((utf8[i + 3] & 0xc0) != 0x80)) - return 0; - - charval = ((SilcUInt32)(utf8[i++] & 0x7)) << 18; - charval |= (utf8[i++] & 0x3f) << 12; - charval |= (utf8[i++] & 0x3f) << 6; - charval |= utf8[i] & 0x3f; - if (charval < 0x10000) - return 0; - } else if ((utf8[i] & 0xfc) == 0xf8) { - if (utf8_len < 5) - return 0; - - if (((utf8[i + 1] & 0xc0) != 0x80) || - ((utf8[i + 2] & 0xc0) != 0x80) || - ((utf8[i + 3] & 0xc0) != 0x80) || - ((utf8[i + 4] & 0xc0) != 0x80)) - return 0; - - charval = ((SilcUInt32)(utf8[i++] & 0x3)) << 24; - charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 18; - charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 12; - charval |= (utf8[i++] & 0x3f) << 6; - charval |= utf8[i] & 0x3f; - if (charval < 0x200000) - return 0; - } else if ((utf8[i] & 0xfe) == 0xfc) { - if (utf8_len < 6) - return 0; - - if (((utf8[i + 1] & 0xc0) != 0x80) || - ((utf8[i + 2] & 0xc0) != 0x80) || - ((utf8[i + 3] & 0xc0) != 0x80) || - ((utf8[i + 4] & 0xc0) != 0x80) || - ((utf8[i + 5] & 0xc0) != 0x80)) - return 0; - - charval = ((SilcUInt32)(utf8[i++] & 0x1)) << 30; - charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 24; - charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 18; - charval |= ((SilcUInt32)(utf8[i++] & 0x3f)) << 12; - charval |= (utf8[i++] & 0x3f) << 6; - charval |= utf8[i] & 0x3f; - if (charval < 0x4000000) - return 0; - } else { - return 0; - } - - switch (bin_encoding) { - case SILC_STRING_ASCII: - if (bin) { - if (enclen + 1 > bin_size) - return 0; - - bin[enclen] = (unsigned char)charval; - } - enclen++; - break; - case SILC_STRING_ASCII_ESC: - return 0; - break; - case SILC_STRING_BMP: - return 0; - break; - case SILC_STRING_UNIVERSAL: - return 0; - break; - } - } - - return enclen; -} - -/* Returns the length of UTF-8 encoded string if the `bin' of - encoding of `bin_encoding' is encoded with silc_utf8_encode. */ - -SilcUInt32 silc_utf8_encoded_len(const unsigned char *bin, SilcUInt32 bin_len, - SilcStringEncoding bin_encoding) -{ - return silc_utf8_encode(bin, bin_len, bin_encoding, NULL, 0); -} - -/* Returns TRUE if the `utf8' string of length of `utf8_len' is valid - UTF-8 encoded string, FALSE if it is not UTF-8 encoded string. */ - -bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len) -{ - return silc_utf8_decode(utf8, utf8_len, 0, NULL, 0) != 0; -} - /* Mime constants and macros */ #define MIME_VERSION "MIME-Version: " #define MIME_VERSION_LEN 14 @@ -417,64 +178,218 @@ bool silc_utf8_valid(const unsigned char *utf8, SilcUInt32 utf8_len) #define MIME_TRANSFER_ENCODING "Content-Transfer-Encoding: " #define MIME_TRANSFER_ENCODING_LEN 27 -#define MIME_GET_FIELD(header, mime, mime_len, field, field_len, \ +#define MIME_GET_FIELD(mime, mime_len, field, field_len, \ dest, dest_size) \ do { \ - char *f = strstr(header, field); \ - if (f && dest) { \ - f = (char *)mime + (f - header) + field_len; \ - for (i = 0; i < (mime_len - (f - (char *)mime)); i++) { \ - if (f[i] == '\r' || f[i] == '\n' || i == dest_size) \ - break; \ - dest[i] = f[i]; \ + if (dest) { \ + char *f = strstr(mime, field); \ + if (f) { \ + int parse_len; \ + f += field_len; \ + parse_len = (mime_len - (f - (char *)mime)); \ + for (i = 0; i < parse_len; i++) { \ + if ((i == dest_size) || \ + ((f[i] == '\n') && \ + ((i == parse_len - 1) || \ + ((f[i+1] != ' ') && (f[i+1] != '\t')))) || \ + ((f[i] == '\r') && \ + ((i == parse_len - 1) || (f[i+1] == '\n')) && \ + ((i >= parse_len - 2) || \ + ((f[i+2] != ' ') && (f[i+2] != '\t'))))) \ + break; \ + dest[i] = f[i]; \ + } \ } \ } \ } while(0) /* Parses MIME object and MIME header in it. */ -bool +bool silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len, char *version, SilcUInt32 version_size, char *content_type, SilcUInt32 content_type_size, char *transfer_encoding, SilcUInt32 transfer_encoding_size, unsigned char **mime_data_ptr, SilcUInt32 *mime_data_len) -{ +{ int i; - char header[512]; - - memcpy(header, mime, 512 > mime_len ? mime_len : 512); - header[sizeof(header) - 1] = '\0'; + unsigned char *tmp; - /* Check for mandatory Content-Type field */ - if (!strstr(header, MIME_CONTENT_TYPE)) - return FALSE; - /* Get the pointer to the data area in the object */ for (i = 0; i < mime_len; i++) { - if (mime_len >= i + 4 && - mime[i ] == '\r' && mime[i + 1] == '\n' && - mime[i + 2] == '\r' && mime[i + 3] == '\n') + if ((mime_len >= i + 4 && + mime[i ] == '\r' && mime[i + 1] == '\n' && + mime[i + 2] == '\r' && mime[i + 3] == '\n') || + (mime_len >= i + 2 && + mime[i ] == '\n' && mime[i + 1] == '\n')) break; } if (i >= mime_len) return FALSE; if (mime_data_ptr) - *mime_data_ptr = (unsigned char *)mime + i + 4; + *mime_data_ptr = (unsigned char *)mime + i + + (mime[i] == '\n' ? 2 : 4); if (mime_data_len) - *mime_data_len = mime_len - ((mime + i + 4) - mime); - + *mime_data_len = mime_len - (i + (mime[i] == '\n' ? 2 : 4)); + + /* Check for mandatory Content-Type field */ + tmp = strstr(mime, MIME_CONTENT_TYPE); + if (!tmp || (tmp - mime) >= i) + return FALSE; + /* Get MIME version, Content-Type and Transfer Encoding fields */ - MIME_GET_FIELD(header, mime, mime_len, + MIME_GET_FIELD(mime, mime_len, MIME_VERSION, MIME_VERSION_LEN, version, version_size); - MIME_GET_FIELD(header, mime, mime_len, + MIME_GET_FIELD(mime, mime_len, MIME_CONTENT_TYPE, MIME_CONTENT_TYPE_LEN, content_type, content_type_size); - MIME_GET_FIELD(header, mime, mime_len, + MIME_GET_FIELD(mime, mime_len, MIME_TRANSFER_ENCODING, MIME_TRANSFER_ENCODING_LEN, transfer_encoding, transfer_encoding_size); return TRUE; } + +/* Concatenates the `src' into `dest'. If `src_len' is more than the + size of the `dest' (minus NULL at the end) the `src' will be + truncated to fit. */ + +char *silc_strncat(char *dest, SilcUInt32 dest_size, + const char *src, SilcUInt32 src_len) +{ + int len; + + dest[dest_size - 1] = '\0'; + + len = dest_size - 1 - strlen(dest); + if (len < src_len) { + if (len > 0) + strncat(dest, src, len); + } else { + strncat(dest, src, src_len); + } + + return dest; +} + +/* Checks that the 'identifier' string is valid identifier string + and does not contain any unassigned or prohibited character. This + function is used to check for valid nicknames, channel names, + server names, usernames, hostnames, service names, algorithm names, + other security property names, and SILC Public Key name. */ + +unsigned char *silc_identifier_check(const unsigned char *identifier, + SilcUInt32 identifier_len, + SilcStringEncoding identifier_encoding, + SilcUInt32 max_allowed_length, + SilcUInt32 *out_len) +{ + unsigned char *utf8s; + SilcUInt32 utf8s_len; + SilcStringprepStatus status; + + if (!identifier || !identifier_len) + return NULL; + + if (max_allowed_length && identifier_len > max_allowed_length) + return NULL; + + status = silc_stringprep(identifier, identifier_len, + identifier_encoding, SILC_IDENTIFIER_PREP, 0, + &utf8s, &utf8s_len, SILC_STRING_UTF8); + if (status != SILC_STRINGPREP_OK) { + SILC_LOG_DEBUG(("silc_stringprep() status error %d", status)); + return NULL; + } + + if (out_len) + *out_len = utf8s_len; + + return utf8s; +} + +/* Same as above but does not allocate memory, just checks the + validity of the string. */ + +bool silc_identifier_verify(const unsigned char *identifier, + SilcUInt32 identifier_len, + SilcStringEncoding identifier_encoding, + SilcUInt32 max_allowed_length) +{ + SilcStringprepStatus status; + + if (!identifier || !identifier_len) + return FALSE; + + if (max_allowed_length && identifier_len > max_allowed_length) + return FALSE; + + status = silc_stringprep(identifier, identifier_len, + identifier_encoding, SILC_IDENTIFIER_PREP, 0, + NULL, NULL, SILC_STRING_UTF8); + if (status != SILC_STRINGPREP_OK) { + SILC_LOG_DEBUG(("silc_stringprep() status error %d", status)); + return FALSE; + } + + return TRUE; +} + +unsigned char *silc_channel_name_check(const unsigned char *identifier, + SilcUInt32 identifier_len, + SilcStringEncoding identifier_encoding, + SilcUInt32 max_allowed_length, + SilcUInt32 *out_len) +{ + unsigned char *utf8s; + SilcUInt32 utf8s_len; + SilcStringprepStatus status; + + if (!identifier || !identifier_len) + return NULL; + + if (max_allowed_length && identifier_len > max_allowed_length) + return NULL; + + status = silc_stringprep(identifier, identifier_len, + identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0, + &utf8s, &utf8s_len, SILC_STRING_UTF8); + if (status != SILC_STRINGPREP_OK) { + SILC_LOG_DEBUG(("silc_stringprep() status error %d", status)); + return NULL; + } + + if (out_len) + *out_len = utf8s_len; + + return utf8s; +} + +/* Same as above but does not allocate memory, just checks the + validity of the string. */ + +bool silc_channel_name_verify(const unsigned char *identifier, + SilcUInt32 identifier_len, + SilcStringEncoding identifier_encoding, + SilcUInt32 max_allowed_length) +{ + SilcStringprepStatus status; + + if (!identifier || !identifier_len) + return FALSE; + + if (max_allowed_length && identifier_len > max_allowed_length) + return FALSE; + + status = silc_stringprep(identifier, identifier_len, + identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0, + NULL, NULL, SILC_STRING_UTF8); + if (status != SILC_STRINGPREP_OK) { + SILC_LOG_DEBUG(("silc_stringprep() status error %d", status)); + return FALSE; + } + + return TRUE; +}