d5a3ceaf15cbe308cec6eef79fe9d7d6536a9ff4
[silc.git] / lib / silcclient / client_prvmsg.c
1 /*
2
3   client_prvmsg.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 /************************** Private Message Send ****************************/
26
27 /* Sends private message to remote client. */
28
29 SilcBool silc_client_send_private_message(SilcClient client,
30                                           SilcClientConnection conn,
31                                           SilcClientEntry client_entry,
32                                           SilcMessageFlags flags,
33                                           SilcHash hash,
34                                           unsigned char *data,
35                                           SilcUInt32 data_len)
36 {
37   SilcBuffer buffer;
38   SilcBool ret;
39
40   if (silc_unlikely(!client || !conn || !client_entry))
41     return FALSE;
42   if (silc_unlikely(flags & SILC_MESSAGE_FLAG_SIGNED && !hash))
43     return FALSE;
44   if (silc_unlikely(conn->internal->disconnected))
45     return FALSE;
46
47   SILC_LOG_DEBUG(("Sending private message"));
48
49   /* Encode private message payload */
50   buffer =
51     silc_message_payload_encode(flags, data, data_len,
52                                 (!client_entry->internal.send_key ? FALSE :
53                                  !client_entry->internal.generated),
54                                 TRUE, client_entry->internal.send_key,
55                                 client_entry->internal.hmac_send,
56                                 client->rng, NULL, conn->private_key,
57                                 hash, NULL);
58   if (silc_unlikely(!buffer)) {
59     SILC_LOG_ERROR(("Error encoding private message"));
60     return FALSE;
61   }
62
63   /* Send the private message packet */
64   ret = silc_packet_send_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE,
65                              client_entry->internal.send_key ?
66                              SILC_PACKET_FLAG_PRIVMSG_KEY : 0,
67                              0, NULL, SILC_ID_CLIENT, &client_entry->id,
68                              silc_buffer_datalen(buffer), NULL, NULL);
69
70   silc_buffer_free(buffer);
71   return ret;
72 }
73
74 /************************* Private Message Receive **************************/
75
76 /* Client resolving callback.  Continues with the private message processing */
77
78 static void silc_client_private_message_resolved(SilcClient client,
79                                                  SilcClientConnection conn,
80                                                  SilcStatus status,
81                                                  SilcDList clients,
82                                                  void *context)
83 {
84   /* If no client found, ignore the private message, a silent error */
85   if (!clients)
86     silc_fsm_next(context, silc_client_private_message_error);
87
88   /* Continue processing the private message packet */
89   SILC_FSM_CALL_CONTINUE(context);
90 }
91
92 /* Private message received. */
93
94 SILC_FSM_STATE(silc_client_private_message)
95 {
96   SilcClientConnection conn = fsm_context;
97   SilcClient client = conn->client;
98   SilcPacket packet = state_context;
99   SilcMessagePayload payload = NULL;
100   SilcClientID remote_id;
101   SilcClientEntry remote_client = NULL;
102   SilcMessageFlags flags;
103   unsigned char *message;
104   SilcUInt32 message_len;
105
106   SILC_LOG_DEBUG(("Received private message"));
107
108   if (silc_unlikely(packet->src_id_type != SILC_ID_CLIENT)) {
109     /** Invalid packet */
110     silc_fsm_next(fsm, silc_client_private_message_error);
111     return SILC_FSM_CONTINUE;
112   }
113
114   if (silc_unlikely(!silc_id_str2id(packet->src_id, packet->src_id_len,
115                                     SILC_ID_CLIENT, &remote_id,
116                                     sizeof(remote_id)))) {
117     /** Invalid source ID */
118     silc_fsm_next(fsm, silc_client_private_message_error);
119     return SILC_FSM_CONTINUE;
120   }
121
122   /* Check whether we know this client already */
123   remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
124   if (!remote_client || !remote_client->nickname[0]) {
125     /** Resolve client info */
126     silc_client_unref_client(client, conn, remote_client);
127     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
128                                          client, conn, &remote_id, NULL,
129                                          silc_client_private_message_resolved,
130                                          fsm));
131     /* NOT REACHED */
132   }
133
134   if (silc_unlikely(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY &&
135                     !remote_client->internal.receive_key &&
136                     !remote_client->internal.hmac_receive))
137     goto out;
138
139   /* Parse the payload and decrypt it also if private message key is set */
140   payload =
141     silc_message_payload_parse(silc_buffer_datalen(&packet->buffer),
142                                TRUE, !remote_client->internal.generated,
143                                remote_client->internal.receive_key,
144                                remote_client->internal.hmac_receive,
145                                NULL, FALSE, NULL);
146   if (silc_unlikely(!payload))
147     goto out;
148
149   /* Pass the private message to application */
150   flags = silc_message_get_flags(payload);
151   message = silc_message_get_data(payload, &message_len);
152   client->internal->ops->private_message(client, conn, remote_client, payload,
153                                          flags, message, message_len);
154
155   /* See if we are away (gone). If we are away we will reply to the
156      sender with the set away message. */
157   if (conn->internal->away && conn->internal->away->away &&
158       !(flags & SILC_MESSAGE_FLAG_NOREPLY)) {
159     /* If it's me, ignore */
160     if (SILC_ID_CLIENT_COMPARE(&remote_id, conn->local_id))
161       goto out;
162
163     /* Send the away message */
164     silc_client_send_private_message(client, conn, remote_client,
165                                      SILC_MESSAGE_FLAG_AUTOREPLY |
166                                      SILC_MESSAGE_FLAG_NOREPLY, NULL,
167                                      conn->internal->away->away,
168                                      strlen(conn->internal->away->away));
169   }
170
171  out:
172   /** Packet processed */
173   silc_packet_free(packet);
174   silc_client_unref_client(client, conn, remote_client);
175   if (payload)
176     silc_message_payload_free(payload);
177   return SILC_FSM_FINISH;
178 }
179
180 /* Private message error. */
181
182 SILC_FSM_STATE(silc_client_private_message_error)
183 {
184   SilcPacket packet = state_context;
185   silc_packet_free(packet);
186   return SILC_FSM_FINISH;
187 }
188
189 /* Blocks the calling process or thread until private message has been
190    received from the specified client. */
191
192 SilcBool silc_client_private_message_wait(SilcClientConnection conn,
193                                           SilcClientEntry client_entry,
194                                           void *waiter,
195                                           SilcMessagePayload *payload)
196 {
197   SilcPacket packet;
198   SilcClientID remote_id;
199   SilcFSMThread thread;
200
201   /* Block until private message arrives */
202   do {
203     if ((silc_packet_wait(waiter, 0, &packet)) < 0)
204       return FALSE;
205
206     /* Parse sender ID */
207     if (!silc_id_str2id(packet->src_id, packet->src_id_len,
208                         SILC_ID_CLIENT, &remote_id,
209                         sizeof(remote_id))) {
210       silc_packet_free(packet);
211       continue;
212     }
213
214     /* If the private message is not for the requested client, pass it to
215        normal private message processing. */
216     if (!SILC_ID_CLIENT_COMPARE(&remote_id, &client_entry->id)) {
217       thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
218                                      silc_client_fsm_destructor, NULL, FALSE);
219       if (!thread) {
220         silc_packet_free(packet);
221         continue;
222       }
223
224       /* The packet will be processed in the connection thread, after this
225          FSM thread is started. */
226       silc_fsm_set_state_context(thread, packet);
227       silc_fsm_start(thread, silc_client_private_message);
228       continue;
229     }
230
231     /* Parse the payload and decrypt it also if private message key is set */
232     *payload =
233       silc_message_payload_parse(silc_buffer_data(&packet->buffer),
234                                  silc_buffer_len(&packet->buffer),
235                                  TRUE, !client_entry->internal.generated,
236                                  client_entry->internal.receive_key,
237                                  client_entry->internal.hmac_receive,
238                                  NULL, FALSE, NULL);
239     if (!(*payload)) {
240       silc_packet_free(packet);
241       continue;
242     }
243
244     break;
245   } while (1);
246
247   silc_packet_free(packet);
248   return TRUE;
249 }
250
251 /*************************** Private Message Key ****************************/
252
253 /* Sends private message key request.  Sender of this packet is initiator
254    when setting the private message key. */
255
256 static SilcBool
257 silc_client_send_private_message_key_request(SilcClient client,
258                                              SilcClientConnection conn,
259                                              SilcClientEntry client_entry)
260 {
261   const char *cipher, *hmac;
262
263   SILC_LOG_DEBUG(("Sending private message key request"));
264
265   cipher = silc_cipher_get_name(client_entry->internal.send_key);
266   hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
267
268   /* Send the packet */
269   return silc_packet_send_va_ext(conn->stream,
270                                  SILC_PACKET_PRIVATE_MESSAGE_KEY,
271                                  0, 0, NULL, SILC_ID_CLIENT,
272                                  &client_entry->id, NULL, NULL,
273                                  SILC_STR_UI_SHORT(strlen(cipher)),
274                                  SILC_STR_DATA(cipher, strlen(cipher)),
275                                  SILC_STR_UI_SHORT(strlen(hmac)),
276                                  SILC_STR_DATA(hmac, strlen(hmac)),
277                                  SILC_STR_END);
278 }
279
280 /* Client resolving callback.  Here we simply mark that we are the responder
281    side of this private message key request.  */
282
283 static void silc_client_private_message_key_cb(SilcClient client,
284                                                SilcClientConnection conn,
285                                                SilcStatus status,
286                                                SilcDList clients,
287                                                void *context)
288 {
289   SilcPacket packet = context;
290   unsigned char *cipher = NULL, *hmac = NULL;
291   SilcClientEntry client_entry;
292   int ret;
293
294   if (!clients) {
295     silc_packet_free(packet);
296     return;
297   }
298
299   /* Parse the private message key payload */
300   ret = silc_buffer_unformat(&packet->buffer,
301                              SILC_STR_UI16_STRING_ALLOC(&cipher),
302                              SILC_STR_UI16_STRING_ALLOC(&hmac),
303                              SILC_STR_END);
304   if (!ret)
305     goto out;
306
307   /* Mark that we are responder */
308   client_entry = silc_dlist_get(clients);
309   client_entry->internal.prv_resp = TRUE;
310
311   /* XXX we should notify application that remote wants to set up the
312      static key.  And we should tell if we already have key with remote.
313      Application should return status telling whether to delete the key
314      or not. */
315
316  out:
317   silc_free(cipher);
318   silc_free(hmac);
319   silc_packet_free(packet);
320 }
321
322 /* Processes incoming Private Message Key payload to indicate that the
323    sender whishes to set up a static private message key. */
324
325 SILC_FSM_STATE(silc_client_private_message_key)
326 {
327   SilcClientConnection conn = fsm_context;
328   SilcClient client = conn->client;
329   SilcPacket packet = state_context;
330   SilcClientID remote_id;
331
332   if (packet->src_id_type != SILC_ID_CLIENT) {
333     silc_packet_free(packet);
334     return SILC_FSM_FINISH;
335   }
336
337   if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
338                       &remote_id, sizeof(remote_id))) {
339     silc_packet_free(packet);
340     return SILC_FSM_FINISH;
341   }
342
343   /* Always resolve the remote client.  The actual packet is processed
344      in the resolving callback. */
345   SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
346                                        client, conn, &remote_id, NULL,
347                                        silc_client_private_message_key_cb,
348                                        fsm));
349 }
350
351 /* Adds new private message key to `client_entry'.  If we are setting this
352    before receiving request for it from `client_entry' we will send the
353    request to the client.  Otherwise, we are responder side. */
354
355 SilcBool silc_client_add_private_message_key(SilcClient client,
356                                              SilcClientConnection conn,
357                                              SilcClientEntry client_entry,
358                                              const char *cipher,
359                                              const char *hmac,
360                                              unsigned char *key,
361                                              SilcUInt32 key_len)
362 {
363   SilcSKEKeyMaterial keymat;
364   SilcBool ret;
365
366   if (!client || !client_entry)
367     return FALSE;
368
369   /* Return FALSE if key already set */
370   if (client_entry->internal.send_key && client_entry->internal.receive_key)
371     return FALSE;
372
373   if (!cipher)
374     cipher = SILC_DEFAULT_CIPHER;
375   if (!hmac)
376     hmac = SILC_DEFAULT_HMAC;
377
378   /* Check the requested cipher and HMAC */
379   if (!silc_cipher_is_supported(cipher))
380     return FALSE;
381   if (!silc_hmac_is_supported(hmac))
382     return FALSE;
383
384   /* Save the key */
385   client_entry->internal.key = silc_memdup(key, key_len);
386   client_entry->internal.key_len = key_len;
387
388   /* Produce the key material as the protocol defines */
389   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
390                                               conn->internal->sha1hash);
391   if (!keymat)
392     return FALSE;
393
394   /* Set the key into use */
395   ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
396                                                 cipher, hmac, keymat);
397   client_entry->internal.generated = FALSE;
398
399   /* Free the key material */
400   silc_ske_free_key_material(keymat);
401
402   /* If we are setting the key without a request from the remote client,
403      we will send request to remote. */
404   if (!client_entry->internal.prv_resp)
405     silc_client_send_private_message_key_request(client, conn, client_entry);
406
407   return ret;
408 }
409
410 /* Same as above but takes the key material from the SKE key material
411    structure. */
412
413 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
414                                                  SilcClientConnection conn,
415                                                  SilcClientEntry client_entry,
416                                                  const char *cipher,
417                                                  const char *hmac,
418                                                  SilcSKEKeyMaterial keymat)
419 {
420   if (!client || !client_entry)
421     return FALSE;
422
423   /* Return FALSE if key already set */
424   if (client_entry->internal.send_key && client_entry->internal.receive_key)
425     return FALSE;
426
427   if (!cipher)
428     cipher = SILC_DEFAULT_CIPHER;
429   if (!hmac)
430     hmac = SILC_DEFAULT_HMAC;
431
432   /* Check the requested cipher and HMAC */
433   if (!silc_cipher_is_supported(cipher))
434     return FALSE;
435   if (!silc_hmac_is_supported(hmac))
436     return FALSE;
437
438   client_entry->internal.generated = TRUE;
439
440   /* Allocate the cipher and HMAC */
441   if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
442     return FALSE;
443   if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
444     return FALSE;
445   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
446     return FALSE;
447   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
448     return FALSE;
449
450   /* Set the keys */
451   if (client_entry->internal.prv_resp) {
452     silc_cipher_set_key(client_entry->internal.send_key,
453                         keymat->receive_enc_key,
454                         keymat->enc_key_len, TRUE);
455     silc_cipher_set_iv(client_entry->internal.send_key,
456                        keymat->receive_iv);
457     silc_cipher_set_key(client_entry->internal.receive_key,
458                         keymat->send_enc_key,
459                         keymat->enc_key_len, FALSE);
460     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
461     silc_hmac_set_key(client_entry->internal.hmac_send,
462                       keymat->receive_hmac_key,
463                       keymat->hmac_key_len);
464     silc_hmac_set_key(client_entry->internal.hmac_receive,
465                       keymat->send_hmac_key,
466                       keymat->hmac_key_len);
467   } else {
468     silc_cipher_set_key(client_entry->internal.send_key,
469                         keymat->send_enc_key,
470                         keymat->enc_key_len, TRUE);
471     silc_cipher_set_iv(client_entry->internal.send_key,
472                        keymat->send_iv);
473     silc_cipher_set_key(client_entry->internal.receive_key,
474                         keymat->receive_enc_key,
475                         keymat->enc_key_len, FALSE);
476     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
477     silc_hmac_set_key(client_entry->internal.hmac_send,
478                       keymat->send_hmac_key,
479                       keymat->hmac_key_len);
480     silc_hmac_set_key(client_entry->internal.hmac_receive,
481                       keymat->receive_hmac_key,
482                       keymat->hmac_key_len);
483   }
484
485   return TRUE;
486 }
487
488 /* Removes the private message from the library. The key won't be used
489    after this to protect the private messages with the remote `client_entry'
490    client. Returns FALSE on error, TRUE otherwise. */
491
492 SilcBool silc_client_del_private_message_key(SilcClient client,
493                                              SilcClientConnection conn,
494                                              SilcClientEntry client_entry)
495 {
496   if (!client || !client_entry)
497     return FALSE;
498
499   if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
500     return FALSE;
501
502   silc_cipher_free(client_entry->internal.send_key);
503   silc_cipher_free(client_entry->internal.receive_key);
504
505   if (client_entry->internal.key) {
506     memset(client_entry->internal.key, 0, client_entry->internal.key_len);
507     silc_free(client_entry->internal.key);
508   }
509
510   client_entry->internal.send_key = NULL;
511   client_entry->internal.receive_key = NULL;
512   client_entry->internal.key = NULL;
513   client_entry->internal.prv_resp = FALSE;
514
515   return TRUE;
516 }
517
518 /* Returns array of set private message keys associated to the connection
519    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
520    count to the `key_count' argument. The array must be freed by the caller
521    by calling the silc_client_free_private_message_keys function. Note:
522    the keys returned in the array is in raw format. It might not be desired
523    to show the keys as is. The application might choose not to show the keys
524    at all or to show the fingerprints of the keys. */
525
526 SilcPrivateMessageKeys
527 silc_client_list_private_message_keys(SilcClient client,
528                                       SilcClientConnection conn,
529                                       SilcUInt32 *key_count)
530 {
531   SilcPrivateMessageKeys keys;
532   SilcUInt32 count = 0;
533   SilcList list;
534   SilcIDCacheEntry id_cache;
535   SilcClientEntry entry;
536
537   if (!client || !conn)
538     return NULL;
539
540   silc_mutex_lock(conn->internal->lock);
541   if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
542     silc_mutex_unlock(conn->internal->lock);
543     return NULL;
544   }
545
546   keys = silc_calloc(silc_list_count(list), sizeof(*keys));
547   if (!keys) {
548     silc_mutex_unlock(conn->internal->lock);
549     return NULL;
550   }
551
552   silc_list_start(list);
553   while ((id_cache = silc_list_get(list))) {
554     entry = id_cache->context;
555     if (entry->internal.send_key) {
556       keys[count].client_entry = entry;
557       keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
558                                                         send_key);
559       keys[count].key = (entry->internal.generated == FALSE ?
560                          entry->internal.key : NULL);
561       keys[count].key_len = (entry->internal.generated == FALSE ?
562                              entry->internal.key_len : 0);
563       count++;
564     }
565   }
566
567   silc_mutex_unlock(conn->internal->lock);
568
569   if (key_count)
570     *key_count = count;
571
572   return keys;
573 }
574
575 /* Frees the SilcPrivateMessageKeys array returned by the function
576    silc_client_list_private_message_keys. */
577
578 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
579                                            SilcUInt32 key_count)
580 {
581   silc_free(keys);
582 }
583
584 /* Sets away `message'.  The away message may be set when the client's
585    mode is changed to SILC_UMODE_GONE and the client whishes to reply
586    to anyone who sends private message.  The `message' will be sent
587    automatically back to the the client who send private message.  If
588    away message is already set this replaces the old message with the
589    new one.  If `message' is NULL the old away message is removed.
590    The sender may freely free the memory of the `message'. */
591
592 void silc_client_set_away_message(SilcClient client,
593                                   SilcClientConnection conn,
594                                   char *message)
595 {
596   assert(client && conn);
597
598   if (!message && conn->internal->away) {
599     silc_free(conn->internal->away->away);
600     silc_free(conn->internal->away);
601     conn->internal->away = NULL;
602   }
603
604   if (message) {
605     if (!conn->internal->away)
606       conn->internal->away = silc_calloc(1, sizeof(*conn->internal->away));
607     if (conn->internal->away->away)
608       silc_free(conn->internal->away->away);
609     conn->internal->away->away = strdup(message);
610   }
611 }