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