1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-01 04:58:35 +03:00

libcli: New routine symlink_target_path for [MS-SMB2] 2.2.2.2.1.1

Right now the only user is the user-space symlink following in
smbd. We will use it in libsmb as well to correctly handle
STOPPED_ON_SYMLINK. When trying to upstream that code I found the
previous_slash function incredibly hard to understand.

This new routine makes copy of "const char *_name_in", so that we can
replace previous_slash with a simple strrchr_m. If that's too
slow (which I doubt, this is "only" chasing symlinks) we can always do
something smarter again.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
This commit is contained in:
Volker Lendecke 2024-07-03 15:55:46 +02:00
parent 659cb9f728
commit b91e257f56
2 changed files with 102 additions and 0 deletions

View File

@ -565,3 +565,97 @@ ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src,
return ret;
}
/*
* Implement [MS-SMB2] 2.2.2.2.1.1 Handling the Symbolic Link Error Response
*/
int symlink_target_path(TALLOC_CTX *ctx,
const char *_name_in,
size_t num_unparsed,
const char *substitute,
bool relative,
char separator,
char **_target)
{
size_t name_in_len = strlen(_name_in);
size_t num_parsed;
char name_in[name_in_len + 1];
char *unparsed = NULL;
char *syml = NULL;
char *target = NULL;
if (num_unparsed > name_in_len) {
return EINVAL;
}
num_parsed = name_in_len - num_unparsed;
/*
* We need to NULL out separators in name_in. Make a copy of
* _name_in, which is a const char *.
*/
memcpy(name_in, _name_in, sizeof(name_in));
unparsed = name_in + num_parsed;
if ((num_unparsed != 0) && (unparsed[0] != separator)) {
/*
* Symlinks in the middle of name_in must end in a separator
*/
return EINVAL;
}
if (!relative) {
/*
* From [MS-SMB2] 2.2.2.2.1.1:
*
* If the SYMLINK_FLAG_RELATIVE flag is not set in the Flags
* field of the symbolic link error response, the unparsed
* portion of the file name MUST be appended to the substitute
* name to create the new target path name.
*/
target = talloc_asprintf(ctx, "%s%s", substitute, unparsed);
goto done;
}
/*
* From [MS-SMB2] 2.2.2.2.1.1:
*
* If the SYMLINK_FLAG_RELATIVE flag is set in the Flags field
* of the symbolic link error response, the symbolic link name
* MUST be identified by backing up one path name element from
* the unparsed portion of the path name. The symbolic link
* MUST be replaced with the substitute name to create the new
* target path name.
*/
{
char symlink_end_char = unparsed[0]; /* '\0' or a separator */
unparsed[0] = '\0';
syml = strrchr_m(name_in, separator);
unparsed[0] = symlink_end_char;
}
if (syml == NULL) {
/*
* Nothing to back up to, the symlink was the first
* path component.
*/
name_in[0] = '\0';
} else {
/*
* Make "name_in" up to the symlink usable for asprintf
*/
syml[1] = '\0';
}
target = talloc_asprintf(ctx, "%s%s%s", name_in, substitute, unparsed);
done:
if (target == NULL) {
return ENOMEM;
}
*_target = target;
return 0;
}

View File

@ -79,4 +79,12 @@ ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src,
uint8_t *buf,
size_t buflen);
int symlink_target_path(TALLOC_CTX *ctx,
const char *_name_in,
size_t num_unparsed,
const char *substitute,
bool relative,
char separator,
char **_target);
#endif