X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcstrutil.c;h=3251c2b0a4d47c43255ca71746e17cf899ffedb4;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=8fddd0b22a7ebdebdeabbfbcd54cebce110eb3fb;hpb=c27a4ecc3e616e8a5ee09b8ca888ed6ff3e501f7;p=silc.git diff --git a/lib/silcutil/silcstrutil.c b/lib/silcutil/silcstrutil.c index 8fddd0b2..3251c2b0 100644 --- a/lib/silcutil/silcstrutil.c +++ b/lib/silcutil/silcstrutil.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002 - 2005 Pekka Riikonen + Copyright (C) 2002 - 2007 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 @@ -18,378 +18,253 @@ */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "silcstrutil.h" -static unsigned char pem_enc[64] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* Encodes data into PEM encoding. Returns NULL terminated PEM encoded - data string. */ +/* 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_pem_encode(unsigned char *data, SilcUInt32 len) +char *silc_strncat(char *dest, SilcUInt32 dest_size, + const char *src, SilcUInt32 src_len) { - int i, j; - SilcUInt32 bits, c, char_count; - char *pem; - - char_count = 0; - bits = 0; - j = 0; - - pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem)); + int len; - for (i = 0; i < len; i++) { - c = data[i]; - bits += c; - char_count++; - - if (char_count == 3) { - pem[j++] = pem_enc[bits >> 18]; - pem[j++] = pem_enc[(bits >> 12) & 0x3f]; - pem[j++] = pem_enc[(bits >> 6) & 0x3f]; - pem[j++] = pem_enc[bits & 0x3f]; - bits = 0; - char_count = 0; - } else { - bits <<= 8; - } - } + dest[dest_size - 1] = '\0'; - if (char_count != 0) { - bits <<= 16 - (8 * char_count); - pem[j++] = pem_enc[bits >> 18]; - pem[j++] = pem_enc[(bits >> 12) & 0x3f]; - - if (char_count == 1) { - pem[j++] = '='; - pem[j] = '='; - } else { - pem[j++] = pem_enc[(bits >> 6) & 0x3f]; - pem[j] = '='; - } + len = dest_size - 1 - strlen(dest); + if (len < src_len) { + if (len > 0) + strncat(dest, src, len); + } else { + strncat(dest, src, src_len); } - return pem; + return dest; } -/* Same as above but puts newline ('\n') every 72 characters. */ +/* Compares two strings. Strings may include wildcards '*' and '?'. + Returns TRUE if strings match. */ -char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len) +int silc_string_compare(char *string1, char *string2) { - int i, j; - SilcUInt32 len, cols; - char *pem, *pem2; - - pem = silc_pem_encode(data, data_len); - len = strlen(pem); + int i; + int slen1; + int slen2; + char *tmpstr1, *tmpstr2; - pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2)); + if (!string1 || !string2) + return FALSE; - for (i = 0, j = 0, cols = 1; i < len; i++, cols++) { - if (cols == 72) { - pem2[i] = '\n'; - cols = 0; - len++; - continue; + slen1 = strlen(string1); + slen2 = strlen(string2); + + /* See if they are same already */ + if (!strncmp(string1, string2, slen2) && slen2 == slen1) + return TRUE; + + if (slen2 < slen1) + if (!strchr(string1, '*')) + return FALSE; + + /* Take copies of the original strings as we will change them */ + tmpstr1 = silc_calloc(slen1 + 1, sizeof(char)); + memcpy(tmpstr1, string1, slen1); + tmpstr2 = silc_calloc(slen2 + 1, sizeof(char)); + memcpy(tmpstr2, string2, slen2); + + for (i = 0; i < slen1; i++) { + + /* * wildcard. Only one * wildcard is possible. */ + if (tmpstr1[i] == '*') + if (!strncmp(tmpstr1, tmpstr2, i)) { + memset(tmpstr2, 0, slen2); + strncpy(tmpstr2, tmpstr1, i); + break; + } + + /* ? wildcard */ + if (tmpstr1[i] == '?') { + if (!strncmp(tmpstr1, tmpstr2, i)) { + if (!(slen1 < i + 1)) + if (tmpstr1[i + 1] != '?' && + tmpstr1[i + 1] != tmpstr2[i + 1]) + continue; + + if (!(slen1 < slen2)) + tmpstr2[i] = '?'; + } } + } + + /* if using *, remove it */ + if (strchr(tmpstr1, '*')) + *strchr(tmpstr1, '*') = 0; - pem2[i] = pem[j++]; + if (!strcmp(tmpstr1, tmpstr2)) { + memset(tmpstr1, 0, slen1); + memset(tmpstr2, 0, slen2); + silc_free(tmpstr1); + silc_free(tmpstr2); + return TRUE; } - silc_free(pem); - return pem2; + memset(tmpstr1, 0, slen1); + memset(tmpstr2, 0, slen2); + silc_free(tmpstr1); + silc_free(tmpstr2); + return FALSE; } -/* Decodes PEM into data. Returns the decoded data. */ +/* Splits a string containing separator `ch' and returns an array of the + splitted strings. */ -unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len, - SilcUInt32 *ret_len) +char **silc_string_split(const char *string, char ch, int *ret_count) { - int i, j; - SilcUInt32 len, c, char_count, bits; - unsigned char *data; - static char ialpha[256], decoder[256]; - - for (i = 64 - 1; i >= 0; i--) { - ialpha[pem_enc[i]] = 1; - decoder[pem_enc[i]] = i; - } + char **splitted = NULL, sep[2], *item, *cp; + int i = 0, len; - char_count = 0; - bits = 0; - j = 0; - - if (!pem_len) - len = strlen(pem); - else - len = pem_len; + if (!string || !ret_count) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return NULL; + } - data = silc_calloc(((len * 6) / 8), sizeof(*data)); + splitted = silc_calloc(1, sizeof(*splitted)); + if (!splitted) + return NULL; - for (i = 0; i < len; i++) { - c = pem[i]; + if (!strchr(string, ch)) { + splitted[0] = silc_memdup(string, strlen(string)); + *ret_count = 1; + return splitted; + } - if (c == '=') + sep[0] = ch; + sep[1] = '\0'; + cp = (char *)string; + while (cp) { + len = strcspn(cp, sep); + if (!len) break; - if (c > 127 || !ialpha[c]) - continue; - - bits += decoder[c]; - char_count++; - - if (char_count == 4) { - data[j++] = bits >> 16; - data[j++] = (bits >> 8) & 0xff; - data[j++] = bits & 0xff; - bits = 0; - char_count = 0; - } else { - bits <<= 6; + item = silc_memdup(cp, len); + if (!item) { + silc_free(splitted); + return NULL; } - } - switch(char_count) { - case 1: - silc_free(data); - return NULL; - break; - case 2: - data[j++] = bits >> 10; - break; - case 3: - data[j++] = bits >> 16; - data[j++] = (bits >> 8) & 0xff; - break; - } - - if (ret_len) - *ret_len = j; + cp += len; + if (strlen(cp) == 0) + cp = NULL; + else + cp++; - return data; -} + splitted[i++] = item; -/* Mime constants and macros */ -#define MIME_VERSION "MIME-Version: " -#define MIME_VERSION_LEN 14 -#define MIME_CONTENT_TYPE "Content-Type: " -#define MIME_CONTENT_TYPE_LEN 14 -#define MIME_TRANSFER_ENCODING "Content-Transfer-Encoding: " -#define MIME_TRANSFER_ENCODING_LEN 27 - -#define MIME_GET_FIELD(mime, mime_len, field, field_len, \ - dest, dest_size) \ -do { \ - 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. */ - -SilcBool -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; - unsigned char *tmp; - - /* 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') || - (mime_len >= i + 2 && - mime[i ] == '\n' && mime[i + 1] == '\n')) - break; + if (cp) { + splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted)); + if (!splitted) + return NULL; + } } - if (i >= mime_len) - return FALSE; - - if (mime_data_ptr) - *mime_data_ptr = (unsigned char *)mime + i + - (mime[i] == '\n' ? 2 : 4); - if (mime_data_len) - *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; + *ret_count = i; - /* Get MIME version, Content-Type and Transfer Encoding fields */ - MIME_GET_FIELD(mime, mime_len, - MIME_VERSION, MIME_VERSION_LEN, - version, version_size); - MIME_GET_FIELD(mime, mime_len, - MIME_CONTENT_TYPE, MIME_CONTENT_TYPE_LEN, - content_type, content_type_size); - MIME_GET_FIELD(mime, mime_len, - MIME_TRANSFER_ENCODING, MIME_TRANSFER_ENCODING_LEN, - transfer_encoding, transfer_encoding_size); - - return TRUE; + return splitted; } -/* 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. */ +/* Inspects the `string' for wildcards and returns regex string that can + be used by the GNU regex library. A comma (`,') in the `string' means + that the string is list. */ -char *silc_strncat(char *dest, SilcUInt32 dest_size, - const char *src, SilcUInt32 src_len) +char *silc_string_regexify(const char *string) { - int len; + int i, len, count; + char *regex; - 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); + if (!string) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return NULL; } - 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; + len = strlen(string); + count = 4; + for (i = 0; i < len; i++) { + if (string[i] == '*' || string[i] == '?') + count++; /* Will add '.' */ + if (string[i] == ',') + count += 2; /* Will add '|' and '^' */ + } - if (!identifier || !identifier_len) + regex = silc_calloc(len + count + 1, sizeof(*regex)); + if (!regex) return NULL; - if (max_allowed_length && identifier_len > max_allowed_length) - return NULL; + count = 0; + regex[count++] = '('; + regex[count++] = '^'; - 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; + for (i = 0; i < len; i++) { + if (string[i] == '*' || string[i] == '?') { + regex[count] = '.'; + count++; + } else if (string[i] == ',') { + if (i + 2 == len) + continue; + regex[count++] = '|'; + regex[count++] = '^'; + continue; + } + + regex[count++] = string[i]; } - if (out_len) - *out_len = utf8s_len; + regex[count++] = ')'; + regex[count] = '$'; - return utf8s; + return regex; } -/* Same as above but does not allocate memory, just checks the - validity of the string. */ - -SilcBool 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; -} +/* Combines two regex strings into one regex string so that they can be + used as one by the GNU regex library. The `string2' is combine into + the `string1'. */ -unsigned char *silc_channel_name_check(const unsigned char *identifier, - SilcUInt32 identifier_len, - SilcStringEncoding identifier_encoding, - SilcUInt32 max_allowed_length, - SilcUInt32 *out_len) +char *silc_string_regex_combine(const char *string1, const char *string2) { - unsigned char *utf8s; - SilcUInt32 utf8s_len; - SilcStringprepStatus status; - - if (!identifier || !identifier_len) - return NULL; + char *tmp; + int len1, len2; - 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)); + if (!string1 || !string2) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return NULL; } - if (out_len) - *out_len = utf8s_len; + len1 = strlen(string1); + len2 = strlen(string2); + + tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp)); + strncat(tmp, string1, len1 - 2); + strncat(tmp, "|", 1); + strncat(tmp, string2 + 1, len2 - 1); - return utf8s; + return tmp; } -/* Same as above but does not allocate memory, just checks the - validity of the string. */ +/* Do regex match to the two strings `string1' and `string2'. If the + `string2' matches the `string1' this returns TRUE. */ -SilcBool silc_channel_name_verify(const unsigned char *identifier, - SilcUInt32 identifier_len, - SilcStringEncoding identifier_encoding, - SilcUInt32 max_allowed_length) +int silc_string_match(const char *string1, const char *string2) { - SilcStringprepStatus status; + char *s1; + int ret = FALSE; - 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; + if (!string1 || !string2) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return ret; } - return TRUE; + s1 = silc_string_regexify(string1); + ret = silc_string_regex_match(s1, string2); + silc_free(s1); + + return ret; }