Avoid NULL dereference when leaving a channel with a private key.
[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->send_key;
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->send_key;
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->send_key;
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->receive_key,
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   channel->cipher = silc_cipher_get_name(channel->internal.send_key);
467   channel->hmac = silc_hmac_get_name(channel->internal.hmac);
468
469   /* Set HMAC key */
470   silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
471                  tmp_len, hash);
472   silc_hmac_set_key(channel->internal.hmac, hash,
473                     silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
474   memset(hash, 0, sizeof(hash));
475   silc_channel_key_payload_free(payload);
476
477   silc_client_unref_channel(client, conn, channel);
478
479   return TRUE;
480 }
481
482 /* Received channel key packet.  The key will replace old channel key. */
483
484 SILC_FSM_STATE(silc_client_channel_key)
485 {
486   SilcClientConnection conn = fsm_context;
487   SilcClient client = conn->client;
488   SilcPacket packet = state_context;
489
490   SILC_LOG_DEBUG(("Received channel key"));
491
492   /* Save the key */
493   silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
494   silc_packet_free(packet);
495
496   return SILC_FSM_FINISH;
497 }
498
499 /**************************** Channel Private Key ***************************/
500
501 /* Add new channel private key */
502
503 SilcBool silc_client_add_channel_private_key(SilcClient client,
504                                              SilcClientConnection conn,
505                                              SilcChannelEntry channel,
506                                              const char *name,
507                                              char *cipher,
508                                              char *hmac,
509                                              unsigned char *key,
510                                              SilcUInt32 key_len,
511                                              SilcChannelPrivateKey *ret_key)
512 {
513   SilcChannelPrivateKey entry;
514   unsigned char hash[SILC_HASH_MAXLEN];
515   SilcSKEKeyMaterial keymat;
516
517   if (!client || !conn || !channel)
518     return FALSE;
519
520   if (!cipher)
521     cipher = SILC_DEFAULT_CIPHER;
522   if (!hmac)
523     hmac = SILC_DEFAULT_HMAC;
524
525   if (!silc_cipher_is_supported(cipher))
526     return FALSE;
527   if (!silc_hmac_is_supported(hmac))
528     return FALSE;
529
530   if (!channel->internal.private_keys) {
531     channel->internal.private_keys = silc_dlist_init();
532     if (!channel->internal.private_keys)
533       return FALSE;
534   }
535
536   /* Produce the key material */
537   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
538                                               conn->internal->sha1hash);
539   if (!keymat)
540     return FALSE;
541
542   /* Save the key */
543   entry = silc_calloc(1, sizeof(*entry));
544   if (!entry) {
545     silc_ske_free_key_material(keymat);
546     return FALSE;
547   }
548   entry->name = name ? strdup(name) : NULL;
549
550   /* Allocate the cipher and set the key */
551   if (!silc_cipher_alloc(cipher, &entry->send_key)) {
552     silc_free(entry);
553     silc_free(entry->name);
554     silc_ske_free_key_material(keymat);
555     return FALSE;
556   }
557   if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
558     silc_free(entry);
559     silc_free(entry->name);
560     silc_cipher_free(entry->send_key);
561     silc_ske_free_key_material(keymat);
562     return FALSE;
563   }
564   silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
565                       keymat->enc_key_len, TRUE);
566   silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
567                       keymat->enc_key_len, FALSE);
568
569   /* Generate HMAC key from the channel key data and set it */
570   if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
571     silc_free(entry);
572     silc_free(entry->name);
573     silc_cipher_free(entry->send_key);
574     silc_cipher_free(entry->receive_key);
575     silc_ske_free_key_material(keymat);
576     return FALSE;
577   }
578   silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
579                  keymat->enc_key_len / 8, hash);
580   silc_hmac_set_key(entry->hmac, hash,
581                     silc_hash_len(silc_hmac_get_hash(entry->hmac)));
582   memset(hash, 0, sizeof(hash));
583
584   /* Add to the private keys list */
585   silc_dlist_add(channel->internal.private_keys, entry);
586
587   if (!channel->internal.curr_key) {
588     channel->internal.curr_key = entry;
589     channel->cipher = silc_cipher_get_name(entry->send_key);
590     channel->hmac = silc_cipher_get_name(entry->send_key);
591   }
592
593   /* Free the key material */
594   silc_ske_free_key_material(keymat);
595
596   if (ret_key)
597     *ret_key = entry;
598
599   return TRUE;
600 }
601
602 /* Removes all private keys from the `channel'. The old channel key is used
603    after calling this to protect the channel messages. Returns FALSE on
604    on error, TRUE otherwise. */
605
606 SilcBool silc_client_del_channel_private_keys(SilcClient client,
607                                               SilcClientConnection conn,
608                                               SilcChannelEntry channel)
609 {
610   SilcChannelPrivateKey entry;
611
612   if (!client || !conn || !channel)
613     return FALSE;
614
615   if (!channel->internal.private_keys)
616     return FALSE;
617
618   silc_dlist_start(channel->internal.private_keys);
619   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
620     silc_dlist_del(channel->internal.private_keys, entry);
621     silc_free(entry->name);
622     silc_cipher_free(entry->send_key);
623     silc_cipher_free(entry->receive_key);
624     silc_hmac_free(entry->hmac);
625     silc_free(entry);
626   }
627
628   channel->internal.curr_key = NULL;
629   if (channel->internal.send_key)
630     channel->cipher = silc_cipher_get_name(channel->internal.send_key);
631   else
632     channel->cipher = NULL;
633   if (channel->internal.hmac)
634     channel->hmac = silc_hmac_get_name(channel->internal.hmac);
635   else
636     channel->hmac = NULL;
637
638   silc_dlist_uninit(channel->internal.private_keys);
639   channel->internal.private_keys = NULL;
640
641   return TRUE;
642 }
643
644 /* Removes and frees private key `key' from the channel `channel'. The `key'
645    is retrieved by calling the function silc_client_list_channel_private_keys.
646    The key is not used after this. If the key was last private key then the
647    old channel key is used hereafter to protect the channel messages. This
648    returns FALSE on error, TRUE otherwise. */
649
650 SilcBool silc_client_del_channel_private_key(SilcClient client,
651                                              SilcClientConnection conn,
652                                              SilcChannelEntry channel,
653                                              SilcChannelPrivateKey key)
654 {
655   SilcChannelPrivateKey entry;
656
657   if (!client || !conn || !channel)
658     return FALSE;
659
660   if (!channel->internal.private_keys)
661     return FALSE;
662
663   silc_dlist_start(channel->internal.private_keys);
664   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
665     if (entry != key)
666       continue;
667
668     if (channel->internal.curr_key == entry) {
669       channel->internal.curr_key = NULL;
670       channel->cipher = silc_cipher_get_name(channel->internal.send_key);
671       channel->hmac = silc_hmac_get_name(channel->internal.hmac);
672     }
673
674     silc_dlist_del(channel->internal.private_keys, entry);
675     silc_free(entry->name);
676     silc_cipher_free(entry->send_key);
677     silc_cipher_free(entry->receive_key);
678     silc_hmac_free(entry->hmac);
679     silc_free(entry);
680
681     if (silc_dlist_count(channel->internal.private_keys) == 0) {
682       silc_dlist_uninit(channel->internal.private_keys);
683       channel->internal.private_keys = NULL;
684     }
685
686     return TRUE;
687   }
688
689   return FALSE;
690 }
691
692 /* Returns array (pointers) of private keys associated to the `channel'.
693    The caller must free the array by calling the function
694    silc_client_free_channel_private_keys. The pointers in the array may be
695    used to delete the specific key by giving the pointer as argument to the
696    function silc_client_del_channel_private_key. */
697
698 SilcDList silc_client_list_channel_private_keys(SilcClient client,
699                                                 SilcClientConnection conn,
700                                                 SilcChannelEntry channel)
701 {
702   SilcChannelPrivateKey entry;
703   SilcDList list;
704
705   if (!client || !conn || !channel)
706     return FALSE;
707
708   if (!channel->internal.private_keys)
709     return NULL;
710
711   list = silc_dlist_init();
712   if (!list)
713     return NULL;
714
715   silc_dlist_start(channel->internal.private_keys);
716   while ((entry = silc_dlist_get(channel->internal.private_keys)))
717     silc_dlist_add(list, entry);
718
719   return list;
720 }
721
722 /* Sets the `key' to be used as current channel private key on the
723    `channel'.  Packet sent after calling this function will be secured
724    with `key'. */
725
726 void silc_client_current_channel_private_key(SilcClient client,
727                                              SilcClientConnection conn,
728                                              SilcChannelEntry channel,
729                                              SilcChannelPrivateKey key)
730 {
731   if (!channel)
732     return;
733   channel->internal.curr_key = key;
734   channel->cipher = silc_cipher_get_name(key->send_key);
735   channel->hmac = silc_hmac_get_name(key->hmac);
736 }
737
738 /***************************** Utility routines *****************************/
739
740 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
741    channel indicated by the `channel'. NULL if client is not joined on
742    the channel. */
743
744 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
745                                        SilcClientEntry client_entry)
746 {
747   SilcChannelUser chu;
748
749   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
750                            (void *)&chu))
751     return chu;
752
753   return NULL;
754 }
755
756 /* Adds client to channel.  Returns TRUE if user was added or is already
757    added to the channel, FALSE on error.  Must be called with both `channel'
758    and `client_entry' locked. */
759
760 SilcBool silc_client_add_to_channel(SilcClient client,
761                                     SilcClientConnection conn,
762                                     SilcChannelEntry channel,
763                                     SilcClientEntry client_entry,
764                                     SilcUInt32 cumode)
765 {
766   SilcChannelUser chu;
767
768   if (silc_client_on_channel(channel, client_entry))
769     return TRUE;
770
771   SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
772
773   chu = silc_calloc(1, sizeof(*chu));
774   if (!chu)
775     return FALSE;
776
777   chu->client = client_entry;
778   chu->channel = channel;
779   chu->mode = cumode;
780
781   silc_client_ref_client(client, conn, client_entry);
782   silc_client_ref_channel(client, conn, channel);
783
784   silc_hash_table_add(channel->user_list, client_entry, chu);
785   silc_hash_table_add(client_entry->channels, channel, chu);
786
787   return TRUE;
788 }
789
790 /* Removes client from a channel.  Returns FALSE if user is not on channel.
791    This handles entry locking internally. */
792
793 SilcBool silc_client_remove_from_channel(SilcClient client,
794                                          SilcClientConnection conn,
795                                          SilcChannelEntry channel,
796                                          SilcClientEntry client_entry)
797 {
798   SilcChannelUser chu;
799
800   chu = silc_client_on_channel(channel, client_entry);
801   if (!chu)
802     return FALSE;
803
804   SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
805
806   silc_rwlock_wrlock(client_entry->internal.lock);
807   silc_rwlock_wrlock(channel->internal.lock);
808
809   silc_hash_table_del(chu->client->channels, chu->channel);
810   silc_hash_table_del(chu->channel->user_list, chu->client);
811   silc_free(chu);
812
813   /* If channel became empty, delete it */
814   if (!silc_hash_table_count(channel->user_list))
815     silc_client_del_channel(client, conn, channel);
816
817   silc_rwlock_unlock(client_entry->internal.lock);
818   silc_rwlock_unlock(channel->internal.lock);
819
820   silc_client_unref_client(client, conn, client_entry);
821   silc_client_unref_channel(client, conn, channel);
822
823   return TRUE;
824 }
825
826 /* Removes a client entry from all channels it has joined.  This handles
827    entry locking internally. */
828
829 void silc_client_remove_from_channels(SilcClient client,
830                                       SilcClientConnection conn,
831                                       SilcClientEntry client_entry)
832 {
833   SilcHashTableList htl;
834   SilcChannelUser chu;
835
836   if (!silc_hash_table_count(client_entry->channels))
837     return;
838
839   SILC_LOG_DEBUG(("Remove client from all joined channels"));
840
841   silc_rwlock_wrlock(client_entry->internal.lock);
842
843   silc_hash_table_list(client_entry->channels, &htl);
844   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
845     silc_rwlock_wrlock(chu->channel->internal.lock);
846
847     silc_hash_table_del(chu->client->channels, chu->channel);
848     silc_hash_table_del(chu->channel->user_list, chu->client);
849
850     /* If channel became empty, delete it */
851     if (!silc_hash_table_count(chu->channel->user_list))
852       silc_client_del_channel(client, conn, chu->channel);
853
854     silc_rwlock_unlock(chu->channel->internal.lock);
855
856     silc_client_unref_client(client, conn, chu->client);
857     silc_client_unref_channel(client, conn, chu->channel);
858     silc_free(chu);
859   }
860
861   silc_rwlock_unlock(client_entry->internal.lock);
862
863   silc_hash_table_list_reset(&htl);
864 }
865
866 /* Empties channel from users.  This handles entry locking internally. */
867
868 void silc_client_empty_channel(SilcClient client,
869                                SilcClientConnection conn,
870                                SilcChannelEntry channel)
871 {
872   SilcHashTableList htl;
873   SilcChannelUser chu;
874
875   silc_rwlock_wrlock(channel->internal.lock);
876
877   silc_hash_table_list(channel->user_list, &htl);
878   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
879     silc_hash_table_del(chu->client->channels, chu->channel);
880     silc_hash_table_del(chu->channel->user_list, chu->client);
881     silc_client_unref_client(client, conn, chu->client);
882     silc_client_unref_channel(client, conn, chu->channel);
883     silc_free(chu);
884   }
885
886   silc_rwlock_unlock(channel->internal.lock);
887
888   silc_hash_table_list_reset(&htl);
889 }
890
891 /* Save public keys to channel public key list.  Removes keys that are
892    marked to be removed.  Must be called with `channel' locked. */
893
894 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
895                                               unsigned char *chpk_list,
896                                               SilcUInt32 chpk_list_len,
897                                               SilcBool remove_all)
898 {
899   SilcArgumentDecodedList a, b;
900   SilcDList chpks;
901   SilcBool found;
902
903   if (remove_all) {
904     /* Remove all channel public keys */
905     if (!channel->channel_pubkeys)
906       return FALSE;
907
908     silc_dlist_start(channel->channel_pubkeys);
909     while ((b = silc_dlist_get(channel->channel_pubkeys)))
910       silc_dlist_del(channel->channel_pubkeys, b);
911
912     silc_dlist_uninit(channel->channel_pubkeys);
913     channel->channel_pubkeys = NULL;
914
915     return TRUE;
916   }
917
918   /* Parse channel public key list and add or remove public keys */
919   chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
920                                            SILC_ARGUMENT_PUBLIC_KEY);
921   if (!chpks)
922     return FALSE;
923
924   if (!channel->channel_pubkeys) {
925     channel->channel_pubkeys = silc_dlist_init();
926     if (!channel->channel_pubkeys) {
927       silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
928       return FALSE;
929     }
930   }
931
932   silc_dlist_start(chpks);
933   while ((a = silc_dlist_get(chpks))) {
934     found = FALSE;
935     silc_dlist_start(channel->channel_pubkeys);
936     while ((b = silc_dlist_get(channel->channel_pubkeys))) {
937       if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
938         found = TRUE;
939         break;
940       }
941     }
942
943     if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
944       silc_dlist_add(channel->channel_pubkeys, a);
945       silc_dlist_del(chpks, a);
946     } else if (a->arg_type == 0x01 && found) {
947       silc_dlist_del(channel->channel_pubkeys, b);
948     }
949   }
950
951   silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
952
953   return TRUE;
954 }