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.
4
Copyright (C) 2009 Stefan Walter
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.
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.
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.
20
Author: Stef Walter <stef@memberwebs.com>
25
#include "gku-prompt-util.h"
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"
39
#include <glib/gi18n.h>
52
static GKeyFile *input_data = NULL;
53
static GKeyFile *output_data = NULL;
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;
60
static gboolean keyboard_grabbed = FALSE;
63
/* An encryption key for returning passwords */
64
static gpointer the_key = NULL;
65
static gsize n_the_key = 0;
68
#define GRAB_KEYBOARD 1
71
* SECTION: gku-prompt-tool.c
72
* @short_description: Displays a propmt for 3rd party programs (ssh, gnupg)
75
/* ------------------------------------------------------------------------------ */
78
* primary: The part that will be bold
79
* secondary: The normal part of the text or NULL
83
* Returns The text encased in markup
86
create_markup (const gchar *primary, const gchar *secondary)
88
return g_markup_printf_escaped ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
89
primary, secondary ? secondary : "");
92
#if GTK_CHECK_VERSION (3,0,0)
94
on_grab_broken (GtkWidget * widget, GdkEventGrabBroken * event)
96
if (grabbed_device && event->keyboard) {
97
grabbed_device = NULL;
106
grab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
108
GdkGrabStatus status;
110
#if GTK_CHECK_VERSION (3,0,0)
111
GdkDevice *device = NULL;
112
GdkDeviceManager *manager;
117
if (grabbed_device || !GRAB_KEYBOARD)
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)) {
125
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
128
g_list_free (devices);
131
g_message ("couldn't find device to grab");
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;
146
g_message ("could not grab keyboard: %d", (int)status);
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;
154
g_message ("could not grab keyboard: %d", (int)status);
159
/* Always return false, so event is handled elsewhere */
164
ungrab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
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;
176
if (keyboard_grabbed)
177
gdk_keyboard_ungrab (gdk_event_get_time (event));
178
keyboard_grabbed = FALSE;
181
/* Always return false, so event is handled elsewhere */
186
* win: The window that changed state
187
* event: The event that triggered it
190
* Depending on the state it will grab the keyboard or ungrab it.
195
window_state_changed (GtkWidget *win, GdkEventWindowState *event, gpointer data)
197
GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (win));
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);
205
grab_keyboard (win, (GdkEvent*)event, data);
212
* editable: The GTK_ENTRY that changed
213
* user_data: the progress bar to update
215
* Will update the password quality displayed in the progress bar.
219
on_password_changed (GtkEditable *editable, gpointer user_data)
221
const char *password;
223
int upper, lower, digit, misc;
226
password = gtk_entry_get_text (GTK_ENTRY (editable));
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
235
length = strlen (password);
241
for ( i = 0; i < length ; i++) {
242
if (g_ascii_isdigit (password[i]))
244
else if (g_ascii_islower (password[i]))
246
else if (g_ascii_isupper (password[i]))
261
pwstrength = ((length*0.1)-0.2) + (digit*0.1) + (misc*0.15) + (upper*0.1);
263
if (pwstrength < 0.0)
265
if (pwstrength > 1.0)
268
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (user_data), pwstrength);
272
* builder: The builder object to look for visibility keys in
275
* Depending on the input_data and the keys in the group "visibility"
276
* this toggles the visibility of displayed widgets
280
prepare_visibility (GtkBuilder *builder, GtkDialog *dialog)
285
keys = g_key_file_get_keys (input_data, "visibility", NULL, NULL);
286
g_return_if_fail (keys);
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);
294
if (g_key_file_get_boolean (input_data, "visibility", *key, NULL))
295
gtk_widget_show (GTK_WIDGET (object));
297
gtk_widget_hide (GTK_WIDGET (object));
305
* dialog: The dialog to set the title for
307
* Sets a new title to the dialog. The title is extracted from the input_data
311
prepare_titlebar (GtkBuilder *builder, GtkDialog *dialog)
315
title = g_key_file_get_string (input_data, "prompt", "title", NULL);
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);
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);
327
* builder: The GtkBuilder to extract the warning label from
328
* text: The text to display in the warning label
330
* Displays a text in the warning_label
334
prepare_warning (GtkBuilder *builder, const gchar *text)
339
label = GTK_LABEL (gtk_builder_get_object (builder, "warning_label"));
340
g_return_if_fail (label);
342
markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", text);
343
gtk_label_set_markup (label, markup);
346
gtk_widget_show (GTK_WIDGET (label));
350
* builder: The GTKBuilder to look for widgets in
353
* Reads data from the input_data and prepares a prompt dialog
357
prepare_prompt (GtkBuilder *builder, GtkDialog *dialog)
359
gchar *primary, *secondary, *markup, *warning;
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);
366
markup = create_markup (primary, secondary);
370
label = GTK_LABEL (gtk_builder_get_object (builder, "prompt_label"));
371
g_return_if_fail (label);
373
gtk_label_set_markup (label, markup);
376
warning = g_key_file_get_string (input_data, "prompt", "warning", NULL);
378
prepare_warning (builder, warning);
383
* builder: The GTK builder to use
384
* dialog: the dialog to add buttons to
386
* Adds buttons to the dialog. Which buttons to add is defined in input_data
390
prepare_buttons (GtkBuilder *builder, GtkDialog *dialog)
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);
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);
405
gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
408
g_free (cancel_text);
413
* entry: the entry to set the buffer for
415
* Adds the secure egg_entry_buffer to the entry
419
prepare_password_entry (GtkEntry *entry)
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);
428
* builder: The GTKBuilder
429
* dialog: The Dialog to prepare
431
* Password entries use a secure buffer. Set this up here.
435
prepare_passwords (GtkBuilder *builder, GtkDialog *dialog)
440
entry = GTK_ENTRY(gtk_builder_get_object (builder, "password_entry"));
441
prepare_password_entry (entry);
443
strength = GTK_WIDGET (gtk_builder_get_object (builder, "strength_bar"));
444
g_signal_connect (entry, "changed", G_CALLBACK (on_password_changed), strength);
446
entry = GTK_ENTRY(gtk_builder_get_object (builder, "original_entry"));
447
prepare_password_entry (entry);
449
entry = GTK_ENTRY(gtk_builder_get_object (builder, "confirm_entry"));
450
prepare_password_entry (entry);
454
* builder: The GTKBuilder
455
* dialog: the dialog to connect signals for
457
* Registers the signal handlers for keyboard grab
461
prepare_security (GtkBuilder *builder, GtkDialog *dialog)
464
* When passwords are involved we grab the keyboard so that people
465
* don't accidentally type their passwords in other windows.
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);
473
prepare_unlock_option (GcrUnlockOptionsWidget *unlock, const gchar *option)
475
GError *error = NULL;
479
text = g_key_file_get_string (input_data, option, "label", NULL);
481
gcr_unlock_options_widget_set_label (unlock, option, text);
484
sensitive = g_key_file_get_boolean (input_data, option, "sensitive", &error);
486
text = g_key_file_get_string (input_data, option, "reason", NULL);
487
gcr_unlock_options_widget_set_sensitive (unlock, option, sensitive, text);
491
g_clear_error (&error);
495
* builder: GtkBuilderobject to read widgets from
496
* dialog: the prompt dialog
498
* Set default value depending on input_data
502
prepare_lock (GtkBuilder *builder, GtkDialog *dialog)
504
GcrUnlockOptionsWidget *unlock;
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));
515
ttl = g_key_file_get_integer (input_data, "unlock-options", "ttl", NULL);
516
gcr_unlock_options_widget_set_ttl (unlock, ttl);
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);
522
prepare_unlock_option (unlock, "always");
523
prepare_unlock_option (unlock, "idle");
524
prepare_unlock_option (unlock, "timeout");
525
prepare_unlock_option (unlock, "session");
529
* builder: The GTKBuilder
532
* Reads the input_data expands the details area depending on "details"-"expanded"
536
prepare_details (GtkBuilder *builder, GtkDialog *dialog)
538
GtkExpander *expander;
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);
547
* builder: The gtk builder to add the gku-prompt.ui to
549
* Create and set up the dialog
551
* Returns the new dialog
554
prepare_dialog (GtkBuilder *builder)
556
GError *error = NULL;
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);
565
dialog = GTK_DIALOG (gtk_builder_get_object (builder, "prompt_dialog"));
566
g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
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);
581
* parent: The parent dialog
583
* Displays a verification dialog if the user wants to use empty passwords
585
* Returns TRUE if the user wants to store data unencrypted
588
validate_blank_password (GtkWindow *parent)
594
dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
595
GTK_BUTTONS_NONE, NULL);
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);
603
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
604
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
605
_("Use Unsafe Storage"), GTK_RESPONSE_ACCEPT,
608
ret = gtk_dialog_run (GTK_DIALOG (dialog));
609
gtk_widget_destroy (dialog);
611
return ret == GTK_RESPONSE_ACCEPT;
615
* builder: The GTK builder being used
616
* dialog: The displayed password dialog
618
* Checks if the passwords are identical (password and confirm)
620
* Returns TRUE if the passwords match, FALSE else
623
validate_passwords (GtkBuilder *builder, GtkDialog *dialog)
625
GtkWidget *pentry, *centry;
626
const gchar *password, *confirm;
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);
633
/* No confirm, no password check */
634
if (!gtk_widget_get_realized (GTK_WIDGET (centry)))
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);
641
/* Do the passwords match? */
642
if (!g_str_equal (password, confirm)) {
643
prepare_warning (builder, _("Passwords do not match."));
647
/* Double check about blank passwords */
650
/* Don't allow blank passwords if in paranoid mode */
651
env = g_getenv ("GNOME_KEYRING_PARANOID");
653
prepare_warning (builder, _("Password cannot be blank"));
656
/* Double check with the user */
657
} else if (!validate_blank_password (GTK_WINDOW (dialog))) {
666
* builder: GTKBuilder data
667
* dialog: The password dialog
670
* Validates if passwords are identical or valid otherwise
672
* Returns TRUE if passwords are ok
675
validate_dialog (GtkBuilder *builder, GtkDialog *dialog, gint response)
677
if (!validate_passwords (builder, dialog))
684
* Negotiates crypto between the calling programm and the prompt
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.
689
* Returns TRUE on success
692
negotiate_transport_crypto (void)
694
gcry_mpi_t base, prime, peer;
695
gcry_mpi_t key, pub, priv;
696
gboolean ret = FALSE;
701
base = prime = peer = NULL;
702
key = pub = priv = NULL;
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)) {
709
/* Generate our own public/priv, and then a key, send it back */
710
if (egg_dh_gen_pair (prime, base, 0, &pub, &priv)) {
712
gku_prompt_util_encode_mpi (output_data, "transport", "public", pub);
714
/* Build up a key we can use */
715
ikm = egg_dh_gen_secret (peer, priv, prime, &n_ikm);
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);
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);
737
* builder: The GTKBuilder
738
* password_type: password type description
740
* Reads the encrypted data from the prompt and transfers it using output_data.
741
* If crypto is available, it uses crypto.
745
gather_password (GtkBuilder *builder, const gchar *password_type)
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));
760
if (!gtk_widget_get_realized (GTK_WIDGET (entry)))
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);
773
if (!the_key && !negotiate_transport_crypto ()) {
774
g_warning ("couldn't negotiate transport crypto for password");
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);
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);
790
* response: The response value from the dialog
792
* Sets "prompt""response" of output_data to a string corresponding to
797
gather_response (gint response)
799
const gchar *value = NULL;
802
case GTK_RESPONSE_OK:
805
case GTK_RESPONSE_CANCEL:
808
case GTK_RESPONSE_DELETE_EVENT:
811
case GTK_RESPONSE_APPLY:
815
g_return_if_reached ();
819
g_key_file_set_string (output_data, "prompt", "response", value);
823
* builder: the gtk builder object
824
* dialog: The dialog to extract the data from
826
* Gets the unlocking settings and stores them in output_data
830
gather_unlock_options (GtkBuilder *builder, GtkDialog *dialog)
832
GcrUnlockOptionsWidget *unlock;
835
unlock = g_object_get_data (G_OBJECT (dialog), "unlock-options-widget");
837
choice = gcr_unlock_options_widget_get_choice (unlock);
839
g_key_file_set_integer (output_data, "unlock-options", "ttl",
840
gcr_unlock_options_widget_get_ttl (unlock));
842
g_key_file_set_string (output_data, "unlock-options", "choice", choice);
847
* builder: The builder
850
* Extracts the status of the details expander and stores it in "details""expanded"
855
gather_details (GtkBuilder *builder, GtkDialog *dialog)
857
GtkExpander *expander;
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));
866
* builder: The GTKBuilder object
867
* dialog: the prompt dialog
869
* Called on "ok" or "apply" user choice.
873
gather_dialog (GtkBuilder *builder, GtkDialog *dialog)
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);
883
* Sets up the dialog, shows it and waits for response
894
builder = gtk_builder_new ();
895
dialog = prepare_dialog (builder);
897
g_object_unref (builder);
902
gtk_widget_show (GTK_WIDGET (dialog));
903
res = gtk_dialog_run (dialog);
905
case GTK_RESPONSE_OK:
906
case GTK_RESPONSE_APPLY:
907
if (!validate_dialog (builder, dialog, res))
909
gather_dialog (builder, dialog);
911
case GTK_RESPONSE_CANCEL:
912
case GTK_RESPONSE_DELETE_EVENT:
915
g_return_if_reached ();
919
/* Break out of the loop by default */
923
gather_response (res);
924
g_object_unref (builder);
927
/* -----------------------------------------------------------------------------
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"
935
#define ABORTMSG "The GNOME_KEYRING_PARANOID environment variable was set. " \
939
* These are called from gkr-secure-memory.c to provide appropriate
940
* locking for memory between threads
946
* Memory locking for threads
950
egg_memory_lock (void)
952
/* No threads used in prompt tool, doesn't need locking */
958
* Memory locking for threads
962
egg_memory_unlock (void)
965
/* No threads used in prompt tool, doesn't need locking */
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
973
* An allround fallback function for
974
* freeing, allocating and resizing memory
975
* Behavior also depends on GNOME_KEYRING_PARANOID environment var.
980
egg_memory_fallback (void *p, size_t sz)
984
/* We were asked to free memory */
990
/* We were asked to allocate */
997
env = g_getenv ("GNOME_KEYRING_PARANOID");
1000
return g_malloc0 (sz);
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.
1011
return g_realloc (p, sz);
1014
/* -------------------------------------------------------------------------
1019
* msg1: optional first message
1020
* msg2: optional second message
1022
* Because Solaris doesn't have err() :(
1023
* prints an error, exits the program. Depending on LOG_ERRORS it will also write logs
1027
fatal (const char *msg1, const char *msg2)
1029
g_printerr ("%s: %s%s%s\n",
1032
msg1 && msg2 ? ": " : "",
1035
syslog (LOG_AUTH | LOG_ERR, "%s%s%s\n",
1037
msg1 && msg2 ? ": " : "",
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
1053
log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1054
const gchar *message, gpointer user_data)
1058
/* Note that crit and err are the other way around in syslog */
1060
switch (G_LOG_LEVEL_MASK & log_level) {
1061
case G_LOG_LEVEL_ERROR:
1064
case G_LOG_LEVEL_CRITICAL:
1067
case G_LOG_LEVEL_WARNING:
1068
level = LOG_WARNING;
1070
case G_LOG_LEVEL_MESSAGE:
1073
case G_LOG_LEVEL_INFO:
1076
case G_LOG_LEVEL_DEBUG:
1085
/* Log to syslog first */
1087
syslog (level, "%s: %s", log_domain, message);
1089
syslog (level, "%s", message);
1090
#endif /* LOG_ERRORS */
1092
/* And then to default handler for aborting and stuff like that */
1093
g_log_default_handler (log_domain, log_level, message, user_data);
1098
* Sets up logging. Identity is "gnome-keyring-prompt"
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;
1108
openlog ("gnome-keyring-prompt", 0, LOG_AUTH);
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);
1118
* data: data to write to stdout
1119
* len: size of this data
1121
* Writes data to stdout
1125
write_all_output (const gchar *data, gsize len)
1130
res = write (1, data, len);
1132
if (errno == EAGAIN || errno == EINTR)
1135
g_warning ("couldn't write dialog response to output: %s",
1136
g_strerror (errno));
1138
} else if (res == 0) {
1139
g_warning ("couldn't write all dialog response to output");
1148
* Reads input from stdin. This is a key-value "file" containing control
1149
* data for this prompt.
1151
* Returns the input as gchar*
1154
read_all_input (void)
1156
GString *data = g_string_new ("");
1161
r = read (0, buf, sizeof (buf));
1163
if (errno == EAGAIN || errno == EINTR)
1165
g_warning ("couldn't read auth dialog instructions from input: %s",
1166
g_strerror (errno));
1171
g_string_append_len (data, buf, r);
1174
return g_string_free (data, FALSE);
1184
hup_handler (int sig)
1187
* Exit due to being cancelled. No real need to do any
1188
* cleanup or anything. All memory will be freed on process end.
1196
* @argv[]: Sent to gtk_init
1198
* Prompt for GnuPG and SSH. Communicates using stdin/stdout. Communication data
1199
* is in ini-file structures
1204
main (int argc, char *argv[])
1211
/* Exit on HUP signal */
1212
signal(SIGINT, hup_handler);
1216
egg_libgcrypt_initialize ();
1218
input_data = g_key_file_new ();
1219
output_data = g_key_file_new ();
1221
gtk_init (&argc, &argv);
1223
#ifdef HAVE_LOCALE_H
1224
/* internationalisation */
1225
setlocale (LC_ALL, "");
1229
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
1230
textdomain (GETTEXT_PACKAGE);
1231
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1234
data = read_all_input ();
1238
fatal ("no auth dialog instructions", NULL);
1240
ret = g_key_file_load_from_data (input_data, data, strlen (data), G_KEY_FILE_NONE, &err);
1244
fatal ("couldn't parse auth dialog instructions", egg_error_message (err));
1248
/* Cleanup after any key */
1250
egg_secure_clear (the_key, n_the_key);
1251
egg_secure_free (the_key);
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);
1261
fatal ("couldn't format auth dialog response: %s", egg_error_message (err));
1263
write_all_output (data, length);