fix CID 1596595: Resource leaks, and CID 1596594: (CHECKED_RETURN)
[claws.git] / src / privacy.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #include "config.h"
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24
25 #include "privacy.h"
26 #include "procmime.h"
27 #include "procmsg.h"
28
29 static GSList *systems = NULL;
30 static gchar *privacy_last_error = NULL;
31
32 void privacy_set_error(const gchar *format, ...)
33 {
34         va_list args;
35         gchar buf[BUFSIZ];
36
37         va_start(args, format);
38         g_vsnprintf(buf, BUFSIZ, format, args);
39         va_end(args);
40         g_free(privacy_last_error);
41         privacy_last_error = g_strdup(buf);
42 }
43
44 static gchar tmp_privacy_error[BUFSIZ];
45
46 void privacy_reset_error(void)
47 {
48         g_free(privacy_last_error);
49         privacy_last_error = NULL;
50 }
51
52 gboolean privacy_peek_error(void)
53 {
54         return (privacy_last_error != NULL);
55 }
56
57 const gchar *privacy_get_error (void)
58 {
59         if (privacy_last_error) {
60                 strncpy2(tmp_privacy_error, privacy_last_error, BUFSIZ-1);
61                 privacy_reset_error();
62                 return tmp_privacy_error;
63         } else {
64                 return _("Unknown error");
65         }
66 }
67
68 static PrivacySystem *privacy_data_get_system(PrivacyData *data)
69 {
70         /* Make sure the cached system is still registered */
71         if (data->system && g_slist_find(systems, data->system))
72                 return data->system;
73         else
74                 return NULL;
75 }
76 /**
77  * Register a new Privacy System
78  *
79  * \param system The Privacy System that should be registered
80  */
81 void privacy_register_system(PrivacySystem *system)
82 {
83         systems = g_slist_append(systems, system);
84 }
85
86 /**
87  * Unregister a new Privacy System. The system must not be in
88  * use anymore when it is unregistered.
89  *
90  * \param system The Privacy System that should be unregistered
91  */
92 void privacy_unregister_system(PrivacySystem *system)
93 {
94         systems = g_slist_remove(systems, system);
95 }
96
97 /**
98  * Free a PrivacyData of a PrivacySystem
99  *
100  * \param privacydata The data to free
101  */
102 void privacy_free_privacydata(PrivacyData *privacydata)
103 {
104         PrivacySystem *system = NULL;
105         
106         cm_return_if_fail(privacydata != NULL);
107
108         system = privacy_data_get_system(privacydata);
109         if (!system)
110                 return;
111         system->free_privacydata(privacydata);
112 }
113
114 void privacy_free_signature_data(gpointer data)
115 {
116         SignatureData *sig_data = (SignatureData *)data;
117
118         cm_return_if_fail(sig_data != NULL);
119
120         g_free(sig_data->info_short);
121         g_free(sig_data->info_full);
122         g_free(sig_data);
123 }
124
125 void privacy_free_sig_check_task_result(gpointer data)
126 {
127         SigCheckTaskResult *result = (SigCheckTaskResult *)data;
128
129         privacy_free_signature_data(result->sig_data);
130         if (result->newinfo)
131                 procmime_mimeinfo_free_all(&result->newinfo);
132         g_free(result);
133 }
134
135 /**
136  * Check if a MimeInfo is signed with one of the available
137  * privacy system. If a privacydata is set in the MimeInfo
138  * it will directory return the return value by the system
139  * set in the privacy data or check all available privacy
140  * systems otherwise.
141  *
142  * \return True if the MimeInfo has a signature
143  */
144 gboolean privacy_mimeinfo_is_signed(MimeInfo *mimeinfo)
145 {
146         GSList *cur;
147         cm_return_val_if_fail(mimeinfo != NULL, FALSE);
148
149         if (mimeinfo->privacy != NULL) {
150                 PrivacySystem *system = 
151                         privacy_data_get_system(mimeinfo->privacy);
152
153                 if (system == NULL) {
154                         mimeinfo->privacy = NULL;
155                         goto try_others;
156                 }
157
158                 if (system->is_signed != NULL)
159                         return system->is_signed(mimeinfo);
160                 else
161                         return FALSE;
162         }
163 try_others:
164         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
165                 PrivacySystem *system = (PrivacySystem *) cur->data;
166
167                 if(system->is_signed != NULL && system->is_signed(mimeinfo))
168                         return TRUE;
169         }
170
171         return FALSE;
172 }
173
174 struct SignedState {
175         MsgInfo *msginfo;
176         gchar **system;
177 };
178
179 static void msginfo_set_signed_flag(GNode *node, gpointer data)
180 {
181         struct SignedState *sstate = (struct SignedState *)data;
182         MsgInfo *msginfo = sstate->msginfo;
183         MimeInfo *mimeinfo = node->data;
184         
185         if (privacy_mimeinfo_is_signed(mimeinfo)) {
186                 procmsg_msginfo_set_flags(msginfo, 0, MSG_SIGNED);
187                 if (sstate->system && !*(sstate->system) && mimeinfo->privacy)
188                         *(sstate->system) = g_strdup(mimeinfo->privacy->system->id);
189         }
190         if (privacy_mimeinfo_is_encrypted(mimeinfo)) {
191                 procmsg_msginfo_set_flags(msginfo, 0, MSG_ENCRYPTED);
192                 if (sstate->system && !*(sstate->system) && mimeinfo->privacy)
193                         *(sstate->system) = g_strdup(mimeinfo->privacy->system->id);
194         } else {
195                 /* searching inside encrypted parts doesn't really make sense */
196                 g_node_children_foreach(mimeinfo->node, G_TRAVERSE_ALL, msginfo_set_signed_flag, sstate);
197         }
198 }
199
200 void privacy_msginfo_get_signed_state(MsgInfo *msginfo, gchar **system)
201 {
202         struct SignedState sstate;
203         MimeInfo *mimeinfo = procmime_scan_message(msginfo);
204         if (!mimeinfo)
205                 return;
206         sstate.msginfo = msginfo;
207         sstate.system = system;
208         g_node_children_foreach(mimeinfo->node, G_TRAVERSE_ALL, msginfo_set_signed_flag, &sstate);
209 }
210
211 /**
212  * Check the signature of a MimeInfo. privacy_mimeinfo_is_signed
213  * should be called before otherwise it is done by this function.
214  * If the MimeInfo is not signed an error code will be returned.
215  *
216  * \return Error code indicating the result of the check,
217  *         < 0 if an error occurred
218  */
219 gint privacy_mimeinfo_check_signature(MimeInfo *mimeinfo,
220         GCancellable *cancellable,
221         GAsyncReadyCallback callback,
222         gpointer user_data)
223 {
224         PrivacySystem *system;
225
226         if (mimeinfo == NULL)
227                 g_error("siginfo was NULL");
228
229         if (mimeinfo->privacy == NULL) {
230                 g_warning("mimeinfo->privacy was NULL");
231
232                 privacy_mimeinfo_is_signed(mimeinfo);
233                 if (mimeinfo->privacy == NULL) {
234                         g_error("failed to set up PrivacyData");
235                 }
236         }
237
238         system = privacy_data_get_system(mimeinfo->privacy);
239         if (system == NULL)
240                 g_error("failed to get privacy system");
241         else if (system->check_signature == NULL)
242                 g_error("didn't find check_signature function");
243
244         return system->check_signature(mimeinfo, cancellable, callback, user_data);
245 }
246
247 SignatureStatus privacy_mimeinfo_get_sig_status(MimeInfo *mimeinfo)
248 {
249         PrivacySystem *system;
250
251         cm_return_val_if_fail(mimeinfo != NULL, -1);
252
253         if (mimeinfo->privacy == NULL) {
254                 privacy_mimeinfo_is_signed(mimeinfo);
255
256                 if (mimeinfo->privacy == NULL)
257                         return SIGNATURE_UNCHECKED;
258         }
259
260         system = privacy_data_get_system(mimeinfo->privacy);
261         if (system == NULL)
262                 return SIGNATURE_UNCHECKED;
263
264         if (mimeinfo->sig_data == NULL)
265                 return SIGNATURE_UNCHECKED;
266         else
267                 return mimeinfo->sig_data->status;
268 }
269
270 gchar *privacy_mimeinfo_get_sig_info(MimeInfo *mimeinfo, gboolean full)
271 {
272         PrivacySystem *system;
273         gchar *info;
274
275         cm_return_val_if_fail(mimeinfo != NULL, NULL);
276
277         if (mimeinfo->privacy == NULL) {
278                 privacy_mimeinfo_is_signed(mimeinfo);
279
280                 if (mimeinfo->privacy == NULL)
281                         return _("No signature found");
282         }
283
284         system = privacy_data_get_system(mimeinfo->privacy);
285         if (system == NULL)
286                 return _("No signature found");
287
288         if (mimeinfo->sig_data == NULL)
289                 return _("No information available");
290
291         info = full ? mimeinfo->sig_data->info_full : mimeinfo->sig_data->info_short;
292         if (info == NULL)
293                 return _("No information available");
294
295         return info;
296 }
297
298 gboolean privacy_mimeinfo_is_encrypted(MimeInfo *mimeinfo)
299 {
300         GSList *cur;
301         cm_return_val_if_fail(mimeinfo != NULL, FALSE);
302
303         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
304                 PrivacySystem *system = (PrivacySystem *) cur->data;
305
306                 if(system->is_encrypted != NULL && system->is_encrypted(mimeinfo))
307                         return TRUE;
308         }
309
310         return FALSE;
311 }
312
313 static gint decrypt(MimeInfo *mimeinfo, PrivacySystem *system)
314 {
315         MimeInfo *decryptedinfo, *parentinfo;
316         gint childnumber;
317         
318         cm_return_val_if_fail(system->decrypt != NULL, -1);
319         
320         decryptedinfo = system->decrypt(mimeinfo);
321         if (decryptedinfo == NULL)
322                 return -1;
323
324         parentinfo = procmime_mimeinfo_parent(mimeinfo);
325         childnumber = g_node_child_index(parentinfo->node, mimeinfo);
326         
327         procmime_mimeinfo_free_all(&mimeinfo);
328
329         g_node_insert(parentinfo->node, childnumber, decryptedinfo->node);
330
331         return 0;
332 }
333
334 gint privacy_mimeinfo_decrypt(MimeInfo *mimeinfo)
335 {
336         GSList *cur;
337         cm_return_val_if_fail(mimeinfo != NULL, FALSE);
338
339         procmime_decode_content(mimeinfo);
340
341         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
342                 PrivacySystem *system = (PrivacySystem *) cur->data;
343
344                 if(system->is_encrypted != NULL && system->is_encrypted(mimeinfo))
345                         return decrypt(mimeinfo, system);
346         }
347
348         return -1;
349 }
350
351 GSList *privacy_get_system_ids()
352 {
353         GSList *cur;
354         GSList *ret = NULL;
355
356         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
357                 PrivacySystem *system = (PrivacySystem *) cur->data;
358
359                 ret = g_slist_append(ret, g_strdup(system->id));
360         }
361
362         return ret;
363 }
364
365 static PrivacySystem *privacy_get_system(const gchar *id)
366 {
367         GSList *cur;
368
369         cm_return_val_if_fail(id != NULL, NULL);
370
371         for(cur = systems; cur != NULL; cur = g_slist_next(cur)) {
372                 PrivacySystem *system = (PrivacySystem *) cur->data;
373
374                 if(strcmp(id, system->id) == 0)
375                         return system;
376         }
377
378         return NULL;
379 }
380
381 const gchar *privacy_system_get_name(const gchar *id)
382 {
383         PrivacySystem *system;
384
385         cm_return_val_if_fail(id != NULL, NULL);
386
387         system = privacy_get_system(id);
388         if (system == NULL)
389                 return NULL;
390
391         return system->name;
392 }
393
394 gboolean privacy_system_can_sign(const gchar *id)
395 {
396         PrivacySystem *system;
397
398         cm_return_val_if_fail(id != NULL, FALSE);
399
400         system = privacy_get_system(id);
401         if (system == NULL)
402                 return FALSE;
403
404         return system->can_sign;
405 }
406
407 gboolean privacy_system_can_encrypt(const gchar *id)
408 {
409         PrivacySystem *system;
410
411         cm_return_val_if_fail(id != NULL, FALSE);
412
413         system = privacy_get_system(id);
414         if (system == NULL)
415                 return FALSE;
416
417         return system->can_encrypt;
418 }
419
420 gboolean privacy_sign(const gchar *id, MimeInfo *target, PrefsAccount *account, const gchar *from_addr)
421 {
422         PrivacySystem *system;
423
424         cm_return_val_if_fail(id != NULL, FALSE);
425         cm_return_val_if_fail(target != NULL, FALSE);
426
427         system = privacy_get_system(id);
428         if (system == NULL)
429                 return FALSE;
430         if (!system->can_sign)
431                 return FALSE;
432         if (system->sign == NULL)
433                 return FALSE;
434
435         return system->sign(target, account, from_addr);
436 }
437
438 gchar *privacy_get_encrypt_data(const gchar *id, GSList *recp_names)
439 {
440         PrivacySystem *system;
441         gchar *ret = NULL;
442         GSList *uniq_names = NULL, *cur;
443
444         cm_return_val_if_fail(id != NULL, NULL);
445         cm_return_val_if_fail(recp_names != NULL, NULL);
446
447         system = privacy_get_system(id);
448         if (system == NULL)
449                 return NULL;
450         if (!system->can_encrypt)
451                 return NULL;
452         if (system->get_encrypt_data == NULL)
453                 return NULL;
454
455         for (cur = recp_names; cur; cur = cur->next) {
456                 if (!g_slist_find_custom(uniq_names, cur->data, (GCompareFunc)strcmp)) {
457                         uniq_names = g_slist_prepend(uniq_names, cur->data);
458                 }
459         }
460         ret = system->get_encrypt_data(uniq_names);
461         
462         g_slist_free(uniq_names);
463         return ret;
464 }
465
466 const gchar *privacy_get_encrypt_warning(const gchar *id)
467 {
468         PrivacySystem *system;
469
470         cm_return_val_if_fail(id != NULL, NULL);
471
472         system = privacy_get_system(id);
473         if (system == NULL)
474                 return NULL;
475         if (!system->can_encrypt)
476                 return NULL;
477         if (system->get_encrypt_warning == NULL)
478                 return NULL;
479
480         return system->get_encrypt_warning();
481 }
482
483 void privacy_inhibit_encrypt_warning(const gchar *id, gboolean inhibit)
484 {
485         PrivacySystem *system;
486
487         cm_return_if_fail(id != NULL);
488
489         system = privacy_get_system(id);
490         if (system == NULL)
491                 return;
492         if (!system->can_encrypt)
493                 return;
494         if (system->inhibit_encrypt_warning == NULL)
495                 return;
496
497         system->inhibit_encrypt_warning(inhibit);
498 }
499
500 gboolean privacy_encrypt(const gchar *id, MimeInfo *mimeinfo, const gchar *encdata)
501 {
502         PrivacySystem *system;
503
504         cm_return_val_if_fail(id != NULL, FALSE);
505         cm_return_val_if_fail(mimeinfo != NULL, FALSE);
506         if (encdata == NULL) {
507                 privacy_set_error(_("No recipient keys defined."));
508                 return FALSE;
509         }
510
511         system = privacy_get_system(id);
512         if (system == NULL)
513                 return FALSE;
514         if (!system->can_encrypt)
515                 return FALSE;
516         if (system->encrypt == NULL)
517                 return FALSE;
518
519         return system->encrypt(mimeinfo, encdata);
520 }
521
522 gboolean privacy_auto_check_signatures(MimeInfo *mimeinfo)
523 {
524         PrivacySystem *system;
525
526         cm_return_val_if_fail(mimeinfo != NULL, FALSE);
527
528         if (mimeinfo->privacy == NULL)
529                 privacy_mimeinfo_is_signed(mimeinfo);
530
531         if (mimeinfo->privacy == NULL)
532                 return FALSE;
533
534         system = privacy_data_get_system(mimeinfo->privacy);
535         if (system == NULL)
536                 return FALSE;
537         if (system->auto_check_signatures == NULL)
538                 return FALSE;
539
540         return system->auto_check_signatures();
541 }