diff --git a/shadow-4.1.5.1-date-parsing.patch b/shadow-4.1.5.1-date-parsing.patch
new file mode 100644
index 0000000..38ec091
--- /dev/null
+++ b/shadow-4.1.5.1-date-parsing.patch
@@ -0,0 +1,138 @@
+diff -up shadow-4.1.5.1/libmisc/getdate.c.date-parsing shadow-4.1.5.1/libmisc/getdate.c
+--- shadow-4.1.5.1/libmisc/getdate.c.date-parsing 2008-06-14 00:07:51.000000000 +0200
++++ shadow-4.1.5.1/libmisc/getdate.c 2014-08-29 13:41:22.553267506 +0200
+@@ -261,6 +261,7 @@ static int yyHaveDay;
+ static int yyHaveRel;
+ static int yyHaveTime;
+ static int yyHaveZone;
++static int yyHaveYear;
+ static int yyTimezone;
+ static int yyDay;
+ static int yyHour;
+@@ -1730,6 +1731,7 @@ yyreduce:
+ yyDay = (yyvsp[(3) - (5)].Number);
+ yyYear = (yyvsp[(5) - (5)].Number);
+ }
++ yyHaveYear++;
+ }
+ break;
+
+@@ -1740,6 +1742,7 @@ yyreduce:
+ yyYear = (yyvsp[(1) - (3)].Number);
+ yyMonth = -(yyvsp[(2) - (3)].Number);
+ yyDay = -(yyvsp[(3) - (3)].Number);
++ yyHaveYear++;
+ }
+ break;
+
+@@ -1750,6 +1753,7 @@ yyreduce:
+ yyDay = (yyvsp[(1) - (3)].Number);
+ yyMonth = (yyvsp[(2) - (3)].Number);
+ yyYear = -(yyvsp[(3) - (3)].Number);
++ yyHaveYear++;
+ }
+ break;
+
+@@ -1767,6 +1771,7 @@ yyreduce:
+ yyMonth = (yyvsp[(1) - (4)].Number);
+ yyDay = (yyvsp[(2) - (4)].Number);
+ yyYear = (yyvsp[(4) - (4)].Number);
++ yyHaveYear++;
+ }
+ break;
+
+@@ -1784,6 +1789,7 @@ yyreduce:
+ yyMonth = (yyvsp[(2) - (3)].Number);
+ yyDay = (yyvsp[(1) - (3)].Number);
+ yyYear = (yyvsp[(3) - (3)].Number);
++ yyHaveYear++;
+ }
+ break;
+
+@@ -1928,7 +1934,8 @@ yyreduce:
+ case 49:
+ #line 397 "getdate.y"
+ {
+- if ((yyHaveTime != 0) && (yyHaveDate != 0) && (yyHaveRel == 0))
++ if ((yyHaveTime != 0 || (yyvsp[(1) - (1)].Number) >= 100) && !yyHaveYear
++ && (yyHaveDate != 0) && (yyHaveRel == 0))
+ yyYear = (yyvsp[(1) - (1)].Number);
+ else
+ {
+@@ -2556,7 +2563,7 @@ yylex (void)
+ return LookupWord (buff);
+ }
+ if (c != '(')
+- return *yyInput++;
++ return (unsigned char)*yyInput++;
+ Count = 0;
+ do
+ {
+diff -up shadow-4.1.5.1/libmisc/getdate.y.date-parsing shadow-4.1.5.1/libmisc/getdate.y
+--- shadow-4.1.5.1/libmisc/getdate.y.date-parsing 2008-05-26 10:57:51.000000000 +0200
++++ shadow-4.1.5.1/libmisc/getdate.y 2014-08-29 13:40:37.502229879 +0200
+@@ -152,6 +152,7 @@ static int yyHaveDay;
+ static int yyHaveRel;
+ static int yyHaveTime;
+ static int yyHaveZone;
++static int yyHaveYear;
+ static int yyTimezone;
+ static int yyDay;
+ static int yyHour;
+@@ -293,18 +294,21 @@ date : tUNUMBER '/' tUNUMBER {
+ yyDay = $3;
+ yyYear = $5;
+ }
++ yyHaveYear++;
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
++ yyHaveYear++;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
++ yyHaveYear++;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+@@ -314,6 +318,7 @@ date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
++ yyHaveYear++;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+@@ -323,6 +328,7 @@ date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
++ yyHaveYear++;
+ }
+ ;
+
+@@ -395,7 +401,8 @@ relunit : tUNUMBER tYEAR_UNIT {
+
+ number : tUNUMBER
+ {
+- if ((yyHaveTime != 0) && (yyHaveDate != 0) && (yyHaveRel == 0))
++ if ((yyHaveTime != 0 || $1 >= 100) && !yyHaveYear
++ && (yyHaveDate != 0) && (yyHaveRel == 0))
+ yyYear = $1;
+ else
+ {
+@@ -802,7 +809,7 @@ yylex (void)
+ return LookupWord (buff);
+ }
+ if (c != '(')
+- return *yyInput++;
++ return (unsigned char)*yyInput++;
+ Count = 0;
+ do
+ {
diff --git a/shadow-4.1.5.1-ingroup.patch b/shadow-4.1.5.1-ingroup.patch
new file mode 100644
index 0000000..e440431
--- /dev/null
+++ b/shadow-4.1.5.1-ingroup.patch
@@ -0,0 +1,63 @@
+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
+@@ -83,15 +83,29 @@ static void usage (void)
+ }
+ }
+
++static bool ingroup(const char *name, struct group *gr)
++{
++ char **look;
++ bool notfound = true;
++
++ look = gr->gr_mem;
++ while (*look && notfound)
++ notfound = strcmp (*look++, name);
++
++ return !notfound;
++}
++
+ /*
+- * find_matching_group - search all groups of a given group id for
++ * find_matching_group - search all groups of a gr's group id for
+ * membership of a given username
++ * but check gr itself first
+ */
+-static /*@null@*/struct group *find_matching_group (const char *name, gid_t gid)
++static /*@null@*/struct group *find_matching_group (const char *name, struct group *gr)
+ {
+- struct group *gr;
+- char **look;
+- bool notfound = true;
++ gid_t gid = gr->gr_gid;
++
++ if (ingroup(name, gr))
++ return gr;
+
+ setgrent ();
+ while ((gr = getgrent ()) != NULL) {
+@@ -103,14 +117,8 @@ static /*@null@*/struct group *find_matc
+ * A group with matching GID was found.
+ * Test for membership of 'name'.
+ */
+- look = gr->gr_mem;
+- while ((NULL != *look) && notfound) {
+- notfound = (strcmp (*look, name) != 0);
+- look++;
+- }
+- if (!notfound) {
++ if (ingroup(name, gr))
+ break;
+- }
+ }
+ endgrent ();
+ return gr;
+@@ -616,7 +624,7 @@ int main (int argc, char **argv)
+ * 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
diff --git a/shadow-4.1.5.1-manfix.patch b/shadow-4.1.5.1-manfix.patch
index 00b792f..2963c98 100644
--- a/shadow-4.1.5.1-manfix.patch
+++ b/shadow-4.1.5.1-manfix.patch
@@ -1,6 +1,19 @@
+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/login.defs.5.xml.manfix shadow-4.1.5.1/man/login.defs.5.xml
--- shadow-4.1.5.1/man/login.defs.5.xml.manfix 2012-05-25 13:45:28.000000000 +0200
-+++ shadow-4.1.5.1/man/login.defs.5.xml 2014-02-12 11:18:36.126334872 +0100
++++ shadow-4.1.5.1/man/login.defs.5.xml 2014-08-29 13:31:38.364812323 +0200
@@ -160,6 +160,17 @@
long numeric parameters is machine-dependent.
@@ -19,9 +32,25 @@ diff -up shadow-4.1.5.1/man/login.defs.5.xml.manfix shadow-4.1.5.1/man/login.def
The following configuration items are provided:
+diff -up shadow-4.1.5.1/man/man1/chage.1.manfix shadow-4.1.5.1/man/man1/chage.1
+--- shadow-4.1.5.1/man/man1/chage.1.manfix 2012-05-25 13:58:18.000000000 +0200
++++ shadow-4.1.5.1/man/man1/chage.1 2014-08-29 13:36:31.303559366 +0200
+@@ -45,7 +45,11 @@ command are:
+ .PP
+ \fB\-d\fR, \fB\-\-lastday\fR \fILAST_DAY\fR
+ .RS 4
+-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)\&.
++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
++\fILAST_DAY\fR
++is set to
++\fB0\fR
++the user is forced to change his password on the next log on\&.
+ .RE
+ .PP
+ \fB\-E\fR, \fB\-\-expiredate\fR \fIEXPIRE_DATE\fR
diff -up shadow-4.1.5.1/man/man5/login.defs.5.manfix shadow-4.1.5.1/man/man5/login.defs.5
--- shadow-4.1.5.1/man/man5/login.defs.5.manfix 2012-05-25 13:59:03.000000000 +0200
-+++ shadow-4.1.5.1/man/man5/login.defs.5 2014-02-12 11:26:27.159851843 +0100
++++ shadow-4.1.5.1/man/man5/login.defs.5 2014-08-29 13:31:38.364812323 +0200
@@ -46,6 +46,14 @@ value\&. Numbers (both regular and long)
\fI0\fR) or hexadecimal values (precede the value with
\fI0x\fR)\&. The maximum value of the regular and long numeric parameters is machine\-dependent\&.
@@ -141,8 +170,8 @@ diff -up shadow-4.1.5.1/man/man5/login.defs.5.manfix shadow-4.1.5.1/man/man5/log
.RS 4
CREATE_HOME GID_MAX GID_MIN MAIL_DIR MAX_MEMBERS_PER_GROUP PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE SYS_GID_MAX SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN UMASK
diff -up shadow-4.1.5.1/man/man8/useradd.8.manfix shadow-4.1.5.1/man/man8/useradd.8
---- shadow-4.1.5.1/man/man8/useradd.8.manfix 2013-11-27 10:25:34.740049650 +0100
-+++ shadow-4.1.5.1/man/man8/useradd.8 2013-11-27 10:25:34.758050045 +0100
+--- shadow-4.1.5.1/man/man8/useradd.8.manfix 2014-08-29 13:31:38.347811932 +0200
++++ shadow-4.1.5.1/man/man8/useradd.8 2014-08-29 13:31:38.364812323 +0200
@@ -85,7 +85,7 @@ by default\&.
Any text string\&. It is generally a short description of the login, and is currently used as the field for the user\*(Aqs full name\&.
.RE
@@ -167,9 +196,30 @@ diff -up shadow-4.1.5.1/man/man8/useradd.8.manfix shadow-4.1.5.1/man/man8/userad
.RS 4
Do not create the user\*(Aqs home directory, even if the system wide setting from
/etc/login\&.defs
+diff -up shadow-4.1.5.1/man/man8/usermod.8.manfix shadow-4.1.5.1/man/man8/usermod.8
+--- shadow-4.1.5.1/man/man8/usermod.8.manfix 2012-05-25 13:59:33.000000000 +0200
++++ shadow-4.1.5.1/man/man8/usermod.8 2014-08-29 13:35:27.343086211 +0200
+@@ -63,7 +63,7 @@ The user\*(Aqs new login directory\&.
+ .sp
+ If the
+ \fB\-m\fR
+-option is given, the contents of the current home directory will be moved to the new home directory, which is created if it does not already exist\&.
++option is given, the contents of the current home directory will be moved to the new home directory, which is created if it does not already exist\&. If the current home directory does not exist the new home directory will not be created\&.
+ .RE
+ .PP
+ \fB\-e\fR, \fB\-\-expiredate\fR \fIEXPIRE_DATE\fR
+@@ -143,7 +143,7 @@ Move the content of the user\*(Aqs home
+ This option is only valid in combination with the
+ \fB\-d\fR
+ (or
+-\fB\-\-home\fR) option\&.
++\fB\-\-home\fR) option\&. If the current home directory does not exist the new home directory will not be created\&.
+ .sp
+
+ \fBusermod\fR
diff -up shadow-4.1.5.1/man/useradd.8.xml.manfix shadow-4.1.5.1/man/useradd.8.xml
---- shadow-4.1.5.1/man/useradd.8.xml.manfix 2013-11-27 10:25:34.740049650 +0100
-+++ shadow-4.1.5.1/man/useradd.8.xml 2013-11-27 10:25:34.759050067 +0100
+--- shadow-4.1.5.1/man/useradd.8.xml.manfix 2014-08-29 13:31:38.347811932 +0200
++++ shadow-4.1.5.1/man/useradd.8.xml 2014-08-29 13:31:38.364812323 +0200
@@ -161,7 +161,7 @@
@@ -197,3 +247,26 @@ diff -up shadow-4.1.5.1/man/useradd.8.xml.manfix shadow-4.1.5.1/man/useradd.8.xm
+diff -up shadow-4.1.5.1/man/usermod.8.xml.manfix shadow-4.1.5.1/man/usermod.8.xml
+--- shadow-4.1.5.1/man/usermod.8.xml.manfix 2012-05-25 13:45:29.000000000 +0200
++++ shadow-4.1.5.1/man/usermod.8.xml 2014-08-29 13:33:40.814632618 +0200
+@@ -132,7 +132,8 @@
+ If the
+ option is given, the contents of the current home directory will
+ be moved to the new home directory, which is created if it does
+- not already exist.
++ not already exist. If the current home directory does not exist
++ the new home directory will not be created.
+
+
+
+@@ -261,7 +262,8 @@
+
+
+ Move the content of the user's home directory to the new
+- location.
++ location. If the current home directory does not exist
++ the new home directory will not be created.
+
+
+ This option is only valid in combination with the
diff --git a/shadow-4.1.5.1-move-home.patch b/shadow-4.1.5.1-move-home.patch
new file mode 100644
index 0000000..c87e232
--- /dev/null
+++ b/shadow-4.1.5.1-move-home.patch
@@ -0,0 +1,15 @@
+diff -up shadow-4.1.5.1/src/usermod.c.move-home shadow-4.1.5.1/src/usermod.c
+--- shadow-4.1.5.1/src/usermod.c.move-home 2014-08-29 13:31:38.000000000 +0200
++++ shadow-4.1.5.1/src/usermod.c 2014-08-29 14:14:13.860671177 +0200
+@@ -1571,6 +1571,11 @@ static void move_home (void)
+ Prog, user_home, user_newhome);
+ fail_exit (E_HOMEDIR);
+ }
++ } else {
++ fprintf (stderr,
++ _("%s: The previous home directory (%s) does "
++ "not exist or is inaccessible. Move cannot be completed.\n"),
++ Prog, user_home);
+ }
+ }
+
diff --git a/shadow-4.1.5.1-selinux.patch b/shadow-4.1.5.1-selinux.patch
index 773fd60..adedf0f 100644
--- a/shadow-4.1.5.1-selinux.patch
+++ b/shadow-4.1.5.1-selinux.patch
@@ -1,7 +1,41 @@
diff -up shadow-4.1.5.1/src/useradd.c.selinux shadow-4.1.5.1/src/useradd.c
---- shadow-4.1.5.1/src/useradd.c.selinux 2012-09-19 18:28:37.662060468 +0200
-+++ shadow-4.1.5.1/src/useradd.c 2012-09-19 18:28:37.672060688 +0200
-@@ -2040,7 +2040,7 @@ int main (int argc, char **argv)
+--- shadow-4.1.5.1/src/useradd.c.selinux 2014-08-28 16:36:09.889422103 +0200
++++ shadow-4.1.5.1/src/useradd.c 2014-08-28 17:28:04.828166192 +0200
+@@ -1850,6 +1850,7 @@ static void create_mail (void)
+ */
+ int main (int argc, char **argv)
+ {
++ int rv = E_SUCCESS;
+ #ifdef ACCT_TOOLS_SETUID
+ #ifdef USE_PAM
+ pam_handle_t *pamh = NULL;
+@@ -2037,10 +2038,33 @@ int main (int argc, char **argv)
+
+ usr_update ();
+
++ close_files ();
++
++ nscd_flush_cache ("passwd");
++ nscd_flush_cache ("group");
++
++#ifdef WITH_SELINUX
++ if (Zflg && *user_selinux) {
++ if (is_selinux_enabled () > 0) {
++ if (set_seuser (user_name, user_selinux) != 0) {
++ fprintf (stderr,
++ _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
++ Prog, user_name, user_selinux);
++#ifdef WITH_AUDIT
++ audit_logger (AUDIT_ADD_USER, Prog,
++ "adding SELinux user mapping",
++ user_name, (unsigned int) user_id, 0);
++#endif /* WITH_AUDIT */
++ rv = E_SE_UPDATE;
++ }
++ }
++ }
++#endif
++
if (mflg) {
create_home ();
if (home_added) {
@@ -10,3 +44,32 @@ diff -up shadow-4.1.5.1/src/useradd.c.selinux shadow-4.1.5.1/src/useradd.c
(uid_t)-1, user_id, (gid_t)-1, user_gid);
} else {
fprintf (stderr,
+@@ -2056,27 +2080,6 @@ int main (int argc, char **argv)
+ create_mail ();
+ }
+
+- close_files ();
+-
+-#ifdef WITH_SELINUX
+- if (Zflg) {
+- if (set_seuser (user_name, user_selinux) != 0) {
+- fprintf (stderr,
+- _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"),
+- Prog, user_name, user_selinux);
+-#ifdef WITH_AUDIT
+- audit_logger (AUDIT_ADD_USER, Prog,
+- "adding SELinux user mapping",
+- user_name, (unsigned int) user_id, 0);
+-#endif /* WITH_AUDIT */
+- fail_exit (E_SE_UPDATE);
+- }
+- }
+-#endif /* WITH_SELINUX */
+-
+- nscd_flush_cache ("passwd");
+- nscd_flush_cache ("group");
+-
+- return E_SUCCESS;
++ return rv;
+ }
+
diff --git a/shadow-utils.spec b/shadow-utils.spec
index 98a549b..a546b6d 100644
--- a/shadow-utils.spec
+++ b/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: 17%{?dist}
+Release: 18%{?dist}
Epoch: 2
URL: http://pkg-shadow.alioth.debian.org/
Source0: http://pkg-shadow.alioth.debian.org/releases/shadow-%{version}.tar.bz2
@@ -27,6 +27,9 @@ Patch15: shadow-4.1.5.1-manfix.patch
Patch16: shadow-4.1.5.1-crypt-null.patch
Patch17: shadow-4.1.5.1-userdel-helpfix.patch
Patch18: shadow-4.1.5.1-group-alloc.patch
+Patch19: shadow-4.1.5.1-date-parsing.patch
+Patch20: shadow-4.1.5.1-ingroup.patch
+Patch21: shadow-4.1.5.1-move-home.patch
License: BSD and GPLv2+
Group: System Environment/Base
@@ -73,6 +76,9 @@ are used for managing group accounts.
%patch16 -p1 -b .crypt-null
%patch17 -p1 -b .userdel
%patch18 -p1 -b .group-alloc
+%patch19 -p1 -b .date-parsing
+%patch20 -p1 -b .ingroup
+%patch21 -p1 -b .move-home
iconv -f ISO88591 -t utf-8 doc/HOWTO > doc/HOWTO.utf8
cp -f doc/HOWTO.utf8 doc/HOWTO
@@ -230,6 +236,13 @@ rm -rf $RPM_BUILD_ROOT
%{_mandir}/man8/vigr.8*
%changelog
+* Fri Aug 29 2014 Tomas Mraz - 2:4.1.5.1-18
+- label the newly created home dir correctly (#1077809)
+- mention that chage -d 0 forces password change (#1135010)
+- improve date parsing and error detecting in chage
+- avoid full group database scanning in newgrp in most common case
+- report error if usermod asked for moving homedir and it does not exist
+
* Mon Aug 18 2014 Fedora Release Engineering - 2:4.1.5.1-17
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild