X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcutil.c;h=c61e70ce4836026c38789cdefc2250c1f192ee53;hb=8556fb525f0f1cb2e9cdffebb96f942bd077f51b;hp=2907f2cccdff8c3f2b08cdbe9952ad920d3b831e;hpb=c85af59be50a5539cb2fd0c80cb4700feab37e4e;p=silc.git diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index 2907f2cc..c61e70ce 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -25,54 +25,42 @@ #include "silcincludes.h" -/* Reads a file to a buffer. The allocated buffer is returned. Length of - the file read is returned to the return_len argument. */ +/* Opens a file indicated by the filename `filename' with flags indicated + by the `flags'. */ -char *silc_file_read(const char *filename, uint32 *return_len) +int silc_file_open(const char *filename, int flags) { int fd; - char *buffer; - int filelen; - fd = open(filename, O_RDONLY); - if (fd < 0) { - SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); - return NULL; - } + fd = open(filename, flags, 0600); - filelen = lseek(fd, (off_t)0L, SEEK_END); - if (filelen < 0) - return NULL; - if (lseek(fd, (off_t)0L, SEEK_SET) < 0) - return NULL; + return fd; +} - if (filelen < 0) { - SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); - return NULL; - } - - buffer = silc_calloc(filelen + 1, sizeof(char)); - - if ((read(fd, buffer, filelen)) == -1) { - memset(buffer, 0, sizeof(buffer)); - close(fd); - SILC_LOG_ERROR(("Cannot read from file %s: %s", filename, - strerror(errno))); - return NULL; - } +/* Reads data from file descriptor `fd' to `buf'. */ - close(fd); - buffer[filelen] = EOF; +int silc_file_read(int fd, unsigned char *buf, uint32 buf_len) +{ + return read(fd, (void *)buf, buf_len); +} - if (return_len) - *return_len = filelen; +/* Writes `buffer' of length of `len' to file descriptor `fd. */ - return buffer; +int silc_file_write(int fd, const char *buffer, uint32 len) +{ + return write(fd, (const void *)buffer, len); +} + +/* Closes file descriptor */ + +int silc_file_close(int fd) +{ + return close(fd); } /* Writes a buffer to the file. */ -int silc_file_write(const char *filename, const char *buffer, uint32 len) +int silc_file_writefile(const char *filename, const char *buffer, uint32 len) { int fd; @@ -84,6 +72,7 @@ int silc_file_write(const char *filename, const char *buffer, uint32 len) if ((write(fd, buffer, len)) == -1) { SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno))); + close(fd); return -1; } @@ -95,8 +84,8 @@ int silc_file_write(const char *filename, const char *buffer, uint32 len) /* Writes a buffer to the file. If the file is created specific mode is set to the file. */ -int silc_file_write_mode(const char *filename, const char *buffer, - uint32 len, int mode) +int silc_file_writefile_mode(const char *filename, const char *buffer, + uint32 len, int mode) { int fd; @@ -108,6 +97,7 @@ int silc_file_write_mode(const char *filename, const char *buffer, if ((write(fd, buffer, len)) == -1) { SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno))); + close(fd); return -1; } @@ -116,6 +106,76 @@ int silc_file_write_mode(const char *filename, const char *buffer, return 0; } +/* Reads a file to a buffer. The allocated buffer is returned. Length of + the file read is returned to the return_len argument. */ + +char *silc_file_readfile(const char *filename, uint32 *return_len) +{ + int fd; + char *buffer; + int filelen; + + fd = silc_file_open(filename, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + return NULL; + SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); + return NULL; + } + + filelen = lseek(fd, (off_t)0L, SEEK_END); + if (filelen < 0) { + close(fd); + return NULL; + } + if (lseek(fd, (off_t)0L, SEEK_SET) < 0) { + close(fd); + return NULL; + } + + if (filelen < 0) { + SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); + close(fd); + return NULL; + } + + buffer = silc_calloc(filelen + 1, sizeof(char)); + + if ((read(fd, buffer, filelen)) == -1) { + memset(buffer, 0, sizeof(buffer)); + close(fd); + SILC_LOG_ERROR(("Cannot read from file %s: %s", filename, + strerror(errno))); + return NULL; + } + + close(fd); + buffer[filelen] = EOF; + + if (return_len) + *return_len = filelen; + + return buffer; +} + +/* Returns files size. Returns 0 on error. */ + +uint64 silc_file_size(const char *filename) +{ + int ret; + struct stat stats; + +#ifndef SILC_WIN32 + ret = lstat(filename, &stats); +#else + ret = stat(filename, &stats); +#endif + if (ret < 0) + return 0; + + return (uint64)stats.st_size; +} + /* Gets line from a buffer. Stops reading when a newline or EOF occurs. This doesn't remove the newline sign from the destination buffer. The argument begin is returned and should be passed again for the function. */ @@ -348,49 +408,30 @@ unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len, return data; } -/* Parse nickname string. The format may be !@ to - support multiple same nicknames. The is the final unifier if same - nickname is on same server. Note, this is only local format and server - does not know anything about these. */ +/* Parse userfqdn string which is in user@fqdn format */ -int silc_parse_nickname(char *string, char **nickname, char **server, - uint32 *num) +bool silc_parse_userfqdn(const char *string, char **left, char **right) { uint32 tlen; - char tmp[256]; if (!string) return FALSE; - if (strchr(string, '!')) { - tlen = strcspn(string, "!"); - memset(tmp, 0, sizeof(tmp)); - memcpy(tmp, string, tlen); - - if (num) - *num = atoi(tmp); - - if (tlen >= strlen(string)) - return FALSE; - - string += tlen + 1; - } - if (strchr(string, '@')) { tlen = strcspn(string, "@"); - if (nickname) { - *nickname = silc_calloc(tlen + 1, sizeof(char)); - memcpy(*nickname, string, tlen); + if (left) { + *left = silc_calloc(tlen + 1, sizeof(char)); + memcpy(*left, string, tlen); } - if (server) { - *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char)); - memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1); + if (right) { + *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char)); + memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1); } } else { - if (nickname) - *nickname = strdup(string); + if (left) + *left = strdup(string); } return TRUE; @@ -411,15 +452,21 @@ void silc_parse_command_line(unsigned char *buffer, int i, len = 0; int argc = 0; const char *cp = buffer; + char *tmp; *parsed = silc_calloc(1, sizeof(**parsed)); *parsed_lens = silc_calloc(1, sizeof(**parsed_lens)); /* Get the command first */ len = strcspn(cp, " "); - (*parsed)[0] = silc_to_upper((char *)cp); + tmp = silc_to_upper((char *)cp); + (*parsed)[0] = silc_calloc(len + 1, sizeof(char)); + memcpy((*parsed)[0], tmp, len); + silc_free(tmp); (*parsed_lens)[0] = len; - cp += len + 1; + cp += len; + while (*cp == ' ') + cp++; argc++; /* Parse arguments */ @@ -430,6 +477,10 @@ void silc_parse_command_line(unsigned char *buffer, len = strcspn(cp, " "); else len = strlen(cp); + while (len && cp[len - 1] == ' ') + len--; + if (!len) + break; *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1)); *parsed_lens = silc_realloc(*parsed_lens, @@ -443,7 +494,8 @@ void silc_parse_command_line(unsigned char *buffer, if (strlen(cp) == 0) break; else - cp++; + while (*cp == ' ') + cp++; } } @@ -623,148 +675,232 @@ int silc_string_compare(char *string1, char *string2) return FALSE; } -/* 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. */ +/* Basic has function to hash strings. May be used with the SilcHashTable. + Note that this lowers the characters of the string (with tolower()) so + this is used usually with nicknames, channel and server names to provide + case insensitive keys. */ -char *silc_string_regexify(const char *string) +uint32 silc_hash_string(void *key, void *user_context) { - int i, len, count; - char *regex; + char *s = (char *)key; + uint32 h = 0, g; + + while (*s != '\0') { + h = (h << 4) + tolower(*s); + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + s++; + } + + return h; +} - len = strlen(string); - count = 4; - for (i = 0; i < len; i++) - if (string[i] == '*' || string[i] == '?') - count++; +/* Basic hash function to hash integers. May be used with the SilcHashTable. */ - regex = silc_calloc(len + count, sizeof(*regex)); +uint32 silc_hash_uint(void *key, void *user_context) +{ + return *(uint32 *)key; +} - count = 0; - regex[count] = '('; - count++; +/* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */ - for (i = 0; i < len; i++) { - if (string[i] == '*' || string[i] == '?') { - regex[count] = '.'; - count++; - } else if (string[i] == ',') { - regex[count] = '|'; - count++; - continue; - } +uint32 silc_hash_ptr(void *key, void *user_context) +{ + return (uint32)key; +} - regex[count] = string[i]; - count++; - } +/* Hash a ID. The `user_context' is the ID type. */ - regex[count - 1] = ')'; - regex[count] = '$'; +uint32 silc_hash_id(void *key, void *user_context) +{ + SilcIdType id_type = (SilcIdType)(uint32)user_context; + uint32 h = 0; + int i; + + switch (id_type) { + case SILC_ID_CLIENT: + { + SilcClientID *id = (SilcClientID *)key; + uint32 g; + + /* The client ID is hashed by hashing the hash of the ID + (which is a truncated MD5 hash of the nickname) so that we + can access the entry from the cache with both Client ID but + with just a hash from the ID as well. */ + + for (i = 0; i < sizeof(id->hash); i++) { + h = (h << 4) + id->hash[i]; + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return h; + } + break; + case SILC_ID_SERVER: + { + SilcServerID *id = (SilcServerID *)key; + + h = id->port * id->rnd; + for (i = 0; i < id->ip.data_len; i++) + h ^= id->ip.data[i]; + + return h; + } + break; + case SILC_ID_CHANNEL: + { + SilcChannelID *id = (SilcChannelID *)key; + + h = id->port * id->rnd; + for (i = 0; i < id->ip.data_len; i++) + h ^= id->ip.data[i]; + + return h; + } + break; + default: + break; + } - return regex; + return h; } -/* 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'. */ +/* Hash binary data. The `user_context' is the data length. */ -char *silc_string_regex_combine(const char *string1, const char *string2) +uint32 silc_hash_data(void *key, void *user_context) { - char *tmp; - int len1, len2; + uint32 len = (uint32)user_context, h = 0; + unsigned char *data = (unsigned char *)key; + int i; + + h = (data[0] * data[len - 1] + 1) * len; + for (i = 0; i < len; i++) + h ^= data[i]; - len1 = strlen(string1); - len2 = strlen(string2); + return h; +} - tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp)); - strncat(tmp, string1, len1 - 2); - strncat(tmp, "|", 1); - strncat(tmp, string2 + 1, len2 - 1); +/* Compares two strings. May be used as SilcHashTable comparison function. */ - return tmp; +bool silc_hash_string_compare(void *key1, void *key2, void *user_context) +{ + return !strcasecmp((char *)key1, (char *)key2); } -/* Matches the two strings and returns TRUE if the strings match. */ +/* Compares two ID's. May be used as SilcHashTable comparison function. + The Client ID's compares only the hash of the Client ID not any other + part of the Client ID. Other ID's are fully compared. */ -int silc_string_regex_match(const char *regex, const char *string) +bool silc_hash_id_compare(void *key1, void *key2, void *user_context) { - regex_t preg; - int ret = FALSE; - - if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0) - return FALSE; + SilcIdType id_type = (SilcIdType)(uint32)user_context; + return (id_type == SILC_ID_CLIENT ? + SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) : + SILC_ID_COMPARE_TYPE(key1, key2, id_type)); +} - if (regexec(&preg, string, 0, NULL, 0) == 0) - ret = TRUE; +/* Compare two Client ID's entirely and not just the hash from the ID. */ - regfree(&preg); +bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context) +{ + return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT); +} - return ret; +/* Compares binary data. May be used as SilcHashTable comparison function. */ + +bool silc_hash_data_compare(void *key1, void *key2, void *user_context) +{ + uint32 len = (uint32)user_context; + return !memcmp(key1, key2, len); } -/* Do regex match to the two strings `string1' and `string2'. If the - `string2' matches the `string1' this returns TRUE. */ +/* Parses mode mask and returns the mode as string. */ -int silc_string_match(const char *string1, const char *string2) +char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac) { - char *s1; - int ret = FALSE; + char string[100]; - s1 = silc_string_regexify(string1); - ret = silc_string_regex_match(s1, string2); - silc_free(s1); + if (!mode) + return NULL; - return ret; + memset(string, 0, sizeof(string)); + + if (mode & SILC_CHANNEL_MODE_PRIVATE) + strncat(string, "p", 1); + + if (mode & SILC_CHANNEL_MODE_SECRET) + strncat(string, "s", 1); + + if (mode & SILC_CHANNEL_MODE_PRIVKEY) + strncat(string, "k", 1); + + if (mode & SILC_CHANNEL_MODE_INVITE) + strncat(string, "i", 1); + + if (mode & SILC_CHANNEL_MODE_TOPIC) + strncat(string, "t", 1); + + if (mode & SILC_CHANNEL_MODE_ULIMIT) + strncat(string, "l", 1); + + if (mode & SILC_CHANNEL_MODE_PASSPHRASE) + strncat(string, "a", 1); + + if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) + strncat(string, "f", 1); + + if (mode & SILC_CHANNEL_MODE_CIPHER) + strncat(string, cipher, strlen(cipher)); + + if (mode & SILC_CHANNEL_MODE_HMAC) + strncat(string, hmac, strlen(hmac)); + + /* Rest of mode is ignored */ + + return strdup(string); } -/* Returns the username of the user. If the global variable LOGNAME - does not exists we will get the name from the password file. */ +/* Parses channel user mode mask and returns te mode as string */ -char *silc_get_username() +char *silc_client_chumode(uint32 mode) { - char *logname = NULL; - - if (!getenv("LOGNAME")) { - fprintf(stderr, "Error: environment variable $LOGNAME not set\n"); + char string[4]; + + if (!mode) return NULL; - } - logname = strdup(getenv("LOGNAME")); - if (!logname) { - logname = getlogin(); - if (!logname) { - struct passwd *pw; + memset(string, 0, sizeof(string)); - pw = getpwuid(getuid()); - if (!pw) { - fprintf(stderr, "silc_get_username: %s\n", strerror(errno)); - return NULL; - } - - logname = strdup(pw->pw_name); - } - } - - return logname; -} + if (mode & SILC_CHANNEL_UMODE_CHANFO) + strncat(string, "f", 1); + + if (mode & SILC_CHANNEL_UMODE_CHANOP) + strncat(string, "o", 1); -/* Returns the real name of ther user. */ + return strdup(string); +} -char *silc_get_real_name() +/* Parses channel user mode and returns it as special mode character. */ + +char *silc_client_chumode_char(uint32 mode) { - char *realname = NULL; - struct passwd *pw; - - pw = getpwuid(getuid()); - if (!pw) { - fprintf(stderr, "silc_get_username: %s\n", strerror(errno)); + char string[4]; + + if (!mode) return NULL; - } - if (strchr(pw->pw_gecos, ',')) - *strchr(pw->pw_gecos, ',') = 0; + memset(string, 0, sizeof(string)); + + if (mode & SILC_CHANNEL_UMODE_CHANFO) + strncat(string, "*", 1); - realname = strdup(pw->pw_gecos); + if (mode & SILC_CHANNEL_UMODE_CHANOP) + strncat(string, "@", 1); - return realname; + return strdup(string); }