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