1 /* 2 * CDDL HEADER START 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 2013-2021 Tintri by DDN, Inc. All rights reserved. 24 * Copyright 2023 RackTop Systems, Inc. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/uio.h> 30 #include <sys/statvfs.h> 31 #include <sys/vnode.h> 32 #include <sys/thread.h> 33 #include <sys/pathname.h> 34 #include <sys/cred.h> 35 #include <sys/extdirent.h> 36 #include <sys/nbmlock.h> 37 #include <sys/share.h> 38 #include <sys/fcntl.h> 39 #include <sys/priv_const.h> 40 #include <sys/policy.h> 41 #include <nfs/lm.h> 42 43 #include <smbsrv/smb_kproto.h> 44 #include <smbsrv/string.h> 45 #include <smbsrv/smb_vops.h> 46 #include <smbsrv/smb_fsops.h> 47 48 /* 49 * CATIA support 50 * 51 * CATIA V4 is a UNIX product and uses characters in filenames that 52 * are considered invalid by Windows. CATIA V5 is available on both 53 * UNIX and Windows. Thus, as CATIA customers migrate from V4 to V5, 54 * some V4 files could become inaccessible to windows clients if the 55 * filename contains the characters that are considered illegal in 56 * Windows. In order to address this issue an optional character 57 * translation is applied to filenames at the smb_vop interface. 58 * 59 * Character Translation Table 60 * ---------------------------------- 61 * Unix-char (v4) | Windows-char (v5) 62 * ---------------------------------- 63 * * | 0x00a4 Currency Sign 64 * | | 0x00a6 Broken Bar 65 * " | 0x00a8 Diaeresis 66 * < | 0x00ab Left-Pointing Double Angle Quotation Mark 67 * > | 0x00bb Right-Pointing Double Angle Quotation Mark 68 * ? | 0x00bf Inverted Question mark 69 * : | 0x00f7 Division Sign 70 * / | 0x00f8 Latin Small Letter o with stroke 71 * \ | 0x00ff Latin Small Letter Y with Diaeresis 72 * 73 * 74 * Two lookup tables are used to perform the character translation: 75 * 76 * smb_catia_v5_lookup - provides the mapping between UNIX ASCII (v4) 77 * characters and equivalent or translated wide characters. 78 * It is indexed by the decimal value of the ASCII character (0-127). 79 * 80 * smb_catia_v4_lookup - provides the mapping between wide characters 81 * in the range from 0x00A4 to 0x00FF and their UNIX (v4) equivalent 82 * (in wide character format). It is indexed by the decimal value of 83 * the wide character (164-255) with an offset of -164. 84 * If this translation produces a filename containing a '/' create, mkdir 85 * or rename (to the '/' name) operations will not be permitted. It is 86 * not valid to create a filename with a '/' in it. However, if such a 87 * file already exists other operations (e.g, lookup, delete, rename) 88 * are permitted on it. 89 */ 90 91 /* number of characters mapped */ 92 #define SMB_CATIA_NUM_MAPS 9 93 94 /* Windows Characters used in special character mapping */ 95 #define SMB_CATIA_WIN_CURRENCY 0x00a4 96 #define SMB_CATIA_WIN_BROKEN_BAR 0x00a6 97 #define SMB_CATIA_WIN_DIAERESIS 0x00a8 98 #define SMB_CATIA_WIN_LEFT_ANGLE 0x00ab 99 #define SMB_CATIA_WIN_RIGHT_ANGLE 0x00bb 100 #define SMB_CATIA_WIN_INVERTED_QUESTION 0x00bf 101 #define SMB_CATIA_WIN_DIVISION 0x00f7 102 #define SMB_CATIA_WIN_LATIN_O 0x00f8 103 #define SMB_CATIA_WIN_LATIN_Y 0x00ff 104 105 #define SMB_CATIA_V4_LOOKUP_LOW SMB_CATIA_WIN_CURRENCY 106 #define SMB_CATIA_V4_LOOKUP_UPPER SMB_CATIA_WIN_LATIN_Y 107 #define SMB_CATIA_V4_LOOKUP_MAX \ 108 (SMB_CATIA_V4_LOOKUP_UPPER - SMB_CATIA_V4_LOOKUP_LOW + 1) 109 #define SMB_CATIA_V5_LOOKUP_MAX 0x0080 110 111 typedef struct smb_catia_map 112 { 113 unsigned char unixchar; /* v4 */ 114 smb_wchar_t winchar; /* v5 */ 115 } smb_catia_map_t; 116 117 smb_catia_map_t const catia_maps[SMB_CATIA_NUM_MAPS] = 118 { 119 {'"', SMB_CATIA_WIN_DIAERESIS}, 120 {'*', SMB_CATIA_WIN_CURRENCY}, 121 {':', SMB_CATIA_WIN_DIVISION}, 122 {'<', SMB_CATIA_WIN_LEFT_ANGLE}, 123 {'>', SMB_CATIA_WIN_RIGHT_ANGLE}, 124 {'?', SMB_CATIA_WIN_INVERTED_QUESTION}, 125 {'\\', SMB_CATIA_WIN_LATIN_Y}, 126 {'/', SMB_CATIA_WIN_LATIN_O}, 127 {'|', SMB_CATIA_WIN_BROKEN_BAR} 128 }; 129 130 static smb_wchar_t smb_catia_v5_lookup[SMB_CATIA_V5_LOOKUP_MAX]; 131 static smb_wchar_t smb_catia_v4_lookup[SMB_CATIA_V4_LOOKUP_MAX]; 132 133 static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); 134 static void smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 135 static void smb_sa_to_va_mask_get(uint_t sa_mask, uint_t *va_maskp); 136 static callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); 137 static void smb_vop_catia_init(); 138 139 extern sysid_t lm_alloc_sysidt(); 140 141 #define SMB_AT_MAX 16 142 static const uint_t smb_attrmap[SMB_AT_MAX] = { 143 0, 144 AT_TYPE, 145 AT_MODE, 146 AT_UID, 147 AT_GID, 148 AT_FSID, 149 AT_NODEID, 150 AT_NLINK, 151 AT_SIZE, 152 AT_ATIME, 153 AT_MTIME, 154 AT_CTIME, 155 AT_RDEV, 156 AT_BLKSIZE, 157 AT_NBLOCKS, 158 AT_SEQ 159 }; 160 161 static boolean_t smb_vop_initialized = B_FALSE; 162 caller_context_t smb_ct; 163 164 /* 165 * smb_vop_init 166 * 167 * This function is not multi-thread safe. The caller must make sure only one 168 * thread makes the call. 169 */ 170 int 171 smb_vop_init(void) 172 { 173 if (smb_vop_initialized) 174 return (0); 175 /* 176 * The caller_context will be used primarily for range locking. 177 * Since the CIFS server is mapping its locks to POSIX locks, 178 * only one pid is used for operations originating from the 179 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 180 * 181 * XXX: Should smb_ct be per-zone? 182 */ 183 smb_ct.cc_sysid = lm_alloc_sysidt(); 184 if (smb_ct.cc_sysid == LM_NOSYSID) 185 return (ENOMEM); 186 187 smb_ct.cc_caller_id = fs_new_caller_id(); 188 smb_ct.cc_pid = IGN_PID; 189 smb_ct.cc_flags = 0; 190 smb_vop_catia_init(); 191 192 smb_vop_initialized = B_TRUE; 193 return (0); 194 } 195 196 /* 197 * smb_vop_fini 198 * 199 * This function is not multi-thread safe. The caller must make sure only one 200 * thread makes the call. 201 */ 202 void 203 smb_vop_fini(void) 204 { 205 if (!smb_vop_initialized) 206 return; 207 208 lm_free_sysidt(smb_ct.cc_sysid); 209 smb_ct.cc_pid = IGN_PID; 210 smb_ct.cc_sysid = LM_NOSYSID; 211 smb_vop_initialized = B_FALSE; 212 } 213 214 /* 215 * The smb_ct will be used primarily for range locking. 216 * Since the CIFS server is mapping its locks to POSIX locks, 217 * only one pid is used for operations originating from the 218 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 219 */ 220 int 221 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred) 222 { 223 return (VOP_OPEN(vpp, mode, cred, &smb_ct)); 224 } 225 226 void 227 smb_vop_close(vnode_t *vp, int mode, cred_t *cred) 228 { 229 (void) VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct); 230 } 231 232 int 233 smb_vop_other_opens(vnode_t *vp, int mode) 234 { 235 return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || 236 (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || 237 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) || 238 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) || 239 vn_is_mapped(vp, V_RDORWR)); 240 } 241 242 /* 243 * The smb_vop_* functions have minimal knowledge of CIFS semantics and 244 * serve as an interface to the VFS layer. 245 * 246 * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 247 * (Higher-level CIFS service code should never skip the smb_fsop_* layer 248 * to call smb_vop_* layer functions directly.) 249 */ 250 251 /* 252 * XXX - Extended attributes support in the file system assumed. 253 * This is needed for full NT Streams functionality. 254 */ 255 256 int 257 smb_vop_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr) 258 { 259 int error; 260 261 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 262 error = VOP_READ(vp, uiop, ioflag, cr, &smb_ct); 263 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 264 return (error); 265 } 266 267 int 268 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount, 269 cred_t *cr) 270 { 271 int error; 272 273 *lcount = uiop->uio_resid; 274 275 uiop->uio_llimit = MAXOFFSET_T; 276 277 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 278 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 279 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 280 281 *lcount -= uiop->uio_resid; 282 283 return (error); 284 } 285 286 int 287 smb_vop_ioctl(vnode_t *vp, int cmd, void *arg, cred_t *cr) 288 { 289 int error, rval = 0; 290 uint_t flags = 0; 291 292 #ifdef FKIOCTL 293 flags |= FKIOCTL; 294 #endif 295 error = VOP_IOCTL(vp, cmd, (intptr_t)arg, (int)flags, cr, 296 &rval, &smb_ct); 297 if (error != 0) 298 rval = error; 299 300 return (rval); 301 } 302 303 /* 304 * Support for zero-copy read/write 305 * Request buffers and return them. 306 */ 307 int 308 smb_vop_reqzcbuf(vnode_t *vp, int ioflag, xuio_t *xuio, cred_t *cr) 309 { 310 int error; 311 312 error = VOP_REQZCBUF(vp, ioflag, xuio, cr, &smb_ct); 313 return (error); 314 } 315 316 int 317 smb_vop_retzcbuf(vnode_t *vp, xuio_t *xuio, cred_t *cr) 318 { 319 int error; 320 321 error = VOP_RETZCBUF(vp, xuio, cr, &smb_ct); 322 return (error); 323 } 324 325 #ifdef _KERNEL 326 /* 327 * Determine whether this user's privileges can satisfy an ACL check. 328 * Caller determines which privileges are needed. 329 * srv_only determines whether all zone privileges are needed 330 * (e.g. kcred/zone_kcred()). 331 * 332 * ZFS first checks the ACL to determine which permissions are granted. 333 * It then uses privileges to satisfy any remaining permissions. 334 * The ACL check can be surprisingly expensive (for example, it may require 335 * going over the network if an FUID needs to be mapped to a posix ID). 336 * The SMB server inverts this order for two special cases: 337 * - When checking whether the SMB user has permission to traverse through a 338 * directory during lookup; 339 * - When checking whether the server (kcred or zone_kcred) has permission to 340 * read attributes for internal purposes. 341 * These checks happen frequently, in hot code, and nearly always succeed via 342 * the privileges granted to these users. In these cases, we first check for the 343 * specific privilege that would satisfy the required access, then skip the 344 * access check when the caller has that privilege. 345 * See zfs_zaccess() and its calls to secpolicy_vnode_access2() for how 346 * v4 accesses are mapped onto privileges. 347 */ 348 boolean_t 349 smb_vop_priv_check(cred_t *cr, int priv, boolean_t srv_only, vnode_t *vp) 350 { 351 return (PRIV_POLICY_ONLY(cr, priv, srv_only) && 352 vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS)); 353 } 354 #endif 355 356 /* 357 * smb_vop_getattr() 358 * 359 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 360 * service (instead of calling VOP_GETATTR directly) to retrieve attributes 361 * due to special processing needed for streams files. 362 * 363 * All attributes are retrieved. 364 * 365 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 366 * the corresponding unnamed stream). 367 * A named stream's attributes (as far as CIFS is concerned) are those of the 368 * unnamed stream (minus the size attribute, and the type), plus the size of 369 * the named stream, and a type value of VREG. 370 * Although the file system may store other attributes with the named stream, 371 * these should not be used by CIFS for any purpose. 372 * 373 * File systems without VFSFT_XVATTR do not support DOS attributes or create 374 * time (crtime). In this case the mtime is used as the crtime. 375 * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr 376 * is 0 and the mtime is used as the crtime. 377 */ 378 int 379 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 380 int flags, cred_t *cr) 381 { 382 int error; 383 vnode_t *use_vp; 384 xvattr_t tmp_xvattr; 385 xoptattr_t *xoap = NULL; 386 387 if (unnamed_vp) 388 use_vp = unnamed_vp; 389 else 390 use_vp = vp; 391 392 #ifdef _KERNEL 393 /* Avoid potentially expensive access checks for non-client queries. */ 394 if (smb_vop_priv_check(cr, PRIV_FILE_DAC_READ, B_TRUE, use_vp)) 395 flags |= ATTR_NOACLCHECK; 396 #endif 397 398 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 399 xva_init(&tmp_xvattr); 400 xoap = xva_getxoptattr(&tmp_xvattr); 401 ASSERT(xoap); 402 403 smb_sa_to_va_mask_get(ret_attr->sa_mask, 404 &tmp_xvattr.xva_vattr.va_mask); 405 406 XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 407 XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 408 XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 409 XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 410 XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 411 XVA_SET_REQ(&tmp_xvattr, XAT_REPARSE); 412 XVA_SET_REQ(&tmp_xvattr, XAT_OFFLINE); 413 XVA_SET_REQ(&tmp_xvattr, XAT_SPARSE); 414 415 error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags, 416 cr, &smb_ct); 417 if (error != 0) 418 return (error); 419 420 ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 421 ret_attr->sa_dosattr = 0; 422 423 if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) { 424 xoap = xva_getxoptattr(&tmp_xvattr); 425 ASSERT(xoap); 426 427 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) && 428 (xoap->xoa_readonly)) { 429 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 430 } 431 432 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) && 433 (xoap->xoa_hidden)) { 434 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 435 } 436 437 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) && 438 (xoap->xoa_system)) { 439 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 440 } 441 442 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) && 443 (xoap->xoa_archive)) { 444 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 445 } 446 447 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_REPARSE)) && 448 (xoap->xoa_reparse)) { 449 ret_attr->sa_dosattr |= 450 FILE_ATTRIBUTE_REPARSE_POINT; 451 } 452 453 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_OFFLINE)) && 454 (xoap->xoa_offline)) { 455 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_OFFLINE; 456 } 457 458 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SPARSE)) && 459 (xoap->xoa_sparse)) { 460 ret_attr->sa_dosattr |= 461 FILE_ATTRIBUTE_SPARSE_FILE; 462 } 463 464 ret_attr->sa_crtime = xoap->xoa_createtime; 465 } else { 466 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; 467 } 468 } else { 469 /* 470 * Support for file systems without VFSFT_XVATTR 471 */ 472 smb_sa_to_va_mask_get(ret_attr->sa_mask, 473 &ret_attr->sa_vattr.va_mask); 474 475 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, 476 flags, cr, &smb_ct); 477 if (error != 0) 478 return (error); 479 480 ret_attr->sa_dosattr = 0; 481 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; 482 } 483 484 if (unnamed_vp) { 485 /* 486 * vp is a named stream under "unnamed_vp" 487 * Need to get the size from vp (not use_vp) 488 */ 489 smb_attr_t tmp_attr; 490 ret_attr->sa_vattr.va_type = VREG; 491 492 if (ret_attr->sa_mask & 493 (SMB_AT_SIZE | SMB_AT_NBLOCKS | SMB_AT_ALLOCSZ)) { 494 tmp_attr.sa_vattr.va_mask = AT_SIZE | AT_NBLOCKS; 495 496 /* 497 * Keep ATTR_NOACLCHECK from use_vp; if it's good for 498 * the file, it's good for the xattr. 499 */ 500 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, 501 flags, cr, &smb_ct); 502 if (error != 0) 503 return (error); 504 505 ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 506 ret_attr->sa_vattr.va_nblocks = 507 tmp_attr.sa_vattr.va_nblocks; 508 } 509 } 510 511 /* 512 * Override a few things so they're as SMB expects. 513 * SMB allocsz is always zero for directories. 514 * For plain files, allocsz is the larger of: 515 * size, allocsize (See smb_node_getattr) 516 */ 517 if (ret_attr->sa_vattr.va_type == VDIR) { 518 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 519 /* SMB expectes directories to have... */ 520 ret_attr->sa_vattr.va_nlink = 1; 521 ret_attr->sa_vattr.va_size = 0; 522 ret_attr->sa_allocsz = 0; 523 } else { 524 if (ret_attr->sa_dosattr == 0) 525 ret_attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL; 526 if ((ret_attr->sa_mask & SMB_AT_ALLOCSZ) != 0) { 527 /* 528 * ZFS includes meta-data in va_nblocks. 529 * Special case zero to keep tests happy. 530 */ 531 if (ret_attr->sa_vattr.va_size == 0 && 532 ret_attr->sa_vattr.va_nblocks == 1) 533 ret_attr->sa_allocsz = 0; 534 else 535 ret_attr->sa_allocsz = 536 ret_attr->sa_vattr.va_nblocks * DEV_BSIZE; 537 if (ret_attr->sa_allocsz < ret_attr->sa_vattr.va_size) { 538 ret_attr->sa_allocsz = P2ROUNDUP( 539 ret_attr->sa_vattr.va_size, DEV_BSIZE); 540 } 541 } 542 } 543 544 return (error); 545 } 546 547 /* 548 * smb_vop_setattr() 549 * 550 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 551 * VOP_SETATTR() when calling from the CIFS service, due to special processing 552 * for streams files. 553 * 554 * Streams have a size but otherwise do not have separate attributes from 555 * the (unnamed stream) file, i.e., the security and ownership of the file 556 * applies to the stream. In contrast, extended attribute files, which are 557 * used to implement streams, are independent objects with their own 558 * attributes. 559 * 560 * For compatibility with streams, we set the size on the extended attribute 561 * file and apply other attributes to the (unnamed stream) file. The one 562 * exception is that the UID and GID can be set on the stream by passing a 563 * NULL unnamed_vp, which allows callers to synchronize stream ownership 564 * with the (unnamed stream) file. 565 */ 566 int 567 smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *attr, 568 int flags, cred_t *cr) 569 { 570 int error = 0; 571 int at_size = 0; 572 vnode_t *use_vp; 573 xvattr_t xvattr; 574 vattr_t *vap; 575 576 if (attr->sa_mask & SMB_AT_DOSATTR) { 577 attr->sa_dosattr &= 578 (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY | 579 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | 580 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_SPARSE_FILE); 581 } 582 583 if (unnamed_vp) { 584 use_vp = unnamed_vp; 585 if (attr->sa_mask & SMB_AT_SIZE) { 586 at_size = 1; 587 attr->sa_mask &= ~SMB_AT_SIZE; 588 } 589 } else { 590 use_vp = vp; 591 } 592 593 /* 594 * The caller should not be setting sa_vattr.va_mask, 595 * but rather sa_mask. 596 */ 597 598 attr->sa_vattr.va_mask = 0; 599 600 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 601 smb_vop_setup_xvattr(attr, &xvattr); 602 vap = &xvattr.xva_vattr; 603 } else { 604 smb_sa_to_va_mask(attr->sa_mask, 605 &attr->sa_vattr.va_mask); 606 vap = &attr->sa_vattr; 607 } 608 609 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 610 return (error); 611 612 if (at_size) { 613 attr->sa_vattr.va_mask = AT_SIZE; 614 error = VOP_SETATTR(vp, &attr->sa_vattr, flags, 615 zone_kcred(), &smb_ct); 616 } 617 618 return (error); 619 } 620 621 int 622 smb_vop_space(vnode_t *vp, int cmd, flock64_t *bfp, int flags, 623 offset_t offset, cred_t *cr) 624 { 625 int error; 626 627 error = VOP_SPACE(vp, cmd, bfp, flags, offset, cr, &smb_ct); 628 629 return (error); 630 } 631 632 /* 633 * smb_vop_access 634 * 635 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 636 * against file's ACL or Unix permissions. CIFS on the other hand needs to 637 * know if the requested operation can succeed for the given object, this 638 * requires more checks in case of DELETE bit since permissions on the parent 639 * directory are important as well. Based on Windows rules if parent's ACL 640 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 641 * permissions. 642 */ 643 int 644 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 645 { 646 int error = 0; 647 648 if (mode == 0) 649 return (0); 650 651 error = VOP_ACCESS(vp, mode, flags, cr, NULL); 652 653 if (error == 0) 654 return (0); 655 656 if ((mode & (ACE_DELETE|ACE_READ_ATTRIBUTES)) == 0 || 657 flags != V_ACE_MASK || dir_vp == NULL) 658 return (error); 659 660 if ((mode & ACE_DELETE) != 0) { 661 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 662 cr, NULL); 663 664 if (error == 0) 665 mode &= ~ACE_DELETE; 666 } 667 if ((mode & ACE_READ_ATTRIBUTES) != 0) { 668 error = VOP_ACCESS(dir_vp, ACE_LIST_DIRECTORY, flags, 669 cr, NULL); 670 671 if (error == 0) 672 mode &= ~ACE_READ_ATTRIBUTES; 673 } 674 675 if (mode != 0) 676 error = VOP_ACCESS(vp, mode, flags, cr, NULL); 677 678 return (error); 679 } 680 681 /* 682 * smb_vop_lookup 683 * 684 * dvp: directory vnode (in) 685 * name: name of file to be looked up (in) 686 * vpp: looked-up vnode (out) 687 * od_name: on-disk name of file (out). 688 * This parameter is optional. If a pointer is passed in, it 689 * must be allocated with MAXNAMELEN bytes 690 * rootvp: vnode of the tree root (in) 691 * This parameter is always passed in non-NULL except at the time 692 * of share set up. 693 * direntflags: dirent flags returned from VOP_LOOKUP 694 */ 695 int 696 smb_vop_lookup( 697 vnode_t *dvp, 698 char *name, 699 vnode_t **vpp, 700 char *od_name, 701 int flags, 702 int *direntflags, 703 vnode_t *rootvp, 704 smb_attr_t *attr, 705 cred_t *cr) 706 { 707 int error = 0; 708 int option_flags = 0; 709 pathname_t rpn; 710 char *np = name; 711 char namebuf[MAXNAMELEN]; 712 713 if (*name == '\0') { 714 /* 715 * This happens creating named streams at the share root. 716 */ 717 VN_HOLD(dvp); 718 *vpp = dvp; 719 goto attr_out; 720 } 721 722 ASSERT(vpp); 723 *vpp = NULL; 724 *direntflags = 0; 725 726 if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 727 if (rootvp && (dvp == rootvp)) { 728 VN_HOLD(dvp); 729 *vpp = dvp; 730 goto attr_out; 731 } 732 733 if (dvp->v_flag & VROOT) { 734 vfs_t *vfsp; 735 vnode_t *cvp = dvp; 736 737 /* 738 * Set dvp and check for races with forced unmount 739 * (see lookuppnvp()) 740 */ 741 742 vfsp = cvp->v_vfsp; 743 vfs_rlock_wait(vfsp); 744 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 745 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 746 vfs_unlock(vfsp); 747 return (EIO); 748 } 749 vfs_unlock(vfsp); 750 } 751 } 752 753 if (flags & SMB_IGNORE_CASE) 754 option_flags = FIGNORECASE; 755 756 if (flags & SMB_CATIA) 757 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf)); 758 759 #ifdef _KERNEL 760 /* 761 * The SMB server enables BYPASS_TRAVERSE_CHECKING by default. 762 * This grants PRIV_FILE_DAC_SEARCH to all users. 763 * If the user has this privilege, we'll always succeed ACE_EXECUTE 764 * checks on directories, so skip the (potentially expensive) 765 * ACL check. 766 */ 767 if (smb_vop_priv_check(cr, PRIV_FILE_DAC_SEARCH, B_FALSE, dvp)) 768 option_flags |= LOOKUP_NOACLCHECK; 769 #endif 770 pn_alloc(&rpn); 771 772 /* 773 * Easier to not have junk in rpn, as not every FS type 774 * will necessarily fill that in for us. 775 */ 776 bzero(rpn.pn_buf, rpn.pn_bufsize); 777 778 error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr, 779 &smb_ct, direntflags, &rpn); 780 781 if (error == 0 && od_name != NULL) { 782 bzero(od_name, MAXNAMELEN); 783 if ((option_flags & FIGNORECASE) != 0 && 784 rpn.pn_buf[0] != '\0') 785 np = rpn.pn_buf; 786 else 787 np = name; 788 if (flags & SMB_CATIA) 789 smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN); 790 else 791 (void) strlcpy(od_name, np, MAXNAMELEN); 792 } 793 pn_free(&rpn); 794 795 attr_out: 796 if (error == 0 && attr != NULL) { 797 attr->sa_mask = SMB_AT_ALL; 798 (void) smb_vop_getattr(*vpp, NULL, attr, 0, 799 zone_kcred()); 800 } 801 802 return (error); 803 } 804 805 int 806 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 807 int flags, cred_t *cr, vsecattr_t *vsap) 808 { 809 int error; 810 int option_flags = 0; 811 xvattr_t xvattr; 812 vattr_t *vap; 813 char *np = name; 814 char namebuf[MAXNAMELEN]; 815 816 if (flags & SMB_IGNORE_CASE) 817 option_flags = FIGNORECASE; 818 819 attr->sa_vattr.va_mask = 0; 820 821 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 822 smb_vop_setup_xvattr(attr, &xvattr); 823 vap = &xvattr.xva_vattr; 824 } else { 825 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 826 vap = &attr->sa_vattr; 827 } 828 829 if (flags & SMB_CATIA) { 830 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf)); 831 if (strchr(np, '/') != NULL) 832 return (EILSEQ); 833 } 834 835 error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode, 836 vpp, cr, option_flags, &smb_ct, vsap); 837 838 /* 839 * One could argue that filesystems should obey the size 840 * if specified in the create attributes. Unfortunately, 841 * they only appear to let you truncate the size to zero. 842 * SMB needs to set a non-zero size, so work-around. 843 */ 844 if (error == 0 && *vpp != NULL && 845 (vap->va_mask & AT_SIZE) != 0 && 846 vap->va_size > 0) { 847 vattr_t ta = *vap; 848 ta.va_mask = AT_SIZE; 849 (void) VOP_SETATTR(*vpp, &ta, 0, cr, &smb_ct); 850 } 851 852 return (error); 853 } 854 855 int 856 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 857 { 858 int error; 859 int option_flags = 0; 860 char *np = name; 861 char namebuf[MAXNAMELEN]; 862 863 if (flags & SMB_IGNORE_CASE) 864 option_flags = FIGNORECASE; 865 866 if (flags & SMB_CATIA) 867 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf)); 868 869 error = VOP_REMOVE(dvp, np, cr, &smb_ct, option_flags); 870 871 return (error); 872 } 873 874 /* 875 * smb_vop_link(target-dir-vp, source-file-vp, target-name) 876 * 877 * Create a link - same tree (identical TID) only. 878 */ 879 int 880 smb_vop_link(vnode_t *to_dvp, vnode_t *from_vp, char *to_name, 881 int flags, cred_t *cr) 882 { 883 int option_flags = 0; 884 char *np, *buf; 885 int rc; 886 887 if (flags & SMB_IGNORE_CASE) 888 option_flags = FIGNORECASE; 889 890 if (flags & SMB_CATIA) { 891 buf = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 892 np = smb_vop_catia_v5tov4(to_name, buf, MAXNAMELEN); 893 if (strchr(np, '/') != NULL) { 894 kmem_free(buf, MAXNAMELEN); 895 return (EILSEQ); 896 } 897 898 rc = VOP_LINK(to_dvp, from_vp, np, cr, &smb_ct, option_flags); 899 kmem_free(buf, MAXNAMELEN); 900 return (rc); 901 } 902 903 rc = VOP_LINK(to_dvp, from_vp, to_name, cr, &smb_ct, option_flags); 904 return (rc); 905 } 906 907 /* 908 * smb_vop_rename() 909 * 910 * The rename is for files in the same tree (identical TID) only. 911 */ 912 int 913 smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 914 char *to_name, int flags, cred_t *cr) 915 { 916 int error; 917 int option_flags = 0; 918 char *from, *to, *fbuf, *tbuf; 919 920 if (flags & SMB_IGNORE_CASE) 921 option_flags = FIGNORECASE; 922 923 if (flags & SMB_CATIA) { 924 tbuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 925 to = smb_vop_catia_v5tov4(to_name, tbuf, MAXNAMELEN); 926 if (strchr(to, '/') != NULL) { 927 kmem_free(tbuf, MAXNAMELEN); 928 return (EILSEQ); 929 } 930 931 fbuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 932 from = smb_vop_catia_v5tov4(from_name, fbuf, MAXNAMELEN); 933 934 error = VOP_RENAME(from_dvp, from, to_dvp, to, cr, 935 &smb_ct, option_flags); 936 937 kmem_free(tbuf, MAXNAMELEN); 938 kmem_free(fbuf, MAXNAMELEN); 939 return (error); 940 } 941 942 error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 943 &smb_ct, option_flags); 944 945 return (error); 946 } 947 948 int 949 smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 950 int flags, cred_t *cr, vsecattr_t *vsap) 951 { 952 int error; 953 int option_flags = 0; 954 xvattr_t xvattr; 955 vattr_t *vap; 956 char *np = name; 957 char namebuf[MAXNAMELEN]; 958 959 if (flags & SMB_IGNORE_CASE) 960 option_flags = FIGNORECASE; 961 962 attr->sa_vattr.va_mask = 0; 963 964 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 965 smb_vop_setup_xvattr(attr, &xvattr); 966 vap = &xvattr.xva_vattr; 967 } else { 968 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 969 vap = &attr->sa_vattr; 970 } 971 972 if (flags & SMB_CATIA) { 973 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf)); 974 if (strchr(np, '/') != NULL) 975 return (EILSEQ); 976 } 977 978 error = VOP_MKDIR(dvp, np, vap, vpp, cr, &smb_ct, option_flags, vsap); 979 980 return (error); 981 } 982 983 /* 984 * smb_vop_rmdir() 985 * 986 * Only simple rmdir supported, consistent with NT semantics 987 * (can only remove an empty directory). 988 * 989 * The third argument to VOP_RMDIR is the current directory of 990 * the process. It allows rmdir wants to EINVAL if one tries to 991 * remove ".". Since SMB servers do not know what their clients' 992 * current directories are, we fake it by supplying a vnode known 993 * to exist and illegal to remove (rootdir). 994 */ 995 int 996 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 997 { 998 int error; 999 int option_flags = 0; 1000 char *np = name; 1001 char namebuf[MAXNAMELEN]; 1002 1003 if (flags & SMB_IGNORE_CASE) 1004 option_flags = FIGNORECASE; 1005 1006 if (flags & SMB_CATIA) 1007 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf)); 1008 1009 error = VOP_RMDIR(dvp, np, rootdir, cr, &smb_ct, option_flags); 1010 return (error); 1011 } 1012 1013 int 1014 smb_vop_commit(vnode_t *vp, cred_t *cr) 1015 { 1016 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 1017 } 1018 1019 /* 1020 * Some code in smb_node.c needs to know which DOS attributes 1021 * we can actually store. Let's define a mask here of all the 1022 * DOS attribute flags supported by the following function. 1023 */ 1024 const uint32_t 1025 smb_vop_dosattr_settable = 1026 FILE_ATTRIBUTE_ARCHIVE | 1027 FILE_ATTRIBUTE_SYSTEM | 1028 FILE_ATTRIBUTE_HIDDEN | 1029 FILE_ATTRIBUTE_READONLY | 1030 FILE_ATTRIBUTE_OFFLINE | 1031 FILE_ATTRIBUTE_SPARSE_FILE; 1032 1033 static void 1034 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 1035 { 1036 xoptattr_t *xoap = NULL; 1037 uint_t xva_mask; 1038 1039 /* 1040 * Initialize xvattr, including bzero 1041 */ 1042 xva_init(xvattr); 1043 xoap = xva_getxoptattr(xvattr); 1044 1045 ASSERT(xoap); 1046 1047 /* 1048 * Copy caller-specified classic attributes to xvattr. 1049 * First save xvattr's mask (set in xva_init()), which 1050 * contains AT_XVATTR. This is |'d in later if needed. 1051 */ 1052 1053 xva_mask = xvattr->xva_vattr.va_mask; 1054 xvattr->xva_vattr = smb_attr->sa_vattr; 1055 1056 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 1057 1058 /* 1059 * Do not set ctime (only the file system can do it) 1060 */ 1061 1062 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 1063 1064 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 1065 1066 /* 1067 * "|" in the original xva_mask, which contains 1068 * AT_XVATTR 1069 */ 1070 1071 xvattr->xva_vattr.va_mask |= xva_mask; 1072 1073 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 1074 XVA_SET_REQ(xvattr, XAT_SYSTEM); 1075 XVA_SET_REQ(xvattr, XAT_READONLY); 1076 XVA_SET_REQ(xvattr, XAT_HIDDEN); 1077 XVA_SET_REQ(xvattr, XAT_OFFLINE); 1078 XVA_SET_REQ(xvattr, XAT_SPARSE); 1079 1080 /* 1081 * smb_attr->sa_dosattr: If a given bit is not set, 1082 * that indicates that the corresponding field needs 1083 * to be updated with a "0" value. This is done 1084 * implicitly as the xoap->xoa_* fields were bzero'd. 1085 */ 1086 1087 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 1088 xoap->xoa_archive = 1; 1089 1090 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 1091 xoap->xoa_system = 1; 1092 1093 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 1094 xoap->xoa_readonly = 1; 1095 1096 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 1097 xoap->xoa_hidden = 1; 1098 1099 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_OFFLINE) 1100 xoap->xoa_offline = 1; 1101 1102 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE) 1103 xoap->xoa_sparse = 1; 1104 } 1105 1106 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 1107 /* 1108 * "|" in the original xva_mask, which contains 1109 * AT_XVATTR 1110 */ 1111 1112 xvattr->xva_vattr.va_mask |= xva_mask; 1113 XVA_SET_REQ(xvattr, XAT_CREATETIME); 1114 xoap->xoa_createtime = smb_attr->sa_crtime; 1115 } 1116 } 1117 1118 /* 1119 * smb_vop_readdir() 1120 * 1121 * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. 1122 * The directory entries are returned in an fs-independent format by the 1123 * underlying file system. That is, the "page" of information returned is 1124 * not literally stored on-disk in the format returned. 1125 * If the file system supports extended directory entries (has features 1126 * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be 1127 * filled with edirent_t structures, instead of dirent64_t structures. 1128 * If the file system supports access based enumeration (abe), set 1129 * V_RDDIR_ACCFILTER to filter directory entries based on user cred. 1130 */ 1131 int 1132 smb_vop_readdir(vnode_t *vp, uint32_t offset, 1133 void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr) 1134 { 1135 int error = 0; 1136 int flags = 0; 1137 int rdirent_size; 1138 struct uio auio; 1139 struct iovec aiov; 1140 1141 if (vp->v_type != VDIR) 1142 return (ENOTDIR); 1143 1144 if ((rddir_flag & SMB_EDIRENT) != 0 && 1145 vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) { 1146 flags |= V_RDDIR_ENTFLAGS; 1147 rdirent_size = sizeof (edirent_t); 1148 } else { 1149 rdirent_size = sizeof (dirent64_t); 1150 } 1151 1152 if (*count < rdirent_size) 1153 return (EINVAL); 1154 1155 if (rddir_flag & SMB_ABE) 1156 flags |= V_RDDIR_ACCFILTER; 1157 1158 aiov.iov_base = buf; 1159 aiov.iov_len = *count; 1160 auio.uio_iov = &aiov; 1161 auio.uio_iovcnt = 1; 1162 auio.uio_loffset = (uint64_t)offset; 1163 auio.uio_segflg = UIO_SYSSPACE; 1164 auio.uio_extflg = UIO_COPY_DEFAULT; 1165 auio.uio_resid = *count; 1166 auio.uio_fmode = 0; 1167 1168 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 1169 error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, flags); 1170 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 1171 1172 if (error == 0) 1173 *count = *count - auio.uio_resid; 1174 1175 return (error); 1176 } 1177 1178 /* 1179 * smb_sa_to_va_mask 1180 * 1181 * Set va_mask by running through the SMB_AT_* #define's and 1182 * setting those bits that correspond to the SMB_AT_* bits 1183 * set in sa_mask. 1184 */ 1185 void 1186 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 1187 { 1188 int i; 1189 uint_t smask; 1190 1191 smask = (sa_mask); 1192 for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 1193 if (smask & 1) 1194 *(va_maskp) |= smb_attrmap[i]; 1195 1196 smask >>= 1; 1197 } 1198 } 1199 1200 /* 1201 * Variant of smb_sa_to_va_mask for vop_getattr, 1202 * adding some bits for SMB_AT_ALLOCSZ etc. 1203 */ 1204 void 1205 smb_sa_to_va_mask_get(uint_t sa_mask, uint_t *va_maskp) 1206 { 1207 smb_sa_to_va_mask(sa_mask, va_maskp); 1208 1209 *va_maskp |= AT_TYPE; 1210 if ((sa_mask & SMB_AT_ALLOCSZ) != 0) { 1211 *va_maskp |= (AT_SIZE | AT_NBLOCKS); 1212 } 1213 } 1214 1215 /* 1216 * smb_vop_stream_lookup() 1217 * 1218 * The name returned in od_name is the on-disk name of the stream with the 1219 * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 1220 * by the caller. 1221 */ 1222 int 1223 smb_vop_stream_lookup( 1224 vnode_t *fvp, 1225 char *stream_name, 1226 vnode_t **vpp, 1227 char *od_name, 1228 vnode_t **xattrdirvpp, 1229 int flags, 1230 vnode_t *rootvp, 1231 cred_t *cr) 1232 { 1233 char *solaris_stream_name; 1234 char *name; 1235 int error, tmpflgs; 1236 1237 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1238 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 1239 return (error); 1240 1241 /* 1242 * Prepend SMB_STREAM_PREFIX to stream name 1243 */ 1244 1245 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1246 (void) snprintf(solaris_stream_name, MAXNAMELEN, 1247 "%s%s", SMB_STREAM_PREFIX, stream_name); 1248 1249 /* 1250 * "name" will hold the on-disk name returned from smb_vop_lookup 1251 * for the stream, including the SMB_STREAM_PREFIX. 1252 */ 1253 1254 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1255 1256 if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 1257 name, flags, &tmpflgs, rootvp, NULL, cr)) != 0) { 1258 VN_RELE(*xattrdirvpp); 1259 } else { 1260 (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 1261 MAXNAMELEN); 1262 } 1263 1264 kmem_free(solaris_stream_name, MAXNAMELEN); 1265 kmem_free(name, MAXNAMELEN); 1266 1267 return (error); 1268 } 1269 1270 int 1271 smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 1272 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 1273 { 1274 char *solaris_stream_name; 1275 int error; 1276 1277 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1278 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 1279 return (error); 1280 1281 /* 1282 * Prepend SMB_STREAM_PREFIX to stream name 1283 */ 1284 1285 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1286 (void) snprintf(solaris_stream_name, MAXNAMELEN, 1287 "%s%s", SMB_STREAM_PREFIX, stream_name); 1288 1289 if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 1290 vpp, flags, cr, NULL)) != 0) 1291 VN_RELE(*xattrdirvpp); 1292 1293 kmem_free(solaris_stream_name, MAXNAMELEN); 1294 1295 return (error); 1296 } 1297 1298 int 1299 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 1300 { 1301 char *solaris_stream_name; 1302 vnode_t *xattrdirvp; 1303 int error; 1304 1305 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr); 1306 if (error != 0) 1307 return (error); 1308 1309 /* 1310 * Prepend SMB_STREAM_PREFIX to stream name 1311 */ 1312 1313 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1314 (void) snprintf(solaris_stream_name, MAXNAMELEN, 1315 "%s%s", SMB_STREAM_PREFIX, stream_name); 1316 1317 /* XXX might have to use kcred */ 1318 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 1319 1320 kmem_free(solaris_stream_name, MAXNAMELEN); 1321 VN_RELE(xattrdirvp); 1322 1323 return (error); 1324 } 1325 1326 int 1327 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 1328 cred_t *cr) 1329 { 1330 int error; 1331 1332 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 1333 &smb_ct, NULL, NULL); 1334 return (error); 1335 } 1336 1337 /* 1338 * smb_vop_traverse_check() 1339 * 1340 * This function checks to see if the passed-in vnode has a file system 1341 * mounted on it. If it does, the mount point is "traversed" and the 1342 * vnode for the root of the file system is returned. 1343 */ 1344 int 1345 smb_vop_traverse_check(vnode_t **vpp) 1346 { 1347 int error; 1348 1349 if (vn_mountedvfs(*vpp) == 0) 1350 return (0); 1351 1352 /* 1353 * traverse() may return a different held vnode, even in the error case. 1354 * If it returns a different vnode, it will have released the original. 1355 */ 1356 1357 error = traverse(vpp); 1358 1359 return (error); 1360 } 1361 1362 int /*ARGSUSED*/ 1363 smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 1364 { 1365 int error; 1366 1367 error = VFS_STATVFS(vp->v_vfsp, statp); 1368 1369 return (error); 1370 } 1371 1372 /* 1373 * smb_vop_acl_read 1374 * 1375 * Reads the ACL of the specified file into 'aclp'. 1376 * acl_type is the type of ACL which the filesystem supports. 1377 * 1378 * Caller has to free the allocated memory for aclp by calling 1379 * acl_free(). 1380 */ 1381 int 1382 smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 1383 cred_t *cr) 1384 { 1385 int error; 1386 vsecattr_t vsecattr; 1387 1388 ASSERT(vp); 1389 ASSERT(aclp); 1390 1391 *aclp = NULL; 1392 bzero(&vsecattr, sizeof (vsecattr_t)); 1393 1394 switch (acl_type) { 1395 case ACLENT_T: 1396 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 1397 VSA_DFACLCNT; 1398 break; 1399 1400 case ACE_T: 1401 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 1402 break; 1403 1404 default: 1405 return (EINVAL); 1406 } 1407 1408 if ((error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) != 0) 1409 return (error); 1410 1411 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 1412 if (vp->v_type == VDIR) 1413 (*aclp)->acl_flags |= ACL_IS_DIR; 1414 1415 return (0); 1416 } 1417 1418 /* 1419 * smb_vop_acl_write 1420 * 1421 * Writes the given ACL in aclp for the specified file. 1422 */ 1423 int 1424 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 1425 { 1426 int error; 1427 vsecattr_t vsecattr; 1428 int aclbsize; 1429 1430 ASSERT(vp); 1431 ASSERT(aclp); 1432 1433 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 1434 1435 if (error == 0) { 1436 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 1437 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 1438 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 1439 } 1440 1441 if (aclbsize && vsecattr.vsa_aclentp) 1442 kmem_free(vsecattr.vsa_aclentp, aclbsize); 1443 1444 return (error); 1445 } 1446 1447 /* 1448 * smb_vop_acl_type 1449 * 1450 * Determines the ACL type for the given vnode. 1451 * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 1452 */ 1453 acl_type_t 1454 smb_vop_acl_type(vnode_t *vp) 1455 { 1456 int error; 1457 ulong_t whichacl; 1458 1459 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, 1460 zone_kcred(), NULL); 1461 if (error != 0) { 1462 /* 1463 * If we got an error, then the filesystem 1464 * likely does not understand the _PC_ACL_ENABLED 1465 * pathconf. In this case, we fall back to trying 1466 * POSIX-draft (aka UFS-style) ACLs. 1467 */ 1468 whichacl = _ACL_ACLENT_ENABLED; 1469 } 1470 1471 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 1472 /* 1473 * If the file system supports neither ACE nor 1474 * ACLENT ACLs we will fall back to UFS-style ACLs 1475 * like we did above if there was an error upon 1476 * calling VOP_PATHCONF. 1477 * 1478 * ACE and ACLENT type ACLs are the only interfaces 1479 * supported thus far. If any other bits are set on 1480 * 'whichacl' upon return from VOP_PATHCONF, we will 1481 * ignore them. 1482 */ 1483 whichacl = _ACL_ACLENT_ENABLED; 1484 } 1485 1486 if (whichacl == _ACL_ACLENT_ENABLED) 1487 return (ACLENT_T); 1488 1489 return (ACE_T); 1490 } 1491 1492 static const int zfs_perms[] = { 1493 ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 1494 ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 1495 ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 1496 ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 1497 }; 1498 1499 static const int unix_perms[] = { VREAD, VWRITE, VEXEC }; 1500 /* 1501 * smb_vop_eaccess 1502 * 1503 * Returns the effective permission of the given credential for the 1504 * specified object. 1505 * 1506 * This is just a workaround. We need VFS/FS support for this. 1507 */ 1508 void 1509 smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 1510 { 1511 int error, i; 1512 int pnum; 1513 1514 *mode = 0; 1515 1516 if (flags == V_ACE_MASK) { 1517 pnum = sizeof (zfs_perms) / sizeof (int); 1518 1519 for (i = 0; i < pnum; i++) { 1520 error = smb_vop_access(vp, zfs_perms[i], flags, 1521 dir_vp, cr); 1522 if (error == 0) 1523 *mode |= zfs_perms[i]; 1524 } 1525 } else { 1526 pnum = sizeof (unix_perms) / sizeof (int); 1527 1528 for (i = 0; i < pnum; i++) { 1529 error = smb_vop_access(vp, unix_perms[i], flags, 1530 dir_vp, cr); 1531 if (error == 0) 1532 *mode |= unix_perms[i]; 1533 } 1534 } 1535 } 1536 1537 /* 1538 * See comments for smb_fsop_shrlock() 1539 */ 1540 int 1541 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 1542 uint32_t share_access, cred_t *cr) 1543 { 1544 struct shrlock shr; 1545 struct shr_locowner shr_own; 1546 short new_access = 0; 1547 short deny = 0; 1548 int flag = 0; 1549 int cmd; 1550 1551 /* 1552 * share locking is not supported for non-regular 1553 * objects in NBMAND mode. 1554 */ 1555 if (nbl_need_check(vp)) { 1556 if (vp->v_type != VREG) 1557 return (0); 1558 1559 cmd = F_SHARE_NBMAND; 1560 } else { 1561 cmd = F_SHARE; 1562 } 1563 1564 if ((desired_access & FILE_DATA_ALL) == 0) { 1565 /* metadata access only */ 1566 new_access |= F_MDACC; 1567 } else { 1568 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 1569 new_access |= F_RDACC; 1570 flag |= FREAD; 1571 } 1572 1573 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 1574 ACE_ADD_FILE)) { 1575 new_access |= F_WRACC; 1576 flag |= FWRITE; 1577 } 1578 1579 if (SMB_DENY_READ(share_access)) { 1580 deny |= F_RDDNY; 1581 } 1582 1583 if (SMB_DENY_WRITE(share_access)) { 1584 deny |= F_WRDNY; 1585 } 1586 1587 if (cmd == F_SHARE_NBMAND) { 1588 if (desired_access & ACE_DELETE) 1589 new_access |= F_RMACC; 1590 1591 if (SMB_DENY_DELETE(share_access)) { 1592 deny |= F_RMDNY; 1593 } 1594 } 1595 } 1596 1597 shr.s_access = new_access; 1598 shr.s_deny = deny; 1599 shr.s_sysid = smb_ct.cc_sysid; 1600 shr.s_pid = uniq_fid; 1601 shr.s_own_len = sizeof (shr_own); 1602 shr.s_owner = (caddr_t)&shr_own; 1603 shr_own.sl_id = shr.s_sysid; 1604 shr_own.sl_pid = shr.s_pid; 1605 1606 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 1607 } 1608 1609 int 1610 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 1611 { 1612 struct shrlock shr; 1613 struct shr_locowner shr_own; 1614 1615 /* 1616 * share locking is not supported for non-regular 1617 * objects in NBMAND mode. 1618 */ 1619 if (nbl_need_check(vp) && (vp->v_type != VREG)) 1620 return (0); 1621 1622 /* 1623 * For s_access and s_deny, we do not need to pass in the original 1624 * values. 1625 */ 1626 shr.s_access = 0; 1627 shr.s_deny = 0; 1628 shr.s_sysid = smb_ct.cc_sysid; 1629 shr.s_pid = uniq_fid; 1630 shr.s_own_len = sizeof (shr_own); 1631 shr.s_owner = (caddr_t)&shr_own; 1632 shr_own.sl_id = shr.s_sysid; 1633 shr_own.sl_pid = shr.s_pid; 1634 1635 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 1636 } 1637 1638 /* 1639 * Note about mandatory vs advisory locks: 1640 * 1641 * The SMB server really should always request mandatory locks, and 1642 * if the file system does not support them, the SMB server should 1643 * just tell the client it could not get the lock. If we were to 1644 * tell the SMB client "you got the lock" when what they really 1645 * got was only an advisory lock, we would be lying to the client 1646 * about their having exclusive access to the locked range, which 1647 * could easily lead to data corruption. If someone really wants 1648 * the (dangerous) behavior they can set: smb_allow_advisory_locks 1649 */ 1650 int 1651 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf) 1652 { 1653 flk_callback_t flk_cb; 1654 int cmd = F_SETLK_NBMAND; 1655 1656 if (smb_allow_advisory_locks != 0 && !nbl_need_check(vp)) { 1657 /* 1658 * The file system does not support nbmand, and 1659 * smb_allow_advisory_locks is enabled. (danger!) 1660 */ 1661 cmd = F_SETLK; 1662 } 1663 1664 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL); 1665 1666 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct)); 1667 } 1668 1669 static callb_cpr_t * 1670 /* ARGSUSED */ 1671 smb_lock_frlock_callback(flk_cb_when_t when, void *error) 1672 { 1673 return (0); 1674 } 1675 1676 /* 1677 * smb_vop_catia_init_v4_lookup 1678 * Initialize mapping between wide characters in the range from 1679 * 0x00A4 to 0x00FF and their UNIX (v4) equivalent (wide character). 1680 * Indexed by the decimal value of the wide character (164-255) 1681 * with an offset of -164. 1682 */ 1683 static void 1684 smb_vop_catia_init_v4_lookup() 1685 { 1686 int i, idx, offset = SMB_CATIA_V4_LOOKUP_LOW; 1687 1688 for (i = 0; i < SMB_CATIA_V4_LOOKUP_MAX; i++) 1689 smb_catia_v4_lookup[i] = (smb_wchar_t)(i + offset); 1690 1691 for (i = 0; i < SMB_CATIA_NUM_MAPS; i++) { 1692 idx = (int)catia_maps[i].winchar - offset; 1693 smb_catia_v4_lookup[idx] = (smb_wchar_t)catia_maps[i].unixchar; 1694 } 1695 } 1696 1697 /* 1698 * smb_vop_catia_init_v5_lookup 1699 * Initialize mapping between UNIX ASCII (v4) characters and equivalent 1700 * or translated wide characters. 1701 * Indexed by the decimal value of the ASCII character (0-127). 1702 */ 1703 static void 1704 smb_vop_catia_init_v5_lookup() 1705 { 1706 int i, idx; 1707 1708 for (i = 0; i < SMB_CATIA_V5_LOOKUP_MAX; i++) 1709 smb_catia_v5_lookup[i] = (smb_wchar_t)i; 1710 1711 for (i = 0; i < SMB_CATIA_NUM_MAPS; i++) { 1712 idx = (int)catia_maps[i].unixchar; 1713 smb_catia_v5_lookup[idx] = catia_maps[i].winchar; 1714 } 1715 } 1716 1717 static void 1718 smb_vop_catia_init() 1719 { 1720 smb_vop_catia_init_v4_lookup(); 1721 smb_vop_catia_init_v5_lookup(); 1722 } 1723 1724 /* 1725 * smb_vop_catia_v5tov4 1726 * (windows (v5) to unix (v4)) 1727 * 1728 * Traverse each character in the given source filename and convert the 1729 * multibyte that is equivalent to any special Windows character listed 1730 * in the catia_maps table to the Unix ASCII character if any is 1731 * encountered in the filename. The translated name is returned in buf. 1732 * 1733 * If an error occurs the conversion terminates and name is returned, 1734 * otherwise buf is returned. 1735 */ 1736 char * 1737 smb_vop_catia_v5tov4(char *name, char *buf, int buflen) 1738 { 1739 int v4_idx, numbytes, inc; 1740 int space_left = buflen - 1; /* one byte reserved for null */ 1741 uint32_t wc; 1742 char mbstring[MTS_MB_CHAR_MAX]; 1743 char *p, *src = name, *dst = buf; 1744 1745 ASSERT(name); 1746 ASSERT(buf); 1747 1748 if (!buf || !name) 1749 return (name); 1750 1751 bzero(buf, buflen); 1752 1753 while (*src) { 1754 if ((numbytes = smb_mbtowc(&wc, src, MTS_MB_CHAR_MAX)) < 0) 1755 return (name); 1756 1757 if (wc < SMB_CATIA_V4_LOOKUP_LOW || 1758 wc > SMB_CATIA_V4_LOOKUP_UPPER) { 1759 inc = numbytes; 1760 p = src; 1761 } else { 1762 /* Lookup required. */ 1763 v4_idx = (int)wc - SMB_CATIA_V4_LOOKUP_LOW; 1764 inc = smb_wctomb(mbstring, smb_catia_v4_lookup[v4_idx]); 1765 p = mbstring; 1766 } 1767 1768 if (space_left < inc) 1769 return (name); 1770 1771 (void) strncpy(dst, p, inc); 1772 dst += inc; 1773 space_left -= inc; 1774 src += numbytes; 1775 } 1776 1777 return (buf); 1778 } 1779 1780 /* 1781 * smb_vop_catia_v4tov5 1782 * (unix (v4) to windows (v5)) 1783 * 1784 * Traverse each character in the given filename 'srcbuf' and convert 1785 * the special Unix character that is listed in the catia_maps table to 1786 * the UTF-8 encoding of the corresponding Windows character if any is 1787 * encountered in the filename. 1788 * 1789 * The translated name is returned in buf. 1790 * If an error occurs the conversion terminates and the original name 1791 * is returned in buf. 1792 */ 1793 void 1794 smb_vop_catia_v4tov5(char *name, char *buf, int buflen) 1795 { 1796 int v5_idx, numbytes; 1797 int space_left = buflen - 1; /* one byte reserved for null */ 1798 uint32_t wc; 1799 char mbstring[MTS_MB_CHAR_MAX]; 1800 char *src = name, *dst = buf; 1801 1802 ASSERT(name); 1803 ASSERT(buf); 1804 1805 if (!buf || !name) 1806 return; 1807 1808 (void) bzero(buf, buflen); 1809 while (*src) { 1810 if (smb_isascii(*src)) { 1811 /* Lookup required */ 1812 v5_idx = (int)*src++; 1813 numbytes = smb_wctomb(mbstring, 1814 smb_catia_v5_lookup[v5_idx]); 1815 if (space_left < numbytes) 1816 break; 1817 (void) strncpy(dst, mbstring, numbytes); 1818 } else { 1819 if ((numbytes = smb_mbtowc(&wc, src, 1820 MTS_MB_CHAR_MAX)) < 0) 1821 break; 1822 if (space_left < numbytes) 1823 break; 1824 (void) strncpy(dst, src, numbytes); 1825 src += numbytes; 1826 } 1827 1828 dst += numbytes; 1829 space_left -= numbytes; 1830 } 1831 1832 if (*src) 1833 (void) strlcpy(buf, name, buflen); 1834 } 1835