Locker
/* $Id$ */
/* Copyright (c) 2011-2018 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Desktop Locker */
/* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <unistd.h>
#include <pwd.h>
#ifdef __linux__
# include <crypt.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <libintl.h>
#include <System.h>
#include <Desktop.h>
#include "Locker.h"
#include "../../config.h"
#define _(string) gettext(string)
/* Password */
/* private */
/* types */
typedef struct _LockerAuth
{
LockerAuthHelper * helper;
guint source;
/* widgets */
GtkWidget * widget;
GtkWidget * password;
GtkWidget * button;
GtkWidget * error;
} Password;
/* prototypes */
/* plug-in */
static Password * _password_init(LockerAuthHelper * helper);
static void _password_destroy(Password * password);
static GtkWidget * _password_get_widget(Password * password);
static int _password_action(Password * password, LockerAction action);
/* callbacks */
static void _password_on_password_activate(gpointer data);
static gboolean _password_on_timeout(gpointer data);
static gboolean _password_on_timeout_clear(gpointer data);
/* public */
/* variables */
/* plug-in */
LockerAuthDefinition plugin =
{
"Password",
NULL,
NULL,
_password_init,
_password_destroy,
_password_get_widget,
_password_action,
};
/* private */
/* functions */
/* password_init */
static Password * _password_init(LockerAuthHelper * helper)
{
Password * password;
PangoFontDescription * bold;
const GdkRGBA white = { 1.0, 1.0, 1.0, 1.0 };
const GdkRGBA red = { 1.0, 0.0, 0.0, 1.0 };
GtkWidget * vbox;
GtkWidget * hbox;
GtkWidget * hbox2;
GtkWidget * widget;
char buf[256];
struct passwd * pw;
char const * username;
if((password = object_new(sizeof(*password))) == NULL)
return NULL;
password->helper = helper;
password->source = 0;
bold = pango_font_description_new();
pango_font_description_set_weight(bold, PANGO_WEIGHT_BOLD);
#if GTK_CHECK_VERSION(3, 0, 0)
password->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
#else
password->widget = gtk_vbox_new(FALSE, 4);
#endif
/* top padding (centering) */
widget = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(password->widget), widget, TRUE, TRUE, 0);
/* dialog */
#if GTK_CHECK_VERSION(3, 0, 0)
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
#else
hbox = gtk_hbox_new(FALSE, 4);
#endif
/* left padding (centering) */
widget = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
/* authentication icon */
widget = gtk_image_new_from_stock(GTK_STOCK_DIALOG_AUTHENTICATION,
GTK_ICON_SIZE_DIALOG);
#if GTK_CHECK_VERSION(3, 0, 0)
g_object_set(widget, "valign", GTK_ALIGN_START, NULL);
#else
gtk_misc_set_alignment(GTK_MISC(widget), 0.5, 0.0);
#endif
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
#if GTK_CHECK_VERSION(3, 0, 0)
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
#else
vbox = gtk_vbox_new(FALSE, 4);
#endif
/* hostname */
if(gethostname(buf, sizeof(buf)) != 0)
snprintf(buf, sizeof(buf), "%s", "DeforaOS " PACKAGE);
else
buf[sizeof(buf) - 1] = '\0';
widget = gtk_label_new(buf);
gtk_widget_override_color(widget, GTK_STATE_FLAG_NORMAL, &white);
gtk_widget_override_font(widget, bold);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
/* screen */
if((pw = getpwuid(getuid())) != NULL)
username = pw->pw_name;
else
username = getenv("USER");
snprintf(buf, sizeof(buf), (username != NULL)
? _("This screen is locked by %s")
: _("This screen is locked"), username);
widget = gtk_label_new(buf);
gtk_widget_override_color(widget, GTK_STATE_FLAG_NORMAL, &white);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
/* prompt */
widget = gtk_label_new(_("Enter password: "));
gtk_widget_override_color(widget, GTK_STATE_FLAG_NORMAL, &white);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
/* entry */
#if GTK_CHECK_VERSION(3, 0, 0)
hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
#else
hbox2 = gtk_hbox_new(FALSE, 4);
#endif
password->password = gtk_entry_new();
gtk_entry_set_visibility(GTK_ENTRY(password->password), FALSE);
g_signal_connect_swapped(password->password, "activate", G_CALLBACK(
_password_on_password_activate), password);
gtk_box_pack_start(GTK_BOX(hbox2), password->password, FALSE, TRUE, 0);
/* button */
password->button = gtk_button_new_from_stock(GTK_STOCK_OK);
g_signal_connect_swapped(password->button, "clicked", G_CALLBACK(
_password_on_password_activate), password);
gtk_box_pack_start(GTK_BOX(hbox2), password->button, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, TRUE, 0);
/* error */
password->error = gtk_label_new("");
gtk_widget_override_color(password->error, GTK_STATE_FLAG_NORMAL, &red);
gtk_widget_override_font(password->error, bold);
gtk_box_pack_start(GTK_BOX(vbox), password->error, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
/* right padding (centering) */
widget = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(password->widget), hbox, FALSE, TRUE, 0);
/* bottom padding (centering) */
widget = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(password->widget), widget, TRUE, TRUE, 0);
gtk_widget_show_all(password->widget);
gtk_widget_hide(password->widget);
pango_font_description_free(bold);
return password;
}
/* password_destroy */
static void _password_destroy(Password * password)
{
gtk_widget_destroy(password->widget);
if(password->source != 0)
g_source_remove(password->source);
object_delete(password);
}
/* password_get_widget */
static GtkWidget * _password_get_widget(Password * password)
{
return password->widget;
}
/* password_action */
static int _password_action(Password * password, LockerAction action)
{
LockerAuthHelper * helper = password->helper;
GtkWidget * entry = password->password;
char const * p;
switch(action)
{
case LOCKER_ACTION_DEACTIVATE:
gtk_widget_grab_focus(entry);
gtk_widget_show(password->widget);
break;
case LOCKER_ACTION_LOCK:
gtk_widget_hide(password->widget);
if((p = helper->config_get(helper->locker, "password",
"password")) == NULL)
{
gtk_entry_set_text(GTK_ENTRY(entry), "");
return -helper->error(helper->locker,
_("No password was set"), 1);
}
gtk_widget_set_sensitive(entry, TRUE);
gtk_widget_set_sensitive(password->button, TRUE);
gtk_entry_set_text(GTK_ENTRY(entry), "");
if(password->source != 0)
g_source_remove(password->source);
password->source = g_timeout_add(30000,
_password_on_timeout, password);
break;
case LOCKER_ACTION_ACTIVATE:
case LOCKER_ACTION_CYCLE:
case LOCKER_ACTION_START:
gtk_widget_hide(password->widget);
break;
case LOCKER_ACTION_UNLOCK:
gtk_widget_hide(password->widget);
if(password->source != 0)
g_source_remove(password->source);
password->source = 0;
break;
default:
break;
}
return 0;
}
/* callbacks */
/* password_on_password_activate */
static void _password_on_password_activate(gpointer data)
{
Password * password = data;
LockerAuthHelper * helper = password->helper;
char const * text;
char const * p;
char const * q;
if(password->source != 0)
g_source_remove(password->source);
password->source = 0;
gtk_widget_set_sensitive(password->password, FALSE);
gtk_widget_set_sensitive(password->button, FALSE);
text = gtk_entry_get_text(GTK_ENTRY(password->password));
if((p = helper->config_get(helper->locker, "password", "password"))
== NULL)
helper->error(NULL, _("No password was set"), 1);
else
{
/* check if the password is hashed */
if(p[0] == '$' && (q = crypt(text, p)) != NULL)
text = q;
if(strcmp(text, p) == 0)
{
gtk_entry_set_text(GTK_ENTRY(password->password), "");
helper->action(helper->locker, LOCKER_ACTION_UNLOCK);
return;
}
}
gtk_entry_set_text(GTK_ENTRY(password->password), "");
helper->error(NULL, _("Authentication failed"), 1);
gtk_widget_grab_focus(password->password);
gtk_label_set_text(GTK_LABEL(password->error), _("Wrong password!"));
password->source = g_timeout_add(3000, _password_on_timeout_clear,
password);
}
/* password_on_timeout */
static gboolean _password_on_timeout(gpointer data)
{
Password * password = data;
gtk_label_set_text(GTK_LABEL(password->error), _("Timed out"));
gtk_widget_set_sensitive(password->password, FALSE);
gtk_widget_set_sensitive(password->button, FALSE);
password->source = g_timeout_add(3000, _password_on_timeout_clear,
password);
return FALSE;
}
/* password_on_timeout_clear */
static gboolean _password_on_timeout_clear(gpointer data)
{
Password * password = data;
password->source = 0;
gtk_label_set_text(GTK_LABEL(password->error), "");
gtk_widget_set_sensitive(password->password, TRUE);
gtk_widget_set_sensitive(password->button, TRUE);
gtk_entry_set_text(GTK_ENTRY(password->password), "");
gtk_widget_hide(password->widget);
password->helper->action(password->helper->locker, LOCKER_ACTION_START);
return FALSE;
}