From b219643fc2667abe7d09cda95ef286f8b16dedc6 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Thu, 13 Jan 2022 17:24:56 -0500 Subject: 15150 WPTS FileInfo_Query_FileAccessInformation_DataSuffix Reviewed by: Jason King Approved by: Dan McDonald --- usr/src/uts/common/fs/smbsrv/smb_pathname.c | 95 +++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/usr/src/uts/common/fs/smbsrv/smb_pathname.c b/usr/src/uts/common/fs/smbsrv/smb_pathname.c index 3dd99c9a61..5edbecb733 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_pathname.c +++ b/usr/src/uts/common/fs/smbsrv/smb_pathname.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. - * Copyright 2021 RackTop Systems, Inc. + * Copyright 2022 RackTop Systems, Inc. */ #include @@ -804,47 +804,99 @@ smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path) /* parse pn->pn_path into its constituent parts */ pname = pn->pn_path; - fname = strrchr(pn->pn_path, '\\'); - if (fname) { + /* + * Split the string between the directory and filename. + * Either part may be empty. + * + * Fill in pn->pn_pname (the path name) + */ + fname = strrchr(pname, '\\'); + if (fname != NULL) { if (fname == pname) { + /* + * Last '/' is at start of string. + * No directory part (dir is root) + */ pn->pn_pname = NULL; } else { + /* + * Directory part ends at the last '/' + * Temporarily truncate and copy + */ *fname = '\0'; pn->pn_pname = smb_pathname_strdup(sr, pname); *fname = '\\'; } ++fname; + /* fname is just after the '/' */ } else { + /* + * No '/' at all in the string. + * It's all filename + */ fname = pname; pn->pn_pname = NULL; } - if (fname[0] == '\0') { - pn->pn_fname = NULL; + /* + * Find end of the filename part of the string, + * which may be the null terminator, or may be + * the start of the optional :sname suffix. + */ + sname = strchr(fname, ':'); + if (sname == NULL) { + /* + * No :sname suffix. We're done. + */ + pn->pn_fname = smb_pathname_strdup(sr, fname); return; } - if (!smb_is_stream_name(fname)) { + /* + * We have a stream name, and maybe a stream type. + * Can't use smb_is_stream_name(fname) here because + * we need to allow sname="::$DATA" + */ + if (sname == fname) { + /* + * The ":sname" part is at the start of + * the file name, which means that the + * file name is "" and this pathname + * refers to a stream on the directory. + */ + pn->pn_fname = NULL; + } else { + /* + * The filename part ends at the ':' + * Temporarily truncate and copy + */ + *sname = '\0'; pn->pn_fname = smb_pathname_strdup(sr, fname); - return; + *sname = ':'; } /* - * find sname and stype in fname. - * sname can't be NULL smb_is_stream_name checks this + * Special case "::$DATA" which "points to" + * the "unnamed" stream (the file itself). + * Basically ignore the "::$DATA" */ - sname = strchr(fname, ':'); - if (sname == fname) - fname = NULL; - else { + if (strcasecmp(sname, "::$DATA") == 0) { + ASSERT(sname >= pname && + sname < (pname + strlen(pname))); *sname = '\0'; - pn->pn_fname = - smb_pathname_strdup(sr, fname); - *sname = ':'; + return; } + /* + * sname points to ":sname:stype" in pn_path + * If ":stype" is missing, add it, then set + * pn_stype to point after the 2nd ':' + * + * Caller knows pn_stype is NOT allocated. + * Allocations here are free'd via smb_srm_fini + */ pn->pn_sname = smb_pathname_strdup(sr, sname); pn->pn_stype = strchr(pn->pn_sname + 1, ':'); if (pn->pn_stype) { @@ -1065,6 +1117,9 @@ smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn) } } + if (pn->pn_sname) + return (smb_validate_stream_name(sr, pn)); + return (B_TRUE); } @@ -1230,14 +1285,6 @@ smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn) ASSERT(pn); ASSERT(pn->pn_sname); - if ((!(pn->pn_sname)) || - ((pn->pn_pname) && !(pn->pn_fname))) { - smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, - ERRDOS, ERROR_INVALID_NAME); - return (B_FALSE); - } - - if (pn->pn_stype != NULL) { for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) { if (strcasecmp(pn->pn_stype, strmtype[i]) == 0) -- cgit v1.2.3