in src/policy.c [894:1032]
bool _qd_policy_approve_link_name_tree(const char *username, const char *allowed, const char *proposed,
qd_parse_tree_t *tree)
{
// Verify string sizes are usable
size_t proposed_len = strlen(proposed);
if (proposed_len == 0) {
// degenerate case of blank proposed name being opened. will never match anything.
return false;
}
size_t a_len = strlen(allowed);
if (a_len == 0) {
// no names in 'allowed'.
return false;
}
if (!username)
username = "";
size_t username_len = strlen(username);
size_t usersubst_len = strlen(user_subst_key);
// make a writable, disposable copy of the csv string
char * dup = strdup(allowed);
if (!dup) {
return false;
}
char * dupend = dup + strlen(dup);
char * pch = dup;
// get a scratch buffer for writing temporary match strings
char * pName = (char *)malloc(QPALN_SIZE);
if (!pName) {
free(dup);
return false;
}
size_t pName_sz = QPALN_SIZE;
bool result = false;
while (pch < dupend) {
// the tuple strings
char *pChar, *pS1, *pS2;
size_t sChar, sS1, sS2;
// extract control field
sChar = strcspn(pch, QPALN_COMMA_SEP);
if (sChar != 1) { assert(false); break;}
pChar = pch;
pChar[sChar] = '\0';
pch += sChar + 1;
if (pch >= dupend) { assert(false); break; }
// extract prefix field S1
sS1 = strcspn(pch, QPALN_COMMA_SEP);
pS1 = pch;
pS1[sS1] = '\0';
pch += sS1 + 1;
if (pch > dupend) { assert(false); break; }
// extract suffix field S2
sS2 = strcspn(pch, QPALN_COMMA_SEP);
pS2 = pch;
pch += sS2 + 1;
pS2[sS2] = '\0';
// compute size of generated string and make sure
// temporary buffer is big enough to hold it.
size_t sName = proposed_len + usersubst_len + 1;
if (sName > pName_sz) {
size_t newSize = sName + QPALN_SIZE;
char * newPtr = (char *)realloc(pName, newSize);
if (!newPtr) {
break;
}
pName = newPtr;
pName_sz = newSize;
}
// From the rule clause construct what the rule is allowing
// given the user name associated with this request.
if (*pChar == *user_subst_i_absent) {
// Substitution spec is absent. The search string is the literal
// S1 in the rule.
snprintf(pName, sName, "%s", proposed);
}
else if (*pChar == *user_subst_i_prefix) {
// Substitution spec is prefix.
if (strncmp(proposed, username, username_len) != 0)
continue; // Denied. Proposed does not have username prefix.
// Check that username is not part of a larger token.
if (username_len == proposed_len) {
// If username is the whole link name then allow if lookup is ok
} else {
// Proposed is longer than username. Make sure that proposed
// is delimited after user name.
if (!is_token_sep(proposed[username_len])) {
continue; // denied. proposed has username prefix it it not a delimited user name
}
}
snprintf(pName, sName, "%s%s", user_subst_key, proposed + username_len);
}
else if (*pChar == *user_subst_i_embed) {
assert(false); // not supported
}
else if (*pChar == *user_subst_i_suffix) {
// Check that link name has username suffix
if (username_len > proposed_len) {
continue; // denied. proposed name is too short to hold username
} else {
//---
// if (username_len == proposed_len) { ... }
// unreachable code. substitution-only rule clause is handled by prefix
//---
if (!is_token_sep(proposed[proposed_len - username_len - 1])) {
continue; // denied. proposed suffix it it not a delimited user name
}
if (strncmp(&proposed[proposed_len - username_len], username, username_len) != 0) {
continue; // denied. username is not the suffix
}
}
pName[0] = '\0';
strncat(pName, proposed, proposed_len - username_len);
strcat(pName, user_subst_key);
}
else {
assert(false);
break;
}
void * unused_payload = 0;
result = qd_parse_tree_retrieve_match_str(tree, pName, &unused_payload);
if (result)
break;
}
free(pName);
free(dup);
return result;
}