File 0001-add-support-for-sha512.diff of Package pwdutils

From eeb5baaeceb5e04c9fa7fe3a4316ab4a3fd3b40c Mon Sep 17 00:00:00 2001
From: Ludwig Nussel <ludwig.nussel@suse.de>
Date: Thu, 14 Jul 2011 15:26:07 +0200
Subject: [PATCH] add support for sha512

* use implicit defaults in /etc/default/passwd
* make it work without xcrypt
---
 configure.in          |    2 +-
 etc/default/passwd    |   48 +++++++++++++++++++++++++--------
 lib/logindefs.c       |    2 +-
 lib/parse_crypt_arg.c |   41 +++++++++++++++++-----------
 lib/parse_crypt_arg.h |    5 +++-
 src/chpasswd.c        |   66 +++++++--------------------------------------
 src/gpasswd.c         |   70 ++++++++----------------------------------------
 7 files changed, 90 insertions(+), 144 deletions(-)

diff --git a/configure.in b/configure.in
index ea0bc27..e9e4cd8 100644
--- a/configure.in
+++ b/configure.in
@@ -192,7 +192,7 @@ dnl Save old LIBS variable and add crypt library
 BACKUP_LIBS=$LIBS
 LIBS="$LIBS $CRYPT_LIB"
 dnl Function check for blowfish crypt
-AC_CHECK_FUNCS(crypt crypt_r xcrypt_gensalt_r)
+AC_CHECK_FUNCS(crypt crypt_r xcrypt_gensalt_r crypt_gensalt_rn)
 dnl restore old LIBS variable
 LIBS=$BACKUP_LIBS
 
diff --git a/etc/default/passwd b/etc/default/passwd
index 87057ea..ec6f0d4 100644
--- a/etc/default/passwd
+++ b/etc/default/passwd
@@ -2,29 +2,53 @@
 # the passwd (1) command and other tools
 # creating or modifying passwords.
 
-# Define default crypt hash. This hash will be
-# used, if there is no hash for a special service
-# the user is stored in.
-# CRYPT={des,md5,sha256,sha512}
-CRYPT=md5
+# Define default crypt hash.
+# CRYPT={des,md5,blowfish,sha256,sha512}
+CRYPT=
 
 # Use another crypt hash for group passwords.
 # This is used by gpasswd, fallback is the CRYPT entry.
 # GROUP_CRYPT=des
 
 
+# We can override the default for a specific service
+# by appending the service name (FILES, YP, NISPLUS, LDAP)
+
+# for local files, use a more secure hash. We
+# don't need to be portable here:
+# CRYPT_FILES=sha512
+#
+# For NIS, we should always use DES:
+# CRYPT_YP=des
+
 # We can override the default for a special service
 # by appending the service name (FILES, YP, NISPLUS, LDAP)
 
 # for local files, use a more secure hash. We
 # don't need to be portable here:
-CRYPT_FILES=sha512
-# sometimes we need to specify special options for
-# a hash (variable is prepended by the name of the
-# crypt hash).
+# CRYPT_FILES=blowfish
+
+# sometimes we need to specify special options for a hash (variable
+# is prepended by the name of the crypt hash). In case of blowfish
+# and sha* this is the number of rounds
 # blowfish: 4-31
+# BLOWFISH_CRYPT_FILES=5
 # sha256/sha512: 1000-9999999
-#SHA512_CRYPT_FILES=1000
+# SHA512_CRYPT_FILES=1000
 
-# For NIS, we should always use DES:
-CRYPT_YP=des
+# In June 2011 it was discovered that the Linux crypt_blowfish
+# implementation contained a bug that made passwords with non-ASCII
+# characters easier to crack (CVE-2011-2483). Affected passwords are
+# also incompatible with the original, correct OpenBSD
+# implementation. Therefore the $2a hash identifier previously used
+# for blowfish now is ambiguous as it could mean the hash was
+# generated with the correct implementation on OpenBSD or the buggy
+# one on Linux. To avoid the ambiguity two new identifier were
+# introduced. $2x now explicitly identifies hashes that were
+# generated with the buggy algorithm while $2y is used for hashes
+# generated with the correct algorithm. New passwords are now
+# generated with the $2y identifier.
+#
+# Setting the following option to "yes" tells the sytem that $2a
+# hashes are to be treated as generated with the buggy algorithm.
+BLOWFISH_2a2x=
diff --git a/lib/logindefs.c b/lib/logindefs.c
index 42effde..d8826e1 100644
--- a/lib/logindefs.c
+++ b/lib/logindefs.c
@@ -88,7 +88,7 @@ search (const char *name)
   while (ptr != NULL)
     {
       if (strcasecmp (name, ptr->name) == 0)
-	return ptr->value;
+	return *ptr->value?ptr->value:NULL;
       ptr = ptr->next;
     }
 
diff --git a/lib/parse_crypt_arg.c b/lib/parse_crypt_arg.c
index 1f76ae6..eae7520 100644
--- a/lib/parse_crypt_arg.c
+++ b/lib/parse_crypt_arg.c
@@ -28,6 +28,10 @@
 #if defined(HAVE_XCRYPT_H)
 #include <xcrypt.h>
 #elif defined(HAVE_CRYPT_H)
+#if defined(HAVE_CRYPT_GENSALT_RN)
+#define _OW_SOURCE
+#define xcrypt_gensalt_r crypt_gensalt_rn
+#endif
 #include <crypt.h>
 #endif
 
@@ -38,7 +42,10 @@
 #define RANDOM_DEVICE "/dev/urandom"
 #endif
 
-#if defined(HAVE_XCRYPT_GENSALT_R)
+#if defined(HAVE_XCRYPT_GENSALT_R) || defined(HAVE_CRYPT_GENSALT_RN)
+
+const char* const prefixes[NUM_CRYPT_T] = { NULL, "", "$1$", NULL, "$2y$", "$5$", "$6$" };
+
 static int
 read_loop (int fd, char *buffer, int count)
 {
@@ -67,14 +74,9 @@ read_loop (int fd, char *buffer, int count)
 #endif
 
 char *
-#if defined(HAVE_XCRYPT_GENSALT_R)
 make_crypt_salt (const char *crypt_prefix, int crypt_rounds)
-#else
-make_crypt_salt (const char *crypt_prefix __attribute__ ((unused)),
-                 int crypt_rounds __attribute__ ((unused)))
-#endif
 {
-#if defined(HAVE_XCRYPT_GENSALT_R)
+#if defined(HAVE_XCRYPT_GENSALT_R) || defined(HAVE_CRYPT_GENSALT_RN)
 #define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
   int fd;
   char entropy[16];
@@ -131,21 +133,28 @@ make_crypt_salt (const char *crypt_prefix __attribute__ ((unused)),
 crypt_t
 parse_crypt_arg (const char *arg)
 {
+  if (!arg || !*arg)
+    goto out;
+
   if (strcasecmp (arg, "des") == 0)
     return DES;
   else if (strcasecmp (arg, "md5") == 0)
     return MD5;
+#if defined(HAVE_XCRYPT_GENSALT_R) || defined(HAVE_CRYPT_GENSALT_RN)
   else if (strcasecmp (arg, "blowfish") == 0 ||
            strcasecmp (arg, "bf") == 0)
-    {
-#if defined(HAVE_XCRYPT_GENSALT_R)
-      return BLOWFISH;
+    return BLOWFISH;
+  else if (strcasecmp (arg, "sha256") == 0)
+    return SHA256;
+  else if (strcasecmp (arg, "sha512") == 0)
+    return SHA512;
+
+  fprintf (stderr, _("No support for %s available, using SHA512.\n"), arg);
+out:
+  return SHA512;
 #else
-      fprintf (stderr, _("No support for blowfish compiled in, using MD5.\n"));
-      return MD5;
-#endif
-    }
-
-  fprintf (stderr, _("No support for %s available, using DES.\n"), optarg);
+  fprintf (stderr, _("No support for %s available, using DES.\n"), arg);
+out:
   return DES;
+#endif
 }
diff --git a/lib/parse_crypt_arg.h b/lib/parse_crypt_arg.h
index 61ed464..507f9d1 100644
--- a/lib/parse_crypt_arg.h
+++ b/lib/parse_crypt_arg.h
@@ -17,7 +17,10 @@
 #ifndef __PARSE_CRYPT_ARG_H__
 #define __PARSE_CRYPT_ARG_H__
 
-enum crypt_t {DES, MD5, BLOWFISH};
+enum crypt_t {NONE, DES, MD5, BIGCRYPT, BLOWFISH, SHA256, SHA512, NUM_CRYPT_T};
+
+extern const char* const prefixes[NUM_CRYPT_T];
+
 typedef enum crypt_t crypt_t;
 
 extern crypt_t parse_crypt_arg (const char *arg);
diff --git a/src/chpasswd.c b/src/chpasswd.c
index a116161..a00b80a 100644
--- a/src/chpasswd.c
+++ b/src/chpasswd.c
@@ -56,7 +56,7 @@
 static void
 print_usage (FILE *stream, const char *program)
 {
-  fprintf (stream, _("Usage: %s [-D binddn] [-P path] [-e] [-c des|md5|blowfish] [file]\n"),
+  fprintf (stream, _("Usage: %s [-D binddn] [-P path] [-e] [-c des|md5|blowfish|sha256|sha512] [file]\n"),
            program);
 }
 
@@ -72,7 +72,7 @@ print_help (const char *program)
 #endif
   fputs (_("  -P path        Search passwd and shadow file in \"path\"\n"),
          stdout);
-  fputs (_("  -c, --crypt    Password should be encrypted with DES, MD5 or blowfish\n"),
+  fputs (_("  -c, --crypt    Password should be encrypted with DES, MD5, blowfish, sha256 or sha512\n"),
 	 stdout);
   fputs (_("  -e, --encrypted The passwords are in encrypted form\n"),
 	 stdout);
@@ -107,7 +107,7 @@ main (int argc, char *argv[])
 
   open_sec_log (program);
 
-  use_crypt = parse_crypt_arg (getlogindefs_str ("CRYPT", "des"));
+  use_crypt = parse_crypt_arg (getlogindefs_str ("CRYPT", NULL));
 
   while (1)
     {
@@ -303,60 +303,16 @@ main (int argc, char *argv[])
 	  struct crypt_data output;
 	  memset (&output, 0, sizeof (output));
 
-	  switch (use_crypt)
+	  salt =  make_crypt_salt (prefixes[use_crypt], 0);
+	  if (salt != NULL)
+	    pw_data->newpassword = strdup (crypt_r (cp, salt, &output));
+	  else
 	    {
-	    case DES:
-	      /* If we don't support passwords longer 8 characters,
-		 truncate them */
-	      if (strlen (cp) > 8)
-		cp[8] = '\0';
-	      salt =  make_crypt_salt ("", 0);
-	      if (salt != NULL)
-	        pw_data->newpassword = strdup (crypt_r (cp, salt, &output));
-	      else
-		{
-		  fprintf (stderr, _("Cannot create salt for standard crypt"));
-		  ++errors;
-		  continue;
-		}
-	      free (salt);
-	      break;
-
-	    case MD5:
-	      /* MD5 has a limit of 127 characters */
-	      if (strlen (cp) > 127)
-		cp[127] = '\0';
-	      salt = make_crypt_salt ("$1$", 0);
-	      if (salt != NULL)
-		pw_data->newpassword = strdup (crypt_r (cp, salt, &output));
-	      else
-		{
-		  fprintf (stderr, _("Cannot create salt for MD5 crypt"));
-		  ++errors;
-		  continue;
-		}
-	      free (salt);
-	      break;
-	    case BLOWFISH:
-#if defined(HAVE_XCRYPT_GENSALT_R)
-	      /* blowfish has a limit of 72 characters */
-	      if (use_crypt == BLOWFISH && strlen (cp) > 72)
-		cp[72] = '\0';
-	      salt = make_crypt_salt ("$2a$", 0 /* XXX crypt_rounds */);
-	      if (salt != NULL)
-		pw_data->newpassword = strdup (crypt_r (cp, salt, &output));
-	      else
-		{
-		  fprintf (stderr, _("Cannot create salt for blowfish crypt"));
-		  ++errors;
-		  continue;
-		}
-	      free (salt);
-#endif
-	      break;
-	    default:
-	      abort();
+	      fprintf (stderr, _("Cannot create salt: %m"));
+	      ++errors;
+	      continue;
 	    }
+	  free (salt);
 	}
       time (&now);
       pw_data->spn.sp_lstchg = (long int)now / (24L*3600L);
diff --git a/src/gpasswd.c b/src/gpasswd.c
index 81ea94a..47ffb04 100644
--- a/src/gpasswd.c
+++ b/src/gpasswd.c
@@ -133,7 +133,7 @@ main (int argc, char **argv)
 
   crypt_str = getlogindefs_str ("GROUP_CRYPT", NULL);
   if (crypt_str == NULL)
-    crypt_str = getlogindefs_str ("CRYPT", "des");
+    crypt_str = getlogindefs_str ("CRYPT", NULL);
   use_crypt = parse_crypt_arg (crypt_str);
 
   /* Parse program arguments */
@@ -408,63 +408,17 @@ main (int argc, char **argv)
           struct crypt_data output;
           memset (&output, 0, sizeof (output));
 
-
-          switch (use_crypt)
-            {
-            case DES:
-              /* If we don't support passwords longer 8 characters,
-                 truncate them */
-              if (strlen (p1) > 8)
-                p1[8] = '\0';
-              salt =  make_crypt_salt ("", 0);
-              if (salt != NULL)
-                gr_data->newpassword = strdup (crypt_r (p1, salt, &output));
-              else
-                {
-		  free (p1);
-                  fprintf (stderr, _("Cannot create salt for standard crypt"));
-		  goto abort_change;
-                }
-              free (salt);
-              break;
-            case BLOWFISH:
-#if defined(HAVE_XCRYPT_GENSALT_R)
-	      /* blowfish has a limit of 72 characters */
-	      if (use_crypt == BLOWFISH && strlen (p1) > 72)
-		p1[72] = '\0';
-              salt = make_crypt_salt ("$2a$", 0 /* XXX crypt_rounds */);
-              if (salt != NULL)
-                gr_data->newpassword = strdup (crypt_r (p1, salt, &output));
-              else
-                {
-		  free (p1);
-                  fprintf (stderr, _("Cannot create salt for blowfish crypt"));
-		  goto abort_change;
-                }
-              free (salt);
-              break;
-#else
-	      fprintf (stderr,
-		       _("No support for blowfish compiled in. Using MD5\n"));
-#endif
-            case MD5:
-              /* MD5 has a limit of 127 characters */
-              if (strlen (p1) > 127)
-                p1[127] = '\0';
-              salt = make_crypt_salt ("$1$", 0);
-              if (salt != NULL)
-                gr_data->newpassword = strdup (crypt_r (p1, salt, &output));
-              else
-                {
-		  free (p1);
-                  fprintf (stderr, _("Cannot create salt for MD5 crypt"));
-		  goto abort_change;
-                }
-              free (salt);
-              break;
-            default:
-              abort();
-            }
+	  puts(prefixes[use_crypt]);
+	  salt =  make_crypt_salt (prefixes[use_crypt], 0);
+	  if (salt != NULL)
+	    gr_data->newpassword = strdup (crypt_r (p1, salt, &output));
+	  else
+	    {
+	      fprintf (stderr, _("Cannot create salt: %m"));
+	      free (p1);
+	      goto abort_change;
+	    }
+	  free (salt);
 	  free (p1);
         }
     }
-- 
1.7.3.4

openSUSE Build Service is sponsored by