diff --git a/SOURCES/shadow-4.6-remove-login-string-references.patch b/SOURCES/shadow-4.6-remove-login-string-references.patch
new file mode 100644
index 0000000..eccf9c6
--- /dev/null
+++ b/SOURCES/shadow-4.6-remove-login-string-references.patch
@@ -0,0 +1,19 @@
+diff -up shadow-4.6/man/login.defs.5.xml.remove_login_string_references shadow-4.6/man/login.defs.5.xml
+--- shadow-4.6/man/login.defs.5.xml.remove_login_string_references	2021-04-27 13:01:49.428338258 +0200
++++ shadow-4.6/man/login.defs.5.xml	2021-04-27 13:01:49.433338329 +0200
+@@ -58,7 +58,6 @@
+ <!ENTITY LOG_OK_LOGINS         SYSTEM "login.defs.d/LOG_OK_LOGINS.xml">
+ <!ENTITY LOG_UNKFAIL_ENAB      SYSTEM "login.defs.d/LOG_UNKFAIL_ENAB.xml">
+ <!ENTITY LOGIN_RETRIES         SYSTEM "login.defs.d/LOGIN_RETRIES.xml">
+-<!ENTITY LOGIN_STRING          SYSTEM "login.defs.d/LOGIN_STRING.xml">
+ <!ENTITY LOGIN_TIMEOUT         SYSTEM "login.defs.d/LOGIN_TIMEOUT.xml">
+ <!ENTITY MAIL_CHECK_ENAB       SYSTEM "login.defs.d/MAIL_CHECK_ENAB.xml">
+ <!ENTITY MAIL_DIR              SYSTEM "login.defs.d/MAIL_DIR.xml">
+@@ -214,7 +213,6 @@
+       &LOG_OK_LOGINS;
+       &LOG_UNKFAIL_ENAB;
+       &LOGIN_RETRIES;
+-      &LOGIN_STRING;
+       &LOGIN_TIMEOUT;
+       &MAIL_CHECK_ENAB;
+       &MAIL_DIR;
diff --git a/SOURCES/shadow-4.6-usermod-allow-all-group-types.patch b/SOURCES/shadow-4.6-usermod-allow-all-group-types.patch
new file mode 100644
index 0000000..fada15e
--- /dev/null
+++ b/SOURCES/shadow-4.6-usermod-allow-all-group-types.patch
@@ -0,0 +1,322 @@
+From e481437ab9ebe9a8bf8fbaabe986d42b2f765991 Mon Sep 17 00:00:00 2001
+From: Iker Pedrosa <ipedrosa@redhat.com>
+Date: Tue, 3 Aug 2021 08:57:20 +0200
+Subject: [PATCH] usermod: allow all group types with -G option
+
+The only way of removing a group from the supplementary list is to use
+-G option, and list all groups that the user is a member of except for
+the one that wants to be removed. The problem lies when there's a user
+that contains both local and remote groups, and the group to be removed
+is a local one. As we need to include the remote group with -G option
+the command will fail.
+
+This reverts commit 140510de9de4771feb3af1d859c09604043a4c9b. This way,
+it would be possible to remove the remote groups from the supplementary
+list.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1967641
+Resolves: https://github.com/shadow-maint/shadow/issues/338
+
+Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
+---
+ src/usermod.c | 220 ++++++++++++++++++--------------------------------
+ 1 file changed, 77 insertions(+), 143 deletions(-)
+
+diff --git a/src/usermod.c b/src/usermod.c
+index 03bb9b9d..a0c03afa 100644
+--- a/src/usermod.c
++++ b/src/usermod.c
+@@ -187,7 +187,6 @@ static bool sub_gid_locked = false;
+ static void date_to_str (/*@unique@*//*@out@*/char *buf, size_t maxsize,
+                          long int date);
+ static int get_groups (char *);
+-static struct group * get_local_group (char * grp_name);
+ static /*@noreturn@*/void usage (int status);
+ static void new_pwent (struct passwd *);
+ static void new_spent (struct spwd *);
+@@ -201,9 +200,7 @@ static void grp_update (void);
+ 
+ static void process_flags (int, char **);
+ static void close_files (void);
+-static void close_group_files (void);
+ static void open_files (void);
+-static void open_group_files (void);
+ static void usr_update (void);
+ static void move_home (void);
+ static void update_lastlog (void);
+@@ -260,11 +257,6 @@ static int get_groups (char *list)
+ 		return 0;
+ 	}
+ 
+-	/*
+-	 * Open the group files
+-	 */
+-	open_group_files ();
+-
+ 	/*
+ 	 * So long as there is some data to be converted, strip off each
+ 	 * name and look it up. A mix of numerical and string values for
+@@ -284,7 +276,7 @@ static int get_groups (char *list)
+ 		 * Names starting with digits are treated as numerical GID
+ 		 * values, otherwise the string is looked up as is.
+ 		 */
+-		grp = get_local_group (list);
++		grp = prefix_getgr_nam_gid (list);
+ 
+ 		/*
+ 		 * There must be a match, either by GID value or by
+@@ -334,8 +326,6 @@ static int get_groups (char *list)
+ 		gr_free ((struct group *)grp);
+ 	} while (NULL != list);
+ 
+-	close_group_files ();
+-
+ 	user_groups[ngroups] = (char *) 0;
+ 
+ 	/*
+@@ -348,44 +338,6 @@ static int get_groups (char *list)
+ 	return 0;
+ }
+ 
+-/*
+- * get_local_group - checks if a given group name exists locally
+- *
+- *	get_local_group() checks if a given group name exists locally.
+- *	If the name exists the group information is returned, otherwise NULL is
+- *	returned.
+- */
+-static struct group * get_local_group(char * grp_name)
+-{
+-	const struct group *grp;
+-	struct group *result_grp = NULL;
+-	long long int gid;
+-	char *endptr;
+-
+-	gid = strtoll (grp_name, &endptr, 10);
+-	if (   ('\0' != *grp_name)
+-		&& ('\0' == *endptr)
+-		&& (ERANGE != errno)
+-		&& (gid == (gid_t)gid)) {
+-		grp = gr_locate_gid ((gid_t) gid);
+-	}
+-	else {
+-		grp = gr_locate(grp_name);
+-	}
+-
+-	if (grp != NULL) {
+-		result_grp = __gr_dup (grp);
+-		if (NULL == result_grp) {
+-			fprintf (stderr,
+-					_("%s: Out of memory. Cannot find group '%s'.\n"),
+-					Prog, grp_name);
+-			fail_exit (E_GRP_UPDATE);
+-		}
+-	}
+-
+-	return result_grp;
+-}
+-
+ #ifdef ENABLE_SUBIDS
+ struct ulong_range
+ {
+@@ -1523,7 +1475,50 @@ static void close_files (void)
+ 	}
+ 
+ 	if (Gflg || lflg) {
+-		close_group_files ();
++		if (gr_close () == 0) {
++			fprintf (stderr,
++			         _("%s: failure while writing changes to %s\n"),
++			         Prog, gr_dbname ());
++			SYSLOG ((LOG_ERR,
++			         "failure while writing changes to %s",
++			         gr_dbname ()));
++			fail_exit (E_GRP_UPDATE);
++		}
++#ifdef SHADOWGRP
++		if (is_shadow_grp) {
++			if (sgr_close () == 0) {
++				fprintf (stderr,
++				         _("%s: failure while writing changes to %s\n"),
++				         Prog, sgr_dbname ());
++				SYSLOG ((LOG_ERR,
++				         "failure while writing changes to %s",
++				         sgr_dbname ()));
++				fail_exit (E_GRP_UPDATE);
++			}
++		}
++#endif
++#ifdef SHADOWGRP
++		if (is_shadow_grp) {
++			if (sgr_unlock () == 0) {
++				fprintf (stderr,
++				         _("%s: failed to unlock %s\n"),
++				         Prog, sgr_dbname ());
++				SYSLOG ((LOG_ERR,
++				         "failed to unlock %s",
++				         sgr_dbname ()));
++				/* continue */
++			}
++		}
++#endif
++		if (gr_unlock () == 0) {
++			fprintf (stderr,
++			         _("%s: failed to unlock %s\n"),
++			         Prog, gr_dbname ());
++			SYSLOG ((LOG_ERR,
++			         "failed to unlock %s",
++			         gr_dbname ()));
++			/* continue */
++		}
+ 	}
+ 
+ 	if (is_shadow_pwd) {
+@@ -1592,60 +1587,6 @@ static void close_files (void)
+ #endif
+ }
+ 
+-/*
+- * close_group_files - close all of the files that were opened
+- *
+- *	close_group_files() closes all of the files that were opened related
+- *  with groups. This causes any modified entries to be written out.
+- */
+-static void close_group_files (void)
+-{
+-	if (gr_close () == 0) {
+-		fprintf (stderr,
+-					_("%s: failure while writing changes to %s\n"),
+-					Prog, gr_dbname ());
+-		SYSLOG ((LOG_ERR,
+-					"failure while writing changes to %s",
+-					gr_dbname ()));
+-		fail_exit (E_GRP_UPDATE);
+-	}
+-#ifdef SHADOWGRP
+-	if (is_shadow_grp) {
+-		if (sgr_close () == 0) {
+-			fprintf (stderr,
+-						_("%s: failure while writing changes to %s\n"),
+-						Prog, sgr_dbname ());
+-			SYSLOG ((LOG_ERR,
+-						"failure while writing changes to %s",
+-						sgr_dbname ()));
+-			fail_exit (E_GRP_UPDATE);
+-		}
+-	}
+-#endif
+-#ifdef SHADOWGRP
+-	if (is_shadow_grp) {
+-		if (sgr_unlock () == 0) {
+-			fprintf (stderr,
+-						_("%s: failed to unlock %s\n"),
+-						Prog, sgr_dbname ());
+-			SYSLOG ((LOG_ERR,
+-						"failed to unlock %s",
+-						sgr_dbname ()));
+-			/* continue */
+-		}
+-	}
+-#endif
+-	if (gr_unlock () == 0) {
+-		fprintf (stderr,
+-					_("%s: failed to unlock %s\n"),
+-					Prog, gr_dbname ());
+-		SYSLOG ((LOG_ERR,
+-					"failed to unlock %s",
+-					gr_dbname ()));
+-		/* continue */
+-	}
+-}
+-
+ /*
+  * open_files - lock and open the password files
+  *
+@@ -1681,7 +1622,38 @@ static void open_files (void)
+ 	}
+ 
+ 	if (Gflg || lflg) {
+-		open_group_files ();
++		/*
++		 * Lock and open the group file. This will load all of the
++		 * group entries.
++		 */
++		if (gr_lock () == 0) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, gr_dbname ());
++			fail_exit (E_GRP_UPDATE);
++		}
++		gr_locked = true;
++		if (gr_open (O_CREAT | O_RDWR) == 0) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, gr_dbname ());
++			fail_exit (E_GRP_UPDATE);
++		}
++#ifdef SHADOWGRP
++		if (is_shadow_grp && (sgr_lock () == 0)) {
++			fprintf (stderr,
++			         _("%s: cannot lock %s; try again later.\n"),
++			         Prog, sgr_dbname ());
++			fail_exit (E_GRP_UPDATE);
++		}
++		sgr_locked = true;
++		if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) {
++			fprintf (stderr,
++			         _("%s: cannot open %s\n"),
++			         Prog, sgr_dbname ());
++			fail_exit (E_GRP_UPDATE);
++		}
++#endif
+ 	}
+ #ifdef ENABLE_SUBIDS
+ 	if (vflg || Vflg) {
+@@ -1717,44 +1689,6 @@ static void open_files (void)
+ #endif				/* ENABLE_SUBIDS */
+ }
+ 
+-/*
+- * open_group_files - lock and open the group files
+- *
+- *	open_group_files() loads all of the group entries.
+- */
+-static void open_group_files (void)
+-{
+-	if (gr_lock () == 0) {
+-		fprintf (stderr,
+-					_("%s: cannot lock %s; try again later.\n"),
+-					Prog, gr_dbname ());
+-		fail_exit (E_GRP_UPDATE);
+-	}
+-	gr_locked = true;
+-	if (gr_open (O_CREAT | O_RDWR) == 0) {
+-		fprintf (stderr,
+-					_("%s: cannot open %s\n"),
+-					Prog, gr_dbname ());
+-		fail_exit (E_GRP_UPDATE);
+-	}
+-
+-#ifdef SHADOWGRP
+-	if (is_shadow_grp && (sgr_lock () == 0)) {
+-		fprintf (stderr,
+-					_("%s: cannot lock %s; try again later.\n"),
+-					Prog, sgr_dbname ());
+-		fail_exit (E_GRP_UPDATE);
+-	}
+-	sgr_locked = true;
+-	if (is_shadow_grp && (sgr_open (O_CREAT | O_RDWR) == 0)) {
+-		fprintf (stderr,
+-					_("%s: cannot open %s\n"),
+-					Prog, sgr_dbname ());
+-		fail_exit (E_GRP_UPDATE);
+-	}
+-#endif
+-}
+-
+ /*
+  * usr_update - create the user entries
+  *
+-- 
+2.31.1
+
diff --git a/SPECS/shadow-utils.spec b/SPECS/shadow-utils.spec
index a806a39..4a66b18 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.6
-Release: 12%{?dist}
+Release: 14%{?dist}
 Epoch: 2
 URL: http://pkg-shadow.alioth.debian.org/
 Source0: https://github.com/shadow-maint/shadow/releases/download/%{version}/shadow-%{version}.tar.xz
@@ -45,6 +45,10 @@ Patch43: shadow-4.6-home_mode-directive.patch
 Patch44: shadow-4.6-check-local-groups.patch
 # https://github.com/shadow-maint/shadow/commit/e84df9e163e133eb11a2728024ff3e3440592cf8
 Patch45: shadow-4.6-sssd-redirect-warning.patch
+# Unused option in Fedora/RHEL - non upstreamable
+Patch46: shadow-4.6-remove-login-string-references.patch
+# https://github.com/shadow-maint/shadow/commit/e481437ab9ebe9a8bf8fbaabe986d42b2f765991
+Patch47: shadow-4.6-usermod-allow-all-group-types.patch
 
 License: BSD and GPLv2+
 Group: System Environment/Base
@@ -108,6 +112,8 @@ are used for managing group accounts.
 %patch43 -p1 -b .home_mode-directive
 %patch44 -p1 -b .check-local-groups
 %patch45 -p1 -b .sssd-redirect-warning
+%patch46 -p1 -b .remove-login-string-references
+%patch47 -p1 -b .usermod-allow-all-group-types
 
 iconv -f ISO88591 -t utf-8  doc/HOWTO > doc/HOWTO.utf8
 cp -f doc/HOWTO.utf8 doc/HOWTO
@@ -262,6 +268,12 @@ done
 %{_mandir}/man8/vigr.8*
 
 %changelog
+* Thu Aug 12 2021 Iker Pedrosa <ipedrosa@redhat.com> - 2:4.6-14
+- usermod: allow all group types with -G option (#1967641)
+
+* Mon May  3 2021 Iker Pedrosa <ipedrosa@redhat.com> - 2:4.6-13
+- man: Remove references to LOGIN_STRING in login.defs (#1884702)
+
 * Fri Oct 23 2020 Iker Pedrosa <ipedrosa@redhat.com> - 2:4.6-12
 - lib/sssd: redirect warning message to file (#1749001)
 - useradd: clarify valid usernames/groupnames (#1869432)