Memory leak fixes.
[silc.git] / lib / silcclient / client_channel.c
1 /*
2
3   client_channel.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Channel Message Send ****************************/
26
27 /* Sends channel message to `channel'. */
28
29 SilcBool silc_client_send_channel_message(SilcClient client,
30                                           SilcClientConnection conn,
31                                           SilcChannelEntry channel,
32                                           SilcChannelPrivateKey key,
33                                           SilcMessageFlags flags,
34                                           SilcHash hash,
35                                           unsigned char *data,
36                                           SilcUInt32 data_len)
37 {
38   SilcChannelUser chu;
39   SilcBuffer buffer;
40   SilcCipher cipher;
41   SilcHmac hmac;
42   SilcBool ret;
43   SilcID sid, rid;
44
45   SILC_LOG_DEBUG(("Sending channel message"));
46
47   if (silc_unlikely(!client || !conn || !channel))
48     return FALSE;
49   if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
50     return FALSE;
51   if (silc_unlikely(conn->internal->disconnected))
52     return FALSE;
53
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");
59     return FALSE;
60   }
61
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 &&
64                     !chu->mode))
65     return FALSE;
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)))
69     return FALSE;
70   if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
71     return FALSE;
72
73   /* Take the key to be used */
74   if (channel->internal.private_keys) {
75     if (key) {
76       /* Use key application specified */
77       cipher = key->cipher;
78       hmac = key->hmac;
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);
91       cipher = key->cipher;
92       hmac = key->hmac;
93
94       /* Use this key as current private key */
95       channel->internal.curr_key = key;
96     } else {
97       /* Use normal channel key generated by the server */
98       cipher = channel->internal.send_key;
99       hmac = channel->internal.hmac;
100     }
101   } else {
102     /* Use normal channel key generated by the server */
103     cipher = channel->internal.send_key;
104     hmac = channel->internal.hmac;
105   }
106
107   if (silc_unlikely(!cipher || !hmac)) {
108     SILC_LOG_ERROR(("No cipher and HMAC for channel"));
109     return FALSE;
110   }
111
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,
120                                        NULL);
121   if (silc_unlikely(!buffer)) {
122     SILC_LOG_ERROR(("Error encoding channel message"));
123     return FALSE;
124   }
125
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);
130
131   silc_buffer_free(buffer);
132   return ret;
133 }
134
135 /************************* Channel Message Receive **************************/
136
137 /* Client resolving callback.  Continues with the channel message processing */
138
139 static void silc_client_channel_message_resolved(SilcClient client,
140                                                  SilcClientConnection conn,
141                                                  SilcStatus status,
142                                                  SilcDList clients,
143                                                  void *context)
144 {
145   /* If no client found, ignore the channel message, a silent error */
146   if (!clients)
147     silc_fsm_next(context, silc_client_channel_message_error);
148
149   /* Continue processing the channel message packet */
150   SILC_FSM_CALL_CONTINUE(context);
151 }
152
153 /* Process received channel message */
154
155 SILC_FSM_STATE(silc_client_channel_message)
156 {
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;
169
170   SILC_LOG_DEBUG(("Received channel message"));
171
172   SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
173                    silc_buffer_len(buffer));
174
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;
179   }
180
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;
187   }
188
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,
197                                          fsm));
198     /* NOT REACHED */
199   }
200
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;
207   }
208
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;
215   }
216
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 "
221                       "server bug"));
222     silc_fsm_next(fsm, silc_client_channel_message_error);
223     return SILC_FSM_CONTINUE;
224   }
225
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,
237                                          NULL, FALSE, NULL);
238
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)) {
243       SilcCipher cipher;
244       SilcHmac hmac;
245
246       if (!channel->internal.old_channel_keys ||
247           !silc_dlist_count(channel->internal.old_channel_keys))
248         goto out;
249
250       SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
251
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);
256         if (!hmac)
257           break;
258
259         payload = silc_message_payload_parse(silc_buffer_data(buffer),
260                                              silc_buffer_len(buffer),
261                                              FALSE, FALSE, cipher, hmac,
262                                              packet->src_id,
263                                              packet->src_id_len,
264                                              packet->dst_id,
265                                              packet->dst_id_len,
266                                              NULL, FALSE, NULL);
267         if (payload)
268           break;
269       }
270       if (!payload)
271         goto out;
272     }
273   } else {
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),
279                                            FALSE, FALSE,
280                                            channel->internal.receive_key,
281                                            channel->internal.hmac,
282                                            packet->src_id,
283                                            packet->src_id_len,
284                                            packet->dst_id,
285                                            packet->dst_id_len,
286                                            NULL, FALSE, NULL);
287
288     if (!payload) {
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,
296                                              packet->src_id_len,
297                                              packet->dst_id,
298                                              packet->dst_id_len,
299                                              NULL, FALSE, NULL);
300         if (payload)
301           break;
302       }
303       if (key == SILC_LIST_END)
304         goto out;
305     }
306   }
307
308   message = silc_message_get_data(payload, &message_len);
309
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);
315
316  out:
317   silc_client_unref_client(client, conn, client_entry);
318   silc_client_unref_channel(client, conn, channel);
319   if (payload)
320     silc_message_payload_free(payload);
321   return SILC_FSM_FINISH;
322 }
323
324 /* Channel message error. */
325
326 SILC_FSM_STATE(silc_client_channel_message_error)
327 {
328   SilcPacket packet = state_context;
329   silc_packet_free(packet);
330   return SILC_FSM_FINISH;
331 }
332
333 /******************************* Channel Key ********************************/
334
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
337    in the list. */
338
339 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
340 {
341   SilcChannelEntry channel = (SilcChannelEntry)context;
342   SilcCipher key;
343   SilcHmac hmac;
344
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);
348     if (key) {
349       silc_dlist_del(channel->internal.old_channel_keys, key);
350       silc_cipher_free(key);
351     }
352   }
353
354   if (channel->internal.old_hmacs) {
355     silc_dlist_start(channel->internal.old_hmacs);
356     hmac = silc_dlist_get(channel->internal.old_hmacs);
357     if (hmac) {
358       silc_dlist_del(channel->internal.old_hmacs, hmac);
359       silc_hmac_free(hmac);
360     }
361   }
362 }
363
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. */
366
367 SilcBool silc_client_save_channel_key(SilcClient client,
368                                       SilcClientConnection conn,
369                                       SilcBuffer key_payload,
370                                       SilcChannelEntry channel)
371 {
372   unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
373   SilcUInt32 tmp_len;
374   SilcChannelID id;
375   SilcChannelKeyPayload payload;
376
377   SILC_LOG_DEBUG(("New channel key"));
378
379   payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
380                                            silc_buffer_len(key_payload));
381   if (!payload)
382     return FALSE;
383
384   id_string = silc_channel_key_get_id(payload, &tmp_len);
385   if (!id_string) {
386     silc_channel_key_payload_free(payload);
387     return FALSE;
388   }
389
390   if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
391     silc_channel_key_payload_free(payload);
392     return FALSE;
393   }
394
395   /* Find channel. */
396   if (!channel) {
397     channel = silc_client_get_channel_by_id(client, conn, &id);
398     if (!channel) {
399       SILC_LOG_DEBUG(("Key for unknown channel"));
400       silc_channel_key_payload_free(payload);
401       return FALSE;
402     }
403   } else {
404     silc_client_ref_channel(client, conn, channel);
405   }
406
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,
420                                    channel, 15, 0);
421   }
422
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(
427                            conn->client, conn,
428                            SILC_CLIENT_MESSAGE_AUDIT,
429                            "Cannot talk to channel: unsupported cipher %s",
430                            cipher);
431     silc_client_unref_channel(client, conn, channel);
432     silc_channel_key_payload_free(payload);
433     return FALSE;
434   }
435   if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
436     client->internal->ops->say(
437                            conn->client, conn,
438                            SILC_CLIENT_MESSAGE_AUDIT,
439                            "Cannot talk to channel: unsupported cipher %s",
440                            cipher);
441     silc_client_unref_channel(client, conn, channel);
442     silc_channel_key_payload_free(payload);
443     return FALSE;
444   }
445
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);
450
451   /* Get channel HMAC */
452   hmac = (channel->internal.hmac ?
453           (char *)silc_hmac_get_name(channel->internal.hmac) :
454           SILC_DEFAULT_HMAC);
455   if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
456     client->internal->ops->say(
457                            conn->client, conn,
458                            SILC_CLIENT_MESSAGE_AUDIT,
459                            "Cannot talk to channel: unsupported HMAC %s",
460                            hmac);
461     silc_client_unref_channel(client, conn, channel);
462     silc_channel_key_payload_free(payload);
463     return FALSE;
464   }
465
466   /* Set HMAC key */
467   silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
468                  tmp_len, hash);
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);
473
474   silc_client_unref_channel(client, conn, channel);
475
476   return TRUE;
477 }
478
479 /* Received channel key packet.  The key will replace old channel key. */
480
481 SILC_FSM_STATE(silc_client_channel_key)
482 {
483   SilcClientConnection conn = fsm_context;
484   SilcClient client = conn->client;
485   SilcPacket packet = state_context;
486
487   SILC_LOG_DEBUG(("Received channel key"));
488
489   /* Save the key */
490   silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
491   silc_packet_free(packet);
492
493   return SILC_FSM_FINISH;
494 }
495
496 /**************************** Channel Private Key ***************************/
497
498 /* Add new channel private key */
499
500 SilcBool silc_client_add_channel_private_key(SilcClient client,
501                                              SilcClientConnection conn,
502                                              SilcChannelEntry channel,
503                                              const char *name,
504                                              char *cipher,
505                                              char *hmac,
506                                              unsigned char *key,
507                                              SilcUInt32 key_len,
508                                              SilcChannelPrivateKey *ret_key)
509 {
510   SilcChannelPrivateKey entry;
511   unsigned char hash[SILC_HASH_MAXLEN];
512   SilcSKEKeyMaterial keymat;
513
514   if (!client || !conn || !channel)
515     return FALSE;
516
517   if (!cipher)
518     cipher = SILC_DEFAULT_CIPHER;
519   if (!hmac)
520     hmac = SILC_DEFAULT_HMAC;
521
522   if (!silc_cipher_is_supported(cipher))
523     return FALSE;
524   if (!silc_hmac_is_supported(hmac))
525     return FALSE;
526
527   if (!channel->internal.private_keys) {
528     channel->internal.private_keys = silc_dlist_init();
529     if (!channel->internal.private_keys)
530       return FALSE;
531   }
532
533   /* Produce the key material */
534   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
535                                               conn->internal->sha1hash);
536   if (!keymat)
537     return FALSE;
538
539   /* Save the key */
540   entry = silc_calloc(1, sizeof(*entry));
541   if (!entry) {
542     silc_ske_free_key_material(keymat);
543     return FALSE;
544   }
545   entry->name = name ? strdup(name) : NULL;
546
547   /* Allocate the cipher and set the key */
548   if (!silc_cipher_alloc(cipher, &entry->cipher)) {
549     silc_free(entry);
550     silc_free(entry->name);
551     silc_ske_free_key_material(keymat);
552     return FALSE;
553   }
554   silc_cipher_set_key(entry->cipher, keymat->send_enc_key,
555                       keymat->enc_key_len, TRUE);
556
557   /* Generate HMAC key from the channel key data and set it */
558   if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
559     silc_free(entry);
560     silc_free(entry->name);
561     silc_cipher_free(entry->cipher);
562     silc_ske_free_key_material(keymat);
563     return FALSE;
564   }
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));
570
571   /* Add to the private keys list */
572   silc_dlist_add(channel->internal.private_keys, entry);
573
574   if (!channel->internal.curr_key)
575     channel->internal.curr_key = entry;
576
577   /* Free the key material */
578   silc_ske_free_key_material(keymat);
579
580   if (ret_key)
581     *ret_key = entry;
582
583   return TRUE;
584 }
585
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. */
589
590 SilcBool silc_client_del_channel_private_keys(SilcClient client,
591                                               SilcClientConnection conn,
592                                               SilcChannelEntry channel)
593 {
594   SilcChannelPrivateKey entry;
595
596   if (!client || !conn || !channel)
597     return FALSE;
598
599   if (!channel->internal.private_keys)
600     return FALSE;
601
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);
608     silc_free(entry);
609   }
610
611   channel->internal.curr_key = NULL;
612
613   silc_dlist_uninit(channel->internal.private_keys);
614   channel->internal.private_keys = NULL;
615
616   return TRUE;
617 }
618
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. */
624
625 SilcBool silc_client_del_channel_private_key(SilcClient client,
626                                              SilcClientConnection conn,
627                                              SilcChannelEntry channel,
628                                              SilcChannelPrivateKey key)
629 {
630   SilcChannelPrivateKey entry;
631
632   if (!client || !conn || !channel)
633     return FALSE;
634
635   if (!channel->internal.private_keys)
636     return FALSE;
637
638   silc_dlist_start(channel->internal.private_keys);
639   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
640     if (entry != key)
641       continue;
642
643     if (channel->internal.curr_key == entry)
644       channel->internal.curr_key = NULL;
645
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);
650     silc_free(entry);
651
652     if (silc_dlist_count(channel->internal.private_keys) == 0) {
653       silc_dlist_uninit(channel->internal.private_keys);
654       channel->internal.private_keys = NULL;
655     }
656
657     return TRUE;
658   }
659
660   return FALSE;
661 }
662
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. */
668
669 SilcDList silc_client_list_channel_private_keys(SilcClient client,
670                                                 SilcClientConnection conn,
671                                                 SilcChannelEntry channel)
672 {
673   SilcChannelPrivateKey entry;
674   SilcDList list;
675
676   if (!client || !conn || !channel)
677     return FALSE;
678
679   if (!channel->internal.private_keys)
680     return NULL;
681
682   list = silc_dlist_init();
683   if (!list)
684     return NULL;
685
686   silc_dlist_start(channel->internal.private_keys);
687   while ((entry = silc_dlist_get(channel->internal.private_keys)))
688     silc_dlist_add(list, entry);
689
690   return list;
691 }
692
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
695    with `key'. */
696
697 void silc_client_current_channel_private_key(SilcClient client,
698                                              SilcClientConnection conn,
699                                              SilcChannelEntry channel,
700                                              SilcChannelPrivateKey key)
701 {
702   if (!channel)
703     return;
704   channel->internal.curr_key = key;
705 }
706
707 /***************************** Utility routines *****************************/
708
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
711    the channel. */
712
713 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
714                                        SilcClientEntry client_entry)
715 {
716   SilcChannelUser chu;
717
718   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
719                            (void *)&chu))
720     return chu;
721
722   return NULL;
723 }
724
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. */
728
729 SilcBool silc_client_add_to_channel(SilcClient client,
730                                     SilcClientConnection conn,
731                                     SilcChannelEntry channel,
732                                     SilcClientEntry client_entry,
733                                     SilcUInt32 cumode)
734 {
735   SilcChannelUser chu;
736
737   if (silc_client_on_channel(channel, client_entry))
738     return TRUE;
739
740   SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
741
742   chu = silc_calloc(1, sizeof(*chu));
743   if (!chu)
744     return FALSE;
745
746   chu->client = client_entry;
747   chu->channel = channel;
748   chu->mode = cumode;
749
750   silc_client_ref_client(client, conn, client_entry);
751   silc_client_ref_channel(client, conn, channel);
752
753   silc_hash_table_add(channel->user_list, client_entry, chu);
754   silc_hash_table_add(client_entry->channels, channel, chu);
755
756   return TRUE;
757 }
758
759 /* Removes client from a channel.  Returns FALSE if user is not on channel.
760    This handles entry locking internally. */
761
762 SilcBool silc_client_remove_from_channel(SilcClient client,
763                                          SilcClientConnection conn,
764                                          SilcChannelEntry channel,
765                                          SilcClientEntry client_entry)
766 {
767   SilcChannelUser chu;
768
769   chu = silc_client_on_channel(channel, client_entry);
770   if (!chu)
771     return FALSE;
772
773   SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
774
775   silc_rwlock_wrlock(client_entry->internal.lock);
776   silc_rwlock_wrlock(channel->internal.lock);
777
778   silc_hash_table_del(chu->client->channels, chu->channel);
779   silc_hash_table_del(chu->channel->user_list, chu->client);
780   silc_free(chu);
781
782   /* If channel became empty, delete it */
783   if (!silc_hash_table_count(channel->user_list))
784     silc_client_del_channel(client, conn, channel);
785
786   silc_rwlock_unlock(client_entry->internal.lock);
787   silc_rwlock_unlock(channel->internal.lock);
788
789   silc_client_unref_client(client, conn, client_entry);
790   silc_client_unref_channel(client, conn, channel);
791
792   return TRUE;
793 }
794
795 /* Removes a client entry from all channels it has joined.  This handles
796    entry locking internally. */
797
798 void silc_client_remove_from_channels(SilcClient client,
799                                       SilcClientConnection conn,
800                                       SilcClientEntry client_entry)
801 {
802   SilcHashTableList htl;
803   SilcChannelUser chu;
804
805   if (!silc_hash_table_count(client_entry->channels))
806     return;
807
808   SILC_LOG_DEBUG(("Remove client from all joined channels"));
809
810   silc_rwlock_wrlock(client_entry->internal.lock);
811
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);
815
816     silc_hash_table_del(chu->client->channels, chu->channel);
817     silc_hash_table_del(chu->channel->user_list, chu->client);
818
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);
822
823     silc_rwlock_unlock(chu->channel->internal.lock);
824
825     silc_client_unref_client(client, conn, chu->client);
826     silc_client_unref_channel(client, conn, chu->channel);
827     silc_free(chu);
828   }
829
830   silc_rwlock_unlock(client_entry->internal.lock);
831
832   silc_hash_table_list_reset(&htl);
833 }
834
835 /* Empties channel from users.  This handles entry locking internally. */
836
837 void silc_client_empty_channel(SilcClient client,
838                                SilcClientConnection conn,
839                                SilcChannelEntry channel)
840 {
841   SilcHashTableList htl;
842   SilcChannelUser chu;
843
844   silc_rwlock_wrlock(channel->internal.lock);
845
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);
852     silc_free(chu);
853   }
854
855   silc_rwlock_unlock(channel->internal.lock);
856
857   silc_hash_table_list_reset(&htl);
858 }
859
860 /* Save public keys to channel public key list.  Removes keys that are
861    marked to be removed.  Must be called with `channel' locked. */
862
863 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
864                                               unsigned char *chpk_list,
865                                               SilcUInt32 chpk_list_len)
866 {
867   SilcArgumentDecodedList a, b;
868   SilcDList chpks;
869   SilcBool found;
870
871   chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
872                                            SILC_ARGUMENT_PUBLIC_KEY);
873   if (!chpks)
874     return FALSE;
875
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);
880       return FALSE;
881     }
882   }
883
884   silc_dlist_start(chpks);
885   while ((a = silc_dlist_get(chpks))) {
886     found = FALSE;
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)) {
890         found = TRUE;
891         break;
892       }
893     }
894
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);
900     }
901   }
902
903   silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
904
905   return TRUE;
906 }