Added support for the new PKCS API, Auth API and other API
[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 typedef struct {
28   SilcClient client;
29   SilcClientConnection conn;
30   SilcChannelEntry channel;
31 } *SilcClientChannelMessageContext;
32
33 /* Message payload encoding callback */
34
35 static void silc_client_send_channel_message_final(SilcBuffer message,
36                                                    void *context)
37 {
38   SilcClientChannelMessageContext c = context;
39
40   /* Send the channel message */
41   if (message)
42     silc_packet_send_ext(c->conn->stream, SILC_PACKET_CHANNEL_MESSAGE, 0,
43                          0, NULL, SILC_ID_CHANNEL, &c->channel->id,
44                          silc_buffer_datalen(message), NULL, NULL);
45
46   silc_client_unref_channel(c->client, c->conn, c->channel);
47   silc_free(c);
48 }
49
50 /* Sends channel message to `channel'. */
51
52 SilcBool silc_client_send_channel_message(SilcClient client,
53                                           SilcClientConnection conn,
54                                           SilcChannelEntry channel,
55                                           SilcChannelPrivateKey key,
56                                           SilcMessageFlags flags,
57                                           SilcHash hash,
58                                           unsigned char *data,
59                                           SilcUInt32 data_len)
60 {
61   SilcClientChannelMessageContext c;
62   SilcChannelUser chu;
63   SilcCipher cipher;
64   SilcHmac hmac;
65   SilcID sid, rid;
66
67   SILC_LOG_DEBUG(("Sending channel message"));
68
69   if (silc_unlikely(!client || !conn || !channel))
70     return FALSE;
71   if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
72     return FALSE;
73   if (silc_unlikely(conn->internal->disconnected))
74     return FALSE;
75
76   chu = silc_client_on_channel(channel, conn->local_entry);
77   if (silc_unlikely(!chu)) {
78     client->internal->ops->say(conn->client, conn,
79                                SILC_CLIENT_MESSAGE_AUDIT,
80                                "Cannot talk to channel: not joined");
81     return FALSE;
82   }
83
84   /* Check if it is allowed to send messages to this channel by us. */
85   if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
86                     !chu->mode))
87     return FALSE;
88   if (silc_unlikely(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
89                     chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
90                     !(chu->mode & SILC_CHANNEL_UMODE_CHANFO)))
91     return FALSE;
92   if (silc_unlikely(chu->mode & SILC_CHANNEL_UMODE_QUIET))
93     return FALSE;
94
95   /* Take the key to be used */
96   if (channel->internal.private_keys) {
97     if (key) {
98       /* Use key application specified */
99       cipher = key->send_key;
100       hmac = key->hmac;
101     } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
102                channel->internal.curr_key) {
103       /* Use current private key */
104       cipher = channel->internal.curr_key->send_key;
105       hmac = channel->internal.curr_key->hmac;
106     } else if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY &&
107                !channel->internal.curr_key &&
108                channel->internal.private_keys) {
109       /* Use just some private key since we don't know what to use
110          and private keys are set. */
111       silc_dlist_start(channel->internal.private_keys);
112       key = silc_dlist_get(channel->internal.private_keys);
113       cipher = key->send_key;
114       hmac = key->hmac;
115
116       /* Use this key as current private key */
117       channel->internal.curr_key = key;
118     } else {
119       /* Use normal channel key generated by the server */
120       cipher = channel->internal.send_key;
121       hmac = channel->internal.hmac;
122     }
123   } else {
124     /* Use normal channel key generated by the server */
125     cipher = channel->internal.send_key;
126     hmac = channel->internal.hmac;
127   }
128
129   if (silc_unlikely(!cipher || !hmac)) {
130     SILC_LOG_ERROR(("No cipher and HMAC for channel"));
131     return FALSE;
132   }
133
134   c = silc_calloc(1, sizeof(*c));
135   if (!c)
136     return FALSE;
137
138   c->client = client;
139   c->conn = conn;
140   c->channel = silc_client_ref_channel(client, conn, channel);
141
142   sid.type = SILC_ID_CLIENT;
143   sid.u.client_id = chu->client->id;
144   rid.type = SILC_ID_CHANNEL;
145   rid.u.channel_id = chu->channel->id;
146
147   /* Encode the message payload. This also encrypts the message payload. */
148   silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
149                               cipher, hmac, client->rng, NULL,
150                               conn->private_key, hash, &sid, &rid, NULL,
151                               silc_client_send_channel_message_final, c);
152
153   return TRUE;
154 }
155
156 /************************* Channel Message Receive **************************/
157
158 /* Client resolving callback.  Continues with the channel message processing */
159
160 static void silc_client_channel_message_resolved(SilcClient client,
161                                                  SilcClientConnection conn,
162                                                  SilcStatus status,
163                                                  SilcDList clients,
164                                                  void *context)
165 {
166   /* If no client found, ignore the channel message, a silent error */
167   if (!clients)
168     silc_fsm_next(context, silc_client_channel_message_error);
169
170   /* Continue processing the channel message packet */
171   SILC_FSM_CALL_CONTINUE(context);
172 }
173
174 /* Process received channel message */
175
176 SILC_FSM_STATE(silc_client_channel_message)
177 {
178   SilcClientConnection conn = fsm_context;
179   SilcClient client = conn->client;
180   SilcPacket packet = state_context;
181   SilcBuffer buffer = &packet->buffer;
182   SilcMessagePayload payload = NULL;
183   SilcChannelEntry channel;
184   SilcClientEntry client_entry;
185   SilcClientID remote_id;
186   SilcChannelID channel_id;
187   unsigned char *message;
188   SilcUInt32 message_len;
189   SilcChannelPrivateKey key = NULL;
190
191   SILC_LOG_DEBUG(("Received channel message"));
192
193   SILC_LOG_HEXDUMP(("Channel message"), silc_buffer_data(buffer),
194                    silc_buffer_len(buffer));
195
196   if (silc_unlikely(packet->dst_id_type != SILC_ID_CHANNEL)) {
197     /** Invalid packet */
198     silc_fsm_next(fsm, silc_client_channel_message_error);
199     return SILC_FSM_CONTINUE;
200   }
201
202   if (silc_unlikely(!silc_id_str2id(packet->src_id,
203                                     packet->src_id_len, SILC_ID_CLIENT,
204                                     &remote_id, sizeof(remote_id)))) {
205     /** Invalid source ID */
206     silc_fsm_next(fsm, silc_client_channel_message_error);
207     return SILC_FSM_CONTINUE;
208   }
209
210   /* Get sender client entry */
211   client_entry = silc_client_get_client_by_id(client, conn, &remote_id);
212   if (!client_entry || !client_entry->internal.valid) {
213     /** Resolve client info */
214     silc_client_unref_client(client, conn, client_entry);
215     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
216                                          client, conn, &remote_id, NULL,
217                                          silc_client_channel_message_resolved,
218                                          fsm));
219     /* NOT REACHED */
220   }
221
222   if (silc_unlikely(!silc_id_str2id(packet->dst_id, packet->dst_id_len,
223                                     SILC_ID_CHANNEL, &channel_id,
224                                     sizeof(channel_id)))) {
225     /** Invalid destination ID */
226     silc_fsm_next(fsm, silc_client_channel_message_error);
227     return SILC_FSM_CONTINUE;
228   }
229
230   /* Find the channel */
231   channel = silc_client_get_channel_by_id(client, conn, &channel_id);
232   if (silc_unlikely(!channel)) {
233     /** Unknown channel */
234     silc_fsm_next(fsm, silc_client_channel_message_error);
235     return SILC_FSM_CONTINUE;
236   }
237
238   /* Check that user is on channel */
239   if (silc_unlikely(!silc_client_on_channel(channel, client_entry))) {
240     /** User not on channel */
241     SILC_LOG_WARNING(("Message from user not on channel, client or "
242                       "server bug"));
243     silc_fsm_next(fsm, silc_client_channel_message_error);
244     return SILC_FSM_CONTINUE;
245   }
246
247   /* If there is no channel private key then just decrypt the message
248      with the channel key. If private keys are set then just go through
249      all private keys and check what decrypts correctly. */
250   if (!channel->internal.private_keys) {
251     /* Parse the channel message payload. This also decrypts the payload */
252     payload = silc_message_payload_parse(silc_buffer_data(buffer),
253                                          silc_buffer_len(buffer), FALSE,
254                                          FALSE, channel->internal.receive_key,
255                                          channel->internal.hmac,
256                                          packet->src_id, packet->src_id_len,
257                                          packet->dst_id, packet->dst_id_len,
258                                          NULL, FALSE, NULL);
259
260     /* If decryption failed and we have just performed channel key rekey
261        we will use the old key in decryption. If that fails too then we
262        cannot do more and will drop the packet. */
263     if (silc_unlikely(!payload)) {
264       SilcCipher cipher;
265       SilcHmac hmac;
266
267       if (!channel->internal.old_channel_keys ||
268           !silc_dlist_count(channel->internal.old_channel_keys))
269         goto out;
270
271       SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
272
273       silc_dlist_end(channel->internal.old_channel_keys);
274       silc_dlist_end(channel->internal.old_hmacs);
275       while ((cipher = silc_dlist_get(channel->internal.old_channel_keys))) {
276         hmac = silc_dlist_get(channel->internal.old_hmacs);
277         if (!hmac)
278           break;
279
280         payload = silc_message_payload_parse(silc_buffer_data(buffer),
281                                              silc_buffer_len(buffer),
282                                              FALSE, FALSE, cipher, hmac,
283                                              packet->src_id,
284                                              packet->src_id_len,
285                                              packet->dst_id,
286                                              packet->dst_id_len,
287                                              NULL, FALSE, NULL);
288         if (payload)
289           break;
290       }
291       if (!payload)
292         goto out;
293     }
294   } else {
295     /* If the private key mode is not set on the channel then try the actual
296        channel key first before trying private keys. */
297     if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
298       payload = silc_message_payload_parse(silc_buffer_data(buffer),
299                                            silc_buffer_len(buffer),
300                                            FALSE, FALSE,
301                                            channel->internal.receive_key,
302                                            channel->internal.hmac,
303                                            packet->src_id,
304                                            packet->src_id_len,
305                                            packet->dst_id,
306                                            packet->dst_id_len,
307                                            NULL, FALSE, NULL);
308
309     if (!payload) {
310       silc_dlist_start(channel->internal.private_keys);
311       while ((key = silc_dlist_get(channel->internal.private_keys))) {
312         /* Parse the message payload. This also decrypts the payload */
313         payload = silc_message_payload_parse(silc_buffer_data(buffer),
314                                              silc_buffer_len(buffer),
315                                              FALSE, FALSE, key->receive_key,
316                                              key->hmac, packet->src_id,
317                                              packet->src_id_len,
318                                              packet->dst_id,
319                                              packet->dst_id_len,
320                                              NULL, FALSE, NULL);
321         if (payload)
322           break;
323       }
324       if (key == SILC_LIST_END)
325         goto out;
326     }
327   }
328
329   message = silc_message_get_data(payload, &message_len);
330
331   /* Pass the message to application */
332   client->internal->ops->channel_message(
333                              client, conn, client_entry, channel, payload,
334                              key, silc_message_get_flags(payload),
335                              message, message_len);
336
337  out:
338   silc_client_unref_client(client, conn, client_entry);
339   silc_client_unref_channel(client, conn, channel);
340   if (payload)
341     silc_message_payload_free(payload);
342   return SILC_FSM_FINISH;
343 }
344
345 /* Channel message error. */
346
347 SILC_FSM_STATE(silc_client_channel_message_error)
348 {
349   SilcPacket packet = state_context;
350   silc_packet_free(packet);
351   return SILC_FSM_FINISH;
352 }
353
354 /******************************* Channel Key ********************************/
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->internal.old_channel_keys) {
367     silc_dlist_start(channel->internal.old_channel_keys);
368     key = silc_dlist_get(channel->internal.old_channel_keys);
369     if (key) {
370       silc_dlist_del(channel->internal.old_channel_keys, key);
371       silc_cipher_free(key);
372     }
373   }
374
375   if (channel->internal.old_hmacs) {
376     silc_dlist_start(channel->internal.old_hmacs);
377     hmac = silc_dlist_get(channel->internal.old_hmacs);
378     if (hmac) {
379       silc_dlist_del(channel->internal.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 receive
386    Channel Key Payload and when we are processing JOIN command reply. */
387
388 SilcBool silc_client_save_channel_key(SilcClient client,
389                                       SilcClientConnection conn,
390                                       SilcBuffer key_payload,
391                                       SilcChannelEntry channel)
392 {
393   unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
394   SilcUInt32 tmp_len;
395   SilcChannelID id;
396   SilcChannelKeyPayload payload;
397
398   SILC_LOG_DEBUG(("New channel key"));
399
400   payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
401                                            silc_buffer_len(key_payload));
402   if (!payload)
403     return FALSE;
404
405   id_string = silc_channel_key_get_id(payload, &tmp_len);
406   if (!id_string) {
407     silc_channel_key_payload_free(payload);
408     return FALSE;
409   }
410
411   if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
412     silc_channel_key_payload_free(payload);
413     return FALSE;
414   }
415
416   /* Find channel. */
417   if (!channel) {
418     channel = silc_client_get_channel_by_id(client, conn, &id);
419     if (!channel) {
420       SILC_LOG_DEBUG(("Key for unknown channel"));
421       silc_channel_key_payload_free(payload);
422       return FALSE;
423     }
424   } else {
425     silc_client_ref_channel(client, conn, channel);
426   }
427
428   /* Save the old key for a short period of time so that we can decrypt
429      channel message even after the rekey if some client would be sending
430      messages with the old key after the rekey. */
431   if (!channel->internal.old_channel_keys)
432     channel->internal.old_channel_keys = silc_dlist_init();
433   if (!channel->internal.old_hmacs)
434     channel->internal.old_hmacs = silc_dlist_init();
435   if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
436     silc_dlist_add(channel->internal.old_channel_keys,
437                    channel->internal.receive_key);
438     silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
439     silc_schedule_task_add_timeout(client->schedule,
440                                    silc_client_save_channel_key_rekey,
441                                    channel, 15, 0);
442   }
443
444   /* Get channel cipher */
445   cipher = silc_channel_key_get_cipher(payload, NULL);
446   if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
447     client->internal->ops->say(
448                            conn->client, conn,
449                            SILC_CLIENT_MESSAGE_AUDIT,
450                            "Cannot talk to channel: unsupported cipher %s",
451                            cipher);
452     silc_client_unref_channel(client, conn, channel);
453     silc_channel_key_payload_free(payload);
454     return FALSE;
455   }
456   if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
457     client->internal->ops->say(
458                            conn->client, conn,
459                            SILC_CLIENT_MESSAGE_AUDIT,
460                            "Cannot talk to channel: unsupported cipher %s",
461                            cipher);
462     silc_client_unref_channel(client, conn, channel);
463     silc_channel_key_payload_free(payload);
464     return FALSE;
465   }
466
467   /* Set the cipher key.  Both sending and receiving keys are same */
468   key = silc_channel_key_get_key(payload, &tmp_len);
469   silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
470   silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);
471
472   /* Get channel HMAC */
473   hmac = (channel->internal.hmac ?
474           (char *)silc_hmac_get_name(channel->internal.hmac) :
475           SILC_DEFAULT_HMAC);
476   if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
477     client->internal->ops->say(
478                            conn->client, conn,
479                            SILC_CLIENT_MESSAGE_AUDIT,
480                            "Cannot talk to channel: unsupported HMAC %s",
481                            hmac);
482     silc_client_unref_channel(client, conn, channel);
483     silc_channel_key_payload_free(payload);
484     return FALSE;
485   }
486
487   channel->cipher = silc_cipher_get_name(channel->internal.send_key);
488   channel->hmac = silc_hmac_get_name(channel->internal.hmac);
489
490   /* Set HMAC key */
491   silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
492                  tmp_len, hash);
493   silc_hmac_set_key(channel->internal.hmac, hash,
494                     silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
495   memset(hash, 0, sizeof(hash));
496   silc_channel_key_payload_free(payload);
497
498   silc_client_unref_channel(client, conn, channel);
499
500   return TRUE;
501 }
502
503 /* Received channel key packet.  The key will replace old channel key. */
504
505 SILC_FSM_STATE(silc_client_channel_key)
506 {
507   SilcClientConnection conn = fsm_context;
508   SilcClient client = conn->client;
509   SilcPacket packet = state_context;
510
511   SILC_LOG_DEBUG(("Received channel key"));
512
513   /* Save the key */
514   silc_client_save_channel_key(client, conn, &packet->buffer, NULL);
515   silc_packet_free(packet);
516
517   return SILC_FSM_FINISH;
518 }
519
520 /**************************** Channel Private Key ***************************/
521
522 /* Add new channel private key */
523
524 SilcBool silc_client_add_channel_private_key(SilcClient client,
525                                              SilcClientConnection conn,
526                                              SilcChannelEntry channel,
527                                              const char *name,
528                                              char *cipher,
529                                              char *hmac,
530                                              unsigned char *key,
531                                              SilcUInt32 key_len,
532                                              SilcChannelPrivateKey *ret_key)
533 {
534   SilcChannelPrivateKey entry;
535   unsigned char hash[SILC_HASH_MAXLEN];
536   SilcSKEKeyMaterial keymat;
537
538   if (!client || !conn || !channel)
539     return FALSE;
540
541   if (!cipher)
542     cipher = SILC_DEFAULT_CIPHER;
543   if (!hmac)
544     hmac = SILC_DEFAULT_HMAC;
545
546   if (!silc_cipher_is_supported(cipher))
547     return FALSE;
548   if (!silc_hmac_is_supported(hmac))
549     return FALSE;
550
551   if (!channel->internal.private_keys) {
552     channel->internal.private_keys = silc_dlist_init();
553     if (!channel->internal.private_keys)
554       return FALSE;
555   }
556
557   /* Produce the key material */
558   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
559                                               conn->internal->sha1hash);
560   if (!keymat)
561     return FALSE;
562
563   /* Save the key */
564   entry = silc_calloc(1, sizeof(*entry));
565   if (!entry) {
566     silc_ske_free_key_material(keymat);
567     return FALSE;
568   }
569   entry->name = name ? strdup(name) : NULL;
570
571   /* Allocate the cipher and set the key */
572   if (!silc_cipher_alloc(cipher, &entry->send_key)) {
573     silc_free(entry);
574     silc_free(entry->name);
575     silc_ske_free_key_material(keymat);
576     return FALSE;
577   }
578   if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
579     silc_free(entry);
580     silc_free(entry->name);
581     silc_cipher_free(entry->send_key);
582     silc_ske_free_key_material(keymat);
583     return FALSE;
584   }
585   silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
586                       keymat->enc_key_len, TRUE);
587   silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
588                       keymat->enc_key_len, FALSE);
589
590   /* Generate HMAC key from the channel key data and set it */
591   if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
592     silc_free(entry);
593     silc_free(entry->name);
594     silc_cipher_free(entry->send_key);
595     silc_cipher_free(entry->receive_key);
596     silc_ske_free_key_material(keymat);
597     return FALSE;
598   }
599   silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
600                  keymat->enc_key_len / 8, hash);
601   silc_hmac_set_key(entry->hmac, hash,
602                     silc_hash_len(silc_hmac_get_hash(entry->hmac)));
603   memset(hash, 0, sizeof(hash));
604
605   /* Add to the private keys list */
606   silc_dlist_add(channel->internal.private_keys, entry);
607
608   if (!channel->internal.curr_key) {
609     channel->internal.curr_key = entry;
610     channel->cipher = silc_cipher_get_name(entry->send_key);
611     channel->hmac = silc_cipher_get_name(entry->send_key);
612   }
613
614   /* Free the key material */
615   silc_ske_free_key_material(keymat);
616
617   if (ret_key)
618     *ret_key = entry;
619
620   return TRUE;
621 }
622
623 /* Removes all private keys from the `channel'. The old channel key is used
624    after calling this to protect the channel messages. Returns FALSE on
625    on error, TRUE otherwise. */
626
627 SilcBool silc_client_del_channel_private_keys(SilcClient client,
628                                               SilcClientConnection conn,
629                                               SilcChannelEntry channel)
630 {
631   SilcChannelPrivateKey entry;
632
633   if (!client || !conn || !channel)
634     return FALSE;
635
636   if (!channel->internal.private_keys)
637     return FALSE;
638
639   silc_dlist_start(channel->internal.private_keys);
640   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
641     silc_dlist_del(channel->internal.private_keys, entry);
642     silc_free(entry->name);
643     silc_cipher_free(entry->send_key);
644     silc_cipher_free(entry->receive_key);
645     silc_hmac_free(entry->hmac);
646     silc_free(entry);
647   }
648
649   channel->internal.curr_key = NULL;
650   channel->cipher = silc_cipher_get_name(channel->internal.send_key);
651   channel->hmac = silc_hmac_get_name(channel->internal.hmac);
652
653   silc_dlist_uninit(channel->internal.private_keys);
654   channel->internal.private_keys = NULL;
655
656   return TRUE;
657 }
658
659 /* Removes and frees private key `key' from the channel `channel'. The `key'
660    is retrieved by calling the function silc_client_list_channel_private_keys.
661    The key is not used after this. If the key was last private key then the
662    old channel key is used hereafter to protect the channel messages. This
663    returns FALSE on error, TRUE otherwise. */
664
665 SilcBool silc_client_del_channel_private_key(SilcClient client,
666                                              SilcClientConnection conn,
667                                              SilcChannelEntry channel,
668                                              SilcChannelPrivateKey key)
669 {
670   SilcChannelPrivateKey entry;
671
672   if (!client || !conn || !channel)
673     return FALSE;
674
675   if (!channel->internal.private_keys)
676     return FALSE;
677
678   silc_dlist_start(channel->internal.private_keys);
679   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
680     if (entry != key)
681       continue;
682
683     if (channel->internal.curr_key == entry) {
684       channel->internal.curr_key = NULL;
685       channel->cipher = silc_cipher_get_name(channel->internal.send_key);
686       channel->hmac = silc_hmac_get_name(channel->internal.hmac);
687     }
688
689     silc_dlist_del(channel->internal.private_keys, entry);
690     silc_free(entry->name);
691     silc_cipher_free(entry->send_key);
692     silc_cipher_free(entry->receive_key);
693     silc_hmac_free(entry->hmac);
694     silc_free(entry);
695
696     if (silc_dlist_count(channel->internal.private_keys) == 0) {
697       silc_dlist_uninit(channel->internal.private_keys);
698       channel->internal.private_keys = NULL;
699     }
700
701     return TRUE;
702   }
703
704   return FALSE;
705 }
706
707 /* Returns array (pointers) of private keys associated to the `channel'.
708    The caller must free the array by calling the function
709    silc_client_free_channel_private_keys. The pointers in the array may be
710    used to delete the specific key by giving the pointer as argument to the
711    function silc_client_del_channel_private_key. */
712
713 SilcDList silc_client_list_channel_private_keys(SilcClient client,
714                                                 SilcClientConnection conn,
715                                                 SilcChannelEntry channel)
716 {
717   SilcChannelPrivateKey entry;
718   SilcDList list;
719
720   if (!client || !conn || !channel)
721     return FALSE;
722
723   if (!channel->internal.private_keys)
724     return NULL;
725
726   list = silc_dlist_init();
727   if (!list)
728     return NULL;
729
730   silc_dlist_start(channel->internal.private_keys);
731   while ((entry = silc_dlist_get(channel->internal.private_keys)))
732     silc_dlist_add(list, entry);
733
734   return list;
735 }
736
737 /* Sets the `key' to be used as current channel private key on the
738    `channel'.  Packet sent after calling this function will be secured
739    with `key'. */
740
741 void silc_client_current_channel_private_key(SilcClient client,
742                                              SilcClientConnection conn,
743                                              SilcChannelEntry channel,
744                                              SilcChannelPrivateKey key)
745 {
746   if (!channel)
747     return;
748   channel->internal.curr_key = key;
749   channel->cipher = silc_cipher_get_name(key->send_key);
750   channel->hmac = silc_hmac_get_name(key->hmac);
751 }
752
753 /***************************** Utility routines *****************************/
754
755 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
756    channel indicated by the `channel'. NULL if client is not joined on
757    the channel. */
758
759 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
760                                        SilcClientEntry client_entry)
761 {
762   SilcChannelUser chu;
763
764   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
765                            (void *)&chu))
766     return chu;
767
768   return NULL;
769 }
770
771 /* Adds client to channel.  Returns TRUE if user was added or is already
772    added to the channel, FALSE on error.  Must be called with both `channel'
773    and `client_entry' locked. */
774
775 SilcBool silc_client_add_to_channel(SilcClient client,
776                                     SilcClientConnection conn,
777                                     SilcChannelEntry channel,
778                                     SilcClientEntry client_entry,
779                                     SilcUInt32 cumode)
780 {
781   SilcChannelUser chu;
782
783   if (silc_client_on_channel(channel, client_entry))
784     return TRUE;
785
786   SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
787
788   chu = silc_calloc(1, sizeof(*chu));
789   if (!chu)
790     return FALSE;
791
792   chu->client = client_entry;
793   chu->channel = channel;
794   chu->mode = cumode;
795
796   silc_client_ref_client(client, conn, client_entry);
797   silc_client_ref_channel(client, conn, channel);
798
799   silc_hash_table_add(channel->user_list, client_entry, chu);
800   silc_hash_table_add(client_entry->channels, channel, chu);
801
802   return TRUE;
803 }
804
805 /* Removes client from a channel.  Returns FALSE if user is not on channel.
806    This handles entry locking internally. */
807
808 SilcBool silc_client_remove_from_channel(SilcClient client,
809                                          SilcClientConnection conn,
810                                          SilcChannelEntry channel,
811                                          SilcClientEntry client_entry)
812 {
813   SilcChannelUser chu;
814
815   chu = silc_client_on_channel(channel, client_entry);
816   if (!chu)
817     return FALSE;
818
819   SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
820
821   silc_rwlock_wrlock(client_entry->internal.lock);
822   silc_rwlock_wrlock(channel->internal.lock);
823
824   silc_hash_table_del(chu->client->channels, chu->channel);
825   silc_hash_table_del(chu->channel->user_list, chu->client);
826   silc_free(chu);
827
828   /* If channel became empty, delete it */
829   if (!silc_hash_table_count(channel->user_list))
830     silc_client_del_channel(client, conn, channel);
831
832   silc_rwlock_unlock(client_entry->internal.lock);
833   silc_rwlock_unlock(channel->internal.lock);
834
835   silc_client_unref_client(client, conn, client_entry);
836   silc_client_unref_channel(client, conn, channel);
837
838   return TRUE;
839 }
840
841 /* Removes a client entry from all channels it has joined.  This handles
842    entry locking internally. */
843
844 void silc_client_remove_from_channels(SilcClient client,
845                                       SilcClientConnection conn,
846                                       SilcClientEntry client_entry)
847 {
848   SilcHashTableList htl;
849   SilcChannelUser chu;
850
851   if (!silc_hash_table_count(client_entry->channels))
852     return;
853
854   SILC_LOG_DEBUG(("Remove client from all joined channels"));
855
856   silc_rwlock_wrlock(client_entry->internal.lock);
857
858   silc_hash_table_list(client_entry->channels, &htl);
859   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
860     silc_rwlock_wrlock(chu->channel->internal.lock);
861
862     silc_hash_table_del(chu->client->channels, chu->channel);
863     silc_hash_table_del(chu->channel->user_list, chu->client);
864
865     /* If channel became empty, delete it */
866     if (!silc_hash_table_count(chu->channel->user_list))
867       silc_client_del_channel(client, conn, chu->channel);
868
869     silc_rwlock_unlock(chu->channel->internal.lock);
870
871     silc_client_unref_client(client, conn, chu->client);
872     silc_client_unref_channel(client, conn, chu->channel);
873     silc_free(chu);
874   }
875
876   silc_rwlock_unlock(client_entry->internal.lock);
877
878   silc_hash_table_list_reset(&htl);
879 }
880
881 /* Empties channel from users.  This handles entry locking internally. */
882
883 void silc_client_empty_channel(SilcClient client,
884                                SilcClientConnection conn,
885                                SilcChannelEntry channel)
886 {
887   SilcHashTableList htl;
888   SilcChannelUser chu;
889
890   silc_rwlock_wrlock(channel->internal.lock);
891
892   silc_hash_table_list(channel->user_list, &htl);
893   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
894     silc_hash_table_del(chu->client->channels, chu->channel);
895     silc_hash_table_del(chu->channel->user_list, chu->client);
896     silc_client_unref_client(client, conn, chu->client);
897     silc_client_unref_channel(client, conn, chu->channel);
898     silc_free(chu);
899   }
900
901   silc_rwlock_unlock(channel->internal.lock);
902
903   silc_hash_table_list_reset(&htl);
904 }
905
906 /* Save public keys to channel public key list.  Removes keys that are
907    marked to be removed.  Must be called with `channel' locked. */
908
909 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
910                                               unsigned char *chpk_list,
911                                               SilcUInt32 chpk_list_len,
912                                               SilcBool remove_all)
913 {
914   SilcArgumentDecodedList a, b;
915   SilcDList chpks;
916   SilcBool found;
917
918   if (remove_all) {
919     /* Remove all channel public keys */
920     if (!channel->channel_pubkeys)
921       return FALSE;
922
923     silc_dlist_start(channel->channel_pubkeys);
924     while ((b = silc_dlist_get(channel->channel_pubkeys)))
925       silc_dlist_del(channel->channel_pubkeys, b);
926
927     silc_dlist_uninit(channel->channel_pubkeys);
928     channel->channel_pubkeys = NULL;
929
930     return TRUE;
931   }
932
933   /* Parse channel public key list and add or remove public keys */
934   chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
935                                            SILC_ARGUMENT_PUBLIC_KEY);
936   if (!chpks)
937     return FALSE;
938
939   if (!channel->channel_pubkeys) {
940     channel->channel_pubkeys = silc_dlist_init();
941     if (!channel->channel_pubkeys) {
942       silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
943       return FALSE;
944     }
945   }
946
947   silc_dlist_start(chpks);
948   while ((a = silc_dlist_get(chpks))) {
949     found = FALSE;
950     silc_dlist_start(channel->channel_pubkeys);
951     while ((b = silc_dlist_get(channel->channel_pubkeys))) {
952       if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
953         found = TRUE;
954         break;
955       }
956     }
957
958     if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
959       silc_dlist_add(channel->channel_pubkeys, a);
960       silc_dlist_del(chpks, a);
961     } else if (a->arg_type == 0x01 && found) {
962       silc_dlist_del(channel->channel_pubkeys, b);
963     }
964   }
965
966   silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
967
968   return TRUE;
969 }