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.7.6p2/match.c
===================================================================
--- sudo-1.7.6p2.orig/match.c
+++ sudo-1.7.6p2/match.c
@@ -115,32 +115,37 @@ _userlist_matches(pw, list)
 {
     struct member *m;
     struct alias *a;
-    int rval, matched = UNSPEC;
+    int matched = UNSPEC;
 
     tq_foreach_rev(list, m) {
 	switch (m->type) {
 	    case ALL:
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 		break;
 	    case NETGROUP:
 		if (netgr_matches(m->name, NULL, 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_find(m->name, USERALIAS)) != NULL) {
-		    rval = _userlist_matches(pw, &a->members);
-		    if (rval != UNSPEC)
-			matched = m->negated ? !rval : rval;
+		    const int rval = _userlist_matches(pw, &a->members);
+		    if (rval != UNSPEC) {
+			if (m->negated) {
+			    matched = rval == ALLOW ? DENY : ALLOW;
+			} else {
+			    matched = rval;
+			}
+		    }
 		    break;
 		}
 		/* FALLTHROUGH */
 	    case WORD:
 		if (userpw_matches(m->name, pw->pw_name, pw))
-		    matched = !m->negated;
+		    matched = m->negated ? DENY : ALLOW;
 		break;
 	}
 	if (matched != UNSPEC)
@@ -177,32 +182,37 @@ _runaslist_matches(user_list, group_list
     if (runas_pw != NULL) {
 	/* If no runas user or runas group listed in sudoers, use default. */
 	if (tq_empty(user_list) && tq_empty(group_list))
-	    return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
+	    return (userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw) ? ALLOW : DENY);
 
 	tq_foreach_rev(user_list, m) {
 	    switch (m->type) {
 		case ALL:
-		    user_matched = !m->negated;
+		    user_matched = m->negated ? DENY : ALLOW;
 		    break;
 		case NETGROUP:
 		    if (netgr_matches(m->name, NULL, 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:
 		    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
 			rval = _runaslist_matches(&a->members, &empty);
-			if (rval != UNSPEC)
-			    user_matched = m->negated ? !rval : rval;
+			if (rval != UNSPEC) {
+			    if (m->negated) {
+				user_matched = rval == ALLOW ? DENY : ALLOW;
+			    } else {
+				user_matched = rval;
+			    }
+			}
 			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;
 	    }
 	    if (user_matched != UNSPEC)
@@ -218,19 +228,24 @@ _runaslist_matches(user_list, group_list
 	tq_foreach_rev(group_list, m) {
 	    switch (m->type) {
 		case ALL:
-		    group_matched = !m->negated;
+		    group_matched = m->negated ? DENY : ALLOW;
 		    break;
 		case ALIAS:
 		    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
 			rval = _runaslist_matches(&a->members, &empty);
-			if (rval != UNSPEC)
-			    group_matched = m->negated ? !rval : rval;
+			if (rval != UNSPEC) {
+			    if (m->negated) {
+				user_matched = rval == ALLOW ? DENY : ALLOW;
+			    } else {
+				user_matched = rval;
+			    }
+			}
 			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)
@@ -270,27 +285,32 @@ _hostlist_matches(list)
     tq_foreach_rev(list, m) {
 	switch (m->type) {
 	    case ALL:
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 		break;
 	    case NETGROUP:
 		if (netgr_matches(m->name, user_host, user_shost, 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:
 		if ((a = alias_find(m->name, HOSTALIAS)) != NULL) {
 		    rval = _hostlist_matches(&a->members);
-		    if (rval != UNSPEC)
-			matched = m->negated ? !rval : rval;
+		    if (rval != UNSPEC) {
+                        if (m->negated) {
+                            matched = rval == ALLOW ? DENY : ALLOW;
+                        } else {
+                            matched = rval;
+                        }
+		    }
 		    break;
 		}
 		/* FALLTHROUGH */
 	    case WORD:
 		if (hostname_matches(user_shost, user_host, m->name))
-		    matched = !m->negated;
+		    matched = m->negated ? DENY : ALLOW;
 		break;
 	}
 	if (matched != UNSPEC)
@@ -348,20 +368,25 @@ cmnd_matches(m)
 
     switch (m->type) {
 	case ALL:
-	    matched = !m->negated;
+	    matched = m->negated ? DENY : ALLOW;
 	    break;
 	case ALIAS:
 	    alias_seqno++;
 	    if ((a = alias_find(m->name, CMNDALIAS)) != NULL) {
 		rval = _cmndlist_matches(&a->members);
-		if (rval != UNSPEC)
-		    matched = m->negated ? !rval : rval;
+		if (rval != UNSPEC) {
+                    if (m->negated) {
+                        matched = rval == ALLOW ? DENY : ALLOW;
+                    } else {
+                        matched = rval;
+                    }
+                }
 	    }
 	    break;
 	case COMMAND:
 	    c = (struct sudo_command *)m->name;
 	    if (command_matches(c->cmnd, c->args))
-		matched = !m->negated;
+		matched = m->negated ? DENY : ALLOW;
 	    break;
     }
     return matched;
