diff --git a/.gitignore b/.gitignore
index 9e53a0f..766ab1a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/sudo-1.8.25p1.tar.gz
+SOURCES/sudo-1.8.29.tar.gz
diff --git a/.sudo.metadata b/.sudo.metadata
index a9c3233..5f0f2dc 100644
--- a/.sudo.metadata
+++ b/.sudo.metadata
@@ -1 +1 @@
-dc49b91ffbd9cd5e1d1eaaf001c42f71f869f377 SOURCES/sudo-1.8.25p1.tar.gz
+fdce342856f1803478eb549479190370001dca95 SOURCES/sudo-1.8.29.tar.gz
diff --git a/SOURCES/sudo-1.8.23-fix-double-quote-parsing-for-Defaults-values.patch b/SOURCES/sudo-1.8.23-fix-double-quote-parsing-for-Defaults-values.patch
deleted file mode 100644
index 25bbfe9..0000000
--- a/SOURCES/sudo-1.8.23-fix-double-quote-parsing-for-Defaults-values.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-diff -up sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.json.ok.defaults-double-quote-fix sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.json.ok
---- sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.json.ok.defaults-double-quote-fix	2018-09-24 18:10:37.235000000 +0200
-+++ sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.json.ok	2018-09-24 18:11:40.153000000 +0200
-@@ -34,7 +34,7 @@
-         },
-         {
-             "Binding": [
--                { "username": "%them" }
-+                { "usergroup": "them" }
-             ],
-             "Options": [
-                 { "set_home": true }
-@@ -42,7 +42,7 @@
-         },
-         {
-             "Binding": [
--                { "username": "%: non UNIX 0 c" }
-+                { "nonunixgroup": " non UNIX 0 c" }
-             ],
-             "Options": [
-                 { "set_home": true }
-@@ -50,7 +50,7 @@
-         },
-         {
-             "Binding": [
--                { "username": "+net" }
-+                { "netgroup": "net" }
-             ],
-             "Options": [
-                 { "set_home": true }
-diff -up sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.toke.ok.defaults-double-quote-fix sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.toke.ok
---- sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.toke.ok.defaults-double-quote-fix	2018-09-24 18:10:25.216000000 +0200
-+++ sudo-1.8.23/plugins/sudoers/regress/sudoers/test2.toke.ok	2018-09-24 18:11:45.213000000 +0200
-@@ -29,9 +29,9 @@ DEFAULTS_HOST BEGINSTR STRBODY ENDSTR WO
- #
- DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
- DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
--DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
--DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
--DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
-+DEFAULTS_USER BEGINSTR STRBODY ENDSTR USERGROUP DEFVAR 
-+DEFAULTS_USER BEGINSTR STRBODY ENDSTR USERGROUP DEFVAR 
-+DEFAULTS_USER BEGINSTR STRBODY ENDSTR NETGROUP DEFVAR 
- 
- #
- DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR 
-diff -up sudo-1.8.23/plugins/sudoers/toke.c.defaults-double-quote-fix sudo-1.8.23/plugins/sudoers/toke.c
---- sudo-1.8.23/plugins/sudoers/toke.c.defaults-double-quote-fix	2018-04-29 21:59:23.000000000 +0200
-+++ sudo-1.8.23/plugins/sudoers/toke.c	2018-09-24 18:06:15.527000000 +0200
-@@ -2395,7 +2395,7 @@ YY_RULE_SETUP
- 				LEXTRACE("ERROR "); /* empty string */
- 				LEXRETURN(ERROR);
- 			    }
--			    if (prev_state == INITIAL) {
-+			    if (prev_state == INITIAL || prev_state == GOTDEFS) {
- 				switch (sudoerslval.string[0]) {
- 				case '%':
- 				    if (sudoerslval.string[1] == '\0' ||
-diff -up sudo-1.8.23/plugins/sudoers/toke.l.defaults-double-quote-fix sudo-1.8.23/plugins/sudoers/toke.l
---- sudo-1.8.23/plugins/sudoers/toke.l.defaults-double-quote-fix	2018-04-29 21:59:23.000000000 +0200
-+++ sudo-1.8.23/plugins/sudoers/toke.l	2018-09-24 18:06:15.528000000 +0200
-@@ -187,7 +187,7 @@ DEFVAR			[a-z_]+
- 				LEXTRACE("ERROR "); /* empty string */
- 				LEXRETURN(ERROR);
- 			    }
--			    if (prev_state == INITIAL) {
-+			    if (prev_state == INITIAL || prev_state == GOTDEFS) {
- 				switch (sudoerslval.string[0]) {
- 				case '%':
- 				    if (sudoerslval.string[1] == '\0' ||
diff --git a/SOURCES/sudo-1.8.23-ldapsearchuidfix.patch b/SOURCES/sudo-1.8.23-ldapsearchuidfix.patch
deleted file mode 100644
index 9698d23..0000000
--- a/SOURCES/sudo-1.8.23-ldapsearchuidfix.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-diff -up sudo-1.8.23/plugins/sudoers/ldap.c.ldapsearchuidfix sudo-1.8.23/plugins/sudoers/ldap.c
---- sudo-1.8.23/plugins/sudoers/ldap.c.ldapsearchuidfix	2018-04-29 21:59:31.000000000 +0200
-+++ sudo-1.8.23/plugins/sudoers/ldap.c	2018-06-18 08:34:01.202686941 +0200
-@@ -1189,8 +1189,8 @@ sudo_ldap_build_pass1(LDAP *ld, struct p
-     if (ldap_conf.search_filter)
- 	sz += strlen(ldap_conf.search_filter);
- 
--    /* Then add (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
--    sz += 29 + sudo_ldap_value_len(pw->pw_name);
-+    /* Then add (|(sudoUser=USERNAME)(sudoUser=#uid)(sudoUser=ALL)) + NUL */
-+    sz += 29 + (12 + MAX_UID_T_LEN) + sudo_ldap_value_len(pw->pw_name);
- 
-     /* Add space for primary and supplementary groups and gids */
-     if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
-@@ -1253,6 +1253,12 @@ sudo_ldap_build_pass1(LDAP *ld, struct p
-     CHECK_LDAP_VCAT(buf, pw->pw_name, sz);
-     CHECK_STRLCAT(buf, ")", sz);
- 
-+    /* Append user uid */
-+    (void) snprintf(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_uid);
-+    (void) strlcat(buf, "(sudoUser=#", sz);
-+    (void) strlcat(buf, gidbuf, sz);
-+    (void) strlcat(buf, ")", sz);
-+
-     /* Append primary group and gid */
-     if (grp != NULL) {
- 	CHECK_STRLCAT(buf, "(sudoUser=%", sz);
diff --git a/SOURCES/sudo-1.8.23-legacy-group-processing.patch b/SOURCES/sudo-1.8.23-legacy-group-processing.patch
index 8cb6a8f..aee16eb 100644
--- a/SOURCES/sudo-1.8.23-legacy-group-processing.patch
+++ b/SOURCES/sudo-1.8.23-legacy-group-processing.patch
@@ -1,7 +1,7 @@
 diff -up ./plugins/sudoers/cvtsudoers.c.legacy-processing ./plugins/sudoers/cvtsudoers.c
---- ./plugins/sudoers/cvtsudoers.c.legacy-processing	2018-09-26 12:27:13.087680204 +0200
-+++ ./plugins/sudoers/cvtsudoers.c	2018-09-26 12:30:59.222466620 +0200
-@@ -321,6 +321,15 @@ main(int argc, char *argv[])
+--- ./plugins/sudoers/cvtsudoers.c.legacy-processing	2019-10-28 13:28:52.000000000 +0100
++++ ./plugins/sudoers/cvtsudoers.c	2019-10-30 13:32:43.309480623 +0100
+@@ -347,6 +347,15 @@ main(int argc, char *argv[])
  	sudo_fatalx("error: unhandled input %d", input_format);
      }
  
@@ -18,9 +18,9 @@ diff -up ./plugins/sudoers/cvtsudoers.c.legacy-processing ./plugins/sudoers/cvts
      filter_userspecs(&parsed_policy, conf);
      filter_defaults(&parsed_policy, conf);
 diff -up ./plugins/sudoers/defaults.c.legacy-processing ./plugins/sudoers/defaults.c
---- ./plugins/sudoers/defaults.c.legacy-processing	2018-09-02 14:30:08.000000000 +0200
-+++ ./plugins/sudoers/defaults.c	2018-09-26 12:27:13.087680204 +0200
-@@ -86,6 +86,7 @@ static struct early_default early_defaul
+--- ./plugins/sudoers/defaults.c.legacy-processing	2019-10-28 13:28:52.000000000 +0100
++++ ./plugins/sudoers/defaults.c	2019-10-30 13:32:43.309480623 +0100
+@@ -93,6 +93,7 @@ static struct early_default early_defaul
      { I_FQDN },
  #endif
      { I_MATCH_GROUP_BY_GID },
@@ -28,7 +28,7 @@ diff -up ./plugins/sudoers/defaults.c.legacy-processing ./plugins/sudoers/defaul
      { I_GROUP_PLUGIN },
      { I_RUNAS_DEFAULT },
      { I_SUDOERS_LOCALE },
-@@ -487,6 +488,8 @@ init_defaults(void)
+@@ -494,6 +495,8 @@ init_defaults(void)
      }
  
      /* First initialize the flags. */
@@ -38,10 +38,10 @@ diff -up ./plugins/sudoers/defaults.c.legacy-processing ./plugins/sudoers/defaul
      def_long_otp_prompt = true;
  #endif
 diff -up ./plugins/sudoers/def_data.c.legacy-processing ./plugins/sudoers/def_data.c
---- ./plugins/sudoers/def_data.c.legacy-processing	2018-08-18 16:10:15.000000000 +0200
-+++ ./plugins/sudoers/def_data.c	2018-09-26 12:27:13.087680204 +0200
-@@ -494,6 +494,10 @@ struct sudo_defs_types sudo_defs_table[]
- 	N_("Ignore case when matching group names"),
+--- ./plugins/sudoers/def_data.c.legacy-processing	2019-10-30 13:32:43.309480623 +0100
++++ ./plugins/sudoers/def_data.c	2019-10-30 13:37:25.914602825 +0100
+@@ -506,6 +506,10 @@ struct sudo_defs_types sudo_defs_table[]
+ 	N_("Log when a command is denied by sudoers"),
  	NULL,
      }, {
 +	"legacy_group_processing", T_FLAG,
@@ -52,31 +52,31 @@ diff -up ./plugins/sudoers/def_data.c.legacy-processing ./plugins/sudoers/def_da
      }
  };
 diff -up ./plugins/sudoers/def_data.h.legacy-processing ./plugins/sudoers/def_data.h
---- ./plugins/sudoers/def_data.h.legacy-processing	2018-08-18 16:10:15.000000000 +0200
-+++ ./plugins/sudoers/def_data.h	2018-09-26 12:27:13.087680204 +0200
-@@ -226,6 +226,8 @@
- #define def_case_insensitive_user (sudo_defs_table[I_CASE_INSENSITIVE_USER].sd_un.flag)
- #define I_CASE_INSENSITIVE_GROUP 113
- #define def_case_insensitive_group (sudo_defs_table[I_CASE_INSENSITIVE_GROUP].sd_un.flag)
-+#define I_LEGACY_GROUP_PROCESSING 114
+--- ./plugins/sudoers/def_data.h.legacy-processing	2019-10-30 13:32:43.310480638 +0100
++++ ./plugins/sudoers/def_data.h	2019-10-30 13:40:59.651713757 +0100
+@@ -232,6 +232,8 @@
+ #define def_log_allowed         (sudo_defs_table[I_LOG_ALLOWED].sd_un.flag)
+ #define I_LOG_DENIED            116
+ #define def_log_denied          (sudo_defs_table[I_LOG_DENIED].sd_un.flag)
++#define I_LEGACY_GROUP_PROCESSING 117
 +#define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag)
  
  enum def_tuple {
  	never,
 diff -up ./plugins/sudoers/def_data.in.legacy-processing ./plugins/sudoers/def_data.in
---- ./plugins/sudoers/def_data.in.legacy-processing	2018-08-18 16:10:15.000000000 +0200
-+++ ./plugins/sudoers/def_data.in	2018-09-26 12:27:13.088680212 +0200
-@@ -357,3 +357,6 @@ case_insensitive_user
- case_insensitive_group
+--- ./plugins/sudoers/def_data.in.legacy-processing	2019-10-30 13:32:43.310480638 +0100
++++ ./plugins/sudoers/def_data.in	2019-10-30 13:42:20.915896239 +0100
+@@ -366,3 +366,6 @@ log_allowed
+ log_denied
  	T_FLAG
- 	"Ignore case when matching group names"
+ 	"Log when a command is denied by sudoers"
 +legacy_group_processing
 +	T_FLAG
 +	"Don't pre-resolve all group names"
 diff -up ./plugins/sudoers/sudoers.c.legacy-processing ./plugins/sudoers/sudoers.c
---- ./plugins/sudoers/sudoers.c.legacy-processing	2018-08-18 16:10:25.000000000 +0200
-+++ ./plugins/sudoers/sudoers.c	2018-09-26 12:27:13.088680212 +0200
-@@ -212,6 +212,10 @@ sudoers_policy_init(void *info, char * c
+--- ./plugins/sudoers/sudoers.c.legacy-processing	2019-10-28 13:28:53.000000000 +0100
++++ ./plugins/sudoers/sudoers.c	2019-10-30 13:32:43.310480638 +0100
+@@ -221,6 +221,10 @@ sudoers_policy_init(void *info, char * c
      if (set_loginclass(runas_pw ? runas_pw : sudo_user.pw))
  	ret = true;
  
diff --git a/SOURCES/sudo-1.8.23-nowaitopt.patch b/SOURCES/sudo-1.8.23-nowaitopt.patch
index 6406396..4c3c603 100644
--- a/SOURCES/sudo-1.8.23-nowaitopt.patch
+++ b/SOURCES/sudo-1.8.23-nowaitopt.patch
@@ -1,7 +1,7 @@
-diff -up sudo-1.8.23/plugins/sudoers/def_data.c.nowaitopt sudo-1.8.23/plugins/sudoers/def_data.c
---- sudo-1.8.23/plugins/sudoers/def_data.c.nowaitopt	2018-06-18 09:36:34.249307795 +0200
-+++ sudo-1.8.23/plugins/sudoers/def_data.c	2018-06-18 09:43:12.122986032 +0200
-@@ -498,6 +498,10 @@ struct sudo_defs_types sudo_defs_table[]
+diff -up ./plugins/sudoers/def_data.c.nowait ./plugins/sudoers/def_data.c
+--- ./plugins/sudoers/def_data.c.nowait	2019-10-30 13:43:48.376168944 +0100
++++ ./plugins/sudoers/def_data.c	2019-10-30 13:43:48.378168973 +0100
+@@ -510,6 +510,10 @@ struct sudo_defs_types sudo_defs_table[]
  	N_("Don't pre-resolve all group names"),
  	NULL,
      }, {
@@ -12,33 +12,32 @@ diff -up sudo-1.8.23/plugins/sudoers/def_data.c.nowaitopt sudo-1.8.23/plugins/su
  	NULL, 0, NULL
      }
  };
-diff -up sudo-1.8.23/plugins/sudoers/def_data.h.nowaitopt sudo-1.8.23/plugins/sudoers/def_data.h
---- sudo-1.8.23/plugins/sudoers/def_data.h.nowaitopt	2018-06-18 09:36:34.250307792 +0200
-+++ sudo-1.8.23/plugins/sudoers/def_data.h	2018-06-18 09:43:44.541878327 +0200
-@@ -228,6 +228,8 @@
- #define def_case_insensitive_group (sudo_defs_table[I_CASE_INSENSITIVE_GROUP].sd_un.flag)
- #define I_LEGACY_GROUP_PROCESSING 114
+diff -up ./plugins/sudoers/def_data.h.nowait ./plugins/sudoers/def_data.h
+--- ./plugins/sudoers/def_data.h.nowait	2019-10-30 13:43:48.378168973 +0100
++++ ./plugins/sudoers/def_data.h	2019-10-30 13:45:38.425770365 +0100
+@@ -234,6 +234,8 @@
+ #define def_log_denied          (sudo_defs_table[I_LOG_DENIED].sd_un.flag)
+ #define I_LEGACY_GROUP_PROCESSING 117
  #define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag)
-+#define I_CMND_NO_WAIT          115
++#define I_CMND_NO_WAIT          118
 +#define def_cmnd_no_wait        (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag)
  
  enum def_tuple {
  	never,
-diff -up sudo-1.8.23/plugins/sudoers/def_data.in.nowaitopt sudo-1.8.23/plugins/sudoers/def_data.in
---- sudo-1.8.23/plugins/sudoers/def_data.in.nowaitopt	2018-06-18 09:36:34.250307792 +0200
-+++ sudo-1.8.23/plugins/sudoers/def_data.in	2018-06-18 09:45:00.076627403 +0200
-@@ -360,3 +360,6 @@ case_insensitive_group
+diff -up ./plugins/sudoers/def_data.in.nowait ./plugins/sudoers/def_data.in
+--- ./plugins/sudoers/def_data.in.nowait	2019-10-30 13:43:48.376168944 +0100
++++ ./plugins/sudoers/def_data.in	2019-10-30 13:43:48.379168987 +0100
+@@ -369,3 +369,6 @@ log_denied
  legacy_group_processing
  	T_FLAG
  	"Don't pre-resolve all group names"
 +cmnd_no_wait
 +	T_FLAG
 +	"Don't fork and wait for the command to finish, just exec it"
-diff -up sudo-1.8.23/plugins/sudoers/policy.c.nowaitopt sudo-1.8.23/plugins/sudoers/policy.c
-diff -up sudo-1.8.23/plugins/sudoers/sudoers.c.nowaitopt sudo-1.8.23/plugins/sudoers/sudoers.c
---- sudo-1.8.23/plugins/sudoers/sudoers.c.nowaitopt	2018-06-18 11:31:51.883751328 +0200
-+++ sudo-1.8.23/plugins/sudoers/sudoers.c	2018-06-18 11:31:03.670899166 +0200
-@@ -213,6 +213,20 @@ sudoers_policy_init(void *info, char * c
+diff -up ./plugins/sudoers/sudoers.c.nowait ./plugins/sudoers/sudoers.c
+--- ./plugins/sudoers/sudoers.c.nowait	2019-10-30 13:43:48.376168944 +0100
++++ ./plugins/sudoers/sudoers.c	2019-10-30 13:43:48.379168987 +0100
+@@ -225,6 +225,20 @@ sudoers_policy_init(void *info, char * c
          def_match_group_by_gid = false;
  	def_legacy_group_processing = false;
      }
diff --git a/SOURCES/sudo-1.8.23-pam-expired-passwords.patch b/SOURCES/sudo-1.8.23-pam-expired-passwords.patch
deleted file mode 100644
index bf2078a..0000000
--- a/SOURCES/sudo-1.8.23-pam-expired-passwords.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-
-# HG changeset patch
-# User Todd C. Miller <Todd.Miller@sudo.ws>
-# Date 1544201494 25200
-# Node ID 656aa910fbaf0be517e012c9271c51eb85c1cca5
-# Parent  ef83f35c9cb090a8b4fd36942f1e47e65c285dce
-The fix for bug #843 was incomplete and caused pam_end() to be called early.
-sudo_pam_approval() must not set the global pam status to an error
-value if it returns AUTH_SUCCESS.  Otherwise, sudo_pam_cleanup()
-will call pam_end() before sudo_pam_begin_session().  This resulted
-in a NULL PAM handle being used in sudo_pam_begin_session().
-
-diff -r ef83f35c9cb0 -r 656aa910fbaf plugins/sudoers/auth/pam.c
---- a/plugins/sudoers/auth/pam.c	Wed Dec 05 10:43:14 2018 -0700
-+++ b/plugins/sudoers/auth/pam.c	Fri Dec 07 09:51:34 2018 -0700
-@@ -210,59 +210,68 @@
- sudo_pam_approval(struct passwd *pw, sudo_auth *auth, bool exempt)
- {
-     const char *s;
-+    int rc, status = AUTH_SUCCESS;
-     int *pam_status = (int *) auth->data;
-     debug_decl(sudo_pam_approval, SUDOERS_DEBUG_AUTH)
- 
--    *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
--    switch (*pam_status) {
-+    rc = pam_acct_mgmt(pamh, PAM_SILENT);
-+    switch (rc) {
- 	case PAM_SUCCESS:
--	    debug_return_int(AUTH_SUCCESS);
-+	    break;
- 	case PAM_AUTH_ERR:
- 	    log_warningx(0, N_("account validation failure, "
- 		"is your account locked?"));
--	    debug_return_int(AUTH_FATAL);
-+	    status = AUTH_FATAL;
-+	    break;
- 	case PAM_NEW_AUTHTOK_REQD:
- 	    /* Ignore if user is exempt from password restrictions. */
- 	    if (exempt)
--		debug_return_int(AUTH_SUCCESS);
-+		break;
- 	    /* New password required, try to change it. */
- 	    log_warningx(0, N_("Account or password is "
- 		"expired, reset your password and try again"));
--	    *pam_status = pam_chauthtok(pamh,
--		PAM_CHANGE_EXPIRED_AUTHTOK);
--	    if (*pam_status == PAM_SUCCESS)
--		debug_return_int(AUTH_SUCCESS);
--	    if ((s = pam_strerror(pamh, *pam_status)) == NULL)
-+	    rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
-+	    if (rc == PAM_SUCCESS)
-+		break;
-+	    if ((s = pam_strerror(pamh, rc)) == NULL)
- 		s = "unknown error";
- 	    log_warningx(0,
- 		N_("unable to change expired password: %s"), s);
--	    debug_return_int(AUTH_FAILURE);
-+	    status = AUTH_FAILURE;
-+	    break;
- 	case PAM_AUTHTOK_EXPIRED:
- 	    /* Ignore if user is exempt from password restrictions. */
- 	    if (exempt)
--		debug_return_int(AUTH_SUCCESS);
-+		break;
- 	    /* Password expired, cannot be updated by user. */
- 	    log_warningx(0,
- 		N_("Password expired, contact your system administrator"));
--	    debug_return_int(AUTH_FATAL);
-+	    status = AUTH_FATAL;
-+	    break;
- 	case PAM_ACCT_EXPIRED:
- 	    log_warningx(0,
- 		N_("Account expired or PAM config lacks an \"account\" "
- 		"section for sudo, contact your system administrator"));
--	    debug_return_int(AUTH_FATAL);
-+	    status = AUTH_FATAL;
-+	    break;
- 	case PAM_AUTHINFO_UNAVAIL:
- 	case PAM_MAXTRIES:
- 	case PAM_PERM_DENIED:
--	    s = pam_strerror(pamh, *pam_status);
-+	    s = pam_strerror(pamh, rc);
- 	    log_warningx(0, N_("PAM account management error: %s"),
- 		s ? s : "unknown error");
--	    debug_return_int(AUTH_FAILURE);
-+	    status = AUTH_FAILURE;
-+	    break;
- 	default:
--	    s = pam_strerror(pamh, *pam_status);
-+	    s = pam_strerror(pamh, rc);
- 	    log_warningx(0, N_("PAM account management error: %s"),
- 		s ? s : "unknown error");
--	    debug_return_int(AUTH_FATAL);
-+	    status = AUTH_FATAL;
-+	    break;
-     }
-+    /* Ignore errors if user is exempt from password restrictions. */
-+    *pam_status = exempt ? PAM_SUCCESS : rc;
-+    debug_return_int(status);
- }
- 
- int
-
diff --git a/SOURCES/sudo-1.8.23-who-am-i.patch b/SOURCES/sudo-1.8.23-who-am-i.patch
deleted file mode 100644
index 2be1c3c..0000000
--- a/SOURCES/sudo-1.8.23-who-am-i.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-commit b2f7983c84fd01e0b29895d7df776b4b162fd8a5
-Author: Todd C. Miller <Todd.Miller@sudo.ws>
-Date:   Wed Jan 2 07:39:33 2019 -0700
-
-    Fix setting of utmp entry when running command in a pty.
-    Regression introduced in sudo 1.8.22.
-
-diff --git a/src/exec_pty.c b/src/exec_pty.c
-index cbcccca3..68312a98 100644
---- a/src/exec_pty.c
-+++ b/src/exec_pty.c
-@@ -140,7 +140,7 @@ pty_cleanup(void)
-  * and slavename globals.
-  */
- static bool
--pty_setup(uid_t uid, const char *tty)
-+pty_setup(struct command_details *details, const char *tty)
- {
-     debug_decl(pty_setup, SUDO_DEBUG_EXEC);
- 
-@@ -152,12 +152,15 @@ pty_setup(uid_t uid, const char *tty)
-     }
- 
-     if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE],
--	slavename, sizeof(slavename), uid))
-+	slavename, sizeof(slavename), details->euid))
- 	sudo_fatal(U_("unable to allocate pty"));
- 
-     /* Add entry to utmp/utmpx? */
--    if (utmp_user != NULL)
-+    if (ISSET(details->flags, CD_SET_UTMP)) {
-+	utmp_user =
-+	    details->utmp_user ? details->utmp_user : user_details.username;
- 	utmp_login(tty, slavename, io_fds[SFD_SLAVE], utmp_user);
-+    }
- 
-     sudo_debug_printf(SUDO_DEBUG_INFO,
- 	"%s: %s fd %d, pty master fd %d, pty slave fd %d",
-@@ -1302,12 +1305,11 @@ exec_pty(struct command_details *details, struct command_status *cstat)
-     /*
-      * Allocate a pty.
-      */
--    if (pty_setup(details->euid, user_details.tty)) {
--	if (ISSET(details->flags, CD_SET_UTMP))
--	    utmp_user = details->utmp_user ? details->utmp_user : user_details.username;
--    } else if (TAILQ_EMPTY(&io_plugins)) {
--	/* Not logging I/O and didn't allocate a pty. */
--	debug_return_bool(false);
-+    if (!pty_setup(details, user_details.tty)) {
-+	if (TAILQ_EMPTY(&io_plugins)) {
-+	    /* Not logging I/O and didn't allocate a pty. */
-+	    debug_return_bool(false);
-+	}
-     }
- 
-     /*
diff --git a/SOURCES/sudo-1.8.25-c-option-help.patch b/SOURCES/sudo-1.8.25-c-option-help.patch
deleted file mode 100644
index 5836052..0000000
--- a/SOURCES/sudo-1.8.25-c-option-help.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 142b370c1f928549db3b357a495d151c7cd87f65 Mon Sep 17 00:00:00 2001
-From: "Todd C. Miller" <Todd.Miller@sudo.ws>
-Date: Tue, 11 Dec 2018 09:05:04 -0700
-Subject: [PATCH 2/4] The -c option was missing from the help info; from
- Radovan Sroka
-
----
- plugins/sudoers/cvtsudoers.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c
-index 795936c1..0221314b 100644
---- a/plugins/sudoers/cvtsudoers.c
-+++ b/plugins/sudoers/cvtsudoers.c
-@@ -1315,6 +1315,7 @@ help(void)
-     usage(0);
-     (void) puts(_("\nOptions:\n"
- 	"  -b, --base=dn              the base DN for sudo LDAP queries\n"
-+	"  -c, --config=conf_file     the path to the configuration file\n"
- 	"  -d, --defaults=deftypes    only convert Defaults of the specified types\n"
- 	"  -e, --expand-aliases       expand aliases when converting\n"
- 	"  -f, --output-format=format set output format: JSON, LDIF or sudoers\n"
--- 
-2.17.2
-
diff --git a/SOURCES/sudo-1.8.25-ipa-hostname.patch b/SOURCES/sudo-1.8.25-ipa-hostname.patch
deleted file mode 100644
index 4186974..0000000
--- a/SOURCES/sudo-1.8.25-ipa-hostname.patch
+++ /dev/null
@@ -1,1063 +0,0 @@
-From e99082e05b9f0dd0e0f47fa1d2e1b9d922ea8c4c Mon Sep 17 00:00:00 2001
-From: "Todd C. Miller" <Todd.Miller@sudo.ws>
-Date: Thu, 15 Aug 2019 14:20:12 -0600
-Subject: [PATCH] Fix special handling of ipa_hostname that was lost in sudo
- 1.8.24. We now include the long and short hostname in sudo parser container.
-
----
- plugins/sudoers/file.c  |   2 +-
- plugins/sudoers/gram.c  | 215 ++++++++++++++++++++--------------------
- plugins/sudoers/gram.y  |   9 +-
- plugins/sudoers/ldap.c  |   2 +-
- plugins/sudoers/match.c |  23 +++--
- plugins/sudoers/parse.h |   3 +-
- plugins/sudoers/sssd.c  |   7 +-
- 7 files changed, 140 insertions(+), 121 deletions(-)
-
-diff --git a/plugins/sudoers/file.c b/plugins/sudoers/file.c
-index fff78a19..5028ce01 100644
---- a/plugins/sudoers/file.c
-+++ b/plugins/sudoers/file.c
-@@ -85,7 +85,7 @@ sudo_file_open(struct sudo_nss *nss)
-     if (handle != NULL) {
- 	handle->fp = open_sudoers(sudoers_file, false, NULL);
- 	if (handle->fp != NULL) {
--	    init_parse_tree(&handle->parse_tree);
-+	    init_parse_tree(&handle->parse_tree, NULL, NULL);
- 	} else {
- 	    free(handle);
- 	    handle = NULL;
-diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c
-index 343e4299..6545e129 100644
---- a/plugins/sudoers/gram.c
-+++ b/plugins/sudoers/gram.c
-@@ -106,7 +106,9 @@ char *errorfile = NULL;
- struct sudoers_parse_tree parsed_policy = {
-     TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs),
-     TAILQ_HEAD_INITIALIZER(parsed_policy.defaults),
--    NULL /* aliases */
-+    NULL, /* aliases */
-+    NULL, /* lhost */
-+    NULL /* shost */
- };
- 
- /*
-@@ -118,7 +120,7 @@ static bool add_userspec(struct member *, struct privilege *);
- static struct defaults *new_default(char *, char *, short);
- static struct member *new_member(char *, int);
- static struct command_digest *new_digest(int, char *);
--#line 80 "gram.y"
-+#line 82 "gram.y"
- #ifndef YYSTYPE_DEFINED
- #define YYSTYPE_DEFINED
- typedef union {
-@@ -135,7 +137,7 @@ typedef union {
-     int tok;
- } YYSTYPE;
- #endif /* YYSTYPE_DEFINED */
--#line 133 "gram.c"
-+#line 135 "gram.c"
- #define COMMAND 257
- #define ALIAS 258
- #define DEFVAR 259
-@@ -675,7 +677,7 @@ short *yysslim;
- YYSTYPE *yyvs;
- unsigned int yystacksize;
- int yyparse(void);
--#line 906 "gram.y"
-+#line 908 "gram.y"
- void
- sudoerserror(const char *s)
- {
-@@ -1019,11 +1021,14 @@ free_userspec(struct userspec *us)
-  * Initialized a sudoers parse tree.
-  */
- void
--init_parse_tree(struct sudoers_parse_tree *parse_tree)
-+init_parse_tree(struct sudoers_parse_tree *parse_tree, const char *lhost,
-+    const char *shost)
- {
-     TAILQ_INIT(&parse_tree->userspecs);
-     TAILQ_INIT(&parse_tree->defaults);
-     parse_tree->aliases = NULL;
-+    parse_tree->shost = shost;
-+    parse_tree->lhost = lhost;
- }
- 
- /*
-@@ -1100,7 +1105,7 @@ init_options(struct command_options *opts)
-     opts->limitprivs = NULL;
- #endif
- }
--#line 1046 "gram.c"
-+#line 1051 "gram.c"
- /* allocate initial stack or double stack size, up to YYMAXDEPTH */
- #if defined(__cplusplus) || defined(__STDC__)
- static int yygrowstack(void)
-@@ -1309,23 +1314,23 @@ yyparse()
-     switch (yyn)
-     {
- case 1:
--#line 178 "gram.y"
-+#line 180 "gram.y"
- { ; }
- break;
- case 5:
--#line 186 "gram.y"
-+#line 188 "gram.y"
- {
- 			    ;
- 			}
- break;
- case 6:
--#line 189 "gram.y"
-+#line 191 "gram.y"
- {
- 			    yyerrok;
- 			}
- break;
- case 7:
--#line 192 "gram.y"
-+#line 194 "gram.y"
- {
- 			    if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) {
- 				sudoerserror(N_("unable to allocate memory"));
-@@ -1334,73 +1339,73 @@ case 7:
- 			}
- break;
- case 8:
--#line 198 "gram.y"
-+#line 200 "gram.y"
- {
- 			    ;
- 			}
- break;
- case 9:
--#line 201 "gram.y"
-+#line 203 "gram.y"
- {
- 			    ;
- 			}
- break;
- case 10:
--#line 204 "gram.y"
-+#line 206 "gram.y"
- {
- 			    ;
- 			}
- break;
- case 11:
--#line 207 "gram.y"
-+#line 209 "gram.y"
- {
- 			    ;
- 			}
- break;
- case 12:
--#line 210 "gram.y"
-+#line 212 "gram.y"
- {
- 			    if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults))
- 				YYERROR;
- 			}
- break;
- case 13:
--#line 214 "gram.y"
-+#line 216 "gram.y"
- {
- 			    if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults))
- 				YYERROR;
- 			}
- break;
- case 14:
--#line 218 "gram.y"
-+#line 220 "gram.y"
- {
- 			    if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults))
- 				YYERROR;
- 			}
- break;
- case 15:
--#line 222 "gram.y"
-+#line 224 "gram.y"
- {
- 			    if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults))
- 				YYERROR;
- 			}
- break;
- case 16:
--#line 226 "gram.y"
-+#line 228 "gram.y"
- {
- 			    if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults))
- 				YYERROR;
- 			}
- break;
- case 18:
--#line 233 "gram.y"
-+#line 235 "gram.y"
- {
- 			    HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries);
- 			    yyval.defaults = yyvsp[-2].defaults;
- 			}
- break;
- case 19:
--#line 239 "gram.y"
-+#line 241 "gram.y"
- {
- 			    yyval.defaults = new_default(yyvsp[0].string, NULL, true);
- 			    if (yyval.defaults == NULL) {
-@@ -1410,7 +1415,7 @@ case 19:
- 			}
- break;
- case 20:
--#line 246 "gram.y"
-+#line 248 "gram.y"
- {
- 			    yyval.defaults = new_default(yyvsp[0].string, NULL, false);
- 			    if (yyval.defaults == NULL) {
-@@ -1420,7 +1425,7 @@ case 20:
- 			}
- break;
- case 21:
--#line 253 "gram.y"
-+#line 255 "gram.y"
- {
- 			    yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true);
- 			    if (yyval.defaults == NULL) {
-@@ -1430,7 +1435,7 @@ case 21:
- 			}
- break;
- case 22:
--#line 260 "gram.y"
-+#line 262 "gram.y"
- {
- 			    yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+');
- 			    if (yyval.defaults == NULL) {
-@@ -1440,7 +1445,7 @@ case 22:
- 			}
- break;
- case 23:
--#line 267 "gram.y"
-+#line 269 "gram.y"
- {
- 			    yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-');
- 			    if (yyval.defaults == NULL) {
-@@ -1450,14 +1455,14 @@ case 23:
- 			}
- break;
- case 25:
--#line 277 "gram.y"
-+#line 279 "gram.y"
- {
- 			    HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries);
- 			    yyval.privilege = yyvsp[-2].privilege;
- 			}
- break;
- case 26:
--#line 283 "gram.y"
-+#line 285 "gram.y"
- {
- 			    struct privilege *p = calloc(1, sizeof(*p));
- 			    if (p == NULL) {
-@@ -1472,21 +1477,21 @@ case 26:
- 			}
- break;
- case 27:
--#line 297 "gram.y"
-+#line 299 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = false;
- 			}
- break;
- case 28:
--#line 301 "gram.y"
-+#line 303 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = true;
- 			}
- break;
- case 29:
--#line 307 "gram.y"
-+#line 309 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
- 			    if (yyval.member == NULL) {
-@@ -1496,7 +1501,7 @@ case 29:
- 			}
- break;
- case 30:
--#line 314 "gram.y"
-+#line 316 "gram.y"
- {
- 			    yyval.member = new_member(NULL, ALL);
- 			    if (yyval.member == NULL) {
-@@ -1506,7 +1511,7 @@ case 30:
- 			}
- break;
- case 31:
--#line 321 "gram.y"
-+#line 323 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, NETGROUP);
- 			    if (yyval.member == NULL) {
-@@ -1516,7 +1521,7 @@ case 31:
- 			}
- break;
- case 32:
--#line 328 "gram.y"
-+#line 330 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, NTWKADDR);
- 			    if (yyval.member == NULL) {
-@@ -1526,7 +1531,7 @@ case 32:
- 			}
- break;
- case 33:
--#line 335 "gram.y"
-+#line 337 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, WORD);
- 			    if (yyval.member == NULL) {
-@@ -1536,7 +1541,7 @@ case 33:
- 			}
- break;
- case 35:
--#line 345 "gram.y"
-+#line 347 "gram.y"
- {
- 			    struct cmndspec *prev;
- 			    prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries);
-@@ -1590,7 +1595,7 @@ case 35:
- 			}
- break;
- case 36:
--#line 398 "gram.y"
-+#line 400 "gram.y"
- {
- 			    struct cmndspec *cs = calloc(1, sizeof(*cs));
- 			    if (cs == NULL) {
-@@ -1642,7 +1647,7 @@ case 36:
- 			}
- break;
- case 37:
--#line 449 "gram.y"
-+#line 451 "gram.y"
- {
- 			    yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string);
- 			    if (yyval.digest == NULL) {
-@@ -1652,7 +1657,7 @@ case 37:
- 			}
- break;
- case 38:
--#line 456 "gram.y"
-+#line 458 "gram.y"
- {
- 			    yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string);
- 			    if (yyval.digest == NULL) {
-@@ -1662,7 +1667,7 @@ case 38:
- 			}
- break;
- case 39:
--#line 463 "gram.y"
-+#line 465 "gram.y"
- {
- 			    yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string);
- 			    if (yyval.digest == NULL) {
-@@ -1672,7 +1677,7 @@ case 39:
- 			}
- break;
- case 40:
--#line 470 "gram.y"
-+#line 472 "gram.y"
- {
- 			    yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string);
- 			    if (yyval.digest == NULL) {
-@@ -1682,13 +1687,13 @@ case 40:
- 			}
- break;
- case 41:
--#line 479 "gram.y"
-+#line 481 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			}
- break;
- case 42:
--#line 482 "gram.y"
-+#line 484 "gram.y"
- {
- 			    if (yyvsp[0].member->type != COMMAND) {
- 				sudoerserror(N_("a digest requires a path name"));
-@@ -1700,75 +1705,75 @@ case 42:
- 			}
- break;
- case 43:
--#line 493 "gram.y"
-+#line 495 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = false;
- 			}
- break;
- case 44:
--#line 497 "gram.y"
-+#line 499 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = true;
- 			}
- break;
- case 45:
--#line 503 "gram.y"
-+#line 505 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 46:
--#line 508 "gram.y"
-+#line 510 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 47:
--#line 512 "gram.y"
-+#line 514 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 48:
--#line 517 "gram.y"
-+#line 519 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 49:
--#line 522 "gram.y"
-+#line 524 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 50:
--#line 527 "gram.y"
-+#line 529 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 51:
--#line 531 "gram.y"
-+#line 533 "gram.y"
- {
- 			    yyval.string = yyvsp[0].string;
- 			}
- break;
- case 52:
--#line 536 "gram.y"
-+#line 538 "gram.y"
- {
- 			    yyval.runas = NULL;
- 			}
- break;
- case 53:
--#line 539 "gram.y"
-+#line 541 "gram.y"
- {
- 			    yyval.runas = yyvsp[-1].runas;
- 			}
- break;
- case 54:
--#line 544 "gram.y"
-+#line 546 "gram.y"
- {
- 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
- 			    if (yyval.runas != NULL) {
-@@ -1786,7 +1791,7 @@ case 54:
- 			}
- break;
- case 55:
--#line 559 "gram.y"
-+#line 561 "gram.y"
- {
- 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
- 			    if (yyval.runas == NULL) {
-@@ -1798,7 +1803,7 @@ case 55:
- 			}
- break;
- case 56:
--#line 568 "gram.y"
-+#line 570 "gram.y"
- {
- 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
- 			    if (yyval.runas == NULL) {
-@@ -1810,7 +1815,7 @@ case 56:
- 			}
- break;
- case 57:
--#line 577 "gram.y"
-+#line 579 "gram.y"
- {
- 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
- 			    if (yyval.runas == NULL) {
-@@ -1822,7 +1827,7 @@ case 57:
- 			}
- break;
- case 58:
--#line 586 "gram.y"
-+#line 588 "gram.y"
- {
- 			    yyval.runas = calloc(1, sizeof(struct runascontainer));
- 			    if (yyval.runas != NULL) {
-@@ -1840,13 +1845,13 @@ case 58:
- 			}
- break;
- case 59:
--#line 603 "gram.y"
-+#line 605 "gram.y"
- {
- 			    init_options(&yyval.options);
- 			}
- break;
- case 60:
--#line 606 "gram.y"
-+#line 608 "gram.y"
- {
- 			    yyval.options.notbefore = parse_gentime(yyvsp[0].string);
- 			    free(yyvsp[0].string);
-@@ -1857,7 +1862,7 @@ case 60:
- 			}
- break;
- case 61:
--#line 614 "gram.y"
-+#line 616 "gram.y"
- {
- 			    yyval.options.notafter = parse_gentime(yyvsp[0].string);
- 			    free(yyvsp[0].string);
-@@ -1868,7 +1873,7 @@ case 61:
- 			}
- break;
- case 62:
--#line 622 "gram.y"
-+#line 624 "gram.y"
- {
- 			    yyval.options.timeout = parse_timeout(yyvsp[0].string);
- 			    free(yyvsp[0].string);
-@@ -1882,7 +1887,7 @@ case 62:
- 			}
- break;
- case 63:
--#line 633 "gram.y"
-+#line 635 "gram.y"
- {
- #ifdef HAVE_SELINUX
- 			    free(yyval.options.role);
-@@ -1891,7 +1896,7 @@ case 63:
- 			}
- break;
- case 64:
--#line 639 "gram.y"
-+#line 641 "gram.y"
- {
- #ifdef HAVE_SELINUX
- 			    free(yyval.options.type);
-@@ -1900,7 +1905,7 @@ case 64:
- 			}
- break;
- case 65:
--#line 645 "gram.y"
-+#line 647 "gram.y"
- {
- #ifdef HAVE_PRIV_SET
- 			    free(yyval.options.privs);
-@@ -1909,7 +1914,7 @@ case 65:
- 			}
- break;
- case 66:
--#line 651 "gram.y"
-+#line 653 "gram.y"
- {
- #ifdef HAVE_PRIV_SET
- 			    free(yyval.options.limitprivs);
-@@ -1918,97 +1923,97 @@ case 66:
- 			}
- break;
- case 67:
--#line 659 "gram.y"
-+#line 661 "gram.y"
- {
- 			    TAGS_INIT(yyval.tag);
- 			}
- break;
- case 68:
--#line 662 "gram.y"
-+#line 664 "gram.y"
- {
- 			    yyval.tag.nopasswd = true;
- 			}
- break;
- case 69:
--#line 665 "gram.y"
-+#line 667 "gram.y"
- {
- 			    yyval.tag.nopasswd = false;
- 			}
- break;
- case 70:
--#line 668 "gram.y"
-+#line 670 "gram.y"
- {
- 			    yyval.tag.noexec = true;
- 			}
- break;
- case 71:
--#line 671 "gram.y"
-+#line 673 "gram.y"
- {
- 			    yyval.tag.noexec = false;
- 			}
- break;
- case 72:
--#line 674 "gram.y"
-+#line 676 "gram.y"
- {
- 			    yyval.tag.setenv = true;
- 			}
- break;
- case 73:
--#line 677 "gram.y"
-+#line 679 "gram.y"
- {
- 			    yyval.tag.setenv = false;
- 			}
- break;
- case 74:
--#line 680 "gram.y"
-+#line 682 "gram.y"
- {
- 			    yyval.tag.log_input = true;
- 			}
- break;
- case 75:
--#line 683 "gram.y"
-+#line 685 "gram.y"
- {
- 			    yyval.tag.log_input = false;
- 			}
- break;
- case 76:
--#line 686 "gram.y"
-+#line 688 "gram.y"
- {
- 			    yyval.tag.log_output = true;
- 			}
- break;
- case 77:
--#line 689 "gram.y"
-+#line 691 "gram.y"
- {
- 			    yyval.tag.log_output = false;
- 			}
- break;
- case 78:
--#line 692 "gram.y"
-+#line 694 "gram.y"
- {
- 			    yyval.tag.follow = true;
- 			}
- break;
- case 79:
--#line 695 "gram.y"
-+#line 697 "gram.y"
- {
- 			    yyval.tag.follow = false;
- 			}
- break;
- case 80:
--#line 698 "gram.y"
-+#line 700 "gram.y"
- {
- 			    yyval.tag.send_mail = true;
- 			}
- break;
- case 81:
--#line 701 "gram.y"
-+#line 703 "gram.y"
- {
- 			    yyval.tag.send_mail = false;
- 			}
- break;
- case 82:
--#line 706 "gram.y"
-+#line 708 "gram.y"
- {
- 			    yyval.member = new_member(NULL, ALL);
- 			    if (yyval.member == NULL) {
-@@ -2018,7 +2023,7 @@ case 82:
- 			}
- break;
- case 83:
--#line 713 "gram.y"
-+#line 715 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
- 			    if (yyval.member == NULL) {
-@@ -2028,7 +2033,7 @@ case 83:
- 			}
- break;
- case 84:
--#line 720 "gram.y"
-+#line 722 "gram.y"
- {
- 			    struct sudo_command *c = calloc(1, sizeof(*c));
- 			    if (c == NULL) {
-@@ -2046,7 +2051,7 @@ case 84:
- 			}
- break;
- case 87:
--#line 741 "gram.y"
-+#line 743 "gram.y"
- {
- 			    const char *s;
- 			    s = alias_add(&parsed_policy, yyvsp[-2].string, HOSTALIAS,
-@@ -2058,14 +2063,14 @@ case 87:
- 			}
- break;
- case 89:
--#line 753 "gram.y"
-+#line 755 "gram.y"
- {
- 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
- 			    yyval.member = yyvsp[-2].member;
- 			}
- break;
- case 92:
--#line 763 "gram.y"
-+#line 765 "gram.y"
- {
- 			    const char *s;
- 			    s = alias_add(&parsed_policy, yyvsp[-2].string, CMNDALIAS,
-@@ -2077,14 +2082,14 @@ case 92:
- 			}
- break;
- case 94:
--#line 775 "gram.y"
-+#line 777 "gram.y"
- {
- 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
- 			    yyval.member = yyvsp[-2].member;
- 			}
- break;
- case 97:
--#line 785 "gram.y"
-+#line 787 "gram.y"
- {
- 			    const char *s;
- 			    s = alias_add(&parsed_policy, yyvsp[-2].string, RUNASALIAS,
-@@ -2096,7 +2101,7 @@ case 97:
- 			}
- break;
- case 100:
--#line 800 "gram.y"
-+#line 802 "gram.y"
- {
- 			    const char *s;
- 			    s = alias_add(&parsed_policy, yyvsp[-2].string, USERALIAS,
-@@ -2108,28 +2113,28 @@ case 100:
- 			}
- break;
- case 102:
--#line 812 "gram.y"
-+#line 814 "gram.y"
- {
- 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
- 			    yyval.member = yyvsp[-2].member;
- 			}
- break;
- case 103:
--#line 818 "gram.y"
-+#line 820 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = false;
- 			}
- break;
- case 104:
--#line 822 "gram.y"
-+#line 824 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = true;
- 			}
- break;
- case 105:
--#line 828 "gram.y"
-+#line 830 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
- 			    if (yyval.member == NULL) {
-@@ -2139,7 +2144,7 @@ case 105:
- 			}
- break;
- case 106:
--#line 835 "gram.y"
-+#line 837 "gram.y"
- {
- 			    yyval.member = new_member(NULL, ALL);
- 			    if (yyval.member == NULL) {
-@@ -2149,7 +2154,7 @@ case 106:
- 			}
- break;
- case 107:
--#line 842 "gram.y"
-+#line 844 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, NETGROUP);
- 			    if (yyval.member == NULL) {
-@@ -2159,7 +2164,7 @@ case 107:
- 			}
- break;
- case 108:
--#line 849 "gram.y"
-+#line 851 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, USERGROUP);
- 			    if (yyval.member == NULL) {
-@@ -2169,7 +2174,7 @@ case 108:
- 			}
- break;
- case 109:
--#line 856 "gram.y"
-+#line 858 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, WORD);
- 			    if (yyval.member == NULL) {
-@@ -2179,28 +2184,28 @@ case 109:
- 			}
- break;
- case 111:
--#line 866 "gram.y"
-+#line 868 "gram.y"
- {
- 			    HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries);
- 			    yyval.member = yyvsp[-2].member;
- 			}
- break;
- case 112:
--#line 872 "gram.y"
-+#line 874 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = false;
- 			}
- break;
- case 113:
--#line 876 "gram.y"
-+#line 878 "gram.y"
- {
- 			    yyval.member = yyvsp[0].member;
- 			    yyval.member->negated = true;
- 			}
- break;
- case 114:
--#line 882 "gram.y"
-+#line 884 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, ALIAS);
- 			    if (yyval.member == NULL) {
-@@ -2210,7 +2215,7 @@ case 114:
- 			}
- break;
- case 115:
--#line 889 "gram.y"
-+#line 891 "gram.y"
- {
- 			    yyval.member = new_member(NULL, ALL);
- 			    if (yyval.member == NULL) {
-@@ -2220,7 +2225,7 @@ case 115:
- 			}
- break;
- case 116:
--#line 896 "gram.y"
-+#line 898 "gram.y"
- {
- 			    yyval.member = new_member(yyvsp[0].string, WORD);
- 			    if (yyval.member == NULL) {
-@@ -2229,7 +2234,7 @@ case 116:
- 			    }
- 			}
- break;
--#line 2175 "gram.c"
-+#line 2180 "gram.c"
-     }
-     yyssp -= yym;
-     yystate = *yyssp;
-diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y
-index 6f437062..e4a0b6d3 100644
---- a/plugins/sudoers/gram.y
-+++ b/plugins/sudoers/gram.y
-@@ -63,7 +63,9 @@ char *errorfile = NULL;
- struct sudoers_parse_tree parsed_policy = {
-     TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs),
-     TAILQ_HEAD_INITIALIZER(parsed_policy.defaults),
--    NULL /* aliases */
-+    NULL, /* aliases */
-+    NULL, /* lhost */
-+    NULL /* shost */
- };
- 
- /*
-@@ -1246,11 +1248,14 @@ free_userspec(struct userspec *us)
-  * Initialized a sudoers parse tree.
-  */
- void
--init_parse_tree(struct sudoers_parse_tree *parse_tree)
-+init_parse_tree(struct sudoers_parse_tree *parse_tree, const char *lhost,
-+    const char *shost)
- {
-     TAILQ_INIT(&parse_tree->userspecs);
-     TAILQ_INIT(&parse_tree->defaults);
-     parse_tree->aliases = NULL;
-+    parse_tree->shost = shost;
-+    parse_tree->lhost = lhost;
- }
- 
- /*
-diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c
-index 3bbd2523..1a4212bf 100644
---- a/plugins/sudoers/ldap.c
-+++ b/plugins/sudoers/ldap.c
-@@ -1665,7 +1665,7 @@ sudo_ldap_open(struct sudo_nss *nss)
-     }
-     handle->ld = ld;
-     /* handle->pw = NULL; */
--    init_parse_tree(&handle->parse_tree);
-+    init_parse_tree(&handle->parse_tree, NULL, NULL);
-     nss->handle = handle;
- 
- done:
-diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c
-index 1936d4b0..165a8f75 100644
---- a/plugins/sudoers/match.c
-+++ b/plugins/sudoers/match.c
-@@ -72,8 +72,10 @@ int
- user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
-     const struct member *m)
- {
--    struct alias *a;
-+    const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
-+    const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost;
-     int matched = UNSPEC;
-+    struct alias *a;
-     debug_decl(user_matches, SUDOERS_DEBUG_MATCH)
- 
-     switch (m->type) {
-@@ -82,8 +84,8 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
- 	    break;
- 	case NETGROUP:
- 	    if (netgr_matches(m->name,
--		def_netgroup_tuple ? user_runhost : NULL,
--		def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name))
-+		def_netgroup_tuple ? lhost : NULL,
-+		def_netgroup_tuple ? shost : NULL, pw->pw_name))
- 		matched = !m->negated;
- 	    break;
- 	case USERGROUP:
-@@ -153,11 +155,13 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
-     const struct member_list *user_list, const struct member_list *group_list,
-     struct member **matching_user, struct member **matching_group)
- {
-+    const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
-+    const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost;
-+    int user_matched = UNSPEC;
-+    int group_matched = UNSPEC;
-     struct member *m;
-     struct alias *a;
-     int rc;
--    int user_matched = UNSPEC;
--    int group_matched = UNSPEC;
-     debug_decl(runaslist_matches, SUDOERS_DEBUG_MATCH)
- 
-     if (ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) || !ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) {
-@@ -175,8 +179,8 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree,
- 			break;
- 		    case NETGROUP:
- 			if (netgr_matches(m->name,
--			    def_netgroup_tuple ? user_runhost : NULL,
--			    def_netgroup_tuple ? user_srunhost : NULL,
-+			    def_netgroup_tuple ? lhost : NULL,
-+			    def_netgroup_tuple ? shost : NULL,
- 			    runas_pw->pw_name))
- 			    user_matched = !m->negated;
- 			break;
-@@ -309,7 +313,10 @@ int
- hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw,
-     const struct member_list *list)
- {
--    return hostlist_matches_int(parse_tree, pw, user_runhost, user_srunhost, list);
-+    const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
-+    const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost;
-+
-+    return hostlist_matches_int(parse_tree, pw, lhost, shost, list);
- }
- 
- /*
-diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h
-index 30813f6d..f5961f7f 100644
---- a/plugins/sudoers/parse.h
-+++ b/plugins/sudoers/parse.h
-@@ -272,6 +272,7 @@ struct sudoers_parse_tree {
-     struct userspec_list userspecs;
-     struct defaults_list defaults;
-     struct rbtree *aliases;
-+    const char *shost, *lhost;
- };
- 
- /* alias.c */
-@@ -297,7 +298,7 @@ void free_userspec(struct userspec *us);
- void free_userspecs(struct userspec_list *usl);
- void free_default(struct defaults *def, struct member_list **binding);
- void free_defaults(struct defaults_list *defs);
--void init_parse_tree(struct sudoers_parse_tree *parse_tree);
-+void init_parse_tree(struct sudoers_parse_tree *parse_tree, const char *shost, const char *lhost);
- void free_parse_tree(struct sudoers_parse_tree *parse_tree);
- void reparent_parse_tree(struct sudoers_parse_tree *new_tree);
- 
-diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c
-index 4f4464a6..69f6c1f9 100644
---- a/plugins/sudoers/sssd.c
-+++ b/plugins/sudoers/sssd.c
-@@ -554,7 +554,6 @@ sudo_sss_open(struct sudo_nss *nss)
- 	sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
- 	debug_return_int(ENOMEM);
-     }
--    init_parse_tree(&handle->parse_tree);
- 
-     /* Load symbols */
-     handle->ssslib = sudo_dso_load(path, SUDO_DSO_LAZY);
-@@ -612,8 +611,6 @@ sudo_sss_open(struct sudo_nss *nss)
- 	debug_return_int(EFAULT);
-     }
- 
--    nss->handle = handle;
--
-     /*
-      * If runhost is the same as the local host, check for ipa_hostname
-      * in sssd.conf and use it in preference to user_runhost.
-@@ -625,6 +622,10 @@ sudo_sss_open(struct sudo_nss *nss)
- 	}
-     }
- 
-+    /* The "parse tree" contains userspecs, defaults, aliases and hostnames. */
-+    init_parse_tree(&handle->parse_tree, handle->ipa_host, handle->ipa_shost);
-+    nss->handle = handle;
-+
-     sudo_debug_printf(SUDO_DEBUG_DEBUG, "handle=%p", handle);
- 
-     debug_return_int(0);
diff --git a/SOURCES/sudo-1.8.25-ldap-backend-parsing-1.patch b/SOURCES/sudo-1.8.25-ldap-backend-parsing-1.patch
deleted file mode 100644
index e2bda07..0000000
--- a/SOURCES/sudo-1.8.25-ldap-backend-parsing-1.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From e1a402f1d65f4f107a40237bc19384e43b334546 Mon Sep 17 00:00:00 2001
-From: "Todd C. Miller" <Todd.Miller@sudo.ws>
-Date: Tue, 16 Oct 2018 12:49:34 -0600
-Subject: [PATCH] sudo_ldap_parse_option() never returns '=' as the operator.
- When parsing command_timeout, role, type, privs and limitprivs, check that
- val is non-NULL instead.  Found by PVS Studio.
-
----
- plugins/sudoers/ldap_util.c | 37 ++++++++++++++-----------------------
- 1 file changed, 14 insertions(+), 23 deletions(-)
-
-diff --git a/plugins/sudoers/ldap_util.c b/plugins/sudoers/ldap_util.c
-index d9be95a61..fecb7a6c5 100644
---- a/plugins/sudoers/ldap_util.c
-+++ b/plugins/sudoers/ldap_util.c
-@@ -405,32 +405,23 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers,
- 		    int op;
- 
- 		    op = sudo_ldap_parse_option(opt, &var, &val);
--		    if (strcmp(var, "command_timeout") == 0) {
--			if (op == '=')
--			    cmndspec->timeout = parse_timeout(val);
-+		    if (strcmp(var, "command_timeout") == 0 && val != NULL) {
-+			cmndspec->timeout = parse_timeout(val);
- #ifdef HAVE_SELINUX
--		    } else if (strcmp(var, "role") == 0) {
--			if (op == '=') {
--			    if ((cmndspec->role = strdup(val)) == NULL)
--				goto oom;
--			}
--		    } else if (strcmp(var, "type") == 0) {
--			if (op == '=') {
--			    if ((cmndspec->type = strdup(val)) == NULL)
--				goto oom;
--			}
-+		    } else if (strcmp(var, "role") == 0 && val != NULL) {
-+			if ((cmndspec->role = strdup(val)) == NULL)
-+			    goto oom;
-+		    } else if (strcmp(var, "type") == 0 && val != NULL) {
-+			if ((cmndspec->type = strdup(val)) == NULL)
-+			    goto oom;
- #endif /* HAVE_SELINUX */
- #ifdef HAVE_PRIV_SET
--		    } else if (strcmp(var, "privs") == 0) {
--			if (op == '=') {
--			    if ((cmndspec->privs = strdup(val)) == NULL)
--				goto oom;
--			}
--		    } else if (strcmp(var, "limitprivs") == 0) {
--			if (op == '=') {
--			    if ((cmndspec->limitprivs = strdup(val)) == NULL)
--				goto oom;
--			}
-+		    } else if (strcmp(var, "privs") == 0 && val != NULL) {
-+			if ((cmndspec->privs = strdup(val)) == NULL)
-+			    goto oom;
-+		    } else if (strcmp(var, "limitprivs") == 0 && val != NULL) {
-+			if ((cmndspec->limitprivs = strdup(val)) == NULL)
-+			    goto oom;
- #endif /* HAVE_PRIV_SET */
- 		    } else if (store_options) {
- 			if (!sudo_ldap_add_default(var, val, op, source,
--- 
-2.21.0
-
diff --git a/SOURCES/sudo-1.8.25-ldap-backend-parsing-2.patch b/SOURCES/sudo-1.8.25-ldap-backend-parsing-2.patch
deleted file mode 100644
index 0865e71..0000000
--- a/SOURCES/sudo-1.8.25-ldap-backend-parsing-2.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 60f0d65e22ba93988229453eb013728e47e5f84e Mon Sep 17 00:00:00 2001
-From: "Todd C. Miller" <Todd.Miller@sudo.ws>
-Date: Wed, 17 Oct 2018 06:57:06 -0600
-Subject: [PATCH] Fix expected test output now that command_timeout is parsed
- correctly in LDIF.
-
----
- .../regress/sudoers/test17.ldif2sudo.ok       | 20 +++++++++----------
- 1 file changed, 10 insertions(+), 10 deletions(-)
-
-diff --git a/plugins/sudoers/regress/sudoers/test17.ldif2sudo.ok b/plugins/sudoers/regress/sudoers/test17.ldif2sudo.ok
-index 6bc2a36ed..608f52fc4 100644
---- a/plugins/sudoers/regress/sudoers/test17.ldif2sudo.ok
-+++ b/plugins/sudoers/regress/sudoers/test17.ldif2sudo.ok
-@@ -1,29 +1,29 @@
- Defaults command_timeout=2d8h10m59s
- 
- # sudoRole user0
--user0 ALL = /usr/bin/id, /usr/bin/who, /bin/ls
-+user0 ALL = TIMEOUT=619830 /usr/bin/id, /usr/bin/who, /bin/ls
- 
- # sudoRole user1
--user1 ALL = /usr/bin/id
-+user1 ALL = TIMEOUT=619830 /usr/bin/id
- 
- # sudoRole user2
--user2 ALL = /usr/bin/id
-+user2 ALL = TIMEOUT=15030 /usr/bin/id
- 
- # sudoRole user3
--user3 ALL = /usr/bin/id
-+user3 ALL = TIMEOUT=630 /usr/bin/id
- 
- # sudoRole user4
--user4 ALL = /usr/bin/id
-+user4 ALL = TIMEOUT=1209600 /usr/bin/id
- 
- # sudoRole user5
--user5 ALL = /usr/bin/id
-+user5 ALL = TIMEOUT=300 /usr/bin/id
- 
- # sudoRole user6
--user6 ALL = /usr/bin/id
-+user6 ALL = TIMEOUT=30 /usr/bin/id
- 
- # sudoRole user7
--user7 ALL = /usr/bin/id
-+user7 ALL = TIMEOUT=45 /usr/bin/id
- 
- # sudoRole user8
--user8 ALL = /usr/bin/id, /usr/bin/id, /usr/bin/id, /usr/bin/id, /usr/bin/id,\
--    /usr/bin/id
-+user8 ALL = TIMEOUT=619830 /usr/bin/id, /usr/bin/id, /usr/bin/id, /usr/bin/id,\
-+    /usr/bin/id, /usr/bin/id
--- 
-2.21.0
-
diff --git a/SOURCES/sudo-1.8.25-sudoreplay-missing-options-help.patch b/SOURCES/sudo-1.8.25-sudoreplay-missing-options-help.patch
deleted file mode 100644
index 88fa081..0000000
--- a/SOURCES/sudo-1.8.25-sudoreplay-missing-options-help.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-diff -up ./plugins/sudoers/sudoreplay.c.sudoreplay-help ./plugins/sudoers/sudoreplay.c
---- ./plugins/sudoers/sudoreplay.c.sudoreplay-help	2018-12-11 18:12:56.715098760 +0100
-+++ ./plugins/sudoers/sudoreplay.c	2018-12-11 18:18:34.345184173 +0100
-@@ -1582,13 +1582,16 @@ help(void)
-     (void) printf(_("%s - replay sudo session logs\n\n"), getprogname());
-     usage(0);
-     (void) puts(_("\nOptions:\n"
--	"  -d, --directory=dir  specify directory for session logs\n"
--	"  -f, --filter=filter  specify which I/O type(s) to display\n"
--	"  -h, --help           display help message and exit\n"
--	"  -l, --list           list available session IDs, with optional expression\n"
--	"  -m, --max-wait=num   max number of seconds to wait between events\n"
--	"  -s, --speed=num      speed up or slow down output\n"
--	"  -V, --version        display version information and exit"));
-+       "  -d, --directory=dir    specify directory for session logs\n"
-+       "  -f, --filter=filter    specify which I/O type(s) to display\n"
-+       "  -h, --help             display help message and exit\n"
-+       "  -l, --list             list available session IDs, with optional expression\n"
-+       "  -m, --max-wait=num     max number of seconds to wait between events\n"
-+       "  -n, --non-interactive  no prompts, session is sent to the standard output\n"
-+       "  -R, --no-resize        do not attempt to re-size the terminal\n"
-+       "  -S, --suspend-wait     wait while the command was suspended\n"
-+       "  -s, --speed=num        speed up or slow down output\n"
-+       "  -V, --version          display version information and exit"));
-     exit(0);
- }
- 
diff --git a/SOURCES/sudo-1.8.25-typos-manpages.patch b/SOURCES/sudo-1.8.25-typos-manpages.patch
deleted file mode 100644
index 32c645e..0000000
--- a/SOURCES/sudo-1.8.25-typos-manpages.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From 04a4b3c1fcc1526ff1ea73597a1764cb160d400b Mon Sep 17 00:00:00 2001
-From: "Todd C. Miller" <Todd.Miller@sudo.ws>
-Date: Tue, 11 Dec 2018 09:02:30 -0700
-Subject: [PATCH 1/4] Fix some typos; reported by Radovan Sroka
-
----
- doc/cvtsudoers.cat     | 6 +++---
- doc/cvtsudoers.man.in  | 6 +++---
- doc/cvtsudoers.mdoc.in | 6 +++---
- 3 files changed, 9 insertions(+), 9 deletions(-)
-
-diff --git a/doc/cvtsudoers.cat b/doc/cvtsudoers.cat
-index 61bf3a28..9c1ef140 100644
---- a/doc/cvtsudoers.cat
-+++ b/doc/cvtsudoers.cat
-@@ -24,7 +24,7 @@ DDEESSCCRRIIPPTTIIOONN
-      --bb _d_n, ----bbaassee=_d_n
-                  The base DN (distinguished name) that will be used when
-                  performing LDAP queries.  Typically this is of the form
--                 ou=SUDOers,dc=-mydomain,dc=com for the domain my-domain.com.
-+                 ou=SUDOers,dc=my-domain,dc=com for the domain my-domain.com.
-                  If this option is not specified, the value of the
-                  SUDOERS_BASE environment variable will be used instead.  Only
-                  necessary when converting to LDIF format.
-@@ -60,7 +60,7 @@ DDEESSCCRRIIPPTTIIOONN
-                  Expand aliases in _i_n_p_u_t___f_i_l_e.  Aliases are preserved by
-                  default when the output _f_o_r_m_a_t is JSON or sudoers.
- 
--     --ff _o_u_t_p_u_t___f_o_r_m_a_t, ----ffoorrmmaatt=_o_u_t_p_u_t___f_o_r_m_a_t
-+     --ff _o_u_t_p_u_t___f_o_r_m_a_t, ----oouuttppuutt--ffoorrmmaatt=_o_u_t_p_u_t___f_o_r_m_a_t
-                  Specify the output format (case-insensitive).  The following
-                  formats are supported:
- 
-diff --git a/doc/cvtsudoers.man.in b/doc/cvtsudoers.man.in
-index b159ee5d..2f45ee1d 100644
---- a/doc/cvtsudoers.man.in
-+++ b/doc/cvtsudoers.man.in
-@@ -59,7 +59,7 @@ The options are as follows:
- The base DN (distinguished name) that will be used when performing
- LDAP queries.
- Typically this is of the form
--\fRou=SUDOers,dc=-mydomain,dc=com\fR
-+\fRou=SUDOers,dc=my-domain,dc=com\fR
- for the domain
- \fRmy-domain.com\fR.
- If this option is not specified, the value of the
-@@ -125,7 +125,7 @@ Aliases are preserved by default when the output
- \fIformat\fR
- is JSON or sudoers.
- .TP 12n
--\fB\-f\fR \fIoutput_format\fR, \fB\--format\fR=\fIoutput_format\fR
-+\fB\-f\fR \fIoutput_format\fR, \fB\--output-format\fR=\fIoutput_format\fR
- Specify the output format (case-insensitive).
- The following formats are supported:
- .PP
-diff --git a/doc/cvtsudoers.mdoc.in b/doc/cvtsudoers.mdoc.in
-index 1812bc67..8261ddc6 100644
---- a/doc/cvtsudoers.mdoc.in
-+++ b/doc/cvtsudoers.mdoc.in
-@@ -57,7 +57,7 @@ The options are as follows:
- The base DN (distinguished name) that will be used when performing
- LDAP queries.
- Typically this is of the form
--.Li ou=SUDOers,dc=-mydomain,dc=com
-+.Li ou=SUDOers,dc=my-domain,dc=com
- for the domain
- .Li my-domain.com .
- If this option is not specified, the value of the
-@@ -110,7 +110,7 @@ Expand aliases in
- Aliases are preserved by default when the output
- .Ar format
- is JSON or sudoers.
--.It Fl f Ar output_format , Fl -format Ns = Ns Ar output_format
-+.It Fl f Ar output_format , Fl -output-format Ns = Ns Ar output_format
- Specify the output format (case-insensitive).
- The following formats are supported:
- .Bl -tag -width 8n
--- 
-2.17.2
-
diff --git a/SOURCES/sudo-1.8.28-CVE-strtouid-test.patch b/SOURCES/sudo-1.8.28-CVE-strtouid-test.patch
deleted file mode 100644
index 0ae387a..0000000
--- a/SOURCES/sudo-1.8.28-CVE-strtouid-test.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-diff -up ./lib/util/regress/atofoo/atofoo_test.c.CVE-strtouid-test ./lib/util/regress/atofoo/atofoo_test.c
---- ./lib/util/regress/atofoo/atofoo_test.c.CVE-strtouid-test	2018-04-29 21:59:23.000000000 +0200
-+++ ./lib/util/regress/atofoo/atofoo_test.c	2019-10-16 09:38:31.851404545 +0200
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2014 Todd C. Miller <Todd.Miller@sudo.ws>
-+ * Copyright (c) 2014-2019 Todd C. Miller <Todd.Miller@sudo.ws>
-  *
-  * Permission to use, copy, modify, and distribute this software for any
-  * purpose with or without fee is hereby granted, provided that the above
-@@ -24,6 +24,7 @@
- #else
- # include "compat/stdbool.h"
- #endif
-+#include <errno.h>
- 
- #include "sudo_compat.h"
- #include "sudo_util.h"
-@@ -78,15 +79,20 @@ static struct strtoid_data {
-     id_t id;
-     const char *sep;
-     const char *ep;
-+    int errnum;
- } strtoid_data[] = {
--    { "0,1", 0, ",", "," },
--    { "10", 10, NULL, NULL },
--    { "-2", -2, NULL, NULL },
-+    { "0,1", 0, ",", ",", 0 },
-+    { "10", 10, NULL, NULL, 0 },
-+    { "-1", 0, NULL, NULL, EINVAL },
-+    { "4294967295", 0, NULL, NULL, EINVAL },
-+    { "4294967296", 0, NULL, NULL, ERANGE },
-+    { "-2147483649", 0, NULL, NULL, ERANGE },
-+    { "-2", -2, NULL, NULL, 0 },
- #if SIZEOF_ID_T != SIZEOF_LONG_LONG
--    { "-2", (id_t)4294967294U, NULL, NULL },
-+    { "-2", (id_t)4294967294U, NULL, NULL, 0 },
- #endif
--    { "4294967294", (id_t)4294967294U, NULL, NULL },
--    { NULL, 0, NULL, NULL }
-+    { "4294967294", (id_t)4294967294U, NULL, NULL, 0 },
-+    { NULL, 0, NULL, NULL, 0 }
- };
- 
- static int
-@@ -102,11 +108,23 @@ test_strtoid(int *ntests)
- 	(*ntests)++;
- 	errstr = "some error";
- 	value = sudo_strtoid(d->idstr, d->sep, &ep, &errstr);
--	if (errstr != NULL) {
--	    if (d->id != (id_t)-1) {
--		sudo_warnx_nodebug("FAIL: %s: %s", d->idstr, errstr);
-+	if (d->errnum != 0) {
-+	    if (errstr == NULL) {
-+		sudo_warnx_nodebug("FAIL: %s: missing errstr for errno %d",
-+		    d->idstr, d->errnum);
-+		errors++;
-+	    } else if (value != 0) {
-+		sudo_warnx_nodebug("FAIL: %s should return 0 on error",
-+		    d->idstr);
-+		errors++;
-+	    } else if (errno != d->errnum) {
-+		sudo_warnx_nodebug("FAIL: %s: errno mismatch, %d != %d",
-+		    d->idstr, errno, d->errnum);
- 		errors++;
- 	    }
-+	} else if (errstr != NULL) {
-+	    sudo_warnx_nodebug("FAIL: %s: %s", d->idstr, errstr);
-+	    errors++;
- 	} else if (value != d->id) {
- 	    sudo_warnx_nodebug("FAIL: %s != %u", d->idstr, (unsigned int)d->id);
- 	    errors++;
-diff -up ./plugins/sudoers/regress/testsudoers/test5.out.ok.CVE-strtouid-test ./plugins/sudoers/regress/testsudoers/test5.out.ok
---- ./plugins/sudoers/regress/testsudoers/test5.out.ok.CVE-strtouid-test	2018-04-29 21:59:23.000000000 +0200
-+++ ./plugins/sudoers/regress/testsudoers/test5.out.ok	2019-10-16 09:29:50.246761680 +0200
-@@ -4,7 +4,7 @@ Parse error in sudoers near line 1.
- Entries for user root:
- 
- Command unmatched
--testsudoers: test5.inc should be owned by gid 4294967295
-+testsudoers: test5.inc should be owned by gid 4294967294
- Parse error in sudoers near line 1.
- 
- Entries for user root:
-diff -up ./plugins/sudoers/regress/testsudoers/test5.sh.CVE-strtouid-test ./plugins/sudoers/regress/testsudoers/test5.sh
---- ./plugins/sudoers/regress/testsudoers/test5.sh.CVE-strtouid-test	2018-04-29 21:59:23.000000000 +0200
-+++ ./plugins/sudoers/regress/testsudoers/test5.sh	2019-10-16 09:29:50.246761680 +0200
-@@ -24,7 +24,7 @@ EOF
- 
- # Test group writable
- chmod 664 $TESTFILE
--./testsudoers -U $MYUID -G -1 root id <<EOF
-+./testsudoers -U $MYUID -G -2 root id <<EOF
- #include $TESTFILE
- EOF
- 
diff --git a/SOURCES/sudo-1.8.28-CVE-strtouid.patch b/SOURCES/sudo-1.8.28-CVE-strtouid.patch
deleted file mode 100644
index dbf9db7..0000000
--- a/SOURCES/sudo-1.8.28-CVE-strtouid.patch
+++ /dev/null
@@ -1,172 +0,0 @@
-Treat an ID of -1 as invalid since that means "no change".
-Fixes CVE-2019-14287.
-Found by Joe Vennix from Apple Information Security.
-
-diff -r fcd7a6d8330e lib/util/strtoid.c
---- a/lib/util/strtoid.c	Fri Jan 11 13:31:15 2019 -0700
-+++ b/lib/util/strtoid.c	Thu Oct 10 09:52:12 2019 -0600
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2013-2016 Todd C. Miller <Todd.Miller@sudo.ws>
-+ * Copyright (c) 2013-2019 Todd C. Miller <Todd.Miller@sudo.ws>
-  *
-  * Permission to use, copy, modify, and distribute this software for any
-  * purpose with or without fee is hereby granted, provided that the above
-@@ -47,6 +47,27 @@
- #include "sudo_util.h"
- 
- /*
-+ * Make sure that the ID ends with a valid separator char.
-+ */
-+static bool
-+valid_separator(const char *p, const char *ep, const char *sep)
-+{
-+    bool valid = false;
-+    debug_decl(valid_separator, SUDO_DEBUG_UTIL)
-+
-+    if (ep != p) {
-+	/* check for valid separator (including '\0') */
-+	if (sep == NULL)
-+	    sep = "";
-+	do {
-+	    if (*ep == *sep)
-+		valid = true;
-+	} while (*sep++ != '\0');
-+    }
-+    debug_return_bool(valid);
-+}
-+
-+/*
-  * Parse a uid/gid in string form.
-  * If sep is non-NULL, it contains valid separator characters (e.g. comma, space)
-  * If endp is non-NULL it is set to the next char after the ID.
-@@ -60,38 +81,35 @@ sudo_strtoid_v1(const char *p, const cha
-     char *ep;
-     id_t ret = 0;
-     long long llval;
--    bool valid = false;
-     debug_decl(sudo_strtoid, SUDO_DEBUG_UTIL)
- 
-     /* skip leading space so we can pick up the sign, if any */
-     while (isspace((unsigned char)*p))
- 	p++;
--    if (sep == NULL)
--	sep = "";
-+
-+    /* While id_t may be 64-bit signed, uid_t and gid_t are 32-bit unsigned. */
-     errno = 0;
-     llval = strtoll(p, &ep, 10);
--    if (ep != p) {
--	/* check for valid separator (including '\0') */
--	do {
--	    if (*ep == *sep)
--		valid = true;
--	} while (*sep++ != '\0');
-+    if ((errno == ERANGE && llval == LLONG_MAX) || llval > (id_t)UINT_MAX) {
-+	errno = ERANGE;
-+	if (errstr != NULL)
-+	    *errstr = N_("value too large");
-+	goto done;
-     }
--    if (!valid) {
-+    if ((errno == ERANGE && llval == LLONG_MIN) || llval < INT_MIN) {
-+	errno = ERANGE;
-+	if (errstr != NULL)
-+	    *errstr = N_("value too small");
-+	goto done;
-+    }
-+
-+    /* Disallow id -1, which means "no change". */
-+    if (!valid_separator(p, ep, sep) || llval == -1 || llval == (id_t)UINT_MAX) {
- 	if (errstr != NULL)
- 	    *errstr = N_("invalid value");
- 	errno = EINVAL;
- 	goto done;
-     }
--    if (errno == ERANGE) {
--	if (errstr != NULL) {
--	    if (llval == LLONG_MAX)
--		*errstr = N_("value too large");
--	    else
--		*errstr = N_("value too small");
--	}
--	goto done;
--    }
-     ret = (id_t)llval;
-     if (errstr != NULL)
- 	*errstr = NULL;
-@@ -106,30 +124,15 @@ sudo_strtoid_v1(const char *p, const cha
- {
-     char *ep;
-     id_t ret = 0;
--    bool valid = false;
-     debug_decl(sudo_strtoid, SUDO_DEBUG_UTIL)
- 
-     /* skip leading space so we can pick up the sign, if any */
-     while (isspace((unsigned char)*p))
- 	p++;
--    if (sep == NULL)
--	sep = "";
-+
-     errno = 0;
-     if (*p == '-') {
- 	long lval = strtol(p, &ep, 10);
--	if (ep != p) {
--	    /* check for valid separator (including '\0') */
--	    do {
--		if (*ep == *sep)
--		    valid = true;
--	    } while (*sep++ != '\0');
--	}
--	if (!valid) {
--	    if (errstr != NULL)
--		*errstr = N_("invalid value");
--	    errno = EINVAL;
--	    goto done;
--	}
- 	if ((errno == ERANGE && lval == LONG_MAX) || lval > INT_MAX) {
- 	    errno = ERANGE;
- 	    if (errstr != NULL)
-@@ -142,28 +145,31 @@ sudo_strtoid_v1(const char *p, const cha
- 		*errstr = N_("value too small");
- 	    goto done;
- 	}
--	ret = (id_t)lval;
--    } else {
--	unsigned long ulval = strtoul(p, &ep, 10);
--	if (ep != p) {
--	    /* check for valid separator (including '\0') */
--	    do {
--		if (*ep == *sep)
--		    valid = true;
--	    } while (*sep++ != '\0');
--	}
--	if (!valid) {
-+
-+	/* Disallow id -1, which means "no change". */
-+	if (!valid_separator(p, ep, sep) || lval == -1) {
- 	    if (errstr != NULL)
- 		*errstr = N_("invalid value");
- 	    errno = EINVAL;
- 	    goto done;
- 	}
-+	ret = (id_t)lval;
-+    } else {
-+	unsigned long ulval = strtoul(p, &ep, 10);
- 	if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) {
- 	    errno = ERANGE;
- 	    if (errstr != NULL)
- 		*errstr = N_("value too large");
- 	    goto done;
- 	}
-+
-+	/* Disallow id -1, which means "no change". */
-+	if (!valid_separator(p, ep, sep) || ulval == UINT_MAX) {
-+	    if (errstr != NULL)
-+		*errstr = N_("invalid value");
-+	    errno = EINVAL;
-+	    goto done;
-+	}
- 	ret = (id_t)ulval;
-     }
-     if (errstr != NULL)
diff --git a/SOURCES/sudo-1.8.29-CVE-2019-18634-part1.patch b/SOURCES/sudo-1.8.29-CVE-2019-18634-part1.patch
deleted file mode 100644
index 5b71919..0000000
--- a/SOURCES/sudo-1.8.29-CVE-2019-18634-part1.patch
+++ /dev/null
@@ -1,158 +0,0 @@
-diff -up ./src/tgetpass.c.bla ./src/tgetpass.c
---- ./src/tgetpass.c.bla	2018-08-18 16:10:15.000000000 +0200
-+++ ./src/tgetpass.c	2020-02-05 17:15:16.216904891 +0100
-@@ -44,11 +44,18 @@
- #include "sudo.h"
- #include "sudo_plugin.h"
- 
-+enum tgetpass_errval {
-+    TGP_ERRVAL_NOERROR,
-+    TGP_ERRVAL_TIMEOUT,
-+    TGP_ERRVAL_NOPASSWORD,
-+    TGP_ERRVAL_READERROR
-+};
-+
- static volatile sig_atomic_t signo[NSIG];
- 
- static bool tty_present(void);
- static void tgetpass_handler(int);
--static char *getln(int, char *, size_t, int);
-+static char *getln(int, char *, size_t, int, enum tgetpass_errval *);
- static char *sudo_askpass(const char *, const char *);
- 
- static int
-@@ -77,6 +84,27 @@ suspend(int signo, struct sudo_conv_call
-     debug_return_int(ret);
- }
- 
-+static void
-+tgetpass_display_error(enum tgetpass_errval errval)
-+{
-+    debug_decl(tgetpass_display_error, SUDO_DEBUG_CONV)
-+
-+    switch (errval) {
-+    case TGP_ERRVAL_NOERROR:
-+	break;
-+    case TGP_ERRVAL_TIMEOUT:
-+	sudo_warnx(U_("timed out reading password"));
-+	break;
-+    case TGP_ERRVAL_NOPASSWORD:
-+	sudo_warnx(U_("no password was provided"));
-+	break;
-+    case TGP_ERRVAL_READERROR:
-+	sudo_warn(U_("unable to read password"));
-+	break;
-+    }
-+    debug_return;
-+}
-+
- /*
-  * Like getpass(3) but with timeout and echo flags.
-  */
-@@ -90,6 +118,7 @@ tgetpass(const char *prompt, int timeout
-     static const char *askpass;
-     static char buf[SUDO_CONV_REPL_MAX + 1];
-     int i, input, output, save_errno, neednl = 0, need_restart;
-+    enum tgetpass_errval errval;
-     debug_decl(tgetpass, SUDO_DEBUG_CONV)
- 
-     (void) fflush(stdout);
-@@ -175,7 +204,7 @@ restart:
- 
-     if (timeout > 0)
- 	alarm(timeout);
--    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK));
-+    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval);
-     alarm(0);
-     save_errno = errno;
- 
-@@ -183,6 +212,7 @@ restart:
- 	if (write(output, "\n", 1) == -1)
- 	    goto restore;
-     }
-+    tgetpass_display_error(errval);
- 
- restore:
-     /* Restore old signal handlers. */
-@@ -210,6 +240,8 @@ restore:
-     for (i = 0; i < NSIG; i++) {
- 	if (signo[i]) {
- 	    switch (i) {
-+		case SIGALRM:
-+		    break;
- 		case SIGTSTP:
- 		case SIGTTIN:
- 		case SIGTTOU:
-@@ -239,6 +271,7 @@ sudo_askpass(const char *askpass, const
- {
-     static char buf[SUDO_CONV_REPL_MAX + 1], *pass;
-     struct sigaction sa, savechld;
-+    enum tgetpass_errval errval;
-     int pfd[2], status;
-     pid_t child;
-     debug_decl(sudo_askpass, SUDO_DEBUG_CONV)
-@@ -281,9 +314,11 @@ sudo_askpass(const char *askpass, const
- 
-     /* Get response from child (askpass). */
-     (void) close(pfd[1]);
--    pass = getln(pfd[0], buf, sizeof(buf), 0);
-+    pass = getln(pfd[0], buf, sizeof(buf), 0, &errval);
-     (void) close(pfd[0]);
- 
-+    tgetpass_display_error(errval);
-+
-     /* Wait for child to exit. */
-     for (;;) {
- 	pid_t rv = waitpid(child, &status, 0);
-@@ -305,7 +340,8 @@ sudo_askpass(const char *askpass, const
- extern int sudo_term_erase, sudo_term_kill;
- 
- static char *
--getln(int fd, char *buf, size_t bufsiz, int feedback)
-+getln(int fd, char *buf, size_t bufsiz, int feedback,
-+      enum tgetpass_errval *errval)
- {
-     size_t left = bufsiz;
-     ssize_t nr = -1;
-@@ -313,7 +349,10 @@ getln(int fd, char *buf, size_t bufsiz,
-     char c = '\0';
-     debug_decl(getln, SUDO_DEBUG_CONV)
- 
-+    *errval = TGP_ERRVAL_NOERROR;
-+
-     if (left == 0) {
-+	*errval = TGP_ERRVAL_READERROR;
- 	errno = EINVAL;
- 	debug_return_str(NULL);		/* sanity */
-     }
-@@ -354,14 +393,27 @@ getln(int fd, char *buf, size_t bufsiz,
- 	}
-     }
- 
--    debug_return_str_masked(nr == 1 ? buf : NULL);
-+    if (nr != 1) {
-+	if (nr == 0) {
-+	    *errval = TGP_ERRVAL_NOPASSWORD;
-+	} else if (nr == -1) {
-+	    if (errno == EINTR) {
-+		if (signo[SIGALRM] == 1)
-+		    *errval = TGP_ERRVAL_TIMEOUT;
-+	    } else {
-+		*errval = TGP_ERRVAL_READERROR;
-+	    }
-+	}
-+	debug_return_str(NULL);
-+    }
-+
-+    debug_return_str_masked(buf);
- }
- 
- static void
- tgetpass_handler(int s)
- {
--    if (s != SIGALRM)
--	signo[s] = 1;
-+    signo[s] = 1;
- }
- 
- static bool
diff --git a/SOURCES/sudo-1.8.29-CVE-2019-18634-part2.patch b/SOURCES/sudo-1.8.29-CVE-2019-18634-part2.patch
deleted file mode 100644
index 86743ba..0000000
--- a/SOURCES/sudo-1.8.29-CVE-2019-18634-part2.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-diff -up ./src/tgetpass.c.CVE-2019-18634 ./src/tgetpass.c
---- ./src/tgetpass.c.CVE-2019-18634	2020-02-05 17:16:07.601420697 +0100
-+++ ./src/tgetpass.c	2020-02-05 17:22:34.206301510 +0100
-@@ -55,7 +55,7 @@ static volatile sig_atomic_t signo[NSIG]
- 
- static bool tty_present(void);
- static void tgetpass_handler(int);
--static char *getln(int, char *, size_t, int, enum tgetpass_errval *);
-+static char *getln(int, char *, size_t, bool, enum tgetpass_errval *);
- static char *sudo_askpass(const char *, const char *);
- 
- static int
-@@ -118,6 +118,7 @@ tgetpass(const char *prompt, int timeout
-     static const char *askpass;
-     static char buf[SUDO_CONV_REPL_MAX + 1];
-     int i, input, output, save_errno, neednl = 0, need_restart;
-+    bool feedback = ISSET(flags, TGP_MASK);
-     enum tgetpass_errval errval;
-     debug_decl(tgetpass, SUDO_DEBUG_CONV)
- 
-@@ -165,7 +166,7 @@ restart:
-      */
-     if (!ISSET(flags, TGP_ECHO)) {
- 	for (;;) {
--	    if (ISSET(flags, TGP_MASK))
-+	    if (feedback)
- 		neednl = sudo_term_cbreak(input);
- 	    else
- 		neednl = sudo_term_noecho(input);
-@@ -179,6 +180,9 @@ restart:
- 	    }
- 	}
-     }
-+    /* Only use feedback mode when we can disable echo. */
-+    if (!neednl)
-+	feedback = false;
- 
-     /*
-      * Catch signals that would otherwise cause the user to end
-@@ -204,7 +208,7 @@ restart:
- 
-     if (timeout > 0)
- 	alarm(timeout);
--    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval);
-+    pass = getln(input, buf, sizeof(buf), feedback, &errval);
-     alarm(0);
-     save_errno = errno;
- 
-@@ -340,7 +344,7 @@ sudo_askpass(const char *askpass, const
- extern int sudo_term_erase, sudo_term_kill;
- 
- static char *
--getln(int fd, char *buf, size_t bufsiz, int feedback,
-+getln(int fd, char *buf, size_t bufsiz, bool feedback,
-       enum tgetpass_errval *errval)
- {
-     size_t left = bufsiz;
-@@ -366,15 +370,15 @@ getln(int fd, char *buf, size_t bufsiz,
- 		while (cp > buf) {
- 		    if (write(fd, "\b \b", 3) == -1)
- 			break;
--		    --cp;
-+		    cp--;
- 		}
-+		cp = buf;
- 		left = bufsiz;
- 		continue;
- 	    } else if (c == sudo_term_erase) {
- 		if (cp > buf) {
--		    if (write(fd, "\b \b", 3) == -1)
--			break;
--		    --cp;
-+		    ignore_result(write(fd, "\b \b", 3));
-+		    cp--;
- 		    left++;
- 		}
- 		continue;
diff --git a/SOURCES/sudo-1.8.29-CVE-2019-18634.patch b/SOURCES/sudo-1.8.29-CVE-2019-18634.patch
new file mode 100644
index 0000000..cc6fa49
--- /dev/null
+++ b/SOURCES/sudo-1.8.29-CVE-2019-18634.patch
@@ -0,0 +1,77 @@
+diff -up ./src/tgetpass.c.CVE-2019-18634 ./src/tgetpass.c
+--- ./src/tgetpass.c.CVE-2019-18634	2019-10-28 13:27:39.000000000 +0100
++++ ./src/tgetpass.c	2020-02-05 14:08:27.516101197 +0100
+@@ -61,7 +61,7 @@ enum tgetpass_errval {
+ static volatile sig_atomic_t signo[NSIG];
+ 
+ static void tgetpass_handler(int);
+-static char *getln(int, char *, size_t, int, enum tgetpass_errval *);
++static char *getln(int, char *, size_t, bool, enum tgetpass_errval *);
+ static char *sudo_askpass(const char *, const char *);
+ 
+ static int
+@@ -125,6 +125,7 @@ tgetpass(const char *prompt, int timeout
+     static char buf[SUDO_CONV_REPL_MAX + 1];
+     int i, input, output, save_errno, ttyfd;
+     bool need_restart, neednl = false;
++    bool feedback = ISSET(flags, TGP_MASK);
+     enum tgetpass_errval errval;
+     debug_decl(tgetpass, SUDO_DEBUG_CONV)
+ 
+@@ -180,7 +181,7 @@ restart:
+      */
+     if (!ISSET(flags, TGP_ECHO)) {
+ 	for (;;) {
+-	    if (ISSET(flags, TGP_MASK))
++	    if (feedback)
+ 		neednl = sudo_term_cbreak(input);
+ 	    else
+ 		neednl = sudo_term_noecho(input);
+@@ -194,6 +195,9 @@ restart:
+ 	    }
+ 	}
+     }
++    /* Only use feedback mode when we can disable echo. */
++    if (!neednl)
++	feedback = false;
+ 
+     /*
+      * Catch signals that would otherwise cause the user to end
+@@ -224,7 +228,7 @@ restart:
+ 
+     if (timeout > 0)
+ 	alarm(timeout);
+-    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval);
++    pass = getln(input, buf, sizeof(buf), feedback, &errval);
+     alarm(0);
+     save_errno = errno;
+ 
+@@ -360,7 +364,7 @@ sudo_askpass(const char *askpass, const
+ extern int sudo_term_eof, sudo_term_erase, sudo_term_kill;
+ 
+ static char *
+-getln(int fd, char *buf, size_t bufsiz, int feedback,
++getln(int fd, char *buf, size_t bufsiz, bool feedback,
+     enum tgetpass_errval *errval)
+ {
+     size_t left = bufsiz;
+@@ -389,15 +393,15 @@ getln(int fd, char *buf, size_t bufsiz,
+ 		while (cp > buf) {
+ 		    if (write(fd, "\b \b", 3) == -1)
+ 			break;
+-		    --cp;
++		    cp--;
+ 		}
++		cp = buf;
+ 		left = bufsiz;
+ 		continue;
+ 	    } else if (c == sudo_term_erase) {
+ 		if (cp > buf) {
+-		    if (write(fd, "\b \b", 3) == -1)
+-			break;
+-		    --cp;
++		    ignore_result(write(fd, "\b \b", 3));
++		    cp--;
+ 		    left++;
+ 		}
+ 		continue;
diff --git a/SOURCES/sudo-1.8.29-CVE-2019-19232.patch b/SOURCES/sudo-1.8.29-CVE-2019-19232.patch
new file mode 100644
index 0000000..f7a006f
--- /dev/null
+++ b/SOURCES/sudo-1.8.29-CVE-2019-19232.patch
@@ -0,0 +1,169 @@
+diff -up ./doc/sudoers.man.in.CVE-2019-19232 ./doc/sudoers.man.in
+--- ./doc/sudoers.man.in.CVE-2019-19232	2019-10-28 13:28:52.000000000 +0100
++++ ./doc/sudoers.man.in	2020-01-14 15:34:46.908027286 +0100
+@@ -2942,6 +2942,23 @@ This flag is
+ \fIoff\fR
+ by default.
+ .TP 18n
++runas_allow_unknown_id
++If enabled, allow matching of runas user and group IDs that are
++not present in the password or group databases.
++In addition to explicitly matching unknown user or group IDs in a
++\fRRunas_List\fR,
++this option also allows the
++\fBALL\fR
++alias to match unknown IDs.
++This flag is
++\fIoff\fR
++by default.
++.sp
++This setting is only supported by version 1.8.29 or higher.
++Older versions of
++\fBsudo\fR
++always allowed matching of unknown user and group IDs.
++.TP 18n
+ runaspw
+ If set,
+ \fBsudo\fR
+diff -up ./doc/sudoers.mdoc.in.CVE-2019-19232 ./doc/sudoers.mdoc.in
+--- ./doc/sudoers.mdoc.in.CVE-2019-19232	2019-10-28 13:28:52.000000000 +0100
++++ ./doc/sudoers.mdoc.in	2020-01-14 15:34:46.908027286 +0100
+@@ -2768,6 +2768,22 @@ when running a command or editing a file
+ This flag is
+ .Em off
+ by default.
++.It runas_allow_unknown_id
++If enabled, allow matching of runas user and group IDs that are
++not present in the password or group databases.
++In addition to explicitly matching unknown user or group IDs in a
++.Li Runas_List ,
++this option also allows the
++.Sy ALL
++alias to match unknown IDs.
++This flag is
++.Em off
++by default.
++.Pp
++This setting is only supported by version 1.8.29 or higher.
++Older versions of
++.Nm sudo
++always allowed matching of unknown user and group IDs.
+ .It runaspw
+ If set,
+ .Nm sudo
+diff -up ./plugins/sudoers/defaults.c.CVE-2019-19232 ./plugins/sudoers/defaults.c
+--- ./plugins/sudoers/defaults.c.CVE-2019-19232	2020-01-14 15:34:46.902027246 +0100
++++ ./plugins/sudoers/defaults.c	2020-01-14 15:34:46.909027293 +0100
+@@ -581,6 +581,7 @@ init_defaults(void)
+     def_fdexec = digest_only;
+     def_log_allowed = true;
+     def_log_denied = true;
++    def_runas_allow_unknown_id = false;
+ 
+     /* Syslog options need special care since they both strings and ints */
+ #if (LOGGING & SLOG_SYSLOG)
+diff -up ./plugins/sudoers/def_data.c.CVE-2019-19232 ./plugins/sudoers/def_data.c
+--- ./plugins/sudoers/def_data.c.CVE-2019-19232	2020-01-14 15:34:46.908027286 +0100
++++ ./plugins/sudoers/def_data.c	2020-01-14 15:40:19.441555509 +0100
+@@ -514,6 +514,10 @@ struct sudo_defs_types sudo_defs_table[]
+ 	N_("Don't fork and wait for the command to finish, just exec it"),
+ 	NULL,
+     }, {
++	"runas_allow_unknown_id", T_FLAG,
++	N_("Allow the use of unknown runas user and/or group ID"),
++	NULL,
++    }, {
+ 	NULL, 0, NULL
+     }
+ };
+diff -up ./plugins/sudoers/def_data.h.CVE-2019-19232 ./plugins/sudoers/def_data.h
+--- ./plugins/sudoers/def_data.h.CVE-2019-19232	2020-01-14 15:34:46.909027293 +0100
++++ ./plugins/sudoers/def_data.h	2020-01-14 15:41:33.658012401 +0100
+@@ -236,6 +236,8 @@
+ #define def_legacy_group_processing (sudo_defs_table[I_LEGACY_GROUP_PROCESSING].sd_un.flag)
+ #define I_CMND_NO_WAIT          118
+ #define def_cmnd_no_wait        (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag)
++#define I_RUNAS_ALLOW_UNKNOWN_ID 119
++#define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag)
+ 
+ enum def_tuple {
+ 	never,
+diff -up ./plugins/sudoers/def_data.in.CVE-2019-19232 ./plugins/sudoers/def_data.in
+--- ./plugins/sudoers/def_data.in.CVE-2019-19232	2020-01-14 15:34:46.909027293 +0100
++++ ./plugins/sudoers/def_data.in	2020-01-14 15:42:42.176481484 +0100
+@@ -372,3 +372,6 @@ legacy_group_processing
+ cmnd_no_wait
+ 	T_FLAG
+ 	"Don't fork and wait for the command to finish, just exec it"
++runas_allow_unknown_id
++	T_FLAG
++	"Allow the use of unknown runas user and/or group ID"
+diff -up ./plugins/sudoers/sudoers.c.CVE-2019-19232 ./plugins/sudoers/sudoers.c
+--- ./plugins/sudoers/sudoers.c.CVE-2019-19232	2020-01-14 15:34:46.905027266 +0100
++++ ./plugins/sudoers/sudoers.c	2020-01-14 15:34:46.910027299 +0100
+@@ -105,6 +105,8 @@ static char *prev_user;
+ static char *runas_user;
+ static char *runas_group;
+ static struct sudo_nss_list *snl;
++static bool unknown_runas_uid;
++static bool unknown_runas_gid;
+ 
+ #ifdef __linux__
+ static struct rlimit nproclimit;
+@@ -354,6 +356,22 @@ sudoers_policy_main(int argc, char * con
+ 	}
+     }
+ 
++    /* Defer uid/gid checks until after defaults have been updated. */
++    if (unknown_runas_uid && !def_runas_allow_unknown_id) {
++	audit_failure(NewArgc, NewArgv, N_("unknown user: %s"),
++	    runas_pw->pw_name);
++	sudo_warnx(U_("unknown user: %s"), runas_pw->pw_name);
++	goto done;
++    }
++    if (runas_gr != NULL) {
++	if (unknown_runas_gid && !def_runas_allow_unknown_id) {
++	    audit_failure(NewArgc, NewArgv, N_("unknown group: %s"),
++		runas_gr->gr_name);
++	    sudo_warnx(U_("unknown group: %s"), runas_gr->gr_name);
++	    goto done;
++	}
++    }
++
+     /*
+      * Look up the timestamp dir owner if one is specified.
+      */
+@@ -1167,12 +1185,15 @@ set_runaspw(const char *user, bool quiet
+     struct passwd *pw = NULL;
+     debug_decl(set_runaspw, SUDOERS_DEBUG_PLUGIN)
+ 
++    unknown_runas_uid = false;
+     if (*user == '#') {
+ 	const char *errstr;
+ 	uid_t uid = sudo_strtoid(user + 1, &errstr);
+ 	if (errstr == NULL) {
+-	    if ((pw = sudo_getpwuid(uid)) == NULL)
++	    if ((pw = sudo_getpwuid(uid)) == NULL) {
++		unknown_runas_uid = true;
+ 		pw = sudo_fakepwnam(user, user_gid);
++	    }
+ 	}
+     }
+     if (pw == NULL) {
+@@ -1198,12 +1219,15 @@ set_runasgr(const char *group, bool quie
+     struct group *gr = NULL;
+     debug_decl(set_runasgr, SUDOERS_DEBUG_PLUGIN)
+ 
++    unknown_runas_gid = false;
+     if (*group == '#') {
+ 	const char *errstr;
+ 	gid_t gid = sudo_strtoid(group + 1, &errstr);
+ 	if (errstr == NULL) {
+-	    if ((gr = sudo_getgrgid(gid)) == NULL)
++	    if ((gr = sudo_getgrgid(gid)) == NULL) {
++		unknown_runas_gid = true;
+ 		gr = sudo_fakegrnam(group);
++	    }
+ 	}
+     }
+     if (gr == NULL) {
diff --git a/SOURCES/sudo-1.8.29-CVE-2019-19234.patch b/SOURCES/sudo-1.8.29-CVE-2019-19234.patch
new file mode 100644
index 0000000..264db7f
--- /dev/null
+++ b/SOURCES/sudo-1.8.29-CVE-2019-19234.patch
@@ -0,0 +1,439 @@
+diff -up ./config.h.in.CVE-2019-19234 ./config.h.in
+--- ./config.h.in.CVE-2019-19234	2019-10-28 13:28:52.000000000 +0100
++++ ./config.h.in	2020-01-14 15:53:40.506988064 +0100
+@@ -334,6 +334,9 @@
+ /* Define to 1 if you have the `getuserattr' function. */
+ #undef HAVE_GETUSERATTR
+ 
++/* Define to 1 if you have the `getusershell' function. */
++#undef HAVE_GETUSERSHELL
++
+ /* Define to 1 if you have the `getutid' function. */
+ #undef HAVE_GETUTID
+ 
+diff -up ./configure.ac.CVE-2019-19234 ./configure.ac
+--- ./configure.ac.CVE-2019-19234	2020-01-14 15:53:40.496987995 +0100
++++ ./configure.ac	2020-01-14 15:53:40.509988084 +0100
+@@ -2562,6 +2562,10 @@ AC_CHECK_FUNCS([getdelim], [], [
+     SUDO_APPEND_COMPAT_EXP(sudo_getdelim)
+     COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }getdelim_test"
+ ])
++AC_CHECK_FUNCS([getusershell], [], [
++    AC_LIBOBJ(getusershell)
++    SUDO_APPEND_COMPAT_EXP(sudo_getusershell)
++])
+ AC_CHECK_FUNCS([reallocarray], [], [
+     AC_LIBOBJ(reallocarray)
+     SUDO_APPEND_COMPAT_EXP(sudo_reallocarray)
+diff -up ./configure.CVE-2019-19234 ./configure
+--- ./configure.CVE-2019-19234	2019-10-28 13:29:14.000000000 +0100
++++ ./configure	2020-01-14 15:53:40.509988084 +0100
+@@ -19395,6 +19395,32 @@ esac
+ fi
+ done
+ 
++for ac_func in getusershell
++do :
++  ac_fn_c_check_func "$LINENO" "getusershell" "ac_cv_func_getusershell"
++if test "x$ac_cv_func_getusershell" = xyes; then :
++  cat >>confdefs.h <<_ACEOF
++#define HAVE_GETUSERSHELL 1
++_ACEOF
++
++else
++
++    case " $LIBOBJS " in
++  *" getusershell.$ac_objext "* ) ;;
++  *) LIBOBJS="$LIBOBJS getusershell.$ac_objext"
++ ;;
++esac
++
++
++    for _sym in sudo_getusershell; do
++	COMPAT_EXP="${COMPAT_EXP}${_sym}
++"
++    done
++
++
++fi
++done
++
+ for ac_func in reallocarray
+ do :
+   ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray"
+diff -up ./doc/sudoers.man.in.CVE-2019-19234 ./doc/sudoers.man.in
+--- ./doc/sudoers.man.in.CVE-2019-19234	2020-01-14 15:53:40.503988043 +0100
++++ ./doc/sudoers.man.in	2020-01-14 15:53:40.510988091 +0100
+@@ -2959,6 +2959,28 @@ Older versions of
+ \fBsudo\fR
+ always allowed matching of unknown user and group IDs.
+ .TP 18n
++runas_check_shell
++.br
++If enabled,
++\fBsudo\fR
++will only run commands as a user whose shell appears in the
++\fI/etc/shells\fR
++file, even if the invoking user's
++\fRRunas_List\fR
++would otherwise permit it.
++If no
++\fI/etc/shells\fR
++file is present, a system-dependent list of built-in default shells is used.
++On many operating systems, system users such as
++\(lqbin\(rq,
++do not have a valid shell and this flag can be used to prevent
++commands from being run as those users.
++This flag is
++\fIoff\fR
++by default.
++.sp
++This setting is only supported by version 1.8.29 or higher.
++.TP 18n
+ runaspw
+ If set,
+ \fBsudo\fR
+diff -up ./doc/sudoers.mdoc.in.CVE-2019-19234 ./doc/sudoers.mdoc.in
+--- ./doc/sudoers.mdoc.in.CVE-2019-19234	2020-01-14 15:53:40.504988050 +0100
++++ ./doc/sudoers.mdoc.in	2020-01-14 15:53:40.510988091 +0100
+@@ -2784,6 +2784,26 @@ This setting is only supported by versio
+ Older versions of
+ .Nm sudo
+ always allowed matching of unknown user and group IDs.
++.It runas_check_shell
++If enabled,
++.Nm sudo
++will only run commands as a user whose shell appears in the
++.Pa /etc/shells
++file, even if the invoking user's
++.Li Runas_List
++would otherwise permit it.
++If no
++.Pa /etc/shells
++file is present, a system-dependent list of built-in default shells is used.
++On many operating systems, system users such as
++.Dq bin ,
++do not have a valid shell and this flag can be used to prevent
++commands from being run as those users.
++This flag is
++.Em off
++by default.
++.Pp
++This setting is only supported by version 1.8.29 or higher.
+ .It runaspw
+ If set,
+ .Nm sudo
+diff -up ./include/sudo_compat.h.CVE-2019-19234 ./include/sudo_compat.h
+--- ./include/sudo_compat.h.CVE-2019-19234	2019-10-28 13:28:52.000000000 +0100
++++ ./include/sudo_compat.h	2020-01-14 15:53:40.511988098 +0100
+@@ -407,6 +407,17 @@ __dso_public ssize_t sudo_getdelim(char
+ # undef getdelim
+ # define getdelim(_a, _b, _c, _d) sudo_getdelim((_a), (_b), (_c), (_d))
+ #endif /* HAVE_GETDELIM */
++#ifndef HAVE_GETUSERSHELL
++__dso_public char *sudo_getusershell(void);
++# undef getusershell
++# define getusershell() sudo_getusershell()
++__dso_public void sudo_setusershell(void);
++# undef setusershell
++# define setusershell() sudo_setusershell()
++__dso_public void sudo_endusershell(void);
++# undef endusershell
++# define endusershell() sudo_endusershell()
++#endif /* HAVE_GETUSERSHELL */
+ #ifndef HAVE_UTIMENSAT
+ __dso_public int sudo_utimensat(int fd, const char *file, const struct timespec *times, int flag);
+ # undef utimensat
+diff -up ./lib/util/getusershell.c.CVE-2019-19234 ./lib/util/getusershell.c
+--- ./lib/util/getusershell.c.CVE-2019-19234	2020-01-14 15:53:40.511988098 +0100
++++ ./lib/util/getusershell.c	2020-01-14 15:53:40.511988098 +0100
+@@ -0,0 +1,138 @@
++/*
++ * SPDX-License-Identifier: ISC
++ *
++ * Copyright (c) 2019 Todd C. Miller <Todd.Miller@courtesan.com>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * This is an open source non-commercial project. Dear PVS-Studio, please check it.
++ * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
++ */
++
++#include <config.h>
++
++#include <sys/types.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <ctype.h>
++#include <errno.h>
++
++#define DEFAULT_TEXT_DOMAIN     "sudo"
++#include "sudo_gettext.h"       /* must be included before sudo_compat.h */
++
++#include "sudo_compat.h"
++#include "sudo_debug.h"
++#include "sudo_util.h"
++
++static char **allowed_shells, **current_shell;
++static char *default_shells[] = {
++    "/bin/sh",
++    "/bin/ksh",
++    "/bin/ksh93",
++    "/bin/bash",
++    "/bin/dash",
++    "/bin/zsh",
++    "/bin/csh",
++    "/bin/tcsh",
++    NULL
++};
++
++static char **
++read_shells(void)
++{
++    size_t maxshells = 16, nshells = 0;
++    size_t linesize = 0;
++    char *line = NULL;
++    FILE *fp;
++    debug_decl(read_shells, SUDO_DEBUG_UTIL)
++
++    if ((fp = fopen("/etc/shells", "r")) == NULL)
++	goto bad;
++
++    free(allowed_shells);
++    allowed_shells = reallocarray(NULL, maxshells, sizeof(char *));
++    if (allowed_shells == NULL)
++	goto bad;
++
++    while (sudo_parseln(&line, &linesize, NULL, fp, PARSELN_CONT_IGN) != -1) {
++	if (nshells + 1 >= maxshells) {
++	    char **new_shells;
++
++	    new_shells = reallocarray(NULL, maxshells + 16, sizeof(char *));
++	    if (new_shells == NULL)
++		goto bad;
++	    allowed_shells = new_shells;
++	    maxshells += 16;
++	}
++	if ((allowed_shells[nshells] = strdup(line)) == NULL)
++	    goto bad;
++	nshells++;
++    }
++    allowed_shells[nshells] = NULL;
++
++    free(line);
++    fclose(fp);
++    debug_return_ptr(allowed_shells);
++bad:
++    free(line);
++    if (fp != NULL)
++	fclose(fp);
++    while (nshells != 0)
++	free(allowed_shells[--nshells]);
++    free(allowed_shells);
++    allowed_shells = NULL;
++    debug_return_ptr(default_shells);
++}
++
++void
++sudo_setusershell(void)
++{
++    debug_decl(setusershell, SUDO_DEBUG_UTIL)
++
++    current_shell = read_shells();
++
++    debug_return;
++}
++
++void
++sudo_endusershell(void)
++{
++    debug_decl(endusershell, SUDO_DEBUG_UTIL)
++
++    if (allowed_shells != NULL) {
++	char **shell;
++
++	for (shell = allowed_shells; *shell != NULL; shell++)
++	    free(*shell);
++	free(allowed_shells);
++	allowed_shells = NULL;
++    }
++    current_shell = NULL;
++
++    debug_return;
++}
++
++char *
++sudo_getusershell(void)
++{
++    debug_decl(getusershell, SUDO_DEBUG_UTIL)
++
++    if (current_shell == NULL)
++	current_shell = read_shells();
++
++    debug_return_str(*current_shell++);
++}
+diff -up ./lib/util/Makefile.in.CVE-2019-19234 ./lib/util/Makefile.in
+--- ./lib/util/Makefile.in.CVE-2019-19234	2019-10-28 13:28:53.000000000 +0100
++++ ./lib/util/Makefile.in	2020-01-14 15:53:40.511988098 +0100
+@@ -678,6 +678,18 @@ gettime.i: $(srcdir)/gettime.c $(incdir)
+ 	$(CC) -E -o $@ $(CPPFLAGS) $<
+ gettime.plog: gettime.i
+ 	rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/gettime.c --i-file $< --output-file $@
++getusershell.lo: $(srcdir)/getusershell.c $(incdir)/compat/stdbool.h \
++                 $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
++                 $(incdir)/sudo_gettext.h $(incdir)/sudo_queue.h \
++                 $(incdir)/sudo_util.h $(top_builddir)/config.h
++	$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/getusershell.c
++getusershell.i: $(srcdir)/getusershell.c $(incdir)/compat/stdbool.h \
++                 $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
++                 $(incdir)/sudo_gettext.h $(incdir)/sudo_queue.h \
++                 $(incdir)/sudo_util.h $(top_builddir)/config.h
++	$(CC) -E -o $@ $(CPPFLAGS) $<
++getusershell.plog: getusershell.i
++	rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/getusershell.c --i-file $< --output-file $@
+ gidlist.lo: $(srcdir)/gidlist.c $(incdir)/compat/stdbool.h \
+             $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
+             $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
+diff -up ./MANIFEST.CVE-2019-19234 ./MANIFEST
+--- ./MANIFEST.CVE-2019-19234	2019-10-28 13:28:52.000000000 +0100
++++ ./MANIFEST	2020-01-14 15:53:40.506988064 +0100
+@@ -103,6 +103,7 @@ lib/util/getgrouplist.c
+ lib/util/gethostname.c
+ lib/util/getopt_long.c
+ lib/util/gettime.c
++lib/util/getusershell.c
+ lib/util/gidlist.c
+ lib/util/glob.c
+ lib/util/inet_ntop.c
+diff -up ./mkdep.pl.CVE-2019-19234 ./mkdep.pl
+--- ./mkdep.pl.CVE-2019-19234	2019-10-28 13:28:52.000000000 +0100
++++ ./mkdep.pl	2020-01-14 15:53:40.511988098 +0100
+@@ -116,7 +116,7 @@ sub mkdep {
+     # XXX - fill in AUTH_OBJS from contents of the auth dir instead
+     $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:;
+     $makefile =~ s:\@DIGEST\@:digest.lo digest_openssl.lo digest_gcrypt.lo:;
+-    $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:;
++    $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo getusershell.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo utimens.lo vsyslog.lo pipe2.lo:;
+ 
+     # Parse OBJS lines
+     my %objs;
+diff -up ./plugins/sudoers/check.c.CVE-2019-19234 ./plugins/sudoers/check.c
+--- ./plugins/sudoers/check.c.CVE-2019-19234	2019-10-28 13:27:45.000000000 +0100
++++ ./plugins/sudoers/check.c	2020-01-14 15:53:40.511988098 +0100
+@@ -333,3 +333,28 @@ get_authpw(int mode)
+ 
+     debug_return_ptr(pw);
+ }
++
++/*
++ * Returns true if the specified shell is allowed by /etc/shells, else false.
++ */
++bool
++check_user_shell(const struct passwd *pw)
++{
++    const char *shell;
++    debug_decl(check_user_shell, SUDOERS_DEBUG_AUTH)
++
++    if (!def_runas_check_shell)
++	debug_return_bool(true);
++
++    sudo_debug_printf(SUDO_DEBUG_INFO,
++	"%s: checking /etc/shells for %s", __func__, pw->pw_shell);
++
++    setusershell();
++    while ((shell = getusershell()) != NULL) {
++	if (strcmp(shell, pw->pw_shell) == 0)
++	    debug_return_bool(true);
++    }
++    endusershell();
++
++    debug_return_bool(false);
++}
+diff -up ./plugins/sudoers/def_data.c.CVE-2019-19234 ./plugins/sudoers/def_data.c
+--- ./plugins/sudoers/def_data.c.CVE-2019-19234	2020-01-14 15:53:40.504988050 +0100
++++ ./plugins/sudoers/def_data.c	2020-01-14 15:53:40.511988098 +0100
+@@ -518,6 +518,10 @@ struct sudo_defs_types sudo_defs_table[]
+ 	N_("Allow the use of unknown runas user and/or group ID"),
+ 	NULL,
+     }, {
++	"runas_check_shell", T_FLAG,
++	N_("Only permit running commands as a user with a valid shell"),
++	NULL,
++    }, {
+ 	NULL, 0, NULL
+     }
+ };
+diff -up ./plugins/sudoers/def_data.h.CVE-2019-19234 ./plugins/sudoers/def_data.h
+--- ./plugins/sudoers/def_data.h.CVE-2019-19234	2020-01-14 15:53:40.512988105 +0100
++++ ./plugins/sudoers/def_data.h	2020-01-14 15:58:06.927808982 +0100
+@@ -238,6 +238,8 @@
+ #define def_cmnd_no_wait        (sudo_defs_table[I_CMND_NO_WAIT].sd_un.flag)
+ #define I_RUNAS_ALLOW_UNKNOWN_ID 119
+ #define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag)
++#define I_RUNAS_CHECK_SHELL     120
++#define def_runas_check_shell   (sudo_defs_table[I_RUNAS_CHECK_SHELL].sd_un.flag)
+ 
+ enum def_tuple {
+ 	never,
+diff -up ./plugins/sudoers/def_data.in.CVE-2019-19234 ./plugins/sudoers/def_data.in
+--- ./plugins/sudoers/def_data.in.CVE-2019-19234	2020-01-14 15:53:40.505988057 +0100
++++ ./plugins/sudoers/def_data.in	2020-01-14 15:53:40.512988105 +0100
+@@ -375,3 +375,7 @@ cmnd_no_wait
+ runas_allow_unknown_id
+ 	T_FLAG
+ 	"Allow the use of unknown runas user and/or group ID"
++runas_check_shell
++	T_FLAG
++	"Only permit running commands as a user with a valid shell"
++
+diff -up ./plugins/sudoers/sudoers.c.CVE-2019-19234 ./plugins/sudoers/sudoers.c
+--- ./plugins/sudoers/sudoers.c.CVE-2019-19234	2020-01-14 15:53:40.505988057 +0100
++++ ./plugins/sudoers/sudoers.c	2020-01-14 15:53:40.512988105 +0100
+@@ -273,7 +273,7 @@ sudoers_policy_main(int argc, char * con
+ 	/* Not an audit event. */
+ 	sudo_warnx(U_("sudoers specifies that root is not allowed to sudo"));
+ 	goto bad;
+-    }    
++    }
+ 
+     if (!set_perms(PERM_INITIAL))
+ 	goto bad;
+@@ -412,6 +412,13 @@ sudoers_policy_main(int argc, char * con
+ 	goto bad;
+     }
+ 
++    /* Check runas user's shell. */
++    if (!check_user_shell(runas_pw)) {
++	log_warningx(SLOG_RAW_MSG, N_("invalid shell for user %s: %s"),
++	    runas_pw->pw_name, runas_pw->pw_shell);
++	goto bad;
++    }
++
+     /*
+      * We don't reset the environment for sudoedit or if the user
+      * specified the -E command line flag and they have setenv privs.
+diff -up ./plugins/sudoers/sudoers.h.CVE-2019-19234 ./plugins/sudoers/sudoers.h
+--- ./plugins/sudoers/sudoers.h.CVE-2019-19234	2020-01-14 15:53:40.502988036 +0100
++++ ./plugins/sudoers/sudoers.h	2020-01-14 15:53:40.512988105 +0100
+@@ -264,6 +264,7 @@ int find_path(const char *infile, char *
+ 
+ /* check.c */
+ int check_user(int validate, int mode);
++bool check_user_shell(const struct passwd *pw);
+ bool user_is_exempt(void);
+ 
+ /* prompt.c */
diff --git a/SPECS/sudo.spec b/SPECS/sudo.spec
index 6cf7ccd..0c1b27e 100644
--- a/SPECS/sudo.spec
+++ b/SPECS/sudo.spec
@@ -1,7 +1,7 @@
 Summary: Allows restricted root access for specified users
 Name: sudo
-Version: 1.8.25p1
-Release: 8%{?dist}.1
+Version: 1.8.29
+Release: 5%{?dist}
 License: ISC
 Group: Applications/System
 URL: http://www.courtesan.com/sudo/
@@ -39,44 +39,18 @@ Patch2: sudo-1.8.23-sudoldapconfman.patch
 Patch3: sudo-1.7.2p1-envdebug.patch
 # 1247591 - Sudo taking a long time when user information is stored externally.
 Patch4: sudo-1.8.23-legacy-group-processing.patch
-# 1135539 - sudo with ldap doesn't work with 'user id' in sudoUser option
-Patch5: sudo-1.8.23-ldapsearchuidfix.patch
 # 840980 - sudo creates a new parent process
 # Adds cmnd_no_wait Defaults option
-Patch6: sudo-1.8.23-nowaitopt.patch
+Patch5: sudo-1.8.23-nowaitopt.patch
 # 1312486 - RHEL7 sudo logs username "root" instead of realuser in /var/log/secure
-Patch7: sudo-1.8.6p7-logsudouser.patch
-# 1547974 - (sudo-rhel-7.6-rebase) Rebase sudo to latest stable upstream version
-Patch8: sudo-1.8.23-fix-double-quote-parsing-for-Defaults-values.patch
-# 1613327 - Man page scan results for sudo
-Patch9: sudo-1.8.25-typos-manpages.patch
-Patch10: sudo-1.8.25-c-option-help.patch
-Patch11: sudo-1.8.25-sudoreplay-missing-options-help.patch
-
-# RHEL 8.1
-# 1673886 - Problem with sudo-1.8.23 and 'who am i'
-Patch12: sudo-1.8.23-who-am-i.patch
-# 1676819 - Backporting sudo bug with expired passwords
-Patch13: sudo-1.8.23-pam-expired-passwords.patch
-# 1738326 - The LDAP backend is not properly parsing sudoOptions, resulting in
-# selinux roles not being applied
-# https://www.sudo.ws/repos/sudo/rev/10f8cff7cce7
-Patch14: sudo-1.8.25-ldap-backend-parsing-1.patch
-# 1738326 - The LDAP backend is not properly parsing sudoOptions, resulting in
-# selinux roles not being applied
-# https://www.sudo.ws/repos/sudo/rev/ba6cfd26330e
-Patch15: sudo-1.8.25-ldap-backend-parsing-2.patch
-# 738662 - sudo ipa_hostname not honored
-# Fix special handling of ipa_hostname that was lost in sudo
-Patch16: sudo-1.8.25-ipa-hostname.patch
-
-# 1760696 - CVE-2019-14287 sudo: Privilege escalation via 'Runas' specification with 'ALL' keyword [rhel-7.8]
-Patch17: sudo-1.8.28-CVE-strtouid.patch
-Patch18: sudo-1.8.28-CVE-strtouid-test.patch
-
-# 1798092 - CVE-2019-18634 sudo: Stack based buffer overflow in when pwfeedback is enabled [rhel-8.1.0.z]
-Patch19: sudo-1.8.29-CVE-2019-18634-part1.patch
-Patch20: sudo-1.8.29-CVE-2019-18634-part2.patch
+Patch6: sudo-1.8.6p7-logsudouser.patch
+# 1786987 - CVE-2019-19232 sudo: attacker with access to a Runas ALL sudoer account
+# can impersonate a nonexistent user [rhel-8]
+Patch7: sudo-1.8.29-CVE-2019-19232.patch
+# 1796518 - [RFE] add optional check for the target user shell
+Patch8: sudo-1.8.29-CVE-2019-19234.patch
+# 1798093 - CVE-2019-18634 sudo: Stack based buffer overflow in when pwfeedback is enabled [rhel-8.2.0]
+Patch9: sudo-1.8.29-CVE-2019-18634.patch
 
 %description
 Sudo (superuser do) allows a system administrator to give certain
@@ -105,26 +79,11 @@ plugins that use %{name}.
 %patch2 -p1 -b .sudoldapconfman
 %patch3 -p1 -b .env-debug
 %patch4 -p1 -b .legacy-processing
-%patch5 -p1 -b .ldap-search-uid
-%patch6 -p1 -b .nowait
-%patch7 -p1 -b .logsudouser
-%patch8 -p1 -b .double-quote
-
-%patch9 -p1 -b .typos
-%patch10 -p1 -b .c-option
-%patch11 -p1 -b .sudoreplay-help
-
-%patch12 -p1 -b .whoami
-%patch13 -p1 -b .pam-expired
-%patch14 -p1 -b .ldap-backend1
-%patch15 -p1 -b .ldap-backend2
-%patch16 -p1 -b .ipa-hostname
-
-%patch17 -p1 -b .cve-strtouid
-%patch18 -p1 -b .cve-strtouid-test
-
-%patch19 -p1 -b .CVE-2019-18634-part1
-%patch20 -p1 -b .CVE-2019-18634-part2
+%patch5 -p1 -b .nowait
+%patch6 -p1 -b .logsudouser
+%patch7 -p1 -b .CVE-2019-19232
+%patch8 -p1 -b .target-shell
+%patch9 -p1 -b .CVE-2019-18634
 
 %build
 # Remove bundled copy of zlib
@@ -284,15 +243,36 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/sudo_plugin.8*
 
 %changelog
-* Wed Feb 05 2020 Radovan Sroka <rsroka@redhat.com> - 1.8.25p1-8.1
-- RHEL 8.1.0.Z ERRATUM
+* Wed Feb 05 2020 Radovan Sroka <rsroka@redhat.com> - 1.8.29-5
+- RHEL 8.2 ERRATUM
 - CVE-2019-18634
-Resolves: rhbz#1798092
-
-* Fri Oct 18 2019 Marek Tamaskovic <mtamasko@redhat.com> - 1.8.25p1-8
-- RHEL-8.1.0
-- fixed CVE-2019-14287
-  Resolves: rhbz#1760696
+Resolves: rhbz#1798093
+
+* Tue Jan 14 2020 Radovan Sroka <rsroka@redhat.com> - 1.8.29-4
+- RHEL 8.2 ERRATUM
+- CVE-2019-19232
+Resolves: rhbz#1786987
+Resolves: rhbz#1796518
+
+* Wed Oct 30 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.29-2
+- RHEL 8.2 ERRATUM
+- rebase to 1.8.29
+Resolves: rhbz#1733961
+Resolves: rhbz#1651662
+
+* Fri Oct 25 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.28p1-1
+- RHEL 8.2 ERRATUM
+- rebase to 1.8.28p1
+Resolves: rhbz#1733961
+- fixed man page for always_set_home
+Resolves: rhbz#1576880
+- sudo does not work with notbefore/after
+Resolves: rhbz#1679508
+- NOTBEFORE showing value of sudoNotAfter Ldap attribute
+Resolves: rhbz#1715516
+- CVE-2019-14287 sudo
+- Privilege escalation via 'Runas' specification with 'ALL' keyword
+Resolves: rhbz#1760697
 
 * Fri Aug 16 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.25-7
 - RHEL 8.1 ERRATUM