X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcutil.c;h=a3746f92ff8bf9f745c731cc17f99bfae5bdfb97;hb=c257b555225193e54d85daf541d29578b3c93882;hp=4ac00f38363803b05857ee774b61ef0a8cb3af86;hpb=c08107c80b816558a1c48ada27eaf23840793157;p=silc.git diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c index 4ac00f38..a3746f92 100644 --- a/lib/silcutil/silcutil.c +++ b/lib/silcutil/silcutil.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 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 @@ -78,31 +78,53 @@ int silc_check_line(char *buf) return 0; } -/* Returns current time as string. */ +/* Returns time as string. If the the `timeval' is non-zero that + value is returned as string. If it is zero the current time of the + local machine is returned. */ -char *silc_get_time() +const char *silc_get_time(SilcUInt32 timeval) { time_t curtime; char *return_time; - curtime = time(NULL); + if (!timeval) + curtime = time(NULL); + else + curtime = (time_t)timeval; return_time = ctime(&curtime); return_time[strlen(return_time) - 1] = '\0'; - return return_time; + return (const char *)return_time; } /* Converts string to capital characters. */ -char *silc_to_upper(char *string) +bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size) { int i; - char *ret = silc_calloc(strlen(string) + 1, sizeof(char)); + + if (strlen(string) > dest_size) + return FALSE; for (i = 0; i < strlen(string); i++) - ret[i] = toupper(string[i]); + dest[i] = toupper(string[i]); - return ret; + return TRUE; +} + +/* Converts string to lower letter characters. */ + +bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size) +{ + int i; + + if (strlen(string) > dest_size) + return FALSE; + + for (i = 0; i < strlen(string); i++) + dest[i] = tolower(string[i]); + + return TRUE; } /* Parse userfqdn string which is in user@fqdn format. */ @@ -134,7 +156,7 @@ bool silc_parse_userfqdn(const char *string, char **left, char **right) } } else { if (left) - *left = strdup(string); + *left = silc_memdup(string, strlen(string)); } return TRUE; @@ -162,7 +184,10 @@ void silc_parse_command_line(unsigned char *buffer, /* Get the command first */ len = strcspn(cp, " "); - tmp = silc_to_upper((char *)cp); + tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp)); + if (!tmp) + return; + silc_to_upper(cp, tmp, strlen(cp)); (*parsed)[0] = silc_calloc(len + 1, sizeof(char)); memcpy((*parsed)[0], tmp, len); silc_free(tmp); @@ -364,7 +389,7 @@ int silc_string_compare(char *string1, char *string2) slen2 = strlen(string2); /* See if they are same already */ - if (!strncmp(string1, string2, strlen(string2))) + if (!strncmp(string1, string2, slen2) && slen2 == slen1) return TRUE; if (slen2 < slen1) @@ -442,6 +467,25 @@ SilcUInt32 silc_hash_string(void *key, void *user_context) return h; } +/* Hash UTF-8 string */ + +SilcUInt32 silc_hash_utf8_string(void *key, void *user_context) +{ + unsigned char *s = (unsigned char *)key; + SilcUInt32 h = 0, g; + + while (*s != '\0') { + h = (h << 4) + *s; + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + s++; + } + + return h; +} + /* Basic hash function to hash integers. May be used with the SilcHashTable. */ SilcUInt32 silc_hash_uint(void *key, void *user_context) @@ -453,14 +497,14 @@ SilcUInt32 silc_hash_uint(void *key, void *user_context) SilcUInt32 silc_hash_ptr(void *key, void *user_context) { - return (SilcUInt32)key; + return SILC_PTR_TO_32(key); } /* Hash a ID. The `user_context' is the ID type. */ SilcUInt32 silc_hash_id(void *key, void *user_context) { - SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context; + SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context); SilcUInt32 h = 0; int i; @@ -468,22 +512,12 @@ SilcUInt32 silc_hash_id(void *key, void *user_context) case SILC_ID_CLIENT: { SilcClientID *id = (SilcClientID *)key; - SilcUInt32 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; + return silc_hash_client_id_hash(id->hash, NULL); } break; case SILC_ID_SERVER: @@ -515,11 +549,30 @@ SilcUInt32 silc_hash_id(void *key, void *user_context) return h; } +/* Hash Client ID's hash. */ + +SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context) +{ + int i; + unsigned char *hash = key; + SilcUInt32 h = 0, g; + + for (i = 0; i < CLIENTID_HASH_LEN; i++) { + h = (h << 4) + hash[i]; + if ((g = h & 0xf0000000)) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return h; +} + /* Hash binary data. The `user_context' is the data length. */ SilcUInt32 silc_hash_data(void *key, void *user_context) { - SilcUInt32 len = (SilcUInt32)user_context, h = 0; + SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0; unsigned char *data = (unsigned char *)key; int i; @@ -535,9 +588,9 @@ SilcUInt32 silc_hash_data(void *key, void *user_context) SilcUInt32 silc_hash_public_key(void *key, void *user_context) { SilcPublicKey pk = (SilcPublicKey)key; - return (pk->len + silc_hash_string(pk->name, NULL) + - silc_hash_string(pk->identifier, NULL) + - silc_hash_data(pk->pk, (void *)pk->pk_len)); + return (pk->len + (silc_hash_string(pk->name, NULL) ^ + silc_hash_string(pk->identifier, NULL) ^ + silc_hash_data(pk->pk, SILC_32_TO_PTR(pk->pk_len)))); } /* Compares two strings. It may be used as SilcHashTable comparison @@ -554,7 +607,7 @@ bool silc_hash_string_compare(void *key1, void *key2, void *user_context) bool silc_hash_id_compare(void *key1, void *key2, void *user_context) { - SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context; + SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context); return (id_type == SILC_ID_CLIENT ? SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) : SILC_ID_COMPARE_TYPE(key1, key2, id_type)); @@ -571,10 +624,21 @@ bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context) bool silc_hash_data_compare(void *key1, void *key2, void *user_context) { - SilcUInt32 len = (SilcUInt32)user_context; + SilcUInt32 len = SILC_PTR_TO_32(user_context); return !memcmp(key1, key2, len); } +/* Compares UTF-8 string. */ + +bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context) +{ + int l1 = strlen((char *)key1); + int l2 = strlen((char *)key2); + if (l1 > l2) + l2 = l1; + return !memcmp(key1, key2, l2); +} + /* Compares two SILC Public keys. It may be used as SilcHashTable comparison function. */ @@ -618,6 +682,9 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac) if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) strncat(string, "f", 1); + if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) + strncat(string, "C", 1); + if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) strncat(string, "m", 1); @@ -625,10 +692,24 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac) strncat(string, "M", 1); if (mode & SILC_CHANNEL_MODE_CIPHER) - strncat(string, cipher, strlen(cipher)); + strncat(string, "c", 1); if (mode & SILC_CHANNEL_MODE_HMAC) - strncat(string, hmac, strlen(hmac)); + strncat(string, "h", 1); + + if (mode & SILC_CHANNEL_MODE_CIPHER) { + if (strlen(cipher) + strlen(string) + 1< sizeof(string)) { + strncat(string, " ", 1); + strncat(string, cipher, strlen(cipher)); + } + } + + if (mode & SILC_CHANNEL_MODE_HMAC) { + if (strlen(hmac) + strlen(string) + 1< sizeof(string)) { + strncat(string, " ", 1); + strncat(string, hmac, strlen(hmac)); + } + } /* Rest of mode is ignored */ @@ -639,7 +720,7 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac) char *silc_client_chumode(SilcUInt32 mode) { - char string[4]; + char string[64]; if (!mode) return NULL; @@ -655,6 +736,15 @@ char *silc_client_chumode(SilcUInt32 mode) if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES) strncat(string, "b", 1); + if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS) + strncat(string, "u", 1); + + if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS) + strncat(string, "r", 1); + + if (mode & SILC_CHANNEL_UMODE_QUIET) + strncat(string, "q", 1); + return strdup(string); } @@ -662,7 +752,7 @@ char *silc_client_chumode(SilcUInt32 mode) char *silc_client_chumode_char(SilcUInt32 mode) { - char string[4]; + char string[64]; if (!mode) return NULL; @@ -675,6 +765,9 @@ char *silc_client_chumode_char(SilcUInt32 mode) if (mode & SILC_CHANNEL_UMODE_CHANOP) strncat(string, "@", 1); + if (mode & SILC_CHANNEL_UMODE_QUIET) + strncat(string, "&", 1); + return strdup(string); } @@ -742,11 +835,12 @@ bool silc_parse_version_string(const char *version, /* Take protocol version */ maj = atoi(cp); - cp = strchr(cp, '.'); - if (cp) { - min = atoi(cp + 1); - cp++; - } + if (!strchr(cp, '.')) + return FALSE; + cp = strchr(cp, '.') + 1; + if (!cp || !(*cp)) + return FALSE; + min = atoi(cp); memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min); @@ -761,14 +855,18 @@ bool silc_parse_version_string(const char *version, maj = 0; min = 0; - cp = strchr(cp, '-'); - if (!cp) + if (!strchr(cp, '-')) + return FALSE; + cp = strchr(cp, '-') + 1; + if (!cp || !(*cp)) return FALSE; - maj = atoi(cp + 1); - cp = strchr(cp, '.'); - if (cp) - min = atoi(cp + 1); + maj = atoi(cp); + if (strchr(cp, '.')) { + cp = strchr(cp, '.') + 1; + if (cp && *cp) + min = atoi(cp); + } memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min); @@ -781,11 +879,10 @@ bool silc_parse_version_string(const char *version, /* Take vendor string */ - cp++; - if (cp) { - cp = strchr(cp, '.'); - if (cp && cp + 1 && vendor_version) - *vendor_version = strdup(cp + 1); + if (strchr(cp, '.')) { + cp = strchr(cp, '.') + 1; + if (cp && *cp && vendor_version) + *vendor_version = strdup(cp); } return TRUE; @@ -817,11 +914,12 @@ SilcUInt32 silc_version_to_num(const char *version) char *silc_get_input(const char *prompt, bool echo_off) { #ifdef SILC_UNIX + int fd; + char input[2048]; + if (echo_off) { char *ret = NULL; #ifdef HAVE_TERMIOS_H - char input[2048]; - int fd; struct termios to; struct termios to_old; @@ -837,8 +935,10 @@ char *silc_get_input(const char *prompt, bool echo_off) tcgetattr(fd, &to); to_old = to; - /* Echo OFF */ + /* Echo OFF, and assure we can prompt and get input */ to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + to.c_lflag |= ICANON; + to.c_cc[VMIN] = 255; tcsetattr(fd, TCSANOW, &to); memset(input, 0, sizeof(input)); @@ -848,6 +948,7 @@ char *silc_get_input(const char *prompt, bool echo_off) if ((read(fd, input, sizeof(input))) < 0) { fprintf(stderr, "silc: %s\n", strerror(errno)); + tcsetattr(fd, TCSANOW, &to_old); return NULL; } @@ -863,15 +964,11 @@ char *silc_get_input(const char *prompt, bool echo_off) tcsetattr(fd, TCSANOW, &to_old); signal(SIGINT, SIG_DFL); - ret = silc_calloc(strlen(input), sizeof(char)); - memcpy(ret, input, strlen(input)); + ret = silc_memdup(input, strlen(input)); memset(input, 0, sizeof(input)); #endif /* HAVE_TERMIOS_H */ return ret; } else { - char input[2048]; - int fd; - fd = open("/dev/tty", O_RDONLY); if (fd < 0) { fprintf(stderr, "silc: %s\n", strerror(errno)); @@ -900,3 +997,206 @@ char *silc_get_input(const char *prompt, bool echo_off) return NULL; #endif /* SILC_UNIX */ } + +/* Return mode list */ + +bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count, + SilcUInt32 **list) +{ + int i; + + if (mode_list->len / 4 != mode_list_count) + return FALSE; + + *list = silc_calloc(mode_list_count, sizeof(**list)); + + for (i = 0; i < mode_list_count; i++) { + SILC_GET32_MSB((*list)[i], mode_list->data); + silc_buffer_pull(mode_list, 4); + } + + silc_buffer_push(mode_list, mode_list->data - mode_list->head); + + return TRUE; +} + +/* Status message structure. Messages are defined below. */ +typedef struct { + SilcStatus status; + const char *message; +} SilcStatusMessage; + +#define STAT(x) SILC_STATUS_ERR_##x +static const SilcStatusMessage silc_status_messages[] = { + + { STAT(NO_SUCH_NICK), "There was no such nickname" }, + { STAT(NO_SUCH_CHANNEL), "There was no such channel" }, + { STAT(NO_SUCH_SERVER), "There was no such server" }, + { STAT(INCOMPLETE_INFORMATION), "Incomplete registration information" }, + { STAT(NO_RECIPIENT), "No recipient given" }, + { STAT(UNKNOWN_COMMAND), "Unknown command" }, + { STAT(WILDCARDS), "Wilcrads not allowed" }, + { STAT(NO_CLIENT_ID), "No Client ID given" }, + { STAT(NO_CHANNEL_ID), "No Channel ID given" }, + { STAT(NO_SERVER_ID), "No Server ID given" }, + { STAT(BAD_CLIENT_ID), "Bad Client ID" }, + { STAT(BAD_CHANNEL_ID), "Bad Channel ID" }, + { STAT(NO_SUCH_CLIENT_ID), "There is no such client" }, + { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" }, + { STAT(NICKNAME_IN_USE), "Nickname already exists" }, + { STAT(NOT_ON_CHANNEL), "You are not on that channel" }, + { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" }, + { STAT(USER_ON_CHANNEL), "User already on the channel" }, + { STAT(NOT_REGISTERED), "You have not registered" }, + { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" }, + { STAT(TOO_MANY_PARAMS), "Too many parameters" }, + { STAT(PERM_DENIED), "Permission denied" }, + { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" }, + { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" }, + { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" }, + { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" }, + { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" }, + { STAT(UNKNOWN_MODE), "Unknown mode" }, + { STAT(NOT_YOU), "Cannot change mode for other users" }, + { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" }, + { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" }, + { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" }, + { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" }, + { STAT(BAD_NICKNAME), "Bad nickname" }, + { STAT(BAD_CHANNEL), "Bad channel name" }, + { STAT(AUTH_FAILED), "Authentication failed" }, + { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" }, + { STAT(NO_SUCH_SERVER_ID), "No such Server ID" }, + { STAT(RESOURCE_LIMIT), "No more free resources" }, + { STAT(NO_SUCH_SERVICE), "Service doesn't exist" }, + { STAT(NOT_AUTHENTICATED), "You have not been authenticated" }, + { STAT(BAD_SERVER_ID), "Server ID is not valid" }, + { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" }, + { STAT(BAD_VERSION), "Bad version" }, + { STAT(TIMEDOUT), "Service timed out" }, + { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" }, + { STAT(OPERATION_ALLOWED), "Operation is not allowed" }, + { STAT(BAD_SERVER), "Bad server name" }, + { STAT(BAD_USERNAME), "Bad user name" }, + + { 0, NULL } +}; + +/* Returns status message string */ + +const char *silc_get_status_message(unsigned char status) +{ + int i; + + for (i = 0; silc_status_messages[i].message; i++) { + if (silc_status_messages[i].status == status) + break; + } + + if (silc_status_messages[i].message == NULL) + return ""; + + return silc_status_messages[i].message; +} + +static const char *packet_name[] = { + "NONE", + "DISCONNECT", + "SUCCESS", + "FAILURE", + "REJECT", + "NOTIFY", + "ERROR", + "CHANNEL MESSAGE", + "CHANNEL KEY", + "PRIVATE MESSAGE", + "PRIVATE MESSAGE KEY", + "COMMAND", + "COMMAND REPLY", + "KEY EXCHANGE", + "KEY EXCHANGE 1", + "KEY EXCHANGE 2", + "CONNECTION AUTH REQUEST", + "CONNECTION AUTH", + "NEW ID", + "NEW CLIENT", + "NEW SERVER", + "NEW CHANNEL", + "REKEY", + "REKEY_DONE", + "HEARTBEAT", + "KEY AGREEMENT", + "RESUME ROUTER", + "FTP", + "RESUME CLIENT", +}; + +/* Returns packet type name */ + +const char *silc_get_packet_name(unsigned char type) +{ + if (type >= SILC_PACKET_MAX) + return "RESERVED"; + if (type >= SILC_PACKET_PRIVATE) + return "PRIVATE RANGE"; + if (type > (sizeof(packet_name) / sizeof(*packet_name))) + return "UNKNOWN"; + return packet_name[type]; +} + +static const char *command_name[] = { + "NONE", + "WHOIS", + "WHOWAS", + "IDENTIFY", + "NICK", + "LIST", + "TOPIC", + "INVITE", + "QUIT", + "KILL", + "INFO", + "STATS", + "PING", + "OPER", + "JOIN", + "MOTD", + "UMODE", + "CMODE", + "CUMODE", + "KICK", + "BAN", + "DETACH", + "WATCH", + "SILCOPER", + "LEAVE", + "USERS", + "GETKEY", + "SERVICE", +}; + +/* Returns command name */ + +const char *silc_get_command_name(unsigned char command) +{ + if (command >= SILC_COMMAND_RESERVED) + return "RESERVED"; + if (command >= SILC_COMMAND_PRIVATE) + return "PRIVATE RANGE"; + if (command > (sizeof(command_name) / sizeof(*command_name))) + return "UNKNOWN"; + return command_name[command]; +} + +/* Return TRUE if `smaller' is smaller than `bigger'. */ + +bool silc_compare_timeval(struct timeval *smaller, + struct timeval *bigger) +{ + if ((smaller->tv_sec < bigger->tv_sec) || + ((smaller->tv_sec == bigger->tv_sec) && + (smaller->tv_usec < bigger->tv_usec))) + return TRUE; + + return FALSE; +}