Sophie

Sophie

distrib > Fedora > 13 > i386 > media > updates-src > by-pkgid > d2cf730f304d51a27160664101352128 > files > 1

yp-tools-2.10-3.fc13.src.rpm

diff -up yp-tools-2.10/src/yppasswd.c.passwords yp-tools-2.10/src/yppasswd.c
--- yp-tools-2.10/src/yppasswd.c.passwords	2004-06-21 14:12:24.000000000 +0200
+++ yp-tools-2.10/src/yppasswd.c	2010-04-16 11:32:58.931877499 +0200
@@ -50,6 +50,8 @@
 #include <libintl.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
 #include <rpcsvc/yp_prot.h>
 #include <rpcsvc/ypclnt.h>
 #ifdef HAVE_RPC_CLNT_SOC_H
@@ -368,6 +370,49 @@ getfield (char *gecos, char *field, int 
   return sp;
 }
 
+#define DES 0
+#define MD5 1
+#define SHA_256 5
+#define SHA_512 6
+
+static int
+get_hash_id (const char *passwd)
+{
+  int hash_id = DES;
+  if (strncmp(passwd, "$1$", 3) == 0)
+    hash_id = MD5;
+  else if (strncmp(passwd, "$5$", 3) == 0)
+    hash_id = SHA_256;
+  else if (strncmp(passwd, "$6$", 3) == 0)
+    hash_id = SHA_512;
+  return hash_id;
+}
+
+static int
+get_passwd_len (const char *passwd)
+{
+  static const char *allowed_chars = 
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+  int passwdlen = strlen (passwd);
+  int hash_id = get_hash_id (passwd);
+
+  /* Some systems (HPU/X) store the password aging info after
+   * the password (with a comma to separate it). To support
+   * this we cut the password after the first invalid char
+   * after the normal 13 ones - in the case of MD5 and DES.
+   * We can't cut at the first invalid char, since MD5 
+   * uses $ in the first char. In case of SHA-2 we are looking
+   * for first invalid char after the 38 ones.
+   */
+  if (passwdlen > 13 && (hash_id == DES || hash_id == MD5))
+      passwdlen = 13 + strspn (passwd + 13, allowed_chars);
+
+  if (passwdlen > 38 && (hash_id == SHA_256 || hash_id == SHA_512))
+      passwdlen = 38 + strspn (passwd + 38, allowed_chars);
+
+  return passwdlen;
+}
+
 #if ! defined(USE_CRACKLIB) || defined(USE_CRACKLIB_STRICT)
 /* this function will verify the user's password
  * for some silly things.  If we're using cracklib, then
@@ -379,6 +424,7 @@ verifypassword (struct passwd *pwd, char
 {
   char *p, *q;
   int ucase, lcase, other, r;
+  int passwdlen;
 
   if ((strlen (pwdstr) < 6) && uid)
     {
@@ -401,8 +447,9 @@ verifypassword (struct passwd *pwd, char
       return 0;
     }
 
+  passwdlen = get_passwd_len (pwd->pw_passwd);
   if (pwd->pw_passwd[0]
-      && !strncmp (pwd->pw_passwd, crypt (pwdstr, pwd->pw_passwd), 13)
+      && !strncmp (pwd->pw_passwd, crypt (pwdstr, pwd->pw_passwd), passwdlen)
       && uid)
     {
       fputs (_("You cannot reuse the old password.\n"), stderr);
@@ -436,11 +483,43 @@ verifypassword (struct passwd *pwd, char
 
 #endif
 
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
+
+static void
+create_random_salt (char *salt, int num_chars)
+{
+  int fd;
+  unsigned char c;
+  int i;
+  int res;
+
+  fd = open ("/dev/urandom", O_RDONLY);
+
+  for (i = 0; i < num_chars; i++)
+    {
+      res = 0;
+      if (fd != 0)
+        res = read (fd, &c, 1);
+
+      if (res != 1)
+        c = random ();
+
+      salt[i] = bin_to_ascii (c & 0x3f);
+    }
+
+  salt[num_chars] = 0;
+
+  if (fd != 0)
+    close (fd);
+}
+
 int
 main (int argc, char **argv)
 {
   char *s, *progname, *domainname = NULL, *user = NULL, *master = NULL;
   int f_flag = 0, l_flag = 0, p_flag = 0, error, status;
+  int hash_id = DES;
+  char rounds[11] = "\0"; /* max length is '999999999$' */
   struct yppasswd yppwd;
   struct passwd *pwd;
   CLIENT *clnt;
@@ -451,6 +530,8 @@ main (int argc, char **argv)
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
+  srandom (time (NULL));
+
   if ((s = strrchr (argv[0], '/')) != NULL)
     progname = s + 1;
   else
@@ -642,27 +723,22 @@ main (int argc, char **argv)
       cp = stpcpy (hashpass, "##");
       strcpy (cp, pwd->pw_name);
 
+      hash_id = get_hash_id (pwd->pw_passwd);
+
+      /* Preserve 'rounds=<N>$' (if present) in case of SHA-2 */
+      if (hash_id == SHA_256 || hash_id == SHA_512)
+	{
+	  if (strncmp (pwd->pw_passwd + 3, "rounds=", 7) == 0)
+	    strncpy (rounds, pwd->pw_passwd + 10, strcspn (pwd->pw_passwd + 10, "$") + 1);
+	}
+
       /* We can't check the password with shadow passwords enabled. We
        * leave the checking to yppasswdd */
       if (uid != 0 && strcmp (pwd->pw_passwd, "x") != 0 &&
 	  strcmp (pwd->pw_passwd, hashpass ) != 0)
 	{
-	  int passwdlen;
-	  char *sane_passwd;
-	  passwdlen = strlen (pwd->pw_passwd);
-	  /* Some systems (HPU/X) store the password aging info after
-	   * the password (with a comma to separate it). To support
-	   * this we cut the password after the first invalid char
-	   * after the normal 13 ones. We can't cut at the first
-	   * invalid char, since MD5 uses $ in the first char.
-	   */
-	  if (passwdlen > 13)
-	    passwdlen = 13 + strspn(pwd->pw_passwd + 13,
-				    "abcdefghijklmnopqrstuvwxyz"
-				    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-				    "0123456789./");
-
-	  sane_passwd = alloca (passwdlen + 1);
+	  int passwdlen = get_passwd_len (pwd->pw_passwd);
+	  char *sane_passwd = alloca (passwdlen + 1);
 	  strncpy (sane_passwd, pwd->pw_passwd, passwdlen);
 	  sane_passwd[passwdlen] = 0;
 	  if (strcmp (crypt (s, sane_passwd), sane_passwd))
@@ -676,13 +752,11 @@ main (int argc, char **argv)
 
   if (p_flag)
     {
-#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
 #ifdef USE_CRACKLIB
       char *error_msg;
 #endif /* USE_CRACKLIB */
-      char *buf, salt[2], *p = NULL;
+      char *buf, salt[37], *p = NULL;
       int tries = 0;
-      time_t tm;
 
       buf = (char *) malloc (129);
 
@@ -733,9 +807,34 @@ main (int argc, char **argv)
 	    }
 	}
 
-      time (&tm);
-      salt[0] = bin_to_ascii (tm & 0x3f);
-      salt[1] = bin_to_ascii ((tm >> 6) & 0x3f);
+      switch (hash_id)
+	{
+	case DES:
+	  create_random_salt (salt, 2);
+	  break;
+
+	case MD5:
+	  /* The user already had a MD5 password, so it's safe to
+	   * use a MD5 password again */
+	  strcpy (salt, "$1$");
+	  create_random_salt (salt + 3, 8);
+	  break;
+
+	case SHA_256:
+	case SHA_512:
+	  /* The user already had a SHA-2 password, so it's safe to
+	   * use a SHA-2 password again */
+	  snprintf (salt, 4, "$%d$", hash_id);
+	  if (strlen (rounds) != 0)
+	    {
+	      strcpy (salt + 3, "rounds=");
+	      strcpy (salt + 3 + 7, rounds);
+	      create_random_salt (salt + 3 + 7 + strlen (rounds), 16);
+	    }
+	  else
+	    create_random_salt (salt + 3, 16);
+	  break;
+	}
 
       yppwd.newpw.pw_passwd = strdup (crypt (buf, salt));
     }