diff --git a/sys/security/mac_do/mac_do.c b/sys/security/mac_do/mac_do.c --- a/sys/security/mac_do/mac_do.c +++ b/sys/security/mac_do/mac_do.c @@ -368,6 +368,48 @@ return ((int)l); } +/* + * strsep() variant skipping spaces and tabs. + * + * Skips spaces and tabs at beginning and end of the token before one of the + * 'delim' characters, i.e., at start of string and just before one of the + * delimiter characters (so it doesn't prevent tokens containing spaces and tabs + * in the middle). + */ +static char * +strsep_noblanks(char **const stringp, const char *delim) +{ + char *p = *stringp; + char *ret, *wsp; + size_t idx; + + if (p == NULL) + return (NULL); + + idx = strspn(p, " \t"); + p += idx; + + ret = strsep(&p, delim); + + /* Rewind spaces/tabs at the end. */ + if (p == NULL) + wsp = ret + strlen(ret); + else + wsp = p - 1; + for (; wsp != ret; --wsp) { + switch (wsp[-1]) { + case ' ': + case '\t': + continue; + } + break; + } + *wsp = '\0'; + + *stringp = p; + return (ret); +} + static void alloc_parse_error(struct parse_error **const parse_error, const size_t pos, @@ -448,13 +490,13 @@ MPASS(*parse_error == NULL); MPASS(to != NULL); - to_type = strsep(&to, "="); + to_type = strsep_noblanks(&to, "="); MPASS(to_type != NULL); error = parse_id_type(to_type, &type, parse_error); if (error != 0) goto einval; - to_id = strsep(&to, ""); + to_id = strsep_noblanks(&to, ""); switch (type) { case IT_GID: if (to_id == NULL) { @@ -784,7 +826,7 @@ /* Freed when the 'struct rules' container is freed. */ new = malloc(sizeof(*new), M_DO, M_WAITOK | M_ZERO); - from_type = strsep(&rule, "="); + from_type = strsep_noblanks(&rule, "="); MPASS(from_type != NULL); /* Because 'rule' was not NULL. */ error = parse_id_type(from_type, &new->from_type, parse_error); if (error != 0) @@ -799,7 +841,7 @@ goto einval; } - from_id = strsep(&rule, ":"); + from_id = strsep_noblanks(&rule, ":"); if (is_null_or_empty(from_id)) { alloc_parse_error(parse_error, 0, "No ID specified."); goto einval; @@ -824,7 +866,7 @@ * allows to minimize memory allocations and enables searching IDs in * O(log(n)) instead of linearly. */ - to_list = strsep(&rule, ","); + to_list = strsep_noblanks(&rule, ","); if (to_list == NULL) { alloc_parse_error(parse_error, 0, "No target list."); goto einval; @@ -837,7 +879,7 @@ goto einval; } - to_list = strsep(&rule, ","); + to_list = strsep_noblanks(&rule, ","); } while (to_list != NULL); if (new->uids_nb != 0) { @@ -904,7 +946,10 @@ * is "uid" or "gid", an UID or GID (depending on ) and is * "*", "any" or a comma-separated list of '=' clauses (see the * comment for parse_single_rule() for more details). For convenience, empty - * rules are allowed (and do nothing). + * rules are allowed (and do nothing), and spaces and tabs are allowed (and + * removed) around each token (tokens are natural ones, except that + * '' as a whole is considered a single token, so no blanks are + * allowed between '' and ''). * * Examples: * - "uid=1001:uid=1010,gid=1010;uid=1002:any" @@ -937,7 +982,7 @@ MPASS(copy[len] == '\0'); /* Catch some races. */ p = copy; - while ((rule = strsep(&p, ";")) != NULL) { + while ((rule = strsep_noblanks(&p, ";")) != NULL) { if (rule[0] == '\0') continue; error = parse_single_rule(rule, rules, parse_error);