Removed HTTP server libary, it's available in SRT now
[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   channel->cipher = silc_cipher_get_name(channel->internal.send_key);
654   channel->hmac = silc_hmac_get_name(channel->internal.hmac);
655
656   silc_dlist_uninit(channel->internal.private_keys);
657   channel->internal.private_keys = NULL;
658
659   return TRUE;
660 }
661
662 /* Removes and frees private key `key' from the channel `channel'. The `key'
663    is retrieved by calling the function silc_client_list_channel_private_keys.
664    The key is not used after this. If the key was last private key then the
665    old channel key is used hereafter to protect the channel messages. This
666    returns FALSE on error, TRUE otherwise. */
667
668 SilcBool silc_client_del_channel_private_key(SilcClient client,
669                                              SilcClientConnection conn,
670                                              SilcChannelEntry channel,
671                                              SilcChannelPrivateKey key)
672 {
673   SilcChannelPrivateKey entry;
674
675   if (!client || !conn || !channel)
676     return FALSE;
677
678   if (!channel->internal.private_keys)
679     return FALSE;
680
681   silc_dlist_start(channel->internal.private_keys);
682   while ((entry = silc_dlist_get(channel->internal.private_keys))) {
683     if (entry != key)
684       continue;
685
686     if (channel->internal.curr_key == entry) {
687       channel->internal.curr_key = NULL;
688       channel->cipher = silc_cipher_get_name(channel->internal.send_key);
689       channel->hmac = silc_hmac_get_name(channel->internal.hmac);
690     }
691
692     silc_dlist_del(channel->internal.private_keys, entry);
693     silc_free(entry->name);
694     silc_cipher_free(entry->send_key);
695     silc_cipher_free(entry->receive_key);
696     silc_hmac_free(entry->hmac);
697     silc_free(entry);
698
699     if (silc_dlist_count(channel->internal.private_keys) == 0) {
700       silc_dlist_uninit(channel->internal.private_keys);
701       channel->internal.private_keys = NULL;
702     }
703
704     return TRUE;
705   }
706
707   return FALSE;
708 }
709
710 /* Returns array (pointers) of private keys associated to the `channel'.
711    The caller must free the array by calling the function
712    silc_client_free_channel_private_keys. The pointers in the array may be
713    used to delete the specific key by giving the pointer as argument to the
714    function silc_client_del_channel_private_key. */
715
716 SilcDList silc_client_list_channel_private_keys(SilcClient client,
717                                                 SilcClientConnection conn,
718                                                 SilcChannelEntry channel)
719 {
720   SilcChannelPrivateKey entry;
721   SilcDList list;
722
723   if (!client || !conn || !channel)
724     return FALSE;
725
726   if (!channel->internal.private_keys)
727     return NULL;
728
729   list = silc_dlist_init();
730   if (!list)
731     return NULL;
732
733   silc_dlist_start(channel->internal.private_keys);
734   while ((entry = silc_dlist_get(channel->internal.private_keys)))
735     silc_dlist_add(list, entry);
736
737   return list;
738 }
739
740 /* Sets the `key' to be used as current channel private key on the
741    `channel'.  Packet sent after calling this function will be secured
742    with `key'. */
743
744 void silc_client_current_channel_private_key(SilcClient client,
745                                              SilcClientConnection conn,
746                                              SilcChannelEntry channel,
747                                              SilcChannelPrivateKey key)
748 {
749   if (!channel)
750     return;
751   channel->internal.curr_key = key;
752   channel->cipher = silc_cipher_get_name(key->send_key);
753   channel->hmac = silc_hmac_get_name(key->hmac);
754 }
755
756 /***************************** Utility routines *****************************/
757
758 /* Returns the SilcChannelUser entry if the `client_entry' is joined on the
759    channel indicated by the `channel'. NULL if client is not joined on
760    the channel. */
761
762 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
763                                        SilcClientEntry client_entry)
764 {
765   SilcChannelUser chu;
766
767   if (silc_hash_table_find(channel->user_list, client_entry, NULL,
768                            (void *)&chu))
769     return chu;
770
771   return NULL;
772 }
773
774 /* Adds client to channel.  Returns TRUE if user was added or is already
775    added to the channel, FALSE on error.  Must be called with both `channel'
776    and `client_entry' locked. */
777
778 SilcBool silc_client_add_to_channel(SilcClient client,
779                                     SilcClientConnection conn,
780                                     SilcChannelEntry channel,
781                                     SilcClientEntry client_entry,
782                                     SilcUInt32 cumode)
783 {
784   SilcChannelUser chu;
785
786   if (silc_client_on_channel(channel, client_entry))
787     return TRUE;
788
789   SILC_LOG_DEBUG(("Add client %s to channel", client_entry->nickname));
790
791   chu = silc_calloc(1, sizeof(*chu));
792   if (!chu)
793     return FALSE;
794
795   chu->client = client_entry;
796   chu->channel = channel;
797   chu->mode = cumode;
798
799   silc_client_ref_client(client, conn, client_entry);
800   silc_client_ref_channel(client, conn, channel);
801
802   silc_hash_table_add(channel->user_list, client_entry, chu);
803   silc_hash_table_add(client_entry->channels, channel, chu);
804
805   return TRUE;
806 }
807
808 /* Removes client from a channel.  Returns FALSE if user is not on channel.
809    This handles entry locking internally. */
810
811 SilcBool silc_client_remove_from_channel(SilcClient client,
812                                          SilcClientConnection conn,
813                                          SilcChannelEntry channel,
814                                          SilcClientEntry client_entry)
815 {
816   SilcChannelUser chu;
817
818   chu = silc_client_on_channel(channel, client_entry);
819   if (!chu)
820     return FALSE;
821
822   SILC_LOG_DEBUG(("Remove client %s from channel", client_entry->nickname));
823
824   silc_rwlock_wrlock(client_entry->internal.lock);
825   silc_rwlock_wrlock(channel->internal.lock);
826
827   silc_hash_table_del(chu->client->channels, chu->channel);
828   silc_hash_table_del(chu->channel->user_list, chu->client);
829   silc_free(chu);
830
831   /* If channel became empty, delete it */
832   if (!silc_hash_table_count(channel->user_list))
833     silc_client_del_channel(client, conn, channel);
834
835   silc_rwlock_unlock(client_entry->internal.lock);
836   silc_rwlock_unlock(channel->internal.lock);
837
838   silc_client_unref_client(client, conn, client_entry);
839   silc_client_unref_channel(client, conn, channel);
840
841   return TRUE;
842 }
843
844 /* Removes a client entry from all channels it has joined.  This handles
845    entry locking internally. */
846
847 void silc_client_remove_from_channels(SilcClient client,
848                                       SilcClientConnection conn,
849                                       SilcClientEntry client_entry)
850 {
851   SilcHashTableList htl;
852   SilcChannelUser chu;
853
854   if (!silc_hash_table_count(client_entry->channels))
855     return;
856
857   SILC_LOG_DEBUG(("Remove client from all joined channels"));
858
859   silc_rwlock_wrlock(client_entry->internal.lock);
860
861   silc_hash_table_list(client_entry->channels, &htl);
862   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
863     silc_rwlock_wrlock(chu->channel->internal.lock);
864
865     silc_hash_table_del(chu->client->channels, chu->channel);
866     silc_hash_table_del(chu->channel->user_list, chu->client);
867
868     /* If channel became empty, delete it */
869     if (!silc_hash_table_count(chu->channel->user_list))
870       silc_client_del_channel(client, conn, chu->channel);
871
872     silc_rwlock_unlock(chu->channel->internal.lock);
873
874     silc_client_unref_client(client, conn, chu->client);
875     silc_client_unref_channel(client, conn, chu->channel);
876     silc_free(chu);
877   }
878
879   silc_rwlock_unlock(client_entry->internal.lock);
880
881   silc_hash_table_list_reset(&htl);
882 }
883
884 /* Empties channel from users.  This handles entry locking internally. */
885
886 void silc_client_empty_channel(SilcClient client,
887                                SilcClientConnection conn,
888                                SilcChannelEntry channel)
889 {
890   SilcHashTableList htl;
891   SilcChannelUser chu;
892
893   silc_rwlock_wrlock(channel->internal.lock);
894
895   silc_hash_table_list(channel->user_list, &htl);
896   while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
897     silc_hash_table_del(chu->client->channels, chu->channel);
898     silc_hash_table_del(chu->channel->user_list, chu->client);
899     silc_client_unref_client(client, conn, chu->client);
900     silc_client_unref_channel(client, conn, chu->channel);
901     silc_free(chu);
902   }
903
904   silc_rwlock_unlock(channel->internal.lock);
905
906   silc_hash_table_list_reset(&htl);
907 }
908
909 /* Save public keys to channel public key list.  Removes keys that are
910    marked to be removed.  Must be called with `channel' locked. */
911
912 SilcBool silc_client_channel_save_public_keys(SilcChannelEntry channel,
913                                               unsigned char *chpk_list,
914                                               SilcUInt32 chpk_list_len,
915                                               SilcBool remove_all)
916 {
917   SilcArgumentDecodedList a, b;
918   SilcDList chpks;
919   SilcBool found;
920
921   if (remove_all) {
922     /* Remove all channel public keys */
923     if (!channel->channel_pubkeys)
924       return FALSE;
925
926     silc_dlist_start(channel->channel_pubkeys);
927     while ((b = silc_dlist_get(channel->channel_pubkeys)))
928       silc_dlist_del(channel->channel_pubkeys, b);
929
930     silc_dlist_uninit(channel->channel_pubkeys);
931     channel->channel_pubkeys = NULL;
932
933     return TRUE;
934   }
935
936   /* Parse channel public key list and add or remove public keys */
937   chpks = silc_argument_list_parse_decoded(chpk_list, chpk_list_len,
938                                            SILC_ARGUMENT_PUBLIC_KEY);
939   if (!chpks)
940     return FALSE;
941
942   if (!channel->channel_pubkeys) {
943     channel->channel_pubkeys = silc_dlist_init();
944     if (!channel->channel_pubkeys) {
945       silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
946       return FALSE;
947     }
948   }
949
950   silc_dlist_start(chpks);
951   while ((a = silc_dlist_get(chpks))) {
952     found = FALSE;
953     silc_dlist_start(channel->channel_pubkeys);
954     while ((b = silc_dlist_get(channel->channel_pubkeys))) {
955       if (silc_pkcs_public_key_compare(a->argument, b->argument)) {
956         found = TRUE;
957         break;
958       }
959     }
960
961     if ((a->arg_type == 0x00 || a->arg_type == 0x03) && !found) {
962       silc_dlist_add(channel->channel_pubkeys, a);
963       silc_dlist_del(chpks, a);
964     } else if (a->arg_type == 0x01 && found) {
965       silc_dlist_del(channel->channel_pubkeys, b);
966     }
967   }
968
969   silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
970
971   return TRUE;
972 }