1 /*
2
3 id.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 1997 - 2008 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; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19 /* $Id: silcid.c,v 1.19 2008/01/08 15:15:10 priikone Exp $ */
20
21 #include "silc.h"
22 #include "silcid.h"
23
24 /* ID lengths (in bytes) without the IP address part */
25 #define ID_SERVER_LEN_PART 4
26 #define ID_CLIENT_LEN_PART CLIENTID_HASH_LEN + 1
27 #define ID_CHANNEL_LEN_PART 4
28
29 /******************************************************************************
30
31 ID Payload
32
33 ******************************************************************************/
34
35 struct SilcIDPayloadStruct {
36 SilcIdType type;
37 SilcUInt16 len;
38 unsigned char *id;
39 };
40
41 /* Parses buffer and return ID payload into payload structure */
42
43 SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
44 SilcUInt32 payload_len)
45 {
46 SilcBufferStruct buffer;
47 SilcIDPayload newp;
48 int ret;
49
50 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
51 newp = silc_calloc(1, sizeof(*newp));
52 if (!newp)
53 return NULL;
54
55 ret = silc_buffer_unformat(&buffer,
56 SILC_STR_UI_SHORT(&newp->type),
57 SILC_STR_UI_SHORT(&newp->len),
58 SILC_STR_END);
59 if (ret == -1)
60 goto err;
61
62 if (newp->type > SILC_ID_CHANNEL)
63 goto err;
64
65 silc_buffer_pull(&buffer, 4);
66
67 if (newp->len > silc_buffer_len(&buffer) ||
68 newp->len > SILC_PACKET_MAX_ID_LEN)
69 goto err;
70
71 ret = silc_buffer_unformat(&buffer,
72 SILC_STR_DATA_ALLOC(&newp->id, newp->len),
73 SILC_STR_END);
74 if (ret == -1)
75 goto err;
76
77 return newp;
78
79 err:
80 SILC_LOG_DEBUG(("Error parsing ID payload"));
81 silc_free(newp);
82 return NULL;
83 }
84
85 /* Return the ID directly from the raw payload data. */
86
87 SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
88 SilcID *ret_id)
89 {
90 SilcBufferStruct buffer;
91 SilcIdType type;
92 SilcUInt16 idlen;
93 unsigned char *id_data;
94 int ret;
95
96 if (!ret_id)
97 return FALSE;
98
99 silc_buffer_set(&buffer, (unsigned char *)data, len);
100 ret = silc_buffer_unformat(&buffer,
101 SILC_STR_UI_SHORT(&type),
102 SILC_STR_UI_SHORT(&idlen),
103 SILC_STR_END);
104 if (ret == -1)
105 goto err;
106
107 if (type > SILC_ID_CHANNEL)
108 goto err;
109
110 silc_buffer_pull(&buffer, 4);
111
112 if (idlen > silc_buffer_len(&buffer) || idlen > SILC_PACKET_MAX_ID_LEN)
113 goto err;
114
115 ret = silc_buffer_unformat(&buffer,
116 SILC_STR_DATA(&id_data, idlen),
117 SILC_STR_END);
118 if (ret == -1)
119 goto err;
120
121 ret_id->type = type;
122
123 if (type == SILC_ID_CLIENT) {
124 if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.client_id,
125 sizeof(SilcClientID)))
126 goto err;
127 } else if (type == SILC_ID_SERVER) {
128 if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.server_id,
129 sizeof(SilcServerID)))
130 goto err;
131 } else {
132 if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.channel_id,
133 sizeof(SilcChannelID)))
134 goto err;
135 }
136
137 return TRUE;
138
139 err:
140 SILC_LOG_DEBUG(("Error parsing ID payload"));
141 return FALSE;
142 }
143
144 /* Encodes ID Payload */
145
146 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
147 {
148 SilcBuffer buffer;
149 unsigned char id_data[32];
150 SilcUInt32 len;
151
152 if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &len))
153 return NULL;
154 buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
155 len, type);
156 return buffer;
157 }
158
159 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
160 SilcUInt32 id_len, SilcIdType type)
161 {
162 SilcBuffer buffer;
163
164 buffer = silc_buffer_alloc_size(4 + id_len);
165 if (!buffer)
166 return NULL;
167 silc_buffer_format(buffer,
168 SILC_STR_UI_SHORT(type),
169 SILC_STR_UI_SHORT(id_len),
170 SILC_STR_DATA(id, id_len),
171 SILC_STR_END);
172 return buffer;
173 }
174
175 /* Free ID Payload */
176
177 void silc_id_payload_free(SilcIDPayload payload)
178 {
179 if (payload) {
180 silc_free(payload->id);
181 silc_free(payload);
182 }
183 }
184
185 /* Get ID type */
186
187 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
188 {
189 return payload ? payload->type : 0;
190 }
191
192 /* Get ID */
193
194 SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
195 SilcUInt32 ret_id_len)
196 {
197 if (!payload)
198 return FALSE;
199 return silc_id_str2id(payload->id, payload->len, payload->type,
200 ret_id, ret_id_len);
201 }
202
203 /* Get raw ID data. Data is duplicated. */
204
205 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
206 {
207 if (!payload)
208 return NULL;
209
210 return silc_memdup(payload->id, payload->len);
211 }
212
213 /* Get length of ID */
214
215 SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload)
216 {
217 return payload ? payload->len : 0;
218 }
219
220 /* Converts ID to string. */
221
222 SilcBool silc_id_id2str(const void *id, SilcIdType type,
223 unsigned char *ret_id, SilcUInt32 ret_id_size,
224 SilcUInt32 *ret_id_len)
225 {
226 SilcServerID *server_id;
227 SilcClientID *client_id;
228 SilcChannelID *channel_id;
229 SilcUInt32 id_len = silc_id_get_len(id, type);
230
231 if (id_len > ret_id_size)
232 return FALSE;
233
234 if (ret_id_len)
235 *ret_id_len = id_len;
236
237 if (id_len > SILC_PACKET_MAX_ID_LEN)
238 return FALSE;
239
240 switch(type) {
241 case SILC_ID_SERVER:
242 server_id = (SilcServerID *)id;
243 memcpy(ret_id, server_id->ip.data, server_id->ip.data_len);
244 SILC_PUT16_MSB(server_id->port, &ret_id[server_id->ip.data_len]);
245 SILC_PUT16_MSB(server_id->rnd, &ret_id[server_id->ip.data_len + 2]);
246 return TRUE;
247 break;
248 case SILC_ID_CLIENT:
249 client_id = (SilcClientID *)id;
250 memcpy(ret_id, client_id->ip.data, client_id->ip.data_len);
251 ret_id[client_id->ip.data_len] = client_id->rnd;
252 memcpy(&ret_id[client_id->ip.data_len + 1], client_id->hash,
253 CLIENTID_HASH_LEN);
254 return TRUE;
255 break;
256 case SILC_ID_CHANNEL:
257 channel_id = (SilcChannelID *)id;
258 memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len);
259 SILC_PUT16_MSB(channel_id->port, &ret_id[channel_id->ip.data_len]);
260 SILC_PUT16_MSB(channel_id->rnd, &ret_id[channel_id->ip.data_len + 2]);
261 return TRUE;
262 break;
263 }
264
265 return FALSE;
266 }
267
268 /* Converts string to a ID */
269
270 SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
271 SilcIdType type, void *ret_id, SilcUInt32 ret_id_size)
272 {
273 if (id_len > SILC_PACKET_MAX_ID_LEN)
274 return FALSE;
275
276 switch(type) {
277 case SILC_ID_SERVER:
278 {
279 SilcServerID *server_id = ret_id;
280
281 if (id_len != ID_SERVER_LEN_PART + 4 &&
282 id_len != ID_SERVER_LEN_PART + 16)
283 return FALSE;
284
285 if (ret_id_size < sizeof(SilcServerID))
286 return FALSE;
287
288 memset(ret_id, 0, ret_id_size);
289 memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ?
290 16 : 4));
291 server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4);
292 SILC_GET16_MSB(server_id->port, &id[server_id->ip.data_len]);
293 SILC_GET16_MSB(server_id->rnd, &id[server_id->ip.data_len + 2]);
294 return TRUE;
295 }
296 break;
297 case SILC_ID_CLIENT:
298 {
299 SilcClientID *client_id = ret_id;
300
301 if (id_len != ID_CLIENT_LEN_PART + 4 &&
302 id_len != ID_CLIENT_LEN_PART + 16)
303 return FALSE;
304
305 if (ret_id_size < sizeof(SilcClientID))
306 return FALSE;
307
308 memset(ret_id, 0, ret_id_size);
309 memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ?
310 16 : 4));
311 client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4);
312 client_id->rnd = id[client_id->ip.data_len];
313 memcpy(client_id->hash, &id[client_id->ip.data_len + 1],
314 CLIENTID_HASH_LEN);
315 return TRUE;
316 }
317 break;
318 case SILC_ID_CHANNEL:
319 {
320 SilcChannelID *channel_id = ret_id;
321
322 if (id_len != ID_CHANNEL_LEN_PART + 4 &&
323 id_len != ID_CHANNEL_LEN_PART + 16)
324 return FALSE;
325
326 if (ret_id_size < sizeof(SilcChannelID))
327 return FALSE;
328
329 memset(ret_id, 0, ret_id_size);
330 memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ?
331 16 : 4));
332 channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4);
333 SILC_GET16_MSB(channel_id->port, &id[channel_id->ip.data_len]);
334 SILC_GET16_MSB(channel_id->rnd, &id[channel_id->ip.data_len + 2]);
335 return TRUE;
336 }
337 break;
338 }
339
340 return FALSE;
341 }
342
343 /* Converts string to ID */
344
345 SilcBool silc_id_str2id2(const unsigned char *id, SilcUInt32 id_len,
346 SilcIdType type, SilcID *ret_id)
347 {
348 if (!ret_id)
349 return FALSE;
350
351 ret_id->type = type;
352
353 switch (type) {
354 case SILC_ID_CLIENT:
355 return silc_id_str2id(id, id_len, type, &ret_id->u.client_id,
356 sizeof(ret_id->u.client_id));
357 break;
358
359 case SILC_ID_SERVER:
360 return silc_id_str2id(id, id_len, type, &ret_id->u.server_id,
361 sizeof(ret_id->u.server_id));
362 break;
363
364 case SILC_ID_CHANNEL:
365 return silc_id_str2id(id, id_len, type, &ret_id->u.channel_id,
366 sizeof(ret_id->u.channel_id));
367 break;
368 }
369
370 return FALSE;
371 }
372
373 /* Returns length of the ID */
374
375 SilcUInt32 silc_id_get_len(const void *id, SilcIdType type)
376 {
377 switch(type) {
378 case SILC_ID_SERVER:
379 {
380 SilcServerID *server_id = (SilcServerID *)id;
381 return ID_SERVER_LEN_PART + server_id->ip.data_len;
382 }
383 break;
384 case SILC_ID_CLIENT:
385 {
386 SilcClientID *client_id = (SilcClientID *)id;
387 return ID_CLIENT_LEN_PART + client_id->ip.data_len;
388 }
389 break;
390 case SILC_ID_CHANNEL:
391 {
392 SilcChannelID *channel_id = (SilcChannelID *)id;
393 return ID_CHANNEL_LEN_PART + channel_id->ip.data_len;
394 }
395 break;
396 }
397
398 return 0;
399 }
400
401 /* Duplicate ID data */
402
403 void *silc_id_dup(const void *id, SilcIdType type)
404 {
405 switch(type) {
406 case SILC_ID_SERVER:
407 {
408 SilcServerID *server_id = (SilcServerID *)id;
409 return silc_memdup(server_id, sizeof(*server_id));
410 }
411 break;
412 case SILC_ID_CLIENT:
413 {
414 SilcClientID *client_id = (SilcClientID *)id;
415 return silc_memdup(client_id, sizeof(*client_id));
416 }
417 break;
418 case SILC_ID_CHANNEL:
419 {
420 SilcChannelID *channel_id = (SilcChannelID *)id;
421 return silc_memdup(channel_id, sizeof(*channel_id));
422 }
423 break;
424 }
425
426 return NULL;
427 }
428
429 /**************************** Utility functions *****************************/
430
431 /* Hash a ID. The `user_context' is the ID type. */
432
433 SilcUInt32 silc_hash_id(void *key, void *user_context)
434 {
435 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
436 SilcUInt32 h = 0;
437 int i;
438
439 switch (id_type) {
440 case SILC_ID_CLIENT:
441 {
442 SilcClientID *id = (SilcClientID *)key;
443
444 /* The client ID is hashed by hashing the hash of the ID
445 (which is a truncated MD5 hash of the nickname) so that we
446 can access the entry from the cache with both Client ID but
447 with just a hash from the ID as well. */
448 return silc_hash_client_id_hash(id->hash, NULL);
449 }
450 break;
451 case SILC_ID_SERVER:
452 {
453 SilcServerID *id = (SilcServerID *)key;
454
455 h = id->port * id->rnd;
456 for (i = 0; i < id->ip.data_len; i++)
457 h ^= id->ip.data[i];
458
459 return h;
460 }
461 break;
462 case SILC_ID_CHANNEL:
463 {
464 SilcChannelID *id = (SilcChannelID *)key;
465
466 h = id->port * id->rnd;
467 for (i = 0; i < id->ip.data_len; i++)
468 h ^= id->ip.data[i];
469
470 return h;
471 }
472 break;
473 default:
474 break;
475 }
476
477 return h;
478 }
479
480 /* Hash Client ID's hash. */
481
482 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
483 {
484 int i;
485 unsigned char *hash = key;
486 SilcUInt32 h = 0, g;
487
488 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
489 h = (h << 4) + hash[i];
490 if ((g = h & 0xf0000000)) {
491 h = h ^ (g >> 24);
492 h = h ^ g;
493 }
494 }
495
496 return h;
497 }
498
499 /* Compares two ID's. May be used as SilcHashTable comparison function.
500 The Client ID's compares only the hash of the Client ID not any other
501 part of the Client ID. Other ID's are fully compared. */
502
503 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
504 {
505 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
506 return (id_type == SILC_ID_CLIENT ?
507 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
508 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
509 }
510
511 /* Compares two ID's. Compares full IDs. */
512
513 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
514 {
515 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
516 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
517 }
518
519 /* Compare two Client ID's entirely and not just the hash from the ID. */
520
521 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
522 void *user_context)
523 {
524 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
525 }
526
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse