From f14be6bcf8bd6e097fd2e617704268681c23c142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Kl=C3=AD=C4=8D?= Date: Mon, 19 Apr 2010 17:25:46 +0000 Subject: [PATCH] Add MD5/SHA support to verifypassword() --- yp-tools-2.10-passwords.patch | 226 ++++++++++++++++++++++++++++++++++ yp-tools-2.7-md5.patch | 109 ---------------- yp-tools-2.9-sha-2.patch | 130 ------------------- yp-tools.spec | 13 +- 4 files changed, 234 insertions(+), 244 deletions(-) create mode 100644 yp-tools-2.10-passwords.patch delete mode 100644 yp-tools-2.7-md5.patch delete mode 100644 yp-tools-2.9-sha-2.patch diff --git a/yp-tools-2.10-passwords.patch b/yp-tools-2.10-passwords.patch new file mode 100644 index 0000000..5e95077 --- /dev/null +++ b/yp-tools-2.10-passwords.patch @@ -0,0 +1,226 @@ +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 + #include + #include ++#include ++#include + #include + #include + #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=$' (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)); + } diff --git a/yp-tools-2.7-md5.patch b/yp-tools-2.7-md5.patch deleted file mode 100644 index df823f1..0000000 --- a/yp-tools-2.7-md5.patch +++ /dev/null @@ -1,109 +0,0 @@ ---- yp-tools-2.8/src/yppasswd.c.orig 2002-12-05 08:49:20.000000000 -0500 -+++ yp-tools-2.8/src/yppasswd.c 2003-04-23 14:58:13.000000000 -0400 -@@ -49,6 +49,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -436,11 +438,44 @@ 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 has_md5_passwd = 0; - struct yppasswd yppwd; - struct passwd *pwd; - CLIENT *clnt; -@@ -451,6 +486,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,6 +679,9 @@ main (int argc, char **argv) - cp = stpcpy (hashpass, "##"); - strcpy (cp, pwd->pw_name); - -+ if (strncmp(pwd->pw_passwd, "$1$", 3) == 0) -+ has_md5_passwd = 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 && -@@ -676,13 +716,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[12], *p = NULL; - int tries = 0; -- time_t tm; - - buf = (char *) malloc (129); - -@@ -733,9 +771,15 @@ main (int argc, char **argv) - } - } - -- time (&tm); -- salt[0] = bin_to_ascii (tm & 0x3f); -- salt[1] = bin_to_ascii ((tm >> 6) & 0x3f); -+ if (!has_md5_passwd) -+ create_random_salt (salt, 2); -+ else -+ { -+ /* 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); -+ } - - yppwd.newpw.pw_passwd = strdup (crypt (buf, salt)); - } diff --git a/yp-tools-2.9-sha-2.patch b/yp-tools-2.9-sha-2.patch deleted file mode 100644 index 1b81eed..0000000 --- a/yp-tools-2.9-sha-2.patch +++ /dev/null @@ -1,130 +0,0 @@ -diff -up yp-tools-2.9/src/yppasswd.c_old yp-tools-2.9/src/yppasswd.c ---- yp-tools-2.9/src/yppasswd.c_old 2009-03-03 15:23:49.000000000 +0100 -+++ yp-tools-2.9/src/yppasswd.c 2009-03-04 12:39:34.000000000 +0100 -@@ -475,7 +475,8 @@ 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 has_md5_passwd = 0; -+ int hash_id = DES; -+ char rounds[11] = "\0"; /* max length is '999999999$' */ - struct yppasswd yppwd; - struct passwd *pwd; - CLIENT *clnt; -@@ -680,7 +681,18 @@ main (int argc, char **argv) - strcpy (cp, pwd->pw_name); - - if (strncmp(pwd->pw_passwd, "$1$", 3) == 0) -- has_md5_passwd = 1; -+ hash_id = MD5; -+ -+ if (strncmp(pwd->pw_passwd, "$5$", 3) == 0) -+ hash_id = SHA_256; -+ -+ if (strncmp(pwd->pw_passwd, "$6$", 3) == 0) -+ hash_id = SHA_512; -+ -+ /* Preserve 'rounds=$' (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 */ -@@ -693,15 +705,23 @@ main (int argc, char **argv) - /* 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. -+ * after the normal 13 ones - in 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) -- passwdlen = 13 + strspn(pwd->pw_passwd + 13, -+ if (passwdlen > 13 && (hash_id == DES || hash_id == MD5)) -+ passwdlen = 13 + strspn(pwd->pw_passwd + 13, - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789./"); - -+ if (passwdlen > 38 && (hash_id == SHA_256 || hash_id == SHA_512)) -+ passwdlen = 38 + strspn(pwd->pw_passwd + 38, -+ "abcdefghijklmnopqrstuvwxyz" -+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ "0123456789./"); -+ - sane_passwd = alloca (passwdlen + 1); - strncpy (sane_passwd, pwd->pw_passwd, passwdlen); - sane_passwd[passwdlen] = 0; -@@ -719,7 +739,7 @@ main (int argc, char **argv) - #ifdef USE_CRACKLIB - char *error_msg; - #endif /* USE_CRACKLIB */ -- char *buf, salt[12], *p = NULL; -+ char *buf, salt[37], *p = NULL; - int tries = 0; - - buf = (char *) malloc (129); -@@ -771,15 +791,37 @@ main (int argc, char **argv) - } - } - -- if (!has_md5_passwd) -- create_random_salt (salt, 2); -- else -- { -- /* 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); -- } -+ 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; -+ default: -+ break; -+ } - - yppwd.newpw.pw_passwd = strdup (crypt (buf, salt)); - } -diff -up yp-tools-2.9/src/yppasswd.h_old yp-tools-2.9/src/yppasswd.h ---- yp-tools-2.9/src/yppasswd.h_old 2009-03-04 10:49:41.000000000 +0100 -+++ yp-tools-2.9/src/yppasswd.h 2009-03-04 11:16:41.000000000 +0100 -@@ -46,4 +46,9 @@ typedef struct yppasswd yppasswd; - extern bool_t xdr_xpasswd (XDR *, xpasswd*); - extern bool_t xdr_yppasswd (XDR *, yppasswd*); - -+#define DES 0 -+#define MD5 1 -+#define SHA_256 5 -+#define SHA_512 6 -+ - #endif /* !__YPPASSWD_H__ */ diff --git a/yp-tools.spec b/yp-tools.spec index 7ac0974..820075a 100644 --- a/yp-tools.spec +++ b/yp-tools.spec @@ -1,13 +1,12 @@ Summary: NIS (or YP) client programs. Name: yp-tools Version: 2.9 -Release: 8%{?dist} +Release: 9%{?dist} License: GPLv2 Group: System Environment/Base Source: ftp://ftp.kernel.org/pub/linux/utils/net/NIS/yp-tools-%{version}.tar.bz2 Url: http://www.linux-nis.org/nis/yp-tools/index.html -Patch1: yp-tools-2.7-md5.patch -Patch2: yp-tools-2.9-sha-2.patch +Patch1: yp-tools-2.10-passwords.patch Obsoletes: yppasswd, yp-clients Requires: ypbind Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -34,8 +33,7 @@ you'll need to install the ypserv package on one machine on the network. %prep %setup -q -%patch1 -p1 -b .md5 -%patch2 -p1 -b .sha-2 +%patch1 -p1 -b .passwords %build %configure --disable-domainname @@ -61,6 +59,11 @@ rm -rf $RPM_BUILD_ROOT %dir /var/yp %changelog +* Thu Apr 15 2010 Karel Klic - 2.9-9 +- Added a new patch -passwords, which merges -md5 and -sha-2 patches + together, and adds proper MD5/SHA support to verifypassword() + #514061 + * Mon Aug 10 2009 Ville Skyttä - 2.9-8 - Convert specfile to UTF-8.