mirror of
https://github.com/Llewellynvdm/Tomb.git
synced 2024-12-31 21:21:56 +00:00
cleanup of password entry mechanism
using pinentry (with Assuan protocol) instead of our own askpass a bit less cooler but much more secure. this also includes partial normalization of variable names and the redirection of tomb operational output to stderr.
This commit is contained in:
parent
5290fd9e8d
commit
1a6fd48def
@ -6,4 +6,3 @@ EXTRA_DIST = Luks_on_disk_format.pdf New_methods_in_HD_encryption.pdf TKS1-draft
|
||||
install-data-hook:
|
||||
ln -sf $(mandir)/man1/tomb.1 $(mandir)/man1/tomb-open.1
|
||||
ln -sf $(mandir)/man1/tomb.1 $(mandir)/man1/tomb-status.1
|
||||
ln -sf $(mandir)/man1/tomb.1 $(mandir)/man1/tomb-askpass.1
|
@ -1,16 +1,12 @@
|
||||
|
||||
bin_SCRIPTS = tomb tomb-open
|
||||
|
||||
bin_PROGRAMS = tomb-status tomb-askpass
|
||||
bin_PROGRAMS = tomb-status
|
||||
|
||||
tomb_status_SOURCES = tomb-status.c
|
||||
tomb_status_LDADD = @GTK2_LIBS@ @NOTIFY_LIBS@
|
||||
tomb_status_CFLAGS = @GTK2_CFLAGS@ @NOTIFY_CFLAGS@
|
||||
|
||||
tomb_askpass_SOURCES = tomb-askpass.c
|
||||
tomb_askpass_LDADD = @GTK2_LIBS@
|
||||
tomb_askpass_CFLAGS = @GTK2_CFLAGS@
|
||||
|
||||
EXTRA_DIST = monmort.xpm
|
||||
pixmapdir = $(datadir)/pixmaps
|
||||
pixmap_DATA = monmort.xpm
|
||||
|
146
src/tomb
146
src/tomb
@ -27,10 +27,10 @@ DATE=Feb/2011
|
||||
|
||||
# standard output message routines
|
||||
# it's always useful to wrap them, in case we change behaviour later
|
||||
notice() { if ! [ $QUIET ]; then echo "[*] $1"; fi }
|
||||
act() { if ! [ $QUIET ]; then echo " . $1"; fi }
|
||||
error() { if ! [ $QUIET ]; then echo "[!] $1"; fi }
|
||||
func() { if [ $DEBUG ]; then echo "[D] $1"; fi }
|
||||
notice() { if ! [ $QUIET ]; then echo "[*] $1" >&2; fi }
|
||||
act() { if ! [ $QUIET ]; then echo " . $1" >&2; fi }
|
||||
error() { if ! [ $QUIET ]; then echo "[!] $1" >&2; fi }
|
||||
func() { if [ $DEBUG ]; then echo "[D] $1" >&2; fi }
|
||||
|
||||
# which dd command to use
|
||||
which dcfldd > /dev/null
|
||||
@ -157,37 +157,31 @@ ask_usbkey() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# user interface (just to ask the password)
|
||||
# we use pinentry now
|
||||
# comes from gpg project and is much more secure
|
||||
# it also conveniently uses the right toolkit
|
||||
ask_password() {
|
||||
|
||||
xhost 2>&1 >/dev/null
|
||||
if [ $? = 0 ]; then # we have access to the X display
|
||||
|
||||
which tomb-askpass > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
export scolopendro="`tomb-askpass ${1} 2>/dev/null`"
|
||||
return
|
||||
fi
|
||||
which ssh-askpass # 2>&1 > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
export scolopendro="`ssh-askpass "Tomb: provide the password to unlock"`"
|
||||
return
|
||||
fi
|
||||
|
||||
else # we'll collect the password from commandline
|
||||
|
||||
act "Tomb: provide the password to unlock"
|
||||
echo -n " > "
|
||||
read -s scolopendro
|
||||
export scolopendro
|
||||
# pinentry has no custom icon setting
|
||||
# so we need to temporary modify the gtk theme
|
||||
cp ~/.gtkrc-2.0 ~/.gtkrc-2.0.bak
|
||||
cat <<EOF >> ~/.gtkrc-2.0
|
||||
pixmap_path "/usr/local/share/pixmaps"
|
||||
style "normal" { stock["gtk-dialog-authentication"] = {{"monmort.xpm"}} }
|
||||
widget "*" style "normal"
|
||||
EOF
|
||||
|
||||
fi
|
||||
cat <<EOF | pinentry | awk '/^D/ { print $2 }'
|
||||
SETTITLE Opening Tomb $1
|
||||
SETDESC You need a password to use its key
|
||||
SETPROMPT Password:
|
||||
GETPIN
|
||||
EOF
|
||||
|
||||
# restore gtk as it was
|
||||
cp ~/.gtkrc-2.0.bak ~/.gtkrc-2.0
|
||||
rm ~/.gtkrc-2.0.bak
|
||||
|
||||
# just in case we'd like to have dialog supported too:
|
||||
# dialog --backtitle "This file is encrypted for privacy protection" \
|
||||
# --title "Security check" --insecure \
|
||||
# --passwordbox "Enter password:" 10 30 2> /var/run/.scolopendro
|
||||
|
||||
}
|
||||
|
||||
# popup notification
|
||||
@ -247,18 +241,21 @@ check_priv() {
|
||||
if [ $? = 0 ]; then
|
||||
func "Using sudo for root execution of 'tomb ${(f)ARGS}'"
|
||||
# check if sudo has a timestamp active
|
||||
sudo -n true 2> /dev/null
|
||||
if [ $? != 0 ]; then
|
||||
# if not then ask a password
|
||||
echo "SETDESC Sudo execution of Tomb ${ARGS[@]}
|
||||
sudok=false
|
||||
sudo -n tomb 2> /dev/null
|
||||
if [ $? != 0 ]; then # if not then ask a password
|
||||
cat <<EOF | pinentry | awk '/^D/ { print $2 }' | sudo -S -v
|
||||
SETTITLE Super user privileges required
|
||||
SETDESC Sudo execution of Tomb ${ARGS[@]}
|
||||
SETPROMPT Insert your USER password:
|
||||
GETPIN" | pinentry | awk '/^D/ { print $2 }' | sudo -S -v
|
||||
GETPIN
|
||||
EOF
|
||||
fi
|
||||
sudo "tomb" ${(s: :)ARGS}
|
||||
exit $?
|
||||
fi
|
||||
fi # have sudo
|
||||
return 1
|
||||
fi
|
||||
fi # are we root already
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -409,17 +406,17 @@ create_tomb() {
|
||||
# here user is prompted for key password
|
||||
for c in 1 2 3; do
|
||||
# 3 tries to write two times a matching password
|
||||
ask_password ${FILE}
|
||||
scolotemp=$scolopendro
|
||||
ask_password "${FILE} (again)"
|
||||
if [ "$scolotemp" = "$scolopendro" ]; then
|
||||
tombpass=`exec_as_user tomb -q askpass ${FILE}`
|
||||
tombpasstmp=$tombpass
|
||||
tombpass=`exec_as_user tomb -q askpass "${FILE} (again)"`
|
||||
if [ "$tombpasstmp" = "$tombpass" ]; then
|
||||
break;
|
||||
fi
|
||||
unset $scolotemp
|
||||
unset $scolopendro
|
||||
unset tombpasstmp
|
||||
unset tombpass
|
||||
done
|
||||
|
||||
if [ -z $scolopendro ]; then
|
||||
if [ -z $tombpass ]; then
|
||||
error "passwords don't match, aborting operation"
|
||||
umount ${keytmp}
|
||||
losetup -d $nstloop
|
||||
@ -427,8 +424,9 @@ create_tomb() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "${scolopendro}" | gpg --batch --no-options --no-tty --passphrase-fd 0 \
|
||||
echo "${tombpass}" | gpg --batch --no-options --no-tty --passphrase-fd 0 \
|
||||
-o "${FILE}.gpg" -c -a ${keytmp}/tomb.tmp
|
||||
|
||||
if [ $? = 2 ]; then
|
||||
error "setting password failed: gnupg returns 2"
|
||||
umount ${keytmp}
|
||||
@ -491,7 +489,7 @@ create_tomb() {
|
||||
cp -v ${FILE}.gpg ${usbkey_mount}/.tomb/
|
||||
chmod -R go-rwx ${usbkey_mount}/.tomb
|
||||
umount ${usbkey_mount}
|
||||
unset ${usbkey_mount}
|
||||
unset usbkey_mount
|
||||
notice "Key ${FILE}.gpg succesfully saved on your USB"
|
||||
act "now we proceed opening your new tomb"
|
||||
KEY=${FILE}.gpg
|
||||
@ -503,6 +501,8 @@ create_tomb() {
|
||||
else # kept besides (deprecated behaviour)
|
||||
act "now we proceed opening your new tomb"
|
||||
KEY=${FILE}.gpg
|
||||
unset CMD2
|
||||
unset CMD3
|
||||
mount_tomb ${FILE}
|
||||
fi
|
||||
|
||||
@ -515,7 +515,6 @@ mount_tomb() {
|
||||
return 1
|
||||
elif [ -r $CMD2 ]; then
|
||||
tombfile=`basename $CMD2`
|
||||
tombdir=`dirname $CMD2`
|
||||
else
|
||||
# try also adding a .tomb extension
|
||||
tombfile=${tombfile%%\.*}.tomb
|
||||
@ -525,6 +524,8 @@ mount_tomb() {
|
||||
fi
|
||||
fi
|
||||
|
||||
tombdir=`dirname $CMD2`
|
||||
|
||||
file ${tombdir}/${tombfile} | grep -i 'luks encrypted.*cbc-essiv' 2>&1 >/dev/null
|
||||
if [ $? != 0 ]; then
|
||||
error "$CMD2 is not a valid tomb file, operation aborted"
|
||||
@ -533,7 +534,7 @@ mount_tomb() {
|
||||
fi
|
||||
|
||||
tombname=${tombfile%%\.*}
|
||||
act "mounting tomb named after $tombname"
|
||||
act "mounting tomb named $tombname"
|
||||
|
||||
if [ $KEY ]; then
|
||||
tombkey="`basename $KEY`"
|
||||
@ -564,14 +565,14 @@ mount_tomb() {
|
||||
fi
|
||||
|
||||
if ! [ $CMD3 ]; then
|
||||
tombmount=/media/`basename ${tombfile}`
|
||||
tombmount=/media/${tombfile}
|
||||
act "mountpoint not specified, using default: $tombmount"
|
||||
elif ! [ -x $CMD3 ]; then
|
||||
error "mountpoint $CMD3 doesn't exist, operation aborted."
|
||||
if [ -n "$usbkey_mount" ]; then
|
||||
umount $usbkey_mount
|
||||
rmdir $usbkey_mount
|
||||
unset $usbkey_mount
|
||||
unset usbkey_mount
|
||||
fi
|
||||
return 1
|
||||
else
|
||||
@ -611,16 +612,16 @@ mount_tomb() {
|
||||
for c in 1 2 3; do
|
||||
|
||||
if [ $c = 1 ]; then
|
||||
ask_password ${keyname}
|
||||
tombpass=`exec_as_user tomb -q askpass ${keyname}`
|
||||
else
|
||||
ask_password "$keyname (retry $c)"
|
||||
tombpass=`exec_as_user tomb -q askpass "$keyname (retry $c)"`
|
||||
fi
|
||||
echo "${scolopendro}" \
|
||||
echo "${tombpass}" \
|
||||
| gpg --batch --passphrase-fd 0 --no-tty --no-options \
|
||||
-d "${tombkeypath}" 2>/dev/null \
|
||||
-d "${tombkeypath}" \
|
||||
| cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
|
||||
|
||||
unset scolopendro
|
||||
unset tombpass
|
||||
|
||||
if [ -r /dev/mapper/${mapper} ]; then
|
||||
break; # password was correct
|
||||
@ -631,7 +632,7 @@ mount_tomb() {
|
||||
if [ -r ${usbkey_mount}/.tomb/${tombkey} ]; then
|
||||
umount ${usbkey_mount}
|
||||
rmdir ${usbkey_mount}
|
||||
unset ${usbkey_mount}
|
||||
unset usbkey_mount
|
||||
fi
|
||||
|
||||
if ! [ -r /dev/mapper/${mapper} ]; then
|
||||
@ -644,7 +645,7 @@ mount_tomb() {
|
||||
act "encrypted storage filesystem check"
|
||||
fsck -p -C0 /dev/mapper/${mapper}
|
||||
act "tomb engraved as $tombname"
|
||||
tune2fs -L ${tombname} /dev/mapper/${mapper}
|
||||
tune2fs -L ${tombname} /dev/mapper/${mapper} > /dev/null
|
||||
|
||||
mount -o rw,noatime,nodev /dev/mapper/${mapper} ${tombmount}
|
||||
|
||||
@ -681,17 +682,17 @@ encode_key() {
|
||||
# here user is prompted for key password
|
||||
for c in 1 2 3; do
|
||||
# 3 tries to write two times a matching password
|
||||
ask_password ${FILE}
|
||||
scolotemp=$scolopendro
|
||||
ask_password "${FILE} (again)"
|
||||
if [ "$scolotemp" = "$scolopendro" ]; then
|
||||
tombpass=`exec_as_user tomb -q askpass ${FILE}`
|
||||
tombpasstmp=$tombpass
|
||||
tombpass=`exec_as_user tomb -q askpass "${FILE} (again)"`
|
||||
if [ "$tombpasstmp" = "$tombpass" ]; then
|
||||
break;
|
||||
fi
|
||||
unset $scolotemp
|
||||
unset $scolopendro
|
||||
unset tombpasstmp
|
||||
unset tombpass
|
||||
done
|
||||
|
||||
if [ -z $scolopendro ]; then
|
||||
if [ -z $tombpass ]; then
|
||||
error "passwords don't match, aborting operation."
|
||||
return 1
|
||||
fi
|
||||
@ -702,7 +703,7 @@ encode_key() {
|
||||
/^Comment/ {next}
|
||||
{print $0}' ${tombkey} \
|
||||
| steghide embed --embedfile - --coverfile ${imagefile} \
|
||||
-p ${scolopendro} -z 9 -e serpent cbc
|
||||
-p ${tombpass} -z 9 -e serpent cbc
|
||||
if [ $? != 0 ]; then
|
||||
error "encoding error: steghide reports problems"
|
||||
res=1
|
||||
@ -711,7 +712,7 @@ encode_key() {
|
||||
res=0
|
||||
fi
|
||||
|
||||
unset scolopendro
|
||||
unset tombpass
|
||||
|
||||
return $res
|
||||
}
|
||||
@ -731,11 +732,11 @@ decode_key() {
|
||||
notice "Decoding a key out of image $imagefile"
|
||||
for c in 1 2 3; do
|
||||
if [ $c = 1 ]; then
|
||||
ask_password ${keyname}
|
||||
tombpass=`exec_as_user tomb -q askpass ${keyname}`
|
||||
else
|
||||
ask_password "$keyname (retry $c)"
|
||||
tombpass=`exec_as_user tomb -q askpass "$keyname (retry $c)"`
|
||||
fi
|
||||
steghide extract -sf ${imagefile} -p ${scolopendro} -xf - \
|
||||
steghide extract -sf ${imagefile} -p ${tombpass} -xf - \
|
||||
| awk '
|
||||
BEGIN {
|
||||
print "-----BEGIN PGP MESSAGE-----"
|
||||
@ -753,7 +754,7 @@ print "-----END PGP MESSAGE-----"
|
||||
fi
|
||||
done
|
||||
|
||||
unset scolopendro
|
||||
unset tombpass
|
||||
|
||||
if [ $res != 0 ]; then
|
||||
error "nothing found."
|
||||
@ -1030,6 +1031,7 @@ case "$CMD" in
|
||||
|
||||
install) check_priv ; install_tomb ;;
|
||||
|
||||
askpass) ask_password $CMD2 $CMD3 ;;
|
||||
status) tomb-status ;;
|
||||
notify) tomb-notify $CMD2 $CMD3 ;;
|
||||
|
||||
@ -1039,4 +1041,4 @@ case "$CMD" in
|
||||
;;
|
||||
esac
|
||||
# return codes from called functions
|
||||
return $?
|
||||
# return $?
|
||||
|
@ -1,332 +0,0 @@
|
||||
/* Tomb askpass
|
||||
|
||||
Derived from gtk-led-askpass.c version 0.9
|
||||
by Dafydd Harries <daf@muse.19inch.net>, 2003 2004
|
||||
(An ssh-askpass alike software)
|
||||
|
||||
Based on ideas from ssh-askpass-gnome, by Damien Miller and Nalin Dahyabhai,
|
||||
and on Jim Knoble's x11-ssh-askpass.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
See also:
|
||||
|
||||
http://www.cgabriel.org/sw/gtk2-ssh-askpass/
|
||||
-- Jim Knoble's x11-ssh-askpass
|
||||
http://www.cgabriel.org/sw/gtk2-ssh-askpass/
|
||||
-- Christopher Gabriel's gtk2-ssh-askpass
|
||||
|
||||
Todo:
|
||||
|
||||
- Internationalise. Probably entails autotoolising.
|
||||
- Add more eye candy.
|
||||
- Implement optional mouse/server grabbing.
|
||||
- Alow overriding the title on the command line.
|
||||
- Make the LED box a proper GTK+ widget.
|
||||
|
||||
*/
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
/* The Tomb icon is an artwork by Jordi aka MonMort
|
||||
a nomadic graffiti artist from Barcelona */
|
||||
#include <monmort.xpm>
|
||||
|
||||
/* Title for the dialog. */
|
||||
#define TITLE "Unlocking tomb"
|
||||
|
||||
/* Width of each LED. */
|
||||
#define LED_WIDTH 8
|
||||
/* Height of each LED. */
|
||||
#define LED_HEIGHT 16
|
||||
/* Space around and between LEDs. */
|
||||
#define LED_MARGIN 5
|
||||
/* Number of LEDs to have. */
|
||||
#define LED_COUNT 12
|
||||
|
||||
/* How many times to attempt to grab the keyboard before giving up. */
|
||||
#define GRAB_TRIES_MAX 10
|
||||
/* How long to sleep, in microseconds, in between keyboard grab attempts. */
|
||||
#define GRAB_SLEEP 100000
|
||||
/* Sleep length, in milliseconds, after Control-U press. */
|
||||
#define CLEAR_SLEEP 800
|
||||
|
||||
enum {
|
||||
LED_STATE_OFF,
|
||||
LED_STATE_GREEN,
|
||||
LED_STATE_RED,
|
||||
LED_STATES
|
||||
};
|
||||
|
||||
GdkPixbuf *pb_monmort;
|
||||
|
||||
GdkColor colours[LED_STATES] = {
|
||||
/* LED_STATE_OFF */
|
||||
{ 0, 0x3333, 0x6666, 0x3333 },
|
||||
/* LED_STATE_GREEN */
|
||||
{ 0, 0x6666, 0xFFFF, 0x6666 },
|
||||
/* LED_STATE_RED */
|
||||
{ 0, 0xDDDD, 0x3333, 0x3333 }
|
||||
};
|
||||
|
||||
|
||||
void draw_led(GtkWidget *widget, gint state, guint offset)
|
||||
{
|
||||
GdkGC *gc = gdk_gc_new(widget->window);
|
||||
|
||||
/* Draw the border. */
|
||||
gdk_draw_rectangle(widget->window,
|
||||
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
|
||||
FALSE,
|
||||
LED_MARGIN + offset * (LED_WIDTH + LED_MARGIN),
|
||||
LED_MARGIN,
|
||||
LED_WIDTH,
|
||||
LED_HEIGHT);
|
||||
|
||||
gdk_gc_set_rgb_fg_color(gc, &(colours[state]));
|
||||
|
||||
/* Draw the inside rectangle. */
|
||||
gdk_draw_rectangle(widget->window,
|
||||
gc,
|
||||
TRUE,
|
||||
LED_MARGIN + offset * (LED_WIDTH + LED_MARGIN) + 1,
|
||||
LED_MARGIN + 1,
|
||||
LED_WIDTH - 1,
|
||||
LED_HEIGHT - 1);
|
||||
}
|
||||
|
||||
gboolean led_area_expose_handler(GtkWidget *led_area, GdkEventExpose *event,
|
||||
GString *passphrase)
|
||||
{
|
||||
gint i, width, height;
|
||||
gint length = passphrase->len;
|
||||
|
||||
gdk_drawable_get_size(GDK_DRAWABLE(led_area->window), &width, &height);
|
||||
|
||||
/* Draw a focus indicator if appropriate. */
|
||||
if (GTK_WIDGET_HAS_FOCUS(led_area))
|
||||
gtk_paint_focus(led_area->style, led_area->window,
|
||||
GTK_WIDGET_STATE(led_area), &(event->area), led_area,
|
||||
"", 0, 0, width, height);
|
||||
|
||||
/* Draw each LED. */
|
||||
for (i = 0; i < LED_COUNT; i++) {
|
||||
/* This is the complicated bit. */
|
||||
gboolean on = ((length / LED_COUNT) % 2 == 0) ?
|
||||
(length % LED_COUNT > i) :
|
||||
(length % LED_COUNT <= i);
|
||||
|
||||
draw_led(led_area, on ? LED_STATE_GREEN : LED_STATE_OFF, i);
|
||||
}
|
||||
|
||||
/* TRUE means not to propagate the event. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean timeout_handler(GtkWidget *led_area)
|
||||
{
|
||||
gtk_widget_queue_draw(led_area);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void clear(GString *passphrase, GtkWidget *led_area)
|
||||
{
|
||||
gint i;
|
||||
|
||||
/*
|
||||
Delete bit by bit to ensure erasure. g_string_erase() will overwrite
|
||||
the last character with 0, so we shouldn't need to worry about leaving
|
||||
sensitive data in memory. Note that the string may be empty. This is
|
||||
so that the interface responds consistently.
|
||||
*/
|
||||
while (passphrase->len > 0)
|
||||
g_string_erase(passphrase, passphrase->len - 1, 1);
|
||||
|
||||
for (i = 0; i < LED_COUNT; i++)
|
||||
draw_led(led_area, LED_STATE_RED, i);
|
||||
|
||||
/*
|
||||
Remove the redness after a delay. If an exposure is triggered, such as
|
||||
by a key getting pressed, then the redraw will simply happen early.
|
||||
*/
|
||||
gtk_timeout_add(CLEAR_SLEEP, (GtkFunction)timeout_handler, led_area);
|
||||
}
|
||||
|
||||
gboolean led_area_key_press_handler(GtkWidget *led_area, GdkEventKey *event,
|
||||
GString *passphrase) {
|
||||
/* Obtain Unicode representation of key released. */
|
||||
gunichar c = gdk_keyval_to_unicode(event->keyval);
|
||||
/* Determine whether the key released was printable. */
|
||||
gint isprint = g_unichar_isprint(c);
|
||||
/* Obtain default modifier mask. */
|
||||
guint modifiers = gtk_accelerator_get_default_mod_mask();
|
||||
|
||||
if (event->keyval == GDK_Delete) {
|
||||
clear(passphrase, led_area);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((event->state & modifiers) == GDK_CONTROL_MASK) {
|
||||
|
||||
if (event->keyval == GDK_u) {
|
||||
/* C-u -- delete everything. */
|
||||
clear(passphrase, led_area);
|
||||
/* Return early in order to avoid the redraw. */
|
||||
return TRUE;
|
||||
|
||||
} else {
|
||||
|
||||
/* Unrecognised keypress. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} else if (event->keyval == GDK_BackSpace && passphrase->len > 0) {
|
||||
/*
|
||||
Backspace -- remove last character. See the comment above
|
||||
about g_string_erase.
|
||||
*/
|
||||
g_string_erase(passphrase, passphrase->len - 1, 1);
|
||||
} else if (isprint) {
|
||||
/* Printable character. */
|
||||
g_string_append_unichar(passphrase, c);
|
||||
} else {
|
||||
/* Unrecognized keypress, propagate. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Trigger a redraw of the LED area. */
|
||||
gtk_widget_queue_draw(led_area);
|
||||
|
||||
/* TRUE means not to propagate the event. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean led_area_button_press_handler(GtkWidget *led_area,
|
||||
GdkEventButton *event, gpointer data)
|
||||
{
|
||||
gtk_widget_grab_focus(led_area);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
gint response, grab_tries, i;
|
||||
char keyname[256];
|
||||
GString *passphrase = g_string_new("");
|
||||
GtkWidget *dialog, *alignment, *led_area;
|
||||
GList tmplist;
|
||||
|
||||
gtk_set_locale();
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
if (argc > 1) {
|
||||
snprintf(keyname,255,"%s",argv[1]);
|
||||
} else {
|
||||
sprintf(keyname,"unknown");
|
||||
}
|
||||
/*
|
||||
dialog
|
||||
`- vbox (implicit)
|
||||
`- aligment
|
||||
`- led_area
|
||||
*/
|
||||
|
||||
/* Question dialog with no parent; OK and Cancel buttons. */
|
||||
dialog = gtk_message_dialog_new_with_markup
|
||||
(NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK,
|
||||
"Enter the password to unlock\n"
|
||||
"<span font=\"Times 24\">%s</span>", keyname);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), TITLE);
|
||||
|
||||
// set and show the image icon
|
||||
pb_monmort = gdk_pixbuf_new_from_xpm_data(monmort);
|
||||
tmplist.data = (gpointer*)pb_monmort;
|
||||
tmplist.prev = tmplist.next = NULL;
|
||||
gtk_window_set_icon_list(GTK_WINDOW(dialog), &tmplist);
|
||||
gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog),
|
||||
gtk_image_new_from_pixbuf(pb_monmort));
|
||||
|
||||
/* Place the dialog in the middle of the screen. */
|
||||
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
|
||||
/* OK is the default action. */
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
|
||||
|
||||
/* Add some spacing within the dialog's vbox. */
|
||||
gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 3);
|
||||
|
||||
/* The alignment widget containing the drawing area. */
|
||||
alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
|
||||
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), alignment);
|
||||
|
||||
/* The drawing area for the LEDs. */
|
||||
led_area = gtk_drawing_area_new();
|
||||
gtk_container_add(GTK_CONTAINER(alignment), led_area);
|
||||
/* Make the LED widget focusable. */
|
||||
GTK_WIDGET_SET_FLAGS(led_area, GTK_CAN_FOCUS);
|
||||
/* Make the LED widget focused. */
|
||||
gtk_widget_grab_focus(led_area);
|
||||
/* Make the LED widget receive key press and button press events. */
|
||||
gtk_widget_add_events(led_area,
|
||||
GDK_KEY_PRESS_MASK | GDK_BUTTON_PRESS_MASK);
|
||||
/* Set a size request. */
|
||||
gtk_widget_set_size_request(led_area,
|
||||
LED_MARGIN + (LED_WIDTH + LED_MARGIN) * LED_COUNT,
|
||||
LED_HEIGHT + LED_MARGIN * 2);
|
||||
/* Set up handler for key releases. */
|
||||
g_signal_connect(G_OBJECT(led_area), "key_press_event",
|
||||
G_CALLBACK(led_area_key_press_handler), passphrase);
|
||||
/* Set up handler for button releases. */
|
||||
g_signal_connect(G_OBJECT(led_area), "button_press_event",
|
||||
G_CALLBACK(led_area_button_press_handler), NULL);
|
||||
/* Set up handler for expose events. */
|
||||
g_signal_connect(G_OBJECT(led_area), "expose_event",
|
||||
G_CALLBACK(led_area_expose_handler), passphrase);
|
||||
|
||||
|
||||
/* Show all the widgets. */
|
||||
gtk_widget_show_all(dialog);
|
||||
/* Put the dialog on the screen now for the grab to work. */
|
||||
gtk_widget_show_now(dialog);
|
||||
|
||||
/* Grab the keyboard */
|
||||
gdk_keyboard_grab(GTK_WIDGET(dialog)->window, FALSE, GDK_CURRENT_TIME);
|
||||
|
||||
/* Make the dialog stay on top. */
|
||||
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
|
||||
|
||||
/* Run the dialog. */
|
||||
response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
/* Ungrab the keyboard. */
|
||||
gdk_keyboard_ungrab(GDK_CURRENT_TIME);
|
||||
|
||||
/* If the OK button was pressed, print the passphrase. */
|
||||
if (response == GTK_RESPONSE_OK)
|
||||
g_print("%s\n", passphrase->str);
|
||||
|
||||
/* Scrub the passphrase, if any. */
|
||||
for (i = 0; i < passphrase->len; i++)
|
||||
passphrase->str[i] = '\0';
|
||||
|
||||
if (response == GTK_RESPONSE_OK)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user