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