pidgin/gtkcertmgr.c

branch
purple-ssl-to-gio
changeset 37625
7ae437591e5e
parent 37422
07dcc28b6039
child 37632
4879ef4db7cf
equal deleted inserted replaced
37624:a61e614c743d 37625:7ae437591e5e
23 #include "internal.h" 23 #include "internal.h"
24 #include "core.h" 24 #include "core.h"
25 #include "pidgin.h" 25 #include "pidgin.h"
26 #include "pidginstock.h" 26 #include "pidginstock.h"
27 27
28 #include "certificate.h" 28 #include "tls-certificate.h"
29 #include "debug.h" 29 #include "debug.h"
30 #include "notify.h" 30 #include "notify.h"
31 #include "request.h" 31 #include "request.h"
32 32
33 #include "gtk3compat.h" 33 #include "gtk3compat.h"
35 #include "gtkutils.h" 35 #include "gtkutils.h"
36 36
37 #include "gtkcertmgr.h" 37 #include "gtkcertmgr.h"
38 38
39 /***************************************************************************** 39 /*****************************************************************************
40 * X.509 tls_peers management interface * 40 * X.509 certificate management interface *
41 *****************************************************************************/ 41 *****************************************************************************/
42 42
43 typedef struct { 43 typedef struct {
44 GtkWidget *mgmt_widget; 44 GtkWidget *mgmt_widget;
45 GtkTreeView *listview; 45 GtkTreeView *listview;
46 GtkTreeSelection *listselect; 46 GtkTreeSelection *listselect;
47 GtkWidget *importbutton; 47 GtkWidget *importbutton;
48 GtkWidget *exportbutton; 48 GtkWidget *exportbutton;
49 GtkWidget *infobutton; 49 GtkWidget *infobutton;
50 GtkWidget *deletebutton; 50 GtkWidget *deletebutton;
51 PurpleCertificatePool *tls_peers;
52 } tls_peers_mgmt_data; 51 } tls_peers_mgmt_data;
53 52
54 tls_peers_mgmt_data *tpm_dat = NULL; 53 tls_peers_mgmt_data *tpm_dat = NULL;
55 54
56 /* Columns 55 /* Columns
74 73
75 static void 74 static void
76 tls_peers_mgmt_repopulate_list(void) 75 tls_peers_mgmt_repopulate_list(void)
77 { 76 {
78 GtkTreeView *listview = tpm_dat->listview; 77 GtkTreeView *listview = tpm_dat->listview;
79 PurpleCertificatePool *tls_peers;
80 GList *idlist, *l; 78 GList *idlist, *l;
81 79
82 GtkListStore *store = GTK_LIST_STORE( 80 GtkListStore *store = GTK_LIST_STORE(
83 gtk_tree_view_get_model(GTK_TREE_VIEW(listview))); 81 gtk_tree_view_get_model(GTK_TREE_VIEW(listview)));
84 82
85 /* First, delete everything in the list */ 83 /* First, delete everything in the list */
86 gtk_list_store_clear(store); 84 gtk_list_store_clear(store);
87 85
88 /* Locate the "tls_peers" pool */ 86 /* Grab the available certificates */
89 tls_peers = purple_certificate_find_pool("x509", "tls_peers"); 87 idlist = purple_tls_certificate_list_ids();
90 g_return_if_fail(tls_peers);
91
92 /* Grab the loaded certificates */
93 idlist = purple_certificate_pool_get_idlist(tls_peers);
94 88
95 /* Populate the listview */ 89 /* Populate the listview */
96 for (l = idlist; l; l = l->next) { 90 for (l = idlist; l; l = l->next) {
97 GtkTreeIter iter; 91 GtkTreeIter iter;
98 gtk_list_store_append(store, &iter); 92 gtk_list_store_append(store, &iter);
99 93
100 gtk_list_store_set(GTK_LIST_STORE(store), &iter, 94 gtk_list_store_set(GTK_LIST_STORE(store), &iter,
101 TPM_HOSTNAME_COLUMN, l->data, 95 TPM_HOSTNAME_COLUMN, l->data,
102 -1); 96 -1);
103 } 97 }
104 purple_certificate_pool_destroy_idlist(idlist); 98
105 } 99 purple_tls_certificate_free_ids(idlist);
106
107 static void
108 tls_peers_mgmt_mod_cb(PurpleCertificatePool *pool, const gchar *id, gpointer data)
109 {
110 g_assert (pool == tpm_dat->tls_peers);
111
112 tls_peers_mgmt_repopulate_list();
113 } 100 }
114 101
115 static void 102 static void
116 tls_peers_mgmt_select_chg_cb(GtkTreeSelection *ignored, gpointer data) 103 tls_peers_mgmt_select_chg_cb(GtkTreeSelection *ignored, gpointer data)
117 { 104 {
135 } 122 }
136 123
137 static void 124 static void
138 tls_peers_mgmt_import_ok2_cb(gpointer data, const char *result) 125 tls_peers_mgmt_import_ok2_cb(gpointer data, const char *result)
139 { 126 {
140 PurpleCertificate *crt = (PurpleCertificate *) data; 127 GTlsCertificate *crt = data;
128 GError *error = NULL;
141 129
142 /* TODO: Perhaps prompt if you're overwriting a cert? */ 130 /* TODO: Perhaps prompt if you're overwriting a cert? */
143 131
144 /* Drop the certificate into the pool */ 132 /* Trust the certificate */
145 if (result && *result) 133 if (result && *result) {
146 purple_certificate_pool_store(tpm_dat->tls_peers, result, crt); 134 if(!purple_tls_certificate_trust(result, crt, &error)) {
135 purple_debug_error("gtkcertmgr/tls_peers_mgmt",
136 "Error trusting certificate '%s': %s",
137 result, error->message);
138 g_clear_error(&error);
139 }
140
141 tls_peers_mgmt_repopulate_list();
142 }
147 143
148 /* And this certificate is not needed any more */ 144 /* And this certificate is not needed any more */
149 purple_certificate_destroy(crt); 145 g_object_unref(crt);
150 } 146 }
151 147
152 static void 148 static void
153 tls_peers_mgmt_import_cancel2_cb(gpointer data, const char *result) 149 tls_peers_mgmt_import_cancel2_cb(gpointer data, const char *result)
154 { 150 {
155 PurpleCertificate *crt = (PurpleCertificate *) data; 151 GTlsCertificate *crt = data;
156 purple_certificate_destroy(crt); 152 g_object_unref(crt);
157 } 153 }
158 154
159 static void 155 static void
160 tls_peers_mgmt_import_ok_cb(gpointer data, const char *filename) 156 tls_peers_mgmt_import_ok_cb(gpointer data, const char *filename)
161 { 157 {
162 PurpleCertificateScheme *x509; 158 GTlsCertificate *crt;
163 PurpleCertificate *crt; 159 GError *error = NULL;
164
165 /* Load the scheme of our tls_peers pool (ought to be x509) */
166 x509 = purple_certificate_pool_get_scheme(tpm_dat->tls_peers);
167 160
168 /* Now load the certificate from disk */ 161 /* Now load the certificate from disk */
169 crt = purple_certificate_import(x509, filename); 162 crt = g_tls_certificate_new_from_file(filename, &error);
170 163
171 /* Did it work? */ 164 /* Did it work? */
172 if (crt != NULL) { 165 if (crt != NULL) {
173 gchar *default_hostname; 166 gchar *default_hostname;
174 /* Get name to add to pool as */ 167 PurpleTlsCertificateInfo *info;
168
169 /* Get name to add trust as */
175 /* Make a guess about what the hostname should be */ 170 /* Make a guess about what the hostname should be */
176 default_hostname = purple_certificate_get_subject_name(crt); 171 info = purple_tls_certificate_get_info(crt);
172 default_hostname = purple_tls_certificate_info_get_subject_name(info);
173 purple_tls_certificate_info_free(info);
174
177 /* TODO: Find a way to make sure that crt gets destroyed 175 /* TODO: Find a way to make sure that crt gets destroyed
178 if the window gets closed unusually, such as by handle 176 if the window gets closed unusually, such as by handle
179 deletion */ 177 deletion */
180 /* TODO: Display some more information on the certificate? */ 178 /* TODO: Display some more information on the certificate? */
181 purple_request_input(tpm_dat, 179 purple_request_input(tpm_dat,
199 /* Errors! Oh no! */ 197 /* Errors! Oh no! */
200 /* TODO: Perhaps find a way to be specific about what just 198 /* TODO: Perhaps find a way to be specific about what just
201 went wrong? */ 199 went wrong? */
202 gchar * secondary; 200 gchar * secondary;
203 201
202 purple_debug_warning("gtkcertmgr/tls_peers_mgmt",
203 "File %s couldn't be imported: %s",
204 filename, error->message);
205 g_clear_error(&error);
206
204 secondary = g_strdup_printf(_("File %s could not be imported.\nMake sure that the file is readable and in PEM format.\n"), filename); 207 secondary = g_strdup_printf(_("File %s could not be imported.\nMake sure that the file is readable and in PEM format.\n"), filename);
205 purple_notify_error(NULL, 208 purple_notify_error(NULL,
206 _("Certificate Import Error"), 209 _("Certificate Import Error"),
207 _("X.509 certificate import failed"), 210 _("X.509 certificate import failed"),
208 secondary, NULL); 211 secondary, NULL);
224 } 227 }
225 228
226 static void 229 static void
227 tls_peers_mgmt_export_ok_cb(gpointer data, const char *filename) 230 tls_peers_mgmt_export_ok_cb(gpointer data, const char *filename)
228 { 231 {
229 PurpleCertificate *crt = (PurpleCertificate *) data; 232 GTlsCertificate *crt = data;
233 gchar *pem = NULL;
234 GError *error = NULL;
230 235
231 g_assert(filename); 236 g_assert(filename);
232 237
233 if (!purple_certificate_export(filename, crt)) { 238 g_object_get(crt, "certificate-pem", &pem, NULL);
239
240 if (!g_file_set_contents(filename, pem, -1, &error)) {
234 /* Errors! Oh no! */ 241 /* Errors! Oh no! */
235 /* TODO: Perhaps find a way to be specific about what just 242 /* TODO: Perhaps find a way to be specific about what just
236 went wrong? */ 243 went wrong? */
237 gchar * secondary; 244 gchar * secondary;
245
246 purple_debug_warning("gtkcertmgr/tls_peers_mgmt",
247 "File %s couldn't be exported: %s",
248 filename, error->message);
249 g_clear_error(&error);
238 250
239 secondary = g_strdup_printf(_("Export to file %s failed.\nCheck that you have write permission to the target path\n"), filename); 251 secondary = g_strdup_printf(_("Export to file %s failed.\nCheck that you have write permission to the target path\n"), filename);
240 purple_notify_error(NULL, 252 purple_notify_error(NULL,
241 _("Certificate Export Error"), 253 _("Certificate Export Error"),
242 _("X.509 certificate export failed"), 254 _("X.509 certificate export failed"),
243 secondary, NULL); 255 secondary, NULL);
244 g_free(secondary); 256 g_free(secondary);
245 } 257 } else {
246 258 tls_peers_mgmt_repopulate_list();
247 purple_certificate_destroy(crt); 259 }
248 } 260
249 261 g_free(pem);
250 static void 262 g_object_unref(crt);
251 tls_peers_mgmt_export_cancel_cb(gpointer data, const char *filename)
252 {
253 PurpleCertificate *crt = (PurpleCertificate *) data;
254 /* Pressing cancel just frees the duplicated certificate */
255 purple_certificate_destroy(crt);
256 } 263 }
257 264
258 static void 265 static void
259 tls_peers_mgmt_export_cb(GtkWidget *button, gpointer data) 266 tls_peers_mgmt_export_cb(GtkWidget *button, gpointer data)
260 { 267 {
261 PurpleCertificate *crt; 268 GTlsCertificate *crt;
262 GtkTreeSelection *select = tpm_dat->listselect; 269 GtkTreeSelection *select = tpm_dat->listselect;
263 GtkTreeIter iter; 270 GtkTreeIter iter;
264 GtkTreeModel *model; 271 GtkTreeModel *model;
265 gchar *id; 272 gchar *id;
273 gchar *path;
274 GError *error = NULL;
266 275
267 /* See if things are selected */ 276 /* See if things are selected */
268 if (!gtk_tree_selection_get_selected(select, &model, &iter)) { 277 if (!gtk_tree_selection_get_selected(select, &model, &iter)) {
269 purple_debug_warning("gtkcertmgr/tls_peers_mgmt", 278 purple_debug_warning("gtkcertmgr/tls_peers_mgmt",
270 "Export clicked with no selection?\n"); 279 "Export clicked with no selection?\n");
274 /* Retrieve the selected hostname */ 283 /* Retrieve the selected hostname */
275 gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1); 284 gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1);
276 285
277 /* Extract the certificate from the pool now to make sure it doesn't 286 /* Extract the certificate from the pool now to make sure it doesn't
278 get deleted out from under us */ 287 get deleted out from under us */
279 crt = purple_certificate_pool_retrieve(tpm_dat->tls_peers, id); 288 crt = purple_tls_certificate_new_from_id(id, &error);
280 289
281 if (NULL == crt) { 290 if (NULL == crt) {
282 purple_debug_error("gtkcertmgr/tls_peers_mgmt", 291 purple_debug_error("gtkcertmgr/tls_peers_mgmt",
283 "Id %s was not in the peers cache?!\n", 292 "Error fetching trusted cert '%s': %s\n",
284 id); 293 id, error->message);
294 g_clear_error(&error);
285 g_free(id); 295 g_free(id);
286 return; 296 return;
287 } 297 }
288 g_free(id); 298 g_free(id);
289 299
291 purple_request_file(tpm_dat, 301 purple_request_file(tpm_dat,
292 _("PEM X.509 Certificate Export"), 302 _("PEM X.509 Certificate Export"),
293 "certificate.pem", 303 "certificate.pem",
294 TRUE, /* Is a save dialog */ 304 TRUE, /* Is a save dialog */
295 G_CALLBACK(tls_peers_mgmt_export_ok_cb), 305 G_CALLBACK(tls_peers_mgmt_export_ok_cb),
296 G_CALLBACK(tls_peers_mgmt_export_cancel_cb), 306 G_CALLBACK(g_object_unref),
297 NULL, /* No extra parameters */ 307 NULL, /* No extra parameters */
298 crt); /* Pass the certificate on to the callback */ 308 crt); /* Pass the certificate on to the callback */
299 } 309 }
300 310
301 static void 311 static void
303 { 313 {
304 GtkTreeSelection *select = tpm_dat->listselect; 314 GtkTreeSelection *select = tpm_dat->listselect;
305 GtkTreeIter iter; 315 GtkTreeIter iter;
306 GtkTreeModel *model; 316 GtkTreeModel *model;
307 gchar *id; 317 gchar *id;
308 PurpleCertificate *crt; 318 GTlsCertificate *crt;
309 char *title; 319 char *title;
320 GError *error = NULL;
310 321
311 /* See if things are selected */ 322 /* See if things are selected */
312 if (!gtk_tree_selection_get_selected(select, &model, &iter)) { 323 if (!gtk_tree_selection_get_selected(select, &model, &iter)) {
313 purple_debug_warning("gtkcertmgr/tls_peers_mgmt", 324 purple_debug_warning("gtkcertmgr/tls_peers_mgmt",
314 "Info clicked with no selection?\n"); 325 "Info clicked with no selection?\n");
317 328
318 /* Retrieve the selected hostname */ 329 /* Retrieve the selected hostname */
319 gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1); 330 gtk_tree_model_get(model, &iter, TPM_HOSTNAME_COLUMN, &id, -1);
320 331
321 /* Now retrieve the certificate */ 332 /* Now retrieve the certificate */
322 crt = purple_certificate_pool_retrieve(tpm_dat->tls_peers, id); 333 crt = purple_tls_certificate_new_from_id(id, NULL);
323 g_return_if_fail(crt); 334
335 if (crt == NULL) {
336 purple_debug_warning("gtkcertmgr/tls_peers_mgmt",
337 "Unable to fetch certificate '%s': %s",
338 id, error->message);
339 g_clear_error(&error);
340 g_free(id);
341 }
324 342
325 /* Fire the notification */ 343 /* Fire the notification */
326 title = g_strdup_printf(_("Certificate Information for %s"), id); 344 title = g_strdup_printf(_("Certificate Information for %s"), id);
327 purple_request_certificate(tpm_dat, title, NULL, NULL, crt, 345 purple_request_certificate(tpm_dat, title, NULL, NULL, crt,
328 _("OK"), G_CALLBACK(purple_certificate_destroy), 346 _("OK"), G_CALLBACK(g_object_unref),
329 _("Cancel"), G_CALLBACK(purple_certificate_destroy), 347 _("Cancel"), G_CALLBACK(g_object_unref),
330 crt); 348 crt);
331 349
332 g_free(id); 350 g_free(id);
333 g_free(title); 351 g_free(title);
334 } 352 }
340 } 358 }
341 359
342 static void 360 static void
343 tls_peers_mgmt_delete_confirm_cb(gchar *id, gint choice) 361 tls_peers_mgmt_delete_confirm_cb(gchar *id, gint choice)
344 { 362 {
363 GError *error = NULL;
364
345 if (1 == choice) { 365 if (1 == choice) {
346 /* Yes, delete was confirmed */ 366 /* Yes, distrust was confirmed */
347 /* Now delete the thing */ 367 /* Now distrust the thing */
348 if (!purple_certificate_pool_delete(tpm_dat->tls_peers, id)) { 368 if (!purple_tls_certificate_distrust(id, &error)) {
349 purple_debug_warning("gtkcertmgr/tls_peers_mgmt", 369 purple_debug_warning("gtkcertmgr/tls_peers_mgmt",
350 "Deletion failed on id %s\n", 370 "Deletion failed on id %s: %s\n",
351 id); 371 id, error->message);
352 }; 372 g_clear_error(&error);
373 } else {
374 tls_peers_mgmt_repopulate_list();
375 }
353 } 376 }
354 377
355 g_free(id); 378 g_free(id);
356 } 379 }
357 380
516 539
517 /* Call the "selection changed" callback, which will probably disable 540 /* Call the "selection changed" callback, which will probably disable
518 all the buttons since nothing is selected yet */ 541 all the buttons since nothing is selected yet */
519 tls_peers_mgmt_select_chg_cb(select, NULL); 542 tls_peers_mgmt_select_chg_cb(select, NULL);
520 543
521 /* Bind us to the tls_peers pool */
522 tpm_dat->tls_peers = purple_certificate_find_pool("x509", "tls_peers");
523
524 /**** libpurple signals ****/
525 /* Respond to certificate add/remove by just reloading everything */
526 purple_signal_connect(tpm_dat->tls_peers, "certificate-stored",
527 tpm_dat, PURPLE_CALLBACK(tls_peers_mgmt_mod_cb),
528 NULL);
529 purple_signal_connect(tpm_dat->tls_peers, "certificate-deleted",
530 tpm_dat, PURPLE_CALLBACK(tls_peers_mgmt_mod_cb),
531 NULL);
532
533 return mgmt_widget; 544 return mgmt_widget;
534 } 545 }
535 546
536 const PidginCertificateManager tls_peers_mgmt = { 547 const PidginCertificateManager tls_peers_mgmt = {
537 tls_peers_mgmt_build, /* Widget creation function */ 548 tls_peers_mgmt_build, /* Widget creation function */
569 GtkWidget *win; 580 GtkWidget *win;
570 GtkWidget *vbox; 581 GtkWidget *vbox;
571 582
572 /* Enumerate all the certificates on file */ 583 /* Enumerate all the certificates on file */
573 { 584 {
574 GList *idlist, *poollist; 585 GList *idlist;
575 586 GList *l;
576 for ( poollist = purple_certificate_get_pools(); 587
577 poollist; 588 purple_debug_info("gtkcertmgr",
578 poollist = poollist->next ) { 589 "Enumerating X.509 certificates:\n");
579 PurpleCertificatePool *pool = poollist->data; 590
580 GList *l; 591 idlist = purple_tls_certificate_list_ids();
581 592
593 for (l=idlist; l; l = l->next) {
582 purple_debug_info("gtkcertmgr", 594 purple_debug_info("gtkcertmgr",
583 "Pool %s found for scheme %s -" 595 "- %s\n",
584 "Enumerating certificates:\n", 596 l->data ? (gchar *) l->data : "(null)");
585 pool->name, pool->scheme_name); 597 } /* idlist */
586 598
587 idlist = purple_certificate_pool_get_idlist(pool); 599 purple_tls_certificate_free_ids(idlist);
588
589 for (l=idlist; l; l = l->next) {
590 purple_debug_info("gtkcertmgr",
591 "- %s\n",
592 l->data ? (gchar *) l->data : "(null)");
593 } /* idlist */
594 purple_certificate_pool_destroy_idlist(idlist);
595 } /* poollist */
596 } 600 }
597 601
598 602
599 /* If the manager is already open, bring it to the front */ 603 /* If the manager is already open, bring it to the front */
600 if (certmgr_dialog != NULL) { 604 if (certmgr_dialog != NULL) {

mercurial