c77ac8c0808755ea9e9b7a22c700b80bf86550ce
[platform/upstream/evolution-data-server.git] / modules / trust-prompt / module-trust-prompt.c
1 /*
2  * module-trust-prompt.c
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22
23 #include <glib/gi18n-lib.h>
24
25 #include <libebackend/libebackend.h>
26 #include "trust-prompt.h"
27
28 /* Standard GObject macros */
29 #define E_TYPE_TRUST_PROMPT (e_trust_prompt_get_type ())
30 #define E_TRUST_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_TRUST_PROMPT, ETrustPrompt))
31
32 typedef struct _ETrustPrompt ETrustPrompt;
33 typedef struct _ETrustPromptClass ETrustPromptClass;
34
35 struct _ETrustPrompt {
36         EUserPrompterServerExtension parent;
37 };
38
39 struct _ETrustPromptClass {
40         EUserPrompterServerExtensionClass parent_class;
41 };
42
43 /* Module Entry Points */
44 void e_module_load (GTypeModule *type_module);
45 void e_module_unload (GTypeModule *type_module);
46
47 /* Forward Declarations */
48 GType e_trust_prompt_get_type (void);
49
50 G_DEFINE_DYNAMIC_TYPE (
51         ETrustPrompt,
52         e_trust_prompt,
53         E_TYPE_USER_PROMPTER_SERVER_EXTENSION)
54
55 #define TRUST_PROMPT_DIALOG "ETrustPrompt::trust-prompt"
56
57 /* dialog definitions */
58
59 /* ETrustPrompt::trust-prompt
60  * The dialog expects these parameters:
61  *    "host" - host from which the certificate is received
62  *    "markup" - markup for the trust prompt, if not set, then "SSL certificate for '<b>host</b>' is not trusted. Do you wish to accept it?" is used
63  *    "certificate" - a base64-encoded DER certificate, for which ask on trust
64  *    "certificate-errors" - a hexa-decimal integer (as string) corresponding to GTlsCertificateFlags
65  *
66  * Result of the dialog is:
67  *    0 - reject
68  *    1 - accept permanently
69  *    2 - accept temporarily
70  *   -1 - user didn't choose any of the above
71  *
72  * The dialog doesn't provide any additional values in the response.
73  */
74
75 static gchar *
76 cert_errors_to_reason (GTlsCertificateFlags flags)
77 {
78         struct _convert_table {
79                 GTlsCertificateFlags flag;
80                 const gchar *description;
81         } convert_table[] = {
82                 { G_TLS_CERTIFICATE_UNKNOWN_CA,
83                   N_("The signing certificate authority is not known.") },
84                 { G_TLS_CERTIFICATE_BAD_IDENTITY,
85                   N_("The certificate does not match the expected identity of the site that it was retrieved from.") },
86                 { G_TLS_CERTIFICATE_NOT_ACTIVATED,
87                   N_("The certificate's activation time is still in the future.") },
88                 { G_TLS_CERTIFICATE_EXPIRED,
89                   N_("The certificate has expired.") },
90                 { G_TLS_CERTIFICATE_REVOKED,
91                   N_("The certificate has been revoked according to the connection's certificate revocation list.") },
92                 { G_TLS_CERTIFICATE_INSECURE,
93                   N_("The certificate's algorithm is considered insecure.") }
94         };
95
96         GString *reason = g_string_new ("");
97         gint ii;
98
99         for (ii = 0; ii < G_N_ELEMENTS (convert_table); ii++) {
100                 if ((flags & convert_table[ii].flag) != 0) {
101                         if (reason->len > 0)
102                                 g_string_append (reason, "\n");
103
104                         g_string_append (reason, _(convert_table[ii].description));
105                 }
106         }
107
108         return g_string_free (reason, FALSE);
109 }
110
111 static void
112 parser_parsed_cb (GcrParser *parser,
113                   GcrParsed **out_parsed)
114 {
115         GcrParsed *parsed;
116
117         parsed = gcr_parser_get_parsed (parser);
118         g_return_if_fail (parsed != NULL);
119
120         *out_parsed = gcr_parsed_ref (parsed);
121 }
122
123 static gboolean
124 trust_prompt_show_trust_prompt (EUserPrompterServerExtension *extension,
125                                 gint prompt_id,
126                                 const ENamedParameters *parameters)
127 {
128         const gchar *host, *markup, *base64_cert, *cert_errs_str;
129         gchar *reason;
130         gint64 cert_errs;
131         GcrParser *parser;
132         GcrParsed *parsed = NULL;
133         guchar *data;
134         gsize data_length;
135         gboolean success;
136         GError *local_error = NULL;
137
138         g_return_val_if_fail (extension != NULL, FALSE);
139         g_return_val_if_fail (parameters != NULL, FALSE);
140
141         /* Continue even if PKCS#11 module registration fails.
142          * Certificate details won't display correctly but the
143          * user can still respond to the prompt. */
144         gcr_pkcs11_initialize (NULL, &local_error);
145         if (local_error != NULL) {
146                 g_warning ("%s: %s", G_STRFUNC, local_error->message);
147                 g_clear_error (&local_error);
148         }
149
150         host = e_named_parameters_get (parameters, "host");
151         markup = e_named_parameters_get (parameters, "markup");
152         base64_cert = e_named_parameters_get (parameters, "certificate");
153         cert_errs_str = e_named_parameters_get (parameters, "certificate-errors");
154
155         g_return_val_if_fail (host != NULL, FALSE);
156         g_return_val_if_fail (base64_cert != NULL, FALSE);
157         g_return_val_if_fail (cert_errs_str != NULL, FALSE);
158
159         cert_errs = g_ascii_strtoll (cert_errs_str, NULL, 16);
160         reason = cert_errors_to_reason (cert_errs);
161
162         parser = gcr_parser_new ();
163
164         g_signal_connect (
165                 parser, "parsed",
166                 G_CALLBACK (parser_parsed_cb), &parsed);
167
168         data = g_base64_decode (base64_cert, &data_length);
169         gcr_parser_parse_data (parser, data, data_length, &local_error);
170         g_free (data);
171
172         g_object_unref (parser);
173
174         /* Sanity check. */
175         g_warn_if_fail (
176                 ((parsed != NULL) && (local_error == NULL)) ||
177                 ((parsed == NULL) && (local_error != NULL)));
178
179         if (parsed != NULL) {
180                 success = trust_prompt_show (
181                         extension, prompt_id, host, markup, parsed, reason);
182                 gcr_parsed_unref (parsed);
183         }
184
185         if (local_error != NULL) {
186                 g_warning ("%s: %s", G_STRFUNC, local_error->message);
187                 g_clear_error (&local_error);
188                 success = FALSE;
189         }
190
191         g_free (reason);
192
193         return success;
194 }
195 static void
196 trust_prompt_register_dialogs (EExtension *extension,
197                                EUserPrompterServer *server)
198 {
199         e_user_prompter_server_register (server, extension, TRUST_PROMPT_DIALOG);
200 }
201
202 static gboolean
203 trust_prompt_prompt (EUserPrompterServerExtension *extension,
204                      gint prompt_id,
205                      const gchar *dialog_name,
206                      const ENamedParameters *parameters)
207 {
208         if (g_strcmp0 (dialog_name, TRUST_PROMPT_DIALOG) == 0)
209                 return trust_prompt_show_trust_prompt (extension, prompt_id, parameters);
210
211         return FALSE;
212 }
213
214 static void
215 e_trust_prompt_class_init (ETrustPromptClass *class)
216 {
217         EUserPrompterServerExtensionClass *server_extension_class;
218
219         server_extension_class = E_USER_PROMPTER_SERVER_EXTENSION_CLASS (class);
220         server_extension_class->register_dialogs = trust_prompt_register_dialogs;
221         server_extension_class->prompt = trust_prompt_prompt;
222 }
223
224 static void
225 e_trust_prompt_class_finalize (ETrustPromptClass *class)
226 {
227 }
228
229 static void
230 e_trust_prompt_init (ETrustPrompt *trust_prompt)
231 {
232 }
233
234 G_MODULE_EXPORT void
235 e_module_load (GTypeModule *type_module)
236 {
237         e_trust_prompt_register_type (type_module);
238 }
239
240 G_MODULE_EXPORT void
241 e_module_unload (GTypeModule *type_module)
242 {
243 }
244