From: Todd C. Miller <Todd.Miller@courtesan.com>
Date: Tue, 12 Jan 2016 21:59:44 +0000 (-0700)
Subject: Add support for matching the entire netgroup tuple (user, host, domain).
X-Git-Tag: SUDO_1_8_16^2~69
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5a77989a33ee8f27349aec831603fcd55cce159c;p=sudo

Add support for matching the entire netgroup tuple (user, host, domain).
---

diff --git a/doc/sudoers.cat b/doc/sudoers.cat
index c5ce069f5..ea1eb968c 100644
--- a/doc/sudoers.cat
+++ b/doc/sudoers.cat
@@ -890,14 +890,6 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
                        This flag is _o_n by default when ssuuddoo is compiled with
                        zzlliibb support.
 
-     use_netgroups     If set, netgroups (prefixed with `+'), may be used in
-                       place of a user or host.  For LDAP-based sudoers,
-                       netgroup support requires an expensive substring match
-                       on the server unless the NNEETTGGRROOUUPP__BBAASSEE directive is
-                       present in the _/_e_t_c_/_l_d_a_p_._c_o_n_f file.  If netgroups are
-                       not needed, this option can be disabled to reduce the
-                       load on the LDAP server.  This flag is _o_n by default.
-
      exec_background   By default, ssuuddoo runs a command as the foreground
                        process as long as ssuuddoo itself is running in the
                        foreground.  When the _e_x_e_c___b_a_c_k_g_r_o_u_n_d flag is enabled
@@ -1140,6 +1132,13 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
                        invoking user is not in the _s_u_d_o_e_r_s file.  This flag is
                        _o_n by default.
 
+     netgroup_tuple    If set, netgroup lookups will be performed using the
+                       full netgroup tuple: host name, user name and domain
+                       (if one is set).  Historically, ssuuddoo only matched the
+                       user name and domain for netgroups used in a User_List
+                       and only matched the host name and domain for netgroups
+                       used in a Host_List.  This flag is _o_f_f by default.
+
      noexec            If set, all commands run via ssuuddoo will behave as if the
                        NOEXEC tag has been set, unless overridden by an EXEC
                        tag.  See the description of _E_X_E_C _a_n_d _N_O_E_X_E_C above as
@@ -1337,6 +1336,14 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
                        available if ssuuddoo is configured with the
                        --with-logincap option.  This flag is _o_f_f by default.
 
+     use_netgroups     If set, netgroups (prefixed with `+'), may be used in
+                       place of a user or host.  For LDAP-based sudoers,
+                       netgroup support requires an expensive substring match
+                       on the server unless the NNEETTGGRROOUUPP__BBAASSEE directive is
+                       present in the _/_e_t_c_/_l_d_a_p_._c_o_n_f file.  If netgroups are
+                       not needed, this option can be disabled to reduce the
+                       load on the LDAP server.  This flag is _o_n by default.
+
      use_pty           If set, ssuuddoo will run the command in a pseudo-pty even
                        if no I/O logging is being gone.  A malicious program
                        run under ssuuddoo could conceivably fork a background
@@ -2498,4 +2505,4 @@ DDIISSCCLLAAIIMMEERR
      file distributed with ssuuddoo or https://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.16                     January 9, 2016                    Sudo 1.8.16
+Sudo 1.8.16                    January 12, 2016                    Sudo 1.8.16
diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in
index 3c7c9728f..00af9a3e2 100644
--- a/doc/sudoers.man.in
+++ b/doc/sudoers.man.in
@@ -21,7 +21,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.TH "SUDOERS" "5" "January 9, 2016" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.TH "SUDOERS" "5" "January 12, 2016" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -1926,22 +1926,6 @@ is compiled with
 \fBzlib\fR
 support.
 .TP 18n
-use_netgroups
-If set, netgroups (prefixed with
-\(oq+\(cq),
-may be used in place of a user or host.
-For LDAP-based sudoers, netgroup support requires an expensive
-substring match on the server unless the
-\fBNETGROUP_BASE\fR
-directive is present in the
-\fI@ldap_conf@\fR
-file.
-If netgroups are not needed, this option can be disabled to reduce the
-load on the LDAP server.
-This flag is
-\fIon\fR
-by default.
-.TP 18n
 exec_background
 By default,
 \fBsudo\fR
@@ -2424,6 +2408,19 @@ This flag is
 \fI@mail_no_user@\fR
 by default.
 .TP 18n
+netgroup_tuple
+If set, netgroup lookups will be performed using the full netgroup
+tuple: host name, user name and domain (if one is set).
+Historically,
+\fBsudo\fR
+only matched the user name and domain for netgroups used in a
+\fRUser_List\fR
+and only matched the host name and domain for netgroups used in a
+\fRHost_List\fR.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
 noexec
 If set, all commands run via
 \fBsudo\fR
@@ -2842,6 +2839,22 @@ This flag is
 \fIoff\fR
 by default.
 .TP 18n
+use_netgroups
+If set, netgroups (prefixed with
+\(oq+\(cq),
+may be used in place of a user or host.
+For LDAP-based sudoers, netgroup support requires an expensive
+substring match on the server unless the
+\fBNETGROUP_BASE\fR
+directive is present in the
+\fI@ldap_conf@\fR
+file.
+If netgroups are not needed, this option can be disabled to reduce the
+load on the LDAP server.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
 use_pty
 If set,
 \fBsudo\fR
diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in
index 4aff03ca8..0d5c9fa36 100644
--- a/doc/sudoers.mdoc.in
+++ b/doc/sudoers.mdoc.in
@@ -19,7 +19,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.Dd January 9, 2016
+.Dd January 12, 2016
 .Dt SUDOERS @mansectform@
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -1796,21 +1796,6 @@ by default when
 is compiled with
 .Sy zlib
 support.
-.It use_netgroups
-If set, netgroups (prefixed with
-.Ql + ) ,
-may be used in place of a user or host.
-For LDAP-based sudoers, netgroup support requires an expensive
-substring match on the server unless the
-.Sy NETGROUP_BASE
-directive is present in the
-.Pa @ldap_conf@
-file.
-If netgroups are not needed, this option can be disabled to reduce the
-load on the LDAP server.
-This flag is
-.Em on
-by default.
 .It exec_background
 By default,
 .Nm sudo
@@ -2276,6 +2261,18 @@ file.
 This flag is
 .Em @mail_no_user@
 by default.
+.It netgroup_tuple
+If set, netgroup lookups will be performed using the full netgroup
+tuple: host name, user name and domain (if one is set).
+Historically,
+.Nm sudo
+only matched the user name and domain for netgroups used in a
+.Li User_List
+and only matched the host name and domain for netgroups used in a
+.Li Host_List .
+This flag is
+.Em off
+by default.
 .It noexec
 If set, all commands run via
 .Nm sudo
@@ -2670,6 +2667,21 @@ option.
 This flag is
 .Em off
 by default.
+.It use_netgroups
+If set, netgroups (prefixed with
+.Ql + ) ,
+may be used in place of a user or host.
+For LDAP-based sudoers, netgroup support requires an expensive
+substring match on the server unless the
+.Sy NETGROUP_BASE
+directive is present in the
+.Pa @ldap_conf@
+file.
+If netgroups are not needed, this option can be disabled to reduce the
+load on the LDAP server.
+This flag is
+.Em on
+by default.
 .It use_pty
 If set,
 .Nm sudo
diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c
index e983263e4..6d7178232 100644
--- a/plugins/sudoers/def_data.c
+++ b/plugins/sudoers/def_data.c
@@ -398,6 +398,10 @@ struct sudo_defs_types sudo_defs_table[] = {
 	"always_query_group_plugin", T_FLAG,
 	N_("Query the group plugin for unknown system groups"),
 	NULL,
+    }, {
+	"netgroup_tuple", T_FLAG,
+	N_("Match netgroups based on the entire tuple: user, host and domain"),
+	NULL,
     }, {
 	NULL, 0, NULL
     }
diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h
index 5005812cf..85f43c23a 100644
--- a/plugins/sudoers/def_data.h
+++ b/plugins/sudoers/def_data.h
@@ -186,6 +186,8 @@
 #define I_SUDOEDIT_FOLLOW       92
 #define def_always_query_group_plugin (sudo_defs_table[93].sd_un.flag)
 #define I_ALWAYS_QUERY_GROUP_PLUGIN93
+#define def_netgroup_tuple      (sudo_defs_table[94].sd_un.flag)
+#define I_NETGROUP_TUPLE        94
 
 enum def_tuple {
 	never,
diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in
index 75e96079c..db76d5342 100644
--- a/plugins/sudoers/def_data.in
+++ b/plugins/sudoers/def_data.in
@@ -295,3 +295,6 @@ sudoedit_follow
 always_query_group_plugin
 	T_FLAG
 	"Query the group plugin for unknown system groups"
+netgroup_tuple
+	T_FLAG
+	"Match netgroups based on the entire tuple: user, host and domain"
diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c
index 58960c09d..2309c64c4 100644
--- a/plugins/sudoers/defaults.c
+++ b/plugins/sudoers/defaults.c
@@ -439,6 +439,7 @@ init_defaults(void)
 #ifdef HAVE_INNETGR
     def_use_netgroups = true;
 #endif
+    def_netgroup_tuple = false;
 
     /* Syslog options need special care since they both strings and ints */
 #if (LOGGING & SLOG_SYSLOG)
@@ -549,7 +550,7 @@ update_defaults(int what)
 		break;
 	    case DEFAULTS_HOST:
 		if (ISSET(what, SETDEF_HOST) &&
-		    hostlist_matches(def->binding) == ALLOW &&
+		    hostlist_matches(sudo_user.pw, def->binding) == ALLOW &&
 		    !set_default(def->var, def->val, def->op))
 		    rc = false;
 		break;
diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c
index f5f62c14a..11eef0eca 100644
--- a/plugins/sudoers/ldap.c
+++ b/plugins/sudoers/ldap.c
@@ -694,7 +694,8 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw)
     for (p = bv; *p != NULL && !ret; p++) {
 	val = (*p)->bv_val;
 	if (*val == '+') {
-	    if (netgr_matches(val, NULL, NULL, pw->pw_name))
+	    if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL,
+		def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name))
 		ret = true;
 	    DPRINTF2("ldap sudoUser netgroup '%s' ... %s", val,
 		ret ? "MATCH!" : "not");
@@ -716,7 +717,7 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw)
 * host match, else false.
 */
 static bool
-sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry)
+sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry, struct passwd *pw)
 {
     struct berval **bv, **p;
     char *val;
@@ -736,7 +737,8 @@ sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry)
 	val = (*p)->bv_val;
 	/* match any or address or netgroup or hostname */
 	if (!strcmp(val, "ALL") || addr_matches(val) ||
-	    netgr_matches(val, user_runhost, user_srunhost, NULL) ||
+	    netgr_matches(val, user_runhost, user_srunhost,
+	    def_netgroup_tuple ? pw->pw_name : NULL) ||
 	    hostname_matches(user_srunhost, user_runhost, val))
 	    ret = true;
 	DPRINTF2("ldap sudoHost '%s' ... %s", val, ret ? "MATCH!" : "not");
@@ -792,7 +794,8 @@ sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry)
 	val = (*p)->bv_val;
 	switch (val[0]) {
 	case '+':
-	    if (netgr_matches(val, NULL, NULL, runas_pw->pw_name))
+	    if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL,
+		def_netgroup_tuple ? user_srunhost : NULL, runas_pw->pw_name))
 		ret = true;
 	    break;
 	case '%':
@@ -1401,8 +1404,8 @@ sudo_netgroup_lookup(LDAP *ld, struct passwd *pw,
     struct timeval tv, *tvp = NULL;
     LDAPMessage *entry, *result = NULL;
     const char *domain;
-    char *escaped_domain, *escaped_host, *escaped_shost, *escaped_user;
-    char *filt = NULL;
+    char *escaped_domain = NULL, *escaped_user = NULL;
+    char *escaped_host = NULL, *escaped_shost = NULL, *filt = NULL;
     int filt_len, rc;
     debug_decl(sudo_netgroup_lookup, SUDOERS_DEBUG_LDAP);
 
@@ -1416,29 +1419,70 @@ sudo_netgroup_lookup(LDAP *ld, struct passwd *pw,
     domain = sudo_getdomainname();
 
     /* Escape the domain, host names, and user name per RFC 4515. */
-    escaped_domain = domain ? sudo_ldap_value_dup(domain) : NULL;
-    escaped_host = sudo_ldap_value_dup(user_runhost);
-    if (user_runhost == user_srunhost)
-	escaped_shost = escaped_host;
-    else 
-	escaped_shost = sudo_ldap_value_dup(user_srunhost);
-    escaped_user = sudo_ldap_value_dup(pw->pw_name);
-    if (escaped_domain == NULL || escaped_host == NULL ||
-	escaped_shost == NULL || escaped_user == NULL)
-	goto oom;
+    if (domain != NULL) {
+	if ((escaped_domain = sudo_ldap_value_dup(domain)) == NULL)
+	    goto oom;
+    }
+    if ((escaped_user = sudo_ldap_value_dup(pw->pw_name)) == NULL)
+	    goto oom;
+    if (def_netgroup_tuple) {
+	escaped_host = sudo_ldap_value_dup(user_runhost);
+	if (user_runhost == user_srunhost)
+	    escaped_shost = escaped_host;
+	else 
+	    escaped_shost = sudo_ldap_value_dup(user_srunhost);
+	if (escaped_host == NULL || escaped_shost == NULL)
+	    goto oom;
+    }
 
     /* Build query, using NIS domain if it is set. */
     if (domain != NULL) {
-	if (user_runhost != user_srunhost) {
-	    filt_len = asprintf(&filt, "(&%s(|(nisNetgroupTriple=\\28,%s,%s\\29)(nisNetgroupTriple=\\28%s,%s,%s\\29)(nisNetgroupTriple=\\28%s,%s,%s\\29)(nisNetgroupTriple=\\28,%s,\\29)(nisNetgroupTriple=\\28%s,%s,\\29)(nisNetgroupTriple=\\28%s,%s,\\29)))", ldap_conf.netgroup_search_filter, escaped_user, escaped_domain, escaped_shost, escaped_user, escaped_domain, escaped_host, escaped_user, escaped_domain, escaped_user, escaped_shost, escaped_user, escaped_host, escaped_user);
+	if (escaped_host != escaped_shost) {
+	    filt_len = asprintf(&filt, "(&%s(|"
+		"(nisNetgroupTriple=\\28,%s,%s\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,%s\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,%s\\29)"
+		"(nisNetgroupTriple=\\28,%s,\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,\\29)))",
+		ldap_conf.netgroup_search_filter, escaped_user, escaped_domain,
+		escaped_shost, escaped_user, escaped_domain,
+		escaped_host, escaped_user, escaped_domain, escaped_user,
+		escaped_shost, escaped_user, escaped_host, escaped_user);
+	} else if (escaped_shost != NULL) {
+	    filt_len = asprintf(&filt, "(&%s(|"
+		"(nisNetgroupTriple=\\28,%s,%s\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,%s\\29)"
+		"(nisNetgroupTriple=\\28,%s,\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,\\29)))",
+		ldap_conf.netgroup_search_filter, escaped_user, escaped_domain,
+		escaped_shost, escaped_user, escaped_domain,
+		escaped_user, escaped_shost, escaped_user);
 	} else {
-	    filt_len = asprintf(&filt, "(&%s(|(nisNetgroupTriple=\\28,%s,%s\\29)(nisNetgroupTriple=\\28%s,%s,%s\\29)(nisNetgroupTriple=\\28,%s,\\29)(nisNetgroupTriple=\\28%s,%s,\\29)))", ldap_conf.netgroup_search_filter, escaped_user, escaped_domain, escaped_shost, escaped_user, escaped_domain, escaped_user, escaped_shost, escaped_user);
+	    filt_len = asprintf(&filt, "(&%s(|"
+		"(nisNetgroupTriple=\\28*,%s,%s\\29)"
+		"(nisNetgroupTriple=\\28*,%s,\\29)))",
+		ldap_conf.netgroup_search_filter, escaped_user, escaped_domain,
+		escaped_user);
 	}
     } else {
-	if (user_runhost != user_srunhost) {
-	    filt_len = asprintf(&filt, "(&%s(|(nisNetgroupTriple=\\28,%s,*\\29)(nisNetgroupTriple=\\28%s,%s,*\\29)(nisNetgroupTriple=\\28%s,%s,*\\29)))", ldap_conf.netgroup_search_filter, escaped_user, escaped_shost, escaped_user, escaped_host, escaped_user);
+	if (escaped_host != escaped_shost) {
+	    filt_len = asprintf(&filt, "(&%s(|"
+		"(nisNetgroupTriple=\\28,%s,*\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,*\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,*\\29)))",
+		ldap_conf.netgroup_search_filter, escaped_user,
+		escaped_shost, escaped_user, escaped_host, escaped_user);
+	} else if (escaped_shost != NULL) {
+	    filt_len = asprintf(&filt, "(&%s(|"
+		"(nisNetgroupTriple=\\28,%s,*\\29)"
+		"(nisNetgroupTriple=\\28%s,%s,*\\29)))",
+		ldap_conf.netgroup_search_filter, escaped_user,
+		escaped_shost, escaped_user);
 	} else {
-	    filt_len = asprintf(&filt, "(&%s(|(nisNetgroupTriple=\\28,%s,*\\29)(nisNetgroupTriple=\\28%s,%s,*\\29)))", ldap_conf.netgroup_search_filter, escaped_user, escaped_shost, escaped_user);
+	    filt_len = asprintf(&filt,
+		"(&%s(|(nisNetgroupTriple=\\28*,%s,*\\29)))",
+		ldap_conf.netgroup_search_filter, escaped_user);
 	}
     }
     if (filt_len == -1)
@@ -1497,10 +1541,10 @@ sudo_netgroup_lookup(LDAP *ld, struct passwd *pw,
 oom:
     sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
     free(escaped_domain);
+    free(escaped_user);
     free(escaped_host);
     if (escaped_host != escaped_shost)
 	free(escaped_shost);
-    free(escaped_user);
     free(filt);
     ldap_msgfree(result);
     debug_return_bool(false);
@@ -3399,7 +3443,7 @@ sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw)
 			continue;
 		    lres->user_matches = true;
 		    /* Check host. */
-		    if (!sudo_ldap_check_host(ld, entry))
+		    if (!sudo_ldap_check_host(ld, entry, pw))
 			continue;
 		    lres->host_matches = true;
 		    if (sudo_ldap_result_add_entry(lres, entry) == NULL) {
diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c
index fcd24df9b..fdbe2628e 100644
--- a/plugins/sudoers/match.c
+++ b/plugins/sudoers/match.c
@@ -107,7 +107,9 @@ userlist_matches(const struct passwd *pw, const struct member_list *list)
 		matched = !m->negated;
 		break;
 	    case NETGROUP:
-		if (netgr_matches(m->name, NULL, NULL, pw->pw_name))
+		if (netgr_matches(m->name,
+		    def_netgroup_tuple ? user_runhost : NULL,
+		    def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name))
 		    matched = !m->negated;
 		break;
 	    case USERGROUP:
@@ -163,7 +165,10 @@ runaslist_matches(const struct member_list *user_list,
 			user_matched = !m->negated;
 			break;
 		    case NETGROUP:
-			if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
+			if (netgr_matches(m->name,
+			    def_netgroup_tuple ? user_runhost : NULL,
+			    def_netgroup_tuple ? user_srunhost : NULL,
+			    runas_pw->pw_name))
 			    user_matched = !m->negated;
 			break;
 		    case USERGROUP:
@@ -250,7 +255,7 @@ runaslist_matches(const struct member_list *user_list,
  * Returns ALLOW, DENY or UNSPEC.
  */
 int
-hostlist_matches(const struct member_list *list)
+hostlist_matches(const struct passwd *pw, const struct member_list *list)
 {
     struct member *m;
     struct alias *a;
@@ -263,7 +268,8 @@ hostlist_matches(const struct member_list *list)
 		matched = !m->negated;
 		break;
 	    case NETGROUP:
-		if (netgr_matches(m->name, user_runhost, user_srunhost, NULL))
+		if (netgr_matches(m->name, user_runhost, user_srunhost,
+		    pw->pw_name))
 		    matched = !m->negated;
 		break;
 	    case NTWKADDR:
@@ -272,7 +278,7 @@ hostlist_matches(const struct member_list *list)
 		break;
 	    case ALIAS:
 		if ((a = alias_get(m->name, HOSTALIAS)) != NULL) {
-		    rval = hostlist_matches(&a->members);
+		    rval = hostlist_matches(pw, &a->members);
 		    if (rval != UNSPEC)
 			matched = m->negated ? !rval : rval;
 		    alias_put(a);
diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c
index b8f04b162..0ac4f808a 100644
--- a/plugins/sudoers/parse.c
+++ b/plugins/sudoers/parse.c
@@ -176,7 +176,7 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
 	    if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
 		continue;
 	    TAILQ_FOREACH(priv, &us->privileges, entries) {
-		if (hostlist_matches(&priv->hostlist) != ALLOW)
+		if (hostlist_matches(sudo_user.pw, &priv->hostlist) != ALLOW)
 		    continue;
 		TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
 		    /* Only check the command when listing another user. */
@@ -212,7 +212,7 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
 	    continue;
 	CLR(validated, FLAG_NO_USER);
 	TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
-	    host_match = hostlist_matches(&priv->hostlist);
+	    host_match = hostlist_matches(sudo_user.pw, &priv->hostlist);
 	    if (host_match == ALLOW)
 		CLR(validated, FLAG_NO_HOST);
 	    else
@@ -415,7 +415,7 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
     /* gcc -Wuninitialized false positive */
     TAGS_INIT(tags);
     TAILQ_FOREACH(priv, &us->privileges, entries) {
-	if (hostlist_matches(&priv->hostlist) != ALLOW)
+	if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
 	    continue;
 	prev_cs = NULL;
 	TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
@@ -494,7 +494,7 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
     debug_decl(sudo_file_display_priv_long, SUDOERS_DEBUG_NSS)
 
     TAILQ_FOREACH(priv, &us->privileges, entries) {
-	if (hostlist_matches(&priv->hostlist) != ALLOW)
+	if (hostlist_matches(pw, &priv->hostlist) != ALLOW)
 	    continue;
 	prev_cs = NULL;
 	TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
@@ -616,7 +616,7 @@ sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
     TAILQ_FOREACH(d, &defaults, entries) {
 	switch (d->type) {
 	    case DEFAULTS_HOST:
-		if (hostlist_matches(d->binding) != ALLOW)
+		if (hostlist_matches(pw, d->binding) != ALLOW)
 		    continue;
 		break;
 	    case DEFAULTS_USER:
@@ -753,7 +753,7 @@ sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
 	    continue;
 
 	TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
-	    host_match = hostlist_matches(&priv->hostlist);
+	    host_match = hostlist_matches(pw, &priv->hostlist);
 	    if (host_match != ALLOW)
 		continue;
 	    TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h
index 85e02297a..9f8cfdec4 100644
--- a/plugins/sudoers/parse.h
+++ b/plugins/sudoers/parse.h
@@ -258,7 +258,7 @@ bool usergr_matches(const char *group, const char *user, const struct passwd *pw
 bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw);
 int cmnd_matches(const struct member *m);
 int cmndlist_matches(const struct member_list *list);
-int hostlist_matches(const struct member_list *list);
+int hostlist_matches(const struct passwd *pw, const struct member_list *list);
 int runaslist_matches(const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group);
 int userlist_matches(const struct passwd *pw, const struct member_list *list);
 const char *sudo_getdomainname(void);
diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c
index 30892bdff..2bf3198b0 100644
--- a/plugins/sudoers/sssd.c
+++ b/plugins/sudoers/sssd.c
@@ -544,7 +544,8 @@ sudo_sss_check_runas_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *
 	switch (val[0]) {
 	case '+':
 	    sudo_debug_printf(SUDO_DEBUG_DEBUG, "netgr_");
-	    if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) {
+	    if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL,
+		def_netgroup_tuple ? user_srunhost : NULL, runas_pw->pw_name)) {
 		sudo_debug_printf(SUDO_DEBUG_DEBUG, "=> match");
 		ret = true;
 	    }
@@ -655,8 +656,7 @@ sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
 	debug_return_bool(ret);
 
     /* get the values from the rule */
-    switch (handle->fn_get_values(rule, "sudoHost", &val_array))
-    {
+    switch (handle->fn_get_values(rule, "sudoHost", &val_array)) {
     case 0:
 	break;
     case ENOENT:
@@ -673,8 +673,8 @@ sudo_sss_check_host(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule)
 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
 
 	/* match any or address or netgroup or hostname */
-	if (!strcmp(val, "ALL") || addr_matches(val) ||
-	    netgr_matches(val, user_runhost, user_srunhost, NULL) ||
+	if (!strcmp(val, "ALL") || addr_matches(val) || netgr_matches(val,
+	    user_runhost, user_srunhost, handle->pw->pw_name) ||
 	    hostname_matches(user_srunhost, user_runhost, val))
 	    ret = true;
 
@@ -724,7 +724,9 @@ sudo_sss_filter_user_netgroup(struct sudo_sss_handle *handle, struct sss_sudo_ru
 	    netgroup_spec_found = true;
 	}
 	sudo_debug_printf(SUDO_DEBUG_DEBUG, "val[%d]=%s", i, val);
-	if (strcmp(val, "ALL") == 0 || netgr_matches(val, NULL, NULL, handle->pw->pw_name)) {
+	if (strcmp(val, "ALL") == 0 || netgr_matches(val,
+	    def_netgroup_tuple ? user_runhost : NULL,
+	    def_netgroup_tuple ? user_srunhost : NULL, handle->pw->pw_name)) {
 	    ret = true;
 	    sudo_debug_printf(SUDO_DEBUG_DIAG,
 		"sssd/ldap sudoUser '%s' ... MATCH! (%s)",
diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c
index 1feee9a4a..28f514709 100644
--- a/plugins/sudoers/testsudoers.c
+++ b/plugins/sudoers/testsudoers.c
@@ -305,7 +305,7 @@ main(int argc, char *argv[])
 	    putchar('\n');
 	    print_privilege(priv);
 	    putchar('\n');
-	    host_match = hostlist_matches(&priv->hostlist);
+	    host_match = hostlist_matches(sudo_user.pw, &priv->hostlist);
 	    if (host_match == ALLOW) {
 		puts("\thost  matched");
 		TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {