summary refs log tree commit diff
path: root/inet/rcmd.c
diff options
context:
space:
mode:
authorCarlos O'Donell <carlos@systemhalted.org>2015-07-08 02:42:11 -0400
committerCarlos O'Donell <carlos@systemhalted.org>2015-07-08 02:42:11 -0400
commit8b59c73386ddb64331ee03c29925a18dae547733 (patch)
tree7e74e2c9e0325cc6e9b5fe138180b6df386708c6 /inet/rcmd.c
parent02d5e5d94a78d32e940dfb3b58ab7f06c31b0f76 (diff)
downloadglibc-8b59c73386ddb64331ee03c29925a18dae547733.tar.gz
glibc-8b59c73386ddb64331ee03c29925a18dae547733.tar.xz
glibc-8b59c73386ddb64331ee03c29925a18dae547733.zip
Fix ruserok scalability with large ~/.rhosts file.
Fixes bug 18557.

The ruserok API does hosts checks first while it walks the
user's ~/.rhosts file. This results in lots of DNS queries
that could have been skipped if we short-circuit test the
user portion first to see if would have had a failed match.

This supports configurations where rlogin is used on internal
secure networks with large numbers of users and machines.

The Red Hat QE team did extensive testing on various rlogin
combinations to validate this change, and in fact we found
a defect in the first version which is fixed in this version.
Diffstat (limited to 'inet/rcmd.c')
-rw-r--r--inet/rcmd.c50
1 files changed, 31 insertions, 19 deletions
diff --git a/inet/rcmd.c b/inet/rcmd.c
index 98b3735d1f..035cb0d87d 100644
--- a/inet/rcmd.c
+++ b/inet/rcmd.c
@@ -809,31 +809,43 @@ __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
 	*p = '\0';              /* <nul> terminate username (+host?) */
 
 	/* buf -> host(?) ; user -> username(?) */
+	if (*buf == '\0')
+	  break;
+	if (*user == '\0')
+	  user = luser;
+
+	/* First check the user part.  In a naive implementation we
+	   would check the host part first, then the user.  However,
+	   if we check the user first and reject the entry we will
+	   have saved doing any host lookups to normalize the comparison
+	   and that likely saves several DNS queries.  Therefore we
+	   check the user first.  */
+	ucheck = __icheckuser (user, ruser);
+
+	/* Either we found the user, or we didn't and this is a
+	   negative host check.  We must do the negative host lookup
+	   in order to preserve the semantics of stopping on this line
+	   before processing others.  */
+	if (ucheck != 0 || *buf == '-') {
+
+	    /* Next check host part.  */
+	    hcheck = __checkhost_sa (ra, ralen, buf, rhost);
+
+	    /* Negative '-host user(?)' match?  */
+	    if (hcheck < 0)
+		break;
 
-	/* First check host part */
-	hcheck = __checkhost_sa (ra, ralen, buf, rhost);
-
-	if (hcheck < 0)
-	    break;
-
-	if (hcheck) {
-	    /* Then check user part */
-	    if (! (*user))
-		user = luser;
-
-	    ucheck = __icheckuser (user, ruser);
-
-	    /* Positive 'host user' match? */
-	    if (ucheck > 0) {
+	    /* Positive 'host user' match?  */
+	    if (hcheck > 0 && ucheck > 0) {
 		retval = 0;
 		break;
 	    }
 
-	    /* Negative 'host -user' match? */
-	    if (ucheck < 0)
-		break;
+	    /* Negative 'host -user' match?  */
+	    if (hcheck > 0 && ucheck < 0)
+	      break;
 
-	    /* Neither, go on looking for match */
+	    /* Neither, go on looking for match.  */
 	}
     }