Static analyzer bug fixes
[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   if (client_entry)
333     client_entry->internal.prv_resp = TRUE;
334
335   /* XXX we should notify application that remote wants to set up the
336      static key.  And we should tell if we already have key with remote.
337      Application should return status telling whether to delete the key
338      or not. */
339
340  out:
341   silc_free(cipher);
342   silc_free(hmac);
343   silc_packet_free(packet);
344   silc_fsm_finish(thread);
345 }
346
347 /* Processes incoming Private Message Key payload to indicate that the
348    sender whishes to set up a static private message key. */
349
350 SILC_FSM_STATE(silc_client_private_message_key)
351 {
352   SilcClientConnection conn = fsm_context;
353   SilcClient client = conn->client;
354   SilcPacket packet = state_context;
355   SilcClientID remote_id;
356
357   if (packet->src_id_type != SILC_ID_CLIENT) {
358     silc_packet_free(packet);
359     return SILC_FSM_FINISH;
360   }
361
362   if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
363                       &remote_id, sizeof(remote_id))) {
364     silc_packet_free(packet);
365     return SILC_FSM_FINISH;
366   }
367
368   /* Always resolve the remote client.  The actual packet is processed
369      in the resolving callback. */
370   SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
371                                        client, conn, &remote_id, NULL,
372                                        silc_client_private_message_key_cb,
373                                        fsm));
374 }
375
376 /* Adds new private message key to `client_entry'.  If we are setting this
377    before receiving request for it from `client_entry' we will send the
378    request to the client.  Otherwise, we are responder side. */
379
380 SilcBool silc_client_add_private_message_key(SilcClient client,
381                                              SilcClientConnection conn,
382                                              SilcClientEntry client_entry,
383                                              const char *cipher,
384                                              const char *hmac,
385                                              unsigned char *key,
386                                              SilcUInt32 key_len)
387 {
388   SilcSKEKeyMaterial keymat;
389   SilcBool ret;
390
391   if (!client || !client_entry)
392     return FALSE;
393
394   /* Return FALSE if key already set */
395   if (client_entry->internal.send_key && client_entry->internal.receive_key)
396     return FALSE;
397
398   if (!cipher)
399     cipher = SILC_DEFAULT_CIPHER;
400   if (!hmac)
401     hmac = SILC_DEFAULT_HMAC;
402
403   /* Check the requested cipher and HMAC */
404   if (!silc_cipher_is_supported(cipher))
405     return FALSE;
406   if (!silc_hmac_is_supported(hmac))
407     return FALSE;
408
409   /* Save the key */
410   client_entry->internal.key = silc_memdup(key, key_len);
411   client_entry->internal.key_len = key_len;
412
413   /* Produce the key material as the protocol defines */
414   keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
415                                               conn->internal->sha1hash);
416   if (!keymat)
417     return FALSE;
418
419   /* Set the key into use */
420   ret = silc_client_add_private_message_key_ske(client, conn, client_entry,
421                                                 cipher, hmac, keymat);
422   client_entry->internal.generated = FALSE;
423
424   /* Free the key material */
425   silc_ske_free_key_material(keymat);
426
427   /* If we are setting the key without a request from the remote client,
428      we will send request to remote. */
429   if (!client_entry->internal.prv_resp)
430     silc_client_send_private_message_key_request(client, conn, client_entry);
431
432   return ret;
433 }
434
435 /* Same as above but takes the key material from the SKE key material
436    structure. */
437
438 SilcBool silc_client_add_private_message_key_ske(SilcClient client,
439                                                  SilcClientConnection conn,
440                                                  SilcClientEntry client_entry,
441                                                  const char *cipher,
442                                                  const char *hmac,
443                                                  SilcSKEKeyMaterial keymat)
444 {
445   if (!client || !client_entry)
446     return FALSE;
447
448   /* Return FALSE if key already set */
449   if (client_entry->internal.send_key && client_entry->internal.receive_key)
450     return FALSE;
451
452   if (!cipher)
453     cipher = SILC_DEFAULT_CIPHER;
454   if (!hmac)
455     hmac = SILC_DEFAULT_HMAC;
456
457   /* Check the requested cipher and HMAC */
458   if (!silc_cipher_is_supported(cipher))
459     return FALSE;
460   if (!silc_hmac_is_supported(hmac))
461     return FALSE;
462
463   client_entry->internal.generated = TRUE;
464
465   /* Allocate the cipher and HMAC */
466   if (!silc_cipher_alloc(cipher, &client_entry->internal.send_key))
467     return FALSE;
468   if (!silc_cipher_alloc(cipher, &client_entry->internal.receive_key))
469     return FALSE;
470   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_send))
471     return FALSE;
472   if (!silc_hmac_alloc(hmac, NULL, &client_entry->internal.hmac_receive))
473     return FALSE;
474
475   /* Set the keys */
476   if (client_entry->internal.prv_resp) {
477     silc_cipher_set_key(client_entry->internal.send_key,
478                         keymat->receive_enc_key,
479                         keymat->enc_key_len, TRUE);
480     silc_cipher_set_iv(client_entry->internal.send_key,
481                        keymat->receive_iv);
482     silc_cipher_set_key(client_entry->internal.receive_key,
483                         keymat->send_enc_key,
484                         keymat->enc_key_len, FALSE);
485     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->send_iv);
486     silc_hmac_set_key(client_entry->internal.hmac_send,
487                       keymat->receive_hmac_key,
488                       keymat->hmac_key_len);
489     silc_hmac_set_key(client_entry->internal.hmac_receive,
490                       keymat->send_hmac_key,
491                       keymat->hmac_key_len);
492   } else {
493     silc_cipher_set_key(client_entry->internal.send_key,
494                         keymat->send_enc_key,
495                         keymat->enc_key_len, TRUE);
496     silc_cipher_set_iv(client_entry->internal.send_key,
497                        keymat->send_iv);
498     silc_cipher_set_key(client_entry->internal.receive_key,
499                         keymat->receive_enc_key,
500                         keymat->enc_key_len, FALSE);
501     silc_cipher_set_iv(client_entry->internal.receive_key, keymat->receive_iv);
502     silc_hmac_set_key(client_entry->internal.hmac_send,
503                       keymat->send_hmac_key,
504                       keymat->hmac_key_len);
505     silc_hmac_set_key(client_entry->internal.hmac_receive,
506                       keymat->receive_hmac_key,
507                       keymat->hmac_key_len);
508   }
509
510   return TRUE;
511 }
512
513 /* Removes the private message from the library. The key won't be used
514    after this to protect the private messages with the remote `client_entry'
515    client. Returns FALSE on error, TRUE otherwise. */
516
517 SilcBool silc_client_del_private_message_key(SilcClient client,
518                                              SilcClientConnection conn,
519                                              SilcClientEntry client_entry)
520 {
521   if (!client || !client_entry)
522     return FALSE;
523
524   if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
525     return FALSE;
526
527   silc_cipher_free(client_entry->internal.send_key);
528   silc_cipher_free(client_entry->internal.receive_key);
529
530   if (client_entry->internal.key) {
531     memset(client_entry->internal.key, 0, client_entry->internal.key_len);
532     silc_free(client_entry->internal.key);
533   }
534
535   client_entry->internal.send_key = NULL;
536   client_entry->internal.receive_key = NULL;
537   client_entry->internal.key = NULL;
538   client_entry->internal.prv_resp = FALSE;
539
540   return TRUE;
541 }
542
543 /* Returns array of set private message keys associated to the connection
544    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
545    count to the `key_count' argument. The array must be freed by the caller
546    by calling the silc_client_free_private_message_keys function. Note:
547    the keys returned in the array is in raw format. It might not be desired
548    to show the keys as is. The application might choose not to show the keys
549    at all or to show the fingerprints of the keys. */
550
551 SilcPrivateMessageKeys
552 silc_client_list_private_message_keys(SilcClient client,
553                                       SilcClientConnection conn,
554                                       SilcUInt32 *key_count)
555 {
556   SilcPrivateMessageKeys keys;
557   SilcUInt32 count = 0;
558   SilcList list;
559   SilcIDCacheEntry id_cache;
560   SilcClientEntry entry;
561
562   if (!client || !conn)
563     return NULL;
564
565   silc_mutex_lock(conn->internal->lock);
566   if (!silc_idcache_get_all(conn->internal->client_cache, &list)) {
567     silc_mutex_unlock(conn->internal->lock);
568     return NULL;
569   }
570
571   keys = silc_calloc(silc_list_count(list), sizeof(*keys));
572   if (!keys) {
573     silc_mutex_unlock(conn->internal->lock);
574     return NULL;
575   }
576
577   silc_list_start(list);
578   while ((id_cache = silc_list_get(list))) {
579     entry = id_cache->context;
580     if (entry->internal.send_key) {
581       keys[count].client_entry = entry;
582       keys[count].cipher = (char *)silc_cipher_get_name(entry->internal.
583                                                         send_key);
584       keys[count].key = (entry->internal.generated == FALSE ?
585                          entry->internal.key : NULL);
586       keys[count].key_len = (entry->internal.generated == FALSE ?
587                              entry->internal.key_len : 0);
588       count++;
589     }
590   }
591
592   silc_mutex_unlock(conn->internal->lock);
593
594   if (key_count)
595     *key_count = count;
596
597   return keys;
598 }
599
600 /* Frees the SilcPrivateMessageKeys array returned by the function
601    silc_client_list_private_message_keys. */
602
603 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
604                                            SilcUInt32 key_count)
605 {
606   silc_free(keys);
607 }
608
609 /* Return private message key from the client entry. */
610
611 SilcBool
612 silc_client_private_message_key_is_set(SilcClient client,
613                                        SilcClientConnection conn,
614                                        SilcClientEntry client_entry)
615 {
616   return client_entry->internal.send_key != NULL;
617 }
618
619 /* Sets away `message'.  The away message may be set when the client's
620    mode is changed to SILC_UMODE_GONE and the client whishes to reply
621    to anyone who sends private message.  The `message' will be sent
622    automatically back to the the client who send private message.  If
623    away message is already set this replaces the old message with the
624    new one.  If `message' is NULL the old away message is removed.
625    The sender may freely free the memory of the `message'. */
626
627 SilcBool silc_client_set_away_message(SilcClient client,
628                                       SilcClientConnection conn,
629                                       char *message)
630 {
631   if (!client || !conn)
632     return FALSE;
633
634   if (!message) {
635     silc_free(conn->internal->away_message);
636     conn->internal->away_message = NULL;
637     return TRUE;
638   }
639
640   if (conn->internal->away_message)
641     silc_free(conn->internal->away_message);
642
643   conn->internal->away_message = strdup(message);
644   if (!conn->internal->away_message)
645     return FALSE;
646
647   return TRUE;
648 }