1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright 2009-2010 Red Hat, Inc,
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
* Written by: Matthias Clasen <mclasen@redhat.com>
26
#include <sys/types.h>
30
#include <glib/gi18n.h>
33
#include "um-password-dialog.h"
34
#include "um-user-manager.h"
36
#include "run-passwd.h"
39
struct _UmPasswordDialog {
43
GtkWidget *action_label;
44
GtkWidget *action_combo;
45
GtkWidget *password_entry;
46
GtkWidget *verify_entry;
47
GtkWidget *strength_indicator;
48
GtkWidget *strength_indicator_label;
49
GtkWidget *normal_hint_entry;
50
GtkWidget *normal_hint_label;
51
GtkWidget *show_password_button;
55
gboolean using_ecryptfs;
57
GtkWidget *old_password_label;
58
GtkWidget *old_password_entry;
59
gboolean old_password_ok;
61
PasswdHandler *passwd_handler;
65
generate_one_password (GtkWidget *widget,
72
gtk_entry_set_text (GTK_ENTRY (um->password_entry), pwd);
73
gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
76
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button),
83
activate_icon (GtkEntry *entry,
84
GtkEntryIconPosition pos,
85
GdkEventButton *event,
88
generate_one_password (GTK_WIDGET (entry), um);
92
populate_menu (GtkEntry *entry,
98
item = gtk_menu_item_new_with_mnemonic (_("_Generate a password"));
99
g_signal_connect (item, "activate",
100
G_CALLBACK (generate_one_password), um);
101
gtk_widget_show (item);
102
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
106
finish_password_change (UmPasswordDialog *um)
108
gtk_widget_hide (um->dialog);
110
gtk_entry_set_text (GTK_ENTRY (um->password_entry), " ");
111
gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
112
gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), "");
113
gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
115
um_password_dialog_set_user (um, NULL);
119
cancel_password_dialog (GtkButton *button,
120
UmPasswordDialog *um)
122
finish_password_change (um);
126
dialog_closed (GtkWidget *dialog,
128
UmPasswordDialog *um)
130
gtk_widget_destroy (dialog);
134
password_changed_cb (PasswdHandler *handler,
136
UmPasswordDialog *um)
139
const gchar *primary_text;
140
const gchar *secondary_text;
142
gtk_widget_set_sensitive (um->dialog, TRUE);
143
gdk_window_set_cursor (gtk_widget_get_window (um->dialog), NULL);
146
finish_password_change (um);
150
if (error->code == PASSWD_ERROR_REJECTED) {
151
primary_text = error->message;
152
secondary_text = _("Please choose another password.");
154
gtk_entry_set_text (GTK_ENTRY (um->password_entry), "");
155
gtk_widget_grab_focus (um->password_entry);
157
gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
159
else if (error->code == PASSWD_ERROR_AUTH_FAILED) {
160
primary_text = error->message;
161
secondary_text = _("Please type your current password again.");
163
gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
164
gtk_widget_grab_focus (um->old_password_entry);
167
primary_text = _("Password could not be changed");
168
secondary_text = error->message;
171
dialog = gtk_message_dialog_new (GTK_WINDOW (um->dialog),
176
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
177
"%s", secondary_text);
178
g_signal_connect (dialog, "response",
179
G_CALLBACK (dialog_closed), um);
180
gtk_window_present (GTK_WINDOW (dialog));
185
accept_password_dialog (GtkButton *button,
186
UmPasswordDialog *um)
192
const gchar *password;
194
model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo));
195
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (um->action_combo), &iter);
196
gtk_tree_model_get (model, &iter, 1, &mode, -1);
198
password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
199
hint = gtk_entry_get_text (GTK_ENTRY (um->normal_hint_entry));
201
if (mode == 0 && um_user_get_uid (um->user) == getuid ()) {
205
/* When setting a password for the current user,
206
* use passwd directly, to preserve the audit trail
207
* and to e.g. update the keyring password.
209
passwd_change_password (um->passwd_handler, password, (PasswdCallback) password_changed_cb, um);
210
gtk_widget_set_sensitive (um->dialog, FALSE);
211
display = gtk_widget_get_display (um->dialog);
212
cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
213
gdk_window_set_cursor (gtk_widget_get_window (um->dialog), cursor);
214
gdk_display_flush (display);
215
g_object_unref (cursor);
218
um_user_set_password (um->user, mode, password, hint);
219
finish_password_change (um);
224
update_sensitivity (UmPasswordDialog *um)
226
const gchar *password, *verify;
227
const gchar *old_password;
228
const gchar *tooltip;
231
password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
232
verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry));
233
old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry));
235
if (strlen (password) < pw_min_length ()) {
237
if (password[0] == '\0') {
238
tooltip = _("You need to enter a new password");
241
tooltip = _("The new password is too short");
244
else if (strcmp (password, verify) != 0) {
246
if (verify[0] == '\0') {
247
tooltip = _("You need to confirm the password");
250
tooltip = _("The passwords do not match");
253
else if (!um->old_password_ok) {
255
if (old_password[0] == '\0') {
256
tooltip = _("You need to enter your current password");
259
tooltip = _("The current password is not correct");
267
gtk_widget_set_sensitive (um->ok_button, can_change);
268
gtk_widget_set_tooltip_text (um->ok_button, tooltip);
272
action_changed (GtkComboBox *combo,
273
UmPasswordDialog *um)
277
active = gtk_combo_box_get_active (combo);
279
gtk_widget_set_sensitive (um->password_entry, TRUE);
280
gtk_entry_set_icon_sensitive (GTK_ENTRY (um->password_entry), GTK_ENTRY_ICON_SECONDARY, TRUE);
281
gtk_widget_set_sensitive (um->verify_entry, TRUE);
282
gtk_widget_set_sensitive (um->old_password_entry, TRUE);
283
gtk_widget_set_sensitive (um->normal_hint_entry, TRUE);
284
gtk_widget_set_sensitive (um->normal_hint_label, TRUE);
285
gtk_widget_set_sensitive (um->strength_indicator_label, TRUE);
286
gtk_widget_set_sensitive (um->show_password_button, TRUE);
288
update_sensitivity (um);
291
gtk_widget_set_sensitive (um->password_entry, FALSE);
292
gtk_entry_set_icon_sensitive (GTK_ENTRY (um->password_entry), GTK_ENTRY_ICON_SECONDARY, FALSE);
293
gtk_widget_set_sensitive (um->verify_entry, FALSE);
294
gtk_widget_set_sensitive (um->old_password_entry, FALSE);
295
gtk_widget_set_sensitive (um->normal_hint_entry, FALSE);
296
gtk_widget_set_sensitive (um->normal_hint_label, FALSE);
297
gtk_widget_set_sensitive (um->strength_indicator_label, FALSE);
298
gtk_widget_set_sensitive (um->show_password_button, FALSE);
299
gtk_widget_set_sensitive (um->ok_button, TRUE);
304
show_password_toggled (GtkToggleButton *button,
305
UmPasswordDialog *um)
309
active = gtk_toggle_button_get_active (button);
310
gtk_entry_set_visibility (GTK_ENTRY (um->password_entry), active);
311
gtk_entry_set_visibility (GTK_ENTRY (um->verify_entry), active);
315
update_password_strength (UmPasswordDialog *um)
317
const gchar *password;
318
const gchar *old_password;
319
const gchar *username;
322
const gchar *long_hint;
324
password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
325
old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry));
326
username = um_user_get_user_name (um->user);
328
pw_strength (password, old_password, username,
329
&hint, &long_hint, &strength_level);
331
gtk_level_bar_set_value (GTK_LEVEL_BAR (um->strength_indicator), strength_level);
332
gtk_label_set_label (GTK_LABEL (um->strength_indicator_label), hint);
333
gtk_widget_set_tooltip_text (um->strength_indicator, long_hint);
334
gtk_widget_set_tooltip_text (um->strength_indicator_label, long_hint);
338
update_password_match (UmPasswordDialog *um)
340
const char *password;
343
password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
344
verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry));
346
if (strlen (password) > 0 && strlen (verify) > 0) {
347
if (strcmp (password, verify) != 0) {
348
set_entry_validation_error (GTK_ENTRY (um->verify_entry),
349
_("Passwords do not match"));
352
clear_entry_validation_error (GTK_ENTRY (um->verify_entry));
358
password_entry_changed (GtkEntry *entry,
360
UmPasswordDialog *um)
362
update_password_strength (um);
363
update_sensitivity (um);
364
update_password_match (um);
368
password_entry_focus_out (GtkWidget *entry,
369
GdkEventFocus *event,
370
UmPasswordDialog *um)
372
update_password_match (um);
377
verify_entry_changed (GtkEntry *entry,
379
UmPasswordDialog *um)
381
clear_entry_validation_error (GTK_ENTRY (entry));
382
update_password_strength (um);
383
update_sensitivity (um);
387
verify_entry_focus_out (GtkWidget *entry,
388
GdkEventFocus *event,
389
UmPasswordDialog *um)
391
update_password_match (um);
396
entry_size_changed (GtkWidget *entry,
397
GtkAllocation *allocation,
400
gtk_widget_set_size_request (label, allocation->width, -1);
404
auth_cb (PasswdHandler *handler,
406
UmPasswordDialog *um)
409
um->old_password_ok = FALSE;
410
set_entry_validation_error (GTK_ENTRY (um->old_password_entry),
411
_("Wrong password"));
414
um->old_password_ok = TRUE;
415
clear_entry_validation_error (GTK_ENTRY (um->old_password_entry));
418
update_sensitivity (um);
422
old_password_entry_focus_out (GtkWidget *entry,
423
GdkEventFocus *event,
424
UmPasswordDialog *um)
428
text = gtk_entry_get_text (GTK_ENTRY (entry));
429
if (strlen (text) > 0) {
430
passwd_authenticate (um->passwd_handler, text,
431
(PasswdCallback)auth_cb, um);
438
old_password_entry_activate (GtkWidget *entry,
439
UmPasswordDialog *um)
443
text = gtk_entry_get_text (GTK_ENTRY (entry));
444
if (strlen (text) > 0) {
445
passwd_authenticate (um->passwd_handler, text,
446
(PasswdCallback)auth_cb, um);
452
old_password_entry_changed (GtkEntry *entry,
454
UmPasswordDialog *um)
456
clear_entry_validation_error (GTK_ENTRY (entry));
457
um->old_password_ok = FALSE;
458
update_sensitivity (um);
462
um_password_dialog_set_privileged (UmPasswordDialog *um,
466
gtk_widget_set_visible (um->action_label, TRUE);
467
gtk_widget_set_visible (um->action_combo, TRUE);
470
gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0);
471
gtk_widget_set_visible (um->action_label, FALSE);
472
gtk_widget_set_visible (um->action_combo, FALSE);
476
int _is_gdm_running = -1;
478
is_gdm_running (void)
480
if (_is_gdm_running == -1) {
484
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
485
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
486
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
487
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
489
"org.gnome.DisplayManager",
490
"/org/gnome/DisplayManager/Manager",
491
"org.gnome.DisplayManager.Manager",
497
owner_name = g_dbus_proxy_get_name_owner (proxy);
499
g_object_unref (proxy);
502
_is_gdm_running = (owner_name != NULL) ? 1 : 0;
505
return _is_gdm_running;
509
um_password_dialog_new (void)
513
const gchar *filename;
514
UmPasswordDialog *um;
516
const char *old_label;
520
builder = gtk_builder_new ();
523
filename = UIDIR "/password-dialog.ui";
524
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
525
filename = "data/password-dialog.ui";
526
if (!gtk_builder_add_from_file (builder, filename, &error)) {
527
g_error ("%s", error->message);
528
g_error_free (error);
532
um = g_new0 (UmPasswordDialog, 1);
534
um->action_label = (GtkWidget *) gtk_builder_get_object (builder, "action-label");
535
widget = (GtkWidget *) gtk_builder_get_object (builder, "action-combo");
536
g_signal_connect (widget, "changed",
537
G_CALLBACK (action_changed), um);
538
um->action_combo = widget;
540
widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog");
541
g_signal_connect (widget, "delete-event",
542
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
545
um->user_icon = (GtkWidget *) gtk_builder_get_object (builder, "user-icon");
546
um->user_name = (GtkWidget *) gtk_builder_get_object (builder, "user-name");
548
widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button");
549
g_signal_connect (widget, "clicked",
550
G_CALLBACK (cancel_password_dialog), um);
552
widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
553
g_signal_connect (widget, "clicked",
554
G_CALLBACK (accept_password_dialog), um);
555
gtk_widget_grab_default (widget);
556
um->ok_button = widget;
558
widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-strength-hints-label");
559
old_label = gtk_label_get_label (GTK_LABEL (widget));
560
if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity"))
561
label = g_strdup_printf ("<a href=\"%s\">%s</a>",
562
"help:ubuntu-help/user-goodpassword",
565
label = g_strdup_printf ("<a href=\"%s\">%s</a>",
566
"help:gnome-help/user-goodpassword",
568
gtk_label_set_markup (GTK_LABEL (widget), label);
571
widget = (GtkWidget *) gtk_builder_get_object (builder, "show-password-checkbutton");
572
g_signal_connect (widget, "toggled",
573
G_CALLBACK (show_password_toggled), um);
574
um->show_password_button = widget;
576
widget = (GtkWidget *) gtk_builder_get_object (builder, "password-entry");
577
g_signal_connect (widget, "notify::text",
578
G_CALLBACK (password_entry_changed), um);
579
g_signal_connect_after (widget, "focus-out-event",
580
G_CALLBACK (password_entry_focus_out), um);
581
gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
583
g_signal_connect (widget, "icon-press",
584
G_CALLBACK (activate_icon), um);
585
g_signal_connect (widget, "populate-popup",
586
G_CALLBACK (populate_menu), um);
588
um->password_entry = widget;
590
widget = (GtkWidget *) gtk_builder_get_object (builder, "old-password-entry");
591
g_signal_connect_after (widget, "focus-out-event",
592
G_CALLBACK (old_password_entry_focus_out), um);
593
g_signal_connect (widget, "notify::text",
594
G_CALLBACK (old_password_entry_changed), um);
595
g_signal_connect (widget, "activate",
596
G_CALLBACK (old_password_entry_activate), um);
597
um->old_password_entry = widget;
598
um->old_password_label = (GtkWidget *) gtk_builder_get_object (builder, "old-password-label");
600
widget = (GtkWidget *) gtk_builder_get_object (builder, "verify-entry");
601
g_signal_connect (widget, "notify::text",
602
G_CALLBACK (verify_entry_changed), um);
603
g_signal_connect_after (widget, "focus-out-event",
604
G_CALLBACK (verify_entry_focus_out), um);
605
um->verify_entry = widget;
608
len = MAX (len, strlen (C_("Password strength", "Too short")));
609
len = MAX (len, strlen (C_("Password strength", "Weak")));
610
len = MAX (len, strlen (C_("Password strength", "Fair")));
611
len = MAX (len, strlen (C_("Password strength", "Good")));
612
len = MAX (len, strlen (C_("Password strength", "Strong")));
615
widget = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label");
616
gtk_label_set_width_chars (GTK_LABEL (widget), len);
618
um->normal_hint_entry = (GtkWidget *) gtk_builder_get_object (builder, "normal-hint-entry");
621
* This only sort-of works because the dialog is non-resizable.
623
widget = (GtkWidget *)gtk_builder_get_object (builder, "password-normal-hint-description-label");
624
g_signal_connect (um->normal_hint_entry, "size-allocate",
625
G_CALLBACK (entry_size_changed), widget);
626
um->normal_hint_label = widget;
628
if (!is_gdm_running ()) {
629
widget = (GtkWidget *) gtk_builder_get_object (builder, "password-normal-hint-label");
630
gtk_widget_hide (widget);
631
gtk_widget_hide (um->normal_hint_entry);
632
gtk_widget_hide (um->normal_hint_label);
635
um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator");
637
um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label");
639
g_object_unref (builder);
645
um_password_dialog_free (UmPasswordDialog *um)
647
gtk_widget_destroy (um->dialog);
650
g_object_unref (um->user);
652
if (um->passwd_handler)
653
passwd_destroy (um->passwd_handler);
659
visible_func (GtkTreeModel *model,
661
UmPasswordDialog *um)
665
gboolean locked = um_user_get_locked (um->user);
667
gtk_tree_model_get (model, iter, 1, &mode, -1);
669
if (mode == 1 && !is_gdm_running ())
672
if (mode == 2 && um->using_ecryptfs)
675
if (mode == 3 && locked)
678
if (mode == 4 && !locked)
688
um_password_dialog_set_user (UmPasswordDialog *um,
695
g_object_unref (um->user);
699
um->user = g_object_ref (user);
701
um->using_ecryptfs = is_using_ecryptfs (um_user_get_user_name (user));
703
pixbuf = um_user_render_icon (user, FALSE, 48);
704
gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf);
705
g_object_unref (pixbuf);
707
gtk_label_set_label (GTK_LABEL (um->user_name),
708
um_user_get_real_name (user));
710
gtk_entry_set_text (GTK_ENTRY (um->password_entry), "");
711
gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
712
gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), "");
713
gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
714
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), FALSE);
715
if (um_user_get_uid (um->user) == getuid () &&
716
um_user_get_password_mode (um->user) == UM_PASSWORD_MODE_REGULAR) {
717
gtk_widget_show (um->old_password_label);
718
gtk_widget_show (um->old_password_entry);
719
um->old_password_ok = FALSE;
722
gtk_widget_hide (um->old_password_label);
723
gtk_widget_hide (um->old_password_entry);
724
um->old_password_ok = TRUE;
726
if (um_user_get_uid (um->user) == getuid()) {
727
if (um->passwd_handler != NULL)
728
passwd_destroy (um->passwd_handler);
729
um->passwd_handler = passwd_init ();
733
model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo));
734
if (!GTK_IS_TREE_MODEL_FILTER (model)) {
735
model = gtk_tree_model_filter_new (model, NULL);
736
gtk_combo_box_set_model (GTK_COMBO_BOX (um->action_combo), model);
737
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
738
(GtkTreeModelFilterVisibleFunc) visible_func,
742
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
743
gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0);
747
um_password_dialog_show (UmPasswordDialog *um,
750
gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent);
751
gtk_window_present (GTK_WINDOW (um->dialog));
752
if (um->old_password_ok == FALSE)
753
gtk_widget_grab_focus (um->old_password_entry);
755
gtk_widget_grab_focus (um->password_entry);