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