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