X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcstrutil.c;h=3251c2b0a4d47c43255ca71746e17cf899ffedb4;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=348bdae052d61c0cde727b357c04142433b32bb9;hpb=ed985c018fe74ee5c1723a3e20083002b77dc3ba;p=silc.git diff --git a/lib/silcutil/silcstrutil.c b/lib/silcutil/silcstrutil.c index 348bdae0..3251c2b0 100644 --- a/lib/silcutil/silcstrutil.c +++ b/lib/silcutil/silcstrutil.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002 - 2006 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 @@ -21,293 +21,250 @@ #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] = '?'; + } } + } - pem2[i] = pem[j++]; + /* if using *, remove it */ + if (strchr(tmpstr1, '*')) + *strchr(tmpstr1, '*') = 0; + + 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; + + if (!string || !ret_count) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return NULL; } - char_count = 0; - bits = 0; - j = 0; + splitted = silc_calloc(1, sizeof(*splitted)); + if (!splitted) + return NULL; - if (!pem_len) - len = strlen(pem); - else - len = pem_len; + if (!strchr(string, ch)) { + splitted[0] = silc_memdup(string, strlen(string)); + *ret_count = 1; + return splitted; + } - data = silc_calloc(((len * 6) / 8), sizeof(*data)); + sep[0] = ch; + sep[1] = '\0'; + cp = (char *)string; + while (cp) { + len = strcspn(cp, sep); + if (!len) + break; - for (i = 0; i < len; i++) { - c = pem[i]; + item = silc_memdup(cp, len); + if (!item) { + silc_free(splitted); + return NULL; + } - if (c == '=') - break; + cp += len; + if (strlen(cp) == 0) + cp = NULL; + else + cp++; - if (c > 127 || !ialpha[c]) - continue; + splitted[i++] = item; - 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; + if (cp) { + splitted = silc_realloc(splitted, (i + 1) * sizeof(*splitted)); + if (!splitted) + return NULL; } } + *ret_count = i; - 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; - - return data; + 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; - - dest[dest_size - 1] = '\0'; + int i, len, count; + char *regex; - 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. */ +/* 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'. */ -SilcBool silc_identifier_verify(const unsigned char *identifier, - SilcUInt32 identifier_len, - SilcStringEncoding identifier_encoding, - SilcUInt32 max_allowed_length) +char *silc_string_regex_combine(const char *string1, const char *string2) { - SilcStringprepStatus status; + char *tmp; + int len1, len2; - 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)); + 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; }