3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  24  */
  25 
  26 #include <smbsrv/smb_kproto.h>
  27 #include <smbsrv/smb_fsops.h>
  28 #include <sys/pathname.h>
  29 #include <sys/sdt.h>
  30 
  31 static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
  32 static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
  33 static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
  34     vnode_t **, vnode_t *, vnode_t *, smb_attr_t *attr, cred_t *);
  35 static char *smb_pathname_strdup(smb_request_t *, const char *);
  36 static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
  37 static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
  38 static void smb_pathname_preprocess_quota(smb_request_t *, smb_pathname_t *);
  39 static int smb_pathname_dfs_preprocess(smb_request_t *, char *, size_t);
  40 static void smb_pathname_preprocess_adminshare(smb_request_t *,
  41     smb_pathname_t *);
  42 
  43 
 
 
 134  *      - "chroot" behavior of share root (handled by lookuppnvp)
 135  *
 136  * In addition, it needs to replace backslashes with forward slashes.  It also
 137  * ensures that link processing is done correctly, and that directory
 138  * information requested by the caller is correctly returned (i.e. for paths
 139  * with a link in the last component, the directory information of the
 140  * link and not the target needs to be returned).
 141  */
 142 
 143 int
 144 smb_pathname_reduce(
 145     smb_request_t       *sr,
 146     cred_t              *cred,
 147     const char          *path,
 148     smb_node_t          *share_root_node,
 149     smb_node_t          *cur_node,
 150     smb_node_t          **dir_node,
 151     char                *last_component)
 152 {
 153         smb_node_t      *root_node;
 154         pathname_t      ppn;
 155         char            *usepath;
 156         int             lookup_flags = FOLLOW;
 157         int             trailing_slash = 0;
 158         int             err = 0;
 159         int             len;
 160         smb_node_t      *vss_cur_node;
 161         smb_node_t      *vss_root_node;
 162         smb_node_t      *local_cur_node;
 163         smb_node_t      *local_root_node;
 164 
 165         ASSERT(dir_node);
 166         ASSERT(last_component);
 167 
 168         *dir_node = NULL;
 169         *last_component = '\0';
 170         vss_cur_node = NULL;
 171         vss_root_node = NULL;
 172 
 173         if (sr && sr->tid_tree) {
 174                 if (STYPE_ISIPC(sr->tid_tree->t_res_type))
 175                         return (EACCES);
 176         }
 177 
 178         if (SMB_TREE_IS_CASEINSENSITIVE(sr))
 179                 lookup_flags |= FIGNORECASE;
 180 
 181         if (path == NULL)
 182                 return (EINVAL);
 183 
 184         if (*path == '\0')
 185                 return (ENOENT);
 186 
 187         usepath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
 188 
 189         len = strlcpy(usepath, path, SMB_MAXPATHLEN);
 190         if (len >= SMB_MAXPATHLEN) {
 191                 kmem_free(usepath, SMB_MAXPATHLEN);
 
 207 
 208         if (SMB_TREE_IS_DFSROOT(sr)) {
 209                 int is_dfs;
 210                 if (sr->session->dialect >= SMB_VERS_2_BASE)
 211                         is_dfs = sr->smb2_hdr_flags &
 212                             SMB2_FLAGS_DFS_OPERATIONS;
 213                 else
 214                         is_dfs = sr->smb_flg2 & SMB_FLAGS2_DFS;
 215                 if (is_dfs != 0) {
 216                         err = smb_pathname_dfs_preprocess(sr, usepath,
 217                             SMB_MAXPATHLEN);
 218                         if (err != 0) {
 219                                 kmem_free(usepath, SMB_MAXPATHLEN);
 220                                 return (err);
 221                         }
 222                         len = strlen(usepath);
 223                 }
 224         }
 225 
 226         if (sr != NULL) {
 227                 boolean_t chk_vss;
 228                 if (sr->session->dialect >= SMB_VERS_2_BASE)
 229                         chk_vss = sr->arg.open.create_timewarp;
 230                 else
 231                         chk_vss = (sr->smb_flg2 &
 232                             SMB_FLAGS2_REPARSE_PATH) != 0;
 233                 if (chk_vss) {
 234                         err = smb_vss_lookup_nodes(sr, root_node, cur_node,
 235                             usepath, &vss_cur_node, &vss_root_node);
 236                         if (err != 0) {
 237                                 kmem_free(usepath, SMB_MAXPATHLEN);
 238                                 return (err);
 239                         }
 240 
 241                         len = strlen(usepath);
 242                         local_cur_node = vss_cur_node;
 243                         local_root_node = vss_root_node;
 244                 }
 245         }
 246 
 247         if (usepath[len - 1] == '/')
 248                 trailing_slash = 1;
 249 
 250         (void) strcanon(usepath, "/");
 251 
 252         (void) pn_alloc_sz(&ppn, SMB_MAXPATHLEN);
 253 
 254         if ((err = pn_set(&ppn, usepath)) != 0) {
 255                 (void) pn_free(&ppn);
 256                 kmem_free(usepath, SMB_MAXPATHLEN);
 257                 if (vss_cur_node != NULL)
 258                         (void) smb_node_release(vss_cur_node);
 259                 if (vss_root_node != NULL)
 260                         (void) smb_node_release(vss_root_node);
 261                 return (err);
 262         }
 263 
 264         /*
 265          * If a path does not have a trailing slash, strip off the
 266          * last component.  (We only need to return an smb_node for
 267          * the second to last component; a name is returned for the
 268          * last component.)
 269          */
 270 
 271         if (trailing_slash) {
 272                 (void) strlcpy(last_component, ".", MAXNAMELEN);
 273         } else {
 274                 (void) pn_setlast(&ppn);
 275                 (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
 276                 ppn.pn_path[0] = '\0';
 277         }
 278 
 279         if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
 280                 smb_node_ref(local_cur_node);
 281                 *dir_node = local_cur_node;
 282         } else {
 283                 err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
 284                     local_root_node, local_cur_node, NULL, dir_node, cred);
 285         }
 286 
 287         (void) pn_free(&ppn);
 288         kmem_free(usepath, SMB_MAXPATHLEN);
 289 
 290         /*
 291          * Prevent traversal to another file system if mount point
 292          * traversal is disabled.
 293          *
 294          * Note that we disregard whether the traversal of the path went
 295          * outside of the file system and then came back (say via a link).
 296          * This means that only symlinks that are expressed relatively to
 297          * the share root work.
 298          *
 299          * share_root_node is NULL when mapping a share, so we disregard
 300          * that case.
 301          */
 302 
 303         if ((err == 0) && share_root_node) {
 304                 if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp) {
 305                         err = EACCES;
 306                         if ((sr) && (sr)->tid_tree &&
 307                             smb_tree_has_feature((sr)->tid_tree,
 308                             SMB_TREE_TRAVERSE_MOUNTS))
 309                                 err = 0;
 310                 }
 311         }
 312 
 313         if (err) {
 314                 if (*dir_node) {
 315                         (void) smb_node_release(*dir_node);
 316                         *dir_node = NULL;
 317                 }
 318                 *last_component = 0;
 319         }
 320 
 321         if (vss_cur_node != NULL)
 322                 (void) smb_node_release(vss_cur_node);
 323         if (vss_root_node != NULL)
 324                 (void) smb_node_release(vss_root_node);
 325 
 326         return (err);
 327 }
 328 
 329 /*
 330  * smb_pathname()
 331  * wrapper to lookuppnvp().  Handles name unmangling.
 332  *
 333  * *dir_node is the true directory of the target *node.
 334  *
 335  * If any component but the last in the path is not found, ENOTDIR instead of
 336  * ENOENT will be returned.
 337  *
 338  * Path components are processed one at a time so that smb_nodes can be
 339  * created for each component.  This allows the n_dnode field in the
 340  * smb_node to be properly populated.
 341  *
 342  * Because of the above, links are also processed in this routine
 343  * (i.e., we do not pass the FOLLOW flag to lookuppnvp()).  This
 344  * will allow smb_nodes to be created for each component of a link.
 345  *
 346  * Mangle checking is per component. If a name is mangled, when the
 347  * unmangled name is passed to smb_pathname_lookup() do not pass
 348  * FIGNORECASE, since the unmangled name is the real on-disk name.
 349  * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
 350  * file system to return "first match" in the event of a case collision.
 351  *
 352  * If CATIA character translation is enabled it is applied to each
 353  * component before passing the component to smb_pathname_lookup().
 354  * After smb_pathname_lookup() the reverse translation is applied.
 355  */
 356 
 357 int
 358 smb_pathname(smb_request_t *sr, char *path, int flags,
 359     smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
 360     smb_node_t **ret_node, cred_t *cred)
 361 {
 362         char            *component, *real_name, *namep;
 363         pathname_t      pn, rpn, upn, link_pn;
 364         smb_node_t      *dnode, *fnode;
 365         smb_attr_t      attr;
 366         vnode_t         *rootvp, *vp;
 367         size_t          pathleft;
 368         int             err = 0;
 369         int             nlink = 0;
 370         int             local_flags;
 371         uint32_t        abe_flag = 0;
 372         char            namebuf[MAXNAMELEN];
 373 
 374         if (path == NULL)
 375                 return (EINVAL);
 376 
 377         ASSERT(root_node);
 378         ASSERT(cur_node);
 379         ASSERT(ret_node);
 380 
 381         *ret_node = NULL;
 382 
 383         if (dir_node)
 384                 *dir_node = NULL;
 385 
 386         (void) pn_alloc_sz(&upn, SMB_MAXPATHLEN);
 387 
 388         if ((err = pn_set(&upn, path)) != 0) {
 389                 (void) pn_free(&upn);
 390                 return (err);
 391         }
 392 
 393         if (SMB_TREE_SUPPORTS_ABE(sr))
 394                 abe_flag = SMB_ABE;
 395 
 396         (void) pn_alloc(&pn);
 397         (void) pn_alloc(&rpn);
 398 
 399         component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 400         real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 401 
 402         fnode = NULL;
 403         dnode = cur_node;
 404         smb_node_ref(dnode);
 405         rootvp = root_node->vp;
 406 
 407         while ((pathleft = pn_pathleft(&upn)) != 0) {
 408                 if (fnode) {
 409                         smb_node_release(dnode);
 410                         dnode = fnode;
 411                         fnode = NULL;
 412                 }
 413 
 414                 if ((err = pn_getcomponent(&upn, component)) != 0)
 415                         break;
 416 
 417                 if ((namep = smb_pathname_catia_v5tov4(sr, component,
 418                     namebuf, sizeof (namebuf))) == NULL) {
 419                         err = EILSEQ;
 420                         break;
 421                 }
 422 
 423                 if ((err = pn_set(&pn, namep)) != 0)
 424                         break;
 425 
 426                 local_flags = flags & FIGNORECASE;
 427                 err = smb_pathname_lookup(&pn, &rpn, local_flags,
 428                     &vp, rootvp, dnode->vp, &attr, cred);
 429 
 430                 if (err) {
 431                         if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
 432                             !smb_maybe_mangled(component))
 433                                 break;
 434 
 435                         if ((err = smb_unmangle(dnode, component,
 436                             real_name, MAXNAMELEN, abe_flag)) != 0)
 437                                 break;
 438 
 439                         if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
 440                             namebuf, sizeof (namebuf))) == NULL) {
 441                                 err = EILSEQ;
 442                                 break;
 443                         }
 444 
 445                         if ((err = pn_set(&pn, namep)) != 0)
 
 510                         }
 511 
 512                         namep = smb_pathname_catia_v4tov5(sr, namep,
 513                             namebuf, sizeof (namebuf));
 514 
 515                         fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
 516                             dnode, NULL);
 517                         VN_RELE(vp);
 518 
 519                         if (fnode == NULL) {
 520                                 err = ENOMEM;
 521                                 break;
 522                         }
 523                 }
 524 
 525                 while (upn.pn_path[0] == '/') {
 526                         upn.pn_path++;
 527                         upn.pn_pathlen--;
 528                 }
 529 
 530         }
 531 
 532         if ((pathleft) && (err == ENOENT))
 533                 err = ENOTDIR;
 534 
 535         if (err) {
 536                 if (fnode)
 537                         smb_node_release(fnode);
 538                 if (dnode)
 539                         smb_node_release(dnode);
 540         } else {
 541                 *ret_node = fnode;
 542 
 543                 if (dir_node)
 544                         *dir_node = dnode;
 545                 else
 546                         smb_node_release(dnode);
 547         }
 548 
 549         kmem_free(component, MAXNAMELEN);
 550         kmem_free(real_name, MAXNAMELEN);
 551         (void) pn_free(&pn);
 552         (void) pn_free(&rpn);
 553         (void) pn_free(&upn);
 554 
 555         return (err);
 556 }
 557 
 558 /*
 559  * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
 560  * and will be released within lookuppnvp().
 561  */
 
 890 {
 891         char *path = pn->pn_path;
 892 
 893         /* ignore any initial "\\" */
 894         path += strspn(path, "\\");
 895 
 896         /* If first component of path is ".." -> PATH_SYNTAX_BAD */
 897         if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
 898                 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
 899                     ERRDOS, ERROR_BAD_PATHNAME);
 900                 return (B_FALSE);
 901         }
 902 
 903         /* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
 904         if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
 905                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 906                     ERRDOS, ERROR_INVALID_NAME);
 907                 return (B_FALSE);
 908         }
 909 
 910         /* If fname is "." -> INVALID_OBJECT_NAME */
 911         if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
 912                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 913                     ERRDOS, ERROR_PATH_NOT_FOUND);
 914                 return (B_FALSE);
 915         }
 916 
 917         return (B_TRUE);
 918 }
 919 
 920 /*
 921  * smb_validate_dirname
 922  *
 923  * smb_pathname_validate() should have already been performed on pn.
 924  *
 925  * Very basic directory name validation:  checks for colons in a path.
 926  * Need to skip the drive prefix since it contains a colon.
 927  *
 928  * Returns: B_TRUE if the name is valid,
 929  *          otherwise returns B_FALSE and sets error status in sr.
 930  */
 931 boolean_t
 932 smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
 933 {
 
 967         if (pn->pn_fname &&
 968             strlen(pn->pn_fname) == 5 &&
 969             smb_isdigit(pn->pn_fname[3]) &&
 970             pn->pn_fname[4] == ':') {
 971                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 972                     ERRDOS, ERROR_INVALID_NAME);
 973                 return (B_FALSE);
 974         }
 975 
 976         if (pn->pn_sname)
 977                 return (smb_validate_stream_name(sr, pn));
 978 
 979         return (B_TRUE);
 980 }
 981 
 982 /*
 983  * smb_stream_parse_name
 984  *
 985  * smb_stream_parse_name should only be called for a path that
 986  * contains a valid named stream.  Path validation should have
 987  * been performed before this function is called.
 988  *
 989  * Find the last component of path and split it into filename
 990  * and stream name.
 991  *
 992  * On return the named stream type will be present.  The stream
 993  * type defaults to ":$DATA", if it has not been defined
 994  * For exmaple, 'stream' contains :<sname>:$DATA
 995  */
 996 void
 997 smb_stream_parse_name(char *path, char *filename, char *stream)
 998 {
 999         char *fname, *sname, *stype;
1000 
1001         ASSERT(path);
1002         ASSERT(filename);
1003         ASSERT(stream);
1004 
1005         fname = strrchr(path, '\\');
1006         fname = (fname == NULL) ? path : fname + 1;
1007         (void) strlcpy(filename, fname, MAXNAMELEN);
1008 
1009         sname = strchr(filename, ':');
1010         (void) strlcpy(stream, sname, MAXNAMELEN);
1011         *sname = '\0';
1012 
1013         stype = strchr(stream + 1, ':');
1014         if (stype == NULL)
1015                 (void) strlcat(stream, ":$DATA", MAXNAMELEN);
1016         else
1017                 (void) smb_strupr(stype);
1018 }
1019 
1020 /*
1021  * smb_is_stream_name
1022  *
1023  * Determines if 'path' specifies a named stream.
1024  *
1025  * path is a NULL terminated string which could be a stream path.
1026  * [pathname/]fname[:stream_name[:stream_type]]
1027  *
1028  * - If there is no colon in the path or it's the last char
1029  *   then it's not a stream name
1030  *
1031  * - '::' is a non-stream and is commonly used by Windows to designate
1032  *   the unamed stream in the form "::$DATA"
1033  */
1034 boolean_t
1035 smb_is_stream_name(char *path)
1036 {
1037         char *colonp;
1038 
1039         if (path == NULL)
1040                 return (B_FALSE);
1041 
1042         colonp = strchr(path, ':');
1043         if ((colonp == NULL) || (*(colonp+1) == '\0'))
1044                 return (B_FALSE);
1045 
1046         if (strstr(path, "::"))
1047                 return (B_FALSE);
1048 
1049         return (B_TRUE);
1050 }
1051 
1052 /*
1053  * smb_validate_stream_name
1054  *
1055  * B_FALSE will be returned, and the error status ser in the sr, if:
1056  * - the path is not a stream name
1057  * - a path is specified but the fname is ommitted.
1058  * - the stream_type is specified but not valid.
1059  *
1060  * Note: the stream type is case-insensitive.
1061  */
1062 boolean_t
1063 smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
1064 {
1065         static char *strmtype[] = {
1066                 "$DATA",
1067                 "$INDEX_ALLOCATION"
1068         };
1069         int i;
1070 
1071         ASSERT(pn);
1072         ASSERT(pn->pn_sname);
1073 
1074         if ((!(pn->pn_sname)) ||
1075             ((pn->pn_pname) && !(pn->pn_fname))) {
1076                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1077                     ERRDOS, ERROR_INVALID_NAME);
1078                 return (B_FALSE);
1079         }
1080 
1081 
1082         if (pn->pn_stype != NULL) {
1083                 for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
1084                         if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
1085                                 return (B_TRUE);
 
 | 
 
 
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
  24  */
  25 
  26 #include <smbsrv/smb_kproto.h>
  27 #include <smbsrv/smb_fsops.h>
  28 #include <sys/pathname.h>
  29 #include <sys/sdt.h>
  30 
  31 static char *smb_pathname_catia_v5tov4(smb_request_t *, char *, char *, int);
  32 static char *smb_pathname_catia_v4tov5(smb_request_t *, char *, char *, int);
  33 static int smb_pathname_lookup(pathname_t *, pathname_t *, int,
  34     vnode_t **, vnode_t *, vnode_t *, smb_attr_t *attr, cred_t *);
  35 static char *smb_pathname_strdup(smb_request_t *, const char *);
  36 static char *smb_pathname_strcat(smb_request_t *, char *, const char *);
  37 static void smb_pathname_preprocess(smb_request_t *, smb_pathname_t *);
  38 static void smb_pathname_preprocess_quota(smb_request_t *, smb_pathname_t *);
  39 static int smb_pathname_dfs_preprocess(smb_request_t *, char *, size_t);
  40 static void smb_pathname_preprocess_adminshare(smb_request_t *,
  41     smb_pathname_t *);
  42 
  43 
 
 
 134  *      - "chroot" behavior of share root (handled by lookuppnvp)
 135  *
 136  * In addition, it needs to replace backslashes with forward slashes.  It also
 137  * ensures that link processing is done correctly, and that directory
 138  * information requested by the caller is correctly returned (i.e. for paths
 139  * with a link in the last component, the directory information of the
 140  * link and not the target needs to be returned).
 141  */
 142 
 143 int
 144 smb_pathname_reduce(
 145     smb_request_t       *sr,
 146     cred_t              *cred,
 147     const char          *path,
 148     smb_node_t          *share_root_node,
 149     smb_node_t          *cur_node,
 150     smb_node_t          **dir_node,
 151     char                *last_component)
 152 {
 153         smb_node_t      *root_node;
 154         pathname_t      ppn, mnt_pn;
 155         char            *usepath;
 156         int             lookup_flags = FOLLOW;
 157         int             trailing_slash = 0;
 158         int             err = 0;
 159         int             len;
 160         smb_node_t      *vss_node;
 161         smb_node_t      *local_cur_node;
 162         smb_node_t      *local_root_node;
 163         boolean_t       chk_vss;
 164         char            *gmttoken;
 165 
 166         ASSERT(dir_node);
 167         ASSERT(last_component);
 168 
 169         *dir_node = NULL;
 170         *last_component = '\0';
 171         vss_node = NULL;
 172         gmttoken = NULL;
 173         chk_vss = B_FALSE;
 174 
 175         if (sr && sr->tid_tree) {
 176                 if (STYPE_ISIPC(sr->tid_tree->t_res_type))
 177                         return (EACCES);
 178         }
 179 
 180         if (SMB_TREE_IS_CASEINSENSITIVE(sr))
 181                 lookup_flags |= FIGNORECASE;
 182 
 183         if (path == NULL)
 184                 return (EINVAL);
 185 
 186         if (*path == '\0')
 187                 return (ENOENT);
 188 
 189         usepath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
 190 
 191         len = strlcpy(usepath, path, SMB_MAXPATHLEN);
 192         if (len >= SMB_MAXPATHLEN) {
 193                 kmem_free(usepath, SMB_MAXPATHLEN);
 
 209 
 210         if (SMB_TREE_IS_DFSROOT(sr)) {
 211                 int is_dfs;
 212                 if (sr->session->dialect >= SMB_VERS_2_BASE)
 213                         is_dfs = sr->smb2_hdr_flags &
 214                             SMB2_FLAGS_DFS_OPERATIONS;
 215                 else
 216                         is_dfs = sr->smb_flg2 & SMB_FLAGS2_DFS;
 217                 if (is_dfs != 0) {
 218                         err = smb_pathname_dfs_preprocess(sr, usepath,
 219                             SMB_MAXPATHLEN);
 220                         if (err != 0) {
 221                                 kmem_free(usepath, SMB_MAXPATHLEN);
 222                                 return (err);
 223                         }
 224                         len = strlen(usepath);
 225                 }
 226         }
 227 
 228         if (sr != NULL) {
 229                 if (sr->session->dialect >= SMB_VERS_2_BASE) {
 230                         chk_vss = sr->arg.open.create_timewarp;
 231                 } else {
 232                         chk_vss = (sr->smb_flg2 &
 233                             SMB_FLAGS2_REPARSE_PATH) != 0;
 234 
 235                         if (chk_vss) {
 236                                 gmttoken = kmem_alloc(SMB_VSS_GMT_SIZE,
 237                                     KM_SLEEP);
 238                                 err = smb_vss_extract_gmttoken(usepath,
 239                                     gmttoken);
 240                                 if (err != 0) {
 241                                         kmem_free(usepath, SMB_MAXPATHLEN);
 242                                         kmem_free(gmttoken, SMB_VSS_GMT_SIZE);
 243                                         return (err);
 244                                 }
 245                                 len = strlen(usepath);
 246                         }
 247                 }
 248                 if (chk_vss)
 249                         (void) pn_alloc(&mnt_pn);
 250         }
 251 
 252         if (usepath[len - 1] == '/')
 253                 trailing_slash = 1;
 254 
 255         (void) strcanon(usepath, "/");
 256 
 257         (void) pn_alloc_sz(&ppn, SMB_MAXPATHLEN);
 258 
 259         if ((err = pn_set(&ppn, usepath)) != 0) {
 260                 (void) pn_free(&ppn);
 261                 kmem_free(usepath, SMB_MAXPATHLEN);
 262                 if (chk_vss)
 263                         (void) pn_free(&mnt_pn);
 264                 if (gmttoken != NULL)
 265                         kmem_free(gmttoken, SMB_VSS_GMT_SIZE);
 266                 return (err);
 267         }
 268 
 269         /*
 270          * If a path does not have a trailing slash, strip off the
 271          * last component.  (We only need to return an smb_node for
 272          * the second to last component; a name is returned for the
 273          * last component.)
 274          *
 275          * For VSS requests, the last component might be a filesystem of its
 276          * own, and we need to discover that before exiting this function,
 277          * so allow the lookup to happen on the last component.
 278          * We'll correct this later when we convert to the snapshot.
 279          */
 280 
 281         if (!chk_vss) {
 282                 if (trailing_slash) {
 283                         (void) strlcpy(last_component, ".", MAXNAMELEN);
 284                 } else {
 285                         (void) pn_setlast(&ppn);
 286                         (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
 287                         ppn.pn_path[0] = '\0';
 288                 }
 289         }
 290 
 291         if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
 292                 smb_node_ref(local_cur_node);
 293                 *dir_node = local_cur_node;
 294         } else {
 295                 err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
 296                     local_root_node, local_cur_node, NULL, dir_node, cred,
 297                     chk_vss ? &mnt_pn : NULL);
 298         }
 299 
 300         (void) pn_free(&ppn);
 301         kmem_free(usepath, SMB_MAXPATHLEN);
 302 
 303         /*
 304          * We need to try and convert to snapshots, even on error.
 305          * This is to handle the following cases:
 306          * - We're on the lowest level filesystem, but a directory got renamed
 307          *   on the live version. We'll get ENOENT, but can still find it in
 308          *   the snapshot.
 309          * - The last component was actually a file. We need to leave the last
 310          *   component in in case it is, itself, a mountpoint, but that means
 311          *   we might get ENOTDIR if it's not actually a directory.
 312          *
 313          * Note that if you change the share-relative name of a mountpoint,
 314          * you won't be able to access previous versions of files under it.
 315          */
 316         if (chk_vss && *dir_node != NULL) {
 317                 if ((err = smb_vss_lookup_nodes(sr, *dir_node, &vss_node,
 318                     gmttoken)) == 0) {
 319                         char *p = mnt_pn.pn_path;
 320                         size_t pathleft;
 321 
 322                         smb_node_release(*dir_node);
 323                         *dir_node = NULL;
 324                         pathleft = pn_pathleft(&mnt_pn);
 325 
 326                         if (pathleft == 0 || trailing_slash) {
 327                                 (void) strlcpy(last_component, ".", MAXNAMELEN);
 328                         } else {
 329                                 (void) pn_setlast(&mnt_pn);
 330                                 (void) strlcpy(last_component, mnt_pn.pn_path,
 331                                     MAXNAMELEN);
 332                                 mnt_pn.pn_path[0] = '\0';
 333                                 pathleft -= strlen(last_component);
 334                         }
 335 
 336                         if (pathleft != 0) {
 337                                 err = smb_pathname(sr, p, lookup_flags,
 338                                     vss_node, vss_node, NULL, dir_node, cred,
 339                                     NULL);
 340                         } else {
 341                                 *dir_node = vss_node;
 342                                 vss_node = NULL;
 343                         }
 344                 }
 345         }
 346 
 347         if (chk_vss)
 348                 (void) pn_free(&mnt_pn);
 349         if (gmttoken != NULL)
 350                 kmem_free(gmttoken, SMB_VSS_GMT_SIZE);
 351 
 352         /*
 353          * Prevent traversal to another file system if mount point
 354          * traversal is disabled.
 355          *
 356          * Note that we disregard whether the traversal of the path went
 357          * outside of the file system and then came back (say via a link).
 358          * This means that only symlinks that are expressed relatively to
 359          * the share root work.
 360          *
 361          * share_root_node is NULL when mapping a share, so we disregard
 362          * that case.
 363          */
 364 
 365         if ((err == 0) && share_root_node) {
 366                 if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp) {
 367                         err = EACCES;
 368                         if ((sr) && (sr)->tid_tree &&
 369                             smb_tree_has_feature((sr)->tid_tree,
 370                             SMB_TREE_TRAVERSE_MOUNTS))
 371                                 err = 0;
 372                 }
 373         }
 374 
 375         if (err) {
 376                 if (*dir_node) {
 377                         (void) smb_node_release(*dir_node);
 378                         *dir_node = NULL;
 379                 }
 380                 *last_component = 0;
 381         }
 382 
 383         if (vss_node != NULL)
 384                 (void) smb_node_release(vss_node);
 385         return (err);
 386 }
 387 
 388 /*
 389  * smb_pathname()
 390  * wrapper to lookuppnvp().  Handles name unmangling.
 391  *
 392  * *dir_node is the true directory of the target *node.
 393  *
 394  * If any component but the last in the path is not found, ENOTDIR instead of
 395  * ENOENT will be returned.
 396  *
 397  * Path components are processed one at a time so that smb_nodes can be
 398  * created for each component.  This allows the n_dnode field in the
 399  * smb_node to be properly populated.
 400  *
 401  * Because of the above, links are also processed in this routine
 402  * (i.e., we do not pass the FOLLOW flag to lookuppnvp()).  This
 403  * will allow smb_nodes to be created for each component of a link.
 404  *
 405  * Mangle checking is per component. If a name is mangled, when the
 406  * unmangled name is passed to smb_pathname_lookup() do not pass
 407  * FIGNORECASE, since the unmangled name is the real on-disk name.
 408  * Otherwise pass FIGNORECASE if it's set in flags. This will cause the
 409  * file system to return "first match" in the event of a case collision.
 410  *
 411  * If CATIA character translation is enabled it is applied to each
 412  * component before passing the component to smb_pathname_lookup().
 413  * After smb_pathname_lookup() the reverse translation is applied.
 414  */
 415 
 416 int
 417 smb_pathname(smb_request_t *sr, char *path, int flags,
 418     smb_node_t *root_node, smb_node_t *cur_node, smb_node_t **dir_node,
 419     smb_node_t **ret_node, cred_t *cred, pathname_t *mnt_pn)
 420 {
 421         char            *component, *real_name, *namep;
 422         pathname_t      pn, rpn, upn, link_pn;
 423         smb_node_t      *dnode, *fnode, *mnt_node;
 424         smb_attr_t      attr;
 425         vnode_t         *rootvp, *vp;
 426         size_t          pathleft;
 427         int             err = 0;
 428         int             nlink = 0;
 429         int             local_flags;
 430         uint32_t        abe_flag = 0;
 431         char            namebuf[MAXNAMELEN];
 432         vnode_t *fsrootvp = NULL;
 433 
 434         if (path == NULL)
 435                 return (EINVAL);
 436 
 437         ASSERT(root_node);
 438         ASSERT(cur_node);
 439         ASSERT(ret_node);
 440 
 441         *ret_node = NULL;
 442 
 443         if (dir_node)
 444                 *dir_node = NULL;
 445 
 446         (void) pn_alloc_sz(&upn, SMB_MAXPATHLEN);
 447 
 448         if ((err = pn_set(&upn, path)) != 0) {
 449                 (void) pn_free(&upn);
 450                 return (err);
 451         }
 452 
 453         if (mnt_pn != NULL && (err = pn_set(mnt_pn, path) != 0)) {
 454                 (void) pn_free(&upn);
 455                 return (err);
 456         }
 457 
 458         if (SMB_TREE_SUPPORTS_ABE(sr))
 459                 abe_flag = SMB_ABE;
 460 
 461         (void) pn_alloc(&pn);
 462         (void) pn_alloc(&rpn);
 463 
 464         component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 465         real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 466 
 467         if (mnt_pn != NULL) {
 468                 mnt_node = cur_node;
 469                 smb_node_ref(cur_node);
 470         } else
 471                 mnt_node = NULL;
 472         fnode = NULL;
 473         dnode = cur_node;
 474         smb_node_ref(dnode);
 475         rootvp = root_node->vp;
 476 
 477         while ((pathleft = pn_pathleft(&upn)) != 0) {
 478                 if (fnode) {
 479                         smb_node_release(dnode);
 480                         dnode = fnode;
 481                         fnode = NULL;
 482                 }
 483 
 484                 if ((err = pn_getcomponent(&upn, component)) != 0)
 485                         break;
 486 
 487                 if ((namep = smb_pathname_catia_v5tov4(sr, component,
 488                     namebuf, sizeof (namebuf))) == NULL) {
 489                         err = EILSEQ;
 490                         break;
 491                 }
 492 
 493                 if ((err = pn_set(&pn, namep)) != 0)
 494                         break;
 495 
 496                 /* We want the DOS attributes. */
 497                 bzero(&attr, sizeof (attr));
 498                 attr.sa_mask = SMB_AT_DOSATTR;
 499 
 500                 local_flags = flags & FIGNORECASE;
 501                 err = smb_pathname_lookup(&pn, &rpn, local_flags,
 502                     &vp, rootvp, dnode->vp, &attr, cred);
 503 
 504                 if (err) {
 505                         if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) ||
 506                             !smb_maybe_mangled(component))
 507                                 break;
 508 
 509                         if ((err = smb_unmangle(dnode, component,
 510                             real_name, MAXNAMELEN, abe_flag)) != 0)
 511                                 break;
 512 
 513                         if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
 514                             namebuf, sizeof (namebuf))) == NULL) {
 515                                 err = EILSEQ;
 516                                 break;
 517                         }
 518 
 519                         if ((err = pn_set(&pn, namep)) != 0)
 
 584                         }
 585 
 586                         namep = smb_pathname_catia_v4tov5(sr, namep,
 587                             namebuf, sizeof (namebuf));
 588 
 589                         fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
 590                             dnode, NULL);
 591                         VN_RELE(vp);
 592 
 593                         if (fnode == NULL) {
 594                                 err = ENOMEM;
 595                                 break;
 596                         }
 597                 }
 598 
 599                 while (upn.pn_path[0] == '/') {
 600                         upn.pn_path++;
 601                         upn.pn_pathlen--;
 602                 }
 603 
 604                 /*
 605                  * If the node we looked up is the root of a filesystem,
 606                  * snapshot the lookup so we can replay this after discovering
 607                  * the lowest mounted filesystem.
 608                  */
 609                 if (mnt_pn != NULL &&
 610                     (err = VFS_ROOT(fnode->vp->v_vfsp, &fsrootvp)) == 0) {
 611                         if (fsrootvp == fnode->vp) {
 612                                 mnt_pn->pn_pathlen = pn_pathleft(&upn);
 613                                 mnt_pn->pn_path = mnt_pn->pn_buf +
 614                                     ((ptrdiff_t)upn.pn_path -
 615                                     (ptrdiff_t)upn.pn_buf);
 616 
 617                                 smb_node_ref(fnode);
 618                                 if (mnt_node != NULL)
 619                                         smb_node_release(mnt_node);
 620                                 mnt_node = fnode;
 621 
 622                         }
 623                         VN_RELE(fsrootvp);
 624                 }
 625         }
 626 
 627         if ((pathleft) && (err == ENOENT))
 628                 err = ENOTDIR;
 629 
 630         if (mnt_node == NULL)
 631                 mnt_pn = NULL;
 632 
 633         /*
 634          * We always want to return a node when we're doing VSS
 635          * (mnt_pn != NULL)
 636          */
 637         if (mnt_pn == NULL && err != 0) {
 638                 if (fnode)
 639                         smb_node_release(fnode);
 640                 if (dnode)
 641                         smb_node_release(dnode);
 642         } else {
 643                 if (mnt_pn != NULL) {
 644                         *ret_node = mnt_node;
 645                         if (fnode != NULL)
 646                                 smb_node_release(fnode);
 647                 } else {
 648                         *ret_node = fnode;
 649                 }
 650 
 651                 if (dir_node)
 652                         *dir_node = dnode;
 653                 else
 654                         smb_node_release(dnode);
 655         }
 656 
 657         kmem_free(component, MAXNAMELEN);
 658         kmem_free(real_name, MAXNAMELEN);
 659         (void) pn_free(&pn);
 660         (void) pn_free(&rpn);
 661         (void) pn_free(&upn);
 662 
 663         return (err);
 664 }
 665 
 666 /*
 667  * Holds on dvp and rootvp (if not rootdir) are required by lookuppnvp()
 668  * and will be released within lookuppnvp().
 669  */
 
 998 {
 999         char *path = pn->pn_path;
1000 
1001         /* ignore any initial "\\" */
1002         path += strspn(path, "\\");
1003 
1004         /* If first component of path is ".." -> PATH_SYNTAX_BAD */
1005         if ((strcmp(path, "..") == 0) || (strncmp(path, "..\\", 3) == 0)) {
1006                 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
1007                     ERRDOS, ERROR_BAD_PATHNAME);
1008                 return (B_FALSE);
1009         }
1010 
1011         /* If there are wildcards in pn->pn_pname -> OBJECT_NAME_INVALID */
1012         if (pn->pn_pname && smb_contains_wildcards(pn->pn_pname)) {
1013                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1014                     ERRDOS, ERROR_INVALID_NAME);
1015                 return (B_FALSE);
1016         }
1017 
1018         /* If fname is "." -> OBJECT_NAME_INVALID */
1019         if (pn->pn_fname && (strcmp(pn->pn_fname, ".") == 0)) {
1020                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1021                     ERRDOS, ERROR_INVALID_NAME);
1022                 return (B_FALSE);
1023         }
1024 
1025         return (B_TRUE);
1026 }
1027 
1028 /*
1029  * smb_validate_dirname
1030  *
1031  * smb_pathname_validate() should have already been performed on pn.
1032  *
1033  * Very basic directory name validation:  checks for colons in a path.
1034  * Need to skip the drive prefix since it contains a colon.
1035  *
1036  * Returns: B_TRUE if the name is valid,
1037  *          otherwise returns B_FALSE and sets error status in sr.
1038  */
1039 boolean_t
1040 smb_validate_dirname(smb_request_t *sr, smb_pathname_t *pn)
1041 {
 
1075         if (pn->pn_fname &&
1076             strlen(pn->pn_fname) == 5 &&
1077             smb_isdigit(pn->pn_fname[3]) &&
1078             pn->pn_fname[4] == ':') {
1079                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1080                     ERRDOS, ERROR_INVALID_NAME);
1081                 return (B_FALSE);
1082         }
1083 
1084         if (pn->pn_sname)
1085                 return (smb_validate_stream_name(sr, pn));
1086 
1087         return (B_TRUE);
1088 }
1089 
1090 /*
1091  * smb_stream_parse_name
1092  *
1093  * smb_stream_parse_name should only be called for a path that
1094  * contains a valid named stream.  Path validation should have
1095  * been performed before this function is called, typically by
1096  * calling smb_is_stream_name() just before this.
1097  *
1098  * Find the last component of path and split it into filename
1099  * and stream name.
1100  *
1101  * On return the named stream type will be present.  The stream
1102  * type defaults to ":$DATA", if it has not been defined
1103  * For example, 'stream' contains :<sname>:$DATA
1104  *
1105  * Output args: filename, stream both MAXNAMELEN
1106  */
1107 void
1108 smb_stream_parse_name(char *path, char *filename, char *stream)
1109 {
1110         char *fname, *sname, *stype;
1111         size_t flen, slen;
1112 
1113         ASSERT(path);
1114         ASSERT(filename);
1115         ASSERT(stream);
1116 
1117         fname = strrchr(path, '\\');
1118         fname = (fname == NULL) ? path : fname + 1;
1119         sname = strchr(fname, ':');
1120         /* Caller makes sure there is a ':' in path. */
1121         VERIFY(sname != NULL);
1122         /* LINTED: possible ptrdiff_t overflow */
1123         flen = sname - fname;
1124         slen = strlen(sname);
1125 
1126         if (flen > (MAXNAMELEN-1))
1127                 flen = (MAXNAMELEN-1);
1128         (void) strncpy(filename, fname, flen);
1129         filename[flen] = '\0';
1130 
1131         if (slen > (MAXNAMELEN-1))
1132                 slen = (MAXNAMELEN-1);
1133         (void) strncpy(stream, sname, slen);
1134         stream[slen] = '\0';
1135 
1136         /* Add a "stream type" if there isn't one. */
1137         stype = strchr(stream + 1, ':');
1138         if (stype == NULL)
1139                 (void) strlcat(stream, ":$DATA", MAXNAMELEN);
1140         else
1141                 (void) smb_strupr(stype);
1142 }
1143 
1144 /*
1145  * smb_is_stream_name
1146  *
1147  * Determines if 'path' specifies a named stream.
1148  *
1149  * path is a NULL terminated string which could be a stream path.
1150  * [pathname/]fname[:stream_name[:stream_type]]
1151  *
1152  * - If there is no colon in the path or it's the last char
1153  *   then it's not a stream name
1154  *
1155  * - '::' is a non-stream and is commonly used by Windows to designate
1156  *   the unamed stream in the form "::$DATA"
1157  */
1158 boolean_t
1159 smb_is_stream_name(char *path)
1160 {
1161         char *colonp;
1162 
1163         if (path == NULL)
1164                 return (B_FALSE);
1165 
1166         colonp = strchr(path, ':');
1167         if ((colonp == NULL) || (*(colonp+1) == '\0'))
1168                 return (B_FALSE);
1169 
1170         if (strstr(path, "::"))
1171                 return (B_FALSE);
1172 
1173         return (B_TRUE);
1174 }
1175 
1176 /*
1177  * Is this stream node a "restricted" type?
1178  */
1179 boolean_t
1180 smb_strname_restricted(char *strname)
1181 {
1182         char *stype;
1183 
1184         stype = strrchr(strname, ':');
1185         if (stype == NULL)
1186                 return (B_FALSE);
1187 
1188         /*
1189          * Only ":$CA" is restricted (for now).
1190          */
1191         if (strcmp(stype, ":$CA") == 0)
1192                 return (B_TRUE);
1193 
1194         return (B_FALSE);
1195 }
1196 
1197 /*
1198  * smb_validate_stream_name
1199  *
1200  * B_FALSE will be returned, and the error status ser in the sr, if:
1201  * - the path is not a stream name
1202  * - a path is specified but the fname is ommitted.
1203  * - the stream_type is specified but not valid.
1204  *
1205  * Note: the stream type is case-insensitive.
1206  */
1207 boolean_t
1208 smb_validate_stream_name(smb_request_t *sr, smb_pathname_t *pn)
1209 {
1210         static char *strmtype[] = {
1211                 "$CA",
1212                 "$DATA",
1213                 "$INDEX_ALLOCATION"
1214         };
1215         int i;
1216 
1217         ASSERT(pn);
1218         ASSERT(pn->pn_sname);
1219 
1220         if ((!(pn->pn_sname)) ||
1221             ((pn->pn_pname) && !(pn->pn_fname))) {
1222                 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
1223                     ERRDOS, ERROR_INVALID_NAME);
1224                 return (B_FALSE);
1225         }
1226 
1227 
1228         if (pn->pn_stype != NULL) {
1229                 for (i = 0; i < sizeof (strmtype) / sizeof (strmtype[0]); ++i) {
1230                         if (strcasecmp(pn->pn_stype, strmtype[i]) == 0)
1231                                 return (B_TRUE);
 
 |