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 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/uio.h>
29 #include <sys/statvfs.h>
30 #include <sys/vnode.h>
31 #include <sys/thread.h>
32 #include <sys/pathname.h>
33 #include <sys/cred.h>
34 #include <sys/extdirent.h>
35 #include <sys/nbmlock.h>
36 #include <sys/share.h>
37 #include <sys/fcntl.h>
38 #include <nfs/lm.h>
39
40 #include <smbsrv/smb_kproto.h>
41 #include <smbsrv/string.h>
42 #include <smbsrv/smb_vops.h>
43 #include <smbsrv/smb_fsops.h>
233 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) ||
234 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
235 vn_is_mapped(vp, V_RDORWR));
236 }
237
238 /*
239 * The smb_vop_* functions have minimal knowledge of CIFS semantics and
240 * serve as an interface to the VFS layer.
241 *
242 * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
243 * (Higher-level CIFS service code should never skip the smb_fsop_* layer
244 * to call smb_vop_* layer functions directly.)
245 */
246
247 /*
248 * XXX - Extended attributes support in the file system assumed.
249 * This is needed for full NT Streams functionality.
250 */
251
252 int
253 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr)
254 {
255 int error;
256
257 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
258 error = VOP_READ(vp, uiop, 0, cr, &smb_ct);
259 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
260 return (error);
261 }
262
263 int
264 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount,
265 cred_t *cr)
266 {
267 int error;
268
269 *lcount = uiop->uio_resid;
270
271 uiop->uio_llimit = MAXOFFSET_T;
272
273 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
274 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct);
275 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
276
277 *lcount -= uiop->uio_resid;
278
279 return (error);
280 }
281
282 /*
283 * smb_vop_getattr()
284 *
285 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
286 * service (instead of calling VOP_GETATTR directly) to retrieve attributes
287 * due to special processing needed for streams files.
288 *
289 * All attributes are retrieved.
290 *
291 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
292 * the corresponding unnamed stream).
293 * A named stream's attributes (as far as CIFS is concerned) are those of the
294 * unnamed stream (minus the size attribute, and the type), plus the size of
295 * the named stream, and a type value of VREG.
296 * Although the file system may store other attributes with the named stream,
297 * these should not be used by CIFS for any purpose.
298 *
299 * File systems without VFSFT_XVATTR do not support DOS attributes or create
300 * time (crtime). In this case the mtime is used as the crtime.
301 * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr
512
513 /*
514 * smb_vop_access
515 *
516 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
517 * against file's ACL or Unix permissions. CIFS on the other hand needs to
518 * know if the requested operation can succeed for the given object, this
519 * requires more checks in case of DELETE bit since permissions on the parent
520 * directory are important as well. Based on Windows rules if parent's ACL
521 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
522 * permissions.
523 */
524 int
525 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
526 {
527 int error = 0;
528
529 if (mode == 0)
530 return (0);
531
532 if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
533 if (dir_vp) {
534 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
535 cr, NULL);
536
537 if (error == 0)
538 mode &= ~ACE_DELETE;
539 }
540 }
541
542 if (mode) {
543 error = VOP_ACCESS(vp, mode, flags, cr, NULL);
544 }
545
546 return (error);
547 }
548
549 /*
550 * smb_vop_lookup
551 *
552 * dvp: directory vnode (in)
553 * name: name of file to be looked up (in)
554 * vpp: looked-up vnode (out)
555 * od_name: on-disk name of file (out).
556 * This parameter is optional. If a pointer is passed in, it
557 * must be allocated with MAXNAMELEN bytes
558 * rootvp: vnode of the tree root (in)
559 * This parameter is always passed in non-NULL except at the time
560 * of share set up.
561 * direntflags: dirent flags returned from VOP_LOOKUP
562 */
563 int
564 smb_vop_lookup(
565 vnode_t *dvp,
603
604 vfsp = cvp->v_vfsp;
605 vfs_rlock_wait(vfsp);
606 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
607 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
608 vfs_unlock(vfsp);
609 return (EIO);
610 }
611 vfs_unlock(vfsp);
612 }
613 }
614
615 if (flags & SMB_IGNORE_CASE)
616 option_flags = FIGNORECASE;
617
618 if (flags & SMB_CATIA)
619 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
620
621 pn_alloc(&rpn);
622
623 error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr,
624 &smb_ct, direntflags, &rpn);
625
626 if (error == 0) {
627 if (od_name) {
628 bzero(od_name, MAXNAMELEN);
629 np = (option_flags == FIGNORECASE) ? rpn.pn_buf : name;
630
631 if (flags & SMB_CATIA)
632 smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN);
633 else
634 (void) strlcpy(od_name, np, MAXNAMELEN);
635 }
636
637 if (attr != NULL) {
638 attr->sa_mask = SMB_AT_ALL;
639 (void) smb_vop_getattr(*vpp, NULL, attr, 0,
640 zone_kcred());
641 }
642 }
643
644 pn_free(&rpn);
645 return (error);
646 }
647
648 int
649 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
650 int flags, cred_t *cr, vsecattr_t *vsap)
661
662 attr->sa_vattr.va_mask = 0;
663
664 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
665 smb_vop_setup_xvattr(attr, &xvattr);
666 vap = &xvattr.xva_vattr;
667 } else {
668 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
669 vap = &attr->sa_vattr;
670 }
671
672 if (flags & SMB_CATIA) {
673 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
674 if (strchr(np, '/') != NULL)
675 return (EILSEQ);
676 }
677
678 error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
679 vpp, cr, option_flags, &smb_ct, vsap);
680
681 return (error);
682 }
683
684 int
685 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr)
686 {
687 int error;
688 int option_flags = 0;
689 char *np = name;
690 char namebuf[MAXNAMELEN];
691
692 if (flags & SMB_IGNORE_CASE)
693 option_flags = FIGNORECASE;
694
695 if (flags & SMB_CATIA)
696 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
697
698 error = VOP_REMOVE(dvp, np, cr, &smb_ct, option_flags);
699
700 return (error);
953 * not literally stored on-disk in the format returned.
954 * If the file system supports extended directory entries (has features
955 * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
956 * filled with edirent_t structures, instead of dirent64_t structures.
957 * If the file system supports access based enumeration (abe), set
958 * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
959 */
960 int
961 smb_vop_readdir(vnode_t *vp, uint32_t offset,
962 void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
963 {
964 int error = 0;
965 int flags = 0;
966 int rdirent_size;
967 struct uio auio;
968 struct iovec aiov;
969
970 if (vp->v_type != VDIR)
971 return (ENOTDIR);
972
973 if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
974 flags |= V_RDDIR_ENTFLAGS;
975 rdirent_size = sizeof (edirent_t);
976 } else {
977 rdirent_size = sizeof (dirent64_t);
978 }
979
980 if (*count < rdirent_size)
981 return (EINVAL);
982
983 if (rddir_flag & SMB_ABE)
984 flags |= V_RDDIR_ACCFILTER;
985
986 aiov.iov_base = buf;
987 aiov.iov_len = *count;
988 auio.uio_iov = &aiov;
989 auio.uio_iovcnt = 1;
990 auio.uio_loffset = (uint64_t)offset;
991 auio.uio_segflg = UIO_SYSSPACE;
992 auio.uio_extflg = UIO_COPY_DEFAULT;
993 auio.uio_resid = *count;
1201 ASSERT(vp);
1202 ASSERT(aclp);
1203
1204 *aclp = NULL;
1205 bzero(&vsecattr, sizeof (vsecattr_t));
1206
1207 switch (acl_type) {
1208 case ACLENT_T:
1209 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
1210 VSA_DFACLCNT;
1211 break;
1212
1213 case ACE_T:
1214 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
1215 break;
1216
1217 default:
1218 return (EINVAL);
1219 }
1220
1221 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct))
1222 return (error);
1223
1224 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
1225 if (vp->v_type == VDIR)
1226 (*aclp)->acl_flags |= ACL_IS_DIR;
1227
1228 return (0);
1229 }
1230
1231 /*
1232 * smb_vop_acl_write
1233 *
1234 * Writes the given ACL in aclp for the specified file.
1235 */
1236 int
1237 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
1238 {
1239 int error;
1240 vsecattr_t vsecattr;
1241 int aclbsize;
1431 */
1432 if (nbl_need_check(vp) && (vp->v_type != VREG))
1433 return (0);
1434
1435 /*
1436 * For s_access and s_deny, we do not need to pass in the original
1437 * values.
1438 */
1439 shr.s_access = 0;
1440 shr.s_deny = 0;
1441 shr.s_sysid = smb_ct.cc_sysid;
1442 shr.s_pid = uniq_fid;
1443 shr.s_own_len = sizeof (shr_own);
1444 shr.s_owner = (caddr_t)&shr_own;
1445 shr_own.sl_id = shr.s_sysid;
1446 shr_own.sl_pid = shr.s_pid;
1447
1448 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL));
1449 }
1450
1451 int
1452 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf)
1453 {
1454 int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
1455 flk_callback_t flk_cb;
1456
1457 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL);
1458
1459 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct));
1460 }
1461
1462 static callb_cpr_t *
1463 /* ARGSUSED */
1464 smb_lock_frlock_callback(flk_cb_when_t when, void *error)
1465 {
1466 return (0);
1467 }
1468
1469 /*
1470 * smb_vop_catia_init_v4_lookup
1471 * Initialize mapping between wide characters in the range from
1472 * 0x00A4 to 0x00FF and their UNIX (v4) equivalent (wide character).
1473 * Indexed by the decimal value of the wide character (164-255)
1474 * with an offset of -164.
1475 */
1476 static void
1514 smb_vop_catia_init_v5_lookup();
1515 }
1516
1517 /*
1518 * smb_vop_catia_v5tov4
1519 * (windows (v5) to unix (v4))
1520 *
1521 * Traverse each character in the given source filename and convert the
1522 * multibyte that is equivalent to any special Windows character listed
1523 * in the catia_maps table to the Unix ASCII character if any is
1524 * encountered in the filename. The translated name is returned in buf.
1525 *
1526 * If an error occurs the conversion terminates and name is returned,
1527 * otherwise buf is returned.
1528 */
1529 char *
1530 smb_vop_catia_v5tov4(char *name, char *buf, int buflen)
1531 {
1532 int v4_idx, numbytes, inc;
1533 int space_left = buflen - 1; /* one byte reserved for null */
1534 smb_wchar_t wc;
1535 char mbstring[MTS_MB_CHAR_MAX];
1536 char *p, *src = name, *dst = buf;
1537
1538 ASSERT(name);
1539 ASSERT(buf);
1540
1541 if (!buf || !name)
1542 return (name);
1543
1544 bzero(buf, buflen);
1545
1546 while (*src) {
1547 if ((numbytes = smb_mbtowc(&wc, src, MTS_MB_CHAR_MAX)) < 0)
1548 return (name);
1549
1550 if (wc < SMB_CATIA_V4_LOOKUP_LOW ||
1551 wc > SMB_CATIA_V4_LOOKUP_UPPER) {
1552 inc = numbytes;
1553 p = src;
1554 } else {
1571 }
1572
1573 /*
1574 * smb_vop_catia_v4tov5
1575 * (unix (v4) to windows (v5))
1576 *
1577 * Traverse each character in the given filename 'srcbuf' and convert
1578 * the special Unix character that is listed in the catia_maps table to
1579 * the UTF-8 encoding of the corresponding Windows character if any is
1580 * encountered in the filename.
1581 *
1582 * The translated name is returned in buf.
1583 * If an error occurs the conversion terminates and the original name
1584 * is returned in buf.
1585 */
1586 void
1587 smb_vop_catia_v4tov5(char *name, char *buf, int buflen)
1588 {
1589 int v5_idx, numbytes;
1590 int space_left = buflen - 1; /* one byte reserved for null */
1591 smb_wchar_t wc;
1592 char mbstring[MTS_MB_CHAR_MAX];
1593 char *src = name, *dst = buf;
1594
1595 ASSERT(name);
1596 ASSERT(buf);
1597
1598 if (!buf || !name)
1599 return;
1600
1601 (void) bzero(buf, buflen);
1602 while (*src) {
1603 if (smb_isascii(*src)) {
1604 /* Lookup required */
1605 v5_idx = (int)*src++;
1606 numbytes = smb_wctomb(mbstring,
1607 smb_catia_v5_lookup[v5_idx]);
1608 if (space_left < numbytes)
1609 break;
1610 (void) strncpy(dst, mbstring, numbytes);
1611 } else {
|
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 <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/uio.h>
29 #include <sys/statvfs.h>
30 #include <sys/vnode.h>
31 #include <sys/thread.h>
32 #include <sys/pathname.h>
33 #include <sys/cred.h>
34 #include <sys/extdirent.h>
35 #include <sys/nbmlock.h>
36 #include <sys/share.h>
37 #include <sys/fcntl.h>
38 #include <nfs/lm.h>
39
40 #include <smbsrv/smb_kproto.h>
41 #include <smbsrv/string.h>
42 #include <smbsrv/smb_vops.h>
43 #include <smbsrv/smb_fsops.h>
233 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) ||
234 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
235 vn_is_mapped(vp, V_RDORWR));
236 }
237
238 /*
239 * The smb_vop_* functions have minimal knowledge of CIFS semantics and
240 * serve as an interface to the VFS layer.
241 *
242 * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
243 * (Higher-level CIFS service code should never skip the smb_fsop_* layer
244 * to call smb_vop_* layer functions directly.)
245 */
246
247 /*
248 * XXX - Extended attributes support in the file system assumed.
249 * This is needed for full NT Streams functionality.
250 */
251
252 int
253 smb_vop_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr)
254 {
255 int error;
256
257 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
258 error = VOP_READ(vp, uiop, ioflag, cr, &smb_ct);
259 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
260 return (error);
261 }
262
263 int
264 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount,
265 cred_t *cr)
266 {
267 int error;
268
269 *lcount = uiop->uio_resid;
270
271 uiop->uio_llimit = MAXOFFSET_T;
272
273 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
274 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct);
275 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
276
277 *lcount -= uiop->uio_resid;
278
279 return (error);
280 }
281
282 int
283 smb_vop_ioctl(vnode_t *vp, int cmd, void *arg, cred_t *cr)
284 {
285 int error, rval = 0;
286 uint_t flags = 0;
287
288 #ifdef FKIOCTL
289 flags |= FKIOCTL;
290 #endif
291 error = VOP_IOCTL(vp, cmd, (intptr_t)arg, (int)flags, cr,
292 &rval, &smb_ct);
293 if (error != 0)
294 rval = error;
295
296 return (rval);
297 }
298
299 /*
300 * smb_vop_getattr()
301 *
302 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
303 * service (instead of calling VOP_GETATTR directly) to retrieve attributes
304 * due to special processing needed for streams files.
305 *
306 * All attributes are retrieved.
307 *
308 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
309 * the corresponding unnamed stream).
310 * A named stream's attributes (as far as CIFS is concerned) are those of the
311 * unnamed stream (minus the size attribute, and the type), plus the size of
312 * the named stream, and a type value of VREG.
313 * Although the file system may store other attributes with the named stream,
314 * these should not be used by CIFS for any purpose.
315 *
316 * File systems without VFSFT_XVATTR do not support DOS attributes or create
317 * time (crtime). In this case the mtime is used as the crtime.
318 * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr
529
530 /*
531 * smb_vop_access
532 *
533 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
534 * against file's ACL or Unix permissions. CIFS on the other hand needs to
535 * know if the requested operation can succeed for the given object, this
536 * requires more checks in case of DELETE bit since permissions on the parent
537 * directory are important as well. Based on Windows rules if parent's ACL
538 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
539 * permissions.
540 */
541 int
542 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
543 {
544 int error = 0;
545
546 if (mode == 0)
547 return (0);
548
549 error = VOP_ACCESS(vp, mode, flags, cr, NULL);
550
551 if (error == 0)
552 return (0);
553
554 if ((mode & (ACE_DELETE|ACE_READ_ATTRIBUTES)) == 0 ||
555 flags != V_ACE_MASK || dir_vp == NULL)
556 return (error);
557
558 smb_audit_save();
559 if ((mode & ACE_DELETE) != 0) {
560 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
561 cr, NULL);
562
563 if (error == 0)
564 mode &= ~ACE_DELETE;
565 }
566 if ((mode & ACE_READ_ATTRIBUTES) != 0) {
567 error = VOP_ACCESS(dir_vp, ACE_LIST_DIRECTORY, flags,
568 cr, NULL);
569
570 if (error == 0)
571 mode &= ~ACE_READ_ATTRIBUTES;
572 }
573
574 if (mode != 0)
575 error = VOP_ACCESS(vp, mode, flags, cr, NULL);
576
577 smb_audit_load();
578 return (error);
579 }
580
581 /*
582 * smb_vop_lookup
583 *
584 * dvp: directory vnode (in)
585 * name: name of file to be looked up (in)
586 * vpp: looked-up vnode (out)
587 * od_name: on-disk name of file (out).
588 * This parameter is optional. If a pointer is passed in, it
589 * must be allocated with MAXNAMELEN bytes
590 * rootvp: vnode of the tree root (in)
591 * This parameter is always passed in non-NULL except at the time
592 * of share set up.
593 * direntflags: dirent flags returned from VOP_LOOKUP
594 */
595 int
596 smb_vop_lookup(
597 vnode_t *dvp,
635
636 vfsp = cvp->v_vfsp;
637 vfs_rlock_wait(vfsp);
638 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
639 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
640 vfs_unlock(vfsp);
641 return (EIO);
642 }
643 vfs_unlock(vfsp);
644 }
645 }
646
647 if (flags & SMB_IGNORE_CASE)
648 option_flags = FIGNORECASE;
649
650 if (flags & SMB_CATIA)
651 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
652
653 pn_alloc(&rpn);
654
655 /*
656 * Easier to not have junk in rpn, as not every FS type
657 * will necessarily fill that in for us.
658 */
659 bzero(rpn.pn_buf, rpn.pn_bufsize);
660
661 error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr,
662 &smb_ct, direntflags, &rpn);
663
664 if (error == 0) {
665 if (od_name) {
666 bzero(od_name, MAXNAMELEN);
667 if ((option_flags & FIGNORECASE) != 0 &&
668 rpn.pn_buf[0] != '\0')
669 np = rpn.pn_buf;
670 else
671 np = name;
672 if (flags & SMB_CATIA)
673 smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN);
674 else
675 (void) strlcpy(od_name, np, MAXNAMELEN);
676 }
677
678 if (attr != NULL) {
679 attr->sa_mask = SMB_AT_ALL;
680 (void) smb_vop_getattr(*vpp, NULL, attr, 0,
681 zone_kcred());
682 }
683 }
684
685 pn_free(&rpn);
686 return (error);
687 }
688
689 int
690 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
691 int flags, cred_t *cr, vsecattr_t *vsap)
702
703 attr->sa_vattr.va_mask = 0;
704
705 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
706 smb_vop_setup_xvattr(attr, &xvattr);
707 vap = &xvattr.xva_vattr;
708 } else {
709 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
710 vap = &attr->sa_vattr;
711 }
712
713 if (flags & SMB_CATIA) {
714 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
715 if (strchr(np, '/') != NULL)
716 return (EILSEQ);
717 }
718
719 error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
720 vpp, cr, option_flags, &smb_ct, vsap);
721
722 /*
723 * One could argue that filesystems should obey the size
724 * if specified in the create attributes. Unfortunately,
725 * they only appear to let you truncate the size to zero.
726 * SMB needs to set a non-zero size, so work-around.
727 */
728 if (error == 0 && *vpp != NULL &&
729 (vap->va_mask & AT_SIZE) != 0 &&
730 vap->va_size > 0) {
731 vattr_t ta = *vap;
732 ta.va_mask = AT_SIZE;
733 (void) VOP_SETATTR(*vpp, &ta, 0, cr, &smb_ct);
734 }
735
736 return (error);
737 }
738
739 int
740 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr)
741 {
742 int error;
743 int option_flags = 0;
744 char *np = name;
745 char namebuf[MAXNAMELEN];
746
747 if (flags & SMB_IGNORE_CASE)
748 option_flags = FIGNORECASE;
749
750 if (flags & SMB_CATIA)
751 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
752
753 error = VOP_REMOVE(dvp, np, cr, &smb_ct, option_flags);
754
755 return (error);
1008 * not literally stored on-disk in the format returned.
1009 * If the file system supports extended directory entries (has features
1010 * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
1011 * filled with edirent_t structures, instead of dirent64_t structures.
1012 * If the file system supports access based enumeration (abe), set
1013 * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
1014 */
1015 int
1016 smb_vop_readdir(vnode_t *vp, uint32_t offset,
1017 void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
1018 {
1019 int error = 0;
1020 int flags = 0;
1021 int rdirent_size;
1022 struct uio auio;
1023 struct iovec aiov;
1024
1025 if (vp->v_type != VDIR)
1026 return (ENOTDIR);
1027
1028 if ((rddir_flag & SMB_EDIRENT) != 0 &&
1029 vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
1030 flags |= V_RDDIR_ENTFLAGS;
1031 rdirent_size = sizeof (edirent_t);
1032 } else {
1033 rdirent_size = sizeof (dirent64_t);
1034 }
1035
1036 if (*count < rdirent_size)
1037 return (EINVAL);
1038
1039 if (rddir_flag & SMB_ABE)
1040 flags |= V_RDDIR_ACCFILTER;
1041
1042 aiov.iov_base = buf;
1043 aiov.iov_len = *count;
1044 auio.uio_iov = &aiov;
1045 auio.uio_iovcnt = 1;
1046 auio.uio_loffset = (uint64_t)offset;
1047 auio.uio_segflg = UIO_SYSSPACE;
1048 auio.uio_extflg = UIO_COPY_DEFAULT;
1049 auio.uio_resid = *count;
1257 ASSERT(vp);
1258 ASSERT(aclp);
1259
1260 *aclp = NULL;
1261 bzero(&vsecattr, sizeof (vsecattr_t));
1262
1263 switch (acl_type) {
1264 case ACLENT_T:
1265 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
1266 VSA_DFACLCNT;
1267 break;
1268
1269 case ACE_T:
1270 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
1271 break;
1272
1273 default:
1274 return (EINVAL);
1275 }
1276
1277 if ((error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) != 0)
1278 return (error);
1279
1280 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
1281 if (vp->v_type == VDIR)
1282 (*aclp)->acl_flags |= ACL_IS_DIR;
1283
1284 return (0);
1285 }
1286
1287 /*
1288 * smb_vop_acl_write
1289 *
1290 * Writes the given ACL in aclp for the specified file.
1291 */
1292 int
1293 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
1294 {
1295 int error;
1296 vsecattr_t vsecattr;
1297 int aclbsize;
1487 */
1488 if (nbl_need_check(vp) && (vp->v_type != VREG))
1489 return (0);
1490
1491 /*
1492 * For s_access and s_deny, we do not need to pass in the original
1493 * values.
1494 */
1495 shr.s_access = 0;
1496 shr.s_deny = 0;
1497 shr.s_sysid = smb_ct.cc_sysid;
1498 shr.s_pid = uniq_fid;
1499 shr.s_own_len = sizeof (shr_own);
1500 shr.s_owner = (caddr_t)&shr_own;
1501 shr_own.sl_id = shr.s_sysid;
1502 shr_own.sl_pid = shr.s_pid;
1503
1504 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL));
1505 }
1506
1507 /*
1508 * Note about mandatory vs advisory locks:
1509 *
1510 * The SMB server really should always request mandatory locks, and
1511 * if the file system does not support them, the SMB server should
1512 * just tell the client it could not get the lock. If we were to
1513 * tell the SMB client "you got the lock" when what they really
1514 * got was only an advisory lock, we would be lying to the client
1515 * about their having exclusive access to the locked range, which
1516 * could easily lead to data corruption. If someone really wants
1517 * the (dangerous) behavior they can set: smb_allow_advisory_locks
1518 */
1519 int
1520 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf)
1521 {
1522 flk_callback_t flk_cb;
1523 int cmd = F_SETLK_NBMAND;
1524
1525 if (smb_allow_advisory_locks != 0 && !nbl_need_check(vp)) {
1526 /*
1527 * The file system does not support nbmand, and
1528 * smb_allow_advisory_locks is enabled. (danger!)
1529 */
1530 cmd = F_SETLK;
1531 }
1532
1533 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL);
1534
1535 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct));
1536 }
1537
1538 static callb_cpr_t *
1539 /* ARGSUSED */
1540 smb_lock_frlock_callback(flk_cb_when_t when, void *error)
1541 {
1542 return (0);
1543 }
1544
1545 /*
1546 * smb_vop_catia_init_v4_lookup
1547 * Initialize mapping between wide characters in the range from
1548 * 0x00A4 to 0x00FF and their UNIX (v4) equivalent (wide character).
1549 * Indexed by the decimal value of the wide character (164-255)
1550 * with an offset of -164.
1551 */
1552 static void
1590 smb_vop_catia_init_v5_lookup();
1591 }
1592
1593 /*
1594 * smb_vop_catia_v5tov4
1595 * (windows (v5) to unix (v4))
1596 *
1597 * Traverse each character in the given source filename and convert the
1598 * multibyte that is equivalent to any special Windows character listed
1599 * in the catia_maps table to the Unix ASCII character if any is
1600 * encountered in the filename. The translated name is returned in buf.
1601 *
1602 * If an error occurs the conversion terminates and name is returned,
1603 * otherwise buf is returned.
1604 */
1605 char *
1606 smb_vop_catia_v5tov4(char *name, char *buf, int buflen)
1607 {
1608 int v4_idx, numbytes, inc;
1609 int space_left = buflen - 1; /* one byte reserved for null */
1610 uint32_t wc;
1611 char mbstring[MTS_MB_CHAR_MAX];
1612 char *p, *src = name, *dst = buf;
1613
1614 ASSERT(name);
1615 ASSERT(buf);
1616
1617 if (!buf || !name)
1618 return (name);
1619
1620 bzero(buf, buflen);
1621
1622 while (*src) {
1623 if ((numbytes = smb_mbtowc(&wc, src, MTS_MB_CHAR_MAX)) < 0)
1624 return (name);
1625
1626 if (wc < SMB_CATIA_V4_LOOKUP_LOW ||
1627 wc > SMB_CATIA_V4_LOOKUP_UPPER) {
1628 inc = numbytes;
1629 p = src;
1630 } else {
1647 }
1648
1649 /*
1650 * smb_vop_catia_v4tov5
1651 * (unix (v4) to windows (v5))
1652 *
1653 * Traverse each character in the given filename 'srcbuf' and convert
1654 * the special Unix character that is listed in the catia_maps table to
1655 * the UTF-8 encoding of the corresponding Windows character if any is
1656 * encountered in the filename.
1657 *
1658 * The translated name is returned in buf.
1659 * If an error occurs the conversion terminates and the original name
1660 * is returned in buf.
1661 */
1662 void
1663 smb_vop_catia_v4tov5(char *name, char *buf, int buflen)
1664 {
1665 int v5_idx, numbytes;
1666 int space_left = buflen - 1; /* one byte reserved for null */
1667 uint32_t wc;
1668 char mbstring[MTS_MB_CHAR_MAX];
1669 char *src = name, *dst = buf;
1670
1671 ASSERT(name);
1672 ASSERT(buf);
1673
1674 if (!buf || !name)
1675 return;
1676
1677 (void) bzero(buf, buflen);
1678 while (*src) {
1679 if (smb_isascii(*src)) {
1680 /* Lookup required */
1681 v5_idx = (int)*src++;
1682 numbytes = smb_wctomb(mbstring,
1683 smb_catia_v5_lookup[v5_idx]);
1684 if (space_left < numbytes)
1685 break;
1686 (void) strncpy(dst, mbstring, numbytes);
1687 } else {
|