Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Jun 2023 21:29:23 GMT
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: f122e552354e - stable/13 - Allow a comma-separated list in login class capabilities, by adding a version of strcspn that allows quoting.
Message-ID:  <202306132129.35DLTNuw018619@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=f122e552354e84f18b82d11e40c6f8f214ed8abc

commit f122e552354e84f18b82d11e40c6f8f214ed8abc
Author:     Sean Eric Fagan <sef@FreeBSD.org>
AuthorDate: 2023-01-14 18:37:31 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2023-06-13 21:28:54 +0000

    Allow a comma-separated list in login class capabilities,
    by adding a version of strcspn that allows quoting.
    
    PR:             236204
    Differential Revision:  https://reviews.freebsd.org/D25368
    
    (cherry picked from commit f32db406504ece1b28f43dc816736e081fe22826)
---
 lib/libutil/login_cap.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 107 insertions(+), 2 deletions(-)

diff --git a/lib/libutil/login_cap.c b/lib/libutil/login_cap.c
index cea7630698af..ffefb865ed5e 100644
--- a/lib/libutil/login_cap.c
+++ b/lib/libutil/login_cap.c
@@ -94,6 +94,101 @@ allocarray(size_t sz)
 }
 
 
+/*
+ * This is a variant of strcspn, which checks for quoted
+ * strings.  That is,:
+ *   strcspn_quote("how 'now, brown' cow", ",", NULL);
+ * will return the index for the nul, rather than the comma, because
+ * the string is quoted.  It does not handle escaped characters
+ * at this time.
+ */
+static size_t
+strcspn_quote(const char *str, const char *exclude, int *is_quoted)
+{
+	size_t indx = 0;
+	char quote = 0;
+
+	if (str == NULL)
+		return 0;
+
+	if (is_quoted)
+		*is_quoted = 0;
+
+	for (indx = 0; str[indx] != 0; indx++) {
+		if (quote && str[indx] == quote) {
+			if (is_quoted)
+				*is_quoted = 1;
+			quote = 0;
+			continue;
+		}
+		if (quote == 0 &&
+		    (str[indx] == '\'' || str[indx] == '"')) {
+			quote = str[indx];
+			continue;
+		}
+		if (quote == 0 &&
+		    strchr(exclude, str[indx]) != NULL)
+			return indx;
+	}
+	return indx;
+}
+
+/*
+ * Remove quotes from the given string.
+ * It's a very simplistic approach:  the first
+ * single or double quote it finds, it looks for
+ * the next one, and if it finds it, moves the
+ * entire string backwards in two chunks
+ * (first quote + 1 to first quote, length
+ * rest of string, and then second quote + 1
+ * to second quote, length rest of the string).
+ */
+static void
+remove_quotes(char *str)
+{
+	static const char *quote_chars = "'\"";
+	char qc = 0;
+	int found = 0;
+
+	do {
+		char *loc = NULL;
+
+		found = 0;
+		/*
+		 * If qc is 0, then we haven't found
+		 * a quote yet, so do a strcspn search.
+		 */
+		if (qc == 0) {
+			size_t indx;
+			indx = strcspn(str, quote_chars);
+			if (str[indx] == '\0')
+				return;	/* We're done */
+			loc = str + indx;
+			qc = str[indx];
+		} else {
+			/*
+			 * We've found a quote character,
+			 * so use strchr to find the next one.
+			 */
+			loc = strchr(str, qc);
+			if (loc == NULL)
+				return;
+			qc = 0;
+		}
+		if (loc) {
+			/*
+			 * This gives us the location of the
+			 * quoted character.  We need to move
+			 * the entire string down, from loc+1
+			 * to loc.
+			 */
+			size_t len = strlen(loc + 1) + 1;
+			memmove(loc, loc + 1, len);
+			found = 1;
+		}
+	} while (found != 0);
+}
+
 /*
  * arrayize()
  * Turn a simple string <str> separated by any of
@@ -112,7 +207,7 @@ arrayize(const char *str, const char *chars, int *size)
 
     /* count the sub-strings */
     for (i = 0, cptr = str; *cptr; i++) {
-	int count = strcspn(cptr, chars);
+        int count = strcspn_quote(cptr, chars, NULL);
 	cptr += count;
 	if (*cptr)
 	    ++cptr;
@@ -126,11 +221,21 @@ arrayize(const char *str, const char *chars, int *size)
 	    /* now split the string */
 	    i = 0;
 	    while (*ptr) {
-		int count = strcspn(ptr, chars);
+		int quoted = 0;
+		int count = strcspn_quote(ptr, chars, &quoted);
+		char *base = ptr;
 		res[i++] = ptr;
 		ptr += count;
 		if (*ptr)
 		    *ptr++ = '\0';
+		/*
+		 * If the string contains a quoted element, we
+		 * need to remove the quotes.
+		 */
+		if (quoted) {
+			remove_quotes(base);
+		}
+					    
 	    }
 	    res[i] = NULL;
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202306132129.35DLTNuw018619>