~noskcaj/ubuntu/vivid/gnome-keyring/3.15.90

« back to all changes in this revision

Viewing changes to ui/gku-prompt-tool.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach
  • Date: 2012-05-14 22:13:02 UTC
  • mfrom: (1.3.1)
  • mto: (80.2.8 experimental) (1.1.77)
  • mto: This revision was merged to the branch mainline in revision 148.
  • Revision ID: package-import@ubuntu.com-20120514221302-0l3gjmqpe6xopond
ImportĀ upstreamĀ versionĀ 3.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
 
/* gku-prompt-tool.c - Handles gui authentication for the keyring daemon.
3
 
 
4
 
   Copyright (C) 2009 Stefan Walter
5
 
 
6
 
   Gnome keyring is free software; you can redistribute it and/or
7
 
   modify it under the terms of the GNU General Public License as
8
 
   published by the Free Software Foundation; either version 2 of the
9
 
   License, or (at your option) any later version.
10
 
 
11
 
   Gnome keyring is distributed in the hope that it will be useful,
12
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 
   General Public License for more details.
15
 
 
16
 
   You should have received a copy of the GNU General Public License
17
 
   along with this program; if not, write to the Free Software
18
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
 
20
 
   Author: Stef Walter <stef@memberwebs.com>
21
 
*/
22
 
 
23
 
#include "config.h"
24
 
 
25
 
#include "gku-prompt-util.h"
26
 
 
27
 
#include "egg/egg-dh.h"
28
 
#include "egg/egg-entry-buffer.h"
29
 
#include "egg/egg-error.h"
30
 
#include "egg/egg-hex.h"
31
 
#include "egg/egg-hkdf.h"
32
 
#include "egg/egg-libgcrypt.h"
33
 
#include "egg/egg-secure-memory.h"
34
 
 
35
 
#include "gcr/gcr.h"
36
 
 
37
 
#include <gcrypt.h>
38
 
 
39
 
#include <glib/gi18n.h>
40
 
 
41
 
#include <gdk/gdk.h>
42
 
#include <gtk/gtk.h>
43
 
 
44
 
#include <errno.h>
45
 
#include <locale.h>
46
 
#include <stdio.h>
47
 
#include <stdlib.h>
48
 
#include <string.h>
49
 
#include <syslog.h>
50
 
#include <unistd.h>
51
 
 
52
 
static GKeyFile *input_data = NULL;
53
 
static GKeyFile *output_data = NULL;
54
 
 
55
 
#if GTK_CHECK_VERSION (3,0,0)
56
 
static GdkDevice *grabbed_device = NULL;
57
 
static guint32 grabbed_at = 0;
58
 
static gulong grab_broken_id = 0;
59
 
#else
60
 
static gboolean keyboard_grabbed = FALSE;
61
 
#endif
62
 
 
63
 
/* An encryption key for returning passwords */
64
 
static gpointer the_key = NULL;
65
 
static gsize n_the_key = 0;
66
 
 
67
 
#define LOG_ERRORS 1
68
 
#define GRAB_KEYBOARD 1
69
 
 
70
 
/**
71
 
* SECTION: gku-prompt-tool.c
72
 
* @short_description: Displays a propmt for 3rd party programs (ssh, gnupg)
73
 
**/
74
 
 
75
 
/* ------------------------------------------------------------------------------ */
76
 
 
77
 
/**
78
 
* primary: The part that will be bold
79
 
* secondary: The normal part of the text or NULL
80
 
*
81
 
*
82
 
*
83
 
* Returns The text encased in markup
84
 
**/
85
 
static gchar*
86
 
create_markup (const gchar *primary, const gchar *secondary)
87
 
{
88
 
        return g_markup_printf_escaped ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
89
 
                                        primary, secondary ? secondary : "");
90
 
}
91
 
 
92
 
#if GTK_CHECK_VERSION (3,0,0)
93
 
static gboolean
94
 
on_grab_broken (GtkWidget * widget, GdkEventGrabBroken * event)
95
 
{
96
 
        if (grabbed_device && event->keyboard) {
97
 
                grabbed_device = NULL;
98
 
                grabbed_at = 0;
99
 
        }
100
 
 
101
 
        return TRUE;
102
 
}
103
 
#endif
104
 
 
105
 
static gboolean
106
 
grab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
107
 
{
108
 
        GdkGrabStatus status;
109
 
 
110
 
#if GTK_CHECK_VERSION (3,0,0)
111
 
        GdkDevice *device = NULL;
112
 
        GdkDeviceManager *manager;
113
 
        GdkDisplay *display;
114
 
        GList *devices, *l;
115
 
        guint32 at;
116
 
 
117
 
        if (grabbed_device || !GRAB_KEYBOARD)
118
 
                return FALSE;
119
 
 
120
 
        display = gtk_widget_get_display (win);
121
 
        manager = gdk_display_get_device_manager (display);
122
 
        devices = gdk_device_manager_list_devices (manager, GDK_DEVICE_TYPE_MASTER);
123
 
        for (l = devices; l; l = g_list_next (l)) {
124
 
                device = l->data;
125
 
                if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
126
 
                        break;
127
 
        }
128
 
        g_list_free (devices);
129
 
 
130
 
        if (!device) {
131
 
                g_message ("couldn't find device to grab");
132
 
                return FALSE;
133
 
        }
134
 
 
135
 
        at = gdk_event_get_time (event);
136
 
        status = gdk_device_grab (device, gtk_widget_get_window (win),
137
 
                                  GDK_OWNERSHIP_WINDOW, TRUE,
138
 
                                  GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, at);
139
 
        if (status == GDK_GRAB_SUCCESS) {
140
 
                grab_broken_id = g_signal_connect (win, "grab-broken-event",
141
 
                                                   G_CALLBACK (on_grab_broken), NULL);
142
 
                gtk_device_grab_add (win, device, TRUE);
143
 
                grabbed_device = device;
144
 
                grabbed_at = at;
145
 
        } else {
146
 
                g_message ("could not grab keyboard: %d", (int)status);
147
 
        }
148
 
#else
149
 
        if (!keyboard_grabbed && GRAB_KEYBOARD) {
150
 
                status = gdk_keyboard_grab (gtk_widget_get_window (win), FALSE, gdk_event_get_time (event));
151
 
                if (status == GDK_GRAB_SUCCESS) {
152
 
                        keyboard_grabbed = TRUE;
153
 
                } else {
154
 
                        g_message ("could not grab keyboard: %d", (int)status);
155
 
                }
156
 
        }
157
 
#endif
158
 
 
159
 
        /* Always return false, so event is handled elsewhere */
160
 
        return FALSE;
161
 
}
162
 
 
163
 
static gboolean
164
 
ungrab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
165
 
{
166
 
#if GTK_CHECK_VERSION (3,0,0)
167
 
        if (grabbed_device) {
168
 
                g_signal_handler_disconnect (win, grab_broken_id);
169
 
                gdk_device_ungrab (grabbed_device, grabbed_at);
170
 
                gtk_device_grab_remove (win, grabbed_device);
171
 
                grabbed_device = NULL;
172
 
                grabbed_at = 0;
173
 
                grab_broken_id = 0;
174
 
        }
175
 
#else
176
 
        if (keyboard_grabbed)
177
 
                gdk_keyboard_ungrab (gdk_event_get_time (event));
178
 
        keyboard_grabbed = FALSE;
179
 
#endif
180
 
 
181
 
        /* Always return false, so event is handled elsewhere */
182
 
        return FALSE;
183
 
}
184
 
 
185
 
/**
186
 
* win: The window that changed state
187
 
* event: The event that triggered it
188
 
* data: ignored
189
 
*
190
 
* Depending on the state it will grab the keyboard or ungrab it.
191
 
*
192
 
* Returns FALSE
193
 
**/
194
 
static gboolean
195
 
window_state_changed (GtkWidget *win, GdkEventWindowState *event, gpointer data)
196
 
{
197
 
        GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (win));
198
 
 
199
 
        if (state & GDK_WINDOW_STATE_WITHDRAWN ||
200
 
            state & GDK_WINDOW_STATE_ICONIFIED ||
201
 
            state & GDK_WINDOW_STATE_FULLSCREEN ||
202
 
            state & GDK_WINDOW_STATE_MAXIMIZED)
203
 
                ungrab_keyboard (win, (GdkEvent*)event, data);
204
 
        else
205
 
                grab_keyboard (win, (GdkEvent*)event, data);
206
 
 
207
 
        return FALSE;
208
 
}
209
 
 
210
 
 
211
 
/**
212
 
* editable: The GTK_ENTRY that changed
213
 
* user_data: the progress bar to update
214
 
*
215
 
* Will update the password quality displayed in the progress bar.
216
 
*
217
 
**/
218
 
static void
219
 
on_password_changed (GtkEditable *editable, gpointer user_data)
220
 
{
221
 
        const char *password;
222
 
        int length, i;
223
 
        int upper, lower, digit, misc;
224
 
        gdouble pwstrength;
225
 
 
226
 
        password = gtk_entry_get_text (GTK_ENTRY (editable));
227
 
 
228
 
        /*
229
 
         * This code is based on the Master Password dialog in Firefox
230
 
         * (pref-masterpass.js)
231
 
         * Original code triple-licensed under the MPL, GPL, and LGPL
232
 
         * so is license-compatible with this file
233
 
         */
234
 
 
235
 
        length = strlen (password);
236
 
        upper = 0;
237
 
        lower = 0;
238
 
        digit = 0;
239
 
        misc = 0;
240
 
 
241
 
        for ( i = 0; i < length ; i++) {
242
 
                if (g_ascii_isdigit (password[i]))
243
 
                        digit++;
244
 
                else if (g_ascii_islower (password[i]))
245
 
                        lower++;
246
 
                else if (g_ascii_isupper (password[i]))
247
 
                        upper++;
248
 
                else
249
 
                        misc++;
250
 
        }
251
 
 
252
 
        if (length > 5)
253
 
                length = 5;
254
 
        if (digit > 3)
255
 
                digit = 3;
256
 
        if (upper > 3)
257
 
                upper = 3;
258
 
        if (misc > 3)
259
 
                misc = 3;
260
 
 
261
 
        pwstrength = ((length*0.1)-0.2) + (digit*0.1) + (misc*0.15) + (upper*0.1);
262
 
 
263
 
        if (pwstrength < 0.0)
264
 
                pwstrength = 0.0;
265
 
        if (pwstrength > 1.0)
266
 
                pwstrength = 1.0;
267
 
 
268
 
        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (user_data), pwstrength);
269
 
}
270
 
 
271
 
/**
272
 
* builder: The builder object to look for visibility keys in
273
 
* dialog: ignored
274
 
*
275
 
* Depending on the input_data and the keys in the group "visibility"
276
 
* this toggles the visibility of displayed widgets
277
 
*
278
 
**/
279
 
static void
280
 
prepare_visibility (GtkBuilder *builder, GtkDialog *dialog)
281
 
{
282
 
        gchar **keys, **key;
283
 
        GObject *object;
284
 
 
285
 
        keys = g_key_file_get_keys (input_data, "visibility", NULL, NULL);
286
 
        g_return_if_fail (keys);
287
 
 
288
 
        for (key = keys; key && *key; ++key) {
289
 
                object = gtk_builder_get_object (builder, *key);
290
 
                if (!GTK_IS_WIDGET (object)) {
291
 
                        g_warning ("can't set visibility on invalid builder object: %s", *key);
292
 
                        continue;
293
 
                }
294
 
                if (g_key_file_get_boolean (input_data, "visibility", *key, NULL))
295
 
                        gtk_widget_show (GTK_WIDGET (object));
296
 
                else
297
 
                        gtk_widget_hide (GTK_WIDGET (object));
298
 
        }
299
 
 
300
 
        g_strfreev (keys);
301
 
}
302
 
 
303
 
/**
304
 
* builder: ignored
305
 
* dialog: The dialog to set the title for
306
 
*
307
 
* Sets a new title to the dialog. The title is extracted from the input_data
308
 
*
309
 
**/
310
 
static void
311
 
prepare_titlebar (GtkBuilder *builder, GtkDialog *dialog)
312
 
{
313
 
        gchar *title;
314
 
 
315
 
        title = g_key_file_get_string (input_data, "prompt", "title", NULL);
316
 
        if (title)
317
 
                gtk_window_set_title (GTK_WINDOW (dialog), title);
318
 
        gtk_window_set_icon_name(GTK_WINDOW(dialog), "stock_lock");
319
 
        gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
320
 
 
321
 
        gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
322
 
        gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
323
 
        gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL);
324
 
}
325
 
 
326
 
/**
327
 
* builder: The GtkBuilder to extract the warning label from
328
 
* text: The text to display in the warning label
329
 
*
330
 
* Displays a text in the warning_label
331
 
*
332
 
**/
333
 
static void
334
 
prepare_warning (GtkBuilder *builder, const gchar *text)
335
 
{
336
 
        GtkLabel *label;
337
 
        gchar *markup;
338
 
 
339
 
        label = GTK_LABEL (gtk_builder_get_object (builder, "warning_label"));
340
 
        g_return_if_fail (label);
341
 
 
342
 
        markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", text);
343
 
        gtk_label_set_markup (label, markup);
344
 
        g_free (markup);
345
 
 
346
 
        gtk_widget_show (GTK_WIDGET (label));
347
 
}
348
 
 
349
 
/**
350
 
* builder: The GTKBuilder to look for widgets in
351
 
* dialog: ignored
352
 
*
353
 
* Reads data from the input_data and prepares a prompt dialog
354
 
*
355
 
**/
356
 
static void
357
 
prepare_prompt (GtkBuilder *builder, GtkDialog *dialog)
358
 
{
359
 
        gchar *primary, *secondary, *markup, *warning;
360
 
        GtkLabel *label;
361
 
 
362
 
        primary = g_key_file_get_string (input_data, "prompt", "primary", NULL);
363
 
        g_return_if_fail (primary);
364
 
        secondary = g_key_file_get_string (input_data, "prompt", "secondary", NULL);
365
 
 
366
 
        markup = create_markup (primary, secondary);
367
 
        g_free (primary);
368
 
        g_free (secondary);
369
 
 
370
 
        label = GTK_LABEL (gtk_builder_get_object (builder, "prompt_label"));
371
 
        g_return_if_fail (label);
372
 
 
373
 
        gtk_label_set_markup (label, markup);
374
 
        g_free (markup);
375
 
 
376
 
        warning = g_key_file_get_string (input_data, "prompt", "warning", NULL);
377
 
        if (warning != NULL)
378
 
                prepare_warning (builder, warning);
379
 
        g_free (warning);
380
 
}
381
 
 
382
 
/**
383
 
* builder: The GTK builder to use
384
 
* dialog: the dialog to add buttons to
385
 
*
386
 
* Adds buttons to the dialog. Which buttons to add is defined in input_data
387
 
*
388
 
**/
389
 
static void
390
 
prepare_buttons (GtkBuilder *builder, GtkDialog *dialog)
391
 
{
392
 
        gchar *ok_text;
393
 
        gchar *cancel_text;
394
 
        gchar *other_text;
395
 
 
396
 
        ok_text = g_key_file_get_string (input_data, "buttons", "ok", NULL);
397
 
        cancel_text = g_key_file_get_string (input_data, "buttons", "cancel", NULL);
398
 
        other_text = g_key_file_get_string (input_data, "buttons", "other", NULL);
399
 
 
400
 
        if (other_text)
401
 
                gtk_dialog_add_button (dialog, other_text, GTK_RESPONSE_APPLY);
402
 
        gtk_dialog_add_button (dialog, cancel_text ? cancel_text : GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
403
 
        gtk_dialog_add_button (dialog, ok_text ? ok_text : GTK_STOCK_OK, GTK_RESPONSE_OK);
404
 
 
405
 
        gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
406
 
 
407
 
        g_free (ok_text);
408
 
        g_free (cancel_text);
409
 
        g_free (other_text);
410
 
}
411
 
 
412
 
/**
413
 
* entry: the entry to set the buffer for
414
 
*
415
 
* Adds the secure egg_entry_buffer to the entry
416
 
*
417
 
**/
418
 
static void
419
 
prepare_password_entry (GtkEntry *entry)
420
 
{
421
 
        GtkEntryBuffer *buffer = egg_entry_buffer_new ();
422
 
        g_return_if_fail (entry);
423
 
        gtk_entry_set_buffer (entry, buffer);
424
 
        g_object_unref (buffer);
425
 
}
426
 
 
427
 
/**
428
 
* builder: The GTKBuilder
429
 
* dialog: The Dialog to prepare
430
 
*
431
 
* Password entries use a secure buffer. Set this up here.
432
 
*
433
 
**/
434
 
static void
435
 
prepare_passwords (GtkBuilder *builder, GtkDialog *dialog)
436
 
{
437
 
        GtkEntry *entry;
438
 
        GtkWidget *strength;
439
 
 
440
 
        entry = GTK_ENTRY(gtk_builder_get_object (builder, "password_entry"));
441
 
        prepare_password_entry (entry);
442
 
 
443
 
        strength = GTK_WIDGET (gtk_builder_get_object (builder, "strength_bar"));
444
 
        g_signal_connect (entry, "changed", G_CALLBACK (on_password_changed), strength);
445
 
 
446
 
        entry = GTK_ENTRY(gtk_builder_get_object (builder, "original_entry"));
447
 
        prepare_password_entry (entry);
448
 
 
449
 
        entry = GTK_ENTRY(gtk_builder_get_object (builder, "confirm_entry"));
450
 
        prepare_password_entry (entry);
451
 
}
452
 
 
453
 
/**
454
 
* builder: The GTKBuilder
455
 
* dialog: the dialog to connect signals for
456
 
*
457
 
* Registers the signal handlers for keyboard grab
458
 
*
459
 
**/
460
 
static void
461
 
prepare_security (GtkBuilder *builder, GtkDialog *dialog)
462
 
{
463
 
        /*
464
 
         * When passwords are involved we grab the keyboard so that people
465
 
         * don't accidentally type their passwords in other windows.
466
 
         */
467
 
        g_signal_connect (dialog, "map-event", G_CALLBACK (grab_keyboard), NULL);
468
 
        g_signal_connect (dialog, "unmap-event", G_CALLBACK (ungrab_keyboard), NULL);
469
 
        g_signal_connect (dialog, "window-state-event", G_CALLBACK (window_state_changed), NULL);
470
 
}
471
 
 
472
 
static void
473
 
prepare_unlock_option (GcrUnlockOptionsWidget *unlock, const gchar *option)
474
 
{
475
 
        GError *error = NULL;
476
 
        gboolean sensitive;
477
 
        gchar *text;
478
 
 
479
 
        text = g_key_file_get_string (input_data, option, "label", NULL);
480
 
        if (text)
481
 
                gcr_unlock_options_widget_set_label (unlock, option, text);
482
 
        g_free (text);
483
 
 
484
 
        sensitive = g_key_file_get_boolean (input_data, option, "sensitive", &error);
485
 
        if (error == NULL) {
486
 
                text = g_key_file_get_string (input_data, option, "reason", NULL);
487
 
                gcr_unlock_options_widget_set_sensitive (unlock, option, sensitive, text);
488
 
                g_free (text);
489
 
        }
490
 
 
491
 
        g_clear_error (&error);
492
 
}
493
 
 
494
 
/**
495
 
* builder: GtkBuilderobject to read widgets from
496
 
* dialog: the prompt dialog
497
 
*
498
 
* Set default value depending on input_data
499
 
*
500
 
**/
501
 
static void
502
 
prepare_lock (GtkBuilder *builder, GtkDialog *dialog)
503
 
{
504
 
        GcrUnlockOptionsWidget *unlock;
505
 
        GtkWidget *area;
506
 
        gchar *option;
507
 
        guint ttl;
508
 
 
509
 
        unlock = GCR_UNLOCK_OPTIONS_WIDGET (gcr_unlock_options_widget_new ());
510
 
        area = GTK_WIDGET (gtk_builder_get_object (builder, "options_area"));
511
 
        g_object_set_data (G_OBJECT (dialog), "unlock-options-widget", unlock);
512
 
        gtk_container_add (GTK_CONTAINER (area), GTK_WIDGET (unlock));
513
 
        gtk_widget_show (GTK_WIDGET (unlock));
514
 
 
515
 
        ttl = g_key_file_get_integer (input_data, "unlock-options", "ttl", NULL);
516
 
        gcr_unlock_options_widget_set_ttl (unlock, ttl);
517
 
 
518
 
        option = g_key_file_get_string (input_data, "unlock-options", "choice", NULL);
519
 
        gcr_unlock_options_widget_set_choice (unlock, option ? option : GCR_UNLOCK_OPTION_SESSION);
520
 
        g_free (option);
521
 
 
522
 
        prepare_unlock_option (unlock, "always");
523
 
        prepare_unlock_option (unlock, "idle");
524
 
        prepare_unlock_option (unlock, "timeout");
525
 
        prepare_unlock_option (unlock, "session");
526
 
}
527
 
 
528
 
/**
529
 
* builder: The GTKBuilder
530
 
* dialog: ignored
531
 
*
532
 
* Reads the input_data expands the details area depending on "details"-"expanded"
533
 
*
534
 
**/
535
 
static void
536
 
prepare_details (GtkBuilder *builder, GtkDialog *dialog)
537
 
{
538
 
        GtkExpander *expander;
539
 
        gboolean expanded;
540
 
 
541
 
        expander = GTK_EXPANDER (gtk_builder_get_object (builder, "details_area"));
542
 
        expanded = g_key_file_get_boolean (input_data, "details", "expanded", NULL);
543
 
        gtk_expander_set_expanded (expander, expanded);
544
 
}
545
 
 
546
 
/**
547
 
* builder: The gtk builder to add the gku-prompt.ui to
548
 
*
549
 
* Create and set up the dialog
550
 
*
551
 
* Returns the new dialog
552
 
**/
553
 
static GtkDialog*
554
 
prepare_dialog (GtkBuilder *builder)
555
 
{
556
 
        GError *error = NULL;
557
 
        GtkDialog *dialog;
558
 
 
559
 
        if (!gtk_builder_add_from_file (builder, UIDIR "gku-prompt.ui", &error)) {
560
 
                g_warning ("couldn't load prompt ui file: %s", egg_error_message (error));
561
 
                g_clear_error (&error);
562
 
                return NULL;
563
 
        }
564
 
 
565
 
        dialog = GTK_DIALOG (gtk_builder_get_object (builder, "prompt_dialog"));
566
 
        g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
567
 
 
568
 
        prepare_visibility (builder, dialog);
569
 
        prepare_titlebar (builder, dialog);
570
 
        prepare_prompt (builder, dialog);
571
 
        prepare_buttons (builder, dialog);
572
 
        prepare_passwords (builder, dialog);
573
 
        prepare_security (builder, dialog);
574
 
        prepare_lock (builder, dialog);
575
 
        prepare_details (builder, dialog);
576
 
 
577
 
        return dialog;
578
 
}
579
 
 
580
 
/**
581
 
* parent: The parent dialog
582
 
*
583
 
* Displays a verification dialog if the user wants to use empty passwords
584
 
*
585
 
* Returns TRUE if the user wants to store data unencrypted
586
 
**/
587
 
static gboolean
588
 
validate_blank_password (GtkWindow *parent)
589
 
{
590
 
        GtkWidget *dialog;
591
 
        gchar *markup;
592
 
        gint ret;
593
 
 
594
 
        dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
595
 
                                         GTK_BUTTONS_NONE, NULL);
596
 
 
597
 
        markup = create_markup (_("Store passwords unencrypted?"),
598
 
                                _("By choosing to use a blank password, your stored passwords will not be safely encrypted. "
599
 
                                  "They will be accessible by anyone with access to your files."));
600
 
        gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup);
601
 
        g_free (markup);
602
 
 
603
 
        gtk_dialog_add_buttons (GTK_DIALOG (dialog),
604
 
                                GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
605
 
                                _("Use Unsafe Storage"), GTK_RESPONSE_ACCEPT,
606
 
                                NULL);
607
 
 
608
 
        ret = gtk_dialog_run (GTK_DIALOG (dialog));
609
 
        gtk_widget_destroy (dialog);
610
 
 
611
 
        return ret == GTK_RESPONSE_ACCEPT;
612
 
}
613
 
 
614
 
/**
615
 
* builder: The GTK builder being used
616
 
* dialog: The displayed password dialog
617
 
*
618
 
* Checks if the passwords are identical (password and confirm)
619
 
*
620
 
* Returns TRUE if the passwords match, FALSE else
621
 
**/
622
 
static gboolean
623
 
validate_passwords (GtkBuilder *builder, GtkDialog *dialog)
624
 
{
625
 
        GtkWidget *pentry, *centry;
626
 
        const gchar *password, *confirm;
627
 
        const gchar *env;
628
 
 
629
 
        pentry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry"));
630
 
        centry = GTK_WIDGET (gtk_builder_get_object (builder, "confirm_entry"));
631
 
        g_return_val_if_fail (pentry && centry, FALSE);
632
 
 
633
 
        /* No confirm, no password check */
634
 
        if (!gtk_widget_get_realized (GTK_WIDGET (centry)))
635
 
                return TRUE;
636
 
 
637
 
        password = gtk_entry_get_text (GTK_ENTRY (pentry));
638
 
        confirm = gtk_entry_get_text (GTK_ENTRY (centry));
639
 
        g_return_val_if_fail (password && confirm, FALSE);
640
 
 
641
 
        /* Do the passwords match? */
642
 
        if (!g_str_equal (password, confirm)) {
643
 
                prepare_warning (builder, _("Passwords do not match."));
644
 
                return FALSE;
645
 
        }
646
 
 
647
 
        /* Double check about blank passwords */
648
 
        if (!password[0]) {
649
 
 
650
 
                /* Don't allow blank passwords if in paranoid mode */
651
 
                env = g_getenv ("GNOME_KEYRING_PARANOID");
652
 
                if (env && *env) {
653
 
                        prepare_warning (builder, _("Password cannot be blank"));
654
 
                        return FALSE;
655
 
 
656
 
                /* Double check with the user */
657
 
                } else if (!validate_blank_password (GTK_WINDOW (dialog))) {
658
 
                        return FALSE;
659
 
                }
660
 
        }
661
 
 
662
 
        return TRUE;
663
 
}
664
 
 
665
 
/**
666
 
* builder: GTKBuilder data
667
 
* dialog: The password dialog
668
 
* response: ignored
669
 
*
670
 
* Validates if passwords are identical or valid otherwise
671
 
*
672
 
* Returns TRUE if passwords are ok
673
 
**/
674
 
static gboolean
675
 
validate_dialog (GtkBuilder *builder, GtkDialog *dialog, gint response)
676
 
{
677
 
        if (!validate_passwords (builder, dialog))
678
 
                return FALSE;
679
 
 
680
 
        return TRUE;
681
 
}
682
 
 
683
 
/**
684
 
* Negotiates crypto between the calling programm and the prompt
685
 
*
686
 
* Reads data from the transport section of input_data and sends the public key back
687
 
* in the transport section of the output_data.
688
 
*
689
 
* Returns TRUE on success
690
 
**/
691
 
static gboolean
692
 
negotiate_transport_crypto (void)
693
 
{
694
 
        gcry_mpi_t base, prime, peer;
695
 
        gcry_mpi_t key, pub, priv;
696
 
        gboolean ret = FALSE;
697
 
        gpointer ikm;
698
 
        gsize n_ikm;
699
 
 
700
 
        g_assert (!the_key);
701
 
        base = prime = peer = NULL;
702
 
        key = pub = priv = NULL;
703
 
 
704
 
        /* The DH stuff coming in from our caller */
705
 
        if (gku_prompt_util_decode_mpi (input_data, "transport", "prime", &prime) &&
706
 
            gku_prompt_util_decode_mpi (input_data, "transport", "base", &base) &&
707
 
            gku_prompt_util_decode_mpi (input_data, "transport", "public", &peer)) {
708
 
 
709
 
                /* Generate our own public/priv, and then a key, send it back */
710
 
                if (egg_dh_gen_pair (prime, base, 0, &pub, &priv)) {
711
 
 
712
 
                        gku_prompt_util_encode_mpi (output_data, "transport", "public", pub);
713
 
 
714
 
                        /* Build up a key we can use */
715
 
                        ikm = egg_dh_gen_secret (peer, priv, prime, &n_ikm);
716
 
                        if (ikm != NULL) {
717
 
                                n_the_key = 16;
718
 
                                the_key = egg_secure_alloc (n_the_key);
719
 
                                if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0, the_key, n_the_key))
720
 
                                        g_return_val_if_reached (FALSE);
721
 
                                ret = TRUE;
722
 
                        }
723
 
                }
724
 
        }
725
 
 
726
 
        gcry_mpi_release (base);
727
 
        gcry_mpi_release (prime);
728
 
        gcry_mpi_release (peer);
729
 
        gcry_mpi_release (key);
730
 
        gcry_mpi_release (pub);
731
 
        gcry_mpi_release (priv);
732
 
 
733
 
        return ret;
734
 
}
735
 
 
736
 
/**
737
 
* builder: The GTKBuilder
738
 
* password_type: password type description
739
 
*
740
 
* Reads the encrypted data from the prompt and transfers it using output_data.
741
 
* If crypto is available, it uses crypto.
742
 
*
743
 
**/
744
 
static void
745
 
gather_password (GtkBuilder *builder, const gchar *password_type)
746
 
{
747
 
        GtkEntry *entry;
748
 
        gchar iv[16];
749
 
        gpointer data;
750
 
        gsize n_data;
751
 
        gchar *name;
752
 
        const gchar *text;
753
 
        gchar *value;
754
 
 
755
 
        name = g_strdup_printf ("%s_entry", password_type);
756
 
        entry = GTK_ENTRY (gtk_builder_get_object (builder, name));
757
 
        g_return_if_fail (GTK_IS_ENTRY (entry));
758
 
        g_free (name);
759
 
 
760
 
        if (!gtk_widget_get_realized (GTK_WIDGET (entry)))
761
 
                return;
762
 
 
763
 
        /* A non-encrypted password: just send the value back */
764
 
        if (!g_key_file_has_group (input_data, "transport")) {
765
 
                text = gtk_entry_get_text (entry);
766
 
                value = egg_hex_encode ((const guchar*)text, strlen (text));
767
 
                g_key_file_set_string (output_data, password_type, "parameter", "");
768
 
                g_key_file_set_string (output_data, password_type, "value", value);
769
 
                g_free (value);
770
 
                return;
771
 
        }
772
 
 
773
 
        if (!the_key && !negotiate_transport_crypto ()) {
774
 
                g_warning ("couldn't negotiate transport crypto for password");
775
 
                return;
776
 
        }
777
 
 
778
 
        gcry_create_nonce (iv, sizeof (iv));
779
 
        data = gku_prompt_util_encrypt_text (the_key, n_the_key, iv, sizeof (iv),
780
 
                                             gtk_entry_get_text (entry), &n_data);
781
 
        g_return_if_fail (data);
782
 
 
783
 
        gku_prompt_util_encode_hex (output_data, password_type, "parameter", iv, sizeof (iv));
784
 
        gku_prompt_util_encode_hex (output_data, password_type, "value", data, n_data);
785
 
 
786
 
        g_free (data);
787
 
}
788
 
 
789
 
/**
790
 
* response: The response value from the dialog
791
 
*
792
 
* Sets "prompt""response" of output_data to a string corresponding to
793
 
* the response value
794
 
*
795
 
**/
796
 
static void
797
 
gather_response (gint response)
798
 
{
799
 
        const gchar *value = NULL;
800
 
 
801
 
        switch (response) {
802
 
        case GTK_RESPONSE_OK:
803
 
                value = "ok";
804
 
                break;
805
 
        case GTK_RESPONSE_CANCEL:
806
 
                value = "no";
807
 
                break;
808
 
        case GTK_RESPONSE_DELETE_EVENT:
809
 
                value = "";
810
 
                break;
811
 
        case GTK_RESPONSE_APPLY:
812
 
                value = "other";
813
 
                break;
814
 
        default:
815
 
                g_return_if_reached ();
816
 
                break;
817
 
        }
818
 
 
819
 
        g_key_file_set_string (output_data, "prompt", "response", value);
820
 
}
821
 
 
822
 
/**
823
 
* builder: the gtk builder object
824
 
* dialog: The dialog to extract the data from
825
 
*
826
 
* Gets the unlocking settings and stores them in output_data
827
 
*
828
 
**/
829
 
static void
830
 
gather_unlock_options (GtkBuilder *builder, GtkDialog *dialog)
831
 
{
832
 
        GcrUnlockOptionsWidget *unlock;
833
 
        const gchar *choice;
834
 
 
835
 
        unlock = g_object_get_data (G_OBJECT (dialog), "unlock-options-widget");
836
 
 
837
 
        choice = gcr_unlock_options_widget_get_choice (unlock);
838
 
        if (choice) {
839
 
                g_key_file_set_integer (output_data, "unlock-options", "ttl",
840
 
                                        gcr_unlock_options_widget_get_ttl (unlock));
841
 
 
842
 
                g_key_file_set_string (output_data, "unlock-options", "choice", choice);
843
 
        }
844
 
}
845
 
 
846
 
/**
847
 
* builder: The builder
848
 
* dialog: ignored
849
 
*
850
 
* Extracts the status of the details expander and stores it in "details""expanded"
851
 
* of the output data
852
 
*
853
 
**/
854
 
static void
855
 
gather_details (GtkBuilder *builder, GtkDialog *dialog)
856
 
{
857
 
        GtkExpander *expander;
858
 
 
859
 
        expander = GTK_EXPANDER (gtk_builder_get_object (builder, "details_area"));
860
 
        g_key_file_set_boolean (output_data, "details", "expanded",
861
 
                                gtk_expander_get_expanded (expander));
862
 
}
863
 
 
864
 
 
865
 
/**
866
 
* builder: The GTKBuilder object
867
 
* dialog: the prompt dialog
868
 
*
869
 
* Called on "ok" or "apply" user choice.
870
 
*
871
 
**/
872
 
static void
873
 
gather_dialog (GtkBuilder *builder, GtkDialog *dialog)
874
 
{
875
 
        gather_password (builder, "password");
876
 
        gather_password (builder, "confirm");
877
 
        gather_password (builder, "original");
878
 
        gather_unlock_options (builder, dialog);
879
 
        gather_details (builder, dialog);
880
 
}
881
 
 
882
 
/**
883
 
* Sets up the dialog, shows it and waits for response
884
 
*
885
 
*
886
 
**/
887
 
static void
888
 
run_dialog (void)
889
 
{
890
 
        GtkBuilder *builder;
891
 
        GtkDialog *dialog;
892
 
        gint res;
893
 
 
894
 
        builder = gtk_builder_new ();
895
 
        dialog = prepare_dialog (builder);
896
 
        if (!dialog) {
897
 
                g_object_unref (builder);
898
 
                return;
899
 
        }
900
 
 
901
 
        for (;;) {
902
 
                gtk_widget_show (GTK_WIDGET (dialog));
903
 
                res = gtk_dialog_run (dialog);
904
 
                switch (res) {
905
 
                case GTK_RESPONSE_OK:
906
 
                case GTK_RESPONSE_APPLY:
907
 
                        if (!validate_dialog (builder, dialog, res))
908
 
                                continue;
909
 
                        gather_dialog (builder, dialog);
910
 
                        break;
911
 
                case GTK_RESPONSE_CANCEL:
912
 
                case GTK_RESPONSE_DELETE_EVENT:
913
 
                        break;
914
 
                default:
915
 
                        g_return_if_reached ();
916
 
                        break;
917
 
                }
918
 
 
919
 
                /* Break out of the loop by default */
920
 
                break;
921
 
        }
922
 
 
923
 
        gather_response (res);
924
 
        g_object_unref (builder);
925
 
}
926
 
 
927
 
/* -----------------------------------------------------------------------------
928
 
 * MEMORY
929
 
 */
930
 
 
931
 
static gboolean do_warning = TRUE;
932
 
#define WARNING  "couldn't allocate secure memory to keep passwords " \
933
 
                 "and or keys from being written to the disk"
934
 
 
935
 
#define ABORTMSG "The GNOME_KEYRING_PARANOID environment variable was set. " \
936
 
                 "Exiting..."
937
 
 
938
 
/*
939
 
 * These are called from gkr-secure-memory.c to provide appropriate
940
 
 * locking for memory between threads
941
 
 */
942
 
 
943
 
/**
944
 
 * egg_memory_lock:
945
 
 *
946
 
 * Memory locking for threads
947
 
 *
948
 
 */
949
 
void
950
 
egg_memory_lock (void)
951
 
{
952
 
        /* No threads used in prompt tool, doesn't need locking */
953
 
}
954
 
 
955
 
/**
956
 
 * egg_memory_unlock:
957
 
 *
958
 
 * Memory locking for threads
959
 
 *
960
 
 */
961
 
void
962
 
egg_memory_unlock (void)
963
 
 
964
 
{
965
 
        /* No threads used in prompt tool, doesn't need locking */
966
 
}
967
 
 
968
 
/**
969
 
 * egg_memory_fallback:
970
 
 * @p: Memory pointer. Can be NULL to create memory
971
 
 * @sz: Size of the pointer. 0 for freeing, everything else is resize or allocate
972
 
 *
973
 
 * An allround fallback function for
974
 
 * freeing, allocating and resizing memory
975
 
 * Behavior also depends on GNOME_KEYRING_PARANOID environment var.
976
 
 *
977
 
 * Returns:
978
 
 */
979
 
void*
980
 
egg_memory_fallback (void *p, size_t sz)
981
 
{
982
 
        const gchar *env;
983
 
 
984
 
        /* We were asked to free memory */
985
 
        if (!sz) {
986
 
                g_free (p);
987
 
                return NULL;
988
 
        }
989
 
 
990
 
        /* We were asked to allocate */
991
 
        if (!p) {
992
 
                if (do_warning) {
993
 
                        g_message (WARNING);
994
 
                        do_warning = FALSE;
995
 
                }
996
 
 
997
 
                env = g_getenv ("GNOME_KEYRING_PARANOID");
998
 
                if (env && *env)
999
 
                        g_error (ABORTMSG);
1000
 
                return g_malloc0 (sz);
1001
 
        }
1002
 
 
1003
 
        /*
1004
 
         * Reallocation is a bit of a gray area, as we can be asked
1005
 
         * by external libraries (like libgcrypt) to reallocate a
1006
 
         * non-secure block into secure memory. We cannot satisfy
1007
 
         * this request (as we don't know the size of the original
1008
 
         * block) so we just try our best here.
1009
 
         */
1010
 
 
1011
 
        return g_realloc (p, sz);
1012
 
}
1013
 
 
1014
 
/* -------------------------------------------------------------------------
1015
 
 * HELPERS
1016
 
 */
1017
 
 
1018
 
/**
1019
 
* msg1: optional first message
1020
 
* msg2: optional second message
1021
 
*
1022
 
* Because Solaris doesn't have err() :(
1023
 
* prints an error, exits the program. Depending on LOG_ERRORS it will also write logs
1024
 
*
1025
 
**/
1026
 
static void
1027
 
fatal (const char *msg1, const char *msg2)
1028
 
{
1029
 
        g_printerr ("%s: %s%s%s\n",
1030
 
                    g_get_prgname (),
1031
 
                    msg1 ? msg1 : "",
1032
 
                    msg1 && msg2 ? ": " : "",
1033
 
                    msg2 ? msg2 : "");
1034
 
#if LOG_ERRORS
1035
 
        syslog (LOG_AUTH | LOG_ERR, "%s%s%s\n",
1036
 
                 msg1 ? msg1 : "",
1037
 
                 msg1 && msg2 ? ": " : "",
1038
 
                 msg2 ? msg2 : "");
1039
 
#endif
1040
 
        exit (1);
1041
 
}
1042
 
 
1043
 
/**
1044
 
* log_domain: Optional domain for the log
1045
 
* log_level: Flags for the log level
1046
 
* message: Message for the log
1047
 
* user_data: used for the default log handler
1048
 
*
1049
 
* Does logging
1050
 
*
1051
 
**/
1052
 
static void
1053
 
log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1054
 
             const gchar *message, gpointer user_data)
1055
 
{
1056
 
        int level;
1057
 
 
1058
 
        /* Note that crit and err are the other way around in syslog */
1059
 
 
1060
 
        switch (G_LOG_LEVEL_MASK & log_level) {
1061
 
        case G_LOG_LEVEL_ERROR:
1062
 
                level = LOG_CRIT;
1063
 
                break;
1064
 
        case G_LOG_LEVEL_CRITICAL:
1065
 
                level = LOG_ERR;
1066
 
                break;
1067
 
        case G_LOG_LEVEL_WARNING:
1068
 
                level = LOG_WARNING;
1069
 
                break;
1070
 
        case G_LOG_LEVEL_MESSAGE:
1071
 
                level = LOG_NOTICE;
1072
 
                break;
1073
 
        case G_LOG_LEVEL_INFO:
1074
 
                level = LOG_INFO;
1075
 
                break;
1076
 
        case G_LOG_LEVEL_DEBUG:
1077
 
                level = LOG_DEBUG;
1078
 
                break;
1079
 
        default:
1080
 
                level = LOG_ERR;
1081
 
                break;
1082
 
        }
1083
 
 
1084
 
#if LOG_ERRORS
1085
 
        /* Log to syslog first */
1086
 
        if (log_domain)
1087
 
                syslog (level, "%s: %s", log_domain, message);
1088
 
        else
1089
 
                syslog (level, "%s", message);
1090
 
#endif /* LOG_ERRORS */
1091
 
 
1092
 
        /* And then to default handler for aborting and stuff like that */
1093
 
        g_log_default_handler (log_domain, log_level, message, user_data);
1094
 
}
1095
 
 
1096
 
/**
1097
 
*
1098
 
* Sets up logging. Identity is "gnome-keyring-prompt"
1099
 
*
1100
 
**/
1101
 
static void
1102
 
prepare_logging ()
1103
 
{
1104
 
        GLogLevelFlags flags = G_LOG_FLAG_FATAL | G_LOG_LEVEL_ERROR |
1105
 
                               G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING |
1106
 
                               G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO;
1107
 
 
1108
 
        openlog ("gnome-keyring-prompt", 0, LOG_AUTH);
1109
 
 
1110
 
        g_log_set_handler (NULL, flags, log_handler, NULL);
1111
 
        g_log_set_handler ("Glib", flags, log_handler, NULL);
1112
 
        g_log_set_handler ("Gtk", flags, log_handler, NULL);
1113
 
        g_log_set_handler ("Gnome", flags, log_handler, NULL);
1114
 
        g_log_set_default_handler (log_handler, NULL);
1115
 
}
1116
 
 
1117
 
/**
1118
 
* data: data to write to stdout
1119
 
* len: size of this data
1120
 
*
1121
 
* Writes data to stdout
1122
 
*
1123
 
**/
1124
 
static void
1125
 
write_all_output (const gchar *data, gsize len)
1126
 
{
1127
 
        int res;
1128
 
 
1129
 
        while (len > 0) {
1130
 
                res = write (1, data, len);
1131
 
                if (res < 0) {
1132
 
                        if (errno == EAGAIN || errno == EINTR)
1133
 
                                continue;
1134
 
                        if (errno != EPIPE)
1135
 
                                g_warning ("couldn't write dialog response to output: %s",
1136
 
                                           g_strerror (errno));
1137
 
                        exit (1);
1138
 
                } else if (res == 0) {
1139
 
                        g_warning ("couldn't write all dialog response to output");
1140
 
                } else  {
1141
 
                        len -= res;
1142
 
                        data += res;
1143
 
                }
1144
 
        }
1145
 
}
1146
 
 
1147
 
/**
1148
 
* Reads input from stdin. This is a key-value "file" containing control
1149
 
* data for this prompt.
1150
 
*
1151
 
* Returns the input as gchar*
1152
 
**/
1153
 
static gchar*
1154
 
read_all_input (void)
1155
 
{
1156
 
        GString *data = g_string_new ("");
1157
 
        gchar buf[256];
1158
 
        int r;
1159
 
 
1160
 
        for (;;) {
1161
 
                r = read (0, buf, sizeof (buf));
1162
 
                if (r < 0) {
1163
 
                        if (errno == EAGAIN || errno == EINTR)
1164
 
                                continue;
1165
 
                        g_warning ("couldn't read auth dialog instructions from input: %s",
1166
 
                                   g_strerror (errno));
1167
 
                        exit (1);
1168
 
                }
1169
 
                if (r == 0)
1170
 
                        break;
1171
 
                g_string_append_len (data, buf, r);
1172
 
        }
1173
 
 
1174
 
        return g_string_free (data, FALSE);
1175
 
}
1176
 
 
1177
 
/**
1178
 
* sig: not used
1179
 
*
1180
 
* Exits
1181
 
*
1182
 
**/
1183
 
static void
1184
 
hup_handler (int sig)
1185
 
{
1186
 
        /*
1187
 
         * Exit due to being cancelled. No real need to do any
1188
 
         * cleanup or anything. All memory will be freed on process end.
1189
 
         **/
1190
 
        _exit (0);
1191
 
}
1192
 
 
1193
 
/**
1194
 
 * main:
1195
 
 * @argc:
1196
 
 * @argv[]: Sent to gtk_init
1197
 
 *
1198
 
 * Prompt for GnuPG and SSH. Communicates using stdin/stdout. Communication data
1199
 
 * is in ini-file structures
1200
 
 *
1201
 
 * Returns: 0
1202
 
 */
1203
 
int
1204
 
main (int argc, char *argv[])
1205
 
{
1206
 
        GError *err = NULL;
1207
 
        gchar *data;
1208
 
        gboolean ret;
1209
 
        gsize length;
1210
 
 
1211
 
        /* Exit on HUP signal */
1212
 
        signal(SIGINT,  hup_handler);
1213
 
 
1214
 
        prepare_logging ();
1215
 
 
1216
 
        egg_libgcrypt_initialize ();
1217
 
 
1218
 
        input_data = g_key_file_new ();
1219
 
        output_data = g_key_file_new ();
1220
 
 
1221
 
        gtk_init (&argc, &argv);
1222
 
 
1223
 
#ifdef HAVE_LOCALE_H
1224
 
        /* internationalisation */
1225
 
        setlocale (LC_ALL, "");
1226
 
#endif
1227
 
 
1228
 
#ifdef HAVE_GETTEXT
1229
 
        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
1230
 
        textdomain (GETTEXT_PACKAGE);
1231
 
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1232
 
#endif
1233
 
 
1234
 
        data = read_all_input ();
1235
 
        g_assert (data);
1236
 
 
1237
 
        if (!data[0])
1238
 
                fatal ("no auth dialog instructions", NULL);
1239
 
 
1240
 
        ret = g_key_file_load_from_data (input_data, data, strlen (data), G_KEY_FILE_NONE, &err);
1241
 
        g_free (data);
1242
 
 
1243
 
        if (!ret)
1244
 
                fatal ("couldn't parse auth dialog instructions", egg_error_message (err));
1245
 
 
1246
 
        run_dialog ();
1247
 
 
1248
 
        /* Cleanup after any key */
1249
 
        if (the_key) {
1250
 
                egg_secure_clear (the_key, n_the_key);
1251
 
                egg_secure_free (the_key);
1252
 
                the_key = NULL;
1253
 
                n_the_key = 0;
1254
 
        }
1255
 
 
1256
 
        g_key_file_free (input_data);
1257
 
        data = g_key_file_to_data (output_data, &length, &err);
1258
 
        g_key_file_free (output_data);
1259
 
 
1260
 
        if (!data)
1261
 
                fatal ("couldn't format auth dialog response: %s", egg_error_message (err));
1262
 
 
1263
 
        write_all_output (data, length);
1264
 
        g_free (data);
1265
 
 
1266
 
        return 0;
1267
 
}