]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
src/login_nopam.c: list_match(): Use iteration instead of recursion
authorTobias Stoeckmann <tobias@stoeckmann.org>
Thu, 16 Jan 2025 20:09:54 +0000 (21:09 +0100)
committerAlejandro Colomar <alx@kernel.org>
Sat, 18 Jan 2025 20:32:20 +0000 (21:32 +0100)
The recursive nature of list_match() triggered regression during
refactoring.  In Linux-PAM, the same code exists which could lead to
stack overflow because <access.conf> could be arbitrarily long.

Use an iterative approach for easier refactoring, to support long
lines in the future and to stay in sync with Linux-PAM.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
src/login_nopam.c

index ca04f68bbdb1b4316cc654d86e4bff07e0d09633..896ab9410373243044c6f3a33a58e4d62d0f82dd 100644 (file)
@@ -147,29 +147,31 @@ static bool
 list_match(char *list, const char *item, bool (*match_fn)(char *, const char*))
 {
        char *tok;
+       bool inclusion = true;
+       bool matched = false;
+       bool result = false;
 
        /*
         * Process tokens one at a time. We have exhausted all possible matches
         * when we reach an "EXCEPT" token or the end of the list. If we do find
-        * a match, look for an "EXCEPT" list and recurse to determine whether
-        * the match is affected by any exceptions.
+        * a match, look for an "EXCEPT" list and determine whether the match is
+        * affected by any exceptions.
         */
        while (NULL != (tok = strsep(&list, ", \t"))) {
-               if (strcasecmp (tok, "EXCEPT") == 0) {  /* EXCEPT: give up */
-                       break;
+               if (strcasecmp (tok, "EXCEPT") == 0) {  /* EXCEPT: invert */
+                       if (!matched) { /* stop processing: not part of list */
+                               break;
+                       }
+                       inclusion = !inclusion;
+                       matched = false;
 
                } else if ((*match_fn)(tok, item)) {
-                       while (   (NULL != (tok = strsep(&list, ", \t")))
-                              && (strcasecmp (tok, "EXCEPT") != 0))
-                               /* VOID */ ;
-                       if (tok == NULL || !list_match(list, item, match_fn)) {
-                               return true;
-                       }
-                       break;
+                       result = inclusion;
+                       matched = true;
                }
        }
 
-       return false;
+       return result;
 }
 
 /* myhostname - figure out local machine name */