1 /*
2
3 idlist.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 1997 - 2005 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: idlist.c,v 1.84 2005/04/23 13:32:24 priikone Exp $ */
21
22 #include "serverincludes.h"
23 #include "idlist.h"
24 #include "server_internal.h"
25
26 /******************************************************************************
27
28 Common functions
29
30 ******************************************************************************/
31
32 /* This function is used to add keys and stuff to common ID entry data
33 structure. */
34
35 void silc_idlist_add_data(void *entry, SilcIDListData idata)
36 {
37 SilcIDListData data = (SilcIDListData)entry;
38 data->send_key = idata->send_key;
39 data->receive_key = idata->receive_key;
40 data->hmac_send = idata->hmac_send;
41 data->hmac_receive = idata->hmac_receive;
42 data->psn_send = idata->psn_send;
43 data->psn_receive = idata->psn_receive;
44 data->hash = idata->hash;
45 data->public_key = idata->public_key;
46 memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
47 data->rekey = idata->rekey;
48 data->last_receive = idata->last_receive;
49 data->last_sent = idata->last_sent;
50 data->status = idata->status;
51
52 data->created = time(0); /* Update creation time */
53 }
54
55 /* Free's all data in the common ID entry data structure. */
56
57 void silc_idlist_del_data(void *entry)
58 {
59 SilcIDListData idata = (SilcIDListData)entry;
60 if (idata->send_key)
61 silc_cipher_free(idata->send_key);
62 if (idata->receive_key)
63 silc_cipher_free(idata->receive_key);
64 if (idata->rekey) {
65 if (idata->rekey->send_enc_key) {
66 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
67 silc_free(idata->rekey->send_enc_key);
68 }
69 silc_free(idata->rekey);
70 }
71 if (idata->hmac_send)
72 silc_hmac_free(idata->hmac_send);
73 if (idata->hmac_receive)
74 silc_hmac_free(idata->hmac_receive);
75 if (idata->hash)
76 silc_hash_free(idata->hash);
77 if (idata->public_key)
78 silc_pkcs_public_key_free(idata->public_key);
79
80 idata->send_key = NULL;
81 idata->receive_key = NULL;
82 idata->rekey = NULL;
83 idata->hmac_send = NULL;
84 idata->hmac_receive = NULL;
85 idata->hash = NULL;
86 idata->public_key = NULL;
87 }
88
89 /* Purges ID cache */
90
91 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
92 {
93 SilcServer server = app_context;
94 SilcIDListPurge i = (SilcIDListPurge)context;
95
96 SILC_LOG_DEBUG(("Purging cache"));
97
98 silc_idcache_purge(i->cache);
99 silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
100 (void *)i, i->timeout, 0,
101 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
102 }
103
104 /******************************************************************************
105
106 Server entry functions
107
108 ******************************************************************************/
109
110 /* Add new server entry. This adds the new server entry to ID cache and
111 returns the allocated entry object or NULL on error. This is called
112 when new server connects to us. We also add ourselves to cache with
113 this function. */
114
115 SilcServerEntry
116 silc_idlist_add_server(SilcIDList id_list,
117 char *server_name, int server_type,
118 SilcServerID *id, SilcServerEntry router,
119 void *connection)
120 {
121 SilcServerEntry server;
122 char *server_namec = NULL;
123
124 SILC_LOG_DEBUG(("Adding new server entry"));
125
126 /* Normalize name. This is cached, original is in server context. */
127 if (server_name) {
128 server_namec = silc_identifier_check(server_name, strlen(server_name),
129 SILC_STRING_UTF8, 256, NULL);
130 if (!server_namec)
131 return NULL;
132 }
133
134 server = silc_calloc(1, sizeof(*server));
135 server->server_name = server_name;
136 server->server_type = server_type;
137 server->id = id;
138 server->router = router;
139 server->connection = connection;
140
141 if (!silc_idcache_add(id_list->servers, server_namec,
142 (void *)server->id, (void *)server, 0, NULL)) {
143 silc_free(server);
144 silc_free(server_namec);
145 return NULL;
146 }
147
148 return server;
149 }
150
151 /* Finds server by Server ID */
152
153 SilcServerEntry
154 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
155 bool registered, SilcIDCacheEntry *ret_entry)
156 {
157 SilcIDCacheEntry id_cache = NULL;
158 SilcServerEntry server;
159
160 if (!id)
161 return NULL;
162
163 SILC_LOG_DEBUG(("Server ID (%s)",
164 silc_id_render(id, SILC_ID_SERVER)));
165
166 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
167 &id_cache))
168 return NULL;
169
170 server = (SilcServerEntry)id_cache->context;
171
172 if (server && registered &&
173 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
174 return NULL;
175
176 if (ret_entry)
177 *ret_entry = id_cache;
178
179 SILC_LOG_DEBUG(("Found"));
180
181 return server;
182 }
183
184 /* Find server by name. The 'name' must be normalized already. */
185
186 SilcServerEntry
187 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
188 bool registered, SilcIDCacheEntry *ret_entry)
189 {
190 SilcIDCacheEntry id_cache = NULL;
191 SilcServerEntry server;
192
193 SILC_LOG_DEBUG(("Server by name `%s'", name));
194
195 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
196 return NULL;
197
198 server = (SilcServerEntry)id_cache->context;
199
200 if (server && registered &&
201 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
202 return NULL;
203
204 if (ret_entry)
205 *ret_entry = id_cache;
206
207 SILC_LOG_DEBUG(("Found"));
208
209 return server;
210 }
211
212 /* Find server by connection parameters, hostname and port */
213
214 SilcServerEntry
215 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
216 int port, bool registered,
217 SilcIDCacheEntry *ret_entry)
218 {
219 SilcIDCacheList list = NULL;
220 SilcIDCacheEntry id_cache = NULL;
221 SilcServerEntry server = NULL;
222 SilcSocketConnection sock;
223
224 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
225
226 if (!silc_idcache_get_all(id_list->servers, &list))
227 return NULL;
228
229 if (!silc_idcache_list_first(list, &id_cache)) {
230 silc_idcache_list_free(list);
231 return NULL;
232 }
233
234 while (id_cache) {
235 server = (SilcServerEntry)id_cache->context;
236 sock = (SilcSocketConnection)server->connection;
237
238 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
239 (sock->ip && !strcasecmp(sock->ip, hostname)))
240 && server->id->port == SILC_SWAB_16(port))
241 break;
242
243 id_cache = NULL;
244 server = NULL;
245
246 if (!silc_idcache_list_next(list, &id_cache))
247 break;
248 }
249
250 silc_idcache_list_free(list);
251
252 if (server && registered &&
253 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
254 return NULL;
255
256 if (ret_entry)
257 *ret_entry = id_cache;
258
259 SILC_LOG_DEBUG(("Found"));
260
261 return server;
262 }
263
264 /* Replaces old Server ID with new one */
265
266 SilcServerEntry
267 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
268 SilcServerID *new_id)
269 {
270 SilcIDCacheEntry id_cache = NULL;
271 SilcServerEntry server;
272 char *name;
273
274 if (!old_id || !new_id)
275 return NULL;
276
277 SILC_LOG_DEBUG(("Replacing Server ID"));
278
279 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
280 &id_cache))
281 return NULL;
282
283 server = (SilcServerEntry)id_cache->context;
284 name = strdup(id_cache->name);
285
286 /* Remove the old entry and add a new one */
287
288 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
289
290 silc_free(server->id);
291 server->id = new_id;
292
293 silc_idcache_add(id_list->servers, name, server->id, server, 0, NULL);
294
295 SILC_LOG_DEBUG(("Found"));
296
297 return server;
298 }
299
300 /* Removes and free's server entry from ID list */
301
302 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
303 {
304 if (entry) {
305 /* Remove from cache */
306 if (!silc_idcache_del_by_context(id_list->servers, entry)) {
307 SILC_LOG_DEBUG(("Unknown server, did not delete"));
308 return FALSE;
309 }
310
311 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
312 entry->server_name : "",
313 entry->id ?
314 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
315
316 /* Free data */
317 silc_free(entry->server_name);
318 silc_free(entry->id);
319 silc_free(entry->server_info);
320
321 memset(entry, 'F', sizeof(*entry));
322 silc_free(entry);
323 return TRUE;
324 }
325
326 return FALSE;
327 }
328
329 /******************************************************************************
330
331 Client entry functions
332
333 ******************************************************************************/
334
335 /* Add new client entry. This adds the client entry to ID cache system
336 and returns the allocated client entry or NULL on error. This is
337 called when new client connection is accepted to the server. If The
338 `router' is provided then the all server routines assume that the client
339 is not directly connected local client but it has router set and is
340 remote. If this is the case then `connection' must be NULL. If, on the
341 other hand, the `connection' is provided then the client is assumed
342 to be directly connected local client and `router' must be NULL. */
343
344 SilcClientEntry
345 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
346 char *userinfo, SilcClientID *id,
347 SilcServerEntry router, void *connection,
348 int expire)
349 {
350 SilcClientEntry client;
351 char *nicknamec = NULL;
352
353 SILC_LOG_DEBUG(("Adding new client entry"));
354
355 /* Normalize name. This is cached, original is in client context. */
356 if (nickname) {
357 nicknamec = silc_identifier_check(nickname, strlen(nickname),
358 SILC_STRING_UTF8, 128, NULL);
359 if (!nicknamec)
360 return NULL;
361 }
362
363 /* Check username. */
364 if (username) {
365 char *u = NULL, *h = NULL;
366 silc_parse_userfqdn(username, &u, &h);
367 if (!u)
368 return NULL;
369 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128)) {
370 silc_free(u);
371 silc_free(h);
372 return NULL;
373 }
374 if (h && !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256)) {
375 silc_free(u);
376 silc_free(h);
377 return NULL;
378 }
379 }
380
381 client = silc_calloc(1, sizeof(*client));
382 client->nickname = nickname;
383 client->username = username ? strdup(username) : NULL;
384 client->userinfo = userinfo;
385 client->id = id;
386 client->router = router;
387 client->connection = connection;
388 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
389 NULL, NULL, NULL, NULL, TRUE);
390
391 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
392 (void *)client, expire, NULL)) {
393 silc_hash_table_free(client->channels);
394 silc_free(client);
395 silc_free(nicknamec);
396 return NULL;
397 }
398
399 return client;
400 }
401
402 /* Free client entry. This free's everything and removes the entry
403 from ID cache. Call silc_idlist_del_data before calling this one. */
404
405 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
406 {
407 SILC_LOG_DEBUG(("Start"));
408
409 if (entry) {
410 if (!silc_idcache_del_by_context(id_list->clients, entry)) {
411 SILC_LOG_DEBUG(("Unknown client, did not delete"));
412 return FALSE;
413 }
414
415 assert(!silc_hash_table_count(entry->channels));
416
417 silc_free(entry->nickname);
418 silc_free(entry->servername);
419 silc_free(entry->username);
420 silc_free(entry->userinfo);
421 silc_free(entry->id);
422 silc_free(entry->attrs);
423 silc_hash_table_free(entry->channels);
424
425 memset(entry, 'F', sizeof(*entry));
426 silc_free(entry);
427
428 return TRUE;
429 }
430
431 return FALSE;
432 }
433
434 /* ID Cache destructor */
435
436 void silc_idlist_client_destructor(SilcIDCache cache,
437 SilcIDCacheEntry entry,
438 void *context)
439 {
440 SilcServer server = context;
441 SilcClientEntry client;
442
443 client = (SilcClientEntry)entry->context;
444 if (client) {
445 /* Remove this client from the public key hash list */
446 if (client->data.public_key)
447 silc_hash_table_del_by_context(server->pk_hash,
448 client->data.public_key, client);
449
450 assert(!silc_hash_table_count(client->channels));
451 silc_free(client->nickname);
452 silc_free(client->servername);
453 silc_free(client->username);
454 silc_free(client->userinfo);
455 silc_free(client->id);
456 silc_free(client->attrs);
457 if (client->data.public_key)
458 silc_pkcs_public_key_free(client->data.public_key);
459 silc_hash_table_free(client->channels);
460
461 memset(client, 'A', sizeof(*client));
462 silc_free(client);
463 }
464 }
465
466 /* Returns all clients matching requested nickname. Number of clients is
467 returned to `clients_count'. Caller must free the returned table.
468 The 'nickname' must be normalized already. */
469
470 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
471 char *server,
472 SilcClientEntry **clients,
473 SilcUInt32 *clients_count)
474 {
475 SilcIDCacheList list = NULL;
476 SilcIDCacheEntry id_cache = NULL;
477
478 SILC_LOG_DEBUG(("Start"));
479
480 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
481 return FALSE;
482
483 *clients = silc_realloc(*clients,
484 (silc_idcache_list_count(list) + *clients_count) *
485 sizeof(**clients));
486
487 silc_idcache_list_first(list, &id_cache);
488 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
489
490 while (silc_idcache_list_next(list, &id_cache))
491 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
492 silc_idcache_list_free(list);
493
494 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
495
496 return TRUE;
497 }
498
499 /* Returns all clients matching requested nickname hash. Number of clients
500 is returned to `clients_count'. Caller must free the returned table.
501 The 'nickname' must be normalized already. */
502
503 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
504 SilcHash md5hash,
505 SilcClientEntry **clients,
506 SilcUInt32 *clients_count)
507 {
508 SilcIDCacheList list = NULL;
509 SilcIDCacheEntry id_cache = NULL;
510 unsigned char hash[32];
511 SilcClientID client_id;
512
513 SILC_LOG_DEBUG(("Start"));
514
515 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
516
517 /* As the Client ID is hashed in the ID cache by hashing only the hash
518 from the Client ID, we can do a lookup with only the hash not the
519 other parts of the ID and get all the clients with that hash, ie.
520 with that nickname, as the hash is from the nickname. */
521 memset(&client_id, 0, sizeof(client_id));
522 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
523 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
524 return FALSE;
525
526 *clients = silc_realloc(*clients,
527 (silc_idcache_list_count(list) + *clients_count) *
528 sizeof(**clients));
529
530 silc_idcache_list_first(list, &id_cache);
531 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
532
533 while (silc_idcache_list_next(list, &id_cache))
534 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
535
536 silc_idcache_list_free(list);
537
538 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
539
540 return TRUE;
541 }
542
543 /* Finds client by Client ID */
544
545 SilcClientEntry
546 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
547 bool registered, SilcIDCacheEntry *ret_entry)
548 {
549 SilcIDCacheEntry id_cache = NULL;
550 SilcClientEntry client;
551
552 if (!id)
553 return NULL;
554
555 SILC_LOG_DEBUG(("Client ID (%s)",
556 silc_id_render(id, SILC_ID_CLIENT)));
557
558 /* Do extended search since the normal ID comparison function for
559 Client ID's compares only the hash from the Client ID and not the
560 entire ID. The silc_hash_client_id_compare compares the entire
561 Client ID as we want to find one specific Client ID. */
562 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
563 NULL, NULL,
564 silc_hash_client_id_compare, NULL,
565 &id_cache))
566 return NULL;
567
568 client = (SilcClientEntry)id_cache->context;
569
570 if (client && registered &&
571 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
572 return NULL;
573
574 if (ret_entry)
575 *ret_entry = id_cache;
576
577 SILC_LOG_DEBUG(("Found"));
578
579 return client;
580 }
581
582 /* Replaces old Client ID with new one */
583
584 SilcClientEntry
585 silc_idlist_replace_client_id(SilcServer server,
586 SilcIDList id_list, SilcClientID *old_id,
587 SilcClientID *new_id, const char *nickname)
588 {
589 SilcIDCacheEntry id_cache = NULL;
590 SilcClientEntry client;
591 char *nicknamec = NULL;
592
593 if (!old_id || !new_id)
594 return NULL;
595
596 SILC_LOG_DEBUG(("Replacing Client ID"));
597
598 /* Normalize name. This is cached, original is in client context. */
599 if (nickname) {
600 nicknamec = silc_identifier_check(nickname, strlen(nickname),
601 SILC_STRING_UTF8, 128, NULL);
602 if (!nicknamec)
603 return NULL;
604 }
605
606 /* Do extended search since the normal ID comparison function for
607 Client ID's compares only the hash from the Client ID and not the
608 entire ID. The silc_hash_client_id_compare compares the entire
609 Client ID as we want to find one specific Client ID. */
610 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
611 NULL, NULL,
612 silc_hash_client_id_compare, NULL,
613 &id_cache))
614 return NULL;
615
616 client = (SilcClientEntry)id_cache->context;
617
618 /* Remove the old entry and add a new one */
619
620 if (!silc_idcache_del_by_context(id_list->clients, client))
621 return NULL;
622
623 /* Check if anyone is watching old nickname */
624 if (server->server_type == SILC_ROUTER)
625 silc_server_check_watcher_list(server, client, nickname,
626 SILC_NOTIFY_TYPE_NICK_CHANGE);
627
628 silc_free(client->id);
629 silc_free(client->nickname);
630 client->id = new_id;
631 client->nickname = nickname ? strdup(nickname) : NULL;
632
633 /* Check if anyone is watching new nickname */
634 if (server->server_type == SILC_ROUTER)
635 silc_server_check_watcher_list(server, client, nickname,
636 SILC_NOTIFY_TYPE_NICK_CHANGE);
637
638 if (!silc_idcache_add(id_list->clients, nicknamec, client->id,
639 client, 0, NULL))
640 return NULL;
641
642 SILC_LOG_DEBUG(("Replaced"));
643
644 return client;
645 }
646
647
648 /******************************************************************************
649
650 Channel entry functions
651
652 ******************************************************************************/
653
654 /* Add new channel entry. This add the new channel entry to the ID cache
655 system and returns the allocated entry or NULL on error. */
656
657 SilcChannelEntry
658 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
659 SilcChannelID *id, SilcServerEntry router,
660 SilcCipher channel_key, SilcHmac hmac,
661 int expire)
662 {
663 SilcChannelEntry channel;
664 char *channel_namec = NULL;
665
666 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
667
668 /* Normalize name. This is cached, original is in client context. */
669 if (channel_name) {
670 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
671 SILC_STRING_UTF8, 256, NULL);
672 if (!channel_namec)
673 return NULL;
674 }
675
676 channel = silc_calloc(1, sizeof(*channel));
677 channel->channel_name = channel_name;
678 channel->mode = mode;
679 channel->id = id;
680 channel->router = router;
681 channel->channel_key = channel_key;
682 channel->hmac = hmac;
683 channel->created = channel->updated = time(0);
684 if (!channel->hmac)
685 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
686 silc_free(channel);
687 return NULL;
688 }
689
690 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
691 NULL, NULL, NULL, TRUE);
692
693 if (!silc_idcache_add(id_list->channels, channel_namec,
694 (void *)channel->id, (void *)channel, expire, NULL)) {
695 silc_hmac_free(channel->hmac);
696 silc_hash_table_free(channel->user_list);
697 silc_free(channel);
698 silc_free(channel_namec);
699 return NULL;
700 }
701
702 return channel;
703 }
704
705 /* Foreach callbcak to free all users from the channel when deleting a
706 channel entry. */
707
708 static void silc_idlist_del_channel_foreach(void *key, void *context,
709 void *user_context)
710 {
711 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
712
713 SILC_LOG_DEBUG(("Removing client %s from channel %s",
714 chl->client->nickname ? chl->client->nickname :
715 (unsigned char *)"", chl->channel->channel_name));
716
717 /* Remove the context from the client's channel hash table as that
718 table and channel's user_list hash table share this same context. */
719 silc_hash_table_del(chl->client->channels, chl->channel);
720 silc_free(chl);
721 }
722
723 /* Free channel entry. This free's everything. */
724
725 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
726 {
727 if (entry) {
728 /* Remove from cache */
729 if (!silc_idcache_del_by_context(id_list->channels, entry)) {
730 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
731 return FALSE;
732 }
733
734 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
735
736 /* Free all client entrys from the users list. The silc_hash_table_free
737 will free all the entries so they are not freed at the foreach
738 callback. */
739 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
740 NULL);
741 silc_hash_table_free(entry->user_list);
742
743 /* Free data */
744 silc_free(entry->channel_name);
745 silc_free(entry->id);
746 silc_free(entry->topic);
747
748 if (entry->invite_list)
749 silc_hash_table_free(entry->invite_list);
750 if (entry->ban_list)
751 silc_hash_table_free(entry->ban_list);
752
753 if (entry->channel_key)
754 silc_cipher_free(entry->channel_key);
755 if (entry->key) {
756 memset(entry->key, 0, entry->key_len / 8);
757 silc_free(entry->key);
758 }
759 silc_free(entry->cipher);
760 if (entry->hmac)
761 silc_hmac_free(entry->hmac);
762 silc_free(entry->hmac_name);
763 silc_free(entry->rekey);
764 if (entry->founder_key)
765 silc_pkcs_public_key_free(entry->founder_key);
766 if (entry->channel_pubkeys)
767 silc_hash_table_free(entry->channel_pubkeys);
768
769 memset(entry, 'F', sizeof(*entry));
770 silc_free(entry);
771 return TRUE;
772 }
773
774 return FALSE;
775 }
776
777 /* Finds channel by channel name. Channel names are unique and they
778 are not case-sensitive. The 'name' must be normalized already. */
779
780 SilcChannelEntry
781 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
782 SilcIDCacheEntry *ret_entry)
783 {
784 SilcIDCacheEntry id_cache = NULL;
785
786 SILC_LOG_DEBUG(("Channel by name %s", name));
787
788 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
789 return NULL;
790
791 if (ret_entry)
792 *ret_entry = id_cache;
793
794 SILC_LOG_DEBUG(("Found"));
795
796 /* Touch channel */
797 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
798
799 return id_cache->context;
800 }
801
802 /* Finds channel by Channel ID. */
803
804 SilcChannelEntry
805 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
806 SilcIDCacheEntry *ret_entry)
807 {
808 SilcIDCacheEntry id_cache = NULL;
809 SilcChannelEntry channel;
810
811 if (!id)
812 return NULL;
813
814 SILC_LOG_DEBUG(("Channel ID (%s)",
815 silc_id_render(id, SILC_ID_CHANNEL)));
816
817 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
818 return NULL;
819
820 channel = (SilcChannelEntry)id_cache->context;
821
822 if (ret_entry)
823 *ret_entry = id_cache;
824
825 SILC_LOG_DEBUG(("Found"));
826
827 /* Touch channel */
828 channel->updated = time(NULL);
829
830 return channel;
831 }
832
833 /* Replaces old Channel ID with new one. This is done when router forces
834 normal server to change Channel ID. */
835
836 SilcChannelEntry
837 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
838 SilcChannelID *new_id)
839 {
840 SilcIDCacheEntry id_cache = NULL;
841 SilcChannelEntry channel;
842 char *name;
843
844 if (!old_id || !new_id)
845 return NULL;
846
847 SILC_LOG_DEBUG(("Replacing Channel ID"));
848
849 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
850 &id_cache))
851 return NULL;
852
853 channel = (SilcChannelEntry)id_cache->context;
854 name = strdup(id_cache->name);
855
856 /* Remove the old entry and add a new one */
857
858 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
859
860 silc_free(channel->id);
861 channel->id = new_id;
862
863 silc_idcache_add(id_list->channels, name, channel->id, channel, 0, NULL);
864
865 SILC_LOG_DEBUG(("Replaced"));
866
867 /* Touch channel */
868 channel->updated = time(NULL);
869
870 return channel;
871 }
872
873 /* Returns channels from the ID list. If the `channel_id' is NULL then
874 all channels are returned. */
875
876 SilcChannelEntry *
877 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
878 SilcUInt32 *channels_count)
879 {
880 SilcIDCacheList list = NULL;
881 SilcIDCacheEntry id_cache = NULL;
882 SilcChannelEntry *channels = NULL;
883 int i = 0;
884
885 SILC_LOG_DEBUG(("Start"));
886
887 if (!channel_id) {
888 if (!silc_idcache_get_all(id_list->channels, &list))
889 return NULL;
890
891 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
892
893 i = 0;
894 silc_idcache_list_first(list, &id_cache);
895 channels[i++] = (SilcChannelEntry)id_cache->context;
896
897 while (silc_idcache_list_next(list, &id_cache))
898 channels[i++] = (SilcChannelEntry)id_cache->context;
899
900 silc_idcache_list_free(list);
901 } else {
902 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
903 return NULL;
904
905 i = 1;
906 channels = silc_calloc(1, sizeof(*channels));
907 channels[0] = (SilcChannelEntry)id_cache->context;
908 }
909
910 if (channels_count)
911 *channels_count = i;
912
913 return channels;
914 }
915
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse