diff --git a/SOURCES/shadow-4.1.5.1-goodname.patch b/SOURCES/shadow-4.1.5.1-goodname.patch
index 49cba21..82b7839 100644
--- a/SOURCES/shadow-4.1.5.1-goodname.patch
+++ b/SOURCES/shadow-4.1.5.1-goodname.patch
@@ -1,7 +1,7 @@
 diff -up shadow-4.1.5.1/libmisc/chkname.c.goodname shadow-4.1.5.1/libmisc/chkname.c
 --- shadow-4.1.5.1/libmisc/chkname.c.goodname	2009-07-13 00:24:45.000000000 +0200
-+++ shadow-4.1.5.1/libmisc/chkname.c	2012-09-19 18:43:53.492160653 +0200
-@@ -49,20 +49,28 @@
++++ shadow-4.1.5.1/libmisc/chkname.c	2018-04-24 16:32:40.970529916 +0200
+@@ -49,25 +49,44 @@
  static bool is_valid_name (const char *name)
  {
  	/*
@@ -14,32 +14,48 @@ diff -up shadow-4.1.5.1/libmisc/chkname.c.goodname shadow-4.1.5.1/libmisc/chknam
 +         *
 +         * as a non-POSIX, extension, allow "$" as the last char for
 +         * sake of Samba 3.x "add machine script"
++         *
++         * Also do not allow fully numeric names or just "." or "..".
 +         */
-+	if ( ('\0' == *name) ||
-+             !((*name >= 'a' && *name <= 'z') ||
-+               (*name >= 'A' && *name <= 'Z') ||
-+               (*name >= '0' && *name <= '9') ||
-+               (*name == '_') || (*name == '.') 
-+	      )) {
++	int numeric;
++
++	if ('\0' == *name ||
++	    ('.' == *name && (('.' == name[1] && '\0' == name[2]) ||
++			      '\0' == name[1])) ||
++	    !((*name >= 'a' && *name <= 'z') ||
++	      (*name >= 'A' && *name <= 'Z') ||
++	      (*name >= '0' && *name <= '9') ||
++	      *name == '_' ||
++	      *name == '.')) {
  		return false;
  	}
  
++	numeric = isdigit(*name);
++
  	while ('\0' != *++name) {
 -		if (!(( ('a' <= *name) && ('z' >= *name) ) ||
 -		      ( ('0' <= *name) && ('9' >= *name) ) ||
 -		      ('_' == *name) ||
 -		      ('-' == *name) ||
 -		      ( ('$' == *name) && ('\0' == *(name + 1)) )
--		     )) {
-+                if (!(  (*name >= 'a' && *name <= 'z') ||
-+                        (*name >= 'A' && *name <= 'Z') ||
-+                        (*name >= '0' && *name <= '9') ||
-+                        (*name == '_') || (*name == '.') || (*name == '-') ||
-+                        (*name == '$' && *(name + 1) == '\0') 
-+                     )) {
++		if (!((*name >= 'a' && *name <= 'z') ||
++		      (*name >= 'A' && *name <= 'Z') ||
++		      (*name >= '0' && *name <= '9') ||
++		      *name == '_' ||
++		      *name == '.' ||
++		      *name == '-' ||
++		      (*name == '$' && name[1] == '\0')
+ 		     )) {
  			return false;
  		}
++		numeric &= isdigit(*name);
  	}
+ 
+-	return true;
++	return !numeric;
+ }
+ 
+ bool is_valid_user_name (const char *name)
 diff -up shadow-4.1.5.1/man/groupadd.8.xml.goodname shadow-4.1.5.1/man/groupadd.8.xml
 --- shadow-4.1.5.1/man/groupadd.8.xml.goodname	2012-05-25 13:45:27.000000000 +0200
 +++ shadow-4.1.5.1/man/groupadd.8.xml	2012-09-19 18:43:53.492160653 +0200
diff --git a/SOURCES/shadow-4.1.5.1-ingroup.patch b/SOURCES/shadow-4.1.5.1-ingroup.patch
index e440431..1844fbc 100644
--- a/SOURCES/shadow-4.1.5.1-ingroup.patch
+++ b/SOURCES/shadow-4.1.5.1-ingroup.patch
@@ -1,6 +1,6 @@
 diff -up shadow-4.1.5.1/src/newgrp.c.ingroup shadow-4.1.5.1/src/newgrp.c
---- shadow-4.1.5.1/src/newgrp.c.ingroup	2014-08-29 13:31:38.000000000 +0200
-+++ shadow-4.1.5.1/src/newgrp.c	2014-08-29 14:04:57.183849650 +0200
+--- shadow-4.1.5.1/src/newgrp.c.ingroup	2018-04-24 16:55:24.546677529 +0200
++++ shadow-4.1.5.1/src/newgrp.c	2018-04-24 16:58:17.113445562 +0200
 @@ -83,15 +83,29 @@ static void usage (void)
  	}
  }
@@ -52,12 +52,70 @@ diff -up shadow-4.1.5.1/src/newgrp.c.ingroup shadow-4.1.5.1/src/newgrp.c
  	}
  	endgrent ();
  	return gr;
-@@ -616,7 +624,7 @@ int main (int argc, char **argv)
+@@ -373,6 +381,7 @@ int main (int argc, char **argv)
+ {
+ 	bool initflag = false;
+ 	int i;
++	bool is_member = false;
+ 	bool cflag = false;
+ 	int err = 0;
+ 	gid_t gid;
+@@ -611,22 +620,36 @@ int main (int argc, char **argv)
+ 		goto failure;
+ 	}
+ 
++#ifdef HAVE_SETGROUPS
++	/* when using pam_group, she will not be listed in the groups
++	 * database. However getgroups() will return the group. So
++	 * if she is listed there already it is ok to grant membership.
++	 */
++	for (i = 0; i < ngroups; i++) {
++		if (grp->gr_gid == grouplist[i]) {
++			is_member = true;
++			break;
++		}
++	}
++#endif                          /* HAVE_SETGROUPS */
+ 	/*
+ 	 * For splitted groups (due to limitations of NIS), check all 
  	 * groups of the same GID like the requested group for
  	 * membership of the current user.
  	 */
 -	grp = find_matching_group (name, grp->gr_gid);
-+	grp = find_matching_group (name, grp);
- 	if (NULL == grp) {
- 		/*
- 		 * No matching group found. As we already know that
+-	if (NULL == grp) {
+-		/*
+-		 * No matching group found. As we already know that
+-		 * the group exists, this happens only in the case
+-		 * of a requested group where the user is not member.
+-		 *
+-		 * Re-read the group entry for further processing.
+-		 */
+-		grp = xgetgrnam (group);
+-		assert (NULL != grp);
++	if (!is_member) {
++		grp = find_matching_group (name, grp);
++		if (NULL == grp) {
++			/*
++			 * No matching group found. As we already know that
++			 * the group exists, this happens only in the case
++			 * of a requested group where the user is not member.
++			 *
++			 * Re-read the group entry for further processing.
++			 */
++			grp = xgetgrnam (group);
++			assert (NULL != grp);
++		}
+ 	}
+ #ifdef SHADOWGRP
+ 	sgrp = getsgnam (group);
+@@ -639,7 +662,9 @@ int main (int argc, char **argv)
+ 	/*
+ 	 * Check if the user is allowed to access this group.
+ 	 */
+-	check_perms (grp, pwd, group);
++	if (!is_member) {
++		check_perms (grp, pwd, group);
++	}
+ 
+ 	/*
+ 	 * all successful validations pass through this point. The group id
diff --git a/SOURCES/shadow-4.1.5.1-long-entry.patch b/SOURCES/shadow-4.1.5.1-long-entry.patch
new file mode 100644
index 0000000..eaf9689
--- /dev/null
+++ b/SOURCES/shadow-4.1.5.1-long-entry.patch
@@ -0,0 +1,84 @@
+diff -up shadow-4.1.5.1/lib/defines.h.long-entry shadow-4.1.5.1/lib/defines.h
+--- shadow-4.1.5.1/lib/defines.h.long-entry	2011-09-18 22:44:10.000000000 +0200
++++ shadow-4.1.5.1/lib/defines.h	2018-04-24 16:34:31.261417493 +0200
+@@ -382,4 +382,7 @@ extern char *strerror ();
+ # endif
+ #endif
+ 
++/* Maximum length of passwd entry */
++#define PASSWD_ENTRY_MAX_LENGTH 32768
++
+ #endif				/* _DEFINES_H_ */
+diff -up shadow-4.1.5.1/lib/pwio.c.long-entry shadow-4.1.5.1/lib/pwio.c
+--- shadow-4.1.5.1/lib/pwio.c.long-entry	2011-02-16 21:32:24.000000000 +0100
++++ shadow-4.1.5.1/lib/pwio.c	2018-04-24 16:34:31.263417454 +0200
+@@ -79,7 +79,10 @@ static int passwd_put (const void *ent,
+ 	    || (pw->pw_gid == (gid_t)-1)
+ 	    || (valid_field (pw->pw_gecos, ":\n") == -1)
+ 	    || (valid_field (pw->pw_dir, ":\n") == -1)
+-	    || (valid_field (pw->pw_shell, ":\n") == -1)) {
++	    || (valid_field (pw->pw_shell, ":\n") == -1)
++	    || (strlen (pw->pw_name) + strlen (pw->pw_passwd) +
++	        strlen (pw->pw_gecos) + strlen (pw->pw_dir) +
++	        strlen (pw->pw_shell) + 100 > PASSWD_ENTRY_MAX_LENGTH)) {
+ 		return -1;
+ 	}
+ 
+diff -up shadow-4.1.5.1/lib/sgetpwent.c.long-entry shadow-4.1.5.1/lib/sgetpwent.c
+--- shadow-4.1.5.1/lib/sgetpwent.c.long-entry	2009-04-06 06:28:53.000000000 +0200
++++ shadow-4.1.5.1/lib/sgetpwent.c	2018-04-24 16:34:31.263417454 +0200
+@@ -57,7 +57,7 @@
+ struct passwd *sgetpwent (const char *buf)
+ {
+ 	static struct passwd pwent;
+-	static char pwdbuf[1024];
++	static char pwdbuf[PASSWD_ENTRY_MAX_LENGTH];
+ 	register int i;
+ 	register char *cp;
+ 	char *fields[NFIELDS];
+@@ -67,8 +67,10 @@ struct passwd *sgetpwent (const char *bu
+ 	 * the password structure remain valid.
+ 	 */
+ 
+-	if (strlen (buf) >= sizeof pwdbuf)
++	if (strlen (buf) >= sizeof pwdbuf) {
++		fprintf (stderr, "Too long passwd entry encountered, file corruption?\n");
+ 		return 0;	/* fail if too long */
++	}
+ 	strcpy (pwdbuf, buf);
+ 
+ 	/*
+diff -up shadow-4.1.5.1/lib/sgetspent.c.long-entry shadow-4.1.5.1/lib/sgetspent.c
+--- shadow-4.1.5.1/lib/sgetspent.c.long-entry	2009-04-12 04:46:43.000000000 +0200
++++ shadow-4.1.5.1/lib/sgetspent.c	2018-04-24 16:34:31.264417435 +0200
+@@ -48,7 +48,7 @@
+  */
+ struct spwd *sgetspent (const char *string)
+ {
+-	static char spwbuf[1024];
++	static char spwbuf[PASSWD_ENTRY_MAX_LENGTH];
+ 	static struct spwd spwd;
+ 	char *fields[FIELDS];
+ 	char *cp;
+@@ -61,6 +61,7 @@ struct spwd *sgetspent (const char *stri
+ 	 */
+ 
+ 	if (strlen (string) >= sizeof spwbuf) {
++		fprintf (stderr, "Too long shadow entry encountered, file corruption?\n");
+ 		return 0;	/* fail if too long */
+ 	}
+ 	strcpy (spwbuf, string);
+diff -up shadow-4.1.5.1/lib/shadowio.c.long-entry shadow-4.1.5.1/lib/shadowio.c
+--- shadow-4.1.5.1/lib/shadowio.c.long-entry	2011-02-16 21:32:24.000000000 +0100
++++ shadow-4.1.5.1/lib/shadowio.c	2018-04-24 16:34:31.265417416 +0200
+@@ -78,7 +78,9 @@ static int shadow_put (const void *ent,
+ 
+ 	if (   (NULL == sp)
+ 	    || (valid_field (sp->sp_namp, ":\n") == -1)
+-	    || (valid_field (sp->sp_pwdp, ":\n") == -1)) {
++	    || (valid_field (sp->sp_pwdp, ":\n") == -1)
++	    || (strlen (sp->sp_namp) + strlen (sp->sp_pwdp) +
++	        1000 > PASSWD_ENTRY_MAX_LENGTH)) {
+ 		return -1;
+ 	}
+ 
diff --git a/SOURCES/shadow-4.1.5.1-manfix.patch b/SOURCES/shadow-4.1.5.1-manfix.patch
index 29623ab..18dc342 100644
--- a/SOURCES/shadow-4.1.5.1-manfix.patch
+++ b/SOURCES/shadow-4.1.5.1-manfix.patch
@@ -1,3 +1,30 @@
+diff -up shadow-4.1.5.1/man/chage.1.xml.manfix shadow-4.1.5.1/man/chage.1.xml
+--- shadow-4.1.5.1/man/chage.1.xml.manfix	2012-05-25 13:45:27.000000000 +0200
++++ shadow-4.1.5.1/man/chage.1.xml	2018-04-24 16:43:48.545743715 +0200
+@@ -102,6 +102,9 @@
+ 	    Set the number of days since January 1st, 1970 when the password
+ 	    was last changed. The date may also be expressed in the format
+ 	    YYYY-MM-DD (or the format more commonly used in your area).
++	    If the <replaceable>LAST_DAY</replaceable> is set to
++	    <emphasis>0</emphasis> the user is forced to change his password
++	    on the next log on.
+ 	  </para>
+ 	</listitem>
+       </varlistentry>
+@@ -123,6 +126,13 @@
+ 	    <replaceable>EXPIRE_DATE</replaceable> will remove an account
+ 	    expiration date.
+ 	  </para>
++	  <para>
++	    For example the following command can be used
++	    to set an account to expire in 180 days:
++	  </para>
++	  <programlisting>
++	    chage -E $(date -d +180days +%Y-%m-%d)
++	  </programlisting>
+ 	</listitem>
+       </varlistentry>
+       <varlistentry>
 diff -up shadow-4.1.5.1/man/groupmems.8.xml.manfix shadow-4.1.5.1/man/groupmems.8.xml
 --- shadow-4.1.5.1/man/groupmems.8.xml.manfix	2012-05-25 13:45:28.000000000 +0200
 +++ shadow-4.1.5.1/man/groupmems.8.xml	2015-12-18 12:27:08.466909647 +0100
@@ -15,19 +42,6 @@ diff -up shadow-4.1.5.1/man/groupmems.8.xml.manfix shadow-4.1.5.1/man/groupmems.
    </refsect1>
  
    <refsect1 id='configuration'>
-diff -up shadow-4.1.5.1/man/chage.1.xml.manfix shadow-4.1.5.1/man/chage.1.xml
---- shadow-4.1.5.1/man/chage.1.xml.manfix	2012-05-25 13:45:27.000000000 +0200
-+++ shadow-4.1.5.1/man/chage.1.xml	2014-08-29 13:36:57.713167654 +0200
-@@ -102,6 +102,9 @@
- 	    Set the number of days since January 1st, 1970 when the password
- 	    was last changed. The date may also be expressed in the format
- 	    YYYY-MM-DD (or the format more commonly used in your area).
-+	    If the <replaceable>LAST_DAY</replaceable> is set to
-+	    <emphasis>0</emphasis> the user is forced to change his password
-+	    on the next log on.
- 	  </para>
- 	</listitem>
-       </varlistentry>
 diff -up shadow-4.1.5.1/man/ja/man5/login.defs.5.manfix shadow-4.1.5.1/man/ja/man5/login.defs.5
 --- shadow-4.1.5.1/man/ja/man5/login.defs.5.manfix	2012-05-25 13:45:27.000000000 +0200
 +++ shadow-4.1.5.1/man/ja/man5/login.defs.5	2015-12-18 12:34:08.080715842 +0100
diff --git a/SPECS/shadow-utils.spec b/SPECS/shadow-utils.spec
index e7f98da..d040f50 100644
--- a/SPECS/shadow-utils.spec
+++ b/SPECS/shadow-utils.spec
@@ -1,7 +1,7 @@
 Summary: Utilities for managing accounts and shadow password files
 Name: shadow-utils
 Version: 4.1.5.1
-Release: 24%{?dist}
+Release: 25%{?dist}
 Epoch: 2
 URL: http://pkg-shadow.alioth.debian.org/
 Source0: http://pkg-shadow.alioth.debian.org/releases/shadow-%{version}.tar.bz2
@@ -35,6 +35,7 @@ Patch25: shadow-4.1.5.1-lastlog-unexpire.patch
 Patch26: shadow-4.1.5.1-chgrp-guard.patch
 Patch27: shadow-4.1.5.1-selinux-perms.patch
 Patch28: shadow-4.1.5.1-null-tm.patch
+Patch29: shadow-4.1.5.1-long-entry.patch
 
 License: BSD and GPLv2+
 Group: System Environment/Base
@@ -92,6 +93,7 @@ are used for managing group accounts.
 %patch26 -p1 -b .chgrp-guard
 %patch27 -p1 -b .selinux-perms
 %patch28 -p1 -b .null-tm
+%patch29 -p1 -b .long-entry
 
 iconv -f ISO88591 -t utf-8  doc/HOWTO > doc/HOWTO.utf8
 cp -f doc/HOWTO.utf8 doc/HOWTO
@@ -249,6 +251,12 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/vigr.8*
 
 %changelog
+* Tue Apr 24 2018 Tomáš Mráz <tmraz@redhat.com> - 2:4.1.5.1-25
+- prevent creating users ".." or "." or with all numeric usernames (#1373645)
+- raise limit for passwd and shadow entry length but also prevent
+  writing longer entries (#1422497)
+- consider also supplementary group membership in newgrp (#1425078)
+
 * Tue Jun 28 2016 Tomáš Mráz <tmraz@redhat.com> - 2:4.1.5.1-24
 - useradd: fix typo in japanese translation (#1202629)