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