From: Stefan Metzmacher Date: Fri, 11 Jun 2021 21:08:19 +0000 (+0000) Subject: vfs_preopen: make use of any hints from samba_path_matching_check_last_component() X-Git-Tag: tevent-0.11.0~95 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=430cbfc7918939fde22d8da2327451b6801173bd;p=thirdparty%2Fsamba.git vfs_preopen: make use of any hints from samba_path_matching_check_last_component() samba_path_matching_check_last_component() may return the start and end offset of a submatch (for us the bytes where the digits are expected). We use that in order to allow preopen_parse_fname() to just look at these bytes and ignore any trailing digits after the submatch. For the current use of samba_path_matching_mswild_create(), there's no difference as we'll always get replace_start=-1 and replace_end=-1. But the next commit will make optional use of samba_path_matching_regex_sub1_create(), which will change the situation and allow to return hints we got from regexec(). Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme --- diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c index fa61d36d533..6ee3c059a07 100644 --- a/source3/modules/vfs_preopen.c +++ b/source3/modules/vfs_preopen.c @@ -359,6 +359,7 @@ static struct preopen_state *preopen_state_get(vfs_handle_struct *handle) static bool preopen_parse_fname(const char *fname, uint64_t *pnum, size_t *pstart_idx, int *pnum_digits) { + char digits[PREOPEN_MAX_DIGITS+1] = { 0, }; const char *p; char *q = NULL; unsigned long long num; @@ -366,6 +367,40 @@ static bool preopen_parse_fname(const char *fname, uint64_t *pnum, int num_digits = -1; int error = 0; + if (*pstart_idx > 0 && *pnum_digits > 0) { + /* + * If the caller knowns + * how many digits are expected + * and on what position, + * we should copy the exact + * subset before we start + * parsing the string into a number + */ + + if (*pnum_digits < 1) { + /* + * We need at least one digit + */ + return false; + } + if (*pnum_digits > PREOPEN_MAX_DIGITS) { + /* + * a string with as much digits as + * PREOPEN_MAX_DIGITS is the longest + * string that would make any sense for us. + * + * The rest will be checked via + * smb_strtoull(). + */ + return false; + } + p = fname + *pstart_idx; + memcpy(digits, p, *pnum_digits); + p = digits; + start_idx = *pstart_idx; + goto parse; + } + p = strrchr_m(fname, '/'); if (p == NULL) { p = fname; @@ -385,6 +420,7 @@ static bool preopen_parse_fname(const char *fname, uint64_t *pnum, start_idx = (p - fname); +parse: num = smb_strtoull(p, (char **)&q, 10, &error, SMB_STR_STANDARD); if (error != 0) { return false; @@ -397,6 +433,15 @@ static bool preopen_parse_fname(const char *fname, uint64_t *pnum, num_digits = (q - p); + if (*pnum_digits != -1 && *pnum_digits != num_digits) { + /* + * If the caller knowns how many digits + * it expects we should fail if we got something + * different. + */ + return false; + } + *pnum = num; *pstart_idx = start_idx; *pnum_digits = num_digits; @@ -446,6 +491,8 @@ static int preopen_openat(struct vfs_handle_struct *handle, int new_digits = -1; size_t new_end = 0; ssize_t match_idx = -1; + ssize_t replace_start = -1; + ssize_t replace_end = -1; bool need_reset = false; DEBUG(10, ("preopen_open called on %s\n", smb_fname_str_dbg(smb_fname))); @@ -493,8 +540,8 @@ static int preopen_openat(struct vfs_handle_struct *handle, status = samba_path_matching_check_last_component(state->preopen_names, smb_fname->base_name, &match_idx, - NULL, /* replace_start */ - NULL);/* replace_end */ + &replace_start, + &replace_end); if (!NT_STATUS_IS_OK(status)) { match_idx = -1; } @@ -511,6 +558,12 @@ static int preopen_openat(struct vfs_handle_struct *handle, return res; } + if (replace_start != -1 && replace_end != -1) { + size_t dirofs = strlen(dirname) + 1; + new_start = dirofs + replace_start; + new_digits = replace_end - replace_start; + } + if (!preopen_parse_fname(new_template, &num, &new_start, &new_digits)) { TALLOC_FREE(new_template);