/* id.c Author: Pekka Riikonen Copyright (C) 1997 - 2005 Pekka Riikonen The contents of this file are subject to one of the Licenses specified in the COPYING file; You may not use this file except in compliance with the License. The software distributed under the License is distributed on an "AS IS" basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the COPYING file for more information. */ /* $Id: silcid.c,v 1.12.2.1 2005/04/30 15:31:27 priikone Exp $ */ #include "silcincludes.h" #include "silcid.h" /* ID lengths (in bytes) without the IP address part */ #define ID_SERVER_LEN_PART 4 #define ID_CLIENT_LEN_PART CLIENTID_HASH_LEN + 1 #define ID_CHANNEL_LEN_PART 4 /****************************************************************************** ID Payload ******************************************************************************/ struct SilcIDPayloadStruct { SilcIdType type; SilcUInt16 len; unsigned char *id; }; /* Parses buffer and return ID payload into payload structure */ SilcIDPayload silc_id_payload_parse(const unsigned char *payload, SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcIDPayload newp; int ret; silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); newp = silc_calloc(1, sizeof(*newp)); if (!newp) return NULL; ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&newp->type), SILC_STR_UI_SHORT(&newp->len), SILC_STR_END); if (ret == -1) goto err; if (newp->type > SILC_ID_CHANNEL) goto err; silc_buffer_pull(&buffer, 4); if (newp->len > buffer.len || newp->len > SILC_PACKET_MAX_ID_LEN) goto err; ret = silc_buffer_unformat(&buffer, SILC_STR_UI_XNSTRING_ALLOC(&newp->id, newp->len), SILC_STR_END); if (ret == -1) goto err; silc_buffer_push(&buffer, 4); return newp; err: SILC_LOG_DEBUG(("Error parsing ID payload")); silc_free(newp); return NULL; } /* Return the ID directly from the raw payload data. */ void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len, SilcIdType *ret_type) { SilcBufferStruct buffer; SilcIdType type; SilcUInt16 idlen; unsigned char *id_data; int ret; void *id; silc_buffer_set(&buffer, (unsigned char *)data, len); ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&type), SILC_STR_UI_SHORT(&idlen), SILC_STR_END); if (ret == -1) goto err; if (type > SILC_ID_CHANNEL) goto err; silc_buffer_pull(&buffer, 4); if (idlen > buffer.len || idlen > SILC_PACKET_MAX_ID_LEN) goto err; ret = silc_buffer_unformat(&buffer, SILC_STR_UI_XNSTRING(&id_data, idlen), SILC_STR_END); if (ret == -1) goto err; id = silc_id_str2id(id_data, idlen, type); if (ret_type) *ret_type = type; return id; err: SILC_LOG_DEBUG(("Error parsing ID payload")); return NULL; } /* Encodes ID Payload */ SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type) { SilcBuffer buffer; unsigned char *id_data; SilcUInt32 len; id_data = silc_id_id2str(id, type); len = silc_id_get_len(id, type); buffer = silc_id_payload_encode_data((const unsigned char *)id_data, len, type); silc_free(id_data); return buffer; } SilcBuffer silc_id_payload_encode_data(const unsigned char *id, SilcUInt32 id_len, SilcIdType type) { SilcBuffer buffer; buffer = silc_buffer_alloc_size(4 + id_len); if (!buffer) return NULL; silc_buffer_format(buffer, SILC_STR_UI_SHORT(type), SILC_STR_UI_SHORT(id_len), SILC_STR_UI_XNSTRING(id, id_len), SILC_STR_END); return buffer; } /* Free ID Payload */ void silc_id_payload_free(SilcIDPayload payload) { if (payload) { silc_free(payload->id); silc_free(payload); } } /* Get ID type */ SilcIdType silc_id_payload_get_type(SilcIDPayload payload) { return payload ? payload->type : 0; } /* Get ID */ void *silc_id_payload_get_id(SilcIDPayload payload) { return payload ? silc_id_str2id(payload->id, payload->len, payload->type) : NULL; } /* Get raw ID data. Data is duplicated. */ unsigned char *silc_id_payload_get_data(SilcIDPayload payload) { if (!payload) return NULL; return silc_memdup(payload->id, payload->len); } /* Get length of ID */ SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload) { return payload ? payload->len : 0; } /* Converts ID to string. */ unsigned char *silc_id_id2str(const void *id, SilcIdType type) { unsigned char *ret_id; SilcServerID *server_id; SilcClientID *client_id; SilcChannelID *channel_id; SilcUInt32 id_len = silc_id_get_len(id, type); if (id_len > SILC_PACKET_MAX_ID_LEN) return NULL; switch(type) { case SILC_ID_SERVER: server_id = (SilcServerID *)id; ret_id = silc_calloc(id_len, sizeof(unsigned char)); if (!ret_id) return NULL; memcpy(ret_id, server_id->ip.data, server_id->ip.data_len); SILC_PUT16_MSB(server_id->port, &ret_id[server_id->ip.data_len]); SILC_PUT16_MSB(server_id->rnd, &ret_id[server_id->ip.data_len + 2]); return ret_id; break; case SILC_ID_CLIENT: client_id = (SilcClientID *)id; ret_id = silc_calloc(id_len, sizeof(unsigned char)); if (!ret_id) return NULL; memcpy(ret_id, client_id->ip.data, client_id->ip.data_len); ret_id[client_id->ip.data_len] = client_id->rnd; memcpy(&ret_id[client_id->ip.data_len + 1], client_id->hash, CLIENTID_HASH_LEN); return ret_id; break; case SILC_ID_CHANNEL: channel_id = (SilcChannelID *)id; ret_id = silc_calloc(id_len, sizeof(unsigned char)); if (!ret_id) return NULL; memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len); SILC_PUT16_MSB(channel_id->port, &ret_id[channel_id->ip.data_len]); SILC_PUT16_MSB(channel_id->rnd, &ret_id[channel_id->ip.data_len + 2]); return ret_id; break; } return NULL; } /* Converts string to a ID */ void *silc_id_str2id(const unsigned char *id, SilcUInt32 id_len, SilcIdType type) { if (id_len > SILC_PACKET_MAX_ID_LEN) return NULL; switch(type) { case SILC_ID_SERVER: { SilcServerID *server_id; if (id_len != ID_SERVER_LEN_PART + 4 && id_len != ID_SERVER_LEN_PART + 16) return NULL; server_id = silc_calloc(1, sizeof(*server_id)); if (!server_id) return NULL; memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4)); server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4); SILC_GET16_MSB(server_id->port, &id[server_id->ip.data_len]); SILC_GET16_MSB(server_id->rnd, &id[server_id->ip.data_len + 2]); return server_id; } break; case SILC_ID_CLIENT: { SilcClientID *client_id; if (id_len != ID_CLIENT_LEN_PART + 4 && id_len != ID_CLIENT_LEN_PART + 16) return NULL; client_id = silc_calloc(1, sizeof(*client_id)); if (!client_id) return NULL; memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4)); client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4); client_id->rnd = id[client_id->ip.data_len]; memcpy(client_id->hash, &id[client_id->ip.data_len + 1], CLIENTID_HASH_LEN); return client_id; } break; case SILC_ID_CHANNEL: { SilcChannelID *channel_id; if (id_len != ID_CHANNEL_LEN_PART + 4 && id_len != ID_CHANNEL_LEN_PART + 16) return NULL; channel_id = silc_calloc(1, sizeof(*channel_id)); if (!channel_id) return NULL; memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4)); channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4); SILC_GET16_MSB(channel_id->port, &id[channel_id->ip.data_len]); SILC_GET16_MSB(channel_id->rnd, &id[channel_id->ip.data_len + 2]); return channel_id; } break; } return NULL; } /* Returns length of the ID */ SilcUInt32 silc_id_get_len(const void *id, SilcIdType type) { switch(type) { case SILC_ID_SERVER: { SilcServerID *server_id = (SilcServerID *)id; return ID_SERVER_LEN_PART + server_id->ip.data_len; } break; case SILC_ID_CLIENT: { SilcClientID *client_id = (SilcClientID *)id; return ID_CLIENT_LEN_PART + client_id->ip.data_len; } break; case SILC_ID_CHANNEL: { SilcChannelID *channel_id = (SilcChannelID *)id; return ID_CHANNEL_LEN_PART + channel_id->ip.data_len; } break; } return 0; } /* Duplicate ID data */ void *silc_id_dup(const void *id, SilcIdType type) { switch(type) { case SILC_ID_SERVER: { SilcServerID *server_id = (SilcServerID *)id; return silc_memdup(server_id, sizeof(*server_id)); } break; case SILC_ID_CLIENT: { SilcClientID *client_id = (SilcClientID *)id; return silc_memdup(client_id, sizeof(*client_id)); } break; case SILC_ID_CHANNEL: { SilcChannelID *channel_id = (SilcChannelID *)id; return silc_memdup(channel_id, sizeof(*channel_id)); } break; } return NULL; }