Merged silc_1_0_branch to trunk.
[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 - 2003 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 /* This file includes channel message sending and receiving routines,
21    channel key receiving and setting, and channel private key handling
22    routines. */
23
24 #include "silcincludes.h"
25 #include "silcclient.h"
26 #include "client_internal.h"
27
28 /* Sends packet to the `channel'. Packet to channel is always encrypted
29    differently from "normal" packets. SILC header of the packet is
30    encrypted with the next receiver's key and the rest of the packet is
31    encrypted with the channel specific key. Padding and HMAC is computed
32    with the next receiver's key. The `data' is the channel message. If
33    the `force_send' is TRUE then the packet is sent immediately. */
34
35 bool silc_client_send_channel_message(SilcClient client,
36                                       SilcClientConnection conn,
37                                       SilcChannelEntry channel,
38                                       SilcChannelPrivateKey key,
39                                       SilcMessageFlags flags,
40                                       unsigned char *data,
41                                       SilcUInt32 data_len,
42                                       bool force_send)
43 {
44   SilcSocketConnection sock;
45   SilcBuffer payload;
46   SilcPacketContext packetdata;
47   const SilcBufferStruct packet;
48   SilcCipher cipher;
49   SilcHmac hmac;
50   unsigned char *id_string;
51   int block_len;
52   SilcChannelUser chu;
53   bool ret = FALSE;
54
55   assert(client && conn && channel);
56   sock = conn->sock;
57   SILC_LOG_DEBUG(("Sending packet to channel"));
58
59   chu = silc_client_on_channel(channel, conn->local_entry);
60   if (!chu) {
61     SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
62     return FALSE;
63   }
64
65   /* Check if it is allowed to send messages to this channel by us. */
66   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
67     return FALSE;
68   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
69       chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
70       !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
71     return FALSE;
72   if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
73     return FALSE;
74
75   /* Take the key to be used */
76   if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
77     if (key) {
78       /* Use key application specified */
79       cipher = key->cipher;
80       hmac = key->hmac;
81     } else if (channel->curr_key) {
82       /* Use current private key */
83       cipher = channel->curr_key->cipher;
84       hmac = channel->curr_key->hmac;
85     } else if (!channel->curr_key && channel->private_keys) {
86       /* Use just some private key since we don't know what to use
87          and private keys are set. */
88       silc_dlist_start(channel->private_keys);
89       key = silc_dlist_get(channel->private_keys);
90       cipher = key->cipher;
91       hmac = key->hmac;
92
93       /* Use this key as current private key */
94       channel->curr_key = key;
95     } else {
96       /* Use normal channel key generated by the server */
97       cipher = channel->channel_key;
98       hmac = channel->hmac;
99     }
100   } else {
101     /* Use normal channel key generated by the server */
102     cipher = channel->channel_key;
103     hmac = channel->hmac;
104   }
105
106   if (!cipher || !hmac) {
107     SILC_LOG_ERROR(("No cipher and HMAC for channel"));
108     return FALSE;
109   }
110
111   block_len = silc_cipher_get_block_len(cipher);
112
113   /* Encode the message payload. This also encrypts the message payload. */
114   payload = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
115                                         cipher, hmac, client->rng, NULL,
116                                         client->private_key, client->sha1hash);
117   if (!payload) {
118     SILC_LOG_ERROR(("Error encoding channel message"));
119     return FALSE;
120   }
121
122   /* Get data used in packet header encryption, keys and stuff. */
123   cipher = conn->internal->send_key;
124   hmac = conn->internal->hmac_send;
125   id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
126
127   /* Set the packet context pointers. The destination ID is always
128      the Channel ID of the channel. Server and router will handle the
129      distribution of the packet. */
130   data = payload->data;
131   data_len = payload->len;
132   packetdata.flags = 0;
133   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
134   packetdata.src_id = conn->local_id_data;
135   packetdata.src_id_len = silc_id_get_len(conn->local_id, SILC_ID_CLIENT);
136   packetdata.src_id_type = SILC_ID_CLIENT;
137   packetdata.dst_id = id_string;
138   packetdata.dst_id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
139   packetdata.dst_id_type = SILC_ID_CHANNEL;
140   data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
141                                  packetdata.src_id_len +
142                                  packetdata.dst_id_len);
143   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
144     packetdata.src_id_len + packetdata.dst_id_len;
145   SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
146                       packetdata.src_id_len +
147                       packetdata.dst_id_len), block_len, packetdata.padlen);
148
149   /* Create the outgoing packet */
150   if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
151                             data, data_len, (const SilcBuffer)&packet)) {
152     SILC_LOG_ERROR(("Error assembling packet"));
153     goto out;
154   }
155
156   /* Encrypt the header and padding of the packet. This is encrypted
157      with normal session key shared with our server. */
158   silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
159                       (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
160                       packetdata.src_id_len + packetdata.dst_id_len +
161                       packetdata.padlen);
162
163   SILC_LOG_HEXDUMP(("Packet to channel, len %d", packet.len),
164                     packet.data, packet.len);
165
166   /* Now actually send the packet */
167   silc_client_packet_send_real(client, sock, force_send);
168
169   /* Check for mandatory rekey */
170   if (conn->internal->psn_send == SILC_CLIENT_REKEY_THRESHOLD)
171     silc_schedule_task_add(client->schedule, sock->sock,
172                            silc_client_rekey_callback, sock, 0, 1,
173                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
174
175   ret = TRUE;
176
177  out:
178   silc_buffer_free(payload);
179   silc_free(id_string);
180
181   return ret;
182 }
183
184 typedef struct {
185   SilcMessagePayload payload;
186   SilcChannelID *channel_id;
187 } *SilcChannelClientResolve;
188
189 static void silc_client_channel_message_cb(SilcClient client,
190                                            SilcClientConnection conn,
191                                            SilcClientEntry *clients,
192                                            SilcUInt32 clients_count,
193                                            void *context)
194 {
195   SilcChannelClientResolve res = (SilcChannelClientResolve)context;
196
197   if (clients_count == 1) {
198     SilcChannelEntry channel;
199     unsigned char *message;
200     SilcUInt32 message_len;
201
202     channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
203     if (!channel)
204       goto out;
205
206     /* If this client is not on channel, add it there since it clearly
207        is there. */
208     if (!silc_client_on_channel(channel, clients[0])) {
209       SilcChannelUser chu = silc_calloc(1, sizeof(*chu));
210       chu->client = clients[0];
211       chu->channel = channel;
212       silc_hash_table_add(channel->user_list, clients[0], chu);
213       silc_hash_table_add(clients[0]->channels, channel, chu);
214     }
215
216     message = silc_message_get_data(res->payload, &message_len);
217
218     /* Pass the message to application */
219     client->internal->ops->channel_message(
220                             client, conn, clients[0], channel, res->payload,
221                             silc_message_get_flags(res->payload),
222                             message, message_len);
223   }
224
225  out:
226   silc_message_payload_free(res->payload);
227   silc_free(res->channel_id);
228   silc_free(res);
229 }
230
231 /* Process received message to a channel (or from a channel, really). This
232    decrypts the channel message with channel specific key and parses the
233    message payload. Finally it displays the message on the screen. */
234
235 void silc_client_channel_message(SilcClient client,
236                                  SilcSocketConnection sock,
237                                  SilcPacketContext *packet)
238 {
239   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
240   SilcBuffer buffer = packet->buffer;
241   SilcMessagePayload payload = NULL;
242   SilcChannelID *id = NULL;
243   SilcChannelEntry channel;
244   SilcClientEntry client_entry;
245   SilcClientID *client_id = NULL;
246   unsigned char *message;
247   SilcUInt32 message_len;
248
249   SILC_LOG_DEBUG(("Received channel message"));
250
251   /* Sanity checks */
252   if (packet->dst_id_type != SILC_ID_CHANNEL)
253     goto out;
254
255   client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
256                              SILC_ID_CLIENT);
257   if (!client_id)
258     goto out;
259   id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
260   if (!id)
261     goto out;
262
263   /* Find the channel entry from channels on this connection */
264   channel = silc_client_get_channel_by_id(client, conn, id);
265   if (!channel)
266     goto out;
267
268   /* If there is no channel private key then just decrypt the message
269      with the channel key. If private keys are set then just go through
270      all private keys and check what decrypts correctly. */
271   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
272     /* Parse the channel message payload. This also decrypts the payload */
273     payload = silc_message_payload_parse(buffer->data, buffer->len, FALSE,
274                                          FALSE, channel->channel_key,
275                                          channel->hmac);
276
277     /* If decryption failed and we have just performed channel key rekey
278        we will use the old key in decryption. If that fails too then we
279        cannot do more and will drop the packet. */
280     if (!payload) {
281       SilcCipher key;
282       SilcHmac hmac;
283       int i;
284
285       if (!channel->old_channel_keys ||
286           !silc_dlist_count(channel->old_channel_keys))
287         goto out;
288
289       SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
290
291       silc_dlist_end(channel->old_channel_keys);
292       silc_dlist_end(channel->old_hmacs);
293       for (i = 0; i < silc_dlist_count(channel->old_channel_keys); i++) {
294         key = silc_dlist_get(channel->old_channel_keys);
295         hmac = silc_dlist_get(channel->old_hmacs);
296         if (!key || !hmac)
297           break;
298
299         payload = silc_message_payload_parse(buffer->data, buffer->len,
300                                              FALSE, FALSE, key, hmac);
301         if (payload)
302           break;
303       }
304       if (!payload)
305         goto out;
306     }
307   } else if (channel->private_keys) {
308     SilcChannelPrivateKey entry;
309
310     silc_dlist_start(channel->private_keys);
311     while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
312       /* Parse the message payload. This also decrypts the payload */
313       payload = silc_message_payload_parse(buffer->data, buffer->len,
314                                            FALSE, FALSE,
315                                            entry->cipher, entry->hmac);
316       if (payload)
317         break;
318     }
319     if (entry == SILC_LIST_END)
320       goto out;
321   } else {
322     goto out;
323   }
324
325   /* Find client entry */
326   client_entry = silc_client_get_client_by_id(client, conn, client_id);
327   if (!client_entry || !client_entry->nickname ||
328       !silc_client_on_channel(channel, client_entry)) {
329     /* Resolve the client info */
330     SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
331     res->payload = payload;
332     res->channel_id = id;
333     silc_client_get_client_by_id_resolve(client, conn, client_id, NULL,
334                                          silc_client_channel_message_cb,
335                                          res);
336     payload = NULL;
337     id = NULL;
338     goto out;
339   }
340
341   message = silc_message_get_data(payload, &message_len);
342
343   /* Pass the message to application */
344   client->internal->ops->channel_message(
345                              client, conn, client_entry, channel, payload,
346                              silc_message_get_flags(payload),
347                              message, message_len);
348
349  out:
350   silc_free(id);
351   silc_free(client_id);
352   if (payload)
353     silc_message_payload_free(payload);
354 }
355
356 /* Timeout callback that is called after a short period of time after the
357    new channel key has been created.  This removes the first channel key
358    in the list. */
359
360 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
361 {
362   SilcChannelEntry channel = (SilcChannelEntry)context;
363   SilcCipher key;
364   SilcHmac hmac;
365
366   if (channel->old_channel_keys) {
367     silc_dlist_start(channel->old_channel_keys);
368     key = silc_dlist_get(channel->old_channel_keys);
369     if (key) {
370       silc_dlist_del(channel->old_channel_keys, key);
371       silc_cipher_free(key);
372     }
373   }
374
375   if (channel->old_hmacs) {
376     silc_dlist_start(channel->old_hmacs);
377     hmac = silc_dlist_get(channel->old_hmacs);
378     if (hmac) {
379       silc_dlist_del(channel->old_hmacs, hmac);
380       silc_hmac_free(hmac);
381     }
382   }
383 }
384
385 /* Saves channel key from encoded `key_payload'. This is used when we
386    receive Channel Key Payload and when we are processing JOIN command
387    reply. */
388
389 void silc_client_save_channel_key(SilcClient client,
390                                   SilcClientConnection conn,
391                                   SilcBuffer key_payload,
392                                   SilcChannelEntry channel)
393 {
394   unsigned char *id_string, *key, *cipher, *hmac, hash[32];
395   SilcUInt32 tmp_len;
396   SilcChannelID *id;
397   SilcChannelKeyPayload payload;
398
399   payload = silc_channel_key_payload_parse(key_payload->data,
400                                            key_payload->len);
401   if (!payload)
402     return;
403
404   id_string = silc_channel_key_get_id(payload, &tmp_len);
405   if (!id_string) {
406     silc_channel_key_payload_free(payload);
407     return;
408   }
409
410   id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
411   if (!id) {
412     silc_channel_key_payload_free(payload);
413     return;
414   }
415
416   /* Find channel. */
417   if (!channel) {
418     channel = silc_client_get_channel_by_id(client, conn, id);
419     if (!channel)
420       goto out;
421   }
422
423   hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) :
424           SILC_DEFAULT_HMAC);
425
426   /* Save the old key for a short period of time so that we can decrypt
427      channel message even after the rekey if some client would be sending
428      messages with the old key after the rekey. */
429   if (!channel->old_channel_keys)
430     channel->old_channel_keys = silc_dlist_init();
431   if (!channel->old_hmacs)
432     channel->old_hmacs = silc_dlist_init();
433   silc_dlist_add(channel->old_channel_keys, channel->channel_key);
434   silc_dlist_add(channel->old_hmacs, channel->hmac);
435   silc_schedule_task_add(client->schedule, 0,
436                          silc_client_save_channel_key_rekey, channel,
437                          10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
438
439   /* Free the old channel key data */
440   silc_free(channel->key);
441
442   /* Save the key */
443   key = silc_channel_key_get_key(payload, &tmp_len);
444   cipher = silc_channel_key_get_cipher(payload, NULL);
445   channel->key_len = tmp_len * 8;
446   channel->key = silc_memdup(key, tmp_len);
447
448   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
449     client->internal->ops->say(
450                            conn->client, conn,
451                            SILC_CLIENT_MESSAGE_AUDIT,
452                            "Cannot talk to channel: unsupported cipher %s",
453                            cipher);
454     goto out;
455   }
456
457   /* Set the cipher key */
458   silc_cipher_set_key(channel->channel_key, key, channel->key_len);
459
460   /* Generate HMAC key from the channel key data and set it */
461   silc_hmac_alloc(hmac, NULL, &channel->hmac);
462   silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
463   silc_hmac_set_key(channel->hmac, hash,
464                     silc_hash_len(silc_hmac_get_hash(channel->hmac)));
465   memset(hash, 0, sizeof(hash));
466
467  out:
468   silc_free(id);
469   silc_channel_key_payload_free(payload);
470 }
471
472 /* Processes received key for channel. The received key will be used
473    to protect the traffic on the channel for now on. Client must receive
474    the key to the channel before talking on the channel is possible.
475    This is the key that server has generated, this is not the channel
476    private key, it is entirely local setting. */
477
478 void silc_client_receive_channel_key(SilcClient client,
479                                      SilcSocketConnection sock,
480                                      SilcBuffer packet)
481 {
482   SILC_LOG_DEBUG(("Received key for channel"));
483
484   /* Save the key */
485   silc_client_save_channel_key(client, sock->user_data, packet, NULL);
486 }
487
488 /* Adds private key for channel. This may be set only if the channel's mode
489    mask includes the SILC_CHANNEL_MODE_PRIVKEY. This returns FALSE if the
490    mode is not set. When channel has private key then the messages are
491    encrypted using that key. All clients on the channel must also know the
492    key in order to decrypt the messages. However, it is possible to have
493    several private keys per one channel. In this case only some of the
494    clients on the channel may know the one key and only some the other key.
495
496    If `cipher' and/or `hmac' is NULL then default values will be used
497    (aes-256-cbc for cipher and hmac-sha1-96 for hmac).
498
499    The private key for channel is optional. If it is not set then the
500    channel messages are encrypted using the channel key generated by the
501    server. However, setting the private key (or keys) for the channel
502    significantly adds security. If more than one key is set the library
503    will automatically try all keys at the message decryption phase. Note:
504    setting many keys slows down the decryption phase as all keys has to
505    be tried in order to find the correct decryption key. However, setting
506    a few keys does not have big impact to the decryption performace.
507
508    NOTE: that this is entirely local setting. The key set using this function
509    is not sent to the network at any phase.
510
511    NOTE: If the key material was originated by the SKE protocol (using
512    silc_client_send_key_agreement) then the `key' MUST be the
513    key->send_enc_key as this is dictated by the SILC protocol. However,
514    currently it is not expected that the SKE key material would be used
515    as channel private key. However, this API allows it. */
516
517 bool silc_client_add_channel_private_key(SilcClient client,
518                                         SilcClientConnection conn,
519                                         SilcChannelEntry channel,
520                                         const char *name,
521                                         char *cipher,
522                                         char *hmac,
523                                         unsigned char *key,
524                                         SilcUInt32 key_len)
525 {
526   SilcChannelPrivateKey entry;
527   unsigned char hash[32];
528   SilcSKEKeyMaterial *keymat;
529
530   assert(client && channel);
531
532   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
533     return FALSE;
534
535   if (!cipher)
536     cipher = SILC_DEFAULT_CIPHER;
537   if (!hmac)
538     hmac = SILC_DEFAULT_HMAC;
539
540   if (!silc_cipher_is_supported(cipher))
541     return FALSE;
542
543   if (!silc_hmac_is_supported(hmac))
544     return FALSE;
545
546   /* Produce the key material */
547   keymat = silc_calloc(1, sizeof(*keymat));
548   if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
549                                          client->sha1hash, keymat)
550       != SILC_SKE_STATUS_OK)
551     return FALSE;
552
553   /* Remove the current key, if it exists. */
554   if (channel->channel_key) {
555     silc_cipher_free(channel->channel_key);
556     memset(channel->key, 0, channel->key_len / 8);
557     silc_free(channel->key);
558     channel->channel_key = NULL;
559     channel->key = NULL;
560     channel->key_len = 0;
561   }
562   if (channel->hmac) {
563     silc_hmac_free(channel->hmac);
564     channel->hmac = NULL;
565   }
566
567   if (!channel->private_keys)
568     channel->private_keys = silc_dlist_init();
569
570   /* Save the key */
571   entry = silc_calloc(1, sizeof(*entry));
572   entry->name = name ? strdup(name) : NULL;
573   entry->key = silc_memdup(keymat->send_enc_key, keymat->enc_key_len / 8);
574   entry->key_len = keymat->enc_key_len / 8;
575
576   /* Allocate the cipher and set the key*/
577   silc_cipher_alloc(cipher, &entry->cipher);
578   silc_cipher_set_key(entry->cipher, entry->key, keymat->enc_key_len);
579
580   /* Generate HMAC key from the channel key data and set it */
581   silc_hmac_alloc(hmac, NULL, &entry->hmac);
582   silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key,
583                  entry->key_len, hash);
584   silc_hmac_set_key(entry->hmac, hash,
585                     silc_hash_len(silc_hmac_get_hash(entry->hmac)));
586   memset(hash, 0, sizeof(hash));
587
588   /* Add to the private keys list */
589   silc_dlist_add(channel->private_keys, entry);
590
591   if (!channel->curr_key)
592     channel->curr_key = entry;
593
594   /* Free the key material */
595   silc_ske_free_key_material(keymat);
596
597   return TRUE;
598 }
599
600 /* Removes all private keys from the `channel'. The old channel key is used
601    after calling this to protect the channel messages. Returns FALSE on
602    on error, TRUE otherwise. */
603
604 bool silc_client_del_channel_private_keys(SilcClient client,
605                                          SilcClientConnection conn,
606                                          SilcChannelEntry channel)
607 {
608   SilcChannelPrivateKey entry;
609
610   assert(client && channel);
611
612   if (!channel->private_keys)
613     return FALSE;
614
615   silc_dlist_start(channel->private_keys);
616   while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
617     silc_dlist_del(channel->private_keys, entry);
618     memset(entry->key, 0, entry->key_len);
619     silc_free(entry->key);
620     silc_free(entry->name);
621     silc_cipher_free(entry->cipher);
622     silc_hmac_free(entry->hmac);
623     silc_free(entry);
624   }
625
626   channel->curr_key = NULL;
627
628   silc_dlist_uninit(channel->private_keys);
629   channel->private_keys = NULL;
630
631   return TRUE;
632 }
633
634 /* Removes and frees private key `key' from the channel `channel'. The `key'
635    is retrieved by calling the function silc_client_list_channel_private_keys.
636    The key is not used after this. If the key was last private key then the
637    old channel key is used hereafter to protect the channel messages. This
638    returns FALSE on error, TRUE otherwise. */
639
640 bool silc_client_del_channel_private_key(SilcClient client,
641                                         SilcClientConnection conn,
642                                         SilcChannelEntry channel,
643                                         SilcChannelPrivateKey key)
644 {
645   SilcChannelPrivateKey entry;
646
647   assert(client && channel);
648
649   if (!channel->private_keys)
650     return FALSE;
651
652   silc_dlist_start(channel->private_keys);
653   while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
654     if (entry == key) {
655       if (channel->curr_key == entry)
656         channel->curr_key = NULL;
657
658       silc_dlist_del(channel->private_keys, entry);
659       memset(entry->key, 0, entry->key_len);
660       silc_free(entry->key);
661       silc_free(entry->name);
662       silc_cipher_free(entry->cipher);
663       silc_hmac_free(entry->hmac);
664       silc_free(entry);
665
666       if (silc_dlist_count(channel->private_keys) == 0) {
667         silc_dlist_uninit(channel->private_keys);
668         channel->private_keys = NULL;
669       }
670
671       return TRUE;
672     }
673   }
674
675   return FALSE;
676 }
677
678 /* Returns array (pointers) of private keys associated to the `channel'.
679    The caller must free the array by calling the function
680    silc_client_free_channel_private_keys. The pointers in the array may be
681    used to delete the specific key by giving the pointer as argument to the
682    function silc_client_del_channel_private_key. */
683
684 SilcChannelPrivateKey *
685 silc_client_list_channel_private_keys(SilcClient client,
686                                       SilcClientConnection conn,
687                                       SilcChannelEntry channel,
688                                       SilcUInt32 *key_count)
689 {
690   SilcChannelPrivateKey *keys = NULL, entry;
691   SilcUInt32 count = 0;
692
693   assert(client && channel);
694
695   if (!channel->private_keys)
696     return NULL;
697
698   silc_dlist_start(channel->private_keys);
699   while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
700     keys = silc_realloc(keys, sizeof(*keys) * (count + 1));
701     keys[count] = entry;
702     count++;
703   }
704
705   if (key_count)
706     *key_count = count;
707
708   return keys;
709 }
710
711 /* Frees the SilcChannelPrivateKey array. */
712
713 void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
714                                            SilcUInt32 key_count)
715 {
716   silc_free(keys);
717 }
718
719 /* Sets the `key' to be used as current channel private key on the
720    `channel'.  Packet sent after calling this function will be secured
721    with `key'. */
722
723 void silc_client_current_channel_private_key(SilcClient client,
724                                              SilcClientConnection conn,
725                                              SilcChannelEntry channel,
726                                              SilcChannelPrivateKey key)
727 {
728   assert(client && channel);
729   channel->curr_key = key;
730 }
731
732 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
733    channel indicated by the `channel'. NULL if client is not joined on
734    the channel. */
735
736 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
737                                        SilcClientEntry client_entry)
738 {
739   SilcChannelUser chu;
740
741   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
742                            (void *)&chu))
743     return chu;
744
745   return NULL;
746 }