5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
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.
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.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Channel Message Send ****************************/
29 SilcClientConnection conn;
30 SilcChannelEntry channel;
31 } *SilcClientChannelMessageContext;
33 /* Message payload encoding callback */
35 static void silc_client_send_channel_message_final(SilcBuffer message,
38 SilcClientChannelMessageContext c = context;
40 /* Send the channel message */
42 silc_packet_send_ext(c->conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
43 0, NULL, SILC_ID_CHANNEL, &c->channel->id,
44 silc_buffer_datalen(message), NULL, NULL);
46 silc_client_unref_channel(c->client, c->conn, c->channel);
50 /* Sends channel message to `channel'. */
52 SilcBool silc_client_send_channel_message(SilcClient client,
53 SilcClientConnection conn,
54 SilcChannelEntry channel,
55 SilcChannelPrivateKey key,
56 SilcMessageFlags flags,
61 SilcClientChannelMessageContext c;
67 SILC_LOG_DEBUG(("Sending channel message"));
69 if (silc_unlikely(!client || !conn || !channel))
71 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
73 if (silc_unlikely(conn->internal->disconnected))
76 chu = silc_client_on_channel(channel, conn->local_entry);
77 if (silc_unlikely(!chu)) {
78 client->internal->ops->say(conn->client, conn,
79 SILC_CLIENT_MESSAGE_AUDIT,
80 "Cannot talk to channel: not joined");
84 /* Check if it is allowed to send messages to this channel by us. */
85 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
88 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
89 chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
90 !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
92 if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
95 /* Take the key to be used */
96 if (channel->internal.private_keys) {
98 /* Use key application specified */
99 cipher = key->send_key;
101 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
102 channel->internal.curr_key) {
103 /* Use current private key */
104 cipher = channel->internal.curr_key->send_key;
105 hmac = channel->internal.curr_key->hmac;
106 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
107 !channel->internal.curr_key &&
108 channel->internal.private_keys) {
109 /* Use just some private key since we don't know what to use
110 and private keys are set. */
111 silc_dlist_start(channel->internal.private_keys);
112 key = silc_dlist_get(channel->internal.private_keys);
113 cipher = key->send_key;
116 /* Use this key as current private key */
117 channel->internal.curr_key = key;
119 /* Use normal channel key generated by the server */
120 cipher = channel->internal.send_key;
121 hmac = channel->internal.hmac;
124 /* Use normal channel key generated by the server */
125 cipher = channel->internal.send_key;
126 hmac = channel->internal.hmac;
129 if (silc_unlikely(!cipher || !hmac)) {
130 SILC_LOG_ERROR(("No cipher and HMAC for channel"));
134 c = silc_calloc(1, sizeof(*c));
140 c->channel = silc_client_ref_channel(client, conn, channel);
142 sid.type = SILC_ID_CLIENT;
143 sid.u.client_id = chu->client->id;
144 rid.type = SILC_ID_CHANNEL;
145 rid.u.channel_id = chu->channel->id;
147 /* Encode the message payload. This also encrypts the message payload. */
148 silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
149 cipher, hmac, client->rng, NULL,
150 conn->private_key, hash, &sid, &rid, NULL,
151 silc_client_send_channel_message_final, c);
156 /************************* Channel Message Receive **************************/
158 /* Client resolving callback. Continues with the channel message processing */
160 static void silc_client_channel_message_resolved(SilcClient client,
161 SilcClientConnection conn,
166 /* If no client found, ignore the channel message, a silent error */
168 silc_fsm_next(context, silc_client_channel_message_error);
170 /* Continue processing the channel message packet */
171 SILC_FSM_CALL_CONTINUE(context);
174 /* Process received channel message */
176 SILC_FSM_STATE(silc_client_channel_message)
178 SilcClientConnection conn = fsm_context;
179 SilcClient client = conn->client;
180 SilcPacket packet = state_context;
181 SilcBuffer buffer = &packet->buffer;
182 SilcMessagePayload payload = NULL;
183 SilcChannelEntry channel;
184 SilcClientEntry client_entry;
185 SilcClientID remote_id;
186 SilcChannelID channel_id;
187 unsigned char *message;
188 SilcUInt32 message_len;
189 SilcChannelPrivateKey key = NULL;
191 SILC_LOG_DEBUG(("Received channel message"));
193 SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
194 silc_buffer_len(buffer));
196 if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
197 /** Invalid packet */
198 silc_fsm_next(fsm, silc_client_channel_message_error);
199 return SILC_FSM_CONTINUE;
202 if (silc_unlikely(!silc_id_str2id(packet->src_id,
203 packet->src_id_len, SILC_ID_CLIENT,
204 &remote_id, sizeof(remote_id)))) {
205 /** Invalid source ID */
206 silc_fsm_next(fsm, silc_client_channel_message_error);
207 return SILC_FSM_CONTINUE;
210 /* Get sender client entry */
211 client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
212 if (!client_entry || !client_entry->internal.valid) {
213 /** Resolve client info */
214 silc_client_unref_client(client, conn, client_entry);
215 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
216 client, conn, &remote_id, NULL,
217 silc_client_channel_message_resolved,
222 if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
223 SILC_ID_CHANNEL, &channel_id,
224 sizeof(channel_id)))) {
225 /** Invalid destination ID */
226 silc_fsm_next(fsm, silc_client_channel_message_error);
227 return SILC_FSM_CONTINUE;
230 /* Find the channel */
231 channel = silc_client_get_channel_by_id(client, conn, &channel_id);
232 if (silc_unlikely(!channel)) {
233 /** Unknown channel */
234 silc_fsm_next(fsm, silc_client_channel_message_error);
235 return SILC_FSM_CONTINUE;
238 /* Check that user is on channel */
239 if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
240 /** User not on channel */
241 SILC_LOG_WARNING(("Message from user not on channel, client or "
243 silc_fsm_next(fsm, silc_client_channel_message_error);
244 return SILC_FSM_CONTINUE;
247 /* If there is no channel private key then just decrypt the message
248 with the channel key. If private keys are set then just go through
249 all private keys and check what decrypts correctly. */
250 if (!channel->internal.private_keys) {
251 /* Parse the channel message payload. This also decrypts the payload */
252 payload = silc_message_payload_parse(silc_buffer_data(buffer),
253 silc_buffer_len(buffer), FALSE,
254 FALSE, channel->internal.receive_key,
255 channel->internal.hmac,
256 packet->src_id, packet->src_id_len,
257 packet->dst_id, packet->dst_id_len,
260 /* If decryption failed and we have just performed channel key rekey
261 we will use the old key in decryption. If that fails too then we
262 cannot do more and will drop the packet. */
263 if (silc_unlikely(!payload)) {
267 if (!channel->internal.old_channel_keys ||
268 !silc_dlist_count(channel->internal.old_channel_keys))
271 SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
273 silc_dlist_end(channel->internal.old_channel_keys);
274 silc_dlist_end(channel->internal.old_hmacs);
275 while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
276 hmac = silc_dlist_get(channel->internal.old_hmacs);
280 payload = silc_message_payload_parse(silc_buffer_data(buffer),
281 silc_buffer_len(buffer),
282 FALSE, FALSE, cipher, hmac,
295 /* If the private key mode is not set on the channel then try the actual
296 channel key first before trying private keys. */
297 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
298 payload = silc_message_payload_parse(silc_buffer_data(buffer),
299 silc_buffer_len(buffer),
301 channel->internal.receive_key,
302 channel->internal.hmac,
310 silc_dlist_start(channel->internal.private_keys);
311 while ((key = silc_dlist_get(channel->internal.private_keys))) {
312 /* Parse the message payload. This also decrypts the payload */
313 payload = silc_message_payload_parse(silc_buffer_data(buffer),
314 silc_buffer_len(buffer),
315 FALSE, FALSE, key->receive_key,
316 key->hmac, packet->src_id,
324 if (key == SILC_LIST_END)
329 message = silc_message_get_data(payload, &message_len);
331 /* Pass the message to application */
332 client->internal->ops->channel_message(
333 client, conn, client_entry, channel, payload,
334 key, silc_message_get_flags(payload),
335 message, message_len);
338 silc_client_unref_client(client, conn, client_entry);
339 silc_client_unref_channel(client, conn, channel);
341 silc_message_payload_free(payload);
342 return SILC_FSM_FINISH;
345 /* Channel message error. */
347 SILC_FSM_STATE(silc_client_channel_message_error)
349 SilcPacket packet = state_context;
350 silc_packet_free(packet);
351 return SILC_FSM_FINISH;
354 /******************************* Channel Key ********************************/
356 /* Timeout callback that is called after a short period of time after the
357 new channel key has been created. This removes the first channel key
360 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
362 SilcChannelEntry channel = (SilcChannelEntry)context;
366 if (channel->internal.old_channel_keys) {
367 silc_dlist_start(channel->internal.old_channel_keys);
368 key = silc_dlist_get(channel->internal.old_channel_keys);
370 silc_dlist_del(channel->internal.old_channel_keys, key);
371 silc_cipher_free(key);
375 if (channel->internal.old_hmacs) {
376 silc_dlist_start(channel->internal.old_hmacs);
377 hmac = silc_dlist_get(channel->internal.old_hmacs);
379 silc_dlist_del(channel->internal.old_hmacs, hmac);
380 silc_hmac_free(hmac);
385 /* Saves channel key from encoded `key_payload'. This is used when we receive
386 Channel Key Payload and when we are processing JOIN command reply. */
388 SilcBool silc_client_save_channel_key(SilcClient client,
389 SilcClientConnection conn,
390 SilcBuffer key_payload,
391 SilcChannelEntry channel)
393 unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
396 SilcChannelKeyPayload payload;
398 SILC_LOG_DEBUG(("New channel key"));
400 payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
401 silc_buffer_len(key_payload));
405 id_string = silc_channel_key_get_id(payload, &tmp_len);
407 silc_channel_key_payload_free(payload);
411 if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
412 silc_channel_key_payload_free(payload);
418 channel = silc_client_get_channel_by_id(client, conn, &id);
420 SILC_LOG_DEBUG(("Key for unknown channel"));
421 silc_channel_key_payload_free(payload);
425 silc_client_ref_channel(client, conn, channel);
428 /* Save the old key for a short period of time so that we can decrypt
429 channel message even after the rekey if some client would be sending
430 messages with the old key after the rekey. */
431 if (!channel->internal.old_channel_keys)
432 channel->internal.old_channel_keys = silc_dlist_init();
433 if (!channel->internal.old_hmacs)
434 channel->internal.old_hmacs = silc_dlist_init();
435 if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
436 silc_dlist_add(channel->internal.old_channel_keys,
437 channel->internal.receive_key);
438 silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
439 silc_schedule_task_add_timeout(client->schedule,
440 silc_client_save_channel_key_rekey,
444 /* Get channel cipher */
445 cipher = silc_channel_key_get_cipher(payload, NULL);
446 if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
447 client->internal->ops->say(
449 SILC_CLIENT_MESSAGE_AUDIT,
450 "Cannot talk to channel: unsupported cipher %s",
452 silc_client_unref_channel(client, conn, channel);
453 silc_channel_key_payload_free(payload);
456 if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
457 client->internal->ops->say(
459 SILC_CLIENT_MESSAGE_AUDIT,
460 "Cannot talk to channel: unsupported cipher %s",
462 silc_client_unref_channel(client, conn, channel);
463 silc_channel_key_payload_free(payload);
467 /* Set the cipher key. Both sending and receiving keys are same */
468 key = silc_channel_key_get_key(payload, &tmp_len);
469 silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
470 silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);
472 /* Get channel HMAC */
473 hmac = (channel->internal.hmac ?
474 (char *)silc_hmac_get_name(channel->internal.hmac) :
476 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
477 client->internal->ops->say(
479 SILC_CLIENT_MESSAGE_AUDIT,
480 "Cannot talk to channel: unsupported HMAC %s",
482 silc_client_unref_channel(client, conn, channel);
483 silc_channel_key_payload_free(payload);
487 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
488 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
491 silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
493 silc_hmac_set_key(channel->internal.hmac, hash,
494 silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
495 memset(hash, 0, sizeof(hash));
496 silc_channel_key_payload_free(payload);
498 silc_client_unref_channel(client, conn, channel);
503 /* Received channel key packet. The key will replace old channel key. */
505 SILC_FSM_STATE(silc_client_channel_key)
507 SilcClientConnection conn = fsm_context;
508 SilcClient client = conn->client;
509 SilcPacket packet = state_context;
511 SILC_LOG_DEBUG(("Received channel key"));
514 silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
515 silc_packet_free(packet);
517 return SILC_FSM_FINISH;
520 /**************************** Channel Private Key ***************************/
522 /* Add new channel private key */
524 SilcBool silc_client_add_channel_private_key(SilcClient client,
525 SilcClientConnection conn,
526 SilcChannelEntry channel,
532 SilcChannelPrivateKey *ret_key)
534 SilcChannelPrivateKey entry;
535 unsigned char hash[SILC_HASH_MAXLEN];
536 SilcSKEKeyMaterial keymat;
538 if (!client || !conn || !channel)
542 cipher = SILC_DEFAULT_CIPHER;
544 hmac = SILC_DEFAULT_HMAC;
546 if (!silc_cipher_is_supported(cipher))
548 if (!silc_hmac_is_supported(hmac))
551 if (!channel->internal.private_keys) {
552 channel->internal.private_keys = silc_dlist_init();
553 if (!channel->internal.private_keys)
557 /* Produce the key material */
558 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
559 conn->internal->sha1hash);
564 entry = silc_calloc(1, sizeof(*entry));
566 silc_ske_free_key_material(keymat);
569 entry->name = name ? strdup(name) : NULL;
571 /* Allocate the cipher and set the key */
572 if (!silc_cipher_alloc(cipher, &entry->send_key)) {
574 silc_free(entry->name);
575 silc_ske_free_key_material(keymat);
578 if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
580 silc_free(entry->name);
581 silc_cipher_free(entry->send_key);
582 silc_ske_free_key_material(keymat);
585 silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
586 keymat->enc_key_len, TRUE);
587 silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
588 keymat->enc_key_len, FALSE);
590 /* Generate HMAC key from the channel key data and set it */
591 if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
593 silc_free(entry->name);
594 silc_cipher_free(entry->send_key);
595 silc_cipher_free(entry->receive_key);
596 silc_ske_free_key_material(keymat);
599 silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
600 keymat->enc_key_len / 8, hash);
601 silc_hmac_set_key(entry->hmac, hash,
602 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
603 memset(hash, 0, sizeof(hash));
605 /* Add to the private keys list */
606 silc_dlist_add(channel->internal.private_keys, entry);
608 if (!channel->internal.curr_key) {
609 channel->internal.curr_key = entry;
610 channel->cipher = silc_cipher_get_name(entry->send_key);
611 channel->hmac = silc_cipher_get_name(entry->send_key);
614 /* Free the key material */
615 silc_ske_free_key_material(keymat);
623 /* Removes all private keys from the `channel'. The old channel key is used
624 after calling this to protect the channel messages. Returns FALSE on
625 on error, TRUE otherwise. */
627 SilcBool silc_client_del_channel_private_keys(SilcClient client,
628 SilcClientConnection conn,
629 SilcChannelEntry channel)
631 SilcChannelPrivateKey entry;
633 if (!client || !conn || !channel)
636 if (!channel->internal.private_keys)
639 silc_dlist_start(channel->internal.private_keys);
640 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
641 silc_dlist_del(channel->internal.private_keys, entry);
642 silc_free(entry->name);
643 silc_cipher_free(entry->send_key);
644 silc_cipher_free(entry->receive_key);
645 silc_hmac_free(entry->hmac);
649 channel->internal.curr_key = NULL;
650 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
651 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
653 silc_dlist_uninit(channel->internal.private_keys);
654 channel->internal.private_keys = NULL;
659 /* Removes and frees private key `key' from the channel `channel'. The `key'
660 is retrieved by calling the function silc_client_list_channel_private_keys.
661 The key is not used after this. If the key was last private key then the
662 old channel key is used hereafter to protect the channel messages. This
663 returns FALSE on error, TRUE otherwise. */
665 SilcBool silc_client_del_channel_private_key(SilcClient client,
666 SilcClientConnection conn,
667 SilcChannelEntry channel,
668 SilcChannelPrivateKey key)
670 SilcChannelPrivateKey entry;
672 if (!client || !conn || !channel)
675 if (!channel->internal.private_keys)
678 silc_dlist_start(channel->internal.private_keys);
679 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
683 if (channel->internal.curr_key == entry) {
684 channel->internal.curr_key = NULL;
685 channel->cipher = silc_cipher_get_name(channel->internal.send_key);
686 channel->hmac = silc_hmac_get_name(channel->internal.hmac);
689 silc_dlist_del(channel->internal.private_keys, entry);
690 silc_free(entry->name);
691 silc_cipher_free(entry->send_key);
692 silc_cipher_free(entry->receive_key);
693 silc_hmac_free(entry->hmac);
696 if (silc_dlist_count(channel->internal.private_keys) == 0) {
697 silc_dlist_uninit(channel->internal.private_keys);
698 channel->internal.private_keys = NULL;
707 /* Returns array (pointers) of private keys associated to the `channel'.
708 The caller must free the array by calling the function
709 silc_client_free_channel_private_keys. The pointers in the array may be
710 used to delete the specific key by giving the pointer as argument to the
711 function silc_client_del_channel_private_key. */
713 SilcDList silc_client_list_channel_private_keys(SilcClient client,
714 SilcClientConnection conn,
715 SilcChannelEntry channel)
717 SilcChannelPrivateKey entry;
720 if (!client || !conn || !channel)
723 if (!channel->internal.private_keys)
726 list = silc_dlist_init();
730 silc_dlist_start(channel->internal.private_keys);
731 while ((entry = silc_dlist_get(channel->internal.private_keys)))
732 silc_dlist_add(list, entry);
737 /* Sets the `key' to be used as current channel private key on the
738 `channel'. Packet sent after calling this function will be secured
741 void silc_client_current_channel_private_key(SilcClient client,
742 SilcClientConnection conn,
743 SilcChannelEntry channel,
744 SilcChannelPrivateKey key)
748 channel->internal.curr_key = key;
749 channel->cipher = silc_cipher_get_name(key->send_key);
750 channel->hmac = silc_hmac_get_name(key->hmac);
753 /***************************** Utility routines *****************************/
755 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
756 channel indicated by the `channel'. NULL if client is not joined on
759 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
760 SilcClientEntry client_entry)
764 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
771 /* Adds client to channel. Returns TRUE if user was added or is already
772 added to the channel, FALSE on error. Must be called with both `channel'
773 and `client_entry' locked. */
775 SilcBool silc_client_add_to_channel(SilcClient client,
776 SilcClientConnection conn,
777 SilcChannelEntry channel,
778 SilcClientEntry client_entry,
783 if (silc_client_on_channel(channel, client_entry))
786 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
788 chu = silc_calloc(1, sizeof(*chu));
792 chu->client = client_entry;
793 chu->channel = channel;
796 silc_client_ref_client(client, conn, client_entry);
797 silc_client_ref_channel(client, conn, channel);
799 silc_hash_table_add(channel->user_list, client_entry, chu);
800 silc_hash_table_add(client_entry->channels, channel, chu);
805 /* Removes client from a channel. Returns FALSE if user is not on channel.
806 This handles entry locking internally. */
808 SilcBool silc_client_remove_from_channel(SilcClient client,
809 SilcClientConnection conn,
810 SilcChannelEntry channel,
811 SilcClientEntry client_entry)
815 chu = silc_client_on_channel(channel, client_entry);
819 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
821 silc_rwlock_wrlock(client_entry->internal.lock);
822 silc_rwlock_wrlock(channel->internal.lock);
824 silc_hash_table_del(chu->client->channels, chu->channel);
825 silc_hash_table_del(chu->channel->user_list, chu->client);
828 /* If channel became empty, delete it */
829 if (!silc_hash_table_count(channel->user_list))
830 silc_client_del_channel(client, conn, channel);
832 silc_rwlock_unlock(client_entry->internal.lock);
833 silc_rwlock_unlock(channel->internal.lock);
835 silc_client_unref_client(client, conn, client_entry);
836 silc_client_unref_channel(client, conn, channel);
841 /* Removes a client entry from all channels it has joined. This handles
842 entry locking internally. */
844 void silc_client_remove_from_channels(SilcClient client,
845 SilcClientConnection conn,
846 SilcClientEntry client_entry)
848 SilcHashTableList htl;
851 if (!silc_hash_table_count(client_entry->channels))
854 SILC_LOG_DEBUG(("Remove client from all joined channels"));
856 silc_rwlock_wrlock(client_entry->internal.lock);
858 silc_hash_table_list(client_entry->channels, &htl);
859 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
860 silc_rwlock_wrlock(chu->channel->internal.lock);
862 silc_hash_table_del(chu->client->channels, chu->channel);
863 silc_hash_table_del(chu->channel->user_list, chu->client);
865 /* If channel became empty, delete it */
866 if (!silc_hash_table_count(chu->channel->user_list))
867 silc_client_del_channel(client, conn, chu->channel);
869 silc_rwlock_unlock(chu->channel->internal.lock);
871 silc_client_unref_client(client, conn, chu->client);
872 silc_client_unref_channel(client, conn, chu->channel);
876 silc_rwlock_unlock(client_entry->internal.lock);
878 silc_hash_table_list_reset(&htl);
881 /* Empties channel from users. This handles entry locking internally. */
883 void silc_client_empty_channel(SilcClient client,
884 SilcClientConnection conn,
885 SilcChannelEntry channel)
887 SilcHashTableList htl;
890 silc_rwlock_wrlock(channel->internal.lock);
892 silc_hash_table_list(channel->user_list, &htl);
893 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
894 silc_hash_table_del(chu->client->channels, chu->channel);
895 silc_hash_table_del(chu->channel->user_list, chu->client);
896 silc_client_unref_client(client, conn, chu->client);
897 silc_client_unref_channel(client, conn, chu->channel);
901 silc_rwlock_unlock(channel->internal.lock);
903 silc_hash_table_list_reset(&htl);
906 /* Save public keys to channel public key list. Removes keys that are
907 marked to be removed. Must be called with `channel' locked. */
909 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
910 unsigned char *chpk_list,
911 SilcUInt32 chpk_list_len,
914 SilcArgumentDecodedList a, b;
919 /* Remove all channel public keys */
920 if (!channel->channel_pubkeys)
923 silc_dlist_start(channel->channel_pubkeys);
924 while ((b = silc_dlist_get(channel->channel_pubkeys)))
925 silc_dlist_del(channel->channel_pubkeys, b);
927 silc_dlist_uninit(channel->channel_pubkeys);
928 channel->channel_pubkeys = NULL;
933 /* Parse channel public key list and add or remove public keys */
934 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
935 SILC_ARGUMENT_PUBLIC_KEY);
939 if (!channel->channel_pubkeys) {
940 channel->channel_pubkeys = silc_dlist_init();
941 if (!channel->channel_pubkeys) {
942 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
947 silc_dlist_start(chpks);
948 while ((a = silc_dlist_get(chpks))) {
950 silc_dlist_start(channel->channel_pubkeys);
951 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
952 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
958 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
959 silc_dlist_add(channel->channel_pubkeys, a);
960 silc_dlist_del(chpks, a);
961 } else if (a->arg_type == 0x01 && found) {
962 silc_dlist_del(channel->channel_pubkeys, b);
966 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);