diff --git a/SOURCES/sudo-1.8.23-pam-expired-passwords.patch b/SOURCES/sudo-1.8.23-pam-expired-passwords.patch
new file mode 100644
index 0000000..bf2078a
--- /dev/null
+++ b/SOURCES/sudo-1.8.23-pam-expired-passwords.patch
@@ -0,0 +1,103 @@
+
+# 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
new file mode 100644
index 0000000..2be1c3c
--- /dev/null
+++ b/SOURCES/sudo-1.8.23-who-am-i.patch
@@ -0,0 +1,56 @@
+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-ipa-hostname.patch b/SOURCES/sudo-1.8.25-ipa-hostname.patch
new file mode 100644
index 0000000..4186974
--- /dev/null
+++ b/SOURCES/sudo-1.8.25-ipa-hostname.patch
@@ -0,0 +1,1063 @@
+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.28-CVE-strtouid-test.patch b/SOURCES/sudo-1.8.28-CVE-strtouid-test.patch
new file mode 100644
index 0000000..0ae387a
--- /dev/null
+++ b/SOURCES/sudo-1.8.28-CVE-strtouid-test.patch
@@ -0,0 +1,96 @@
+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
new file mode 100644
index 0000000..dbf9db7
--- /dev/null
+++ b/SOURCES/sudo-1.8.28-CVE-strtouid.patch
@@ -0,0 +1,172 @@
+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/SPECS/sudo.spec b/SPECS/sudo.spec
index 4e18ed9..e550d0d 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: 4%{?dist}.1
+Release: 8%{?dist}
 License: ISC
 Group: Applications/System
 URL: http://www.courtesan.com/sudo/
@@ -53,14 +53,26 @@ 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
-Patch12: sudo-1.8.25-ldap-backend-parsing-1.patch
+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
-Patch13: sudo-1.8.25-ldap-backend-parsing-2.patch
+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
 
 %description
 Sudo (superuser do) allows a system administrator to give certain
@@ -98,8 +110,14 @@ plugins that use %{name}.
 %patch10 -p1 -b .c-option
 %patch11 -p1 -b .sudoreplay-help
 
-%patch12 -p1 -b .ldap-backend1
-%patch13 -p1 -b .ldap-backend2
+%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
 
 %build
 # Remove bundled copy of zlib
@@ -259,18 +277,36 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/sudo_plugin.8*
 
 %changelog
-* Mon Aug 19 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.25-4.1
-- RHEL 8.0.0z ERRATUM
+* Fri Oct 18 2019 Marek Tamaskovic <mtamasko@redhat.com> - 1.8.25p1-8
+- RHEL-8.1.0
+- fixed CVE-2019-14287
+  Resolves: rhbz#1760696
+
+
+* Fri Aug 16 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.25-7
+- RHEL 8.1 ERRATUM
+- sudo ipa_hostname not honored
+Resolves: rhbz#1738662
+
+* Mon Aug 12 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.25-6
+- RHEL 8.1 ERRATUM
 - Fixed The LDAP backend which is not properly parsing sudoOptions,
   resulting in selinux roles not being applied
-Resolves: rhbz#1743168
+Resolves: rhbz#1738326
+
+* Tue May 28 2019 Radovan Sroka <rsroka@redhat.com> - 1.8.25-5
+- RHEL 8.1 ERRATUM
+- Fixed problem with sudo-1.8.23 and 'who am i'
+Resolves: rhbz#1673886
+- Backporting sudo bug with expired passwords
+Resolves: rhbz#1676819
 
 * Tue Dec 11 2018 Radovan Sroka <rsroka@redhat.com> - 1.8.25-4
 - Fix most of the man page scans problems
 - Resolves: rhbz#1613327
 
 * Fri Oct 12 2018 Daniel Kopecek <dkopecek@redhat.com> - 1.8.25-3
-- bump release for new build after gating tests fixes
+- bump release for new build
 Resolves: rhbz#1625683
 
 * Thu Oct 11 2018 Daniel Kopecek <dkopecek@redhat.com> - 1.8.25-2
@@ -300,7 +336,7 @@ Resolves: rhbz#1633144
 
 * Thu Sep 21 2017 Marek Tamaskovic <mtamasko@redhat.com> - 1.8.21p2-1
 - update to 1.8.21p2
-- Moved libsudo_util.so from the -devel sub-package to main package (1481225) 
+- Moved libsudo_util.so from the -devel sub-package to main package (1481225)
 
 * Wed Sep 06 2017 Matthew Miller <mattdm@fedoraproject.org> - 1.8.20p2-4
 - replace file-based requirements with package-level ones:
@@ -389,7 +425,7 @@ Resolves: rhbz#1633144
 
 * Mon Aug 24 2015 Radovan Sroka <rsroka@redhat.com> 1.8.14p3-2
 - add patch that resolves initialization problem before sudo_strsplit call
-- add patch that resolves deadcode in visudo.c 
+- add patch that resolves deadcode in visudo.c
 - add patch that removes extra while in visudo.c and sudoers.c
 
 * Mon Jul 27 2015 Radovan Sroka <rsroka@redhat.com> 1.8.14p3-1
@@ -425,9 +461,9 @@ Resolves: rhbz#1633144
 - major changes & fixes:
   - when running a command in the background, sudo will now forward
     SIGINFO to the command
-  - the passwords in ldap.conf and ldap.secret may now be encoded in base64. 
+  - the passwords in ldap.conf and ldap.secret may now be encoded in base64.
   - SELinux role changes are now audited. For sudoedit, we now audit
-    the actual editor being run, instead of just the sudoedit command. 
+    the actual editor being run, instead of just the sudoedit command.
   - it is now possible to match an environment variable's value as well as
     its name using env_keep and env_check
   - new files created via sudoedit as a non-root user now have the proper group id
@@ -527,7 +563,7 @@ Resolves: rhbz#1633144
 * Thu May 17 2012 Daniel Kopecek <dkopecek@redhat.com> - 1.8.5-1
 - update to 1.8.5
 - fixed CVE-2012-2337
-- temporarily disabled SSSD support 
+- temporarily disabled SSSD support
 
 * Wed Feb 29 2012 Daniel Kopecek <dkopecek@redhat.com> - 1.8.3p1-6
 - fixed problems with undefined symbols (rhbz#798517)
@@ -546,7 +582,7 @@ Resolves: rhbz#1633144
 
 * Thu Nov 10 2011 Daniel Kopecek <dkopecek@redhat.com> - 1.8.3p1-1
 - update to 1.8.3p1
-- disable output word wrapping if the output is piped 
+- disable output word wrapping if the output is piped
 
 * Wed Sep  7 2011 Peter Robinson <pbrobinson@fedoraproject.org> - 1.8.1p2-2
 - Remove execute bit from sample script in docs so we don't pull in perl
@@ -681,7 +717,7 @@ Resolves: rhbz#1633144
 - sparc64 needs to be in the -fPIE list with s390
 
 * Mon Jan 07 2008 Peter Vrabec <pvrabec@redhat.com> 1.6.9p4-5
-- fix complains about audit_log_user_command(): Connection 
+- fix complains about audit_log_user_command(): Connection
   refused (#401201)
 
 * Wed Dec 05 2007 Release Engineering <rel-eng at fedoraproject dot org> - 1.6.9p4-4
@@ -783,7 +819,7 @@ Resolves: rhbz#1633144
 - rebuild
 
 * Mon Oct  4 2004 Thomas Woerner <twoerner@redhat.com> 1.6.7p5-30.1
-- added missing BuildRequires for libselinux-devel (#132883) 
+- added missing BuildRequires for libselinux-devel (#132883)
 
 * Wed Sep 29 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-30
 - Fix missing param error in sesh
@@ -810,7 +846,7 @@ Resolves: rhbz#1633144
   exec of child with SELinux patch
 
 * Thu Mar 18 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-23
-- change to default to sysadm_r 
+- change to default to sysadm_r
 - Fix tty handling
 
 * Thu Mar 18 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-22
@@ -818,7 +854,7 @@ Resolves: rhbz#1633144
 - replace /bin/bash -c with /bin/sesh
 
 * Tue Mar 16 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-21
-- Hard code to use "/bin/bash -c" for selinux 
+- Hard code to use "/bin/bash -c" for selinux
 
 * Tue Mar 16 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-20
 - Eliminate closing and reopening of terminals, to match su.
@@ -843,7 +879,7 @@ Resolves: rhbz#1633144
 - Fix is_selinux_enabled call
 
 * Tue Jan 13 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-13
-- Clean up patch on failure 
+- Clean up patch on failure
 
 * Tue Jan 6 2004 Dan Walsh <dwalsh@redhat.com> 1.6.7p5-12
 - Remove sudo.te for now.
@@ -966,7 +1002,7 @@ Resolves: rhbz#1633144
 - fixed so it doesn't find /usr/bin/vi first, but instead /bin/vi (always installed)
 
 * Thu Oct 08 1998 Michael Maher <mike@redhat.com>
-- built package for 5.2 
+- built package for 5.2
 
 * Mon May 18 1998 Michael Maher <mike@redhat.com>
 - updated SPEC file
@@ -978,10 +1014,9 @@ Resolves: rhbz#1633144
 - built for glibc, no problems
 
 * Fri Apr 25 1997 Michael Fulbright <msf@redhat.com>
-- Fixed for 4.2 PowerTools 
+- Fixed for 4.2 PowerTools
 - Still need to be pamified
 - Still need to move stmp file to /var/log
 
 * Mon Feb 17 1997 Michael Fulbright <msf@redhat.com>
 - First version for PowerCD.
-