From cf00568d888c90a8c5d06a06283bc87a45992933 Mon Sep 17 00:00:00 2001
From: "Todd C. Miller" <Todd.Miller@sudo.ws>
Date: Sat, 26 Aug 2023 10:32:37 -0600
Subject: [PATCH] Do not rely on the definition of ALLOW/DENY being true/false.

We now explicitly check for ALLOW and DENY when checking return
values and negating values.
---
 plugins/sudoers/cvtsudoers.c |  8 ++--
 plugins/sudoers/match.c      | 87 +++++++++++++++++++++++-------------
 2 files changed, 60 insertions(+), 35 deletions(-)

Index: sudo-1.9.5p2/plugins/sudoers/cvtsudoers.c
===================================================================
--- sudo-1.9.5p2.orig/plugins/sudoers/cvtsudoers.c
+++ sudo-1.9.5p2/plugins/sudoers/cvtsudoers.c
@@ -685,7 +685,7 @@ userlist_matches_filter(struct sudoers_p
 	    pw.pw_uid = (uid_t)-1;
 	    pw.pw_gid = (gid_t)-1;
 
-	    if (user_matches(parse_tree, &pw, m) == true)
+	    if (user_matches(parse_tree, &pw, m) == ALLOW)
 		matched = true;
 	} else {
 	    STAILQ_FOREACH(s, &filters->users, entries) {
@@ -711,7 +711,7 @@ userlist_matches_filter(struct sudoers_p
 		if (pw == NULL)
 		    continue;
 
-		if (user_matches(parse_tree, pw, m) == true)
+		if (user_matches(parse_tree, pw, m) == ALLOW)
 		    matched = true;
 		sudo_pw_delref(pw);
 
@@ -787,7 +787,7 @@ hostlist_matches_filter(struct sudoers_p
 
 	    /* Only need one host in the filter to match. */
 	    /* XXX - can't use netgroup_tuple with NULL pw */
-	    if (host_matches(parse_tree, NULL, lhost, shost, m) == true) {
+	    if (host_matches(parse_tree, NULL, lhost, shost, m) == ALLOW) {
 		matched = true;
 		break;
 	    }
Index: sudo-1.9.5p2/plugins/sudoers/match.c
===================================================================
--- sudo-1.9.5p2.orig/plugins/sudoers/match.c
+++ sudo-1.9.5p2/plugins/sudoers/match.c
@@ -76,31 +76,36 @@ user_matches(struct sudoers_parse_tree *
 
     switch (m->type) {
 	case ALL:
-	    matched = !m->negated;
+	    matched = m->negated ? DENY : ALLOW;
 	    break;
 	case NETGROUP:
 	    if (netgr_matches(m->name,
 		def_netgroup_tuple ? lhost : NULL,
 		def_netgroup_tuple ? shost : NULL, pw->pw_name))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
 	case USERGROUP:
 	    if (usergr_matches(m->name, pw->pw_name, pw))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
 	case ALIAS:
 	    if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) {
 		/* XXX */
-		int rc = userlist_matches(parse_tree, pw, &a->members);
-		if (rc != UNSPEC)
-		    matched = m->negated ? !rc : rc;
+		const int rc = userlist_matches(parse_tree, pw, &a->members);
+		if (rc != UNSPEC) {
+		    if (m->negated) {
+			matched = rc == ALLOW ? DENY : ALLOW;
+		    } else {
+			matched = rc;
+		    }
+		}
 		alias_put(a);
 		break;
 	    }
 	    FALLTHROUGH;
 	case WORD:
 	    if (userpw_matches(m->name, pw->pw_name, pw))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
     }
     debug_return_int(matched);
@@ -164,45 +169,50 @@ runaslist_matches(struct sudoers_parse_t
 	/* If no runas user or runas group listed in sudoers, use default. */
 	if (user_list == NULL && group_list == NULL) {
 	    debug_return_int(userpw_matches(def_runas_default,
-		runas_pw->pw_name, runas_pw));
+		runas_pw->pw_name, runas_pw) ? ALLOW : DENY);
 	}
 
 	if (user_list != NULL) {
 	    TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) {
 		switch (m->type) {
 		    case ALL:
-			user_matched = !m->negated;
+			user_matched = m->negated ? DENY : ALLOW;
 			break;
 		    case NETGROUP:
 			if (netgr_matches(m->name,
 			    def_netgroup_tuple ? lhost : NULL,
 			    def_netgroup_tuple ? shost : NULL,
 			    runas_pw->pw_name))
-			    user_matched = !m->negated;
+			    user_matched = m->negated ? DENY : ALLOW;
 			break;
 		    case USERGROUP:
 			if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
-			    user_matched = !m->negated;
+			    user_matched = m->negated ? DENY : ALLOW;
 			break;
 		    case ALIAS:
 			a = alias_get(parse_tree, m->name, RUNASALIAS);
 			if (a != NULL) {
 			    rc = runaslist_matches(parse_tree, &a->members,
 				&empty, matching_user, NULL);
-			    if (rc != UNSPEC)
-				user_matched = m->negated ? !rc : rc;
+			    if (rc != UNSPEC) {
+				if (m->negated) {
+				    user_matched = rc == ALLOW ? DENY : ALLOW;
+				} else {
+				    user_matched = rc;
+				}
+			    }
 			    alias_put(a);
 			    break;
 			}
 			FALLTHROUGH;
 		    case WORD:
 			if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
-			    user_matched = !m->negated;
+			    user_matched = m->negated ? DENY : ALLOW;
 			break;
 		    case MYSELF:
 			if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) ||
 			    strcmp(user_name, runas_pw->pw_name) == 0)
-			    user_matched = !m->negated;
+			    user_matched = m->negated ? DENY : ALLOW;
 			break;
 		}
 		if (user_matched != UNSPEC) {
@@ -226,22 +236,27 @@ runaslist_matches(struct sudoers_parse_t
 	    TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) {
 		switch (m->type) {
 		    case ALL:
-			group_matched = !m->negated;
+			group_matched = m->negated ? DENY : ALLOW;
 			break;
 		    case ALIAS:
 			a = alias_get(parse_tree, m->name, RUNASALIAS);
 			if (a != NULL) {
 			    rc = runaslist_matches(parse_tree, &empty,
 				&a->members, NULL, matching_group);
-			    if (rc != UNSPEC)
-				group_matched = m->negated ? !rc : rc;
+				if (rc != UNSPEC) {
+				    if (m->negated) {
+					group_matched = rc == ALLOW ? DENY : ALLOW;
+				    } else {
+					group_matched = rc;
+				    }
+				}
 			    alias_put(a);
 			    break;
 			}
 			FALLTHROUGH;
 		    case WORD:
 			if (group_matches(m->name, runas_gr))
-			    group_matched = !m->negated;
+			    group_matched = m->negated ? DENY : ALLOW;
 			break;
 		}
 		if (group_matched != UNSPEC) {
@@ -329,32 +344,37 @@ host_matches(struct sudoers_parse_tree *
 
     switch (m->type) {
 	case ALL:
-	    matched = !m->negated;
+	    matched = m->negated ? DENY : ALLOW;
 	    break;
 	case NETGROUP:
 	    if (netgr_matches(m->name, lhost, shost,
 		def_netgroup_tuple ? pw->pw_name : NULL))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
 	case NTWKADDR:
 	    if (addr_matches(m->name))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
 	case ALIAS:
 	    a = alias_get(parse_tree, m->name, HOSTALIAS);
 	    if (a != NULL) {
 		/* XXX */
-		int rc = hostlist_matches_int(parse_tree, pw, lhost, shost,
-		    &a->members);
-		if (rc != UNSPEC)
-		    matched = m->negated ? !rc : rc;
+		const int rc = hostlist_matches_int(parse_tree, pw, lhost,
+		    shost, &a->members);
+		if (rc != UNSPEC) {
+		    if (m->negated) {
+			matched = rc == ALLOW ? DENY : ALLOW;
+		    } else {
+			matched = rc;
+		    }
+		}
 		alias_put(a);
 		break;
 	    }
 	    FALLTHROUGH;
 	case WORD:
 	    if (hostname_matches(shost, lhost, m->name))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
     }
     debug_return_int(matched);
@@ -397,21 +417,26 @@ cmnd_matches(struct sudoers_parse_tree *
     switch (m->type) {
 	case ALL:
 	    if (m->name == NULL) {
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 		break;
 	    }
 	    FALLTHROUGH;
 	case COMMAND:
 	    c = (struct sudo_command *)m->name;
 	    if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
 	case ALIAS:
 	    a = alias_get(parse_tree, m->name, CMNDALIAS);
 	    if (a != NULL) {
 		rc = cmndlist_matches(parse_tree, &a->members, runchroot, info);
-		if (rc != UNSPEC)
-		    matched = m->negated ? !rc : rc;
+		if (rc != UNSPEC) {
+		    if (m->negated) {
+			matched = rc == ALLOW ? DENY : ALLOW;
+		    } else {
+			matched = rc;
+		    }
+		}
 		alias_put(a);
 	    }
 	    break;
