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 ****************************/
27 /* Sends channel message to `channel'. */
29 SilcBool silc_client_send_channel_message(SilcClient client,
30 SilcClientConnection conn,
31 SilcChannelEntry channel,
32 SilcChannelPrivateKey key,
33 SilcMessageFlags flags,
45 SILC_LOG_DEBUG(("Sending channel message"));
47 if (silc_unlikely(!client || !conn || !channel))
49 if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
51 if (silc_unlikely(conn->internal->disconnected))
54 chu = silc_client_on_channel(channel, conn->local_entry);
55 if (silc_unlikely(!chu)) {
56 client->internal->ops->say(conn->client, conn,
57 SILC_CLIENT_MESSAGE_AUDIT,
58 "Cannot talk to channel: not joined");
62 /* Check if it is allowed to send messages to this channel by us. */
63 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
66 if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
67 chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
68 !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
70 if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
73 /* Take the key to be used */
74 if (channel->internal.private_keys) {
76 /* Use key application specified */
79 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
80 channel->internal.curr_key) {
81 /* Use current private key */
82 cipher = channel->internal.curr_key->cipher;
83 hmac = channel->internal.curr_key->hmac;
84 } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
85 !channel->internal.curr_key &&
86 channel->internal.private_keys) {
87 /* Use just some private key since we don't know what to use
88 and private keys are set. */
89 silc_dlist_start(channel->internal.private_keys);
90 key = silc_dlist_get(channel->internal.private_keys);
94 /* Use this key as current private key */
95 channel->internal.curr_key = key;
97 /* Use normal channel key generated by the server */
98 cipher = channel->internal.send_key;
99 hmac = channel->internal.hmac;
102 /* Use normal channel key generated by the server */
103 cipher = channel->internal.send_key;
104 hmac = channel->internal.hmac;
107 if (silc_unlikely(!cipher || !hmac)) {
108 SILC_LOG_ERROR(("No cipher and HMAC for channel"));
112 /* Encode the message payload. This also encrypts the message payload. */
113 sid.type = SILC_ID_CLIENT;
114 sid.u.client_id = chu->client->id;
115 rid.type = SILC_ID_CHANNEL;
116 rid.u.channel_id = chu->channel->id;
117 buffer = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
118 cipher, hmac, client->rng, NULL,
119 conn->private_key, hash, &sid, &rid,
121 if (silc_unlikely(!buffer)) {
122 SILC_LOG_ERROR(("Error encoding channel message"));
126 /* Send the channel message */
127 ret = silc_packet_send_ext(conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
128 0, NULL, SILC_ID_CHANNEL, &channel->id,
129 silc_buffer_datalen(buffer), NULL, NULL);
131 silc_buffer_free(buffer);
135 /************************* Channel Message Receive **************************/
137 /* Client resolving callback. Continues with the channel message processing */
139 static void silc_client_channel_message_resolved(SilcClient client,
140 SilcClientConnection conn,
145 /* If no client found, ignore the channel message, a silent error */
147 silc_fsm_next(context, silc_client_channel_message_error);
149 /* Continue processing the channel message packet */
150 SILC_FSM_CALL_CONTINUE(context);
153 /* Process received channel message */
155 SILC_FSM_STATE(silc_client_channel_message)
157 SilcClientConnection conn = fsm_context;
158 SilcClient client = conn->client;
159 SilcPacket packet = state_context;
160 SilcBuffer buffer = &packet->buffer;
161 SilcMessagePayload payload = NULL;
162 SilcChannelEntry channel;
163 SilcClientEntry client_entry;
164 SilcClientID remote_id;
165 SilcChannelID channel_id;
166 unsigned char *message;
167 SilcUInt32 message_len;
168 SilcChannelPrivateKey key = NULL;
170 SILC_LOG_DEBUG(("Received channel message"));
172 SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
173 silc_buffer_len(buffer));
175 if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
176 /** Invalid packet */
177 silc_fsm_next(fsm, silc_client_channel_message_error);
178 return SILC_FSM_CONTINUE;
181 if (silc_unlikely(!silc_id_str2id(packet->src_id,
182 packet->src_id_len, SILC_ID_CLIENT,
183 &remote_id, sizeof(remote_id)))) {
184 /** Invalid source ID */
185 silc_fsm_next(fsm, silc_client_channel_message_error);
186 return SILC_FSM_CONTINUE;
189 /* Get sender client entry */
190 client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
191 if (!client_entry || !client_entry->internal.valid) {
192 /** Resolve client info */
193 silc_client_unref_client(client, conn, client_entry);
194 SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
195 client, conn, &remote_id, NULL,
196 silc_client_channel_message_resolved,
201 if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
202 SILC_ID_CHANNEL, &channel_id,
203 sizeof(channel_id)))) {
204 /** Invalid destination ID */
205 silc_fsm_next(fsm, silc_client_channel_message_error);
206 return SILC_FSM_CONTINUE;
209 /* Find the channel */
210 channel = silc_client_get_channel_by_id(client, conn, &channel_id);
211 if (silc_unlikely(!channel)) {
212 /** Unknown channel */
213 silc_fsm_next(fsm, silc_client_channel_message_error);
214 return SILC_FSM_CONTINUE;
217 /* Check that user is on channel */
218 if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
219 /** User not on channel */
220 SILC_LOG_WARNING(("Message from user not on channel, client or "
222 silc_fsm_next(fsm, silc_client_channel_message_error);
223 return SILC_FSM_CONTINUE;
226 /* If there is no channel private key then just decrypt the message
227 with the channel key. If private keys are set then just go through
228 all private keys and check what decrypts correctly. */
229 if (!channel->internal.private_keys) {
230 /* Parse the channel message payload. This also decrypts the payload */
231 payload = silc_message_payload_parse(silc_buffer_data(buffer),
232 silc_buffer_len(buffer), FALSE,
233 FALSE, channel->internal.receive_key,
234 channel->internal.hmac,
235 packet->src_id, packet->src_id_len,
236 packet->dst_id, packet->dst_id_len,
239 /* If decryption failed and we have just performed channel key rekey
240 we will use the old key in decryption. If that fails too then we
241 cannot do more and will drop the packet. */
242 if (silc_unlikely(!payload)) {
246 if (!channel->internal.old_channel_keys ||
247 !silc_dlist_count(channel->internal.old_channel_keys))
250 SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
252 silc_dlist_end(channel->internal.old_channel_keys);
253 silc_dlist_end(channel->internal.old_hmacs);
254 while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
255 hmac = silc_dlist_get(channel->internal.old_hmacs);
259 payload = silc_message_payload_parse(silc_buffer_data(buffer),
260 silc_buffer_len(buffer),
261 FALSE, FALSE, cipher, hmac,
274 /* If the private key mode is not set on the channel then try the actual
275 channel key first before trying private keys. */
276 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
277 payload = silc_message_payload_parse(silc_buffer_data(buffer),
278 silc_buffer_len(buffer),
280 channel->internal.receive_key,
281 channel->internal.hmac,
289 silc_dlist_start(channel->internal.private_keys);
290 while ((key = silc_dlist_get(channel->internal.private_keys))) {
291 /* Parse the message payload. This also decrypts the payload */
292 payload = silc_message_payload_parse(silc_buffer_data(buffer),
293 silc_buffer_len(buffer),
294 FALSE, FALSE, key->cipher,
295 key->hmac, packet->src_id,
303 if (key == SILC_LIST_END)
308 message = silc_message_get_data(payload, &message_len);
310 /* Pass the message to application */
311 client->internal->ops->channel_message(
312 client, conn, client_entry, channel, payload,
313 key, silc_message_get_flags(payload),
314 message, message_len);
317 silc_client_unref_client(client, conn, client_entry);
318 silc_client_unref_channel(client, conn, channel);
320 silc_message_payload_free(payload);
321 return SILC_FSM_FINISH;
324 /* Channel message error. */
326 SILC_FSM_STATE(silc_client_channel_message_error)
328 SilcPacket packet = state_context;
329 silc_packet_free(packet);
330 return SILC_FSM_FINISH;
333 /******************************* Channel Key ********************************/
335 /* Timeout callback that is called after a short period of time after the
336 new channel key has been created. This removes the first channel key
339 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
341 SilcChannelEntry channel = (SilcChannelEntry)context;
345 if (channel->internal.old_channel_keys) {
346 silc_dlist_start(channel->internal.old_channel_keys);
347 key = silc_dlist_get(channel->internal.old_channel_keys);
349 silc_dlist_del(channel->internal.old_channel_keys, key);
350 silc_cipher_free(key);
354 if (channel->internal.old_hmacs) {
355 silc_dlist_start(channel->internal.old_hmacs);
356 hmac = silc_dlist_get(channel->internal.old_hmacs);
358 silc_dlist_del(channel->internal.old_hmacs, hmac);
359 silc_hmac_free(hmac);
364 /* Saves channel key from encoded `key_payload'. This is used when we receive
365 Channel Key Payload and when we are processing JOIN command reply. */
367 SilcBool silc_client_save_channel_key(SilcClient client,
368 SilcClientConnection conn,
369 SilcBuffer key_payload,
370 SilcChannelEntry channel)
372 unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
375 SilcChannelKeyPayload payload;
377 SILC_LOG_DEBUG(("New channel key"));
379 payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
380 silc_buffer_len(key_payload));
384 id_string = silc_channel_key_get_id(payload, &tmp_len);
386 silc_channel_key_payload_free(payload);
390 if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
391 silc_channel_key_payload_free(payload);
397 channel = silc_client_get_channel_by_id(client, conn, &id);
399 SILC_LOG_DEBUG(("Key for unknown channel"));
400 silc_channel_key_payload_free(payload);
404 silc_client_ref_channel(client, conn, channel);
407 /* Save the old key for a short period of time so that we can decrypt
408 channel message even after the rekey if some client would be sending
409 messages with the old key after the rekey. */
410 if (!channel->internal.old_channel_keys)
411 channel->internal.old_channel_keys = silc_dlist_init();
412 if (!channel->internal.old_hmacs)
413 channel->internal.old_hmacs = silc_dlist_init();
414 if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
415 silc_dlist_add(channel->internal.old_channel_keys,
416 channel->internal.receive_key);
417 silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
418 silc_schedule_task_add_timeout(client->schedule,
419 silc_client_save_channel_key_rekey,
423 /* Get channel cipher */
424 cipher = silc_channel_key_get_cipher(payload, NULL);
425 if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
426 client->internal->ops->say(
428 SILC_CLIENT_MESSAGE_AUDIT,
429 "Cannot talk to channel: unsupported cipher %s",
431 silc_client_unref_channel(client, conn, channel);
432 silc_channel_key_payload_free(payload);
435 if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
436 client->internal->ops->say(
438 SILC_CLIENT_MESSAGE_AUDIT,
439 "Cannot talk to channel: unsupported cipher %s",
441 silc_client_unref_channel(client, conn, channel);
442 silc_channel_key_payload_free(payload);
446 /* Set the cipher key. Both sending and receiving keys are same */
447 key = silc_channel_key_get_key(payload, &tmp_len);
448 silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
449 silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);
451 /* Get channel HMAC */
452 hmac = (channel->internal.hmac ?
453 (char *)silc_hmac_get_name(channel->internal.hmac) :
455 if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
456 client->internal->ops->say(
458 SILC_CLIENT_MESSAGE_AUDIT,
459 "Cannot talk to channel: unsupported HMAC %s",
461 silc_client_unref_channel(client, conn, channel);
462 silc_channel_key_payload_free(payload);
467 silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
469 silc_hmac_set_key(channel->internal.hmac, hash,
470 silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
471 memset(hash, 0, sizeof(hash));
472 silc_channel_key_payload_free(payload);
474 silc_client_unref_channel(client, conn, channel);
479 /* Received channel key packet. The key will replace old channel key. */
481 SILC_FSM_STATE(silc_client_channel_key)
483 SilcClientConnection conn = fsm_context;
484 SilcClient client = conn->client;
485 SilcPacket packet = state_context;
487 SILC_LOG_DEBUG(("Received channel key"));
490 silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
491 silc_packet_free(packet);
493 return SILC_FSM_FINISH;
496 /**************************** Channel Private Key ***************************/
498 /* Add new channel private key */
500 SilcBool silc_client_add_channel_private_key(SilcClient client,
501 SilcClientConnection conn,
502 SilcChannelEntry channel,
508 SilcChannelPrivateKey *ret_key)
510 SilcChannelPrivateKey entry;
511 unsigned char hash[SILC_HASH_MAXLEN];
512 SilcSKEKeyMaterial keymat;
514 if (!client || !conn || !channel)
518 cipher = SILC_DEFAULT_CIPHER;
520 hmac = SILC_DEFAULT_HMAC;
522 if (!silc_cipher_is_supported(cipher))
524 if (!silc_hmac_is_supported(hmac))
527 if (!channel->internal.private_keys) {
528 channel->internal.private_keys = silc_dlist_init();
529 if (!channel->internal.private_keys)
533 /* Produce the key material */
534 keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
535 conn->internal->sha1hash);
540 entry = silc_calloc(1, sizeof(*entry));
542 silc_ske_free_key_material(keymat);
545 entry->name = name ? strdup(name) : NULL;
547 /* Allocate the cipher and set the key */
548 if (!silc_cipher_alloc(cipher, &entry->cipher)) {
550 silc_free(entry->name);
551 silc_ske_free_key_material(keymat);
554 silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
555 keymat->enc_key_len, TRUE);
557 /* Generate HMAC key from the channel key data and set it */
558 if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
560 silc_free(entry->name);
561 silc_cipher_free(entry->cipher);
562 silc_ske_free_key_material(keymat);
565 silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
566 keymat->enc_key_len / 8, hash);
567 silc_hmac_set_key(entry->hmac, hash,
568 silc_hash_len(silc_hmac_get_hash(entry->hmac)));
569 memset(hash, 0, sizeof(hash));
571 /* Add to the private keys list */
572 silc_dlist_add(channel->internal.private_keys, entry);
574 if (!channel->internal.curr_key)
575 channel->internal.curr_key = entry;
577 /* Free the key material */
578 silc_ske_free_key_material(keymat);
586 /* Removes all private keys from the `channel'. The old channel key is used
587 after calling this to protect the channel messages. Returns FALSE on
588 on error, TRUE otherwise. */
590 SilcBool silc_client_del_channel_private_keys(SilcClient client,
591 SilcClientConnection conn,
592 SilcChannelEntry channel)
594 SilcChannelPrivateKey entry;
596 if (!client || !conn || !channel)
599 if (!channel->internal.private_keys)
602 silc_dlist_start(channel->internal.private_keys);
603 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
604 silc_dlist_del(channel->internal.private_keys, entry);
605 silc_free(entry->name);
606 silc_cipher_free(entry->cipher);
607 silc_hmac_free(entry->hmac);
611 channel->internal.curr_key = NULL;
613 silc_dlist_uninit(channel->internal.private_keys);
614 channel->internal.private_keys = NULL;
619 /* Removes and frees private key `key' from the channel `channel'. The `key'
620 is retrieved by calling the function silc_client_list_channel_private_keys.
621 The key is not used after this. If the key was last private key then the
622 old channel key is used hereafter to protect the channel messages. This
623 returns FALSE on error, TRUE otherwise. */
625 SilcBool silc_client_del_channel_private_key(SilcClient client,
626 SilcClientConnection conn,
627 SilcChannelEntry channel,
628 SilcChannelPrivateKey key)
630 SilcChannelPrivateKey entry;
632 if (!client || !conn || !channel)
635 if (!channel->internal.private_keys)
638 silc_dlist_start(channel->internal.private_keys);
639 while ((entry = silc_dlist_get(channel->internal.private_keys))) {
643 if (channel->internal.curr_key == entry)
644 channel->internal.curr_key = NULL;
646 silc_dlist_del(channel->internal.private_keys, entry);
647 silc_free(entry->name);
648 silc_cipher_free(entry->cipher);
649 silc_hmac_free(entry->hmac);
652 if (silc_dlist_count(channel->internal.private_keys) == 0) {
653 silc_dlist_uninit(channel->internal.private_keys);
654 channel->internal.private_keys = NULL;
663 /* Returns array (pointers) of private keys associated to the `channel'.
664 The caller must free the array by calling the function
665 silc_client_free_channel_private_keys. The pointers in the array may be
666 used to delete the specific key by giving the pointer as argument to the
667 function silc_client_del_channel_private_key. */
669 SilcDList silc_client_list_channel_private_keys(SilcClient client,
670 SilcClientConnection conn,
671 SilcChannelEntry channel)
673 SilcChannelPrivateKey entry;
676 if (!client || !conn || !channel)
679 if (!channel->internal.private_keys)
682 list = silc_dlist_init();
686 silc_dlist_start(channel->internal.private_keys);
687 while ((entry = silc_dlist_get(channel->internal.private_keys)))
688 silc_dlist_add(list, entry);
693 /* Sets the `key' to be used as current channel private key on the
694 `channel'. Packet sent after calling this function will be secured
697 void silc_client_current_channel_private_key(SilcClient client,
698 SilcClientConnection conn,
699 SilcChannelEntry channel,
700 SilcChannelPrivateKey key)
704 channel->internal.curr_key = key;
707 /***************************** Utility routines *****************************/
709 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
710 channel indicated by the `channel'. NULL if client is not joined on
713 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
714 SilcClientEntry client_entry)
718 if (silc_hash_table_find(channel->user_list, client_entry, NULL,
725 /* Adds client to channel. Returns TRUE if user was added or is already
726 added to the channel, FALSE on error. Must be called with both `channel'
727 and `client_entry' locked. */
729 SilcBool silc_client_add_to_channel(SilcClient client,
730 SilcClientConnection conn,
731 SilcChannelEntry channel,
732 SilcClientEntry client_entry,
737 if (silc_client_on_channel(channel, client_entry))
740 SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
742 chu = silc_calloc(1, sizeof(*chu));
746 chu->client = client_entry;
747 chu->channel = channel;
750 silc_client_ref_client(client, conn, client_entry);
751 silc_client_ref_channel(client, conn, channel);
753 silc_hash_table_add(channel->user_list, client_entry, chu);
754 silc_hash_table_add(client_entry->channels, channel, chu);
759 /* Removes client from a channel. Returns FALSE if user is not on channel.
760 This handles entry locking internally. */
762 SilcBool silc_client_remove_from_channel(SilcClient client,
763 SilcClientConnection conn,
764 SilcChannelEntry channel,
765 SilcClientEntry client_entry)
769 chu = silc_client_on_channel(channel, client_entry);
773 SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
775 silc_rwlock_wrlock(client_entry->internal.lock);
776 silc_rwlock_wrlock(channel->internal.lock);
778 silc_hash_table_del(chu->client->channels, chu->channel);
779 silc_hash_table_del(chu->channel->user_list, chu->client);
782 /* If channel became empty, delete it */
783 if (!silc_hash_table_count(channel->user_list))
784 silc_client_del_channel(client, conn, channel);
786 silc_rwlock_unlock(client_entry->internal.lock);
787 silc_rwlock_unlock(channel->internal.lock);
789 silc_client_unref_client(client, conn, client_entry);
790 silc_client_unref_channel(client, conn, channel);
795 /* Removes a client entry from all channels it has joined. This handles
796 entry locking internally. */
798 void silc_client_remove_from_channels(SilcClient client,
799 SilcClientConnection conn,
800 SilcClientEntry client_entry)
802 SilcHashTableList htl;
805 if (!silc_hash_table_count(client_entry->channels))
808 SILC_LOG_DEBUG(("Remove client from all joined channels"));
810 silc_rwlock_wrlock(client_entry->internal.lock);
812 silc_hash_table_list(client_entry->channels, &htl);
813 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
814 silc_rwlock_wrlock(chu->channel->internal.lock);
816 silc_hash_table_del(chu->client->channels, chu->channel);
817 silc_hash_table_del(chu->channel->user_list, chu->client);
819 /* If channel became empty, delete it */
820 if (!silc_hash_table_count(chu->channel->user_list))
821 silc_client_del_channel(client, conn, chu->channel);
823 silc_rwlock_unlock(chu->channel->internal.lock);
825 silc_client_unref_client(client, conn, chu->client);
826 silc_client_unref_channel(client, conn, chu->channel);
830 silc_rwlock_unlock(client_entry->internal.lock);
832 silc_hash_table_list_reset(&htl);
835 /* Empties channel from users. This handles entry locking internally. */
837 void silc_client_empty_channel(SilcClient client,
838 SilcClientConnection conn,
839 SilcChannelEntry channel)
841 SilcHashTableList htl;
844 silc_rwlock_wrlock(channel->internal.lock);
846 silc_hash_table_list(channel->user_list, &htl);
847 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
848 silc_hash_table_del(chu->client->channels, chu->channel);
849 silc_hash_table_del(chu->channel->user_list, chu->client);
850 silc_client_unref_client(client, conn, chu->client);
851 silc_client_unref_channel(client, conn, chu->channel);
855 silc_rwlock_unlock(channel->internal.lock);
857 silc_hash_table_list_reset(&htl);
860 /* Save public keys to channel public key list. Removes keys that are
861 marked to be removed. Must be called with `channel' locked. */
863 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
864 unsigned char *chpk_list,
865 SilcUInt32 chpk_list_len)
867 SilcArgumentDecodedList a, b;
871 chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
872 SILC_ARGUMENT_PUBLIC_KEY);
876 if (!channel->channel_pubkeys) {
877 channel->channel_pubkeys = silc_dlist_init();
878 if (!channel->channel_pubkeys) {
879 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
884 silc_dlist_start(chpks);
885 while ((a = silc_dlist_get(chpks))) {
887 silc_dlist_start(channel->channel_pubkeys);
888 while ((b = silc_dlist_get(channel->channel_pubkeys))) {
889 if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
895 if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
896 silc_dlist_add(channel->channel_pubkeys, a);
897 silc_dlist_del(chpks, a);
898 } else if (a->arg_type == 0x01 && found) {
899 silc_dlist_del(channel->channel_pubkeys, b);
903 silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);