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