20370cf6647bc828140da993cec051fce555d3b8
[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_message &&
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_message,
168                                      strlen(conn->internal->away_message));
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 /* Initialize private message waiter for the `conn' connection. */
190
191 SilcBool silc_client_private_message_wait_init(SilcClient client,
192                                                SilcClientConnection conn)
193 {
194   if (conn->internal->prv_waiter)
195     return TRUE;
196
197   conn->internal->prv_waiter =
198     silc_packet_wait_init(conn->stream, SILC_PACKET_PRIVATE_MESSAGE, -1);
199   if (!conn->internal->prv_waiter)
200     return FALSE;
201
202   return TRUE;
203 }
204
205 /* Uninitializes private message waiter. */
206
207 void silc_client_private_message_wait_uninit(SilcClient client,
208                                              SilcClientConnection conn)
209 {
210   if (!conn->internal->prv_waiter)
211     return;
212   silc_packet_wait_uninit(conn->internal->prv_waiter, conn->stream);
213   conn->internal->prv_waiter = NULL;
214 }
215
216 /* Blocks the calling process or thread until private message has been
217    received from the specified client. */
218
219 SilcBool silc_client_private_message_wait(SilcClient client,
220                                           SilcClientConnection conn,
221                                           SilcClientEntry client_entry,
222                                           SilcMessagePayload *payload)
223 {
224   SilcPacket packet;
225   SilcClientID remote_id;
226   SilcFSMThread thread;
227
228   if (!conn->internal->prv_waiter)
229     return FALSE;
230
231   /* Block until private message arrives */
232   do {
233     if ((silc_packet_wait(conn->internal->prv_waiter, 0, &packet)) < 0)
234       return FALSE;
235
236     /* Parse sender ID */
237     if (!silc_id_str2id(packet->src_id, packet->src_id_len,
238                         SILC_ID_CLIENT, &remote_id,
239                         sizeof(remote_id))) {
240       silc_packet_free(packet);
241       continue;
242     }
243
244     /* If the private message is not for the requested client, pass it to
245        normal private message processing. */
246     if (!SILC_ID_CLIENT_COMPARE(&remote_id, &client_entry->id)) {
247       thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
248                                      silc_client_fsm_destructor, NULL, FALSE);
249       if (!thread) {
250         silc_packet_free(packet);
251         continue;
252       }
253
254       /* The packet will be processed in the connection thread, after this
255          FSM thread is started. */
256       silc_fsm_set_state_context(thread, packet);
257       silc_fsm_start(thread, silc_client_private_message);
258       continue;
259     }
260
261     /* Parse the payload and decrypt it also if private message key is set */
262     *payload =
263       silc_message_payload_parse(silc_buffer_data(&packet->buffer),
264                                  silc_buffer_len(&packet->buffer),
265                                  TRUE, !client_entry->internal.generated,
266                                  client_entry->internal.receive_key,
267                                  client_entry->internal.hmac_receive,
268                                  NULL, FALSE, NULL);
269     if (!(*payload)) {
270       silc_packet_free(packet);
271       continue;
272     }
273
274     break;
275   } while (1);
276
277   silc_packet_free(packet);
278   return TRUE;
279 }
280
281 /*************************** Private Message Key ****************************/
282
283 /* Sends private message key request.  Sender of this packet is initiator
284    when setting the private message key. */
285
286 static SilcBool
287 silc_client_send_private_message_key_request(SilcClient client,
288                                              SilcClientConnection conn,
289                                              SilcClientEntry client_entry)
290 {
291   const char *cipher, *hmac;
292
293   SILC_LOG_DEBUG(("Sending private message key request"));
294
295   cipher = silc_cipher_get_name(client_entry->internal.send_key);
296   hmac = silc_hmac_get_name(client_entry->internal.hmac_send);
297
298   /* Send the packet */
299   return silc_packet_send_va_ext(conn->stream,
300                                  SILC_PACKET_PRIVATE_MESSAGE_KEY,
301                                  0, 0, NULL, SILC_ID_CLIENT,
302                                  &client_entry->id, NULL, NULL,
303                                  SILC_STR_UI_SHORT(strlen(cipher)),
304                                  SILC_STR_DATA(cipher, strlen(cipher)),
305                                  SILC_STR_UI_SHORT(strlen(hmac)),
306                                  SILC_STR_DATA(hmac, strlen(hmac)),
307                                  SILC_STR_END);
308 }
309
310 /* Client resolving callback.  Here we simply mark that we are the responder
311    side of this private message key request.  */
312
313 static void silc_client_private_message_key_cb(SilcClient client,
314                                                SilcClientConnection conn,
315                                                SilcStatus status,
316                                                SilcDList clients,
317                                                void *context)
318 {
319   SilcPacket packet = context;
320   unsigned char *cipher = NULL, *hmac = NULL;
321   SilcClientEntry client_entry;
322   int ret;
323
324   if (!clients) {
325     silc_packet_free(packet);
326     return;
327   }
328
329   /* Parse the private message key payload */
330   ret = silc_buffer_unformat(&packet->buffer,
331                              SILC_STR_UI16_STRING_ALLOC(&cipher),
332                              SILC_STR_UI16_STRING_ALLOC(&hmac),
333                              SILC_STR_END);
334   if (!ret)
335     goto out;
336
337   /* Mark that we are responder */
338   client_entry = silc_dlist_get(clients);
339   client_entry->internal.prv_resp = TRUE;
340
341   /* XXX we should notify application that remote wants to set up the
342      static key.  And we should tell if we already have key with remote.
343      Application should return status telling whether to delete the key
344      or not. */
345
346  out:
347   silc_free(cipher);
348   silc_free(hmac);
349   silc_packet_free(packet);
350 }
351
352 /* Processes incoming Private Message Key payload to indicate that the
353    sender whishes to set up a static private message key. */
354
355 SILC_FSM_STATE(silc_client_private_message_key)
356 {
357   SilcClientConnection conn = fsm_context;
358   SilcClient client = conn->client;
359   SilcPacket packet = state_context;
360   SilcClientID remote_id;
361
362   if (packet->src_id_type != SILC_ID_CLIENT) {
363     silc_packet_free(packet);
364     return SILC_FSM_FINISH;
365   }
366
367   if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
368                       &remote_id, sizeof(remote_id))) {
369     silc_packet_free(packet);
370     return SILC_FSM_FINISH;
371   }
372
373   /* Always resolve the remote client.  The actual packet is processed
374      in the resolving callback. */
375   SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
376                                        client, conn, &remote_id, NULL,
377                                        silc_client_private_message_key_cb,
378                                        fsm));
379 }
380
381 /* Adds new private message key to `client_entry'.  If we are setting this
382    before receiving request for it from `client_entry' we will send the
383    request to the client.  Otherwise, we are responder side. */
384
385 SilcBool silc_client_add_private_message_key(SilcClient client,
386                                              SilcClientConnection conn,
387                                              SilcClientEntry client_entry,
388                                              const char *cipher,
389                                              const char *hmac,
390                                              unsigned char *key,
391                                              SilcUInt32 key_len)
392 {
393   SilcSKEKeyMaterial keymat;
394   SilcBool ret;
395
396   if (!client || !client_entry)
397     return FALSE;
398
399   /* Return FALSE if key already set */
400   if (client_entry->internal.send_key && client_entry->internal.receive_key)
401     return FALSE;
402
403   if (!cipher)
404     cipher = SILC_DEFAULT_CIPHER;
405   if (!hmac)
406     hmac = SILC_DEFAULT_HMAC;
407
408   /* Check the requested cipher and HMAC */
409   if (!silc_cipher_is_supported(cipher))
410     return FALSE;
411   if (!silc_hmac_is_supported(hmac))
412     return FALSE;
413
414   /* Save the key */
415   client_entry->internal.key = silc_memdup(key, key_len);
416   client_entry->internal.key_len = key_len;
417
418   /* Produce the key material as the protocol defines */
419   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
420                                               conn->internal->sha1hash);
421   if (!keymat)
422     return FALSE;
423
424   /* Set the key into use */
425   ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
426                                                 cipher, hmac, keymat);
427   client_entry->internal.generated = FALSE;
428
429   /* Free the key material */
430   silc_ske_free_key_material(keymat);
431
432   /* If we are setting the key without a request from the remote client,
433      we will send request to remote. */
434   if (!client_entry->internal.prv_resp)
435     silc_client_send_private_message_key_request(client, conn, client_entry);
436
437   return ret;
438 }
439
440 /* Same as above but takes the key material from the SKE key material
441    structure. */
442
443 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
444                                                  SilcClientConnection conn,
445                                                  SilcClientEntry client_entry,
446                                                  const char *cipher,
447                                                  const char *hmac,
448                                                  SilcSKEKeyMaterial keymat)
449 {
450   if (!client || !client_entry)
451     return FALSE;
452
453   /* Return FALSE if key already set */
454   if (client_entry->internal.send_key && client_entry->internal.receive_key)
455     return FALSE;
456
457   if (!cipher)
458     cipher = SILC_DEFAULT_CIPHER;
459   if (!hmac)
460     hmac = SILC_DEFAULT_HMAC;
461
462   /* Check the requested cipher and HMAC */
463   if (!silc_cipher_is_supported(cipher))
464     return FALSE;
465   if (!silc_hmac_is_supported(hmac))
466     return FALSE;
467
468   client_entry->internal.generated = TRUE;
469
470   /* Allocate the cipher and HMAC */
471   if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
472     return FALSE;
473   if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
474     return FALSE;
475   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
476     return FALSE;
477   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
478     return FALSE;
479
480   /* Set the keys */
481   if (client_entry->internal.prv_resp) {
482     silc_cipher_set_key(client_entry->internal.send_key,
483                         keymat->receive_enc_key,
484                         keymat->enc_key_len, TRUE);
485     silc_cipher_set_iv(client_entry->internal.send_key,
486                        keymat->receive_iv);
487     silc_cipher_set_key(client_entry->internal.receive_key,
488                         keymat->send_enc_key,
489                         keymat->enc_key_len, FALSE);
490     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
491     silc_hmac_set_key(client_entry->internal.hmac_send,
492                       keymat->receive_hmac_key,
493                       keymat->hmac_key_len);
494     silc_hmac_set_key(client_entry->internal.hmac_receive,
495                       keymat->send_hmac_key,
496                       keymat->hmac_key_len);
497   } else {
498     silc_cipher_set_key(client_entry->internal.send_key,
499                         keymat->send_enc_key,
500                         keymat->enc_key_len, TRUE);
501     silc_cipher_set_iv(client_entry->internal.send_key,
502                        keymat->send_iv);
503     silc_cipher_set_key(client_entry->internal.receive_key,
504                         keymat->receive_enc_key,
505                         keymat->enc_key_len, FALSE);
506     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
507     silc_hmac_set_key(client_entry->internal.hmac_send,
508                       keymat->send_hmac_key,
509                       keymat->hmac_key_len);
510     silc_hmac_set_key(client_entry->internal.hmac_receive,
511                       keymat->receive_hmac_key,
512                       keymat->hmac_key_len);
513   }
514
515   return TRUE;
516 }
517
518 /* Removes the private message from the library. The key won't be used
519    after this to protect the private messages with the remote `client_entry'
520    client. Returns FALSE on error, TRUE otherwise. */
521
522 SilcBool silc_client_del_private_message_key(SilcClient client,
523                                              SilcClientConnection conn,
524                                              SilcClientEntry client_entry)
525 {
526   if (!client || !client_entry)
527     return FALSE;
528
529   if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
530     return FALSE;
531
532   silc_cipher_free(client_entry->internal.send_key);
533   silc_cipher_free(client_entry->internal.receive_key);
534
535   if (client_entry->internal.key) {
536     memset(client_entry->internal.key, 0, client_entry->internal.key_len);
537     silc_free(client_entry->internal.key);
538   }
539
540   client_entry->internal.send_key = NULL;
541   client_entry->internal.receive_key = NULL;
542   client_entry->internal.key = NULL;
543   client_entry->internal.prv_resp = FALSE;
544
545   return TRUE;
546 }
547
548 /* Returns array of set private message keys associated to the connection
549    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
550    count to the `key_count' argument. The array must be freed by the caller
551    by calling the silc_client_free_private_message_keys function. Note:
552    the keys returned in the array is in raw format. It might not be desired
553    to show the keys as is. The application might choose not to show the keys
554    at all or to show the fingerprints of the keys. */
555
556 SilcPrivateMessageKeys
557 silc_client_list_private_message_keys(SilcClient client,
558                                       SilcClientConnection conn,
559                                       SilcUInt32 *key_count)
560 {
561   SilcPrivateMessageKeys keys;
562   SilcUInt32 count = 0;
563   SilcList list;
564   SilcIDCacheEntry id_cache;
565   SilcClientEntry entry;
566
567   if (!client || !conn)
568     return NULL;
569
570   silc_mutex_lock(conn->internal->lock);
571   if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
572     silc_mutex_unlock(conn->internal->lock);
573     return NULL;
574   }
575
576   keys = silc_calloc(silc_list_count(list), sizeof(*keys));
577   if (!keys) {
578     silc_mutex_unlock(conn->internal->lock);
579     return NULL;
580   }
581
582   silc_list_start(list);
583   while ((id_cache = silc_list_get(list))) {
584     entry = id_cache->context;
585     if (entry->internal.send_key) {
586       keys[count].client_entry = entry;
587       keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
588                                                         send_key);
589       keys[count].key = (entry->internal.generated == FALSE ?
590                          entry->internal.key : NULL);
591       keys[count].key_len = (entry->internal.generated == FALSE ?
592                              entry->internal.key_len : 0);
593       count++;
594     }
595   }
596
597   silc_mutex_unlock(conn->internal->lock);
598
599   if (key_count)
600     *key_count = count;
601
602   return keys;
603 }
604
605 /* Frees the SilcPrivateMessageKeys array returned by the function
606    silc_client_list_private_message_keys. */
607
608 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
609                                            SilcUInt32 key_count)
610 {
611   silc_free(keys);
612 }
613
614 /* Sets away `message'.  The away message may be set when the client's
615    mode is changed to SILC_UMODE_GONE and the client whishes to reply
616    to anyone who sends private message.  The `message' will be sent
617    automatically back to the the client who send private message.  If
618    away message is already set this replaces the old message with the
619    new one.  If `message' is NULL the old away message is removed.
620    The sender may freely free the memory of the `message'. */
621
622 SilcBool silc_client_set_away_message(SilcClient client,
623                                       SilcClientConnection conn,
624                                       char *message)
625 {
626   if (!client || !conn)
627     return FALSE;
628
629   if (!message) {
630     silc_free(conn->internal->away_message);
631     conn->internal->away_message = NULL;
632     return TRUE;
633   }
634
635   if (conn->internal->away_message)
636     silc_free(conn->internal->away_message);
637
638   conn->internal->away_message = strdup(message);
639   if (!conn->internal->away_message)
640     return FALSE;
641
642   return TRUE;
643 }