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