Skip to content

Commit 1d2b95f

Browse files
yosuke-wolfsslejohnstown
authored andcommitted
wolfsshd: fix Match User/Group directive misparse
1 parent 0256f4c commit 1d2b95f

2 files changed

Lines changed: 402 additions & 34 deletions

File tree

apps/wolfsshd/configuration.c

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -923,44 +923,86 @@ static int HandleChrootDir(WOLFSSHD_CONFIG* conf, const char* value)
923923
}
924924

925925

926-
/* returns WS_SUCCESS on success, helps with adding a restricted case to the
927-
* config */
928-
static int AddRestrictedCase(WOLFSSHD_CONFIG* config, const char* mtch,
929-
const char* value, char** out)
926+
/* Parse the value of a Match directive into the user and group applies-to
927+
* fields of 'config'. The value is a whitespace separated sequence of
928+
* keyword/name pairs, e.g. "User alice Group admins". The token immediately
929+
* following a "User" or "Group" keyword is taken literally as the name and is
930+
* never re-examined as a keyword, so a principal named like the opposite
931+
* keyword (e.g. "Match User Group") is handled by position rather than by a
932+
* substring search. A recognized keyword with no following name (e.g. a bare
933+
* "Match User") is a configuration error so the admin's intent is not silently
934+
* dropped. Unrecognized tokens are ignored to stay lenient toward Match
935+
* criteria that are not yet supported. Returns WS_SUCCESS on success. */
936+
static int ParseMatchCriteria(WOLFSSHD_CONFIG* config, const char* value)
930937
{
931938
int ret = WS_SUCCESS;
932-
char* pt;
939+
const char* pt;
933940

934-
pt = (char*)XSTRSTR(value, mtch);
935-
if (pt != NULL) {
936-
int sz, i;
941+
if (config == NULL || value == NULL) {
942+
ret = WS_BAD_ARGUMENT;
943+
}
937944

938-
pt += (int)XSTRLEN(mtch);
939-
sz = (int)XSTRLEN(pt);
945+
pt = value;
946+
while (ret == WS_SUCCESS && pt != NULL && *pt != '\0') {
947+
const char* tok;
948+
int tokSz;
949+
char** out = NULL;
940950

941-
/* remove spaces between 'mtch' and the user name */
942-
for (i = 0; i < sz; i++) {
943-
if (pt[i] != ' ') break;
951+
/* skip separators preceding the keyword token */
952+
while (WISSPACE((unsigned char)*pt)) {
953+
pt++;
944954
}
945-
if (i == sz) {
946-
wolfSSH_Log(WS_LOG_ERROR,
947-
"[SSHD] No valid input found with Match");
948-
ret = WS_FATAL_ERROR;
955+
if (*pt == '\0') {
956+
break;
949957
}
950958

951-
if (ret == WS_SUCCESS) {
952-
pt += i;
953-
sz -= i;
959+
/* read the keyword token */
960+
tok = pt;
961+
while (*pt != '\0' && !WISSPACE((unsigned char)*pt)) {
962+
pt++;
963+
}
964+
tokSz = (int)(pt - tok);
965+
966+
/* map the keyword to its applies-to field; ignore anything else */
967+
if (tokSz == (int)XSTRLEN("User") &&
968+
WSTRNCMP(tok, "User", tokSz) == 0) {
969+
out = &config->usrAppliesTo;
970+
}
971+
else if (tokSz == (int)XSTRLEN("Group") &&
972+
WSTRNCMP(tok, "Group", tokSz) == 0) {
973+
out = &config->groupAppliesTo;
974+
}
975+
976+
if (out != NULL) {
977+
/* skip separators between the keyword and its name */
978+
while (WISSPACE((unsigned char)*pt)) {
979+
pt++;
980+
}
954981

955-
/* get the actual size of the user name */
956-
for (i = 0; i < sz; i++) {
957-
if (pt[i] == ' ' || pt[i] == '\r' || pt[i] == '\n') break;
982+
/* the next token is the name, taken literally */
983+
tok = pt;
984+
while (*pt != '\0' && !WISSPACE((unsigned char)*pt)) {
985+
pt++;
958986
}
959-
sz = i;
987+
tokSz = (int)(pt - tok);
960988

961-
ret = CreateString(out, pt, sz, config->heap);
989+
if (tokSz == 0) {
990+
wolfSSH_Log(WS_LOG_ERROR,
991+
"[SSHD] Match %s directive is missing a name",
992+
(out == &config->usrAppliesTo) ? "User" : "Group");
993+
ret = WS_FATAL_ERROR;
994+
}
995+
996+
if (ret == WS_SUCCESS) {
997+
/* a repeated keyword replaces the earlier value */
998+
if (*out != NULL) {
999+
FreeString(out, config->heap);
1000+
}
1001+
ret = CreateString(out, tok, tokSz, config->heap);
1002+
}
9621003
}
9631004
}
1005+
9641006
return ret;
9651007
}
9661008

@@ -1052,16 +1094,9 @@ static int HandleMatch(WOLFSSHD_CONFIG** conf, const char* value, int valueSz)
10521094
}
10531095
}
10541096

1055-
/* users the settings apply to */
1097+
/* parse the User/Group criteria the settings apply to */
10561098
if (ret == WS_SUCCESS) {
1057-
ret = AddRestrictedCase(newConf, "User", value,
1058-
&newConf->usrAppliesTo);
1059-
}
1060-
1061-
/* groups the settings apply to */
1062-
if (ret == WS_SUCCESS) {
1063-
ret = AddRestrictedCase(newConf, "Group", value,
1064-
&newConf->groupAppliesTo);
1099+
ret = ParseMatchCriteria(newConf, value);
10651100
}
10661101

10671102
/* @TODO handle , separated user/group list */
@@ -1077,6 +1112,10 @@ static int HandleMatch(WOLFSSHD_CONFIG** conf, const char* value, int valueSz)
10771112
(*conf)->next = newConf;
10781113
(*conf) = newConf;
10791114
}
1115+
else {
1116+
/* newConf was allocated but not linked into the list; free it */
1117+
wolfSSHD_ConfigFree(newConf);
1118+
}
10801119

10811120
(void)valueSz;
10821121
return ret;

0 commit comments

Comments
 (0)