updates.
[silc.git] / lib / silccore / silcid.c
1 /*
2
3   id.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcid.h"
24
25 /* ID lengths (in bytes) without the IP address part */
26 #define ID_SERVER_LEN_PART      4
27 #define ID_CLIENT_LEN_PART      CLIENTID_HASH_LEN + 1
28 #define ID_CHANNEL_LEN_PART     4
29
30 /******************************************************************************
31
32                                 ID Payload
33
34 ******************************************************************************/
35
36 struct SilcIDPayloadStruct {
37   SilcIdType type;
38   SilcUInt16 len;
39   unsigned char *id;
40 };
41
42 /* Parses buffer and return ID payload into payload structure */
43
44 SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
45                                     SilcUInt32 payload_len)
46 {
47   SilcBufferStruct buffer;
48   SilcIDPayload newp;
49   int ret;
50
51   SILC_LOG_DEBUG(("Parsing ID payload"));
52
53   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
54   newp = silc_calloc(1, sizeof(*newp));
55   if (!newp)
56     return NULL;
57
58   ret = silc_buffer_unformat(&buffer,
59                              SILC_STR_UI_SHORT(&newp->type),
60                              SILC_STR_UI_SHORT(&newp->len),
61                              SILC_STR_END);
62   if (ret == -1)
63     goto err;
64
65   silc_buffer_pull(&buffer, 4);
66
67   if (newp->len > buffer.len || newp->len > SILC_PACKET_MAX_ID_LEN)
68     goto err;
69
70   ret = silc_buffer_unformat(&buffer,
71                              SILC_STR_UI_XNSTRING_ALLOC(&newp->id, newp->len),
72                              SILC_STR_END);
73   if (ret == -1)
74     goto err;
75
76   silc_buffer_push(&buffer, 4);
77
78   return newp;
79
80  err:
81   silc_free(newp);
82   return NULL;
83 }
84
85 /* Return the ID directly from the raw payload data. */
86
87 void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
88                                SilcIdType *ret_type)
89 {
90   SilcBufferStruct buffer;
91   SilcIdType type;
92   SilcUInt16 idlen;
93   unsigned char *id_data;
94   int ret;
95   void *id;
96
97   silc_buffer_set(&buffer, (unsigned char *)data, len);
98   ret = silc_buffer_unformat(&buffer,
99                              SILC_STR_UI_SHORT(&type),
100                              SILC_STR_UI_SHORT(&idlen),
101                              SILC_STR_END);
102   if (ret == -1)
103     return NULL;
104
105   silc_buffer_pull(&buffer, 4);
106
107   if (idlen > buffer.len || idlen > SILC_PACKET_MAX_ID_LEN)
108     return NULL;
109
110   ret = silc_buffer_unformat(&buffer,
111                              SILC_STR_UI_XNSTRING(&id_data, idlen),
112                              SILC_STR_END);
113   if (ret == -1)
114     return NULL;
115
116   id = silc_id_str2id(id_data, idlen, type);
117
118   if (ret_type)
119     *ret_type = type;
120
121   return id;
122 }
123
124 /* Encodes ID Payload */
125
126 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
127 {
128   SilcBuffer buffer;
129   unsigned char *id_data;
130   SilcUInt32 len;
131
132   id_data = silc_id_id2str(id, type);
133   len = silc_id_get_len(id, type);
134   buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
135                                        len, type);
136   silc_free(id_data);
137   return buffer;
138 }
139
140 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
141                                        SilcUInt32 id_len, SilcIdType type)
142 {
143   SilcBuffer buffer;
144
145   SILC_LOG_DEBUG(("Encoding %s ID payload",
146                   type == SILC_ID_CLIENT ? "Client" :
147                   type == SILC_ID_SERVER ? "Server" : "Channel"));
148
149   buffer = silc_buffer_alloc_size(4 + id_len);
150   if (!buffer)
151     return NULL;
152   silc_buffer_format(buffer,
153                      SILC_STR_UI_SHORT(type),
154                      SILC_STR_UI_SHORT(id_len),
155                      SILC_STR_UI_XNSTRING(id, id_len),
156                      SILC_STR_END);
157   return buffer;
158 }
159
160 /* Free ID Payload */
161
162 void silc_id_payload_free(SilcIDPayload payload)
163 {
164   if (payload) {
165     silc_free(payload->id);
166     silc_free(payload);
167   }
168 }
169
170 /* Get ID type */
171
172 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
173 {
174   return payload ? payload->type : 0;
175 }
176
177 /* Get ID */
178
179 void *silc_id_payload_get_id(SilcIDPayload payload)
180 {
181   return payload ? silc_id_str2id(payload->id, payload->len,
182                                   payload->type) : NULL;
183 }
184
185 /* Get raw ID data. Data is duplicated. */
186
187 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
188 {
189   if (!payload)
190     return NULL;
191
192   return silc_memdup(payload->id, payload->len);
193 }
194
195 /* Get length of ID */
196
197 SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload)
198 {
199   return payload ? payload->len : 0;
200 }
201
202 /* Converts ID to string. */
203
204 unsigned char *silc_id_id2str(const void *id, SilcIdType type)
205 {
206   unsigned char *ret_id;
207   SilcServerID *server_id;
208   SilcClientID *client_id;
209   SilcChannelID *channel_id;
210   SilcUInt32 id_len = silc_id_get_len(id, type);
211
212   switch(type) {
213   case SILC_ID_SERVER:
214     server_id = (SilcServerID *)id;
215     ret_id = silc_calloc(id_len, sizeof(unsigned char));
216     if (!ret_id)
217       return NULL;
218     memcpy(ret_id, server_id->ip.data, server_id->ip.data_len);
219     SILC_PUT16_MSB(server_id->port, &ret_id[server_id->ip.data_len]);
220     SILC_PUT16_MSB(server_id->rnd, &ret_id[server_id->ip.data_len + 2]);
221     return ret_id;
222     break;
223   case SILC_ID_CLIENT:
224     client_id = (SilcClientID *)id;
225     ret_id = silc_calloc(id_len, sizeof(unsigned char));
226     if (!ret_id)
227       return NULL;
228     memcpy(ret_id, client_id->ip.data, client_id->ip.data_len);
229     ret_id[client_id->ip.data_len] = client_id->rnd;
230     memcpy(&ret_id[client_id->ip.data_len + 1], client_id->hash, 
231            CLIENTID_HASH_LEN);
232     return ret_id;
233     break;
234   case SILC_ID_CHANNEL:
235     channel_id = (SilcChannelID *)id;
236     ret_id = silc_calloc(id_len, sizeof(unsigned char));
237     if (!ret_id)
238       return NULL;
239     memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len);
240     SILC_PUT16_MSB(channel_id->port, &ret_id[channel_id->ip.data_len]);
241     SILC_PUT16_MSB(channel_id->rnd, &ret_id[channel_id->ip.data_len + 2]);
242     return ret_id;
243     break;
244   }
245
246   return NULL;
247 }
248
249 /* Converts string to a ID */
250
251 void *silc_id_str2id(const unsigned char *id, SilcUInt32 id_len, 
252                      SilcIdType type)
253 {
254
255   switch(type) {
256   case SILC_ID_SERVER:
257     {
258       SilcServerID *server_id;
259
260       if (id_len != ID_SERVER_LEN_PART + 4 &&
261           id_len != ID_SERVER_LEN_PART + 16)
262         return NULL;
263
264       server_id = silc_calloc(1, sizeof(*server_id));
265       if (!server_id)
266         return NULL;
267       memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ?
268                                       16 : 4));
269       server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4);
270       SILC_GET16_MSB(server_id->port, &id[server_id->ip.data_len]);
271       SILC_GET16_MSB(server_id->rnd, &id[server_id->ip.data_len + 2]);
272       return server_id;
273     }
274     break;
275   case SILC_ID_CLIENT:
276     {
277       SilcClientID *client_id;
278
279       if (id_len != ID_CLIENT_LEN_PART + 4 &&
280           id_len != ID_CLIENT_LEN_PART + 16)
281         return NULL;
282
283       client_id = silc_calloc(1, sizeof(*client_id));
284       if (!client_id)
285         return NULL;
286       memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ?
287                                       16 : 4));
288       client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4);
289       client_id->rnd = id[client_id->ip.data_len];
290       memcpy(client_id->hash, &id[client_id->ip.data_len + 1], 
291              CLIENTID_HASH_LEN);
292       return client_id;
293     }
294     break;
295   case SILC_ID_CHANNEL:
296     {
297       SilcChannelID *channel_id;
298
299       if (id_len != ID_CHANNEL_LEN_PART + 4 &&
300           id_len != ID_CHANNEL_LEN_PART + 16)
301         return NULL;
302
303       channel_id = silc_calloc(1, sizeof(*channel_id));
304       if (!channel_id)
305         return NULL;
306       memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ?
307                                        16 : 4));
308       channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4);
309       SILC_GET16_MSB(channel_id->port, &id[channel_id->ip.data_len]);
310       SILC_GET16_MSB(channel_id->rnd, &id[channel_id->ip.data_len + 2]);
311       return channel_id;
312     }
313     break;
314   }
315
316   return NULL;
317 }
318
319 /* Returns length of the ID */
320
321 SilcUInt32 silc_id_get_len(const void *id, SilcIdType type)
322 {
323   switch(type) {
324   case SILC_ID_SERVER:
325     {
326       SilcServerID *server_id = (SilcServerID *)id;
327       return ID_SERVER_LEN_PART + server_id->ip.data_len;
328     }
329     break;
330   case SILC_ID_CLIENT:
331     {
332       SilcClientID *client_id = (SilcClientID *)id;
333       return ID_CLIENT_LEN_PART + client_id->ip.data_len;
334     }
335     break;
336   case SILC_ID_CHANNEL:
337     {
338       SilcChannelID *channel_id = (SilcChannelID *)id;
339       return ID_CHANNEL_LEN_PART + channel_id->ip.data_len;
340     }
341     break;
342   }
343
344   return 0;
345 }
346
347 /* Duplicate ID data */
348
349 void *silc_id_dup(const void *id, SilcIdType type)
350 {
351   switch(type) {
352   case SILC_ID_SERVER:
353     {
354       SilcServerID *server_id = (SilcServerID *)id;
355       return silc_memdup(server_id, sizeof(*server_id));
356     }
357     break;
358   case SILC_ID_CLIENT:
359     {
360       SilcClientID *client_id = (SilcClientID *)id;
361       return silc_memdup(client_id, sizeof(*client_id));
362     }
363     break;
364   case SILC_ID_CHANNEL:
365     {
366       SilcChannelID *channel_id = (SilcChannelID *)id;
367       return silc_memdup(channel_id, sizeof(*channel_id));
368     }
369     break;
370   }
371
372   return NULL;
373 }