X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcapputil%2Fsilcapputil.c;h=573d4585e17a9f0ba439658351165effe749702f;hb=1ea936cbf1bb3b19bd55839b904ef59ada84b8b5;hp=fe0ae5400d5e76c3207c63d93b8fc4d48ae6ad4c;hpb=ebfae3bbce6fed0dece516307f537ce5e270e7e0;p=silc.git diff --git a/lib/silcapputil/silcapputil.c b/lib/silcapputil/silcapputil.c index fe0ae540..573d4585 100644 --- a/lib/silcapputil/silcapputil.c +++ b/lib/silcapputil/silcapputil.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 @@ -31,19 +31,23 @@ static char *silc_create_pk_identifier(void) /* Get hostname */ hostname = silc_net_localhost(); - if (!hostname) + if (!hostname) { + fprintf(stderr, "Could not resolve local hostname/IP address"); return NULL; + } /* Get username (mandatory) */ username = silc_get_username(); - if (!username) + if (!username) { + fprintf(stderr, "Could not determine username"); return NULL; + } /* Create default email address, whether it is right or not */ - snprintf(email, sizeof(email), "%s@%s", username, hostname); + silc_snprintf(email, sizeof(email), "%s@%s", username, hostname); - ident = silc_pkcs_silc_encode_identifier(username, hostname, realname, - email, NULL, NULL); + ident = silc_pkcs_silc_encode_identifier(NULL, username, hostname, realname, + email, NULL, NULL, NULL); if (realname) silc_free(realname); silc_free(hostname); @@ -71,6 +75,8 @@ SilcBool silc_create_key_pair(const char *pkcs_name, char *alg = pkcs_name ? strdup(pkcs_name) : NULL; char *identifier = pub_identifier ? strdup(pub_identifier) : NULL; char *pass = passphrase ? strdup(passphrase) : NULL; + SilcPublicKey public_key; + SilcPrivateKey private_key; if (interactive && (!alg || !pub_filename || !prv_filename)) printf("\ @@ -121,9 +127,9 @@ New pair of keys will be created. Please, answer to following questions.\n\ if (interactive) { memset(line, 0, sizeof(line)); if (def) - snprintf(line, sizeof(line), "Identifier [%s]: ", def); + silc_snprintf(line, sizeof(line), "Identifier [%s]: ", def); else - snprintf(line, sizeof(line), + silc_snprintf(line, sizeof(line), "Identifier (eg. UN=jon, HN=jon.dummy.com, " "RN=Jon Johnson, E=jon@dummy.com): "); @@ -134,8 +140,7 @@ New pair of keys will be created. Please, answer to following questions.\n\ } } else { if (!def) { - fprintf(stderr, "Could not create public key identifier: %s\n", - strerror(errno)); + fprintf(stderr, "Could not create public key identifier\n"); return FALSE; } identifier = strdup(def); @@ -144,6 +149,12 @@ New pair of keys will be created. Please, answer to following questions.\n\ silc_free(def); } + if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) { + fprintf(stderr, "Invalid public key identifier. You must specify both " + "UN and HN\n"); + return FALSE; + } + rng = silc_rng_alloc(); silc_rng_init(rng); silc_rng_global_init(rng); @@ -151,7 +162,7 @@ New pair of keys will be created. Please, answer to following questions.\n\ if (!pkfile) { if (interactive) { memset(line, 0, sizeof(line)); - snprintf(line, sizeof(line), "Public key filename [public_key.pub]: "); + silc_snprintf(line, sizeof(line), "Public key filename [public_key.pub]: "); pkfile = silc_get_input(line, FALSE); } if (!pkfile) @@ -161,7 +172,7 @@ New pair of keys will be created. Please, answer to following questions.\n\ if (!prvfile) { if (interactive) { memset(line, 0, sizeof(line)); - snprintf(line, sizeof(line), "Private key filename [private_key.prv]: "); + silc_snprintf(line, sizeof(line), "Private key filename [private_key.prv]: "); prvfile = silc_get_input(line, FALSE); } if (!prvfile) @@ -190,19 +201,34 @@ New pair of keys will be created. Please, answer to following questions.\n\ } } + if (interactive) + printf("\nGenerating the key pair...\n"); + /* Generate keys */ - if (!silc_pkcs_silc_generate_key(alg, "pkcs1-no-oid", key_len_bits, - identifier, rng, return_public_key, - return_private_key)) + if (!silc_pkcs_silc_generate_key(alg, key_len_bits, + identifier, rng, &public_key, + &private_key)) return FALSE; /* Save public key into file */ - silc_pkcs_save_public_key(pkfile, *return_public_key, SILC_PKCS_FILE_BASE64); + if (!silc_pkcs_save_public_key(pkfile, public_key, SILC_PKCS_FILE_BASE64)) + return FALSE; /* Save private key into file */ - silc_pkcs_save_private_key(prvfile, *return_private_key, - (const unsigned char *)pass, strlen(pass), - SILC_PKCS_FILE_BIN, rng); + if (!silc_pkcs_save_private_key(prvfile, private_key, + (const unsigned char *)pass, strlen(pass), + SILC_PKCS_FILE_BIN, rng)) + return FALSE; + + if (return_public_key) + *return_public_key = public_key; + else + silc_pkcs_public_key_free(public_key); + + if (return_private_key) + *return_private_key = private_key; + else + silc_pkcs_private_key_free(private_key); printf("Public key has been saved into `%s'.\n", pkfile); printf("Private key has been saved into `%s'.\n", prvfile); @@ -234,7 +260,8 @@ SilcBool silc_load_key_pair(const char *pub_filename, SILC_LOG_DEBUG(("Loading public and private keys")); - if (!silc_pkcs_load_public_key(pub_filename, return_public_key)) { + if (!silc_pkcs_load_public_key(pub_filename, + SILC_PKCS_ANY, return_public_key)) { if (pass) memset(pass, 0, strlen(pass)); silc_free(pass); @@ -249,7 +276,10 @@ SilcBool silc_load_key_pair(const char *pub_filename, if (!silc_pkcs_load_private_key(prv_filename, (const unsigned char *)pass, strlen(pass), + SILC_PKCS_ANY, return_private_key)) { + silc_pkcs_public_key_free(*return_public_key); + *return_public_key = NULL; memset(pass, 0, strlen(pass)); silc_free(pass); return FALSE; @@ -262,9 +292,8 @@ SilcBool silc_load_key_pair(const char *pub_filename, /* Dump public key into stdout */ -SilcBool silc_show_public_key(const char *pub_filename) +SilcBool silc_show_public_key(SilcPublicKey public_key) { - SilcPublicKey public_key; SilcSILCPublicKey silc_pubkey; SilcPublicKeyIdentifier ident; char *fingerprint, *babbleprint; @@ -272,31 +301,23 @@ SilcBool silc_show_public_key(const char *pub_filename) SilcUInt32 pk_len; SilcUInt32 key_len = 0; - if (!silc_pkcs_load_public_key((char *)pub_filename, &public_key)) { - fprintf(stderr, "Could not load public key file `%s'\n", pub_filename); + silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key); + if (!silc_pubkey) return FALSE; - } - - silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); - if (!silc_pubkey) { - silc_pkcs_public_key_free(public_key); - return FALSE; - } ident = &silc_pubkey->identifier; key_len = silc_pkcs_public_key_get_len(public_key); - pk = silc_pkcs_public_key_encode(public_key, &pk_len); - if (!pk) { - silc_pkcs_public_key_free(public_key); + pk = silc_pkcs_public_key_encode(NULL, public_key, &pk_len); + if (!pk) return FALSE; - } fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); - printf("Public key file : %s\n", pub_filename); printf("Algorithm : %s\n", silc_pkcs_get_name(public_key)); if (key_len) printf("Key length (bits) : %d\n", (unsigned int)key_len); + if (ident->version) + printf("Version : %s\n", ident->version); if (ident->realname) printf("Real name : %s\n", ident->realname); if (ident->username) @@ -317,11 +338,30 @@ SilcBool silc_show_public_key(const char *pub_filename) silc_free(fingerprint); silc_free(babbleprint); silc_free(pk); - silc_pkcs_public_key_free(public_key); return TRUE; } +/* Dump public key into stdout */ + +SilcBool silc_show_public_key_file(const char *pub_filename) +{ + SilcPublicKey public_key; + SilcBool ret; + + if (!silc_pkcs_load_public_key((char *)pub_filename, + SILC_PKCS_ANY, &public_key)) { + fprintf(stderr, "Could not load public key file `%s'\n", pub_filename); + return FALSE; + } + + printf("Public key file : %s\n", pub_filename); + ret = silc_show_public_key(public_key); + silc_pkcs_public_key_free(public_key); + + return ret; +} + /* Change private key passphrase */ SilcBool silc_change_private_key_passphrase(const char *prv_filename, @@ -341,6 +381,7 @@ SilcBool silc_change_private_key_passphrase(const char *prv_filename, if (!silc_pkcs_load_private_key(prv_filename, (const unsigned char *)pass, strlen(pass), + SILC_PKCS_ANY, &private_key)) { memset(pass, 0, strlen(pass)); silc_free(pass); @@ -509,3 +550,498 @@ SilcBool silc_channel_name_verify(const unsigned char *identifier, return TRUE; } + +/* Return mode list */ + +SilcBool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count, + SilcUInt32 **list) +{ + int i; + + if (silc_buffer_len(mode_list) / 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" }, + { STAT(NO_SUCH_PUBLIC_KEY), "Unknown public key" }, + + { 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]; +} + +/* Parses SILC protocol style version string. */ + +SilcBool silc_parse_version_string(const char *version, + SilcUInt32 *protocol_version, + char **protocol_version_string, + SilcUInt32 *software_version, + char **software_version_string, + char **vendor_version) +{ + char *cp, buf[32]; + int maj = 0, min = 0; + + if (!strstr(version, "SILC-")) + return FALSE; + + cp = (char *)version + 5; + if (!cp || !(*cp)) + return FALSE; + + /* Take protocol version */ + + maj = atoi(cp); + if (!strchr(cp, '.')) + return FALSE; + cp = strchr(cp, '.') + 1; + if (!cp || !(*cp)) + return FALSE; + min = atoi(cp); + + memset(buf, 0, sizeof(buf)); + silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min); + if (protocol_version) + *protocol_version = atoi(buf); + memset(buf, 0, sizeof(buf)); + silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min); + if (protocol_version_string) + *protocol_version_string = strdup(buf); + + /* Take software version */ + + maj = 0; + min = 0; + if (!strchr(cp, '-')) + return FALSE; + cp = strchr(cp, '-') + 1; + if (!cp || !(*cp)) + return FALSE; + + maj = atoi(cp); + if (strchr(cp, '.')) { + cp = strchr(cp, '.') + 1; + if (cp && *cp) + min = atoi(cp); + } + + memset(buf, 0, sizeof(buf)); + silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min); + if (software_version) + *software_version = atoi(buf); + memset(buf, 0, sizeof(buf)); + silc_snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min); + if (software_version_string) + *software_version_string = strdup(buf); + + /* Take vendor string */ + + if (strchr(cp, '.')) { + cp = strchr(cp, '.') + 1; + if (cp && *cp && vendor_version) + *vendor_version = strdup(cp); + } else if (strchr(cp, ' ')) { + cp = strchr(cp, ' ') + 1; + if (cp && *cp && vendor_version) + *vendor_version = strdup(cp); + } + + return TRUE; +} + +/* Converts version string x.x into number representation. */ + +SilcUInt32 silc_version_to_num(const char *version) +{ + int maj = 0, min = 0; + char *cp, buf[32]; + + if (!version) + return 0; + + cp = (char *)version; + maj = atoi(cp); + cp = strchr(cp, '.'); + if (cp) + min = atoi(cp + 1); + + memset(buf, 0, sizeof(buf)); + silc_snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min); + return (SilcUInt32)atoi(buf); +} + +/* Parses mode mask and returns the mode as string. */ + +char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac) +{ + char string[100]; + + if (!mode) + return NULL; + + 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_CHANNEL_AUTH) + strncat(string, "C", 1); + + if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) + strncat(string, "m", 1); + + if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) + strncat(string, "M", 1); + + if (mode & SILC_CHANNEL_MODE_CIPHER) + strncat(string, "c", 1); + + if (mode & SILC_CHANNEL_MODE_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 */ + + return strdup(string); +} + +/* Parses channel user mode mask and returns te mode as string */ + +char *silc_client_chumode(SilcUInt32 mode) +{ + char string[64]; + + if (!mode) + return NULL; + + memset(string, 0, sizeof(string)); + + if (mode & SILC_CHANNEL_UMODE_CHANFO) + strncat(string, "f", 1); + + if (mode & SILC_CHANNEL_UMODE_CHANOP) + strncat(string, "o", 1); + + 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); +} + +/* Parses channel user mode and returns it as special mode character. */ + +char *silc_client_chumode_char(SilcUInt32 mode) +{ + char string[64]; + + if (!mode) + return NULL; + + memset(string, 0, sizeof(string)); + + if (mode & SILC_CHANNEL_UMODE_CHANFO) + strncat(string, "*", 1); + + if (mode & SILC_CHANNEL_UMODE_CHANOP) + strncat(string, "@", 1); + + if (mode & SILC_CHANNEL_UMODE_QUIET) + strncat(string, "&", 1); + + return strdup(string); +} + +/* Renders ID to suitable to print for example to log file. */ + +static char rid[256]; +#define _PUT_STRING(__d__, __s__) \ +do { \ + int __sp = sizeof(__d__) - 1 - strlen(__d__); \ + if (__sp < strlen(__s__)) { \ + if (__sp) \ + strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \ + } else { \ + strncat(__d__, __s__, strlen(__s__)); \ + } \ +} while(0) + +char *silc_id_render(void *id, SilcIdType id_type) +{ + char tmp[100]; + unsigned char tmps[2]; + + memset(rid, 0, sizeof(rid)); + switch(id_type) { + case SILC_ID_SERVER: + { + SilcServerID *server_id = (SilcServerID *)id; + + if (!silc_net_bin2addr(server_id->ip.data, server_id->ip.data_len, + tmp, sizeof(tmp))) + return NULL; + + memset(tmp, 0, sizeof(tmp)); + silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", silc_ntohs(server_id->port)); + _PUT_STRING(rid, tmp); + SILC_PUT16_MSB(server_id->rnd, tmps); + memset(tmp, 0, sizeof(tmp)); + silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]); + _PUT_STRING(rid, tmp); + } + break; + case SILC_ID_CLIENT: + { + SilcClientID *client_id = (SilcClientID *)id; + + if (!silc_net_bin2addr(client_id->ip.data, client_id->ip.data_len, + tmp, sizeof(tmp))) + return NULL; + + memset(tmp, 0, sizeof(tmp)); + silc_snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd); + _PUT_STRING(rid, tmp); + memset(tmp, 0, sizeof(tmp)); + silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]", + client_id->hash[0], client_id->hash[1], + client_id->hash[2], client_id->hash[3]); + _PUT_STRING(rid, tmp); + } + break; + case SILC_ID_CHANNEL: + { + SilcChannelID *channel_id = (SilcChannelID *)id; + + if (!silc_net_bin2addr(channel_id->ip.data, channel_id->ip.data_len, + tmp, sizeof(tmp))) + return NULL; + + memset(tmp, 0, sizeof(tmp)); + silc_snprintf(tmp, sizeof(tmp) - 1, ",%d,", + silc_ntohs(channel_id->port)); + _PUT_STRING(rid, tmp); + SILC_PUT16_MSB(channel_id->rnd, tmps); + memset(tmp, 0, sizeof(tmp)); + silc_snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]); + _PUT_STRING(rid, tmp); + } + break; + } + + return rid; +} +#undef _PUT_STRING