From 7c30dc38cfcab9801e1cdd3bf62aa5e625c17f52 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sun, 29 Jun 2008 01:12:24 -0400 Subject: [PATCH] Added pinentry's password quality meter support. Requires cracklib2 and --enable-quality passed to ./configure. --- README | 11 +++++-- configure.ac | 21 ++++++++++--- src/Makefile.am | 4 +++ src/common.h | 8 +++++ src/pinentry.c | 93 ++++++++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 110 insertions(+), 27 deletions(-) diff --git a/README b/README index cdc3ac49..2fb62238 100644 --- a/README +++ b/README @@ -47,9 +47,14 @@ Requirements: required. pinentry - http://www.gnupg.org/aegypten - Not really required, but recommended. There are various - interfaces for password entry: console/curses, X11/GTK2, - X11/QT. The X11 versions also support console/curses. + There are various interfaces for password entry: + console/curses, X11/GTK2, X11/QT. The X11 versions also + support console/curses. Version 0.7.5 or later is required + unless --disable-pinentry is passed to ./configure. + + cracklib2 - http://sourceforge.net/projects/cracklib + If --enable-quality is passed to ./configure then a + password quality meter is used with pinentry. Optional. Debian has packages for all of these. Your distro may have them too. diff --git a/configure.ac b/configure.ac index 61bc073e..9edba6e6 100644 --- a/configure.ac +++ b/configure.ac @@ -119,21 +119,34 @@ AC_DEFINE([DEFAULT_ZLIB_BUFSIZE], 65536, \ AC_ARG_ENABLE(pinentry, AC_HELP_STRING([--disable-pinentry], [Disable pinentry(1) support.]), USE_PINENTRY=no, USE_PINENTRY=yes) - if test "x$USE_PINENTRY" = "xyes"; then AC_DEFINE(WITH_PINENTRY, 1, [Define if you want pinentry(1) support.]) fi - AM_CONDITIONAL(WITH_PINENTRY, [test "x$USE_PINENTRY" = "xyes"]) pinentry="/usr/bin/pinentry" - AC_ARG_WITH(pinentry, AC_HELP_STRING([--with-pinentry=PATH], [Default location of the pinentry binary (/usr/bin/pinentry)]), pinentry="$withval") - AC_SUBST(pinentry) AC_DEFINE_UNQUOTED(PINENTRY_PATH, ["$pinentry"], [Default location of the pinentry binary.]) +AC_ARG_ENABLE(quality, AC_HELP_STRING([--enable-quality], + [Enable password quality checking with cracklib.]), CRACKLIB=yes, + CRACKLIB=no) +if test "x$CRACKLIB" = "xyes"; then + AC_CHECK_HEADER([crack.h],, AC_MSG_ERROR([Missing or invalid cracklib installation.])) + AC_CHECK_LIB([crack], FascistCheck,, AC_MSG_ERROR([Missing or invalid cracklib installation.])) + AC_DEFINE(WITH_QUALITY, 1, [Define if you want password quality checking.]) +fi +AM_CONDITIONAL(WITH_QUALITY, [test "x$CRACKLIB" = "xyes"]) + +crackdict="/var/cache/cracklib/cracklib_dict" +AC_ARG_WITH(crackdict, AC_HELP_STRING([--with-crack-dict=PATH], + [Location of the cracklib dictionary (/var/cache/cracklib/cracklib_dict).]), + crackdict="$withval") +AC_SUBST(crackdict) +AC_DEFINE_UNQUOTED(CRACKLIB_DICT, ["$crackdict"], [The location of the cracklib dictionary.]) + AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile doc/pwmd.1 po/Makefile.in]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 1f4ba917..e00efb51 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,3 +23,7 @@ endif if WITH_PINENTRY pwmd_SOURCES += pinentry.c pinentry.h endif + +if WITH_QUALITY +pwmd_LDFLAGS += -lcrack +endif diff --git a/src/common.h b/src/common.h index edadcc26..071df0ba 100644 --- a/src/common.h +++ b/src/common.h @@ -48,6 +48,11 @@ typedef enum { } inquire_status_t; #ifdef WITH_PINENTRY +typedef struct { + size_t len; + void *buf; +} membuf_t; + typedef enum { PINENTRY_NONE, PINENTRY_INIT, @@ -95,6 +100,9 @@ struct pinentry_s { gint timeout; gboolean has_lock; gint enable; + membuf_t data; + int (*inquire_cb)(void *data, const char *line); + void *inquire_data; }; #endif diff --git a/src/pinentry.c b/src/pinentry.c index bb525573..414a0fc4 100644 --- a/src/pinentry.c +++ b/src/pinentry.c @@ -27,17 +27,16 @@ #include #endif +#ifdef WITH_QUALITY +#include +#endif + #include "mem.h" #include "common.h" #include "commands.h" #include "pinentry.h" #include "pwmd_error.h" -typedef struct { - size_t len; - void *buf; -} membuf_t; - void free_client_list(); static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which); @@ -58,28 +57,72 @@ static int mem_realloc_cb(void *data, const void *buffer, size_t len) return 0; } +#ifdef WITH_QUALITY +static int quality_cb(void *data, const char *line) +{ + struct pinentry_s *pin = data; + gpg_error_t rc; + const gchar *tmp; + gint score = 0; + gchar buf[5]; + + if (strncmp(line, "QUALITY ", 8) != 0) + return GPG_ERR_INV_ARG; + + if (!(tmp = FascistCheck(line+8, CRACKLIB_DICT))) + return assuan_send_data(pin->ctx, "100", 3); + + if (!strcmp(tmp, "it's WAY too short")) + score = 10; + else if (!strcmp(tmp, "it is too short")) + score = 20; + else if (!strcmp(tmp, "it is all whitespace")) + score = 25; + else if (!strcmp(tmp, "it is based on your username")) + score = 30; + else if (!strcmp(tmp, "it is based on a dictionary word")) + score = 40; + else if (!strcmp(tmp, "it is based upon your password entry")) + score = 50; + else if (!strcmp(tmp, "it's derived from your password entry")) + score = 50; + else if (!strcmp(tmp, "it is based on a (reversed) dictionary word")) + score = 60; + else if (!strcmp(tmp, "it is derivable from your password entry")) + score = 70; + else if (!strcmp(tmp, "it does not contain enough DIFFERENT characters")) + score = 80; + else if (!strcmp(tmp, "it is too simplistic/systematic")) + score = 90; + else + score = 0; + + tmp = (const gchar *)print_fmt(buf, sizeof(buf), "%i", score); + return assuan_send_data(pin->ctx, tmp, strlen(tmp)); +} +#endif + static gpg_error_t assuan_command(struct pinentry_s *pin, gchar **result, const gchar *cmd) { - membuf_t data; gpg_error_t rc; - data.len = 0; - data.buf = NULL; + pin->data.len = 0; + pin->data.buf = NULL; - rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &data, NULL, NULL, - NULL, NULL); + rc = assuan_transact(pin->ctx, cmd, mem_realloc_cb, &pin->data, + pin->inquire_cb, pin->inquire_data, NULL, NULL); if (rc) { - if (data.buf) { - xfree(data.buf); - data.buf = NULL; + if (pin->data.buf) { + xfree(pin->data.buf); + pin->data.buf = NULL; } } else { - if (data.buf) { - mem_realloc_cb(&data, "", 1); - *result = (gchar *)data.buf; + if (pin->data.buf) { + mem_realloc_cb(&pin->data, "", 1); + *result = (gchar *)pin->data.buf; } } @@ -179,6 +222,18 @@ static gpg_error_t set_pinentry_strings(struct pinentry_s *pin, int which) gpg_error_t rc; gchar *title = NULL; +#ifdef WITH_QUALITY + if (pin->which == PINENTRY_SAVE && which != 2) { + rc = pinentry_command(pin, NULL, "SETQUALITYBAR"); + + if (rc) + goto done; + + pin->inquire_cb = quality_cb; + pin->inquire_data = pin; + } +#endif + if (which == 1) title = g_strdup(N_("Password mismatch, please try again.")); else if (!pin->title) @@ -255,10 +310,8 @@ gpg_error_t pinentry_getpin(struct pinentry_s *pin, gchar **result) gpg_error_t rc = set_pinentry_strings(pin, which); gchar *result1 = NULL; - if (rc) { - pinentry_disconnect(pin); - return rc; - } + if (rc) + goto done; again: rc = do_getpin(pin, result); -- 2.11.4.GIT