Add optional libpwquality support for new LUKS passwords.
authorMilan Broz <gmazyland@gmail.com>
Wed, 19 Dec 2012 16:25:11 +0000 (17:25 +0100)
committerMilan Broz <gmazyland@gmail.com>
Wed, 19 Dec 2012 16:25:11 +0000 (17:25 +0100)
If password is entered through terminal (no keyfile specified)
and cryptsetup is compiled with --enable-pwquality, default
system pwquality settings are used to check password quality.

configure.in
man/cryptsetup.8
src/Makefile.am
src/cryptsetup.c
src/cryptsetup.h
src/utils_password.c [new file with mode: 0644]
src/utils_tools.c

index ed84b2f..3922d55 100644 (file)
@@ -92,6 +92,20 @@ AC_DEFUN([NO_FIPS], [
 ])
 
 dnl ==========================================================================
+dnl pwquality library (cryptsetup CLI only)
+AC_ARG_ENABLE([pwquality], AS_HELP_STRING([--enable-pwquality],[enable password quality checking]),
+[with_pwquality=$enableval],
+[with_pwquality=no])
+
+if test "x$with_pwquality" = "xyes"; then
+       AC_DEFINE(ENABLE_PWQUALITY, 1, [Enable password quality checking])
+       PKG_CHECK_MODULES([PWQUALITY], [pwquality >= 1.0.0],,
+               AC_MSG_ERROR([You need pwquality library.]))
+
+       PWQUALITY_STATIC_LIBS=$PWQUALITY_LIBS
+fi
+
+dnl ==========================================================================
 dnl Crypto backend functions
 
 AC_DEFUN([CONFIGURE_GCRYPT], [
@@ -287,6 +301,9 @@ fi
 AC_SUBST([DEVMAPPER_LIBS])
 AC_SUBST([DEVMAPPER_STATIC_LIBS])
 
+AC_SUBST([PWQUALITY_LIBS])
+AC_SUBST([PWQUALITY_STATIC_LIBS])
+
 AC_SUBST([CRYPTO_CFLAGS])
 AC_SUBST([CRYPTO_LIBS])
 AC_SUBST([CRYPTO_STATIC_LIBS])
index 41ad39f..5a294df 100644 (file)
@@ -752,6 +752,16 @@ actually belongs to the header given. In fact you can specify an
 arbitrary device as the ciphertext device for \fIopen\fR
 with the \-\-header option. Use with care.
 .TP
+.B "\-\-force-password\fR"
+Do not use password quality checking for new LUKS passwords.
+
+This option applies only to \fIluksFormat\fR, \fIluksAddKey\fR and
+\fIluksChangeKey\fR and is ignored if cryptsetup is built without
+password quality checking support.
+
+For more info about password quality check, see manual page
+for \fBpwquality.conf(5)\fR.
+.TP
 .B "\-\-version"
 Show the program version.
 .TP
index f071acc..969aa6c 100644 (file)
@@ -15,13 +15,15 @@ cryptsetup_SOURCES = \
        $(top_builddir)/lib/utils_loop.c        \
        $(top_builddir)/lib/utils_fips.c        \
        utils_tools.c                           \
+       utils_password.c                        \
        cryptsetup.c                            \
        cryptsetup.h
 
 cryptsetup_LDADD = \
        $(top_builddir)/lib/libcryptsetup.la    \
        @POPT_LIBS@                             \
-       @FIPSCHECK_LIBS@
+       @FIPSCHECK_LIBS@                        \
+       @PWQUALITY_LIBS@
 
 cryptsetup_CFLAGS = -Wall
 
@@ -34,6 +36,7 @@ cryptsetup_static_CFLAGS = $(cryptsetup_CFLAGS)
 cryptsetup_static_LDFLAGS = -all-static
 cryptsetup_static_LDADD = $(cryptsetup_LDADD)  \
        @CRYPTO_STATIC_LIBS@                    \
+       @PWQUALITY_STATIC_LIBS@                 \
        @DEVMAPPER_STATIC_LIBS@                 \
        @UUID_LIBS@
 endif
index 3e66975..3659b73 100644 (file)
@@ -1369,7 +1369,8 @@ int main(int argc, const char **argv)
                { "header",            '\0', POPT_ARG_STRING, &opt_header_device,       0, N_("Device or file with separated LUKS header."), NULL },
                { "test-passphrase",   '\0', POPT_ARG_NONE, &opt_test_passphrase,       0, N_("Do not activate device, just check passphrase."), NULL },
                { "hidden",            '\0', POPT_ARG_NONE, &opt_hidden,                0, N_("Use hidden header (hidden TCRYPT device) ."), NULL },
-               { "type",              'M',  POPT_ARG_STRING, &opt_type,                0, N_("Type of device metadata: luks, plain, loopaes, tcrypt."), NULL },
+               { "type",               'M', POPT_ARG_STRING, &opt_type,                0, N_("Type of device metadata: luks, plain, loopaes, tcrypt."), NULL },
+               { "force-password",    '\0', POPT_ARG_NONE, &opt_force_password,         0, N_("Disable password quality check (if enabled)."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
index fa870b6..0eb9c55 100644 (file)
@@ -56,6 +56,7 @@
 extern int opt_debug;
 extern int opt_verbose;
 extern int opt_batch_mode;
+extern int opt_force_password;
 
 /* Common tools */
 void clogger(struct crypt_device *cd, int level, const char *file, int line,
@@ -74,6 +75,7 @@ extern volatile int quit;
 void set_int_block(int block);
 void set_int_handler(int block);
 void check_signal(int *r);
+int tools_signals_blocked(void);
 
 int tools_get_key(const char *prompt,
                  char **key, size_t *key_size,
diff --git a/src/utils_password.c b/src/utils_password.c
new file mode 100644 (file)
index 0000000..795ba59
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Password quality check wrapper
+ *
+ * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2012, Milan Broz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "cryptsetup.h"
+
+int opt_force_password = 0;
+
+#if ENABLE_PWQUALITY
+#include <pwquality.h>
+
+static int tools_check_pwquality(const char *password)
+{
+       int r;
+       void *auxerror;
+       pwquality_settings_t *pwq; 
+
+       log_dbg("Checking new password using default pwquality settings.");
+       pwq = pwquality_default_settings();
+       if (!pwq)
+               return -EINVAL;
+
+       r = pwquality_read_config(pwq, NULL, &auxerror);
+       if (r) {
+               log_err(_("Cannot check passsword quality: %s\n"),
+                       pwquality_strerror(NULL, 0, r, auxerror));
+               pwquality_free_settings(pwq);
+               return -EINVAL;
+       }
+
+       r = pwquality_check(pwq, password, NULL, NULL, &auxerror);
+       if (r < 0) {
+               log_err(_("Password quality check failed:\n %s\n"),
+                       pwquality_strerror(NULL, 0, r, auxerror));
+               r = -EPERM;
+       } else {
+               log_dbg("New password libpwquality score is %d.", r);
+               r = 0;
+       }
+
+       pwquality_free_settings(pwq);
+       return r;
+}
+#else /* ENABLE_PWQUALITY */
+static int tools_check_pwquality(const char *password)
+{
+       return 0;
+}
+#endif /* ENABLE_PWQUALITY */
+
+int tools_get_key(const char *prompt,
+                 char **key, size_t *key_size,
+                 size_t keyfile_offset, size_t keyfile_size_max,
+                 const char *key_file,
+                 int timeout, int verify, int pwquality,
+                 struct crypt_device *cd)
+{
+       int r, block;
+
+       block = tools_signals_blocked();
+       if (block)
+               set_int_block(0);
+
+       r = crypt_get_key(prompt, key, key_size, keyfile_offset,
+                         keyfile_size_max, key_file, timeout, verify, cd);
+       if (block && !quit)
+               set_int_block(1);
+
+       /* Check pwquality for password (not keyfile) */
+       if (pwquality && !opt_force_password && !key_file && !r)
+               r = tools_check_pwquality(*key);
+
+       return r;
+}
index 418f53e..6210536 100644 (file)
@@ -35,6 +35,11 @@ static void int_handler(int sig __attribute__((__unused__)))
        quit++;
 }
 
+int tools_signals_blocked(void)
+{
+       return signals_blocked;
+}
+
 void set_int_block(int block)
 {
        sigset_t signals_open;
@@ -67,28 +72,6 @@ void check_signal(int *r)
                *r = -EINTR;
 }
 
-/* crypt_get_key() with signal handler */
-int tools_get_key(const char *prompt,
-                 char **key, size_t *key_size,
-                 size_t keyfile_offset, size_t keyfile_size_max,
-                 const char *key_file,
-                 int timeout, int verify, int pwquality,
-                 struct crypt_device *cd)
-{
-       int r, block;
-
-       block = signals_blocked;
-       if (block)
-               set_int_block(0);
-
-       r = crypt_get_key(prompt, key, key_size, keyfile_offset,
-                         keyfile_size_max, key_file, timeout, verify, cd);
-       if (block && !quit)
-               set_int_block(1);
-
-       return r;
-}
-
 __attribute__((format(printf, 5, 6)))
 void clogger(struct crypt_device *cd, int level, const char *file, int line,
             const char *format, ...)
@@ -151,7 +134,7 @@ int yesDialog(const char *msg, void *usrptr __attribute__((unused)))
        size_t size = 0;
        int r = 1, block;
 
-       block = signals_blocked;
+       block = tools_signals_blocked();
        if (block)
                set_int_block(0);