1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

s3:lib: add a new samba_path_matching* infrastructure

This aims to replace the current is_in_path() code in the long run.

For now it implements samba_path_matching_mswild_create()
in order to replace is_in_path() in the long run.

But there will be other "backends" using regexec() too.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
Stefan Metzmacher 2021-06-09 14:44:39 +02:00
parent 0a459c6b2d
commit 845a59919e
4 changed files with 367 additions and 4 deletions

282
source3/lib/util_matching.c Normal file
View File

@ -0,0 +1,282 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Stefan Metzmacher 2021
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/util_matching.h"
#include "lib/util/string_wrappers.h"
struct samba_path_matching_entry {
const char *name;
bool is_wild;
};
struct samba_path_matching_result {
ssize_t replace_start;
ssize_t replace_end;
bool match;
};
struct samba_path_matching {
bool case_sensitive;
NTSTATUS (*matching_fn)(const struct samba_path_matching *pm,
const struct samba_path_matching_entry *e,
const char *namecomponent,
struct samba_path_matching_result *result);
size_t num_entries;
struct samba_path_matching_entry *entries;
};
static NTSTATUS samba_path_matching_split(TALLOC_CTX *mem_ctx,
const char *namelist_in,
struct samba_path_matching **ppm)
{
TALLOC_CTX *frame = talloc_stackframe();
char *name_end = NULL;
char *namelist = NULL;
char *namelist_end = NULL;
char *nameptr = NULL;
struct samba_path_matching *pm = NULL;
size_t num_entries = 0;
struct samba_path_matching_entry *entries = NULL;
*ppm = NULL;
pm = talloc_zero(mem_ctx, struct samba_path_matching);
if (pm == NULL) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
talloc_reparent(mem_ctx, frame, pm);
namelist = talloc_strdup(frame, namelist_in);
if (namelist == NULL) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
nameptr = namelist;
namelist_end = &namelist[strlen(namelist)];
/*
* We need to make two passes over the string. The
* first to count the number of elements, the second
* to split it.
*
* The 1st time entries is NULL.
* the 2nd time entries is allocated.
*/
again:
while (nameptr <= namelist_end) {
/* anything left? */
if (*nameptr == '\0') {
break;
}
if (*nameptr == '/') {
/* cope with multiple (useless) /s) */
nameptr++;
continue;
}
/* find the next '/' or consume remaining */
name_end = strchr_m(nameptr, '/');
if (entries != NULL) {
if (name_end != NULL) {
*name_end = '\0';
}
entries[num_entries].name = talloc_strdup(entries,
nameptr);
if (entries[num_entries].name == NULL) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
}
num_entries++;
if (name_end != NULL) {
/* next segment please */
nameptr = name_end + 1;
continue;
}
/* no entries remaining */
break;
}
if (num_entries == 0) {
/*
* No entries in the first round => we're done
*/
goto done;
}
if (entries != NULL) {
/*
* We finished the 2nd round => we're done
*/
goto done;
}
/*
* Now allocate the array and loop again
* in order to split the names.
*/
entries = talloc_zero_array(pm,
struct samba_path_matching_entry,
num_entries);
if (entries == NULL) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
num_entries = 0;
nameptr = namelist;
goto again;
done:
pm->num_entries = num_entries;
pm->entries = entries;
*ppm = talloc_move(mem_ctx, &pm);
TALLOC_FREE(frame);
return NT_STATUS_OK;
};
static NTSTATUS samba_path_create_mswild_fn(const struct samba_path_matching *pm,
const struct samba_path_matching_entry *e,
const char *namecomponent,
struct samba_path_matching_result *result)
{
bool match = false;
if (e->is_wild) {
match = mask_match(namecomponent, e->name, pm->case_sensitive);
} else if (pm->case_sensitive) {
match = (strcmp(namecomponent, e->name) == 0);
} else {
match = (strcasecmp_m(namecomponent, e->name) == 0);
}
*result = (struct samba_path_matching_result) {
.match = match,
.replace_start = -1,
.replace_end = -1,
};
return NT_STATUS_OK;
}
NTSTATUS samba_path_matching_mswild_create(TALLOC_CTX *mem_ctx,
bool case_sensitive,
const char *namelist_in,
struct samba_path_matching **ppm)
{
NTSTATUS status;
TALLOC_CTX *frame = talloc_stackframe();
struct samba_path_matching *pm = NULL;
size_t i;
*ppm = NULL;
status = samba_path_matching_split(mem_ctx, namelist_in, &pm);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
return status;
}
talloc_reparent(mem_ctx, frame, pm);
for (i = 0; i < pm->num_entries; i++) {
struct samba_path_matching_entry *e = &pm->entries[i];
e->is_wild = ms_has_wild(e->name);
}
pm->case_sensitive = case_sensitive;
pm->matching_fn = samba_path_create_mswild_fn;
*ppm = talloc_move(mem_ctx, &pm);
TALLOC_FREE(frame);
return NT_STATUS_OK;
};
NTSTATUS samba_path_matching_check_last_component(struct samba_path_matching *pm,
const char *name,
ssize_t *p_match_idx,
ssize_t *p_replace_start,
ssize_t *p_replace_end)
{
struct samba_path_matching_result result = {
.match = false,
.replace_start = -1,
.replace_end = -1,
};
ssize_t match_idx = -1;
NTSTATUS status = NT_STATUS_OK;
const char *last_component = NULL;
size_t i;
if (pm->num_entries == 0) {
goto finish;
}
/* Get the last component of the unix name. */
last_component = strrchr_m(name, '/');
if (last_component == NULL) {
last_component = name;
} else {
last_component++; /* Go past '/' */
}
for (i = 0; i < pm->num_entries; i++) {
struct samba_path_matching_entry *e = &pm->entries[i];
status = pm->matching_fn(pm, e, last_component, &result);
if (!NT_STATUS_IS_OK(status)) {
result = (struct samba_path_matching_result) {
.match = false,
.replace_start = -1,
.replace_end = -1,
};
goto finish;
}
if (result.match) {
match_idx = i;
goto finish;
}
}
finish:
*p_match_idx = match_idx;
if (p_replace_start != NULL) {
size_t last_ofs = 0;
if (result.replace_start >= 0) {
last_ofs = PTR_DIFF(last_component, name);
}
*p_replace_start = last_ofs + result.replace_start;
}
if (p_replace_end != NULL) {
size_t last_ofs = 0;
if (result.replace_end >= 0) {
last_ofs = PTR_DIFF(last_component, name);
}
*p_replace_end = last_ofs + result.replace_end;
}
return status;
}

View File

@ -0,0 +1,36 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Stefan Metzmacher 2021
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SAMBA_LIB_UTIL_MATCHING_H_
#define _SAMBA_LIB_UTIL_MATCHING_H_
struct samba_path_matching;
NTSTATUS samba_path_matching_mswild_create(TALLOC_CTX *mem_ctx,
bool case_sensitive,
const char *namelist_in,
struct samba_path_matching **ppm);
NTSTATUS samba_path_matching_check_last_component(struct samba_path_matching *pm,
const char *name,
ssize_t *p_match_idx,
ssize_t *p_replace_start,
ssize_t *p_replace_end);
#endif /* _SAMBA_LIB_UTIL_MATCHING_H_ */

View File

@ -18,13 +18,16 @@
*/
#include "includes.h"
#include "lib/util_matching.h"
#include "proto.h"
bool run_str_match_mswild(int dummy)
{
const char *namelist = "/abc*.txt/xyz*.dat/a0123456789Z/";
name_compare_entry *name_entries = NULL;
const struct test_name {
struct samba_path_matching *pmcs = NULL;
struct samba_path_matching *pmci = NULL;
const struct str_match_mswild_name {
const char *name;
ssize_t case_sensitive_idx;
ssize_t case_insensitive_idx;
@ -57,6 +60,7 @@ bool run_str_match_mswild(int dummy)
.case_sensitive_idx = -1,
.case_insensitive_idx = 2,
}};
NTSTATUS status;
size_t i;
bool ret = true;
@ -65,10 +69,26 @@ bool run_str_match_mswild(int dummy)
set_namearray(&name_entries, namelist);
SMB_ASSERT(name_entries != NULL);
status = samba_path_matching_mswild_create(talloc_tos(),
true, /* case_sensitive */
namelist,
&pmcs);
SMB_ASSERT(NT_STATUS_IS_OK(status));
status = samba_path_matching_mswild_create(talloc_tos(),
false, /* case_sensitive */
namelist,
&pmci);
SMB_ASSERT(NT_STATUS_IS_OK(status));
for (i = 0; i < ARRAY_SIZE(names); i++) {
const struct test_name *n = &names[i];
const struct str_match_mswild_name *n = &names[i];
bool case_sensitive_match;
bool case_insensitive_match;
ssize_t cs_match_idx = -1;
ssize_t ci_match_idx = -1;
ssize_t replace_start = -1;
ssize_t replace_end = -1;
bool ok = true;
case_sensitive_match = is_in_path(n->name,
@ -79,6 +99,17 @@ bool run_str_match_mswild(int dummy)
} else {
ok &= !case_sensitive_match;
}
status = samba_path_matching_check_last_component(pmcs,
n->name,
&cs_match_idx,
&replace_start,
&replace_end);
SMB_ASSERT(NT_STATUS_IS_OK(status));
SMB_ASSERT(replace_start == -1);
SMB_ASSERT(replace_end == -1);
if (n->case_sensitive_idx != cs_match_idx) {
ok = false;
}
case_insensitive_match = is_in_path(n->name,
name_entries,
false);
@ -87,16 +118,29 @@ bool run_str_match_mswild(int dummy)
} else {
ok &= !case_insensitive_match;
}
status = samba_path_matching_check_last_component(pmci,
n->name,
&ci_match_idx,
&replace_start,
&replace_end);
SMB_ASSERT(NT_STATUS_IS_OK(status));
SMB_ASSERT(replace_start == -1);
SMB_ASSERT(replace_end == -1);
if (n->case_insensitive_idx != ci_match_idx) {
ok = false;
}
d_fprintf(stderr, "name[%s] "
"case_sensitive[TIDX=%zd;MATCH=%u] "
"case_insensitive[TIDX=%zd;MATCH=%u] "
"case_sensitive[TIDX=%zd;MATCH=%u;MIDX=%zd] "
"case_insensitive[TIDX=%zd;MATCH=%u;MIDX=%zd] "
"%s\n",
n->name,
n->case_sensitive_idx,
case_sensitive_match,
cs_match_idx,
n->case_insensitive_idx,
case_insensitive_match,
ci_match_idx,
ok ? "OK" : "FAIL");
ret &= ok;

View File

@ -287,6 +287,7 @@ bld.SAMBA3_SUBSYSTEM('samba3util',
lib/util_file.c
lib/util.c
lib/util_path.c
lib/util_matching.c
lib/util_procid.c
lib/util_sock.c
lib/util_tsock.c