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 LAST_DAY is set to
++ 0 the user is forced to change his password
++ on the next log on.
+
+
+
+@@ -123,6 +126,13 @@
+ EXPIRE_DATE will remove an account
+ expiration date.
+
++
++ For example the following command can be used
++ to set an account to expire in 180 days:
++
++
++ chage -E $(date -d +180days +%Y-%m-%d)
++
+
+
+
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.
-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 LAST_DAY is set to
-+ 0 the user is forced to change his password
-+ on the next log on.
-
-
-
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 - 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 - 2:4.1.5.1-24
- useradd: fix typo in japanese translation (#1202629)