tcleanup of password entry mechanism - tomb - the crypto undertaker
 (HTM) git clone git://parazyd.org/tomb.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 1a6fd48def3ed490c5435bfdf4d5317a319479bd
 (DIR) parent 5290fd9e8d0643cbc37a1089eadb1fdb687b88b6
 (HTM) Author: Jaromil <jaromil@dyne.org>
       Date:   Mon, 14 Feb 2011 10:24:31 +0100
       
       cleanup of password entry mechanism
       
       using pinentry (with Assuan protocol) instead of our own askpass
       a bit less cooler but much more secure.
       tthis also includes partial normalization of variable names
       and the redirection of tomb operational output to stderr.
       
       Diffstat:
         M doc/Makefile.am                     |       2 --
         M src/Makefile.am                     |       6 +-----
         M src/tomb                            |     146 ++++++++++++++++---------------
         D src/tomb-askpass.c                  |     332 -------------------------------
       
       4 files changed, 75 insertions(+), 411 deletions(-)
       ---
 (DIR) diff --git a/doc/Makefile.am b/doc/Makefile.am
       t@@ -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
       -\ No newline at end of file
 (DIR) diff --git a/src/Makefile.am b/src/Makefile.am
       t@@ -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
 (DIR) diff --git a/src/tomb b/src/tomb
       t@@ -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
       t@@ -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
       t@@ -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
        }
        
       t@@ -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
       t@@ -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}
       t@@ -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
       t@@ -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
        
       t@@ -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
       t@@ -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"
       t@@ -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`"
       t@@ -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
       t@@ -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
       t@@ -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
       t@@ -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}
        
       t@@ -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
       t@@ -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
       t@@ -711,7 +712,7 @@ encode_key() {
                res=0
            fi
        
       -    unset scolopendro
       +    unset tombpass
        
            return $res
        }
       t@@ -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-----"
       t@@ -753,7 +754,7 @@ print "-----END PGP MESSAGE-----"
                fi
            done
        
       -    unset scolopendro
       +    unset tombpass
        
            if [ $res != 0 ]; then
                error "nothing found."
       t@@ -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 ;;
        
       t@@ -1039,4 +1041,4 @@ case "$CMD" in
                ;;
        esac
        # return codes from called functions
       -return $?
       +# return $?
 (DIR) diff --git a/src/tomb-askpass.c b/src/tomb-askpass.c
       t@@ -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;
       -}
       -